Home | History | Annotate | Download | only in dsp
      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 // SSE2 variant of methods for lossless decoder
     11 //
     12 // Author: Skal (pascal.massimino (at) gmail.com)
     13 
     14 #include "./dsp.h"
     15 
     16 #if defined(WEBP_USE_SSE2)
     17 
     18 #include "./common_sse2.h"
     19 #include "./lossless.h"
     20 #include "./lossless_common.h"
     21 #include <assert.h>
     22 #include <emmintrin.h>
     23 
     24 //------------------------------------------------------------------------------
     25 // Predictor Transform
     26 
     27 static WEBP_INLINE uint32_t ClampedAddSubtractFull(uint32_t c0, uint32_t c1,
     28                                                    uint32_t c2) {
     29   const __m128i zero = _mm_setzero_si128();
     30   const __m128i C0 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(c0), zero);
     31   const __m128i C1 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(c1), zero);
     32   const __m128i C2 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(c2), zero);
     33   const __m128i V1 = _mm_add_epi16(C0, C1);
     34   const __m128i V2 = _mm_sub_epi16(V1, C2);
     35   const __m128i b = _mm_packus_epi16(V2, V2);
     36   const uint32_t output = _mm_cvtsi128_si32(b);
     37   return output;
     38 }
     39 
     40 static WEBP_INLINE uint32_t ClampedAddSubtractHalf(uint32_t c0, uint32_t c1,
     41                                                    uint32_t c2) {
     42   const __m128i zero = _mm_setzero_si128();
     43   const __m128i C0 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(c0), zero);
     44   const __m128i C1 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(c1), zero);
     45   const __m128i B0 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(c2), zero);
     46   const __m128i avg = _mm_add_epi16(C1, C0);
     47   const __m128i A0 = _mm_srli_epi16(avg, 1);
     48   const __m128i A1 = _mm_sub_epi16(A0, B0);
     49   const __m128i BgtA = _mm_cmpgt_epi16(B0, A0);
     50   const __m128i A2 = _mm_sub_epi16(A1, BgtA);
     51   const __m128i A3 = _mm_srai_epi16(A2, 1);
     52   const __m128i A4 = _mm_add_epi16(A0, A3);
     53   const __m128i A5 = _mm_packus_epi16(A4, A4);
     54   const uint32_t output = _mm_cvtsi128_si32(A5);
     55   return output;
     56 }
     57 
     58 static WEBP_INLINE uint32_t Select(uint32_t a, uint32_t b, uint32_t c) {
     59   int pa_minus_pb;
     60   const __m128i zero = _mm_setzero_si128();
     61   const __m128i A0 = _mm_cvtsi32_si128(a);
     62   const __m128i B0 = _mm_cvtsi32_si128(b);
     63   const __m128i C0 = _mm_cvtsi32_si128(c);
     64   const __m128i AC0 = _mm_subs_epu8(A0, C0);
     65   const __m128i CA0 = _mm_subs_epu8(C0, A0);
     66   const __m128i BC0 = _mm_subs_epu8(B0, C0);
     67   const __m128i CB0 = _mm_subs_epu8(C0, B0);
     68   const __m128i AC = _mm_or_si128(AC0, CA0);
     69   const __m128i BC = _mm_or_si128(BC0, CB0);
     70   const __m128i pa = _mm_unpacklo_epi8(AC, zero);  // |a - c|
     71   const __m128i pb = _mm_unpacklo_epi8(BC, zero);  // |b - c|
     72   const __m128i diff = _mm_sub_epi16(pb, pa);
     73   {
     74     int16_t out[8];
     75     _mm_storeu_si128((__m128i*)out, diff);
     76     pa_minus_pb = out[0] + out[1] + out[2] + out[3];
     77   }
     78   return (pa_minus_pb <= 0) ? a : b;
     79 }
     80 
     81 static WEBP_INLINE void Average2_m128i(const __m128i* const a0,
     82                                        const __m128i* const a1,
     83                                        __m128i* const avg) {
     84   // (a + b) >> 1 = ((a + b + 1) >> 1) - ((a ^ b) & 1)
     85   const __m128i ones = _mm_set1_epi8(1);
     86   const __m128i avg1 = _mm_avg_epu8(*a0, *a1);
     87   const __m128i one = _mm_and_si128(_mm_xor_si128(*a0, *a1), ones);
     88   *avg = _mm_sub_epi8(avg1, one);
     89 }
     90 
     91 static WEBP_INLINE void Average2_uint32(const uint32_t a0, const uint32_t a1,
     92                                         __m128i* const avg) {
     93   // (a + b) >> 1 = ((a + b + 1) >> 1) - ((a ^ b) & 1)
     94   const __m128i ones = _mm_set1_epi8(1);
     95   const __m128i A0 = _mm_cvtsi32_si128(a0);
     96   const __m128i A1 = _mm_cvtsi32_si128(a1);
     97   const __m128i avg1 = _mm_avg_epu8(A0, A1);
     98   const __m128i one = _mm_and_si128(_mm_xor_si128(A0, A1), ones);
     99   *avg = _mm_sub_epi8(avg1, one);
    100 }
    101 
    102 static WEBP_INLINE __m128i Average2_uint32_16(uint32_t a0, uint32_t a1) {
    103   const __m128i zero = _mm_setzero_si128();
    104   const __m128i A0 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(a0), zero);
    105   const __m128i A1 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(a1), zero);
    106   const __m128i sum = _mm_add_epi16(A1, A0);
    107   return _mm_srli_epi16(sum, 1);
    108 }
    109 
    110 static WEBP_INLINE uint32_t Average2(uint32_t a0, uint32_t a1) {
    111   __m128i output;
    112   Average2_uint32(a0, a1, &output);
    113   return _mm_cvtsi128_si32(output);
    114 }
    115 
    116 static WEBP_INLINE uint32_t Average3(uint32_t a0, uint32_t a1, uint32_t a2) {
    117   const __m128i zero = _mm_setzero_si128();
    118   const __m128i avg1 = Average2_uint32_16(a0, a2);
    119   const __m128i A1 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(a1), zero);
    120   const __m128i sum = _mm_add_epi16(avg1, A1);
    121   const __m128i avg2 = _mm_srli_epi16(sum, 1);
    122   const __m128i A2 = _mm_packus_epi16(avg2, avg2);
    123   const uint32_t output = _mm_cvtsi128_si32(A2);
    124   return output;
    125 }
    126 
    127 static WEBP_INLINE uint32_t Average4(uint32_t a0, uint32_t a1,
    128                                      uint32_t a2, uint32_t a3) {
    129   const __m128i avg1 = Average2_uint32_16(a0, a1);
    130   const __m128i avg2 = Average2_uint32_16(a2, a3);
    131   const __m128i sum = _mm_add_epi16(avg2, avg1);
    132   const __m128i avg3 = _mm_srli_epi16(sum, 1);
    133   const __m128i A0 = _mm_packus_epi16(avg3, avg3);
    134   const uint32_t output = _mm_cvtsi128_si32(A0);
    135   return output;
    136 }
    137 
    138 static uint32_t Predictor5_SSE2(uint32_t left, const uint32_t* const top) {
    139   const uint32_t pred = Average3(left, top[0], top[1]);
    140   return pred;
    141 }
    142 static uint32_t Predictor6_SSE2(uint32_t left, const uint32_t* const top) {
    143   const uint32_t pred = Average2(left, top[-1]);
    144   return pred;
    145 }
    146 static uint32_t Predictor7_SSE2(uint32_t left, const uint32_t* const top) {
    147   const uint32_t pred = Average2(left, top[0]);
    148   return pred;
    149 }
    150 static uint32_t Predictor8_SSE2(uint32_t left, const uint32_t* const top) {
    151   const uint32_t pred = Average2(top[-1], top[0]);
    152   (void)left;
    153   return pred;
    154 }
    155 static uint32_t Predictor9_SSE2(uint32_t left, const uint32_t* const top) {
    156   const uint32_t pred = Average2(top[0], top[1]);
    157   (void)left;
    158   return pred;
    159 }
    160 static uint32_t Predictor10_SSE2(uint32_t left, const uint32_t* const top) {
    161   const uint32_t pred = Average4(left, top[-1], top[0], top[1]);
    162   return pred;
    163 }
    164 static uint32_t Predictor11_SSE2(uint32_t left, const uint32_t* const top) {
    165   const uint32_t pred = Select(top[0], left, top[-1]);
    166   return pred;
    167 }
    168 static uint32_t Predictor12_SSE2(uint32_t left, const uint32_t* const top) {
    169   const uint32_t pred = ClampedAddSubtractFull(left, top[0], top[-1]);
    170   return pred;
    171 }
    172 static uint32_t Predictor13_SSE2(uint32_t left, const uint32_t* const top) {
    173   const uint32_t pred = ClampedAddSubtractHalf(left, top[0], top[-1]);
    174   return pred;
    175 }
    176 
    177 // Batch versions of those functions.
    178 
    179 // Predictor0: ARGB_BLACK.
    180 static void PredictorAdd0_SSE2(const uint32_t* in, const uint32_t* upper,
    181                                int num_pixels, uint32_t* out) {
    182   int i;
    183   const __m128i black = _mm_set1_epi32(ARGB_BLACK);
    184   for (i = 0; i + 4 <= num_pixels; i += 4) {
    185     const __m128i src = _mm_loadu_si128((const __m128i*)&in[i]);
    186     const __m128i res = _mm_add_epi8(src, black);
    187     _mm_storeu_si128((__m128i*)&out[i], res);
    188   }
    189   if (i != num_pixels) {
    190     VP8LPredictorsAdd_C[0](in + i, upper + i, num_pixels - i, out + i);
    191   }
    192 }
    193 
    194 // Predictor1: left.
    195 static void PredictorAdd1_SSE2(const uint32_t* in, const uint32_t* upper,
    196                                int num_pixels, uint32_t* out) {
    197   int i;
    198   __m128i prev = _mm_set1_epi32(out[-1]);
    199   for (i = 0; i + 4 <= num_pixels; i += 4) {
    200     // a | b | c | d
    201     const __m128i src = _mm_loadu_si128((const __m128i*)&in[i]);
    202     // 0 | a | b | c
    203     const __m128i shift0 = _mm_slli_si128(src, 4);
    204     // a | a + b | b + c | c + d
    205     const __m128i sum0 = _mm_add_epi8(src, shift0);
    206     // 0 | 0 | a | a + b
    207     const __m128i shift1 = _mm_slli_si128(sum0, 8);
    208     // a | a + b | a + b + c | a + b + c + d
    209     const __m128i sum1 = _mm_add_epi8(sum0, shift1);
    210     const __m128i res = _mm_add_epi8(sum1, prev);
    211     _mm_storeu_si128((__m128i*)&out[i], res);
    212     // replicate prev output on the four lanes
    213     prev = _mm_shuffle_epi32(res, (3 << 0) | (3 << 2) | (3 << 4) | (3 << 6));
    214   }
    215   if (i != num_pixels) {
    216     VP8LPredictorsAdd_C[1](in + i, upper + i, num_pixels - i, out + i);
    217   }
    218 }
    219 
    220 // Macro that adds 32-bit integers from IN using mod 256 arithmetic
    221 // per 8 bit channel.
    222 #define GENERATE_PREDICTOR_1(X, IN)                                           \
    223 static void PredictorAdd##X##_SSE2(const uint32_t* in, const uint32_t* upper, \
    224                                   int num_pixels, uint32_t* out) {            \
    225   int i;                                                                      \
    226   for (i = 0; i + 4 <= num_pixels; i += 4) {                                  \
    227     const __m128i src = _mm_loadu_si128((const __m128i*)&in[i]);              \
    228     const __m128i other = _mm_loadu_si128((const __m128i*)&(IN));             \
    229     const __m128i res = _mm_add_epi8(src, other);                             \
    230     _mm_storeu_si128((__m128i*)&out[i], res);                                 \
    231   }                                                                           \
    232   if (i != num_pixels) {                                                      \
    233     VP8LPredictorsAdd_C[(X)](in + i, upper + i, num_pixels - i, out + i);     \
    234   }                                                                           \
    235 }
    236 
    237 // Predictor2: Top.
    238 GENERATE_PREDICTOR_1(2, upper[i])
    239 // Predictor3: Top-right.
    240 GENERATE_PREDICTOR_1(3, upper[i + 1])
    241 // Predictor4: Top-left.
    242 GENERATE_PREDICTOR_1(4, upper[i - 1])
    243 #undef GENERATE_PREDICTOR_1
    244 
    245 // Due to averages with integers, values cannot be accumulated in parallel for
    246 // predictors 5 to 7.
    247 GENERATE_PREDICTOR_ADD(Predictor5_SSE2, PredictorAdd5_SSE2)
    248 GENERATE_PREDICTOR_ADD(Predictor6_SSE2, PredictorAdd6_SSE2)
    249 GENERATE_PREDICTOR_ADD(Predictor7_SSE2, PredictorAdd7_SSE2)
    250 
    251 #define GENERATE_PREDICTOR_2(X, IN)                                           \
    252 static void PredictorAdd##X##_SSE2(const uint32_t* in, const uint32_t* upper, \
    253                                    int num_pixels, uint32_t* out) {           \
    254   int i;                                                                      \
    255   for (i = 0; i + 4 <= num_pixels; i += 4) {                                  \
    256     const __m128i Tother = _mm_loadu_si128((const __m128i*)&(IN));            \
    257     const __m128i T = _mm_loadu_si128((const __m128i*)&upper[i]);             \
    258     const __m128i src = _mm_loadu_si128((const __m128i*)&in[i]);              \
    259     __m128i avg, res;                                                         \
    260     Average2_m128i(&T, &Tother, &avg);                                        \
    261     res = _mm_add_epi8(avg, src);                                             \
    262     _mm_storeu_si128((__m128i*)&out[i], res);                                 \
    263   }                                                                           \
    264   if (i != num_pixels) {                                                      \
    265     VP8LPredictorsAdd_C[(X)](in + i, upper + i, num_pixels - i, out + i);     \
    266   }                                                                           \
    267 }
    268 // Predictor8: average TL T.
    269 GENERATE_PREDICTOR_2(8, upper[i - 1])
    270 // Predictor9: average T TR.
    271 GENERATE_PREDICTOR_2(9, upper[i + 1])
    272 #undef GENERATE_PREDICTOR_2
    273 
    274 // Predictor10: average of (average of (L,TL), average of (T, TR)).
    275 static void PredictorAdd10_SSE2(const uint32_t* in, const uint32_t* upper,
    276                                 int num_pixels, uint32_t* out) {
    277   int i, j;
    278   __m128i L = _mm_cvtsi32_si128(out[-1]);
    279   for (i = 0; i + 4 <= num_pixels; i += 4) {
    280     __m128i src = _mm_loadu_si128((const __m128i*)&in[i]);
    281     __m128i TL = _mm_loadu_si128((const __m128i*)&upper[i - 1]);
    282     const __m128i T = _mm_loadu_si128((const __m128i*)&upper[i]);
    283     const __m128i TR = _mm_loadu_si128((const __m128i*)&upper[i + 1]);
    284     __m128i avgTTR;
    285     Average2_m128i(&T, &TR, &avgTTR);
    286     for (j = 0; j < 4; ++j) {
    287       __m128i avgLTL, avg;
    288       Average2_m128i(&L, &TL, &avgLTL);
    289       Average2_m128i(&avgTTR, &avgLTL, &avg);
    290       L = _mm_add_epi8(avg, src);
    291       out[i + j] = _mm_cvtsi128_si32(L);
    292       // Rotate the pre-computed values for the next iteration.
    293       avgTTR = _mm_srli_si128(avgTTR, 4);
    294       TL = _mm_srli_si128(TL, 4);
    295       src = _mm_srli_si128(src, 4);
    296     }
    297   }
    298   if (i != num_pixels) {
    299     VP8LPredictorsAdd_C[10](in + i, upper + i, num_pixels - i, out + i);
    300   }
    301 }
    302 
    303 // Predictor11: select.
    304 static void GetSumAbsDiff32(const __m128i* const A, const __m128i* const B,
    305                             __m128i* const out) {
    306   // We can unpack with any value on the upper 32 bits, provided it's the same
    307   // on both operands (to that their sum of abs diff is zero). Here we use *A.
    308   const __m128i A_lo = _mm_unpacklo_epi32(*A, *A);
    309   const __m128i B_lo = _mm_unpacklo_epi32(*B, *A);
    310   const __m128i A_hi = _mm_unpackhi_epi32(*A, *A);
    311   const __m128i B_hi = _mm_unpackhi_epi32(*B, *A);
    312   const __m128i s_lo = _mm_sad_epu8(A_lo, B_lo);
    313   const __m128i s_hi = _mm_sad_epu8(A_hi, B_hi);
    314   *out = _mm_packs_epi32(s_lo, s_hi);
    315 }
    316 
    317 static void PredictorAdd11_SSE2(const uint32_t* in, const uint32_t* upper,
    318                                 int num_pixels, uint32_t* out) {
    319   int i, j;
    320   __m128i L = _mm_cvtsi32_si128(out[-1]);
    321   for (i = 0; i + 4 <= num_pixels; i += 4) {
    322     __m128i T = _mm_loadu_si128((const __m128i*)&upper[i]);
    323     __m128i TL = _mm_loadu_si128((const __m128i*)&upper[i - 1]);
    324     __m128i src = _mm_loadu_si128((const __m128i*)&in[i]);
    325     __m128i pa;
    326     GetSumAbsDiff32(&T, &TL, &pa);   // pa = sum |T-TL|
    327     for (j = 0; j < 4; ++j) {
    328       const __m128i L_lo = _mm_unpacklo_epi32(L, L);
    329       const __m128i TL_lo = _mm_unpacklo_epi32(TL, L);
    330       const __m128i pb = _mm_sad_epu8(L_lo, TL_lo);  // pb = sum |L-TL|
    331       const __m128i mask = _mm_cmpgt_epi32(pb, pa);
    332       const __m128i A = _mm_and_si128(mask, L);
    333       const __m128i B = _mm_andnot_si128(mask, T);
    334       const __m128i pred = _mm_or_si128(A, B);    // pred = (L > T)? L : T
    335       L = _mm_add_epi8(src, pred);
    336       out[i + j] = _mm_cvtsi128_si32(L);
    337       // Shift the pre-computed value for the next iteration.
    338       T = _mm_srli_si128(T, 4);
    339       TL = _mm_srli_si128(TL, 4);
    340       src = _mm_srli_si128(src, 4);
    341       pa = _mm_srli_si128(pa, 4);
    342     }
    343   }
    344   if (i != num_pixels) {
    345     VP8LPredictorsAdd_C[11](in + i, upper + i, num_pixels - i, out + i);
    346   }
    347 }
    348 
    349 // Predictor12: ClampedAddSubtractFull.
    350 #define DO_PRED12(DIFF, LANE, OUT)                          \
    351 do {                                                        \
    352   const __m128i all = _mm_add_epi16(L, (DIFF));             \
    353   const __m128i alls = _mm_packus_epi16(all, all);          \
    354   const __m128i res = _mm_add_epi8(src, alls);              \
    355   out[i + (OUT)] = _mm_cvtsi128_si32(res);                  \
    356   L = _mm_unpacklo_epi8(res, zero);                         \
    357   /* Shift the pre-computed value for the next iteration.*/ \
    358   if (LANE == 0) (DIFF) = _mm_srli_si128((DIFF), 8);        \
    359   src = _mm_srli_si128(src, 4);                             \
    360 } while (0)
    361 
    362 static void PredictorAdd12_SSE2(const uint32_t* in, const uint32_t* upper,
    363                                 int num_pixels, uint32_t* out) {
    364   int i;
    365   const __m128i zero = _mm_setzero_si128();
    366   const __m128i L8 = _mm_cvtsi32_si128(out[-1]);
    367   __m128i L = _mm_unpacklo_epi8(L8, zero);
    368   for (i = 0; i + 4 <= num_pixels; i += 4) {
    369     // Load 4 pixels at a time.
    370     __m128i src = _mm_loadu_si128((const __m128i*)&in[i]);
    371     const __m128i T = _mm_loadu_si128((const __m128i*)&upper[i]);
    372     const __m128i T_lo = _mm_unpacklo_epi8(T, zero);
    373     const __m128i T_hi = _mm_unpackhi_epi8(T, zero);
    374     const __m128i TL = _mm_loadu_si128((const __m128i*)&upper[i - 1]);
    375     const __m128i TL_lo = _mm_unpacklo_epi8(TL, zero);
    376     const __m128i TL_hi = _mm_unpackhi_epi8(TL, zero);
    377     __m128i diff_lo = _mm_sub_epi16(T_lo, TL_lo);
    378     __m128i diff_hi = _mm_sub_epi16(T_hi, TL_hi);
    379     DO_PRED12(diff_lo, 0, 0);
    380     DO_PRED12(diff_lo, 1, 1);
    381     DO_PRED12(diff_hi, 0, 2);
    382     DO_PRED12(diff_hi, 1, 3);
    383   }
    384   if (i != num_pixels) {
    385     VP8LPredictorsAdd_C[12](in + i, upper + i, num_pixels - i, out + i);
    386   }
    387 }
    388 #undef DO_PRED12
    389 
    390 // Due to averages with integers, values cannot be accumulated in parallel for
    391 // predictors 13.
    392 GENERATE_PREDICTOR_ADD(Predictor13_SSE2, PredictorAdd13_SSE2)
    393 
    394 //------------------------------------------------------------------------------
    395 // Subtract-Green Transform
    396 
    397 static void AddGreenToBlueAndRed(const uint32_t* const src, int num_pixels,
    398                                  uint32_t* dst) {
    399   int i;
    400   for (i = 0; i + 4 <= num_pixels; i += 4) {
    401     const __m128i in = _mm_loadu_si128((const __m128i*)&src[i]); // argb
    402     const __m128i A = _mm_srli_epi16(in, 8);     // 0 a 0 g
    403     const __m128i B = _mm_shufflelo_epi16(A, _MM_SHUFFLE(2, 2, 0, 0));
    404     const __m128i C = _mm_shufflehi_epi16(B, _MM_SHUFFLE(2, 2, 0, 0));  // 0g0g
    405     const __m128i out = _mm_add_epi8(in, C);
    406     _mm_storeu_si128((__m128i*)&dst[i], out);
    407   }
    408   // fallthrough and finish off with plain-C
    409   if (i != num_pixels) {
    410     VP8LAddGreenToBlueAndRed_C(src + i, num_pixels - i, dst + i);
    411   }
    412 }
    413 
    414 //------------------------------------------------------------------------------
    415 // Color Transform
    416 
    417 static void TransformColorInverse(const VP8LMultipliers* const m,
    418                                   const uint32_t* const src, int num_pixels,
    419                                   uint32_t* dst) {
    420 // sign-extended multiplying constants, pre-shifted by 5.
    421 #define CST(X)  (((int16_t)(m->X << 8)) >> 5)   // sign-extend
    422   const __m128i mults_rb = _mm_set_epi16(
    423       CST(green_to_red_), CST(green_to_blue_),
    424       CST(green_to_red_), CST(green_to_blue_),
    425       CST(green_to_red_), CST(green_to_blue_),
    426       CST(green_to_red_), CST(green_to_blue_));
    427   const __m128i mults_b2 = _mm_set_epi16(
    428       CST(red_to_blue_), 0, CST(red_to_blue_), 0,
    429       CST(red_to_blue_), 0, CST(red_to_blue_), 0);
    430 #undef CST
    431   const __m128i mask_ag = _mm_set1_epi32(0xff00ff00);  // alpha-green masks
    432   int i;
    433   for (i = 0; i + 4 <= num_pixels; i += 4) {
    434     const __m128i in = _mm_loadu_si128((const __m128i*)&src[i]); // argb
    435     const __m128i A = _mm_and_si128(in, mask_ag);     // a   0   g   0
    436     const __m128i B = _mm_shufflelo_epi16(A, _MM_SHUFFLE(2, 2, 0, 0));
    437     const __m128i C = _mm_shufflehi_epi16(B, _MM_SHUFFLE(2, 2, 0, 0));  // g0g0
    438     const __m128i D = _mm_mulhi_epi16(C, mults_rb);    // x dr  x db1
    439     const __m128i E = _mm_add_epi8(in, D);             // x r'  x   b'
    440     const __m128i F = _mm_slli_epi16(E, 8);            // r' 0   b' 0
    441     const __m128i G = _mm_mulhi_epi16(F, mults_b2);    // x db2  0  0
    442     const __m128i H = _mm_srli_epi32(G, 8);            // 0  x db2  0
    443     const __m128i I = _mm_add_epi8(H, F);              // r' x  b'' 0
    444     const __m128i J = _mm_srli_epi16(I, 8);            // 0  r'  0  b''
    445     const __m128i out = _mm_or_si128(J, A);
    446     _mm_storeu_si128((__m128i*)&dst[i], out);
    447   }
    448   // Fall-back to C-version for left-overs.
    449   if (i != num_pixels) {
    450     VP8LTransformColorInverse_C(m, src + i, num_pixels - i, dst + i);
    451   }
    452 }
    453 
    454 //------------------------------------------------------------------------------
    455 // Color-space conversion functions
    456 
    457 static void ConvertBGRAToRGB(const uint32_t* src, int num_pixels,
    458                              uint8_t* dst) {
    459   const __m128i* in = (const __m128i*)src;
    460   __m128i* out = (__m128i*)dst;
    461 
    462   while (num_pixels >= 32) {
    463     // Load the BGRA buffers.
    464     __m128i in0 = _mm_loadu_si128(in + 0);
    465     __m128i in1 = _mm_loadu_si128(in + 1);
    466     __m128i in2 = _mm_loadu_si128(in + 2);
    467     __m128i in3 = _mm_loadu_si128(in + 3);
    468     __m128i in4 = _mm_loadu_si128(in + 4);
    469     __m128i in5 = _mm_loadu_si128(in + 5);
    470     __m128i in6 = _mm_loadu_si128(in + 6);
    471     __m128i in7 = _mm_loadu_si128(in + 7);
    472     VP8L32bToPlanar(&in0, &in1, &in2, &in3);
    473     VP8L32bToPlanar(&in4, &in5, &in6, &in7);
    474     // At this points, in1/in5 contains red only, in2/in6 green only ...
    475     // Pack the colors in 24b RGB.
    476     VP8PlanarTo24b(&in1, &in5, &in2, &in6, &in3, &in7);
    477     _mm_storeu_si128(out + 0, in1);
    478     _mm_storeu_si128(out + 1, in5);
    479     _mm_storeu_si128(out + 2, in2);
    480     _mm_storeu_si128(out + 3, in6);
    481     _mm_storeu_si128(out + 4, in3);
    482     _mm_storeu_si128(out + 5, in7);
    483     in += 8;
    484     out += 6;
    485     num_pixels -= 32;
    486   }
    487   // left-overs
    488   if (num_pixels > 0) {
    489     VP8LConvertBGRAToRGB_C((const uint32_t*)in, num_pixels, (uint8_t*)out);
    490   }
    491 }
    492 
    493 static void ConvertBGRAToRGBA(const uint32_t* src,
    494                               int num_pixels, uint8_t* dst) {
    495   const __m128i* in = (const __m128i*)src;
    496   __m128i* out = (__m128i*)dst;
    497   while (num_pixels >= 8) {
    498     const __m128i bgra0 = _mm_loadu_si128(in++);     // bgra0|bgra1|bgra2|bgra3
    499     const __m128i bgra4 = _mm_loadu_si128(in++);     // bgra4|bgra5|bgra6|bgra7
    500     const __m128i v0l = _mm_unpacklo_epi8(bgra0, bgra4);  // b0b4g0g4r0r4a0a4...
    501     const __m128i v0h = _mm_unpackhi_epi8(bgra0, bgra4);  // b2b6g2g6r2r6a2a6...
    502     const __m128i v1l = _mm_unpacklo_epi8(v0l, v0h);   // b0b2b4b6g0g2g4g6...
    503     const __m128i v1h = _mm_unpackhi_epi8(v0l, v0h);   // b1b3b5b7g1g3g5g7...
    504     const __m128i v2l = _mm_unpacklo_epi8(v1l, v1h);   // b0...b7 | g0...g7
    505     const __m128i v2h = _mm_unpackhi_epi8(v1l, v1h);   // r0...r7 | a0...a7
    506     const __m128i ga0 = _mm_unpackhi_epi64(v2l, v2h);  // g0...g7 | a0...a7
    507     const __m128i rb0 = _mm_unpacklo_epi64(v2h, v2l);  // r0...r7 | b0...b7
    508     const __m128i rg0 = _mm_unpacklo_epi8(rb0, ga0);   // r0g0r1g1 ... r6g6r7g7
    509     const __m128i ba0 = _mm_unpackhi_epi8(rb0, ga0);   // b0a0b1a1 ... b6a6b7a7
    510     const __m128i rgba0 = _mm_unpacklo_epi16(rg0, ba0);  // rgba0|rgba1...
    511     const __m128i rgba4 = _mm_unpackhi_epi16(rg0, ba0);  // rgba4|rgba5...
    512     _mm_storeu_si128(out++, rgba0);
    513     _mm_storeu_si128(out++, rgba4);
    514     num_pixels -= 8;
    515   }
    516   // left-overs
    517   if (num_pixels > 0) {
    518     VP8LConvertBGRAToRGBA_C((const uint32_t*)in, num_pixels, (uint8_t*)out);
    519   }
    520 }
    521 
    522 static void ConvertBGRAToRGBA4444(const uint32_t* src,
    523                                   int num_pixels, uint8_t* dst) {
    524   const __m128i mask_0x0f = _mm_set1_epi8(0x0f);
    525   const __m128i mask_0xf0 = _mm_set1_epi8(0xf0);
    526   const __m128i* in = (const __m128i*)src;
    527   __m128i* out = (__m128i*)dst;
    528   while (num_pixels >= 8) {
    529     const __m128i bgra0 = _mm_loadu_si128(in++);     // bgra0|bgra1|bgra2|bgra3
    530     const __m128i bgra4 = _mm_loadu_si128(in++);     // bgra4|bgra5|bgra6|bgra7
    531     const __m128i v0l = _mm_unpacklo_epi8(bgra0, bgra4);  // b0b4g0g4r0r4a0a4...
    532     const __m128i v0h = _mm_unpackhi_epi8(bgra0, bgra4);  // b2b6g2g6r2r6a2a6...
    533     const __m128i v1l = _mm_unpacklo_epi8(v0l, v0h);    // b0b2b4b6g0g2g4g6...
    534     const __m128i v1h = _mm_unpackhi_epi8(v0l, v0h);    // b1b3b5b7g1g3g5g7...
    535     const __m128i v2l = _mm_unpacklo_epi8(v1l, v1h);    // b0...b7 | g0...g7
    536     const __m128i v2h = _mm_unpackhi_epi8(v1l, v1h);    // r0...r7 | a0...a7
    537     const __m128i ga0 = _mm_unpackhi_epi64(v2l, v2h);   // g0...g7 | a0...a7
    538     const __m128i rb0 = _mm_unpacklo_epi64(v2h, v2l);   // r0...r7 | b0...b7
    539     const __m128i ga1 = _mm_srli_epi16(ga0, 4);         // g0-|g1-|...|a6-|a7-
    540     const __m128i rb1 = _mm_and_si128(rb0, mask_0xf0);  // -r0|-r1|...|-b6|-a7
    541     const __m128i ga2 = _mm_and_si128(ga1, mask_0x0f);  // g0-|g1-|...|a6-|a7-
    542     const __m128i rgba0 = _mm_or_si128(ga2, rb1);       // rg0..rg7 | ba0..ba7
    543     const __m128i rgba1 = _mm_srli_si128(rgba0, 8);     // ba0..ba7 | 0
    544 #ifdef WEBP_SWAP_16BIT_CSP
    545     const __m128i rgba = _mm_unpacklo_epi8(rgba1, rgba0);  // barg0...barg7
    546 #else
    547     const __m128i rgba = _mm_unpacklo_epi8(rgba0, rgba1);  // rgba0...rgba7
    548 #endif
    549     _mm_storeu_si128(out++, rgba);
    550     num_pixels -= 8;
    551   }
    552   // left-overs
    553   if (num_pixels > 0) {
    554     VP8LConvertBGRAToRGBA4444_C((const uint32_t*)in, num_pixels, (uint8_t*)out);
    555   }
    556 }
    557 
    558 static void ConvertBGRAToRGB565(const uint32_t* src,
    559                                 int num_pixels, uint8_t* dst) {
    560   const __m128i mask_0xe0 = _mm_set1_epi8(0xe0);
    561   const __m128i mask_0xf8 = _mm_set1_epi8(0xf8);
    562   const __m128i mask_0x07 = _mm_set1_epi8(0x07);
    563   const __m128i* in = (const __m128i*)src;
    564   __m128i* out = (__m128i*)dst;
    565   while (num_pixels >= 8) {
    566     const __m128i bgra0 = _mm_loadu_si128(in++);     // bgra0|bgra1|bgra2|bgra3
    567     const __m128i bgra4 = _mm_loadu_si128(in++);     // bgra4|bgra5|bgra6|bgra7
    568     const __m128i v0l = _mm_unpacklo_epi8(bgra0, bgra4);  // b0b4g0g4r0r4a0a4...
    569     const __m128i v0h = _mm_unpackhi_epi8(bgra0, bgra4);  // b2b6g2g6r2r6a2a6...
    570     const __m128i v1l = _mm_unpacklo_epi8(v0l, v0h);      // b0b2b4b6g0g2g4g6...
    571     const __m128i v1h = _mm_unpackhi_epi8(v0l, v0h);      // b1b3b5b7g1g3g5g7...
    572     const __m128i v2l = _mm_unpacklo_epi8(v1l, v1h);      // b0...b7 | g0...g7
    573     const __m128i v2h = _mm_unpackhi_epi8(v1l, v1h);      // r0...r7 | a0...a7
    574     const __m128i ga0 = _mm_unpackhi_epi64(v2l, v2h);     // g0...g7 | a0...a7
    575     const __m128i rb0 = _mm_unpacklo_epi64(v2h, v2l);     // r0...r7 | b0...b7
    576     const __m128i rb1 = _mm_and_si128(rb0, mask_0xf8);    // -r0..-r7|-b0..-b7
    577     const __m128i g_lo1 = _mm_srli_epi16(ga0, 5);
    578     const __m128i g_lo2 = _mm_and_si128(g_lo1, mask_0x07);  // g0-...g7-|xx (3b)
    579     const __m128i g_hi1 = _mm_slli_epi16(ga0, 3);
    580     const __m128i g_hi2 = _mm_and_si128(g_hi1, mask_0xe0);  // -g0...-g7|xx (3b)
    581     const __m128i b0 = _mm_srli_si128(rb1, 8);              // -b0...-b7|0
    582     const __m128i rg1 = _mm_or_si128(rb1, g_lo2);           // gr0...gr7|xx
    583     const __m128i b1 = _mm_srli_epi16(b0, 3);
    584     const __m128i gb1 = _mm_or_si128(b1, g_hi2);            // bg0...bg7|xx
    585 #ifdef WEBP_SWAP_16BIT_CSP
    586     const __m128i rgba = _mm_unpacklo_epi8(gb1, rg1);     // rggb0...rggb7
    587 #else
    588     const __m128i rgba = _mm_unpacklo_epi8(rg1, gb1);     // bgrb0...bgrb7
    589 #endif
    590     _mm_storeu_si128(out++, rgba);
    591     num_pixels -= 8;
    592   }
    593   // left-overs
    594   if (num_pixels > 0) {
    595     VP8LConvertBGRAToRGB565_C((const uint32_t*)in, num_pixels, (uint8_t*)out);
    596   }
    597 }
    598 
    599 static void ConvertBGRAToBGR(const uint32_t* src,
    600                              int num_pixels, uint8_t* dst) {
    601   const __m128i mask_l = _mm_set_epi32(0, 0x00ffffff, 0, 0x00ffffff);
    602   const __m128i mask_h = _mm_set_epi32(0x00ffffff, 0, 0x00ffffff, 0);
    603   const __m128i* in = (const __m128i*)src;
    604   const uint8_t* const end = dst + num_pixels * 3;
    605   // the last storel_epi64 below writes 8 bytes starting at offset 18
    606   while (dst + 26 <= end) {
    607     const __m128i bgra0 = _mm_loadu_si128(in++);     // bgra0|bgra1|bgra2|bgra3
    608     const __m128i bgra4 = _mm_loadu_si128(in++);     // bgra4|bgra5|bgra6|bgra7
    609     const __m128i a0l = _mm_and_si128(bgra0, mask_l);   // bgr0|0|bgr0|0
    610     const __m128i a4l = _mm_and_si128(bgra4, mask_l);   // bgr0|0|bgr0|0
    611     const __m128i a0h = _mm_and_si128(bgra0, mask_h);   // 0|bgr0|0|bgr0
    612     const __m128i a4h = _mm_and_si128(bgra4, mask_h);   // 0|bgr0|0|bgr0
    613     const __m128i b0h = _mm_srli_epi64(a0h, 8);         // 000b|gr00|000b|gr00
    614     const __m128i b4h = _mm_srli_epi64(a4h, 8);         // 000b|gr00|000b|gr00
    615     const __m128i c0 = _mm_or_si128(a0l, b0h);          // rgbrgb00|rgbrgb00
    616     const __m128i c4 = _mm_or_si128(a4l, b4h);          // rgbrgb00|rgbrgb00
    617     const __m128i c2 = _mm_srli_si128(c0, 8);
    618     const __m128i c6 = _mm_srli_si128(c4, 8);
    619     _mm_storel_epi64((__m128i*)(dst +   0), c0);
    620     _mm_storel_epi64((__m128i*)(dst +   6), c2);
    621     _mm_storel_epi64((__m128i*)(dst +  12), c4);
    622     _mm_storel_epi64((__m128i*)(dst +  18), c6);
    623     dst += 24;
    624     num_pixels -= 8;
    625   }
    626   // left-overs
    627   if (num_pixels > 0) {
    628     VP8LConvertBGRAToBGR_C((const uint32_t*)in, num_pixels, dst);
    629   }
    630 }
    631 
    632 //------------------------------------------------------------------------------
    633 // Entry point
    634 
    635 extern void VP8LDspInitSSE2(void);
    636 
    637 WEBP_TSAN_IGNORE_FUNCTION void VP8LDspInitSSE2(void) {
    638   VP8LPredictors[5] = Predictor5_SSE2;
    639   VP8LPredictors[6] = Predictor6_SSE2;
    640   VP8LPredictors[7] = Predictor7_SSE2;
    641   VP8LPredictors[8] = Predictor8_SSE2;
    642   VP8LPredictors[9] = Predictor9_SSE2;
    643   VP8LPredictors[10] = Predictor10_SSE2;
    644   VP8LPredictors[11] = Predictor11_SSE2;
    645   VP8LPredictors[12] = Predictor12_SSE2;
    646   VP8LPredictors[13] = Predictor13_SSE2;
    647 
    648   VP8LPredictorsAdd[0] = PredictorAdd0_SSE2;
    649   VP8LPredictorsAdd[1] = PredictorAdd1_SSE2;
    650   VP8LPredictorsAdd[2] = PredictorAdd2_SSE2;
    651   VP8LPredictorsAdd[3] = PredictorAdd3_SSE2;
    652   VP8LPredictorsAdd[4] = PredictorAdd4_SSE2;
    653   VP8LPredictorsAdd[5] = PredictorAdd5_SSE2;
    654   VP8LPredictorsAdd[6] = PredictorAdd6_SSE2;
    655   VP8LPredictorsAdd[7] = PredictorAdd7_SSE2;
    656   VP8LPredictorsAdd[8] = PredictorAdd8_SSE2;
    657   VP8LPredictorsAdd[9] = PredictorAdd9_SSE2;
    658   VP8LPredictorsAdd[10] = PredictorAdd10_SSE2;
    659   VP8LPredictorsAdd[11] = PredictorAdd11_SSE2;
    660   VP8LPredictorsAdd[12] = PredictorAdd12_SSE2;
    661   VP8LPredictorsAdd[13] = PredictorAdd13_SSE2;
    662 
    663   VP8LAddGreenToBlueAndRed = AddGreenToBlueAndRed;
    664   VP8LTransformColorInverse = TransformColorInverse;
    665 
    666   VP8LConvertBGRAToRGB = ConvertBGRAToRGB;
    667   VP8LConvertBGRAToRGBA = ConvertBGRAToRGBA;
    668   VP8LConvertBGRAToRGBA4444 = ConvertBGRAToRGBA4444;
    669   VP8LConvertBGRAToRGB565 = ConvertBGRAToRGB565;
    670   VP8LConvertBGRAToBGR = ConvertBGRAToBGR;
    671 }
    672 
    673 #else  // !WEBP_USE_SSE2
    674 
    675 WEBP_DSP_INIT_STUB(VP8LDspInitSSE2)
    676 
    677 #endif  // WEBP_USE_SSE2
    678