Coverage Report

Created: 2026-09-28 07:02

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libwebp/src/dsp/lossless_avx2.c
Line
Count
Source
1
// Copyright 2025 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
// AVX2 variant of methods for lossless decoder
11
//
12
// Author: Vincent Rabaud (vrabaud@google.com)
13
14
#include "src/dsp/dsp.h"
15
16
#if defined(WEBP_USE_AVX2)
17
18
#include <immintrin.h>
19
#include <stddef.h>
20
21
#include "src/dsp/cpu.h"
22
#include "src/dsp/lossless.h"
23
#include "src/webp/format_constants.h"
24
#include "src/webp/types.h"
25
26
//------------------------------------------------------------------------------
27
// Predictor Transform
28
29
static WEBP_INLINE void Average2_m256i(const __m256i* const a0,
30
                                       const __m256i* const a1,
31
1.24M
                                       __m256i* const avg) {
32
  // (a + b) >> 1 = ((a + b + 1) >> 1) - ((a ^ b) & 1)
33
1.24M
  const __m256i ones = _mm256_set1_epi8(1);
34
1.24M
  const __m256i avg1 = _mm256_avg_epu8(*a0, *a1);
35
1.24M
  const __m256i one = _mm256_and_si256(_mm256_xor_si256(*a0, *a1), ones);
36
1.24M
  *avg = _mm256_sub_epi8(avg1, one);
37
1.24M
}
38
39
// Batch versions of those functions.
40
41
// Predictor0: ARGB_BLACK.
42
static void PredictorAdd0_AVX2(const uint32_t* in, const uint32_t* upper,
43
4.09M
                               int num_pixels, uint32_t* WEBP_RESTRICT out) {
44
4.09M
  int i;
45
4.09M
  const __m256i black = _mm256_set1_epi32((int)ARGB_BLACK);
46
13.1M
  for (i = 0; i + 8 <= num_pixels; i += 8) {
47
9.10M
    const __m256i src = _mm256_loadu_si256((const __m256i*)&in[i]);
48
9.10M
    const __m256i res = _mm256_add_epi8(src, black);
49
9.10M
    _mm256_storeu_si256((__m256i*)&out[i], res);
50
9.10M
  }
51
4.09M
  if (i != num_pixels) {
52
1.37M
    VP8LPredictorsAdd_SSE[0](in + i, NULL, num_pixels - i, out + i);
53
1.37M
  }
54
4.09M
  (void)upper;
55
4.09M
}
56
57
// Predictor1: left.
58
static void PredictorAdd1_AVX2(const uint32_t* in, const uint32_t* upper,
59
2.90M
                               int num_pixels, uint32_t* WEBP_RESTRICT out) {
60
2.90M
  int i;
61
2.90M
  __m256i prev = _mm256_set1_epi32((int)out[-1]);
62
11.8M
  for (i = 0; i + 8 <= num_pixels; i += 8) {
63
    // h | g | f | e | d | c | b | a
64
8.91M
    const __m256i src = _mm256_loadu_si256((const __m256i*)&in[i]);
65
    // g | f | e | 0 | c | b | a | 0
66
8.91M
    const __m256i shift0 = _mm256_slli_si256(src, 4);
67
    // g + h | f + g | e + f | e | c + d | b + c | a + b | a
68
8.91M
    const __m256i sum0 = _mm256_add_epi8(src, shift0);
69
    // e + f | e | 0 | 0 | a + b | a | 0 | 0
70
8.91M
    const __m256i shift1 = _mm256_slli_si256(sum0, 8);
71
    // e + f + g + h | e + f + g | e + f | e | a + b + c + d | a + b + c | a + b
72
    // | a
73
8.91M
    const __m256i sum1 = _mm256_add_epi8(sum0, shift1);
74
    // Add a + b + c + d to the upper lane.
75
8.91M
    const int32_t sum_abcd = _mm256_extract_epi32(sum1, 3);
76
8.91M
    const __m256i sum2 = _mm256_add_epi8(
77
8.91M
        sum1,
78
8.91M
        _mm256_set_epi32(sum_abcd, sum_abcd, sum_abcd, sum_abcd, 0, 0, 0, 0));
79
80
8.91M
    const __m256i res = _mm256_add_epi8(sum2, prev);
81
8.91M
    _mm256_storeu_si256((__m256i*)&out[i], res);
82
    // replicate last res output in prev.
83
8.91M
    prev = _mm256_permutevar8x32_epi32(
84
8.91M
        res, _mm256_set_epi32(7, 7, 7, 7, 7, 7, 7, 7));
85
8.91M
  }
86
2.90M
  if (i != num_pixels) {
87
745k
    VP8LPredictorsAdd_SSE[1](in + i, upper + i, num_pixels - i, out + i);
88
745k
  }
89
2.90M
}
90
91
// Macro that adds 32-bit integers from IN using mod 256 arithmetic
92
// per 8 bit channel.
93
#define GENERATE_PREDICTOR_1(X, IN)                                           \
94
  static void PredictorAdd##X##_AVX2(const uint32_t* in,                      \
95
                                     const uint32_t* upper, int num_pixels,   \
96
10.0k
                                     uint32_t* WEBP_RESTRICT out) {           \
97
10.0k
    int i;                                                                    \
98
196k
    for (i = 0; i + 8 <= num_pixels; i += 8) {                                \
99
186k
      const __m256i src = _mm256_loadu_si256((const __m256i*)&in[i]);         \
100
186k
      const __m256i other = _mm256_loadu_si256((const __m256i*)&(IN));        \
101
186k
      const __m256i res = _mm256_add_epi8(src, other);                        \
102
186k
      _mm256_storeu_si256((__m256i*)&out[i], res);                            \
103
186k
    }                                                                         \
104
10.0k
    if (i != num_pixels) {                                                    \
105
6.40k
      VP8LPredictorsAdd_SSE[(X)](in + i, upper + i, num_pixels - i, out + i); \
106
6.40k
    }                                                                         \
107
10.0k
  }
lossless_avx2.c:PredictorAdd2_AVX2
Line
Count
Source
96
3.66k
                                     uint32_t* WEBP_RESTRICT out) {           \
97
3.66k
    int i;                                                                    \
98
33.0k
    for (i = 0; i + 8 <= num_pixels; i += 8) {                                \
99
29.3k
      const __m256i src = _mm256_loadu_si256((const __m256i*)&in[i]);         \
100
29.3k
      const __m256i other = _mm256_loadu_si256((const __m256i*)&(IN));        \
101
29.3k
      const __m256i res = _mm256_add_epi8(src, other);                        \
102
29.3k
      _mm256_storeu_si256((__m256i*)&out[i], res);                            \
103
29.3k
    }                                                                         \
104
3.66k
    if (i != num_pixels) {                                                    \
105
2.06k
      VP8LPredictorsAdd_SSE[(X)](in + i, upper + i, num_pixels - i, out + i); \
106
2.06k
    }                                                                         \
107
3.66k
  }
lossless_avx2.c:PredictorAdd3_AVX2
Line
Count
Source
96
3.40k
                                     uint32_t* WEBP_RESTRICT out) {           \
97
3.40k
    int i;                                                                    \
98
96.1k
    for (i = 0; i + 8 <= num_pixels; i += 8) {                                \
99
92.7k
      const __m256i src = _mm256_loadu_si256((const __m256i*)&in[i]);         \
100
92.7k
      const __m256i other = _mm256_loadu_si256((const __m256i*)&(IN));        \
101
92.7k
      const __m256i res = _mm256_add_epi8(src, other);                        \
102
92.7k
      _mm256_storeu_si256((__m256i*)&out[i], res);                            \
103
92.7k
    }                                                                         \
104
3.40k
    if (i != num_pixels) {                                                    \
105
2.37k
      VP8LPredictorsAdd_SSE[(X)](in + i, upper + i, num_pixels - i, out + i); \
106
2.37k
    }                                                                         \
107
3.40k
  }
lossless_avx2.c:PredictorAdd4_AVX2
Line
Count
Source
96
2.99k
                                     uint32_t* WEBP_RESTRICT out) {           \
97
2.99k
    int i;                                                                    \
98
67.4k
    for (i = 0; i + 8 <= num_pixels; i += 8) {                                \
99
64.4k
      const __m256i src = _mm256_loadu_si256((const __m256i*)&in[i]);         \
100
64.4k
      const __m256i other = _mm256_loadu_si256((const __m256i*)&(IN));        \
101
64.4k
      const __m256i res = _mm256_add_epi8(src, other);                        \
102
64.4k
      _mm256_storeu_si256((__m256i*)&out[i], res);                            \
103
64.4k
    }                                                                         \
104
2.99k
    if (i != num_pixels) {                                                    \
105
1.96k
      VP8LPredictorsAdd_SSE[(X)](in + i, upper + i, num_pixels - i, out + i); \
106
1.96k
    }                                                                         \
107
2.99k
  }
108
109
// Predictor2: Top.
110
GENERATE_PREDICTOR_1(2, upper[i])
111
// Predictor3: Top-right.
112
GENERATE_PREDICTOR_1(3, upper[i + 1])
113
// Predictor4: Top-left.
114
GENERATE_PREDICTOR_1(4, upper[i - 1])
115
#undef GENERATE_PREDICTOR_1
116
117
// Due to averages with integers, values cannot be accumulated in parallel for
118
// predictors 5 to 7.
119
120
#define GENERATE_PREDICTOR_2(X, IN)                                           \
121
  static void PredictorAdd##X##_AVX2(const uint32_t* in,                      \
122
                                     const uint32_t* upper, int num_pixels,   \
123
9.34k
                                     uint32_t* WEBP_RESTRICT out) {           \
124
9.34k
    int i;                                                                    \
125
266k
    for (i = 0; i + 8 <= num_pixels; i += 8) {                                \
126
256k
      const __m256i Tother = _mm256_loadu_si256((const __m256i*)&(IN));       \
127
256k
      const __m256i T = _mm256_loadu_si256((const __m256i*)&upper[i]);        \
128
256k
      const __m256i src = _mm256_loadu_si256((const __m256i*)&in[i]);         \
129
256k
      __m256i avg, res;                                                       \
130
256k
      Average2_m256i(&T, &Tother, &avg);                                      \
131
256k
      res = _mm256_add_epi8(avg, src);                                        \
132
256k
      _mm256_storeu_si256((__m256i*)&out[i], res);                            \
133
256k
    }                                                                         \
134
9.34k
    if (i != num_pixels) {                                                    \
135
5.16k
      VP8LPredictorsAdd_SSE[(X)](in + i, upper + i, num_pixels - i, out + i); \
136
5.16k
    }                                                                         \
137
9.34k
  }
lossless_avx2.c:PredictorAdd8_AVX2
Line
Count
Source
123
5.08k
                                     uint32_t* WEBP_RESTRICT out) {           \
124
5.08k
    int i;                                                                    \
125
144k
    for (i = 0; i + 8 <= num_pixels; i += 8) {                                \
126
139k
      const __m256i Tother = _mm256_loadu_si256((const __m256i*)&(IN));       \
127
139k
      const __m256i T = _mm256_loadu_si256((const __m256i*)&upper[i]);        \
128
139k
      const __m256i src = _mm256_loadu_si256((const __m256i*)&in[i]);         \
129
139k
      __m256i avg, res;                                                       \
130
139k
      Average2_m256i(&T, &Tother, &avg);                                      \
131
139k
      res = _mm256_add_epi8(avg, src);                                        \
132
139k
      _mm256_storeu_si256((__m256i*)&out[i], res);                            \
133
139k
    }                                                                         \
134
5.08k
    if (i != num_pixels) {                                                    \
135
2.77k
      VP8LPredictorsAdd_SSE[(X)](in + i, upper + i, num_pixels - i, out + i); \
136
2.77k
    }                                                                         \
137
5.08k
  }
lossless_avx2.c:PredictorAdd9_AVX2
Line
Count
Source
123
4.25k
                                     uint32_t* WEBP_RESTRICT out) {           \
124
4.25k
    int i;                                                                    \
125
121k
    for (i = 0; i + 8 <= num_pixels; i += 8) {                                \
126
117k
      const __m256i Tother = _mm256_loadu_si256((const __m256i*)&(IN));       \
127
117k
      const __m256i T = _mm256_loadu_si256((const __m256i*)&upper[i]);        \
128
117k
      const __m256i src = _mm256_loadu_si256((const __m256i*)&in[i]);         \
129
117k
      __m256i avg, res;                                                       \
130
117k
      Average2_m256i(&T, &Tother, &avg);                                      \
131
117k
      res = _mm256_add_epi8(avg, src);                                        \
132
117k
      _mm256_storeu_si256((__m256i*)&out[i], res);                            \
133
117k
    }                                                                         \
134
4.25k
    if (i != num_pixels) {                                                    \
135
2.39k
      VP8LPredictorsAdd_SSE[(X)](in + i, upper + i, num_pixels - i, out + i); \
136
2.39k
    }                                                                         \
137
4.25k
  }
138
// Predictor8: average TL T.
139
GENERATE_PREDICTOR_2(8, upper[i - 1])
140
// Predictor9: average T TR.
141
GENERATE_PREDICTOR_2(9, upper[i + 1])
142
#undef GENERATE_PREDICTOR_2
143
144
// Predictor10: average of (average of (L,TL), average of (T, TR)).
145
#define DO_PRED10(OUT)                                  \
146
464k
  do {                                                  \
147
464k
    __m256i avgLTL, avg;                                \
148
464k
    Average2_m256i(&L, &TL, &avgLTL);                   \
149
464k
    Average2_m256i(&avgTTR, &avgLTL, &avg);             \
150
464k
    L = _mm256_add_epi8(avg, src);                      \
151
464k
    out[i + (OUT)] = (uint32_t)_mm256_cvtsi256_si32(L); \
152
464k
  } while (0)
153
154
#define DO_PRED10_SHIFT                                         \
155
464k
  do {                                                          \
156
464k
    /* Rotate the pre-computed values for the next iteration.*/ \
157
464k
    avgTTR = _mm256_srli_si256(avgTTR, 4);                      \
158
464k
    TL = _mm256_srli_si256(TL, 4);                              \
159
464k
    src = _mm256_srli_si256(src, 4);                            \
160
464k
  } while (0)
161
162
static void PredictorAdd10_AVX2(const uint32_t* in, const uint32_t* upper,
163
3.51k
                                int num_pixels, uint32_t* WEBP_RESTRICT out) {
164
3.51k
  int i, j;
165
3.51k
  __m256i L = _mm256_setr_epi32((int)out[-1], 0, 0, 0, 0, 0, 0, 0);
166
61.5k
  for (i = 0; i + 8 <= num_pixels; i += 8) {
167
58.0k
    __m256i src = _mm256_loadu_si256((const __m256i*)&in[i]);
168
58.0k
    __m256i TL = _mm256_loadu_si256((const __m256i*)&upper[i - 1]);
169
58.0k
    const __m256i T = _mm256_loadu_si256((const __m256i*)&upper[i]);
170
58.0k
    const __m256i TR = _mm256_loadu_si256((const __m256i*)&upper[i + 1]);
171
58.0k
    __m256i avgTTR;
172
58.0k
    Average2_m256i(&T, &TR, &avgTTR);
173
58.0k
    {
174
58.0k
      const __m256i avgTTR_bak = avgTTR;
175
58.0k
      const __m256i TL_bak = TL;
176
58.0k
      const __m256i src_bak = src;
177
290k
      for (j = 0; j < 4; ++j) {
178
232k
        DO_PRED10(j);
179
232k
        DO_PRED10_SHIFT;
180
232k
      }
181
58.0k
      avgTTR = _mm256_permute2x128_si256(avgTTR_bak, avgTTR_bak, 1);
182
58.0k
      TL = _mm256_permute2x128_si256(TL_bak, TL_bak, 1);
183
58.0k
      src = _mm256_permute2x128_si256(src_bak, src_bak, 1);
184
290k
      for (; j < 8; ++j) {
185
232k
        DO_PRED10(j);
186
232k
        DO_PRED10_SHIFT;
187
232k
      }
188
58.0k
    }
189
58.0k
  }
190
3.51k
  if (i != num_pixels) {
191
2.00k
    VP8LPredictorsAdd_SSE[10](in + i, upper + i, num_pixels - i, out + i);
192
2.00k
  }
193
3.51k
}
194
#undef DO_PRED10
195
#undef DO_PRED10_SHIFT
196
197
// Predictor11: select.
198
#define DO_PRED11(OUT)                                                      \
199
1.47M
  do {                                                                      \
200
1.47M
    const __m256i L_lo = _mm256_unpacklo_epi32(L, T);                       \
201
1.47M
    const __m256i TL_lo = _mm256_unpacklo_epi32(TL, T);                     \
202
1.47M
    const __m256i pb = _mm256_sad_epu8(L_lo, TL_lo); /* pb = sum |L-TL|*/   \
203
1.47M
    const __m256i mask = _mm256_cmpgt_epi32(pb, pa);                        \
204
1.47M
    const __m256i A = _mm256_and_si256(mask, L);                            \
205
1.47M
    const __m256i B = _mm256_andnot_si256(mask, T);                         \
206
1.47M
    const __m256i pred = _mm256_or_si256(A, B); /* pred = (pa > b)? L : T*/ \
207
1.47M
    L = _mm256_add_epi8(src, pred);                                         \
208
1.47M
    out[i + (OUT)] = (uint32_t)_mm256_cvtsi256_si32(L);                     \
209
1.47M
  } while (0)
210
211
#define DO_PRED11_SHIFT                                       \
212
1.47M
  do {                                                        \
213
1.47M
    /* Shift the pre-computed value for the next iteration.*/ \
214
1.47M
    T = _mm256_srli_si256(T, 4);                              \
215
1.47M
    TL = _mm256_srli_si256(TL, 4);                            \
216
1.47M
    src = _mm256_srli_si256(src, 4);                          \
217
1.47M
    pa = _mm256_srli_si256(pa, 4);                            \
218
1.47M
  } while (0)
219
220
static void PredictorAdd11_AVX2(const uint32_t* in, const uint32_t* upper,
221
9.76k
                                int num_pixels, uint32_t* WEBP_RESTRICT out) {
222
9.76k
  int i, j;
223
9.76k
  __m256i pa;
224
9.76k
  __m256i L = _mm256_setr_epi32((int)out[-1], 0, 0, 0, 0, 0, 0, 0);
225
194k
  for (i = 0; i + 8 <= num_pixels; i += 8) {
226
184k
    __m256i T = _mm256_loadu_si256((const __m256i*)&upper[i]);
227
184k
    __m256i TL = _mm256_loadu_si256((const __m256i*)&upper[i - 1]);
228
184k
    __m256i src = _mm256_loadu_si256((const __m256i*)&in[i]);
229
184k
    {
230
      // We can unpack with any value on the upper 32 bits, provided it's the
231
      // same on both operands (so that their sum of abs diff is zero). Here we
232
      // use T.
233
184k
      const __m256i T_lo = _mm256_unpacklo_epi32(T, T);
234
184k
      const __m256i TL_lo = _mm256_unpacklo_epi32(TL, T);
235
184k
      const __m256i T_hi = _mm256_unpackhi_epi32(T, T);
236
184k
      const __m256i TL_hi = _mm256_unpackhi_epi32(TL, T);
237
184k
      const __m256i s_lo = _mm256_sad_epu8(T_lo, TL_lo);
238
184k
      const __m256i s_hi = _mm256_sad_epu8(T_hi, TL_hi);
239
184k
      pa = _mm256_packs_epi32(s_lo, s_hi);  // pa = sum |T-TL|
240
184k
    }
241
184k
    {
242
184k
      const __m256i T_bak = T;
243
184k
      const __m256i TL_bak = TL;
244
184k
      const __m256i src_bak = src;
245
184k
      const __m256i pa_bak = pa;
246
924k
      for (j = 0; j < 4; ++j) {
247
739k
        DO_PRED11(j);
248
739k
        DO_PRED11_SHIFT;
249
739k
      }
250
184k
      T = _mm256_permute2x128_si256(T_bak, T_bak, 1);
251
184k
      TL = _mm256_permute2x128_si256(TL_bak, TL_bak, 1);
252
184k
      src = _mm256_permute2x128_si256(src_bak, src_bak, 1);
253
184k
      pa = _mm256_permute2x128_si256(pa_bak, pa_bak, 1);
254
924k
      for (; j < 8; ++j) {
255
739k
        DO_PRED11(j);
256
739k
        DO_PRED11_SHIFT;
257
739k
      }
258
184k
    }
259
184k
  }
260
9.76k
  if (i != num_pixels) {
261
7.73k
    VP8LPredictorsAdd_SSE[11](in + i, upper + i, num_pixels - i, out + i);
262
7.73k
  }
263
9.76k
}
264
#undef DO_PRED11
265
#undef DO_PRED11_SHIFT
266
267
// Predictor12: ClampedAddSubtractFull.
268
#define DO_PRED12(DIFF, OUT)                              \
269
1.70M
  do {                                                    \
270
1.70M
    const __m256i all = _mm256_add_epi16(L, (DIFF));      \
271
1.70M
    const __m256i alls = _mm256_packus_epi16(all, all);   \
272
1.70M
    const __m256i res = _mm256_add_epi8(src, alls);       \
273
1.70M
    out[i + (OUT)] = (uint32_t)_mm256_cvtsi256_si32(res); \
274
1.70M
    L = _mm256_unpacklo_epi8(res, zero);                  \
275
1.70M
  } while (0)
276
277
#define DO_PRED12_SHIFT(DIFF, LANE)                           \
278
1.49M
  do {                                                        \
279
1.49M
    /* Shift the pre-computed value for the next iteration.*/ \
280
1.49M
    if ((LANE) == 0) (DIFF) = _mm256_srli_si256(DIFF, 8);     \
281
1.49M
    src = _mm256_srli_si256(src, 4);                          \
282
1.49M
  } while (0)
283
284
static void PredictorAdd12_AVX2(const uint32_t* in, const uint32_t* upper,
285
6.36k
                                int num_pixels, uint32_t* WEBP_RESTRICT out) {
286
6.36k
  int i;
287
6.36k
  const __m256i zero = _mm256_setzero_si256();
288
6.36k
  const __m256i L8 = _mm256_setr_epi32((int)out[-1], 0, 0, 0, 0, 0, 0, 0);
289
6.36k
  __m256i L = _mm256_unpacklo_epi8(L8, zero);
290
219k
  for (i = 0; i + 8 <= num_pixels; i += 8) {
291
    // Load 8 pixels at a time.
292
213k
    __m256i src = _mm256_loadu_si256((const __m256i*)&in[i]);
293
213k
    const __m256i T = _mm256_loadu_si256((const __m256i*)&upper[i]);
294
213k
    const __m256i T_lo = _mm256_unpacklo_epi8(T, zero);
295
213k
    const __m256i T_hi = _mm256_unpackhi_epi8(T, zero);
296
213k
    const __m256i TL = _mm256_loadu_si256((const __m256i*)&upper[i - 1]);
297
213k
    const __m256i TL_lo = _mm256_unpacklo_epi8(TL, zero);
298
213k
    const __m256i TL_hi = _mm256_unpackhi_epi8(TL, zero);
299
213k
    __m256i diff_lo = _mm256_sub_epi16(T_lo, TL_lo);
300
213k
    __m256i diff_hi = _mm256_sub_epi16(T_hi, TL_hi);
301
213k
    const __m256i diff_lo_bak = diff_lo;
302
213k
    const __m256i diff_hi_bak = diff_hi;
303
213k
    const __m256i src_bak = src;
304
213k
    DO_PRED12(diff_lo, 0);
305
213k
    DO_PRED12_SHIFT(diff_lo, 0);
306
213k
    DO_PRED12(diff_lo, 1);
307
213k
    DO_PRED12_SHIFT(diff_lo, 0);
308
213k
    DO_PRED12(diff_hi, 2);
309
213k
    DO_PRED12_SHIFT(diff_hi, 0);
310
213k
    DO_PRED12(diff_hi, 3);
311
213k
    DO_PRED12_SHIFT(diff_hi, 0);
312
313
    // Process the upper lane.
314
213k
    diff_lo = _mm256_permute2x128_si256(diff_lo_bak, diff_lo_bak, 1);
315
213k
    diff_hi = _mm256_permute2x128_si256(diff_hi_bak, diff_hi_bak, 1);
316
213k
    src = _mm256_permute2x128_si256(src_bak, src_bak, 1);
317
318
213k
    DO_PRED12(diff_lo, 4);
319
213k
    DO_PRED12_SHIFT(diff_lo, 0);
320
213k
    DO_PRED12(diff_lo, 5);
321
213k
    DO_PRED12_SHIFT(diff_lo, 1);
322
213k
    DO_PRED12(diff_hi, 6);
323
213k
    DO_PRED12_SHIFT(diff_hi, 0);
324
213k
    DO_PRED12(diff_hi, 7);
325
213k
  }
326
6.36k
  if (i != num_pixels) {
327
4.45k
    VP8LPredictorsAdd_SSE[12](in + i, upper + i, num_pixels - i, out + i);
328
4.45k
  }
329
6.36k
}
330
#undef DO_PRED12
331
#undef DO_PRED12_SHIFT
332
333
// Due to averages with integers, values cannot be accumulated in parallel for
334
// predictors 13.
335
336
//------------------------------------------------------------------------------
337
// Subtract-Green Transform
338
339
static void AddGreenToBlueAndRed_AVX2(const uint32_t* const src, int num_pixels,
340
7.35k
                                      uint32_t* dst) {
341
7.35k
  int i;
342
7.35k
  const __m256i kCstShuffle = _mm256_set_epi8(
343
7.35k
      -1, 29, -1, 29, -1, 25, -1, 25, -1, 21, -1, 21, -1, 17, -1, 17, -1, 13,
344
7.35k
      -1, 13, -1, 9, -1, 9, -1, 5, -1, 5, -1, 1, -1, 1);
345
19.5M
  for (i = 0; i + 8 <= num_pixels; i += 8) {
346
19.5M
    const __m256i in = _mm256_loadu_si256((const __m256i*)&src[i]);  // argb
347
19.5M
    const __m256i in_0g0g = _mm256_shuffle_epi8(in, kCstShuffle);    // 0g0g
348
19.5M
    const __m256i out = _mm256_add_epi8(in, in_0g0g);
349
19.5M
    _mm256_storeu_si256((__m256i*)&dst[i], out);
350
19.5M
  }
351
  // fallthrough and finish off with SSE.
352
7.35k
  if (i != num_pixels) {
353
88
    VP8LAddGreenToBlueAndRed_SSE(src + i, num_pixels - i, dst + i);
354
88
  }
355
7.35k
}
356
357
//------------------------------------------------------------------------------
358
// Color Transform
359
360
static void TransformColorInverse_AVX2(const VP8LMultipliers* const m,
361
                                       const uint32_t* const src,
362
8.31M
                                       int num_pixels, uint32_t* dst) {
363
// sign-extended multiplying constants, pre-shifted by 5.
364
24.9M
#define CST(X) (((int16_t)(m->X << 8)) >> 5)  // sign-extend
365
8.31M
  const __m256i mults_rb = _mm256_set1_epi32(
366
8.31M
      (int)((uint32_t)CST(green_to_red) << 16 | (CST(green_to_blue) & 0xffff)));
367
8.31M
  const __m256i mults_b2 = _mm256_set1_epi32(CST(red_to_blue));
368
8.31M
#undef CST
369
8.31M
  const __m256i mask_ag = _mm256_set1_epi32((int)0xff00ff00);
370
8.31M
  const __m256i perm1 = _mm256_setr_epi8(
371
8.31M
      -1, 1, -1, 1, -1, 5, -1, 5, -1, 9, -1, 9, -1, 13, -1, 13, -1, 17, -1, 17,
372
8.31M
      -1, 21, -1, 21, -1, 25, -1, 25, -1, 29, -1, 29);
373
8.31M
  const __m256i perm2 = _mm256_setr_epi8(
374
8.31M
      -1, 2, -1, -1, -1, 6, -1, -1, -1, 10, -1, -1, -1, 14, -1, -1, -1, 18, -1,
375
8.31M
      -1, -1, 22, -1, -1, -1, 26, -1, -1, -1, 30, -1, -1);
376
8.31M
  int i;
377
20.2M
  for (i = 0; i + 8 <= num_pixels; i += 8) {
378
11.8M
    const __m256i A = _mm256_loadu_si256((const __m256i*)(src + i));
379
11.8M
    const __m256i B = _mm256_shuffle_epi8(A, perm1);  // argb -> g0g0
380
11.8M
    const __m256i C = _mm256_mulhi_epi16(B, mults_rb);
381
11.8M
    const __m256i D = _mm256_add_epi8(A, C);
382
11.8M
    const __m256i E = _mm256_shuffle_epi8(D, perm2);
383
11.8M
    const __m256i F = _mm256_mulhi_epi16(E, mults_b2);
384
11.8M
    const __m256i G = _mm256_add_epi8(D, F);
385
11.8M
    const __m256i out = _mm256_blendv_epi8(G, A, mask_ag);
386
11.8M
    _mm256_storeu_si256((__m256i*)&dst[i], out);
387
11.8M
  }
388
  // Fall-back to SSE-version for left-overs.
389
8.31M
  if (i != num_pixels) {
390
4.41M
    VP8LTransformColorInverse_SSE(m, src + i, num_pixels - i, dst + i);
391
4.41M
  }
392
8.31M
}
393
394
//------------------------------------------------------------------------------
395
// Color-space conversion functions
396
397
static void ConvertBGRAToRGBA_AVX2(const uint32_t* WEBP_RESTRICT src,
398
1.32M
                                   int num_pixels, uint8_t* WEBP_RESTRICT dst) {
399
1.32M
  const __m256i* in = (const __m256i*)src;
400
1.32M
  __m256i* out = (__m256i*)dst;
401
173M
  while (num_pixels >= 8) {
402
171M
    const __m256i A = _mm256_loadu_si256(in++);
403
171M
    const __m256i B = _mm256_shuffle_epi8(
404
171M
        A,
405
171M
        _mm256_set_epi8(15, 12, 13, 14, 11, 8, 9, 10, 7, 4, 5, 6, 3, 0, 1, 2,
406
171M
                        15, 12, 13, 14, 11, 8, 9, 10, 7, 4, 5, 6, 3, 0, 1, 2));
407
171M
    _mm256_storeu_si256(out++, B);
408
171M
    num_pixels -= 8;
409
171M
  }
410
  // left-overs
411
1.32M
  if (num_pixels > 0) {
412
1.23M
    VP8LConvertBGRAToRGBA_SSE((const uint32_t*)in, num_pixels, (uint8_t*)out);
413
1.23M
  }
414
1.32M
}
415
416
//------------------------------------------------------------------------------
417
// Entry point
418
419
extern void VP8LDspInitAVX2(void);
420
421
1
WEBP_TSAN_IGNORE_FUNCTION void VP8LDspInitAVX2(void) {
422
1
  VP8LPredictorsAdd[0] = PredictorAdd0_AVX2;
423
1
  VP8LPredictorsAdd[1] = PredictorAdd1_AVX2;
424
1
  VP8LPredictorsAdd[2] = PredictorAdd2_AVX2;
425
1
  VP8LPredictorsAdd[3] = PredictorAdd3_AVX2;
426
1
  VP8LPredictorsAdd[4] = PredictorAdd4_AVX2;
427
1
  VP8LPredictorsAdd[8] = PredictorAdd8_AVX2;
428
1
  VP8LPredictorsAdd[9] = PredictorAdd9_AVX2;
429
1
  VP8LPredictorsAdd[10] = PredictorAdd10_AVX2;
430
1
  VP8LPredictorsAdd[11] = PredictorAdd11_AVX2;
431
1
  VP8LPredictorsAdd[12] = PredictorAdd12_AVX2;
432
433
1
  VP8LAddGreenToBlueAndRed = AddGreenToBlueAndRed_AVX2;
434
1
  VP8LTransformColorInverse = TransformColorInverse_AVX2;
435
1
  VP8LConvertBGRAToRGBA = ConvertBGRAToRGBA_AVX2;
436
1
}
437
438
#else  // !WEBP_USE_AVX2
439
440
WEBP_DSP_INIT_STUB(VP8LDspInitAVX2)
441
442
#endif  // WEBP_USE_AVX2