Coverage Report

Created: 2025-11-16 06:41

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libwebp/src/dsp/yuv_sse2.c
Line
Count
Source
1
// Copyright 2014 Google Inc. All Rights Reserved.
2
//
3
// Use of this source code is governed by a BSD-style license
4
// that can be found in the COPYING file in the root of the source
5
// tree. An additional intellectual property rights grant can be found
6
// in the file PATENTS. All contributing project authors may
7
// be found in the AUTHORS file in the root of the source tree.
8
// -----------------------------------------------------------------------------
9
//
10
// YUV->RGB conversion functions
11
//
12
// Author: Skal (pascal.massimino@gmail.com)
13
14
#include "src/dsp/yuv.h"
15
16
#if defined(WEBP_USE_SSE2)
17
#include <emmintrin.h>
18
#include <stdlib.h>
19
20
#include "src/dsp/common_sse2.h"
21
#include "src/dsp/cpu.h"
22
#include "src/dsp/dsp.h"
23
#include "src/utils/utils.h"
24
#include "src/webp/decode.h"
25
#include "src/webp/types.h"
26
27
//-----------------------------------------------------------------------------
28
// Convert spans of 32 pixels to various RGB formats for the fancy upsampler.
29
30
// These constants are 14b fixed-point version of ITU-R BT.601 constants.
31
// R = (19077 * y             + 26149 * v - 14234) >> 6
32
// G = (19077 * y -  6419 * u - 13320 * v +  8708) >> 6
33
// B = (19077 * y + 33050 * u             - 17685) >> 6
34
static void ConvertYUV444ToRGB_SSE2(const __m128i* const Y0,
35
                                    const __m128i* const U0,
36
                                    const __m128i* const V0, __m128i* const R,
37
8.51M
                                    __m128i* const G, __m128i* const B) {
38
8.51M
  const __m128i k19077 = _mm_set1_epi16(19077);
39
8.51M
  const __m128i k26149 = _mm_set1_epi16(26149);
40
8.51M
  const __m128i k14234 = _mm_set1_epi16(14234);
41
  // 33050 doesn't fit in a signed short: only use this with unsigned arithmetic
42
8.51M
  const __m128i k33050 = _mm_set1_epi16((short)33050);
43
8.51M
  const __m128i k17685 = _mm_set1_epi16(17685);
44
8.51M
  const __m128i k6419 = _mm_set1_epi16(6419);
45
8.51M
  const __m128i k13320 = _mm_set1_epi16(13320);
46
8.51M
  const __m128i k8708 = _mm_set1_epi16(8708);
47
48
8.51M
  const __m128i Y1 = _mm_mulhi_epu16(*Y0, k19077);
49
50
8.51M
  const __m128i R0 = _mm_mulhi_epu16(*V0, k26149);
51
8.51M
  const __m128i R1 = _mm_sub_epi16(Y1, k14234);
52
8.51M
  const __m128i R2 = _mm_add_epi16(R1, R0);
53
54
8.51M
  const __m128i G0 = _mm_mulhi_epu16(*U0, k6419);
55
8.51M
  const __m128i G1 = _mm_mulhi_epu16(*V0, k13320);
56
8.51M
  const __m128i G2 = _mm_add_epi16(Y1, k8708);
57
8.51M
  const __m128i G3 = _mm_add_epi16(G0, G1);
58
8.51M
  const __m128i G4 = _mm_sub_epi16(G2, G3);
59
60
  // be careful with the saturated *unsigned* arithmetic here!
61
8.51M
  const __m128i B0 = _mm_mulhi_epu16(*U0, k33050);
62
8.51M
  const __m128i B1 = _mm_adds_epu16(B0, Y1);
63
8.51M
  const __m128i B2 = _mm_subs_epu16(B1, k17685);
64
65
  // use logical shift for B2, which can be larger than 32767
66
8.51M
  *R = _mm_srai_epi16(R2, 6);  // range: [-14234, 30815]
67
8.51M
  *G = _mm_srai_epi16(G4, 6);  // range: [-10953, 27710]
68
8.51M
  *B = _mm_srli_epi16(B2, 6);  // range: [0, 34238]
69
8.51M
}
70
71
// Load the bytes into the *upper* part of 16b words. That's "<< 8", basically.
72
25.5M
static WEBP_INLINE __m128i Load_HI_16_SSE2(const uint8_t* src) {
73
25.5M
  const __m128i zero = _mm_setzero_si128();
74
25.5M
  return _mm_unpacklo_epi8(zero, _mm_loadl_epi64((const __m128i*)src));
75
25.5M
}
76
77
// Load and replicate the U/V samples
78
0
static WEBP_INLINE __m128i Load_UV_HI_8_SSE2(const uint8_t* src) {
79
0
  const __m128i zero = _mm_setzero_si128();
80
0
  const __m128i tmp0 = _mm_cvtsi32_si128(WebPMemToInt32(src));
81
0
  const __m128i tmp1 = _mm_unpacklo_epi8(zero, tmp0);
82
0
  return _mm_unpacklo_epi16(tmp1, tmp1);  // replicate samples
83
0
}
84
85
// Convert 32 samples of YUV444 to R/G/B
86
static void YUV444ToRGB_SSE2(const uint8_t* WEBP_RESTRICT const y,
87
                             const uint8_t* WEBP_RESTRICT const u,
88
                             const uint8_t* WEBP_RESTRICT const v,
89
                             __m128i* const R, __m128i* const G,
90
8.51M
                             __m128i* const B) {
91
8.51M
  const __m128i Y0 = Load_HI_16_SSE2(y), U0 = Load_HI_16_SSE2(u),
92
8.51M
                V0 = Load_HI_16_SSE2(v);
93
8.51M
  ConvertYUV444ToRGB_SSE2(&Y0, &U0, &V0, R, G, B);
94
8.51M
}
95
96
// Convert 32 samples of YUV420 to R/G/B
97
static void YUV420ToRGB_SSE2(const uint8_t* WEBP_RESTRICT const y,
98
                             const uint8_t* WEBP_RESTRICT const u,
99
                             const uint8_t* WEBP_RESTRICT const v,
100
                             __m128i* const R, __m128i* const G,
101
0
                             __m128i* const B) {
102
0
  const __m128i Y0 = Load_HI_16_SSE2(y), U0 = Load_UV_HI_8_SSE2(u),
103
0
                V0 = Load_UV_HI_8_SSE2(v);
104
0
  ConvertYUV444ToRGB_SSE2(&Y0, &U0, &V0, R, G, B);
105
0
}
106
107
// Pack R/G/B/A results into 32b output.
108
static WEBP_INLINE void PackAndStore4_SSE2(const __m128i* const R,
109
                                           const __m128i* const G,
110
                                           const __m128i* const B,
111
                                           const __m128i* const A,
112
8.51M
                                           uint8_t* WEBP_RESTRICT const dst) {
113
8.51M
  const __m128i rb = _mm_packus_epi16(*R, *B);
114
8.51M
  const __m128i ga = _mm_packus_epi16(*G, *A);
115
8.51M
  const __m128i rg = _mm_unpacklo_epi8(rb, ga);
116
8.51M
  const __m128i ba = _mm_unpackhi_epi8(rb, ga);
117
8.51M
  const __m128i RGBA_lo = _mm_unpacklo_epi16(rg, ba);
118
8.51M
  const __m128i RGBA_hi = _mm_unpackhi_epi16(rg, ba);
119
8.51M
  _mm_storeu_si128((__m128i*)(dst + 0), RGBA_lo);
120
8.51M
  _mm_storeu_si128((__m128i*)(dst + 16), RGBA_hi);
121
8.51M
}
122
123
// Pack R/G/B/A results into 16b output.
124
static WEBP_INLINE void PackAndStore4444_SSE2(
125
    const __m128i* const R, const __m128i* const G, const __m128i* const B,
126
0
    const __m128i* const A, uint8_t* WEBP_RESTRICT const dst) {
127
0
#if (WEBP_SWAP_16BIT_CSP == 0)
128
0
  const __m128i rg0 = _mm_packus_epi16(*R, *G);
129
0
  const __m128i ba0 = _mm_packus_epi16(*B, *A);
130
#else
131
  const __m128i rg0 = _mm_packus_epi16(*B, *A);
132
  const __m128i ba0 = _mm_packus_epi16(*R, *G);
133
#endif
134
0
  const __m128i mask_0xf0 = _mm_set1_epi8((char)0xf0);
135
0
  const __m128i rb1 = _mm_unpacklo_epi8(rg0, ba0);  // rbrbrbrbrb...
136
0
  const __m128i ga1 = _mm_unpackhi_epi8(rg0, ba0);  // gagagagaga...
137
0
  const __m128i rb2 = _mm_and_si128(rb1, mask_0xf0);
138
0
  const __m128i ga2 = _mm_srli_epi16(_mm_and_si128(ga1, mask_0xf0), 4);
139
0
  const __m128i rgba4444 = _mm_or_si128(rb2, ga2);
140
0
  _mm_storeu_si128((__m128i*)dst, rgba4444);
141
0
}
142
143
// Pack R/G/B results into 16b output.
144
static WEBP_INLINE void PackAndStore565_SSE2(const __m128i* const R,
145
                                             const __m128i* const G,
146
                                             const __m128i* const B,
147
0
                                             uint8_t* WEBP_RESTRICT const dst) {
148
0
  const __m128i r0 = _mm_packus_epi16(*R, *R);
149
0
  const __m128i g0 = _mm_packus_epi16(*G, *G);
150
0
  const __m128i b0 = _mm_packus_epi16(*B, *B);
151
0
  const __m128i r1 = _mm_and_si128(r0, _mm_set1_epi8((char)0xf8));
152
0
  const __m128i b1 = _mm_and_si128(_mm_srli_epi16(b0, 3), _mm_set1_epi8(0x1f));
153
0
  const __m128i g1 =
154
0
      _mm_srli_epi16(_mm_and_si128(g0, _mm_set1_epi8((char)0xe0)), 5);
155
0
  const __m128i g2 = _mm_slli_epi16(_mm_and_si128(g0, _mm_set1_epi8(0x1c)), 3);
156
0
  const __m128i rg = _mm_or_si128(r1, g1);
157
0
  const __m128i gb = _mm_or_si128(g2, b1);
158
0
#if (WEBP_SWAP_16BIT_CSP == 0)
159
0
  const __m128i rgb565 = _mm_unpacklo_epi8(rg, gb);
160
#else
161
  const __m128i rgb565 = _mm_unpacklo_epi8(gb, rg);
162
#endif
163
0
  _mm_storeu_si128((__m128i*)dst, rgb565);
164
0
}
165
166
// Pack the planar buffers
167
// rrrr... rrrr... gggg... gggg... bbbb... bbbb....
168
// triplet by triplet in the output buffer rgb as rgbrgbrgbrgb ...
169
static WEBP_INLINE void PlanarTo24b_SSE2(__m128i* const in0, __m128i* const in1,
170
                                         __m128i* const in2, __m128i* const in3,
171
                                         __m128i* const in4, __m128i* const in5,
172
0
                                         uint8_t* WEBP_RESTRICT const rgb) {
173
  // The input is 6 registers of sixteen 8b but for the sake of explanation,
174
  // let's take 6 registers of four 8b values.
175
  // To pack, we will keep taking one every two 8b integer and move it
176
  // around as follows:
177
  // Input:
178
  //   r0r1r2r3 | r4r5r6r7 | g0g1g2g3 | g4g5g6g7 | b0b1b2b3 | b4b5b6b7
179
  // Split the 6 registers in two sets of 3 registers: the first set as the even
180
  // 8b bytes, the second the odd ones:
181
  //   r0r2r4r6 | g0g2g4g6 | b0b2b4b6 | r1r3r5r7 | g1g3g5g7 | b1b3b5b7
182
  // Repeat the same permutations twice more:
183
  //   r0r4g0g4 | b0b4r1r5 | g1g5b1b5 | r2r6g2g6 | b2b6r3r7 | g3g7b3b7
184
  //   r0g0b0r1 | g1b1r2g2 | b2r3g3b3 | r4g4b4r5 | g5b5r6g6 | b6r7g7b7
185
0
  VP8PlanarTo24b_SSE2(in0, in1, in2, in3, in4, in5);
186
187
0
  _mm_storeu_si128((__m128i*)(rgb + 0), *in0);
188
0
  _mm_storeu_si128((__m128i*)(rgb + 16), *in1);
189
0
  _mm_storeu_si128((__m128i*)(rgb + 32), *in2);
190
0
  _mm_storeu_si128((__m128i*)(rgb + 48), *in3);
191
0
  _mm_storeu_si128((__m128i*)(rgb + 64), *in4);
192
0
  _mm_storeu_si128((__m128i*)(rgb + 80), *in5);
193
0
}
194
195
void VP8YuvToRgba32_SSE2(const uint8_t* WEBP_RESTRICT y,
196
                         const uint8_t* WEBP_RESTRICT u,
197
                         const uint8_t* WEBP_RESTRICT v,
198
2.12M
                         uint8_t* WEBP_RESTRICT dst) {
199
2.12M
  const __m128i kAlpha = _mm_set1_epi16(255);
200
2.12M
  int n;
201
10.6M
  for (n = 0; n < 32; n += 8, dst += 32) {
202
8.51M
    __m128i R, G, B;
203
8.51M
    YUV444ToRGB_SSE2(y + n, u + n, v + n, &R, &G, &B);
204
8.51M
    PackAndStore4_SSE2(&R, &G, &B, &kAlpha, dst);
205
8.51M
  }
206
2.12M
}
207
208
void VP8YuvToBgra32_SSE2(const uint8_t* WEBP_RESTRICT y,
209
                         const uint8_t* WEBP_RESTRICT u,
210
                         const uint8_t* WEBP_RESTRICT v,
211
0
                         uint8_t* WEBP_RESTRICT dst) {
212
0
  const __m128i kAlpha = _mm_set1_epi16(255);
213
0
  int n;
214
0
  for (n = 0; n < 32; n += 8, dst += 32) {
215
0
    __m128i R, G, B;
216
0
    YUV444ToRGB_SSE2(y + n, u + n, v + n, &R, &G, &B);
217
0
    PackAndStore4_SSE2(&B, &G, &R, &kAlpha, dst);
218
0
  }
219
0
}
220
221
void VP8YuvToArgb32_SSE2(const uint8_t* WEBP_RESTRICT y,
222
                         const uint8_t* WEBP_RESTRICT u,
223
                         const uint8_t* WEBP_RESTRICT v,
224
0
                         uint8_t* WEBP_RESTRICT dst) {
225
0
  const __m128i kAlpha = _mm_set1_epi16(255);
226
0
  int n;
227
0
  for (n = 0; n < 32; n += 8, dst += 32) {
228
0
    __m128i R, G, B;
229
0
    YUV444ToRGB_SSE2(y + n, u + n, v + n, &R, &G, &B);
230
0
    PackAndStore4_SSE2(&kAlpha, &R, &G, &B, dst);
231
0
  }
232
0
}
233
234
void VP8YuvToRgba444432_SSE2(const uint8_t* WEBP_RESTRICT y,
235
                             const uint8_t* WEBP_RESTRICT u,
236
                             const uint8_t* WEBP_RESTRICT v,
237
0
                             uint8_t* WEBP_RESTRICT dst) {
238
0
  const __m128i kAlpha = _mm_set1_epi16(255);
239
0
  int n;
240
0
  for (n = 0; n < 32; n += 8, dst += 16) {
241
0
    __m128i R, G, B;
242
0
    YUV444ToRGB_SSE2(y + n, u + n, v + n, &R, &G, &B);
243
0
    PackAndStore4444_SSE2(&R, &G, &B, &kAlpha, dst);
244
0
  }
245
0
}
246
247
void VP8YuvToRgb56532_SSE2(const uint8_t* WEBP_RESTRICT y,
248
                           const uint8_t* WEBP_RESTRICT u,
249
                           const uint8_t* WEBP_RESTRICT v,
250
0
                           uint8_t* WEBP_RESTRICT dst) {
251
0
  int n;
252
0
  for (n = 0; n < 32; n += 8, dst += 16) {
253
0
    __m128i R, G, B;
254
0
    YUV444ToRGB_SSE2(y + n, u + n, v + n, &R, &G, &B);
255
0
    PackAndStore565_SSE2(&R, &G, &B, dst);
256
0
  }
257
0
}
258
259
void VP8YuvToRgb32_SSE2(const uint8_t* WEBP_RESTRICT y,
260
                        const uint8_t* WEBP_RESTRICT u,
261
                        const uint8_t* WEBP_RESTRICT v,
262
0
                        uint8_t* WEBP_RESTRICT dst) {
263
0
  __m128i R0, R1, R2, R3, G0, G1, G2, G3, B0, B1, B2, B3;
264
0
  __m128i rgb0, rgb1, rgb2, rgb3, rgb4, rgb5;
265
266
0
  YUV444ToRGB_SSE2(y + 0, u + 0, v + 0, &R0, &G0, &B0);
267
0
  YUV444ToRGB_SSE2(y + 8, u + 8, v + 8, &R1, &G1, &B1);
268
0
  YUV444ToRGB_SSE2(y + 16, u + 16, v + 16, &R2, &G2, &B2);
269
0
  YUV444ToRGB_SSE2(y + 24, u + 24, v + 24, &R3, &G3, &B3);
270
271
  // Cast to 8b and store as RRRRGGGGBBBB.
272
0
  rgb0 = _mm_packus_epi16(R0, R1);
273
0
  rgb1 = _mm_packus_epi16(R2, R3);
274
0
  rgb2 = _mm_packus_epi16(G0, G1);
275
0
  rgb3 = _mm_packus_epi16(G2, G3);
276
0
  rgb4 = _mm_packus_epi16(B0, B1);
277
0
  rgb5 = _mm_packus_epi16(B2, B3);
278
279
  // Pack as RGBRGBRGBRGB.
280
0
  PlanarTo24b_SSE2(&rgb0, &rgb1, &rgb2, &rgb3, &rgb4, &rgb5, dst);
281
0
}
282
283
void VP8YuvToBgr32_SSE2(const uint8_t* WEBP_RESTRICT y,
284
                        const uint8_t* WEBP_RESTRICT u,
285
                        const uint8_t* WEBP_RESTRICT v,
286
0
                        uint8_t* WEBP_RESTRICT dst) {
287
0
  __m128i R0, R1, R2, R3, G0, G1, G2, G3, B0, B1, B2, B3;
288
0
  __m128i bgr0, bgr1, bgr2, bgr3, bgr4, bgr5;
289
290
0
  YUV444ToRGB_SSE2(y + 0, u + 0, v + 0, &R0, &G0, &B0);
291
0
  YUV444ToRGB_SSE2(y + 8, u + 8, v + 8, &R1, &G1, &B1);
292
0
  YUV444ToRGB_SSE2(y + 16, u + 16, v + 16, &R2, &G2, &B2);
293
0
  YUV444ToRGB_SSE2(y + 24, u + 24, v + 24, &R3, &G3, &B3);
294
295
  // Cast to 8b and store as BBBBGGGGRRRR.
296
0
  bgr0 = _mm_packus_epi16(B0, B1);
297
0
  bgr1 = _mm_packus_epi16(B2, B3);
298
0
  bgr2 = _mm_packus_epi16(G0, G1);
299
0
  bgr3 = _mm_packus_epi16(G2, G3);
300
0
  bgr4 = _mm_packus_epi16(R0, R1);
301
0
  bgr5 = _mm_packus_epi16(R2, R3);
302
303
  // Pack as BGRBGRBGRBGR.
304
0
  PlanarTo24b_SSE2(&bgr0, &bgr1, &bgr2, &bgr3, &bgr4, &bgr5, dst);
305
0
}
306
307
//-----------------------------------------------------------------------------
308
// Arbitrary-length row conversion functions
309
310
static void YuvToRgbaRow_SSE2(const uint8_t* WEBP_RESTRICT y,
311
                              const uint8_t* WEBP_RESTRICT u,
312
                              const uint8_t* WEBP_RESTRICT v,
313
0
                              uint8_t* WEBP_RESTRICT dst, int len) {
314
0
  const __m128i kAlpha = _mm_set1_epi16(255);
315
0
  int n;
316
0
  for (n = 0; n + 8 <= len; n += 8, dst += 32) {
317
0
    __m128i R, G, B;
318
0
    YUV420ToRGB_SSE2(y, u, v, &R, &G, &B);
319
0
    PackAndStore4_SSE2(&R, &G, &B, &kAlpha, dst);
320
0
    y += 8;
321
0
    u += 4;
322
0
    v += 4;
323
0
  }
324
0
  for (; n < len; ++n) {  // Finish off
325
0
    VP8YuvToRgba(y[0], u[0], v[0], dst);
326
0
    dst += 4;
327
0
    y += 1;
328
0
    u += (n & 1);
329
0
    v += (n & 1);
330
0
  }
331
0
}
332
333
static void YuvToBgraRow_SSE2(const uint8_t* WEBP_RESTRICT y,
334
                              const uint8_t* WEBP_RESTRICT u,
335
                              const uint8_t* WEBP_RESTRICT v,
336
0
                              uint8_t* WEBP_RESTRICT dst, int len) {
337
0
  const __m128i kAlpha = _mm_set1_epi16(255);
338
0
  int n;
339
0
  for (n = 0; n + 8 <= len; n += 8, dst += 32) {
340
0
    __m128i R, G, B;
341
0
    YUV420ToRGB_SSE2(y, u, v, &R, &G, &B);
342
0
    PackAndStore4_SSE2(&B, &G, &R, &kAlpha, dst);
343
0
    y += 8;
344
0
    u += 4;
345
0
    v += 4;
346
0
  }
347
0
  for (; n < len; ++n) {  // Finish off
348
0
    VP8YuvToBgra(y[0], u[0], v[0], dst);
349
0
    dst += 4;
350
0
    y += 1;
351
0
    u += (n & 1);
352
0
    v += (n & 1);
353
0
  }
354
0
}
355
356
static void YuvToArgbRow_SSE2(const uint8_t* WEBP_RESTRICT y,
357
                              const uint8_t* WEBP_RESTRICT u,
358
                              const uint8_t* WEBP_RESTRICT v,
359
0
                              uint8_t* WEBP_RESTRICT dst, int len) {
360
0
  const __m128i kAlpha = _mm_set1_epi16(255);
361
0
  int n;
362
0
  for (n = 0; n + 8 <= len; n += 8, dst += 32) {
363
0
    __m128i R, G, B;
364
0
    YUV420ToRGB_SSE2(y, u, v, &R, &G, &B);
365
0
    PackAndStore4_SSE2(&kAlpha, &R, &G, &B, dst);
366
0
    y += 8;
367
0
    u += 4;
368
0
    v += 4;
369
0
  }
370
0
  for (; n < len; ++n) {  // Finish off
371
0
    VP8YuvToArgb(y[0], u[0], v[0], dst);
372
0
    dst += 4;
373
0
    y += 1;
374
0
    u += (n & 1);
375
0
    v += (n & 1);
376
0
  }
377
0
}
378
379
static void YuvToRgbRow_SSE2(const uint8_t* WEBP_RESTRICT y,
380
                             const uint8_t* WEBP_RESTRICT u,
381
                             const uint8_t* WEBP_RESTRICT v,
382
0
                             uint8_t* WEBP_RESTRICT dst, int len) {
383
0
  int n;
384
0
  for (n = 0; n + 32 <= len; n += 32, dst += 32 * 3) {
385
0
    __m128i R0, R1, R2, R3, G0, G1, G2, G3, B0, B1, B2, B3;
386
0
    __m128i rgb0, rgb1, rgb2, rgb3, rgb4, rgb5;
387
388
0
    YUV420ToRGB_SSE2(y + 0, u + 0, v + 0, &R0, &G0, &B0);
389
0
    YUV420ToRGB_SSE2(y + 8, u + 4, v + 4, &R1, &G1, &B1);
390
0
    YUV420ToRGB_SSE2(y + 16, u + 8, v + 8, &R2, &G2, &B2);
391
0
    YUV420ToRGB_SSE2(y + 24, u + 12, v + 12, &R3, &G3, &B3);
392
393
    // Cast to 8b and store as RRRRGGGGBBBB.
394
0
    rgb0 = _mm_packus_epi16(R0, R1);
395
0
    rgb1 = _mm_packus_epi16(R2, R3);
396
0
    rgb2 = _mm_packus_epi16(G0, G1);
397
0
    rgb3 = _mm_packus_epi16(G2, G3);
398
0
    rgb4 = _mm_packus_epi16(B0, B1);
399
0
    rgb5 = _mm_packus_epi16(B2, B3);
400
401
    // Pack as RGBRGBRGBRGB.
402
0
    PlanarTo24b_SSE2(&rgb0, &rgb1, &rgb2, &rgb3, &rgb4, &rgb5, dst);
403
404
0
    y += 32;
405
0
    u += 16;
406
0
    v += 16;
407
0
  }
408
0
  for (; n < len; ++n) {  // Finish off
409
0
    VP8YuvToRgb(y[0], u[0], v[0], dst);
410
0
    dst += 3;
411
0
    y += 1;
412
0
    u += (n & 1);
413
0
    v += (n & 1);
414
0
  }
415
0
}
416
417
static void YuvToBgrRow_SSE2(const uint8_t* WEBP_RESTRICT y,
418
                             const uint8_t* WEBP_RESTRICT u,
419
                             const uint8_t* WEBP_RESTRICT v,
420
0
                             uint8_t* WEBP_RESTRICT dst, int len) {
421
0
  int n;
422
0
  for (n = 0; n + 32 <= len; n += 32, dst += 32 * 3) {
423
0
    __m128i R0, R1, R2, R3, G0, G1, G2, G3, B0, B1, B2, B3;
424
0
    __m128i bgr0, bgr1, bgr2, bgr3, bgr4, bgr5;
425
426
0
    YUV420ToRGB_SSE2(y + 0, u + 0, v + 0, &R0, &G0, &B0);
427
0
    YUV420ToRGB_SSE2(y + 8, u + 4, v + 4, &R1, &G1, &B1);
428
0
    YUV420ToRGB_SSE2(y + 16, u + 8, v + 8, &R2, &G2, &B2);
429
0
    YUV420ToRGB_SSE2(y + 24, u + 12, v + 12, &R3, &G3, &B3);
430
431
    // Cast to 8b and store as BBBBGGGGRRRR.
432
0
    bgr0 = _mm_packus_epi16(B0, B1);
433
0
    bgr1 = _mm_packus_epi16(B2, B3);
434
0
    bgr2 = _mm_packus_epi16(G0, G1);
435
0
    bgr3 = _mm_packus_epi16(G2, G3);
436
0
    bgr4 = _mm_packus_epi16(R0, R1);
437
0
    bgr5 = _mm_packus_epi16(R2, R3);
438
439
    // Pack as BGRBGRBGRBGR.
440
0
    PlanarTo24b_SSE2(&bgr0, &bgr1, &bgr2, &bgr3, &bgr4, &bgr5, dst);
441
442
0
    y += 32;
443
0
    u += 16;
444
0
    v += 16;
445
0
  }
446
0
  for (; n < len; ++n) {  // Finish off
447
0
    VP8YuvToBgr(y[0], u[0], v[0], dst);
448
0
    dst += 3;
449
0
    y += 1;
450
0
    u += (n & 1);
451
0
    v += (n & 1);
452
0
  }
453
0
}
454
455
//------------------------------------------------------------------------------
456
// Entry point
457
458
extern void WebPInitSamplersSSE2(void);
459
460
1
WEBP_TSAN_IGNORE_FUNCTION void WebPInitSamplersSSE2(void) {
461
1
  WebPSamplers[MODE_RGB] = YuvToRgbRow_SSE2;
462
1
  WebPSamplers[MODE_RGBA] = YuvToRgbaRow_SSE2;
463
1
  WebPSamplers[MODE_BGR] = YuvToBgrRow_SSE2;
464
1
  WebPSamplers[MODE_BGRA] = YuvToBgraRow_SSE2;
465
1
  WebPSamplers[MODE_ARGB] = YuvToArgbRow_SSE2;
466
1
}
467
468
//------------------------------------------------------------------------------
469
// RGB24/32 -> YUV converters
470
471
// Load eight 16b-words from *src.
472
0
#define LOAD_16(src) _mm_loadu_si128((const __m128i*)(src))
473
// Store either 16b-words into *dst
474
0
#define STORE_16(V, dst) _mm_storeu_si128((__m128i*)(dst), (V))
475
476
// Function that inserts a value of the second half of the in buffer in between
477
// every two char of the first half.
478
static WEBP_INLINE void RGB24PackedToPlanarHelper_SSE2(
479
0
    const __m128i* const in /*in[6]*/, __m128i* const out /*out[6]*/) {
480
0
  out[0] = _mm_unpacklo_epi8(in[0], in[3]);
481
0
  out[1] = _mm_unpackhi_epi8(in[0], in[3]);
482
0
  out[2] = _mm_unpacklo_epi8(in[1], in[4]);
483
0
  out[3] = _mm_unpackhi_epi8(in[1], in[4]);
484
0
  out[4] = _mm_unpacklo_epi8(in[2], in[5]);
485
0
  out[5] = _mm_unpackhi_epi8(in[2], in[5]);
486
0
}
487
488
// Unpack the 8b input rgbrgbrgbrgb ... as contiguous registers:
489
// rrrr... rrrr... gggg... gggg... bbbb... bbbb....
490
// Similar to PlanarTo24bHelper(), but in reverse order.
491
static WEBP_INLINE void RGBPackedToPlanar_SSE2(
492
0
    const uint8_t* WEBP_RESTRICT const rgb, __m128i* const out /*out[6]*/) {
493
0
  __m128i tmp[6];
494
0
  tmp[0] = _mm_loadu_si128((const __m128i*)(rgb + 0));
495
0
  tmp[1] = _mm_loadu_si128((const __m128i*)(rgb + 16));
496
0
  tmp[2] = _mm_loadu_si128((const __m128i*)(rgb + 32));
497
0
  tmp[3] = _mm_loadu_si128((const __m128i*)(rgb + 48));
498
0
  tmp[4] = _mm_loadu_si128((const __m128i*)(rgb + 64));
499
0
  tmp[5] = _mm_loadu_si128((const __m128i*)(rgb + 80));
500
501
0
  RGB24PackedToPlanarHelper_SSE2(tmp, out);
502
0
  RGB24PackedToPlanarHelper_SSE2(out, tmp);
503
0
  RGB24PackedToPlanarHelper_SSE2(tmp, out);
504
0
  RGB24PackedToPlanarHelper_SSE2(out, tmp);
505
0
  RGB24PackedToPlanarHelper_SSE2(tmp, out);
506
0
}
507
508
// Unpack the 8b input rgbargbargba... as contiguous registers:
509
// rrrr... rrrr... gggg... gggg... bbbb... bbbb....
510
static WEBP_INLINE void RGBAPackedToRGBPlanar_SSE2(
511
0
    const uint8_t* WEBP_RESTRICT const rgba, __m128i* const rgb /*in[6]*/) {
512
0
  __m128i a0 = _mm_loadu_si128((const __m128i*)(rgba + 0));
513
0
  __m128i a1 = _mm_loadu_si128((const __m128i*)(rgba + 16));
514
0
  __m128i a2 = _mm_loadu_si128((const __m128i*)(rgba + 32));
515
0
  __m128i a3 = _mm_loadu_si128((const __m128i*)(rgba + 48));
516
0
  __m128i a4 = _mm_loadu_si128((const __m128i*)(rgba + 64));
517
0
  __m128i a5 = _mm_loadu_si128((const __m128i*)(rgba + 80));
518
0
  __m128i a6 = _mm_loadu_si128((const __m128i*)(rgba + 96));
519
0
  __m128i a7 = _mm_loadu_si128((const __m128i*)(rgba + 112));
520
0
  VP8L32bToPlanar_SSE2(&a0, &a1, &a2, &a3);
521
0
  rgb[0] = a3;
522
0
  rgb[2] = a2;
523
0
  rgb[4] = a1;
524
0
  VP8L32bToPlanar_SSE2(&a4, &a5, &a6, &a7);
525
0
  rgb[1] = a7;
526
0
  rgb[3] = a6;
527
0
  rgb[5] = a5;
528
0
}
529
530
// Unpack the 8b input argbargbargb... as contiguous registers:
531
// 0r0r0r... 0r0r0r... 0g0g0g... 0g0g0g0... 0b0b0b... 0b0b0b....
532
static WEBP_INLINE void RGB32PackedToPlanar16_SSE2(
533
0
    const uint32_t* WEBP_RESTRICT const argb, __m128i* const rgb /*in[6]*/) {
534
0
  const __m128i zero = _mm_setzero_si128();
535
0
  __m128i a0 = LOAD_16(argb + 0);
536
0
  __m128i a1 = LOAD_16(argb + 4);
537
0
  __m128i a2 = LOAD_16(argb + 8);
538
0
  __m128i a3 = LOAD_16(argb + 12);
539
0
  VP8L32bToPlanar_SSE2(&a0, &a1, &a2, &a3);
540
0
  rgb[0] = _mm_unpacklo_epi8(a1, zero);
541
0
  rgb[1] = _mm_unpackhi_epi8(a1, zero);
542
0
  rgb[2] = _mm_unpacklo_epi8(a2, zero);
543
0
  rgb[3] = _mm_unpackhi_epi8(a2, zero);
544
0
  rgb[4] = _mm_unpacklo_epi8(a3, zero);
545
0
  rgb[5] = _mm_unpackhi_epi8(a3, zero);
546
0
}
547
548
// This macro computes (RG * MULT_RG + GB * MULT_GB + ROUNDER) >> DESCALE_FIX
549
// It's a macro and not a function because we need to use immediate values with
550
// srai_epi32, e.g.
551
#define TRANSFORM(RG_LO, RG_HI, GB_LO, GB_HI, MULT_RG, MULT_GB, ROUNDER, \
552
                  DESCALE_FIX, OUT)                                      \
553
0
  do {                                                                   \
554
0
    const __m128i V0_lo = _mm_madd_epi16(RG_LO, MULT_RG);                \
555
0
    const __m128i V0_hi = _mm_madd_epi16(RG_HI, MULT_RG);                \
556
0
    const __m128i V1_lo = _mm_madd_epi16(GB_LO, MULT_GB);                \
557
0
    const __m128i V1_hi = _mm_madd_epi16(GB_HI, MULT_GB);                \
558
0
    const __m128i V2_lo = _mm_add_epi32(V0_lo, V1_lo);                   \
559
0
    const __m128i V2_hi = _mm_add_epi32(V0_hi, V1_hi);                   \
560
0
    const __m128i V3_lo = _mm_add_epi32(V2_lo, ROUNDER);                 \
561
0
    const __m128i V3_hi = _mm_add_epi32(V2_hi, ROUNDER);                 \
562
0
    const __m128i V5_lo = _mm_srai_epi32(V3_lo, DESCALE_FIX);            \
563
0
    const __m128i V5_hi = _mm_srai_epi32(V3_hi, DESCALE_FIX);            \
564
0
    (OUT) = _mm_packs_epi32(V5_lo, V5_hi);                               \
565
0
  } while (0)
566
567
0
#define MK_CST_16(A, B) _mm_set_epi16((B), (A), (B), (A), (B), (A), (B), (A))
568
static WEBP_INLINE void ConvertRGBToYImpl_SSE2(const __m128i* const R,
569
                                               const __m128i* const G,
570
                                               const __m128i* const B,
571
0
                                               __m128i* const Y) {
572
0
  const __m128i kRG_y = MK_CST_16(16839, 33059 - 16384);
573
0
  const __m128i kGB_y = MK_CST_16(16384, 6420);
574
0
  const __m128i kHALF_Y = _mm_set1_epi32((16 << YUV_FIX) + YUV_HALF);
575
576
0
  const __m128i RG_lo = _mm_unpacklo_epi16(*R, *G);
577
0
  const __m128i RG_hi = _mm_unpackhi_epi16(*R, *G);
578
0
  const __m128i GB_lo = _mm_unpacklo_epi16(*G, *B);
579
0
  const __m128i GB_hi = _mm_unpackhi_epi16(*G, *B);
580
0
  TRANSFORM(RG_lo, RG_hi, GB_lo, GB_hi, kRG_y, kGB_y, kHALF_Y, YUV_FIX, *Y);
581
0
}
582
583
static WEBP_INLINE void ConvertRGBToUV_SSE2(const __m128i* const R,
584
                                            const __m128i* const G,
585
                                            const __m128i* const B,
586
                                            __m128i* const U,
587
0
                                            __m128i* const V) {
588
0
  const __m128i kRG_u = MK_CST_16(-9719, -19081);
589
0
  const __m128i kGB_u = MK_CST_16(0, 28800);
590
0
  const __m128i kRG_v = MK_CST_16(28800, 0);
591
0
  const __m128i kGB_v = MK_CST_16(-24116, -4684);
592
0
  const __m128i kHALF_UV = _mm_set1_epi32(((128 << YUV_FIX) + YUV_HALF) << 2);
593
594
0
  const __m128i RG_lo = _mm_unpacklo_epi16(*R, *G);
595
0
  const __m128i RG_hi = _mm_unpackhi_epi16(*R, *G);
596
0
  const __m128i GB_lo = _mm_unpacklo_epi16(*G, *B);
597
0
  const __m128i GB_hi = _mm_unpackhi_epi16(*G, *B);
598
0
  TRANSFORM(RG_lo, RG_hi, GB_lo, GB_hi, kRG_u, kGB_u, kHALF_UV, YUV_FIX + 2,
599
0
            *U);
600
0
  TRANSFORM(RG_lo, RG_hi, GB_lo, GB_hi, kRG_v, kGB_v, kHALF_UV, YUV_FIX + 2,
601
0
            *V);
602
0
}
603
604
#undef MK_CST_16
605
#undef TRANSFORM
606
607
static WEBP_INLINE void ConvertRGBToYHelper_SSE2(
608
    const __m128i* const rgb_plane /*in[6]*/, int swap_rb, int* i,
609
0
    uint8_t* WEBP_RESTRICT y) {
610
0
  int j;
611
612
0
  for (j = 0; j < 2; ++j, *i += 16) {
613
0
    const __m128i zero = _mm_setzero_si128();
614
0
    __m128i r, g, b, Y0, Y1;
615
616
    // Convert to 16-bit Y.
617
0
    r = _mm_unpacklo_epi8(rgb_plane[(swap_rb ? 4 : 0) + j], zero);
618
0
    g = _mm_unpacklo_epi8(rgb_plane[2 + j], zero);
619
0
    b = _mm_unpacklo_epi8(rgb_plane[(swap_rb ? 0 : 4) + j], zero);
620
0
    ConvertRGBToYImpl_SSE2(&r, &g, &b, &Y0);
621
622
    // Convert to 16-bit Y.
623
0
    r = _mm_unpackhi_epi8(rgb_plane[(swap_rb ? 4 : 0) + j], zero);
624
0
    g = _mm_unpackhi_epi8(rgb_plane[2 + j], zero);
625
0
    b = _mm_unpackhi_epi8(rgb_plane[(swap_rb ? 0 : 4) + j], zero);
626
0
    ConvertRGBToYImpl_SSE2(&r, &g, &b, &Y1);
627
628
    // Cast to 8-bit and store.
629
0
    STORE_16(_mm_packus_epi16(Y0, Y1), y + *i);
630
0
  }
631
0
}
632
633
static void ConvertRGBToY_SSE2(const uint8_t* WEBP_RESTRICT rgb,
634
0
                               uint8_t* WEBP_RESTRICT y, int width, int step) {
635
0
  const int max_width = width & ~31;
636
0
  int i;
637
0
  __m128i rgb_plane[6];
638
0
  if (step == 3) {
639
0
    for (i = 0; i < max_width; rgb += 3 * 16 * 2) {
640
0
      RGBPackedToPlanar_SSE2(rgb, rgb_plane);
641
0
      ConvertRGBToYHelper_SSE2(rgb_plane, /*swap_rb=*/0, &i, y);
642
0
    }
643
0
  } else {
644
0
    for (i = 0; i < max_width; rgb += 4 * 16 * 2) {
645
0
      RGBAPackedToRGBPlanar_SSE2(rgb, rgb_plane);
646
0
      ConvertRGBToYHelper_SSE2(rgb_plane, /*swap_rb=*/0, &i, y);
647
0
    }
648
0
  }
649
0
  for (; i < width; ++i, rgb += step) {  // left-over
650
0
    y[i] = VP8RGBToY(rgb[0], rgb[1], rgb[2], YUV_HALF);
651
0
  }
652
0
}
653
654
static void ConvertBGRToY_SSE2(const uint8_t* WEBP_RESTRICT bgr,
655
0
                               uint8_t* WEBP_RESTRICT y, int width, int step) {
656
0
  const int max_width = width & ~31;
657
0
  int i;
658
0
  __m128i bgr_plane[6];
659
0
  if (step == 3) {
660
0
    for (i = 0; i < max_width; bgr += 3 * 16 * 2) {
661
0
      RGBPackedToPlanar_SSE2(bgr, bgr_plane);
662
0
      ConvertRGBToYHelper_SSE2(bgr_plane, /*swap_rb=*/1, &i, y);
663
0
    }
664
0
  } else {
665
0
    for (i = 0; i < max_width; bgr += 4 * 16 * 2) {
666
0
      RGBAPackedToRGBPlanar_SSE2(bgr, bgr_plane);
667
0
      ConvertRGBToYHelper_SSE2(bgr_plane, /*swap_rb=*/1, &i, y);
668
0
    }
669
0
  }
670
0
  for (; i < width; ++i, bgr += step) {  // left-over
671
0
    y[i] = VP8RGBToY(bgr[2], bgr[1], bgr[0], YUV_HALF);
672
0
  }
673
0
}
674
675
static void ConvertARGBToY_SSE2(const uint32_t* WEBP_RESTRICT argb,
676
0
                                uint8_t* WEBP_RESTRICT y, int width) {
677
0
  const int max_width = width & ~15;
678
0
  int i;
679
0
  for (i = 0; i < max_width; i += 16) {
680
0
    __m128i Y0, Y1, rgb[6];
681
0
    RGB32PackedToPlanar16_SSE2(&argb[i], rgb);
682
0
    ConvertRGBToYImpl_SSE2(&rgb[0], &rgb[2], &rgb[4], &Y0);
683
0
    ConvertRGBToYImpl_SSE2(&rgb[1], &rgb[3], &rgb[5], &Y1);
684
0
    STORE_16(_mm_packus_epi16(Y0, Y1), y + i);
685
0
  }
686
0
  for (; i < width; ++i) {  // left-over
687
0
    const uint32_t p = argb[i];
688
0
    y[i] =
689
0
        VP8RGBToY((p >> 16) & 0xff, (p >> 8) & 0xff, (p >> 0) & 0xff, YUV_HALF);
690
0
  }
691
0
}
692
693
// Horizontal add (doubled) of two 16b values, result is 16b.
694
// in: A | B | C | D | ... -> out: 2*(A+B) | 2*(C+D) | ...
695
static void HorizontalAddPack_SSE2(const __m128i* const A,
696
0
                                   const __m128i* const B, __m128i* const out) {
697
0
  const __m128i k2 = _mm_set1_epi16(2);
698
0
  const __m128i C = _mm_madd_epi16(*A, k2);
699
0
  const __m128i D = _mm_madd_epi16(*B, k2);
700
0
  *out = _mm_packs_epi32(C, D);
701
0
}
702
703
static void ConvertARGBToUV_SSE2(const uint32_t* WEBP_RESTRICT argb,
704
                                 uint8_t* WEBP_RESTRICT u,
705
                                 uint8_t* WEBP_RESTRICT v, int src_width,
706
0
                                 int do_store) {
707
0
  const int max_width = src_width & ~31;
708
0
  int i;
709
0
  for (i = 0; i < max_width; i += 32, u += 16, v += 16) {
710
0
    __m128i rgb[6], U0, V0, U1, V1;
711
0
    RGB32PackedToPlanar16_SSE2(&argb[i], rgb);
712
0
    HorizontalAddPack_SSE2(&rgb[0], &rgb[1], &rgb[0]);
713
0
    HorizontalAddPack_SSE2(&rgb[2], &rgb[3], &rgb[2]);
714
0
    HorizontalAddPack_SSE2(&rgb[4], &rgb[5], &rgb[4]);
715
0
    ConvertRGBToUV_SSE2(&rgb[0], &rgb[2], &rgb[4], &U0, &V0);
716
717
0
    RGB32PackedToPlanar16_SSE2(&argb[i + 16], rgb);
718
0
    HorizontalAddPack_SSE2(&rgb[0], &rgb[1], &rgb[0]);
719
0
    HorizontalAddPack_SSE2(&rgb[2], &rgb[3], &rgb[2]);
720
0
    HorizontalAddPack_SSE2(&rgb[4], &rgb[5], &rgb[4]);
721
0
    ConvertRGBToUV_SSE2(&rgb[0], &rgb[2], &rgb[4], &U1, &V1);
722
723
0
    U0 = _mm_packus_epi16(U0, U1);
724
0
    V0 = _mm_packus_epi16(V0, V1);
725
0
    if (!do_store) {
726
0
      const __m128i prev_u = LOAD_16(u);
727
0
      const __m128i prev_v = LOAD_16(v);
728
0
      U0 = _mm_avg_epu8(U0, prev_u);
729
0
      V0 = _mm_avg_epu8(V0, prev_v);
730
0
    }
731
0
    STORE_16(U0, u);
732
0
    STORE_16(V0, v);
733
0
  }
734
0
  if (i < src_width) {  // left-over
735
0
    WebPConvertARGBToUV_C(argb + i, u, v, src_width - i, do_store);
736
0
  }
737
0
}
738
739
// Convert 16 packed ARGB 16b-values to r[], g[], b[]
740
static WEBP_INLINE void RGBA32PackedToPlanar_16b_SSE2(
741
    const uint16_t* WEBP_RESTRICT const rgbx, __m128i* const r,
742
0
    __m128i* const g, __m128i* const b) {
743
0
  const __m128i in0 = LOAD_16(rgbx + 0);   // r0 | g0 | b0 |x| r1 | g1 | b1 |x
744
0
  const __m128i in1 = LOAD_16(rgbx + 8);   // r2 | g2 | b2 |x| r3 | g3 | b3 |x
745
0
  const __m128i in2 = LOAD_16(rgbx + 16);  // r4 | ...
746
0
  const __m128i in3 = LOAD_16(rgbx + 24);  // r6 | ...
747
  // column-wise transpose
748
0
  const __m128i A0 = _mm_unpacklo_epi16(in0, in1);
749
0
  const __m128i A1 = _mm_unpackhi_epi16(in0, in1);
750
0
  const __m128i A2 = _mm_unpacklo_epi16(in2, in3);
751
0
  const __m128i A3 = _mm_unpackhi_epi16(in2, in3);
752
0
  const __m128i B0 = _mm_unpacklo_epi16(A0, A1);  // r0 r1 r2 r3 | g0 g1 ..
753
0
  const __m128i B1 = _mm_unpackhi_epi16(A0, A1);  // b0 b1 b2 b3 | x x x x
754
0
  const __m128i B2 = _mm_unpacklo_epi16(A2, A3);  // r4 r5 r6 r7 | g4 g5 ..
755
0
  const __m128i B3 = _mm_unpackhi_epi16(A2, A3);  // b4 b5 b6 b7 | x x x x
756
0
  *r = _mm_unpacklo_epi64(B0, B2);
757
0
  *g = _mm_unpackhi_epi64(B0, B2);
758
0
  *b = _mm_unpacklo_epi64(B1, B3);
759
0
}
760
761
static void ConvertRGBA32ToUV_SSE2(const uint16_t* WEBP_RESTRICT rgb,
762
                                   uint8_t* WEBP_RESTRICT u,
763
0
                                   uint8_t* WEBP_RESTRICT v, int width) {
764
0
  const int max_width = width & ~15;
765
0
  const uint16_t* const last_rgb = rgb + 4 * max_width;
766
0
  while (rgb < last_rgb) {
767
0
    __m128i r, g, b, U0, V0, U1, V1;
768
0
    RGBA32PackedToPlanar_16b_SSE2(rgb + 0, &r, &g, &b);
769
0
    ConvertRGBToUV_SSE2(&r, &g, &b, &U0, &V0);
770
0
    RGBA32PackedToPlanar_16b_SSE2(rgb + 32, &r, &g, &b);
771
0
    ConvertRGBToUV_SSE2(&r, &g, &b, &U1, &V1);
772
0
    STORE_16(_mm_packus_epi16(U0, U1), u);
773
0
    STORE_16(_mm_packus_epi16(V0, V1), v);
774
0
    u += 16;
775
0
    v += 16;
776
0
    rgb += 2 * 32;
777
0
  }
778
0
  if (max_width < width) {  // left-over
779
0
    WebPConvertRGBA32ToUV_C(rgb, u, v, width - max_width);
780
0
  }
781
0
}
782
783
//------------------------------------------------------------------------------
784
785
extern void WebPInitConvertARGBToYUVSSE2(void);
786
787
0
WEBP_TSAN_IGNORE_FUNCTION void WebPInitConvertARGBToYUVSSE2(void) {
788
0
  WebPConvertARGBToY = ConvertARGBToY_SSE2;
789
0
  WebPConvertARGBToUV = ConvertARGBToUV_SSE2;
790
791
0
  WebPConvertRGBToY = ConvertRGBToY_SSE2;
792
0
  WebPConvertBGRToY = ConvertBGRToY_SSE2;
793
794
0
  WebPConvertRGBA32ToUV = ConvertRGBA32ToUV_SSE2;
795
0
}
796
797
#else  // !WEBP_USE_SSE2
798
799
WEBP_DSP_INIT_STUB(WebPInitSamplersSSE2)
800
WEBP_DSP_INIT_STUB(WebPInitConvertARGBToYUVSSE2)
801
802
#endif  // WEBP_USE_SSE2