Coverage Report

Created: 2026-09-14 08:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libvpx/vpx_dsp/x86/highbd_convolve_avx2.c
Line
Count
Source
1
/*
2
 *  Copyright (c) 2017 The WebM project authors. All Rights Reserved.
3
 *
4
 *  Use of this source code is governed by a BSD-style license
5
 *  that can be found in the LICENSE file in the root of the source
6
 *  tree. An additional intellectual property rights grant can be found
7
 *  in the file PATENTS.  All contributing project authors may
8
 *  be found in the AUTHORS file in the root of the source tree.
9
 */
10
11
#include <immintrin.h>
12
#include "./vpx_dsp_rtcd.h"
13
#include "vpx_dsp/x86/convolve.h"
14
#include "vpx_dsp/x86/convolve_avx2.h"
15
16
// -----------------------------------------------------------------------------
17
// Copy and average
18
19
void vpx_highbd_convolve_copy_avx2(const uint16_t *src, ptrdiff_t src_stride,
20
                                   uint16_t *dst, ptrdiff_t dst_stride,
21
                                   const InterpKernel *filter, int x0_q4,
22
                                   int x_step_q4, int y0_q4, int y_step_q4,
23
1.72M
                                   int w, int h, int bd) {
24
1.72M
  (void)filter;
25
1.72M
  (void)x0_q4;
26
1.72M
  (void)x_step_q4;
27
1.72M
  (void)y0_q4;
28
1.72M
  (void)y_step_q4;
29
1.72M
  (void)bd;
30
31
1.72M
  assert(w % 4 == 0);
32
1.72M
  if (w > 32) {  // w = 64
33
6.05M
    do {
34
6.05M
      const __m256i p0 = _mm256_loadu_si256((const __m256i *)src);
35
6.05M
      const __m256i p1 = _mm256_loadu_si256((const __m256i *)(src + 16));
36
6.05M
      const __m256i p2 = _mm256_loadu_si256((const __m256i *)(src + 32));
37
6.05M
      const __m256i p3 = _mm256_loadu_si256((const __m256i *)(src + 48));
38
6.05M
      src += src_stride;
39
6.05M
      _mm256_storeu_si256((__m256i *)dst, p0);
40
6.05M
      _mm256_storeu_si256((__m256i *)(dst + 16), p1);
41
6.05M
      _mm256_storeu_si256((__m256i *)(dst + 32), p2);
42
6.05M
      _mm256_storeu_si256((__m256i *)(dst + 48), p3);
43
6.05M
      dst += dst_stride;
44
6.05M
      h--;
45
6.05M
    } while (h > 0);
46
1.60M
  } else if (w > 16) {  // w = 32
47
8.31M
    do {
48
8.31M
      const __m256i p0 = _mm256_loadu_si256((const __m256i *)src);
49
8.31M
      const __m256i p1 = _mm256_loadu_si256((const __m256i *)(src + 16));
50
8.31M
      src += src_stride;
51
8.31M
      _mm256_storeu_si256((__m256i *)dst, p0);
52
8.31M
      _mm256_storeu_si256((__m256i *)(dst + 16), p1);
53
8.31M
      dst += dst_stride;
54
8.31M
      h--;
55
8.31M
    } while (h > 0);
56
1.29M
  } else if (w > 8) {  // w = 16
57
253k
    __m256i p0, p1;
58
2.15M
    do {
59
2.15M
      p0 = _mm256_loadu_si256((const __m256i *)src);
60
2.15M
      src += src_stride;
61
2.15M
      p1 = _mm256_loadu_si256((const __m256i *)src);
62
2.15M
      src += src_stride;
63
64
2.15M
      _mm256_storeu_si256((__m256i *)dst, p0);
65
2.15M
      dst += dst_stride;
66
2.15M
      _mm256_storeu_si256((__m256i *)dst, p1);
67
2.15M
      dst += dst_stride;
68
2.15M
      h -= 2;
69
2.15M
    } while (h > 0);
70
1.04M
  } else if (w > 4) {  // w = 8
71
504k
    __m128i p0, p1;
72
2.14M
    do {
73
2.14M
      p0 = _mm_loadu_si128((const __m128i *)src);
74
2.14M
      src += src_stride;
75
2.14M
      p1 = _mm_loadu_si128((const __m128i *)src);
76
2.14M
      src += src_stride;
77
78
2.14M
      _mm_storeu_si128((__m128i *)dst, p0);
79
2.14M
      dst += dst_stride;
80
2.14M
      _mm_storeu_si128((__m128i *)dst, p1);
81
2.14M
      dst += dst_stride;
82
2.14M
      h -= 2;
83
2.14M
    } while (h > 0);
84
540k
  } else {  // w = 4
85
540k
    __m128i p0, p1;
86
1.20M
    do {
87
1.20M
      p0 = _mm_loadl_epi64((const __m128i *)src);
88
1.20M
      src += src_stride;
89
1.20M
      p1 = _mm_loadl_epi64((const __m128i *)src);
90
1.20M
      src += src_stride;
91
92
1.20M
      _mm_storel_epi64((__m128i *)dst, p0);
93
1.20M
      dst += dst_stride;
94
1.20M
      _mm_storel_epi64((__m128i *)dst, p1);
95
1.20M
      dst += dst_stride;
96
1.20M
      h -= 2;
97
1.20M
    } while (h > 0);
98
540k
  }
99
1.72M
}
100
101
void vpx_highbd_convolve_avg_avx2(const uint16_t *src, ptrdiff_t src_stride,
102
                                  uint16_t *dst, ptrdiff_t dst_stride,
103
                                  const InterpKernel *filter, int x0_q4,
104
                                  int x_step_q4, int y0_q4, int y_step_q4,
105
489k
                                  int w, int h, int bd) {
106
489k
  (void)filter;
107
489k
  (void)x0_q4;
108
489k
  (void)x_step_q4;
109
489k
  (void)y0_q4;
110
489k
  (void)y_step_q4;
111
489k
  (void)bd;
112
113
489k
  assert(w % 4 == 0);
114
489k
  if (w > 32) {  // w = 64
115
7.79k
    __m256i p0, p1, p2, p3, u0, u1, u2, u3;
116
478k
    do {
117
478k
      p0 = _mm256_loadu_si256((const __m256i *)src);
118
478k
      p1 = _mm256_loadu_si256((const __m256i *)(src + 16));
119
478k
      p2 = _mm256_loadu_si256((const __m256i *)(src + 32));
120
478k
      p3 = _mm256_loadu_si256((const __m256i *)(src + 48));
121
478k
      src += src_stride;
122
478k
      u0 = _mm256_loadu_si256((const __m256i *)dst);
123
478k
      u1 = _mm256_loadu_si256((const __m256i *)(dst + 16));
124
478k
      u2 = _mm256_loadu_si256((const __m256i *)(dst + 32));
125
478k
      u3 = _mm256_loadu_si256((const __m256i *)(dst + 48));
126
478k
      _mm256_storeu_si256((__m256i *)dst, _mm256_avg_epu16(p0, u0));
127
478k
      _mm256_storeu_si256((__m256i *)(dst + 16), _mm256_avg_epu16(p1, u1));
128
478k
      _mm256_storeu_si256((__m256i *)(dst + 32), _mm256_avg_epu16(p2, u2));
129
478k
      _mm256_storeu_si256((__m256i *)(dst + 48), _mm256_avg_epu16(p3, u3));
130
478k
      dst += dst_stride;
131
478k
      h--;
132
478k
    } while (h > 0);
133
482k
  } else if (w > 16) {  // w = 32
134
42.0k
    __m256i p0, p1, u0, u1;
135
1.44M
    do {
136
1.44M
      p0 = _mm256_loadu_si256((const __m256i *)src);
137
1.44M
      p1 = _mm256_loadu_si256((const __m256i *)(src + 16));
138
1.44M
      src += src_stride;
139
1.44M
      u0 = _mm256_loadu_si256((const __m256i *)dst);
140
1.44M
      u1 = _mm256_loadu_si256((const __m256i *)(dst + 16));
141
1.44M
      _mm256_storeu_si256((__m256i *)dst, _mm256_avg_epu16(p0, u0));
142
1.44M
      _mm256_storeu_si256((__m256i *)(dst + 16), _mm256_avg_epu16(p1, u1));
143
1.44M
      dst += dst_stride;
144
1.44M
      h--;
145
1.44M
    } while (h > 0);
146
440k
  } else if (w > 8) {  // w = 16
147
86.1k
    __m256i p0, p1, u0, u1;
148
773k
    do {
149
773k
      p0 = _mm256_loadu_si256((const __m256i *)src);
150
773k
      p1 = _mm256_loadu_si256((const __m256i *)(src + src_stride));
151
773k
      src += src_stride << 1;
152
773k
      u0 = _mm256_loadu_si256((const __m256i *)dst);
153
773k
      u1 = _mm256_loadu_si256((const __m256i *)(dst + dst_stride));
154
155
773k
      _mm256_storeu_si256((__m256i *)dst, _mm256_avg_epu16(p0, u0));
156
773k
      _mm256_storeu_si256((__m256i *)(dst + dst_stride),
157
773k
                          _mm256_avg_epu16(p1, u1));
158
773k
      dst += dst_stride << 1;
159
773k
      h -= 2;
160
773k
    } while (h > 0);
161
353k
  } else if (w > 4) {  // w = 8
162
163k
    __m128i p0, p1, u0, u1;
163
669k
    do {
164
669k
      p0 = _mm_loadu_si128((const __m128i *)src);
165
669k
      p1 = _mm_loadu_si128((const __m128i *)(src + src_stride));
166
669k
      src += src_stride << 1;
167
669k
      u0 = _mm_loadu_si128((const __m128i *)dst);
168
669k
      u1 = _mm_loadu_si128((const __m128i *)(dst + dst_stride));
169
170
669k
      _mm_storeu_si128((__m128i *)dst, _mm_avg_epu16(p0, u0));
171
669k
      _mm_storeu_si128((__m128i *)(dst + dst_stride), _mm_avg_epu16(p1, u1));
172
669k
      dst += dst_stride << 1;
173
669k
      h -= 2;
174
669k
    } while (h > 0);
175
190k
  } else {  // w = 4
176
190k
    __m128i p0, p1, u0, u1;
177
418k
    do {
178
418k
      p0 = _mm_loadl_epi64((const __m128i *)src);
179
418k
      p1 = _mm_loadl_epi64((const __m128i *)(src + src_stride));
180
418k
      src += src_stride << 1;
181
418k
      u0 = _mm_loadl_epi64((const __m128i *)dst);
182
418k
      u1 = _mm_loadl_epi64((const __m128i *)(dst + dst_stride));
183
184
418k
      _mm_storel_epi64((__m128i *)dst, _mm_avg_epu16(u0, p0));
185
418k
      _mm_storel_epi64((__m128i *)(dst + dst_stride), _mm_avg_epu16(u1, p1));
186
418k
      dst += dst_stride << 1;
187
418k
      h -= 2;
188
418k
    } while (h > 0);
189
190k
  }
190
489k
}
191
192
#if HAVE_X86_ASM
193
// -----------------------------------------------------------------------------
194
// Horizontal and vertical filtering
195
196
static const uint8_t signal_pattern_0[32] = { 0, 1, 2, 3, 2, 3, 4, 5, 4, 5, 6,
197
                                              7, 6, 7, 8, 9, 0, 1, 2, 3, 2, 3,
198
                                              4, 5, 4, 5, 6, 7, 6, 7, 8, 9 };
199
200
static const uint8_t signal_pattern_1[32] = { 4, 5, 6,  7,  6,  7,  8,  9,
201
                                              8, 9, 10, 11, 10, 11, 12, 13,
202
                                              4, 5, 6,  7,  6,  7,  8,  9,
203
                                              8, 9, 10, 11, 10, 11, 12, 13 };
204
205
static const uint8_t signal_pattern_2[32] = { 6,  7,  8,  9,  8,  9,  10, 11,
206
                                              10, 11, 12, 13, 12, 13, 14, 15,
207
                                              6,  7,  8,  9,  8,  9,  10, 11,
208
                                              10, 11, 12, 13, 12, 13, 14, 15 };
209
210
static const uint32_t signal_index[8] = { 2, 3, 4, 5, 2, 3, 4, 5 };
211
212
345M
#define CONV8_ROUNDING_BITS (7)
213
223k
#define CONV8_ROUNDING_NUM (1 << (CONV8_ROUNDING_BITS - 1))
214
215
// -----------------------------------------------------------------------------
216
// Horizontal Filtering
217
218
66.6M
static INLINE void pack_pixels(const __m256i *s, __m256i *p /*p[4]*/) {
219
66.6M
  const __m256i idx = _mm256_loadu_si256((const __m256i *)signal_index);
220
66.6M
  const __m256i sf0 = _mm256_loadu_si256((const __m256i *)signal_pattern_0);
221
66.6M
  const __m256i sf1 = _mm256_loadu_si256((const __m256i *)signal_pattern_1);
222
66.6M
  const __m256i c = _mm256_permutevar8x32_epi32(*s, idx);
223
224
66.6M
  p[0] = _mm256_shuffle_epi8(*s, sf0);  // x0x6
225
66.6M
  p[1] = _mm256_shuffle_epi8(*s, sf1);  // x1x7
226
66.6M
  p[2] = _mm256_shuffle_epi8(c, sf0);   // x2x4
227
66.6M
  p[3] = _mm256_shuffle_epi8(c, sf1);   // x3x5
228
66.6M
}
229
230
// Note:
231
//  Shared by 8x2 and 16x1 block
232
static INLINE void pack_16_pixels(const __m256i *s0, const __m256i *s1,
233
32.9M
                                  __m256i *x /*x[8]*/) {
234
32.9M
  __m256i pp[8];
235
32.9M
  pack_pixels(s0, pp);
236
32.9M
  pack_pixels(s1, &pp[4]);
237
32.9M
  x[0] = _mm256_permute2x128_si256(pp[0], pp[4], 0x20);
238
32.9M
  x[1] = _mm256_permute2x128_si256(pp[1], pp[5], 0x20);
239
32.9M
  x[2] = _mm256_permute2x128_si256(pp[2], pp[6], 0x20);
240
32.9M
  x[3] = _mm256_permute2x128_si256(pp[3], pp[7], 0x20);
241
32.9M
  x[4] = x[2];
242
32.9M
  x[5] = x[3];
243
32.9M
  x[6] = _mm256_permute2x128_si256(pp[0], pp[4], 0x31);
244
32.9M
  x[7] = _mm256_permute2x128_si256(pp[1], pp[5], 0x31);
245
32.9M
}
246
247
794k
static INLINE void pack_8x1_pixels(const uint16_t *src, __m256i *x) {
248
794k
  __m256i pp[8];
249
794k
  __m256i s0;
250
794k
  s0 = _mm256_loadu_si256((const __m256i *)src);
251
794k
  pack_pixels(&s0, pp);
252
794k
  x[0] = _mm256_permute2x128_si256(pp[0], pp[2], 0x30);
253
794k
  x[1] = _mm256_permute2x128_si256(pp[1], pp[3], 0x30);
254
794k
  x[2] = _mm256_permute2x128_si256(pp[2], pp[0], 0x30);
255
794k
  x[3] = _mm256_permute2x128_si256(pp[3], pp[1], 0x30);
256
794k
}
257
258
static INLINE void pack_8x2_pixels(const uint16_t *src, ptrdiff_t stride,
259
6.25M
                                   __m256i *x) {
260
6.25M
  __m256i s0, s1;
261
6.25M
  s0 = _mm256_loadu_si256((const __m256i *)src);
262
6.25M
  s1 = _mm256_loadu_si256((const __m256i *)(src + stride));
263
6.25M
  pack_16_pixels(&s0, &s1, x);
264
6.25M
}
265
266
26.6M
static INLINE void pack_16x1_pixels(const uint16_t *src, __m256i *x) {
267
26.6M
  __m256i s0, s1;
268
26.6M
  s0 = _mm256_loadu_si256((const __m256i *)src);
269
26.6M
  s1 = _mm256_loadu_si256((const __m256i *)(src + 8));
270
26.6M
  pack_16_pixels(&s0, &s1, x);
271
26.6M
}
272
273
// Note:
274
//  Shared by horizontal and vertical filtering
275
3.75M
static INLINE void pack_filters(const int16_t *filter, __m256i *f /*f[4]*/) {
276
3.75M
  const __m128i h = _mm_loadu_si128((const __m128i *)filter);
277
3.75M
  const __m256i hh = _mm256_insertf128_si256(_mm256_castsi128_si256(h), h, 1);
278
3.75M
  const __m256i p0 = _mm256_set1_epi32(0x03020100);
279
3.75M
  const __m256i p1 = _mm256_set1_epi32(0x07060504);
280
3.75M
  const __m256i p2 = _mm256_set1_epi32(0x0b0a0908);
281
3.75M
  const __m256i p3 = _mm256_set1_epi32(0x0f0e0d0c);
282
3.75M
  f[0] = _mm256_shuffle_epi8(hh, p0);
283
3.75M
  f[1] = _mm256_shuffle_epi8(hh, p1);
284
3.75M
  f[2] = _mm256_shuffle_epi8(hh, p2);
285
3.75M
  f[3] = _mm256_shuffle_epi8(hh, p3);
286
3.75M
}
287
288
static INLINE void filter_8x1_pixels(const __m256i *sig /*sig[4]*/,
289
                                     const __m256i *fil /*fil[4]*/,
290
128M
                                     __m256i *y) {
291
128M
  __m256i a, a0, a1;
292
293
128M
  a0 = _mm256_madd_epi16(fil[0], sig[0]);
294
128M
  a1 = _mm256_madd_epi16(fil[3], sig[3]);
295
128M
  a = _mm256_add_epi32(a0, a1);
296
297
128M
  a0 = _mm256_madd_epi16(fil[1], sig[1]);
298
128M
  a1 = _mm256_madd_epi16(fil[2], sig[2]);
299
300
128M
  {
301
128M
    const __m256i min = _mm256_min_epi32(a0, a1);
302
128M
    a = _mm256_add_epi32(a, min);
303
128M
  }
304
128M
  {
305
128M
    const __m256i max = _mm256_max_epi32(a0, a1);
306
128M
    a = _mm256_add_epi32(a, max);
307
128M
  }
308
128M
  {
309
128M
    const __m256i rounding = _mm256_set1_epi32(1 << (CONV8_ROUNDING_BITS - 1));
310
128M
    a = _mm256_add_epi32(a, rounding);
311
128M
    *y = _mm256_srai_epi32(a, CONV8_ROUNDING_BITS);
312
128M
  }
313
128M
}
314
315
static INLINE void store_8x1_pixels(const __m256i *y, const __m256i *mask,
316
1.03M
                                    uint16_t *dst) {
317
1.03M
  const __m128i a0 = _mm256_castsi256_si128(*y);
318
1.03M
  const __m128i a1 = _mm256_extractf128_si256(*y, 1);
319
1.03M
  __m128i res = _mm_packus_epi32(a0, a1);
320
1.03M
  res = _mm_min_epi16(res, _mm256_castsi256_si128(*mask));
321
1.03M
  _mm_storeu_si128((__m128i *)dst, res);
322
1.03M
}
323
324
static INLINE void store_8x2_pixels(const __m256i *y0, const __m256i *y1,
325
                                    const __m256i *mask, uint16_t *dst,
326
10.5M
                                    ptrdiff_t pitch) {
327
10.5M
  __m256i a = _mm256_packus_epi32(*y0, *y1);
328
10.5M
  a = _mm256_min_epi16(a, *mask);
329
10.5M
  _mm_storeu_si128((__m128i *)dst, _mm256_castsi256_si128(a));
330
10.5M
  _mm_storeu_si128((__m128i *)(dst + pitch), _mm256_extractf128_si256(a, 1));
331
10.5M
}
332
333
static INLINE void store_16x1_pixels(const __m256i *y0, const __m256i *y1,
334
43.2M
                                     const __m256i *mask, uint16_t *dst) {
335
43.2M
  __m256i a = _mm256_packus_epi32(*y0, *y1);
336
43.2M
  a = _mm256_min_epi16(a, *mask);
337
43.2M
  _mm256_storeu_si256((__m256i *)dst, a);
338
43.2M
}
339
340
static void vpx_highbd_filter_block1d8_h8_avx2(
341
    const uint16_t *src_ptr, ptrdiff_t src_pitch, uint16_t *dst_ptr,
342
939k
    ptrdiff_t dst_pitch, uint32_t height, const int16_t *filter, int bd) {
343
939k
  __m256i signal[8], res0, res1;
344
939k
  const __m256i max = _mm256_set1_epi16((1 << bd) - 1);
345
346
939k
  __m256i ff[4];
347
939k
  pack_filters(filter, ff);
348
349
939k
  src_ptr -= 3;
350
6.02M
  do {
351
6.02M
    pack_8x2_pixels(src_ptr, src_pitch, signal);
352
6.02M
    filter_8x1_pixels(signal, ff, &res0);
353
6.02M
    filter_8x1_pixels(&signal[4], ff, &res1);
354
6.02M
    store_8x2_pixels(&res0, &res1, &max, dst_ptr, dst_pitch);
355
6.02M
    height -= 2;
356
6.02M
    src_ptr += src_pitch << 1;
357
6.02M
    dst_ptr += dst_pitch << 1;
358
6.02M
  } while (height > 1);
359
360
939k
  if (height > 0) {
361
794k
    pack_8x1_pixels(src_ptr, signal);
362
794k
    filter_8x1_pixels(signal, ff, &res0);
363
794k
    store_8x1_pixels(&res0, &max, dst_ptr);
364
794k
  }
365
939k
}
366
367
static void vpx_highbd_filter_block1d16_h8_avx2(
368
    const uint16_t *src_ptr, ptrdiff_t src_pitch, uint16_t *dst_ptr,
369
688k
    ptrdiff_t dst_pitch, uint32_t height, const int16_t *filter, int bd) {
370
688k
  __m256i signal[8], res0, res1;
371
688k
  const __m256i max = _mm256_set1_epi16((1 << bd) - 1);
372
373
688k
  __m256i ff[4];
374
688k
  pack_filters(filter, ff);
375
376
688k
  src_ptr -= 3;
377
25.1M
  do {
378
25.1M
    pack_16x1_pixels(src_ptr, signal);
379
25.1M
    filter_8x1_pixels(signal, ff, &res0);
380
25.1M
    filter_8x1_pixels(&signal[4], ff, &res1);
381
25.1M
    store_16x1_pixels(&res0, &res1, &max, dst_ptr);
382
25.1M
    height -= 1;
383
25.1M
    src_ptr += src_pitch;
384
25.1M
    dst_ptr += dst_pitch;
385
25.1M
  } while (height > 0);
386
688k
}
387
388
// -----------------------------------------------------------------------------
389
// 2-tap horizontal filtering
390
391
1.16M
static INLINE void pack_2t_filter(const int16_t *filter, __m256i *f) {
392
1.16M
  const __m128i h = _mm_loadu_si128((const __m128i *)filter);
393
1.16M
  const __m256i hh = _mm256_insertf128_si256(_mm256_castsi128_si256(h), h, 1);
394
1.16M
  const __m256i p = _mm256_set1_epi32(0x09080706);
395
1.16M
  f[0] = _mm256_shuffle_epi8(hh, p);
396
1.16M
}
397
398
// can be used by pack_8x2_2t_pixels() and pack_16x1_2t_pixels()
399
// the difference is s0/s1 specifies first and second rows or,
400
// first 16 samples and 8-sample shifted 16 samples
401
static INLINE void pack_16_2t_pixels(const __m256i *s0, const __m256i *s1,
402
12.7M
                                     __m256i *sig) {
403
12.7M
  const __m256i idx = _mm256_loadu_si256((const __m256i *)signal_index);
404
12.7M
  const __m256i sf2 = _mm256_loadu_si256((const __m256i *)signal_pattern_2);
405
12.7M
  __m256i x0 = _mm256_shuffle_epi8(*s0, sf2);
406
12.7M
  __m256i x1 = _mm256_shuffle_epi8(*s1, sf2);
407
12.7M
  __m256i r0 = _mm256_permutevar8x32_epi32(*s0, idx);
408
12.7M
  __m256i r1 = _mm256_permutevar8x32_epi32(*s1, idx);
409
12.7M
  r0 = _mm256_shuffle_epi8(r0, sf2);
410
12.7M
  r1 = _mm256_shuffle_epi8(r1, sf2);
411
12.7M
  sig[0] = _mm256_permute2x128_si256(x0, x1, 0x20);
412
12.7M
  sig[1] = _mm256_permute2x128_si256(r0, r1, 0x20);
413
12.7M
}
414
415
static INLINE void pack_8x2_2t_pixels(const uint16_t *src,
416
1.52M
                                      const ptrdiff_t pitch, __m256i *sig) {
417
1.52M
  const __m256i r0 = _mm256_loadu_si256((const __m256i *)src);
418
1.52M
  const __m256i r1 = _mm256_loadu_si256((const __m256i *)(src + pitch));
419
1.52M
  pack_16_2t_pixels(&r0, &r1, sig);
420
1.52M
}
421
422
static INLINE void pack_16x1_2t_pixels(const uint16_t *src,
423
11.2M
                                       __m256i *sig /*sig[2]*/) {
424
11.2M
  const __m256i r0 = _mm256_loadu_si256((const __m256i *)src);
425
11.2M
  const __m256i r1 = _mm256_loadu_si256((const __m256i *)(src + 8));
426
11.2M
  pack_16_2t_pixels(&r0, &r1, sig);
427
11.2M
}
428
429
static INLINE void pack_8x1_2t_pixels(const uint16_t *src,
430
235k
                                      __m256i *sig /*sig[2]*/) {
431
235k
  const __m256i idx = _mm256_loadu_si256((const __m256i *)signal_index);
432
235k
  const __m256i sf2 = _mm256_loadu_si256((const __m256i *)signal_pattern_2);
433
235k
  __m256i r0 = _mm256_loadu_si256((const __m256i *)src);
434
235k
  __m256i x0 = _mm256_shuffle_epi8(r0, sf2);
435
235k
  r0 = _mm256_permutevar8x32_epi32(r0, idx);
436
235k
  r0 = _mm256_shuffle_epi8(r0, sf2);
437
235k
  sig[0] = _mm256_permute2x128_si256(x0, r0, 0x20);
438
235k
}
439
440
// can be used by filter_8x2_2t_pixels() and filter_16x1_2t_pixels()
441
static INLINE void filter_16_2t_pixels(const __m256i *sig, const __m256i *f,
442
24.3M
                                       __m256i *y0, __m256i *y1) {
443
24.3M
  const __m256i rounding = _mm256_set1_epi32(1 << (CONV8_ROUNDING_BITS - 1));
444
24.3M
  __m256i x0 = _mm256_madd_epi16(sig[0], *f);
445
24.3M
  __m256i x1 = _mm256_madd_epi16(sig[1], *f);
446
24.3M
  x0 = _mm256_add_epi32(x0, rounding);
447
24.3M
  x1 = _mm256_add_epi32(x1, rounding);
448
24.3M
  *y0 = _mm256_srai_epi32(x0, CONV8_ROUNDING_BITS);
449
24.3M
  *y1 = _mm256_srai_epi32(x1, CONV8_ROUNDING_BITS);
450
24.3M
}
451
452
static INLINE void filter_8x1_2t_pixels(const __m256i *sig, const __m256i *f,
453
235k
                                        __m256i *y0) {
454
235k
  const __m256i rounding = _mm256_set1_epi32(1 << (CONV8_ROUNDING_BITS - 1));
455
235k
  __m256i x0 = _mm256_madd_epi16(sig[0], *f);
456
235k
  x0 = _mm256_add_epi32(x0, rounding);
457
235k
  *y0 = _mm256_srai_epi32(x0, CONV8_ROUNDING_BITS);
458
235k
}
459
460
static void vpx_highbd_filter_block1d8_h2_avx2(
461
    const uint16_t *src_ptr, ptrdiff_t src_pitch, uint16_t *dst_ptr,
462
267k
    ptrdiff_t dst_pitch, uint32_t height, const int16_t *filter, int bd) {
463
267k
  __m256i signal[2], res0, res1;
464
267k
  const __m256i max = _mm256_set1_epi16((1 << bd) - 1);
465
466
267k
  __m256i ff;
467
267k
  pack_2t_filter(filter, &ff);
468
469
267k
  src_ptr -= 3;
470
1.45M
  do {
471
1.45M
    pack_8x2_2t_pixels(src_ptr, src_pitch, signal);
472
1.45M
    filter_16_2t_pixels(signal, &ff, &res0, &res1);
473
1.45M
    store_8x2_pixels(&res0, &res1, &max, dst_ptr, dst_pitch);
474
1.45M
    height -= 2;
475
1.45M
    src_ptr += src_pitch << 1;
476
1.45M
    dst_ptr += dst_pitch << 1;
477
1.45M
  } while (height > 1);
478
479
267k
  if (height > 0) {
480
235k
    pack_8x1_2t_pixels(src_ptr, signal);
481
235k
    filter_8x1_2t_pixels(signal, &ff, &res0);
482
235k
    store_8x1_pixels(&res0, &max, dst_ptr);
483
235k
  }
484
267k
}
485
486
static void vpx_highbd_filter_block1d16_h2_avx2(
487
    const uint16_t *src_ptr, ptrdiff_t src_pitch, uint16_t *dst_ptr,
488
400k
    ptrdiff_t dst_pitch, uint32_t height, const int16_t *filter, int bd) {
489
400k
  __m256i signal[2], res0, res1;
490
400k
  const __m256i max = _mm256_set1_epi16((1 << bd) - 1);
491
492
400k
  __m256i ff;
493
400k
  pack_2t_filter(filter, &ff);
494
495
400k
  src_ptr -= 3;
496
10.5M
  do {
497
10.5M
    pack_16x1_2t_pixels(src_ptr, signal);
498
10.5M
    filter_16_2t_pixels(signal, &ff, &res0, &res1);
499
10.5M
    store_16x1_pixels(&res0, &res1, &max, dst_ptr);
500
10.5M
    height -= 1;
501
10.5M
    src_ptr += src_pitch;
502
10.5M
    dst_ptr += dst_pitch;
503
10.5M
  } while (height > 0);
504
400k
}
505
506
// -----------------------------------------------------------------------------
507
// Vertical Filtering
508
509
1.18M
static void pack_8x9_init(const uint16_t *src, ptrdiff_t pitch, __m256i *sig) {
510
1.18M
  __m256i s0 = _mm256_castsi128_si256(_mm_loadu_si128((const __m128i *)src));
511
1.18M
  __m256i s1 =
512
1.18M
      _mm256_castsi128_si256(_mm_loadu_si128((const __m128i *)(src + pitch)));
513
1.18M
  __m256i s2 = _mm256_castsi128_si256(
514
1.18M
      _mm_loadu_si128((const __m128i *)(src + 2 * pitch)));
515
1.18M
  __m256i s3 = _mm256_castsi128_si256(
516
1.18M
      _mm_loadu_si128((const __m128i *)(src + 3 * pitch)));
517
1.18M
  __m256i s4 = _mm256_castsi128_si256(
518
1.18M
      _mm_loadu_si128((const __m128i *)(src + 4 * pitch)));
519
1.18M
  __m256i s5 = _mm256_castsi128_si256(
520
1.18M
      _mm_loadu_si128((const __m128i *)(src + 5 * pitch)));
521
1.18M
  __m256i s6 = _mm256_castsi128_si256(
522
1.18M
      _mm_loadu_si128((const __m128i *)(src + 6 * pitch)));
523
524
1.18M
  s0 = _mm256_inserti128_si256(s0, _mm256_castsi256_si128(s1), 1);
525
1.18M
  s1 = _mm256_inserti128_si256(s1, _mm256_castsi256_si128(s2), 1);
526
1.18M
  s2 = _mm256_inserti128_si256(s2, _mm256_castsi256_si128(s3), 1);
527
1.18M
  s3 = _mm256_inserti128_si256(s3, _mm256_castsi256_si128(s4), 1);
528
1.18M
  s4 = _mm256_inserti128_si256(s4, _mm256_castsi256_si128(s5), 1);
529
1.18M
  s5 = _mm256_inserti128_si256(s5, _mm256_castsi256_si128(s6), 1);
530
531
1.18M
  sig[0] = _mm256_unpacklo_epi16(s0, s1);
532
1.18M
  sig[4] = _mm256_unpackhi_epi16(s0, s1);
533
1.18M
  sig[1] = _mm256_unpacklo_epi16(s2, s3);
534
1.18M
  sig[5] = _mm256_unpackhi_epi16(s2, s3);
535
1.18M
  sig[2] = _mm256_unpacklo_epi16(s4, s5);
536
1.18M
  sig[6] = _mm256_unpackhi_epi16(s4, s5);
537
1.18M
  sig[8] = s6;
538
1.18M
}
539
540
static INLINE void pack_8x9_pixels(const uint16_t *src, ptrdiff_t pitch,
541
4.47M
                                   __m256i *sig) {
542
  // base + 7th row
543
4.47M
  __m256i s0 = _mm256_castsi128_si256(
544
4.47M
      _mm_loadu_si128((const __m128i *)(src + 7 * pitch)));
545
  // base + 8th row
546
4.47M
  __m256i s1 = _mm256_castsi128_si256(
547
4.47M
      _mm_loadu_si128((const __m128i *)(src + 8 * pitch)));
548
4.47M
  __m256i s2 = _mm256_inserti128_si256(sig[8], _mm256_castsi256_si128(s0), 1);
549
4.47M
  __m256i s3 = _mm256_inserti128_si256(s0, _mm256_castsi256_si128(s1), 1);
550
4.47M
  sig[3] = _mm256_unpacklo_epi16(s2, s3);
551
4.47M
  sig[7] = _mm256_unpackhi_epi16(s2, s3);
552
4.47M
  sig[8] = s1;
553
4.47M
}
554
555
static INLINE void filter_8x9_pixels(const __m256i *sig, const __m256i *f,
556
4.47M
                                     __m256i *y0, __m256i *y1) {
557
4.47M
  filter_8x1_pixels(sig, f, y0);
558
4.47M
  filter_8x1_pixels(&sig[4], f, y1);
559
4.47M
}
560
561
30.8M
static INLINE void update_pixels(__m256i *sig) {
562
30.8M
  int i;
563
123M
  for (i = 0; i < 3; ++i) {
564
92.6M
    sig[i] = sig[i + 1];
565
92.6M
    sig[i + 4] = sig[i + 5];
566
92.6M
  }
567
30.8M
}
568
569
static void vpx_highbd_filter_block1d8_v8_avx2(
570
    const uint16_t *src_ptr, ptrdiff_t src_pitch, uint16_t *dst_ptr,
571
797k
    ptrdiff_t dst_pitch, uint32_t height, const int16_t *filter, int bd) {
572
797k
  __m256i signal[9], res0, res1;
573
797k
  const __m256i max = _mm256_set1_epi16((1 << bd) - 1);
574
575
797k
  __m256i ff[4];
576
797k
  pack_filters(filter, ff);
577
578
797k
  pack_8x9_init(src_ptr, src_pitch, signal);
579
580
3.04M
  do {
581
3.04M
    pack_8x9_pixels(src_ptr, src_pitch, signal);
582
583
3.04M
    filter_8x9_pixels(signal, ff, &res0, &res1);
584
3.04M
    store_8x2_pixels(&res0, &res1, &max, dst_ptr, dst_pitch);
585
3.04M
    update_pixels(signal);
586
587
3.04M
    src_ptr += src_pitch << 1;
588
3.04M
    dst_ptr += dst_pitch << 1;
589
3.04M
    height -= 2;
590
3.04M
  } while (height > 0);
591
797k
}
592
593
843k
static void pack_16x9_init(const uint16_t *src, ptrdiff_t pitch, __m256i *sig) {
594
843k
  __m256i u0, u1, u2, u3;
595
  // load 0-6 rows
596
843k
  const __m256i s0 = _mm256_loadu_si256((const __m256i *)src);
597
843k
  const __m256i s1 = _mm256_loadu_si256((const __m256i *)(src + pitch));
598
843k
  const __m256i s2 = _mm256_loadu_si256((const __m256i *)(src + 2 * pitch));
599
843k
  const __m256i s3 = _mm256_loadu_si256((const __m256i *)(src + 3 * pitch));
600
843k
  const __m256i s4 = _mm256_loadu_si256((const __m256i *)(src + 4 * pitch));
601
843k
  const __m256i s5 = _mm256_loadu_si256((const __m256i *)(src + 5 * pitch));
602
843k
  const __m256i s6 = _mm256_loadu_si256((const __m256i *)(src + 6 * pitch));
603
604
843k
  u0 = _mm256_permute2x128_si256(s0, s1, 0x20);  // 0, 1 low
605
843k
  u1 = _mm256_permute2x128_si256(s0, s1, 0x31);  // 0, 1 high
606
607
843k
  u2 = _mm256_permute2x128_si256(s1, s2, 0x20);  // 1, 2 low
608
843k
  u3 = _mm256_permute2x128_si256(s1, s2, 0x31);  // 1, 2 high
609
610
843k
  sig[0] = _mm256_unpacklo_epi16(u0, u2);
611
843k
  sig[4] = _mm256_unpackhi_epi16(u0, u2);
612
613
843k
  sig[8] = _mm256_unpacklo_epi16(u1, u3);
614
843k
  sig[12] = _mm256_unpackhi_epi16(u1, u3);
615
616
843k
  u0 = _mm256_permute2x128_si256(s2, s3, 0x20);
617
843k
  u1 = _mm256_permute2x128_si256(s2, s3, 0x31);
618
619
843k
  u2 = _mm256_permute2x128_si256(s3, s4, 0x20);
620
843k
  u3 = _mm256_permute2x128_si256(s3, s4, 0x31);
621
622
843k
  sig[1] = _mm256_unpacklo_epi16(u0, u2);
623
843k
  sig[5] = _mm256_unpackhi_epi16(u0, u2);
624
625
843k
  sig[9] = _mm256_unpacklo_epi16(u1, u3);
626
843k
  sig[13] = _mm256_unpackhi_epi16(u1, u3);
627
628
843k
  u0 = _mm256_permute2x128_si256(s4, s5, 0x20);
629
843k
  u1 = _mm256_permute2x128_si256(s4, s5, 0x31);
630
631
843k
  u2 = _mm256_permute2x128_si256(s5, s6, 0x20);
632
843k
  u3 = _mm256_permute2x128_si256(s5, s6, 0x31);
633
634
843k
  sig[2] = _mm256_unpacklo_epi16(u0, u2);
635
843k
  sig[6] = _mm256_unpackhi_epi16(u0, u2);
636
637
843k
  sig[10] = _mm256_unpacklo_epi16(u1, u3);
638
843k
  sig[14] = _mm256_unpackhi_epi16(u1, u3);
639
640
843k
  sig[16] = s6;
641
843k
}
642
643
static void pack_16x9_pixels(const uint16_t *src, ptrdiff_t pitch,
644
13.2M
                             __m256i *sig) {
645
  // base + 7th row
646
13.2M
  const __m256i s7 = _mm256_loadu_si256((const __m256i *)(src + 7 * pitch));
647
  // base + 8th row
648
13.2M
  const __m256i s8 = _mm256_loadu_si256((const __m256i *)(src + 8 * pitch));
649
650
13.2M
  __m256i u0, u1, u2, u3;
651
13.2M
  u0 = _mm256_permute2x128_si256(sig[16], s7, 0x20);
652
13.2M
  u1 = _mm256_permute2x128_si256(sig[16], s7, 0x31);
653
654
13.2M
  u2 = _mm256_permute2x128_si256(s7, s8, 0x20);
655
13.2M
  u3 = _mm256_permute2x128_si256(s7, s8, 0x31);
656
657
13.2M
  sig[3] = _mm256_unpacklo_epi16(u0, u2);
658
13.2M
  sig[7] = _mm256_unpackhi_epi16(u0, u2);
659
660
13.2M
  sig[11] = _mm256_unpacklo_epi16(u1, u3);
661
13.2M
  sig[15] = _mm256_unpackhi_epi16(u1, u3);
662
663
13.2M
  sig[16] = s8;
664
13.2M
}
665
666
static INLINE void filter_16x9_pixels(const __m256i *sig, const __m256i *f,
667
13.2M
                                      __m256i *y0, __m256i *y1) {
668
13.2M
  __m256i res[4];
669
13.2M
  int i;
670
66.0M
  for (i = 0; i < 4; ++i) {
671
52.8M
    filter_8x1_pixels(&sig[i << 2], f, &res[i]);
672
52.8M
  }
673
674
13.2M
  {
675
13.2M
    const __m256i l0l1 = _mm256_packus_epi32(res[0], res[1]);
676
13.2M
    const __m256i h0h1 = _mm256_packus_epi32(res[2], res[3]);
677
13.2M
    *y0 = _mm256_permute2x128_si256(l0l1, h0h1, 0x20);
678
13.2M
    *y1 = _mm256_permute2x128_si256(l0l1, h0h1, 0x31);
679
13.2M
  }
680
13.2M
}
681
682
static INLINE void store_16x2_pixels(const __m256i *y0, const __m256i *y1,
683
                                     const __m256i *mask, uint16_t *dst,
684
8.95M
                                     ptrdiff_t pitch) {
685
8.95M
  __m256i p = _mm256_min_epi16(*y0, *mask);
686
8.95M
  _mm256_storeu_si256((__m256i *)dst, p);
687
8.95M
  p = _mm256_min_epi16(*y1, *mask);
688
8.95M
  _mm256_storeu_si256((__m256i *)(dst + pitch), p);
689
8.95M
}
690
691
13.2M
static void update_16x9_pixels(__m256i *sig) {
692
13.2M
  update_pixels(&sig[0]);
693
13.2M
  update_pixels(&sig[8]);
694
13.2M
}
695
696
static void vpx_highbd_filter_block1d16_v8_avx2(
697
    const uint16_t *src_ptr, ptrdiff_t src_pitch, uint16_t *dst_ptr,
698
576k
    ptrdiff_t dst_pitch, uint32_t height, const int16_t *filter, int bd) {
699
576k
  __m256i signal[17], res0, res1;
700
576k
  const __m256i max = _mm256_set1_epi16((1 << bd) - 1);
701
702
576k
  __m256i ff[4];
703
576k
  pack_filters(filter, ff);
704
705
576k
  pack_16x9_init(src_ptr, src_pitch, signal);
706
707
8.95M
  do {
708
8.95M
    pack_16x9_pixels(src_ptr, src_pitch, signal);
709
8.95M
    filter_16x9_pixels(signal, ff, &res0, &res1);
710
8.95M
    store_16x2_pixels(&res0, &res1, &max, dst_ptr, dst_pitch);
711
8.95M
    update_16x9_pixels(signal);
712
713
8.95M
    src_ptr += src_pitch << 1;
714
8.95M
    dst_ptr += dst_pitch << 1;
715
8.95M
    height -= 2;
716
8.95M
  } while (height > 0);
717
576k
}
718
719
// -----------------------------------------------------------------------------
720
// 2-tap vertical filtering
721
722
459k
static void pack_16x2_init(const uint16_t *src, __m256i *sig) {
723
459k
  sig[2] = _mm256_loadu_si256((const __m256i *)src);
724
459k
}
725
726
static INLINE void pack_16x2_2t_pixels(const uint16_t *src, ptrdiff_t pitch,
727
11.5M
                                       __m256i *sig) {
728
  // load the next row
729
11.5M
  const __m256i u = _mm256_loadu_si256((const __m256i *)(src + pitch));
730
11.5M
  sig[0] = _mm256_unpacklo_epi16(sig[2], u);
731
11.5M
  sig[1] = _mm256_unpackhi_epi16(sig[2], u);
732
11.5M
  sig[2] = u;
733
11.5M
}
734
735
static INLINE void filter_16x2_2t_pixels(const __m256i *sig, const __m256i *f,
736
11.5M
                                         __m256i *y0, __m256i *y1) {
737
11.5M
  filter_16_2t_pixels(sig, f, y0, y1);
738
11.5M
}
739
740
static void vpx_highbd_filter_block1d16_v2_avx2(
741
    const uint16_t *src_ptr, ptrdiff_t src_pitch, uint16_t *dst_ptr,
742
303k
    ptrdiff_t dst_pitch, uint32_t height, const int16_t *filter, int bd) {
743
303k
  __m256i signal[3], res0, res1;
744
303k
  const __m256i max = _mm256_set1_epi16((1 << bd) - 1);
745
303k
  __m256i ff;
746
747
303k
  pack_2t_filter(filter, &ff);
748
303k
  pack_16x2_init(src_ptr, signal);
749
750
7.66M
  do {
751
7.66M
    pack_16x2_2t_pixels(src_ptr, src_pitch, signal);
752
7.66M
    filter_16x2_2t_pixels(signal, &ff, &res0, &res1);
753
7.66M
    store_16x1_pixels(&res0, &res1, &max, dst_ptr);
754
755
7.66M
    src_ptr += src_pitch;
756
7.66M
    dst_ptr += dst_pitch;
757
7.66M
    height -= 1;
758
7.66M
  } while (height > 0);
759
303k
}
760
761
297k
static INLINE void pack_8x1_2t_filter(const int16_t *filter, __m128i *f) {
762
297k
  const __m128i h = _mm_loadu_si128((const __m128i *)filter);
763
297k
  const __m128i p = _mm_set1_epi32(0x09080706);
764
297k
  f[0] = _mm_shuffle_epi8(h, p);
765
297k
}
766
767
297k
static void pack_8x2_init(const uint16_t *src, __m128i *sig) {
768
297k
  sig[2] = _mm_loadu_si128((const __m128i *)src);
769
297k
}
770
771
static INLINE void pack_8x2_2t_pixels_ver(const uint16_t *src, ptrdiff_t pitch,
772
3.23M
                                          __m128i *sig) {
773
  // load the next row
774
3.23M
  const __m128i u = _mm_loadu_si128((const __m128i *)(src + pitch));
775
3.23M
  sig[0] = _mm_unpacklo_epi16(sig[2], u);
776
3.23M
  sig[1] = _mm_unpackhi_epi16(sig[2], u);
777
3.23M
  sig[2] = u;
778
3.23M
}
779
780
static INLINE void filter_8_2t_pixels(const __m128i *sig, const __m128i *f,
781
3.23M
                                      __m128i *y0, __m128i *y1) {
782
3.23M
  const __m128i rounding = _mm_set1_epi32(1 << (CONV8_ROUNDING_BITS - 1));
783
3.23M
  __m128i x0 = _mm_madd_epi16(sig[0], *f);
784
3.23M
  __m128i x1 = _mm_madd_epi16(sig[1], *f);
785
3.23M
  x0 = _mm_add_epi32(x0, rounding);
786
3.23M
  x1 = _mm_add_epi32(x1, rounding);
787
3.23M
  *y0 = _mm_srai_epi32(x0, CONV8_ROUNDING_BITS);
788
3.23M
  *y1 = _mm_srai_epi32(x1, CONV8_ROUNDING_BITS);
789
3.23M
}
790
791
static INLINE void store_8x1_2t_pixels_ver(const __m128i *y0, const __m128i *y1,
792
2.20M
                                           const __m128i *mask, uint16_t *dst) {
793
2.20M
  __m128i res = _mm_packus_epi32(*y0, *y1);
794
2.20M
  res = _mm_min_epi16(res, *mask);
795
2.20M
  _mm_storeu_si128((__m128i *)dst, res);
796
2.20M
}
797
798
static void vpx_highbd_filter_block1d8_v2_avx2(
799
    const uint16_t *src_ptr, ptrdiff_t src_pitch, uint16_t *dst_ptr,
800
201k
    ptrdiff_t dst_pitch, uint32_t height, const int16_t *filter, int bd) {
801
201k
  __m128i signal[3], res0, res1;
802
201k
  const __m128i max = _mm_set1_epi16((1 << bd) - 1);
803
201k
  __m128i ff;
804
805
201k
  pack_8x1_2t_filter(filter, &ff);
806
201k
  pack_8x2_init(src_ptr, signal);
807
808
2.20M
  do {
809
2.20M
    pack_8x2_2t_pixels_ver(src_ptr, src_pitch, signal);
810
2.20M
    filter_8_2t_pixels(signal, &ff, &res0, &res1);
811
2.20M
    store_8x1_2t_pixels_ver(&res0, &res1, &max, dst_ptr);
812
813
2.20M
    src_ptr += src_pitch;
814
2.20M
    dst_ptr += dst_pitch;
815
2.20M
    height -= 1;
816
2.20M
  } while (height > 0);
817
201k
}
818
819
// Calculation with averaging the input pixels
820
821
static INLINE void store_8x1_avg_pixels(const __m256i *y0, const __m256i *mask,
822
0
                                        uint16_t *dst) {
823
0
  const __m128i a0 = _mm256_castsi256_si128(*y0);
824
0
  const __m128i a1 = _mm256_extractf128_si256(*y0, 1);
825
0
  __m128i res = _mm_packus_epi32(a0, a1);
826
0
  const __m128i pix = _mm_loadu_si128((const __m128i *)dst);
827
0
  res = _mm_min_epi16(res, _mm256_castsi256_si128(*mask));
828
0
  res = _mm_avg_epu16(res, pix);
829
0
  _mm_storeu_si128((__m128i *)dst, res);
830
0
}
831
832
static INLINE void store_8x2_avg_pixels(const __m256i *y0, const __m256i *y1,
833
                                        const __m256i *mask, uint16_t *dst,
834
1.72M
                                        ptrdiff_t pitch) {
835
1.72M
  __m256i a = _mm256_packus_epi32(*y0, *y1);
836
1.72M
  const __m128i pix0 = _mm_loadu_si128((const __m128i *)dst);
837
1.72M
  const __m128i pix1 = _mm_loadu_si128((const __m128i *)(dst + pitch));
838
1.72M
  const __m256i pix =
839
1.72M
      _mm256_insertf128_si256(_mm256_castsi128_si256(pix0), pix1, 1);
840
1.72M
  a = _mm256_min_epi16(a, *mask);
841
1.72M
  a = _mm256_avg_epu16(a, pix);
842
1.72M
  _mm_storeu_si128((__m128i *)dst, _mm256_castsi256_si128(a));
843
1.72M
  _mm_storeu_si128((__m128i *)(dst + pitch), _mm256_extractf128_si256(a, 1));
844
1.72M
}
845
846
static INLINE void store_16x1_avg_pixels(const __m256i *y0, const __m256i *y1,
847
6.19M
                                         const __m256i *mask, uint16_t *dst) {
848
6.19M
  __m256i a = _mm256_packus_epi32(*y0, *y1);
849
6.19M
  const __m256i pix = _mm256_loadu_si256((const __m256i *)dst);
850
6.19M
  a = _mm256_min_epi16(a, *mask);
851
6.19M
  a = _mm256_avg_epu16(a, pix);
852
6.19M
  _mm256_storeu_si256((__m256i *)dst, a);
853
6.19M
}
854
855
static INLINE void store_16x2_avg_pixels(const __m256i *y0, const __m256i *y1,
856
                                         const __m256i *mask, uint16_t *dst,
857
4.25M
                                         ptrdiff_t pitch) {
858
4.25M
  const __m256i pix0 = _mm256_loadu_si256((const __m256i *)dst);
859
4.25M
  const __m256i pix1 = _mm256_loadu_si256((const __m256i *)(dst + pitch));
860
4.25M
  __m256i p = _mm256_min_epi16(*y0, *mask);
861
4.25M
  p = _mm256_avg_epu16(p, pix0);
862
4.25M
  _mm256_storeu_si256((__m256i *)dst, p);
863
864
4.25M
  p = _mm256_min_epi16(*y1, *mask);
865
4.25M
  p = _mm256_avg_epu16(p, pix1);
866
4.25M
  _mm256_storeu_si256((__m256i *)(dst + pitch), p);
867
4.25M
}
868
869
static INLINE void store_8x1_2t_avg_pixels_ver(const __m128i *y0,
870
                                               const __m128i *y1,
871
                                               const __m128i *mask,
872
1.02M
                                               uint16_t *dst) {
873
1.02M
  __m128i res = _mm_packus_epi32(*y0, *y1);
874
1.02M
  const __m128i pix = _mm_loadu_si128((const __m128i *)dst);
875
1.02M
  res = _mm_min_epi16(res, *mask);
876
1.02M
  res = _mm_avg_epu16(res, pix);
877
1.02M
  _mm_storeu_si128((__m128i *)dst, res);
878
1.02M
}
879
880
static void vpx_highbd_filter_block1d8_h8_avg_avx2(
881
    const uint16_t *src_ptr, ptrdiff_t src_pitch, uint16_t *dst_ptr,
882
57.1k
    ptrdiff_t dst_pitch, uint32_t height, const int16_t *filter, int bd) {
883
57.1k
  __m256i signal[8], res0, res1;
884
57.1k
  const __m256i max = _mm256_set1_epi16((1 << bd) - 1);
885
886
57.1k
  __m256i ff[4];
887
57.1k
  pack_filters(filter, ff);
888
889
57.1k
  src_ptr -= 3;
890
229k
  do {
891
229k
    pack_8x2_pixels(src_ptr, src_pitch, signal);
892
229k
    filter_8x1_pixels(signal, ff, &res0);
893
229k
    filter_8x1_pixels(&signal[4], ff, &res1);
894
229k
    store_8x2_avg_pixels(&res0, &res1, &max, dst_ptr, dst_pitch);
895
229k
    height -= 2;
896
229k
    src_ptr += src_pitch << 1;
897
229k
    dst_ptr += dst_pitch << 1;
898
229k
  } while (height > 1);
899
900
57.1k
  if (height > 0) {
901
0
    pack_8x1_pixels(src_ptr, signal);
902
0
    filter_8x1_pixels(signal, ff, &res0);
903
0
    store_8x1_avg_pixels(&res0, &max, dst_ptr);
904
0
  }
905
57.1k
}
906
907
static void vpx_highbd_filter_block1d16_h8_avg_avx2(
908
    const uint16_t *src_ptr, ptrdiff_t src_pitch, uint16_t *dst_ptr,
909
46.0k
    ptrdiff_t dst_pitch, uint32_t height, const int16_t *filter, int bd) {
910
46.0k
  __m256i signal[8], res0, res1;
911
46.0k
  const __m256i max = _mm256_set1_epi16((1 << bd) - 1);
912
913
46.0k
  __m256i ff[4];
914
46.0k
  pack_filters(filter, ff);
915
916
46.0k
  src_ptr -= 3;
917
1.54M
  do {
918
1.54M
    pack_16x1_pixels(src_ptr, signal);
919
1.54M
    filter_8x1_pixels(signal, ff, &res0);
920
1.54M
    filter_8x1_pixels(&signal[4], ff, &res1);
921
1.54M
    store_16x1_avg_pixels(&res0, &res1, &max, dst_ptr);
922
1.54M
    height -= 1;
923
1.54M
    src_ptr += src_pitch;
924
1.54M
    dst_ptr += dst_pitch;
925
1.54M
  } while (height > 0);
926
46.0k
}
927
928
static void vpx_highbd_filter_block1d4_h4_avx2(
929
    const uint16_t *src_ptr, ptrdiff_t src_stride, uint16_t *dst_ptr,
930
8.72k
    ptrdiff_t dst_stride, uint32_t height, const int16_t *kernel, int bd) {
931
  // We extract the middle four elements of the kernel into two registers in
932
  // the form
933
  // ... k[3] k[2] k[3] k[2]
934
  // ... k[5] k[4] k[5] k[4]
935
  // Then we shuffle the source into
936
  // ... s[1] s[0] s[0] s[-1]
937
  // ... s[3] s[2] s[2] s[1]
938
  // Calling multiply and add gives us half of the sum. Calling add on the two
939
  // halves gives us the output. Since avx2 allows us to use 256-bit buffer, we
940
  // can do this two rows at a time.
941
942
8.72k
  __m256i src_reg, src_reg_shift_0, src_reg_shift_2;
943
8.72k
  __m256i res_reg;
944
8.72k
  __m256i idx_shift_0 =
945
8.72k
      _mm256_setr_epi8(0, 1, 2, 3, 2, 3, 4, 5, 4, 5, 6, 7, 6, 7, 8, 9, 0, 1, 2,
946
8.72k
                       3, 2, 3, 4, 5, 4, 5, 6, 7, 6, 7, 8, 9);
947
8.72k
  __m256i idx_shift_2 =
948
8.72k
      _mm256_setr_epi8(4, 5, 6, 7, 6, 7, 8, 9, 8, 9, 10, 11, 10, 11, 12, 13, 4,
949
8.72k
                       5, 6, 7, 6, 7, 8, 9, 8, 9, 10, 11, 10, 11, 12, 13);
950
951
8.72k
  __m128i kernel_reg_128;  // Kernel
952
8.72k
  __m256i kernel_reg, kernel_reg_23,
953
8.72k
      kernel_reg_45;  // Segments of the kernel used
954
8.72k
  const __m256i reg_round =
955
8.72k
      _mm256_set1_epi32(CONV8_ROUNDING_NUM);  // Used for rounding
956
8.72k
  const __m256i reg_max = _mm256_set1_epi16((1 << bd) - 1);
957
8.72k
  const ptrdiff_t unrolled_src_stride = src_stride << 1;
958
8.72k
  const ptrdiff_t unrolled_dst_stride = dst_stride << 1;
959
8.72k
  int h;
960
961
  // Start one pixel before as we need tap/2 - 1 = 1 sample from the past
962
8.72k
  src_ptr -= 1;
963
964
  // Load Kernel
965
8.72k
  kernel_reg_128 = _mm_loadu_si128((const __m128i *)kernel);
966
8.72k
  kernel_reg = _mm256_broadcastsi128_si256(kernel_reg_128);
967
8.72k
  kernel_reg_23 = _mm256_shuffle_epi32(kernel_reg, 0x55);
968
8.72k
  kernel_reg_45 = _mm256_shuffle_epi32(kernel_reg, 0xaa);
969
970
29.6k
  for (h = height; h >= 2; h -= 2) {
971
    // Load the source
972
20.8k
    src_reg = mm256_loadu2_si128(src_ptr, src_ptr + src_stride);
973
20.8k
    src_reg_shift_0 = _mm256_shuffle_epi8(src_reg, idx_shift_0);
974
20.8k
    src_reg_shift_2 = _mm256_shuffle_epi8(src_reg, idx_shift_2);
975
976
    // Get the output
977
20.8k
    res_reg = mm256_madd_add_epi32(&src_reg_shift_0, &src_reg_shift_2,
978
20.8k
                                   &kernel_reg_23, &kernel_reg_45);
979
980
    // Round the result
981
20.8k
    res_reg = mm256_round_epi32(&res_reg, &reg_round, CONV8_ROUNDING_BITS);
982
983
    // Finally combine to get the final dst
984
20.8k
    res_reg = _mm256_packus_epi32(res_reg, res_reg);
985
20.8k
    res_reg = _mm256_min_epi16(res_reg, reg_max);
986
20.8k
    mm256_storeu2_epi64((__m128i *)dst_ptr, (__m128i *)(dst_ptr + dst_stride),
987
20.8k
                        &res_reg);
988
989
20.8k
    src_ptr += unrolled_src_stride;
990
20.8k
    dst_ptr += unrolled_dst_stride;
991
20.8k
  }
992
993
  // Repeat for the last row if needed
994
8.72k
  if (h > 0) {
995
    // Load the source
996
3.44k
    src_reg = mm256_loadu2_si128(src_ptr, src_ptr + 4);
997
3.44k
    src_reg_shift_0 = _mm256_shuffle_epi8(src_reg, idx_shift_0);
998
3.44k
    src_reg_shift_2 = _mm256_shuffle_epi8(src_reg, idx_shift_2);
999
1000
    // Get the output
1001
3.44k
    res_reg = mm256_madd_add_epi32(&src_reg_shift_0, &src_reg_shift_2,
1002
3.44k
                                   &kernel_reg_23, &kernel_reg_45);
1003
1004
    // Round the result
1005
3.44k
    res_reg = mm256_round_epi32(&res_reg, &reg_round, CONV8_ROUNDING_BITS);
1006
1007
    // Finally combine to get the final dst
1008
3.44k
    res_reg = _mm256_packus_epi32(res_reg, res_reg);
1009
3.44k
    res_reg = _mm256_min_epi16(res_reg, reg_max);
1010
3.44k
    _mm_storel_epi64((__m128i *)dst_ptr, _mm256_castsi256_si128(res_reg));
1011
3.44k
  }
1012
8.72k
}
1013
1014
static void vpx_highbd_filter_block1d8_h4_avx2(
1015
    const uint16_t *src_ptr, ptrdiff_t src_stride, uint16_t *dst_ptr,
1016
104k
    ptrdiff_t dst_stride, uint32_t height, const int16_t *kernel, int bd) {
1017
  // We will extract the middle four elements of the kernel into two registers
1018
  // in the form
1019
  // ... k[3] k[2] k[3] k[2]
1020
  // ... k[5] k[4] k[5] k[4]
1021
  // Then we shuffle the source into
1022
  // ... s[1] s[0] s[0] s[-1]
1023
  // ... s[3] s[2] s[2] s[1]
1024
  // Calling multiply and add gives us half of the sum of the first half.
1025
  // Calling add gives us first half of the output. Repat again to get the whole
1026
  // output. Since avx2 allows us to use 256-bit buffer, we can do this two rows
1027
  // at a time.
1028
1029
104k
  __m256i src_reg, src_reg_shift_0, src_reg_shift_2;
1030
104k
  __m256i res_reg, res_first, res_last;
1031
104k
  __m256i idx_shift_0 =
1032
104k
      _mm256_setr_epi8(0, 1, 2, 3, 2, 3, 4, 5, 4, 5, 6, 7, 6, 7, 8, 9, 0, 1, 2,
1033
104k
                       3, 2, 3, 4, 5, 4, 5, 6, 7, 6, 7, 8, 9);
1034
104k
  __m256i idx_shift_2 =
1035
104k
      _mm256_setr_epi8(4, 5, 6, 7, 6, 7, 8, 9, 8, 9, 10, 11, 10, 11, 12, 13, 4,
1036
104k
                       5, 6, 7, 6, 7, 8, 9, 8, 9, 10, 11, 10, 11, 12, 13);
1037
1038
104k
  __m128i kernel_reg_128;  // Kernel
1039
104k
  __m256i kernel_reg, kernel_reg_23,
1040
104k
      kernel_reg_45;  // Segments of the kernel used
1041
104k
  const __m256i reg_round =
1042
104k
      _mm256_set1_epi32(CONV8_ROUNDING_NUM);  // Used for rounding
1043
104k
  const __m256i reg_max = _mm256_set1_epi16((1 << bd) - 1);
1044
104k
  const ptrdiff_t unrolled_src_stride = src_stride << 1;
1045
104k
  const ptrdiff_t unrolled_dst_stride = dst_stride << 1;
1046
104k
  int h;
1047
1048
  // Start one pixel before as we need tap/2 - 1 = 1 sample from the past
1049
104k
  src_ptr -= 1;
1050
1051
  // Load Kernel
1052
104k
  kernel_reg_128 = _mm_loadu_si128((const __m128i *)kernel);
1053
104k
  kernel_reg = _mm256_broadcastsi128_si256(kernel_reg_128);
1054
104k
  kernel_reg_23 = _mm256_shuffle_epi32(kernel_reg, 0x55);
1055
104k
  kernel_reg_45 = _mm256_shuffle_epi32(kernel_reg, 0xaa);
1056
1057
1.54M
  for (h = height; h >= 2; h -= 2) {
1058
    // Load the source
1059
1.43M
    src_reg = mm256_loadu2_si128(src_ptr, src_ptr + src_stride);
1060
1.43M
    src_reg_shift_0 = _mm256_shuffle_epi8(src_reg, idx_shift_0);
1061
1.43M
    src_reg_shift_2 = _mm256_shuffle_epi8(src_reg, idx_shift_2);
1062
1063
    // Result for first half
1064
1.43M
    res_first = mm256_madd_add_epi32(&src_reg_shift_0, &src_reg_shift_2,
1065
1.43M
                                     &kernel_reg_23, &kernel_reg_45);
1066
1067
    // Do again to get the second half of dst
1068
    // Load the source
1069
1.43M
    src_reg = mm256_loadu2_si128(src_ptr + 4, src_ptr + src_stride + 4);
1070
1.43M
    src_reg_shift_0 = _mm256_shuffle_epi8(src_reg, idx_shift_0);
1071
1.43M
    src_reg_shift_2 = _mm256_shuffle_epi8(src_reg, idx_shift_2);
1072
1073
    // Result for second half
1074
1.43M
    res_last = mm256_madd_add_epi32(&src_reg_shift_0, &src_reg_shift_2,
1075
1.43M
                                    &kernel_reg_23, &kernel_reg_45);
1076
1077
    // Round each result
1078
1.43M
    res_first = mm256_round_epi32(&res_first, &reg_round, CONV8_ROUNDING_BITS);
1079
1.43M
    res_last = mm256_round_epi32(&res_last, &reg_round, CONV8_ROUNDING_BITS);
1080
1081
    // Finally combine to get the final dst
1082
1.43M
    res_reg = _mm256_packus_epi32(res_first, res_last);
1083
1.43M
    res_reg = _mm256_min_epi16(res_reg, reg_max);
1084
1.43M
    mm256_store2_si128((__m128i *)dst_ptr, (__m128i *)(dst_ptr + dst_stride),
1085
1.43M
                       &res_reg);
1086
1087
1.43M
    src_ptr += unrolled_src_stride;
1088
1.43M
    dst_ptr += unrolled_dst_stride;
1089
1.43M
  }
1090
1091
  // Repeat for the last row if needed
1092
104k
  if (h > 0) {
1093
40.4k
    src_reg = mm256_loadu2_si128(src_ptr, src_ptr + 4);
1094
40.4k
    src_reg_shift_0 = _mm256_shuffle_epi8(src_reg, idx_shift_0);
1095
40.4k
    src_reg_shift_2 = _mm256_shuffle_epi8(src_reg, idx_shift_2);
1096
1097
40.4k
    res_reg = mm256_madd_add_epi32(&src_reg_shift_0, &src_reg_shift_2,
1098
40.4k
                                   &kernel_reg_23, &kernel_reg_45);
1099
1100
40.4k
    res_reg = mm256_round_epi32(&res_reg, &reg_round, CONV8_ROUNDING_BITS);
1101
1102
40.4k
    res_reg = _mm256_packus_epi32(res_reg, res_reg);
1103
40.4k
    res_reg = _mm256_min_epi16(res_reg, reg_max);
1104
1105
40.4k
    mm256_storeu2_epi64((__m128i *)dst_ptr, (__m128i *)(dst_ptr + 4), &res_reg);
1106
40.4k
  }
1107
104k
}
1108
1109
static void vpx_highbd_filter_block1d16_h4_avx2(
1110
    const uint16_t *src_ptr, ptrdiff_t src_stride, uint16_t *dst_ptr,
1111
36.8k
    ptrdiff_t dst_stride, uint32_t height, const int16_t *kernel, int bd) {
1112
36.8k
  vpx_highbd_filter_block1d8_h4_avx2(src_ptr, src_stride, dst_ptr, dst_stride,
1113
36.8k
                                     height, kernel, bd);
1114
36.8k
  vpx_highbd_filter_block1d8_h4_avx2(src_ptr + 8, src_stride, dst_ptr + 8,
1115
36.8k
                                     dst_stride, height, kernel, bd);
1116
36.8k
}
1117
1118
static void vpx_highbd_filter_block1d8_v8_avg_avx2(
1119
    const uint16_t *src_ptr, ptrdiff_t src_pitch, uint16_t *dst_ptr,
1120
383k
    ptrdiff_t dst_pitch, uint32_t height, const int16_t *filter, int bd) {
1121
383k
  __m256i signal[9], res0, res1;
1122
383k
  const __m256i max = _mm256_set1_epi16((1 << bd) - 1);
1123
1124
383k
  __m256i ff[4];
1125
383k
  pack_filters(filter, ff);
1126
1127
383k
  pack_8x9_init(src_ptr, src_pitch, signal);
1128
1129
1.42M
  do {
1130
1.42M
    pack_8x9_pixels(src_ptr, src_pitch, signal);
1131
1132
1.42M
    filter_8x9_pixels(signal, ff, &res0, &res1);
1133
1.42M
    store_8x2_avg_pixels(&res0, &res1, &max, dst_ptr, dst_pitch);
1134
1.42M
    update_pixels(signal);
1135
1136
1.42M
    src_ptr += src_pitch << 1;
1137
1.42M
    dst_ptr += dst_pitch << 1;
1138
1.42M
    height -= 2;
1139
1.42M
  } while (height > 0);
1140
383k
}
1141
1142
static void vpx_highbd_filter_block1d16_v8_avg_avx2(
1143
    const uint16_t *src_ptr, ptrdiff_t src_pitch, uint16_t *dst_ptr,
1144
266k
    ptrdiff_t dst_pitch, uint32_t height, const int16_t *filter, int bd) {
1145
266k
  __m256i signal[17], res0, res1;
1146
266k
  const __m256i max = _mm256_set1_epi16((1 << bd) - 1);
1147
1148
266k
  __m256i ff[4];
1149
266k
  pack_filters(filter, ff);
1150
1151
266k
  pack_16x9_init(src_ptr, src_pitch, signal);
1152
1153
4.25M
  do {
1154
4.25M
    pack_16x9_pixels(src_ptr, src_pitch, signal);
1155
4.25M
    filter_16x9_pixels(signal, ff, &res0, &res1);
1156
4.25M
    store_16x2_avg_pixels(&res0, &res1, &max, dst_ptr, dst_pitch);
1157
4.25M
    update_16x9_pixels(signal);
1158
1159
4.25M
    src_ptr += src_pitch << 1;
1160
4.25M
    dst_ptr += dst_pitch << 1;
1161
4.25M
    height -= 2;
1162
4.25M
  } while (height > 0);
1163
266k
}
1164
1165
static void vpx_highbd_filter_block1d8_h2_avg_avx2(
1166
    const uint16_t *src_ptr, ptrdiff_t src_pitch, uint16_t *dst_ptr,
1167
13.4k
    ptrdiff_t dst_pitch, uint32_t height, const int16_t *filter, int bd) {
1168
13.4k
  __m256i signal[2], res0, res1;
1169
13.4k
  const __m256i max = _mm256_set1_epi16((1 << bd) - 1);
1170
1171
13.4k
  __m256i ff;
1172
13.4k
  pack_2t_filter(filter, &ff);
1173
1174
13.4k
  src_ptr -= 3;
1175
65.6k
  do {
1176
65.6k
    pack_8x2_2t_pixels(src_ptr, src_pitch, signal);
1177
65.6k
    filter_16_2t_pixels(signal, &ff, &res0, &res1);
1178
65.6k
    store_8x2_avg_pixels(&res0, &res1, &max, dst_ptr, dst_pitch);
1179
65.6k
    height -= 2;
1180
65.6k
    src_ptr += src_pitch << 1;
1181
65.6k
    dst_ptr += dst_pitch << 1;
1182
65.6k
  } while (height > 1);
1183
1184
13.4k
  if (height > 0) {
1185
0
    pack_8x1_2t_pixels(src_ptr, signal);
1186
0
    filter_8x1_2t_pixels(signal, &ff, &res0);
1187
0
    store_8x1_avg_pixels(&res0, &max, dst_ptr);
1188
0
  }
1189
13.4k
}
1190
1191
static void vpx_highbd_filter_block1d16_h2_avg_avx2(
1192
    const uint16_t *src_ptr, ptrdiff_t src_pitch, uint16_t *dst_ptr,
1193
28.2k
    ptrdiff_t dst_pitch, uint32_t height, const int16_t *filter, int bd) {
1194
28.2k
  __m256i signal[2], res0, res1;
1195
28.2k
  const __m256i max = _mm256_set1_epi16((1 << bd) - 1);
1196
1197
28.2k
  __m256i ff;
1198
28.2k
  pack_2t_filter(filter, &ff);
1199
1200
28.2k
  src_ptr -= 3;
1201
722k
  do {
1202
722k
    pack_16x1_2t_pixels(src_ptr, signal);
1203
722k
    filter_16_2t_pixels(signal, &ff, &res0, &res1);
1204
722k
    store_16x1_avg_pixels(&res0, &res1, &max, dst_ptr);
1205
722k
    height -= 1;
1206
722k
    src_ptr += src_pitch;
1207
722k
    dst_ptr += dst_pitch;
1208
722k
  } while (height > 0);
1209
28.2k
}
1210
1211
static void vpx_highbd_filter_block1d16_v2_avg_avx2(
1212
    const uint16_t *src_ptr, ptrdiff_t src_pitch, uint16_t *dst_ptr,
1213
155k
    ptrdiff_t dst_pitch, uint32_t height, const int16_t *filter, int bd) {
1214
155k
  __m256i signal[3], res0, res1;
1215
155k
  const __m256i max = _mm256_set1_epi16((1 << bd) - 1);
1216
155k
  __m256i ff;
1217
1218
155k
  pack_2t_filter(filter, &ff);
1219
155k
  pack_16x2_init(src_ptr, signal);
1220
1221
3.92M
  do {
1222
3.92M
    pack_16x2_2t_pixels(src_ptr, src_pitch, signal);
1223
3.92M
    filter_16x2_2t_pixels(signal, &ff, &res0, &res1);
1224
3.92M
    store_16x1_avg_pixels(&res0, &res1, &max, dst_ptr);
1225
1226
3.92M
    src_ptr += src_pitch;
1227
3.92M
    dst_ptr += dst_pitch;
1228
3.92M
    height -= 1;
1229
3.92M
  } while (height > 0);
1230
155k
}
1231
1232
static void vpx_highbd_filter_block1d8_v2_avg_avx2(
1233
    const uint16_t *src_ptr, ptrdiff_t src_pitch, uint16_t *dst_ptr,
1234
95.9k
    ptrdiff_t dst_pitch, uint32_t height, const int16_t *filter, int bd) {
1235
95.9k
  __m128i signal[3], res0, res1;
1236
95.9k
  const __m128i max = _mm_set1_epi16((1 << bd) - 1);
1237
95.9k
  __m128i ff;
1238
1239
95.9k
  pack_8x1_2t_filter(filter, &ff);
1240
95.9k
  pack_8x2_init(src_ptr, signal);
1241
1242
1.02M
  do {
1243
1.02M
    pack_8x2_2t_pixels_ver(src_ptr, src_pitch, signal);
1244
1.02M
    filter_8_2t_pixels(signal, &ff, &res0, &res1);
1245
1.02M
    store_8x1_2t_avg_pixels_ver(&res0, &res1, &max, dst_ptr);
1246
1247
1.02M
    src_ptr += src_pitch;
1248
1.02M
    dst_ptr += dst_pitch;
1249
1.02M
    height -= 1;
1250
1.02M
  } while (height > 0);
1251
95.9k
}
1252
1253
static void vpx_highbd_filter_block1d4_v4_avx2(
1254
    const uint16_t *src_ptr, ptrdiff_t src_stride, uint16_t *dst_ptr,
1255
8.28k
    ptrdiff_t dst_stride, uint32_t height, const int16_t *kernel, int bd) {
1256
  // We will load two rows of pixels and rearrange them into the form
1257
  // ... s[1,0] s[0,0] s[0,0] s[-1,0]
1258
  // so that we can call multiply and add with the kernel partial output. Then
1259
  // we can call add with another row to get the output.
1260
1261
  // Register for source s[-1:3, :]
1262
8.28k
  __m256i src_reg_1, src_reg_2, src_reg_3;
1263
  // Interleaved rows of the source. lo is first half, hi second
1264
8.28k
  __m256i src_reg_m10, src_reg_01, src_reg_12, src_reg_23;
1265
8.28k
  __m256i src_reg_m1001, src_reg_1223;
1266
1267
  // Result after multiply and add
1268
8.28k
  __m256i res_reg;
1269
1270
8.28k
  __m128i kernel_reg_128;                            // Kernel
1271
8.28k
  __m256i kernel_reg, kernel_reg_23, kernel_reg_45;  // Segments of kernel used
1272
1273
8.28k
  const __m256i reg_round =
1274
8.28k
      _mm256_set1_epi32(CONV8_ROUNDING_NUM);  // Used for rounding
1275
8.28k
  const __m256i reg_max = _mm256_set1_epi16((1 << bd) - 1);
1276
8.28k
  const ptrdiff_t src_stride_unrolled = src_stride << 1;
1277
8.28k
  const ptrdiff_t dst_stride_unrolled = dst_stride << 1;
1278
8.28k
  int h;
1279
1280
  // Load Kernel
1281
8.28k
  kernel_reg_128 = _mm_loadu_si128((const __m128i *)kernel);
1282
8.28k
  kernel_reg = _mm256_broadcastsi128_si256(kernel_reg_128);
1283
8.28k
  kernel_reg_23 = _mm256_shuffle_epi32(kernel_reg, 0x55);
1284
8.28k
  kernel_reg_45 = _mm256_shuffle_epi32(kernel_reg, 0xaa);
1285
1286
  // Row -1 to row 0
1287
8.28k
  src_reg_m10 = mm256_loadu2_epi64((const __m128i *)src_ptr,
1288
8.28k
                                   (const __m128i *)(src_ptr + src_stride));
1289
1290
  // Row 0 to row 1
1291
8.28k
  src_reg_1 = _mm256_castsi128_si256(
1292
8.28k
      _mm_loadu_si128((const __m128i *)(src_ptr + src_stride * 2)));
1293
8.28k
  src_reg_01 = _mm256_permute2x128_si256(src_reg_m10, src_reg_1, 0x21);
1294
1295
  // First three rows
1296
8.28k
  src_reg_m1001 = _mm256_unpacklo_epi16(src_reg_m10, src_reg_01);
1297
1298
24.8k
  for (h = height; h > 1; h -= 2) {
1299
16.5k
    src_reg_2 = _mm256_castsi128_si256(
1300
16.5k
        _mm_loadl_epi64((const __m128i *)(src_ptr + src_stride * 3)));
1301
1302
16.5k
    src_reg_12 = _mm256_inserti128_si256(src_reg_1,
1303
16.5k
                                         _mm256_castsi256_si128(src_reg_2), 1);
1304
1305
16.5k
    src_reg_3 = _mm256_castsi128_si256(
1306
16.5k
        _mm_loadl_epi64((const __m128i *)(src_ptr + src_stride * 4)));
1307
1308
16.5k
    src_reg_23 = _mm256_inserti128_si256(src_reg_2,
1309
16.5k
                                         _mm256_castsi256_si128(src_reg_3), 1);
1310
1311
    // Last three rows
1312
16.5k
    src_reg_1223 = _mm256_unpacklo_epi16(src_reg_12, src_reg_23);
1313
1314
    // Output
1315
16.5k
    res_reg = mm256_madd_add_epi32(&src_reg_m1001, &src_reg_1223,
1316
16.5k
                                   &kernel_reg_23, &kernel_reg_45);
1317
1318
    // Round the words
1319
16.5k
    res_reg = mm256_round_epi32(&res_reg, &reg_round, CONV8_ROUNDING_BITS);
1320
1321
    // Combine to get the result
1322
16.5k
    res_reg = _mm256_packus_epi32(res_reg, res_reg);
1323
16.5k
    res_reg = _mm256_min_epi16(res_reg, reg_max);
1324
1325
    // Save the result
1326
16.5k
    mm256_storeu2_epi64((__m128i *)dst_ptr, (__m128i *)(dst_ptr + dst_stride),
1327
16.5k
                        &res_reg);
1328
1329
    // Update the source by two rows
1330
16.5k
    src_ptr += src_stride_unrolled;
1331
16.5k
    dst_ptr += dst_stride_unrolled;
1332
1333
16.5k
    src_reg_m1001 = src_reg_1223;
1334
16.5k
    src_reg_1 = src_reg_3;
1335
16.5k
  }
1336
8.28k
}
1337
1338
static void vpx_highbd_filter_block1d8_v4_avx2(
1339
    const uint16_t *src_ptr, ptrdiff_t src_stride, uint16_t *dst_ptr,
1340
102k
    ptrdiff_t dst_stride, uint32_t height, const int16_t *kernel, int bd) {
1341
  // We will load two rows of pixels and rearrange them into the form
1342
  // ... s[1,0] s[0,0] s[0,0] s[-1,0]
1343
  // so that we can call multiply and add with the kernel partial output. Then
1344
  // we can call add with another row to get the output.
1345
1346
  // Register for source s[-1:3, :]
1347
102k
  __m256i src_reg_1, src_reg_2, src_reg_3;
1348
  // Interleaved rows of the source. lo is first half, hi second
1349
102k
  __m256i src_reg_m10, src_reg_01, src_reg_12, src_reg_23;
1350
102k
  __m256i src_reg_m1001_lo, src_reg_m1001_hi, src_reg_1223_lo, src_reg_1223_hi;
1351
1352
102k
  __m128i kernel_reg_128;                            // Kernel
1353
102k
  __m256i kernel_reg, kernel_reg_23, kernel_reg_45;  // Segments of kernel
1354
1355
  // Result after multiply and add
1356
102k
  __m256i res_reg, res_reg_lo, res_reg_hi;
1357
1358
102k
  const __m256i reg_round =
1359
102k
      _mm256_set1_epi32(CONV8_ROUNDING_NUM);  // Used for rounding
1360
102k
  const __m256i reg_max = _mm256_set1_epi16((1 << bd) - 1);
1361
102k
  const ptrdiff_t src_stride_unrolled = src_stride << 1;
1362
102k
  const ptrdiff_t dst_stride_unrolled = dst_stride << 1;
1363
102k
  int h;
1364
1365
  // Load Kernel
1366
102k
  kernel_reg_128 = _mm_loadu_si128((const __m128i *)kernel);
1367
102k
  kernel_reg = _mm256_broadcastsi128_si256(kernel_reg_128);
1368
102k
  kernel_reg_23 = _mm256_shuffle_epi32(kernel_reg, 0x55);
1369
102k
  kernel_reg_45 = _mm256_shuffle_epi32(kernel_reg, 0xaa);
1370
1371
  // Row -1 to row 0
1372
102k
  src_reg_m10 = mm256_loadu2_si128((const __m128i *)src_ptr,
1373
102k
                                   (const __m128i *)(src_ptr + src_stride));
1374
1375
  // Row 0 to row 1
1376
102k
  src_reg_1 = _mm256_castsi128_si256(
1377
102k
      _mm_loadu_si128((const __m128i *)(src_ptr + src_stride * 2)));
1378
102k
  src_reg_01 = _mm256_permute2x128_si256(src_reg_m10, src_reg_1, 0x21);
1379
1380
  // First three rows
1381
102k
  src_reg_m1001_lo = _mm256_unpacklo_epi16(src_reg_m10, src_reg_01);
1382
102k
  src_reg_m1001_hi = _mm256_unpackhi_epi16(src_reg_m10, src_reg_01);
1383
1384
1.49M
  for (h = height; h > 1; h -= 2) {
1385
1.39M
    src_reg_2 = _mm256_castsi128_si256(
1386
1.39M
        _mm_loadu_si128((const __m128i *)(src_ptr + src_stride * 3)));
1387
1388
1.39M
    src_reg_12 = _mm256_inserti128_si256(src_reg_1,
1389
1.39M
                                         _mm256_castsi256_si128(src_reg_2), 1);
1390
1391
1.39M
    src_reg_3 = _mm256_castsi128_si256(
1392
1.39M
        _mm_loadu_si128((const __m128i *)(src_ptr + src_stride * 4)));
1393
1394
1.39M
    src_reg_23 = _mm256_inserti128_si256(src_reg_2,
1395
1.39M
                                         _mm256_castsi256_si128(src_reg_3), 1);
1396
1397
    // Last three rows
1398
1.39M
    src_reg_1223_lo = _mm256_unpacklo_epi16(src_reg_12, src_reg_23);
1399
1.39M
    src_reg_1223_hi = _mm256_unpackhi_epi16(src_reg_12, src_reg_23);
1400
1401
    // Output from first half
1402
1.39M
    res_reg_lo = mm256_madd_add_epi32(&src_reg_m1001_lo, &src_reg_1223_lo,
1403
1.39M
                                      &kernel_reg_23, &kernel_reg_45);
1404
1405
    // Output from second half
1406
1.39M
    res_reg_hi = mm256_madd_add_epi32(&src_reg_m1001_hi, &src_reg_1223_hi,
1407
1.39M
                                      &kernel_reg_23, &kernel_reg_45);
1408
1409
    // Round the words
1410
1.39M
    res_reg_lo =
1411
1.39M
        mm256_round_epi32(&res_reg_lo, &reg_round, CONV8_ROUNDING_BITS);
1412
1.39M
    res_reg_hi =
1413
1.39M
        mm256_round_epi32(&res_reg_hi, &reg_round, CONV8_ROUNDING_BITS);
1414
1415
    // Combine to get the result
1416
1.39M
    res_reg = _mm256_packus_epi32(res_reg_lo, res_reg_hi);
1417
1.39M
    res_reg = _mm256_min_epi16(res_reg, reg_max);
1418
1419
    // Save the result
1420
1.39M
    mm256_store2_si128((__m128i *)dst_ptr, (__m128i *)(dst_ptr + dst_stride),
1421
1.39M
                       &res_reg);
1422
1423
    // Update the source by two rows
1424
1.39M
    src_ptr += src_stride_unrolled;
1425
1.39M
    dst_ptr += dst_stride_unrolled;
1426
1427
1.39M
    src_reg_m1001_lo = src_reg_1223_lo;
1428
1.39M
    src_reg_m1001_hi = src_reg_1223_hi;
1429
1.39M
    src_reg_1 = src_reg_3;
1430
1.39M
  }
1431
102k
}
1432
1433
static void vpx_highbd_filter_block1d16_v4_avx2(
1434
    const uint16_t *src_ptr, ptrdiff_t src_stride, uint16_t *dst_ptr,
1435
36.7k
    ptrdiff_t dst_stride, uint32_t height, const int16_t *kernel, int bd) {
1436
36.7k
  vpx_highbd_filter_block1d8_v4_avx2(src_ptr, src_stride, dst_ptr, dst_stride,
1437
36.7k
                                     height, kernel, bd);
1438
36.7k
  vpx_highbd_filter_block1d8_v4_avx2(src_ptr + 8, src_stride, dst_ptr + 8,
1439
36.7k
                                     dst_stride, height, kernel, bd);
1440
36.7k
}
1441
1442
// From vpx_dsp/x86/vpx_high_subpixel_8t_sse2.asm.
1443
highbd_filter8_1dfunction vpx_highbd_filter_block1d4_h8_sse2;
1444
highbd_filter8_1dfunction vpx_highbd_filter_block1d4_v8_sse2;
1445
1446
// From vpx_dsp/x86/vpx_high_subpixel_bilinear_sse2.asm.
1447
highbd_filter8_1dfunction vpx_highbd_filter_block1d4_h2_sse2;
1448
highbd_filter8_1dfunction vpx_highbd_filter_block1d4_v2_sse2;
1449
1450
1.40M
#define vpx_highbd_filter_block1d4_h8_avx2 vpx_highbd_filter_block1d4_h8_sse2
1451
438k
#define vpx_highbd_filter_block1d4_h2_avx2 vpx_highbd_filter_block1d4_h2_sse2
1452
1.09M
#define vpx_highbd_filter_block1d4_v8_avx2 vpx_highbd_filter_block1d4_v8_sse2
1453
340k
#define vpx_highbd_filter_block1d4_v2_avx2 vpx_highbd_filter_block1d4_v2_sse2
1454
1455
// Use the [vh]8 version because there is no [vh]4 implementation.
1456
#define vpx_highbd_filter_block1d16_v4_avg_avx2 \
1457
0
  vpx_highbd_filter_block1d16_v8_avg_avx2
1458
#define vpx_highbd_filter_block1d16_h4_avg_avx2 \
1459
0
  vpx_highbd_filter_block1d16_h8_avg_avx2
1460
#define vpx_highbd_filter_block1d8_v4_avg_avx2 \
1461
0
  vpx_highbd_filter_block1d8_v8_avg_avx2
1462
#define vpx_highbd_filter_block1d8_h4_avg_avx2 \
1463
0
  vpx_highbd_filter_block1d8_h8_avg_avx2
1464
#define vpx_highbd_filter_block1d4_v4_avg_avx2 \
1465
0
  vpx_highbd_filter_block1d4_v8_avg_avx2
1466
#define vpx_highbd_filter_block1d4_h4_avg_avx2 \
1467
0
  vpx_highbd_filter_block1d4_h8_avg_avx2
1468
1469
HIGH_FUN_CONV_1D(horiz, x0_q4, x_step_q4, h, src, , avx2, 0)
1470
HIGH_FUN_CONV_1D(vert, y0_q4, y_step_q4, v,
1471
                 src - src_stride * (num_taps / 2 - 1), , avx2, 0)
1472
2.33M
HIGH_FUN_CONV_2D(, avx2, 0)
1473
1474
// From vpx_dsp/x86/vpx_high_subpixel_8t_sse2.asm.
1475
highbd_filter8_1dfunction vpx_highbd_filter_block1d4_h8_avg_sse2;
1476
highbd_filter8_1dfunction vpx_highbd_filter_block1d4_v8_avg_sse2;
1477
1478
// From vpx_dsp/x86/vpx_high_subpixel_bilinear_sse2.asm.
1479
highbd_filter8_1dfunction vpx_highbd_filter_block1d4_h2_avg_sse2;
1480
highbd_filter8_1dfunction vpx_highbd_filter_block1d4_v2_avg_sse2;
1481
1482
#define vpx_highbd_filter_block1d4_h8_avg_avx2 \
1483
78.0k
  vpx_highbd_filter_block1d4_h8_avg_sse2
1484
#define vpx_highbd_filter_block1d4_h2_avg_avx2 \
1485
19.5k
  vpx_highbd_filter_block1d4_h2_avg_sse2
1486
#define vpx_highbd_filter_block1d4_v8_avg_avx2 \
1487
521k
  vpx_highbd_filter_block1d4_v8_avg_sse2
1488
#define vpx_highbd_filter_block1d4_v2_avg_avx2 \
1489
141k
  vpx_highbd_filter_block1d4_v2_avg_sse2
1490
1491
HIGH_FUN_CONV_1D(avg_horiz, x0_q4, x_step_q4, h, src, avg_, avx2, 1)
1492
HIGH_FUN_CONV_1D(avg_vert, y0_q4, y_step_q4, v,
1493
                 src - src_stride * (num_taps / 2 - 1), avg_, avx2, 1)
1494
HIGH_FUN_CONV_2D(avg_, avx2, 1)
1495
1496
#undef HIGHBD_FUNC
1497
#endif  // HAVE_X86_ASM