Coverage Report

Created: 2026-11-12 08:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/aom/aom_dsp/x86/highbd_convolve_avx2.c
Line
Count
Source
1
/*
2
 * Copyright (c) 2017, Alliance for Open Media. All rights reserved.
3
 *
4
 * This source code is subject to the terms of the BSD 2 Clause License and
5
 * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
6
 * was not distributed with this source code in the LICENSE file, you can
7
 * obtain it at www.aomedia.org/license/software. If the Alliance for Open
8
 * Media Patent License 1.0 was not distributed with this source code in the
9
 * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
10
 */
11
#include <immintrin.h>
12
#include <string.h>
13
14
#include "config/aom_config.h"
15
#include "config/av1_rtcd.h"
16
17
#include "aom_dsp/x86/convolve.h"
18
#include "aom_dsp/x86/convolve_avx2.h"
19
#include "aom_dsp/x86/synonyms.h"
20
21
// -----------------------------------------------------------------------------
22
// Copy and average
23
24
#if HAVE_X86_ASM
25
static const uint8_t ip_shuffle_f2f3[32] = { 0, 1, 2, 3, 2, 3, 4, 5, 4, 5, 6,
26
                                             7, 6, 7, 8, 9, 0, 1, 2, 3, 2, 3,
27
                                             4, 5, 4, 5, 6, 7, 6, 7, 8, 9 };
28
static const uint8_t ip_shuffle_f4f5[32] = { 4, 5, 6,  7,  6,  7,  8,  9,
29
                                             8, 9, 10, 11, 10, 11, 12, 13,
30
                                             4, 5, 6,  7,  6,  7,  8,  9,
31
                                             8, 9, 10, 11, 10, 11, 12, 13 };
32
#endif  // HAVE_X86_ASM
33
34
void av1_highbd_convolve_x_sr_ssse3(const uint16_t *src, int src_stride,
35
                                    uint16_t *dst, int dst_stride, int w, int h,
36
                                    const InterpFilterParams *filter_params_x,
37
                                    const int subpel_x_qn,
38
                                    ConvolveParams *conv_params, int bd);
39
void av1_highbd_convolve_y_sr_ssse3(const uint16_t *src, int src_stride,
40
                                    uint16_t *dst, int dst_stride, int w, int h,
41
                                    const InterpFilterParams *filter_params_y,
42
                                    const int subpel_y_qn, int bd);
43
44
void av1_highbd_convolve_y_sr_avx2(const uint16_t *src, int src_stride,
45
                                   uint16_t *dst, int dst_stride, int w, int h,
46
                                   const InterpFilterParams *filter_params_y,
47
785k
                                   const int subpel_y_qn, int bd) {
48
785k
  if (filter_params_y->taps == 12) {
49
0
    av1_highbd_convolve_y_sr_ssse3(src, src_stride, dst, dst_stride, w, h,
50
0
                                   filter_params_y, subpel_y_qn, bd);
51
0
    return;
52
0
  }
53
785k
  int i, j;
54
785k
  const int fo_vert = filter_params_y->taps / 2 - 1;
55
785k
  const uint16_t *const src_ptr = src - fo_vert * src_stride;
56
57
785k
  __m256i s[8], coeffs_y[4];
58
59
785k
  const int bits = FILTER_BITS;
60
61
785k
  const __m128i round_shift_bits = _mm_cvtsi32_si128(bits);
62
785k
  const __m256i round_const_bits = _mm256_set1_epi32((1 << bits) >> 1);
63
785k
  const __m256i clip_pixel =
64
785k
      _mm256_set1_epi16(bd == 10 ? 1023 : (bd == 12 ? 4095 : 255));
65
785k
  const __m256i zero = _mm256_setzero_si256();
66
67
785k
  prepare_coeffs(filter_params_y, subpel_y_qn, coeffs_y);
68
69
1.87M
  for (j = 0; j < w; j += 8) {
70
1.08M
    const uint16_t *data = &src_ptr[j];
71
    /* Vertical filter */
72
1.08M
    {
73
1.08M
      __m256i src6;
74
1.08M
      __m256i s01 = _mm256_permute2x128_si256(
75
1.08M
          _mm256_castsi128_si256(
76
1.08M
              _mm_loadu_si128((__m128i *)(data + 0 * src_stride))),
77
1.08M
          _mm256_castsi128_si256(
78
1.08M
              _mm_loadu_si128((__m128i *)(data + 1 * src_stride))),
79
1.08M
          0x20);
80
1.08M
      __m256i s12 = _mm256_permute2x128_si256(
81
1.08M
          _mm256_castsi128_si256(
82
1.08M
              _mm_loadu_si128((__m128i *)(data + 1 * src_stride))),
83
1.08M
          _mm256_castsi128_si256(
84
1.08M
              _mm_loadu_si128((__m128i *)(data + 2 * src_stride))),
85
1.08M
          0x20);
86
1.08M
      __m256i s23 = _mm256_permute2x128_si256(
87
1.08M
          _mm256_castsi128_si256(
88
1.08M
              _mm_loadu_si128((__m128i *)(data + 2 * src_stride))),
89
1.08M
          _mm256_castsi128_si256(
90
1.08M
              _mm_loadu_si128((__m128i *)(data + 3 * src_stride))),
91
1.08M
          0x20);
92
1.08M
      __m256i s34 = _mm256_permute2x128_si256(
93
1.08M
          _mm256_castsi128_si256(
94
1.08M
              _mm_loadu_si128((__m128i *)(data + 3 * src_stride))),
95
1.08M
          _mm256_castsi128_si256(
96
1.08M
              _mm_loadu_si128((__m128i *)(data + 4 * src_stride))),
97
1.08M
          0x20);
98
1.08M
      __m256i s45 = _mm256_permute2x128_si256(
99
1.08M
          _mm256_castsi128_si256(
100
1.08M
              _mm_loadu_si128((__m128i *)(data + 4 * src_stride))),
101
1.08M
          _mm256_castsi128_si256(
102
1.08M
              _mm_loadu_si128((__m128i *)(data + 5 * src_stride))),
103
1.08M
          0x20);
104
1.08M
      src6 = _mm256_castsi128_si256(
105
1.08M
          _mm_loadu_si128((__m128i *)(data + 6 * src_stride)));
106
1.08M
      __m256i s56 = _mm256_permute2x128_si256(
107
1.08M
          _mm256_castsi128_si256(
108
1.08M
              _mm_loadu_si128((__m128i *)(data + 5 * src_stride))),
109
1.08M
          src6, 0x20);
110
111
1.08M
      s[0] = _mm256_unpacklo_epi16(s01, s12);
112
1.08M
      s[1] = _mm256_unpacklo_epi16(s23, s34);
113
1.08M
      s[2] = _mm256_unpacklo_epi16(s45, s56);
114
115
1.08M
      s[4] = _mm256_unpackhi_epi16(s01, s12);
116
1.08M
      s[5] = _mm256_unpackhi_epi16(s23, s34);
117
1.08M
      s[6] = _mm256_unpackhi_epi16(s45, s56);
118
119
7.67M
      for (i = 0; i < h; i += 2) {
120
6.58M
        data = &src_ptr[i * src_stride + j];
121
122
6.58M
        const __m256i s67 = _mm256_permute2x128_si256(
123
6.58M
            src6,
124
6.58M
            _mm256_castsi128_si256(
125
6.58M
                _mm_loadu_si128((__m128i *)(data + 7 * src_stride))),
126
6.58M
            0x20);
127
128
6.58M
        src6 = _mm256_castsi128_si256(
129
6.58M
            _mm_loadu_si128((__m128i *)(data + 8 * src_stride)));
130
131
6.58M
        const __m256i s78 = _mm256_permute2x128_si256(
132
6.58M
            _mm256_castsi128_si256(
133
6.58M
                _mm_loadu_si128((__m128i *)(data + 7 * src_stride))),
134
6.58M
            src6, 0x20);
135
136
6.58M
        s[3] = _mm256_unpacklo_epi16(s67, s78);
137
6.58M
        s[7] = _mm256_unpackhi_epi16(s67, s78);
138
139
6.58M
        const __m256i res_a = convolve(s, coeffs_y);
140
141
6.58M
        __m256i res_a_round = _mm256_sra_epi32(
142
6.58M
            _mm256_add_epi32(res_a, round_const_bits), round_shift_bits);
143
144
6.58M
        if (w - j > 4) {
145
5.48M
          const __m256i res_b = convolve(s + 4, coeffs_y);
146
5.48M
          __m256i res_b_round = _mm256_sra_epi32(
147
5.48M
              _mm256_add_epi32(res_b, round_const_bits), round_shift_bits);
148
149
5.48M
          __m256i res_16bit = _mm256_packs_epi32(res_a_round, res_b_round);
150
5.48M
          res_16bit = _mm256_min_epi16(res_16bit, clip_pixel);
151
5.48M
          res_16bit = _mm256_max_epi16(res_16bit, zero);
152
153
5.48M
          _mm_storeu_si128((__m128i *)&dst[i * dst_stride + j],
154
5.48M
                           _mm256_castsi256_si128(res_16bit));
155
5.48M
          _mm_storeu_si128((__m128i *)&dst[i * dst_stride + j + dst_stride],
156
5.48M
                           _mm256_extracti128_si256(res_16bit, 1));
157
5.48M
        } else if (w == 4) {
158
883k
          res_a_round = _mm256_packs_epi32(res_a_round, res_a_round);
159
883k
          res_a_round = _mm256_min_epi16(res_a_round, clip_pixel);
160
883k
          res_a_round = _mm256_max_epi16(res_a_round, zero);
161
162
883k
          _mm_storel_epi64((__m128i *)&dst[i * dst_stride + j],
163
883k
                           _mm256_castsi256_si128(res_a_round));
164
883k
          _mm_storel_epi64((__m128i *)&dst[i * dst_stride + j + dst_stride],
165
883k
                           _mm256_extracti128_si256(res_a_round, 1));
166
883k
        } else {
167
212k
          res_a_round = _mm256_packs_epi32(res_a_round, res_a_round);
168
212k
          res_a_round = _mm256_min_epi16(res_a_round, clip_pixel);
169
212k
          res_a_round = _mm256_max_epi16(res_a_round, zero);
170
171
212k
          xx_storel_32(&dst[i * dst_stride + j],
172
212k
                       _mm256_castsi256_si128(res_a_round));
173
212k
          xx_storel_32(&dst[i * dst_stride + j + dst_stride],
174
212k
                       _mm256_extracti128_si256(res_a_round, 1));
175
212k
        }
176
177
6.58M
        s[0] = s[1];
178
6.58M
        s[1] = s[2];
179
6.58M
        s[2] = s[3];
180
181
6.58M
        s[4] = s[5];
182
6.58M
        s[5] = s[6];
183
6.58M
        s[6] = s[7];
184
6.58M
      }
185
1.08M
    }
186
1.08M
  }
187
785k
}
188
189
void av1_highbd_convolve_x_sr_avx2(const uint16_t *src, int src_stride,
190
                                   uint16_t *dst, int dst_stride, int w, int h,
191
                                   const InterpFilterParams *filter_params_x,
192
                                   const int subpel_x_qn,
193
708k
                                   ConvolveParams *conv_params, int bd) {
194
708k
  if (filter_params_x->taps == 12) {
195
0
    av1_highbd_convolve_x_sr_ssse3(src, src_stride, dst, dst_stride, w, h,
196
0
                                   filter_params_x, subpel_x_qn, conv_params,
197
0
                                   bd);
198
0
    return;
199
0
  }
200
708k
  int i, j;
201
708k
  const int fo_horiz = filter_params_x->taps / 2 - 1;
202
708k
  const uint16_t *const src_ptr = src - fo_horiz;
203
204
  // Check that, even with 12-bit input, the intermediate values will fit
205
  // into an unsigned 16-bit intermediate array.
206
708k
  assert(bd + FILTER_BITS + 2 - conv_params->round_0 <= 16);
207
208
708k
  __m256i s[4], coeffs_x[4];
209
210
708k
  const __m256i round_const_x =
211
708k
      _mm256_set1_epi32(((1 << conv_params->round_0) >> 1));
212
708k
  const __m128i round_shift_x = _mm_cvtsi32_si128(conv_params->round_0);
213
214
708k
  const int bits = FILTER_BITS - conv_params->round_0;
215
708k
  const __m128i round_shift_bits = _mm_cvtsi32_si128(bits);
216
708k
  const __m256i round_const_bits = _mm256_set1_epi32((1 << bits) >> 1);
217
708k
  const __m256i clip_pixel =
218
18.4E
      _mm256_set1_epi16(bd == 10 ? 1023 : (bd == 12 ? 4095 : 255));
219
708k
  const __m256i zero = _mm256_setzero_si256();
220
221
708k
  assert(bits >= 0);
222
708k
  assert((FILTER_BITS - conv_params->round_1) >= 0 ||
223
708k
         ((conv_params->round_0 + conv_params->round_1) == 2 * FILTER_BITS));
224
225
708k
  prepare_coeffs(filter_params_x, subpel_x_qn, coeffs_x);
226
227
1.75M
  for (j = 0; j < w; j += 8) {
228
    /* Horizontal filter */
229
9.62M
    for (i = 0; i < h; i += 2) {
230
8.57M
      const __m256i row0 =
231
8.57M
          _mm256_loadu_si256((__m256i *)&src_ptr[i * src_stride + j]);
232
8.57M
      __m256i row1 =
233
8.57M
          _mm256_loadu_si256((__m256i *)&src_ptr[(i + 1) * src_stride + j]);
234
235
8.57M
      const __m256i r0 = _mm256_permute2x128_si256(row0, row1, 0x20);
236
8.57M
      const __m256i r1 = _mm256_permute2x128_si256(row0, row1, 0x31);
237
238
      // even pixels
239
8.57M
      s[0] = _mm256_alignr_epi8(r1, r0, 0);
240
8.57M
      s[1] = _mm256_alignr_epi8(r1, r0, 4);
241
8.57M
      s[2] = _mm256_alignr_epi8(r1, r0, 8);
242
8.57M
      s[3] = _mm256_alignr_epi8(r1, r0, 12);
243
244
8.57M
      __m256i res_even = convolve(s, coeffs_x);
245
8.57M
      res_even = _mm256_sra_epi32(_mm256_add_epi32(res_even, round_const_x),
246
8.57M
                                  round_shift_x);
247
248
      // odd pixels
249
8.57M
      s[0] = _mm256_alignr_epi8(r1, r0, 2);
250
8.57M
      s[1] = _mm256_alignr_epi8(r1, r0, 6);
251
8.57M
      s[2] = _mm256_alignr_epi8(r1, r0, 10);
252
8.57M
      s[3] = _mm256_alignr_epi8(r1, r0, 14);
253
254
8.57M
      __m256i res_odd = convolve(s, coeffs_x);
255
8.57M
      res_odd = _mm256_sra_epi32(_mm256_add_epi32(res_odd, round_const_x),
256
8.57M
                                 round_shift_x);
257
258
8.57M
      res_even = _mm256_sra_epi32(_mm256_add_epi32(res_even, round_const_bits),
259
8.57M
                                  round_shift_bits);
260
8.57M
      res_odd = _mm256_sra_epi32(_mm256_add_epi32(res_odd, round_const_bits),
261
8.57M
                                 round_shift_bits);
262
263
8.57M
      __m256i res_even1 = _mm256_packs_epi32(res_even, res_even);
264
8.57M
      __m256i res_odd1 = _mm256_packs_epi32(res_odd, res_odd);
265
266
8.57M
      __m256i res = _mm256_unpacklo_epi16(res_even1, res_odd1);
267
8.57M
      res = _mm256_min_epi16(res, clip_pixel);
268
8.57M
      res = _mm256_max_epi16(res, zero);
269
270
8.57M
      if (w - j > 4) {
271
7.61M
        _mm_storeu_si128((__m128i *)&dst[i * dst_stride + j],
272
7.61M
                         _mm256_castsi256_si128(res));
273
7.61M
        _mm_storeu_si128((__m128i *)&dst[i * dst_stride + j + dst_stride],
274
7.61M
                         _mm256_extracti128_si256(res, 1));
275
7.61M
      } else if (w == 4) {
276
777k
        _mm_storel_epi64((__m128i *)&dst[i * dst_stride + j],
277
777k
                         _mm256_castsi256_si128(res));
278
777k
        _mm_storel_epi64((__m128i *)&dst[i * dst_stride + j + dst_stride],
279
777k
                         _mm256_extracti128_si256(res, 1));
280
777k
      } else {
281
174k
        xx_storel_32(&dst[i * dst_stride + j], _mm256_castsi256_si128(res));
282
174k
        xx_storel_32(&dst[i * dst_stride + j + dst_stride],
283
174k
                     _mm256_extracti128_si256(res, 1));
284
174k
      }
285
8.57M
    }
286
1.04M
  }
287
708k
}
288
289
0
#define CONV8_ROUNDING_BITS (7)
290
291
// -----------------------------------------------------------------------------
292
// Horizontal and vertical filtering
293
294
#if HAVE_X86_ASM
295
// The aom_highbd_convolve8_{horiz,vert}_avx2 functions below also call SSE2
296
// assembly.
297
static const uint8_t signal_pattern_0[32] = { 0, 1, 2, 3, 2, 3, 4, 5, 4, 5, 6,
298
                                              7, 6, 7, 8, 9, 0, 1, 2, 3, 2, 3,
299
                                              4, 5, 4, 5, 6, 7, 6, 7, 8, 9 };
300
301
static const uint8_t signal_pattern_1[32] = { 4, 5, 6,  7,  6,  7,  8,  9,
302
                                              8, 9, 10, 11, 10, 11, 12, 13,
303
                                              4, 5, 6,  7,  6,  7,  8,  9,
304
                                              8, 9, 10, 11, 10, 11, 12, 13 };
305
306
static const uint8_t signal_pattern_2[32] = { 6,  7,  8,  9,  8,  9,  10, 11,
307
                                              10, 11, 12, 13, 12, 13, 14, 15,
308
                                              6,  7,  8,  9,  8,  9,  10, 11,
309
                                              10, 11, 12, 13, 12, 13, 14, 15 };
310
311
static const uint32_t signal_index[8] = { 2, 3, 4, 5, 2, 3, 4, 5 };
312
313
// -----------------------------------------------------------------------------
314
// Horizontal Filtering
315
316
0
static inline void pack_pixels(const __m256i *s, __m256i *p /*p[4]*/) {
317
0
  const __m256i idx = _mm256_loadu_si256((const __m256i *)signal_index);
318
0
  const __m256i sf0 = _mm256_loadu_si256((const __m256i *)signal_pattern_0);
319
0
  const __m256i sf1 = _mm256_loadu_si256((const __m256i *)signal_pattern_1);
320
0
  const __m256i c = _mm256_permutevar8x32_epi32(*s, idx);
321
322
0
  p[0] = _mm256_shuffle_epi8(*s, sf0);  // x0x6
323
0
  p[1] = _mm256_shuffle_epi8(*s, sf1);  // x1x7
324
0
  p[2] = _mm256_shuffle_epi8(c, sf0);   // x2x4
325
0
  p[3] = _mm256_shuffle_epi8(c, sf1);   // x3x5
326
0
}
327
328
// Note:
329
//  Shared by 8x2 and 16x1 block
330
static inline void pack_16_pixels(const __m256i *s0, const __m256i *s1,
331
0
                                  __m256i *x /*x[8]*/) {
332
0
  __m256i pp[8];
333
0
  pack_pixels(s0, pp);
334
0
  pack_pixels(s1, &pp[4]);
335
0
  x[0] = _mm256_permute2x128_si256(pp[0], pp[4], 0x20);
336
0
  x[1] = _mm256_permute2x128_si256(pp[1], pp[5], 0x20);
337
0
  x[2] = _mm256_permute2x128_si256(pp[2], pp[6], 0x20);
338
0
  x[3] = _mm256_permute2x128_si256(pp[3], pp[7], 0x20);
339
0
  x[4] = x[2];
340
0
  x[5] = x[3];
341
0
  x[6] = _mm256_permute2x128_si256(pp[0], pp[4], 0x31);
342
0
  x[7] = _mm256_permute2x128_si256(pp[1], pp[5], 0x31);
343
0
}
344
345
0
static inline void pack_8x1_pixels(const uint16_t *src, __m256i *x) {
346
0
  __m256i pp[8];
347
0
  __m256i s0;
348
0
  s0 = _mm256_loadu_si256((const __m256i *)src);
349
0
  pack_pixels(&s0, pp);
350
0
  x[0] = _mm256_permute2x128_si256(pp[0], pp[2], 0x30);
351
0
  x[1] = _mm256_permute2x128_si256(pp[1], pp[3], 0x30);
352
0
  x[2] = _mm256_permute2x128_si256(pp[2], pp[0], 0x30);
353
0
  x[3] = _mm256_permute2x128_si256(pp[3], pp[1], 0x30);
354
0
}
355
356
static inline void pack_8x2_pixels(const uint16_t *src, ptrdiff_t stride,
357
0
                                   __m256i *x) {
358
0
  __m256i s0, s1;
359
0
  s0 = _mm256_loadu_si256((const __m256i *)src);
360
0
  s1 = _mm256_loadu_si256((const __m256i *)(src + stride));
361
0
  pack_16_pixels(&s0, &s1, x);
362
0
}
363
364
0
static inline void pack_16x1_pixels(const uint16_t *src, __m256i *x) {
365
0
  __m256i s0, s1;
366
0
  s0 = _mm256_loadu_si256((const __m256i *)src);
367
0
  s1 = _mm256_loadu_si256((const __m256i *)(src + 8));
368
0
  pack_16_pixels(&s0, &s1, x);
369
0
}
370
371
// Note:
372
//  Shared by horizontal and vertical filtering
373
0
static inline void pack_filters(const int16_t *filter, __m256i *f /*f[4]*/) {
374
0
  const __m128i h = _mm_loadu_si128((const __m128i *)filter);
375
0
  const __m256i hh = _mm256_insertf128_si256(_mm256_castsi128_si256(h), h, 1);
376
0
  const __m256i p0 = _mm256_set1_epi32(0x03020100);
377
0
  const __m256i p1 = _mm256_set1_epi32(0x07060504);
378
0
  const __m256i p2 = _mm256_set1_epi32(0x0b0a0908);
379
0
  const __m256i p3 = _mm256_set1_epi32(0x0f0e0d0c);
380
0
  f[0] = _mm256_shuffle_epi8(hh, p0);
381
0
  f[1] = _mm256_shuffle_epi8(hh, p1);
382
0
  f[2] = _mm256_shuffle_epi8(hh, p2);
383
0
  f[3] = _mm256_shuffle_epi8(hh, p3);
384
0
}
385
386
static inline void pack_filters_4tap(const int16_t *filter,
387
0
                                     __m256i *f /*f[4]*/) {
388
0
  const __m128i h = _mm_loadu_si128((const __m128i *)filter);
389
0
  const __m256i coeff = _mm256_broadcastsi128_si256(h);
390
391
  // coeffs 2 3 2 3 2 3 2 3
392
0
  f[0] = _mm256_shuffle_epi32(coeff, 0x55);
393
  // coeffs 4 5 4 5 4 5 4 5
394
0
  f[1] = _mm256_shuffle_epi32(coeff, 0xaa);
395
0
}
396
397
static inline void filter_8x1_pixels(const __m256i *sig /*sig[4]*/,
398
                                     const __m256i *fil /*fil[4]*/,
399
0
                                     __m256i *y) {
400
0
  __m256i a, a0, a1;
401
402
0
  a0 = _mm256_madd_epi16(fil[0], sig[0]);
403
0
  a1 = _mm256_madd_epi16(fil[3], sig[3]);
404
0
  a = _mm256_add_epi32(a0, a1);
405
406
0
  a0 = _mm256_madd_epi16(fil[1], sig[1]);
407
0
  a1 = _mm256_madd_epi16(fil[2], sig[2]);
408
409
0
  {
410
0
    const __m256i min = _mm256_min_epi32(a0, a1);
411
0
    a = _mm256_add_epi32(a, min);
412
0
  }
413
0
  {
414
0
    const __m256i max = _mm256_max_epi32(a0, a1);
415
0
    a = _mm256_add_epi32(a, max);
416
0
  }
417
0
  {
418
0
    const __m256i rounding = _mm256_set1_epi32(1 << (CONV8_ROUNDING_BITS - 1));
419
0
    a = _mm256_add_epi32(a, rounding);
420
0
    *y = _mm256_srai_epi32(a, CONV8_ROUNDING_BITS);
421
0
  }
422
0
}
423
424
static inline void store_8x1_pixels(const __m256i *y, const __m256i *mask,
425
0
                                    uint16_t *dst) {
426
0
  const __m128i a0 = _mm256_castsi256_si128(*y);
427
0
  const __m128i a1 = _mm256_extractf128_si256(*y, 1);
428
0
  __m128i res = _mm_packus_epi32(a0, a1);
429
0
  res = _mm_min_epi16(res, _mm256_castsi256_si128(*mask));
430
0
  _mm_storeu_si128((__m128i *)dst, res);
431
0
}
432
433
static inline void store_8x2_pixels(const __m256i *y0, const __m256i *y1,
434
                                    const __m256i *mask, uint16_t *dst,
435
0
                                    ptrdiff_t pitch) {
436
0
  __m256i a = _mm256_packus_epi32(*y0, *y1);
437
0
  a = _mm256_min_epi16(a, *mask);
438
0
  _mm_storeu_si128((__m128i *)dst, _mm256_castsi256_si128(a));
439
0
  _mm_storeu_si128((__m128i *)(dst + pitch), _mm256_extractf128_si256(a, 1));
440
0
}
441
442
static inline void store_16x1_pixels(const __m256i *y0, const __m256i *y1,
443
0
                                     const __m256i *mask, uint16_t *dst) {
444
0
  __m256i a = _mm256_packus_epi32(*y0, *y1);
445
0
  a = _mm256_min_epi16(a, *mask);
446
0
  _mm256_storeu_si256((__m256i *)dst, a);
447
0
}
448
449
static void aom_highbd_filter_block1d8_h8_avx2(
450
    const uint16_t *src_ptr, ptrdiff_t src_pitch, uint16_t *dst_ptr,
451
0
    ptrdiff_t dst_pitch, uint32_t height, const int16_t *filter, int bd) {
452
0
  __m256i signal[8], res0, res1;
453
0
  const __m256i max = _mm256_set1_epi16((1 << bd) - 1);
454
455
0
  __m256i ff[4];
456
0
  pack_filters(filter, ff);
457
458
0
  src_ptr -= 3;
459
0
  do {
460
0
    pack_8x2_pixels(src_ptr, src_pitch, signal);
461
0
    filter_8x1_pixels(signal, ff, &res0);
462
0
    filter_8x1_pixels(&signal[4], ff, &res1);
463
0
    store_8x2_pixels(&res0, &res1, &max, dst_ptr, dst_pitch);
464
0
    height -= 2;
465
0
    src_ptr += src_pitch << 1;
466
0
    dst_ptr += dst_pitch << 1;
467
0
  } while (height > 1);
468
469
0
  if (height > 0) {
470
0
    pack_8x1_pixels(src_ptr, signal);
471
0
    filter_8x1_pixels(signal, ff, &res0);
472
0
    store_8x1_pixels(&res0, &max, dst_ptr);
473
0
  }
474
0
}
475
476
static void aom_highbd_filter_block1d16_h8_avx2(
477
    const uint16_t *src_ptr, ptrdiff_t src_pitch, uint16_t *dst_ptr,
478
0
    ptrdiff_t dst_pitch, uint32_t height, const int16_t *filter, int bd) {
479
0
  __m256i signal[8], res0, res1;
480
0
  const __m256i max = _mm256_set1_epi16((1 << bd) - 1);
481
482
0
  __m256i ff[4];
483
0
  pack_filters(filter, ff);
484
485
0
  src_ptr -= 3;
486
0
  do {
487
0
    pack_16x1_pixels(src_ptr, signal);
488
0
    filter_8x1_pixels(signal, ff, &res0);
489
0
    filter_8x1_pixels(&signal[4], ff, &res1);
490
0
    store_16x1_pixels(&res0, &res1, &max, dst_ptr);
491
0
    height -= 1;
492
0
    src_ptr += src_pitch;
493
0
    dst_ptr += dst_pitch;
494
0
  } while (height > 0);
495
0
}
496
497
static void aom_highbd_filter_block1d4_h4_avx2(
498
    const uint16_t *src_ptr, ptrdiff_t src_pitch, uint16_t *dst_ptr,
499
0
    ptrdiff_t dst_pitch, uint32_t height, const int16_t *filter, int bd) {
500
0
  const __m256i rounding = _mm256_set1_epi32(1 << (CONV8_ROUNDING_BITS - 1));
501
0
  __m256i ff[2], s[2];
502
0
  uint32_t i;
503
0
  const __m256i clip_pixel =
504
0
      _mm256_set1_epi16(bd == 10 ? 1023 : (bd == 12 ? 4095 : 255));
505
0
  const __m256i zero = _mm256_setzero_si256();
506
507
0
  static const uint8_t shuffle_mask[32] = { 0, 1, 2, 3, 2, 3, 4, 5, 4, 5, 6,
508
0
                                            7, 6, 7, 8, 9, 0, 1, 2, 3, 2, 3,
509
0
                                            4, 5, 4, 5, 6, 7, 6, 7, 8, 9 };
510
511
0
  __m256i mask = _mm256_loadu_si256((__m256i *)shuffle_mask);
512
0
  __m256i ip_mask_f2f3 = _mm256_loadu_si256((__m256i *)ip_shuffle_f2f3);
513
0
  __m256i ip_mask_f4f5 = _mm256_loadu_si256((__m256i *)ip_shuffle_f4f5);
514
515
0
  pack_filters_4tap(filter, ff);
516
0
  src_ptr -= 3;
517
0
  for (i = 0; i <= (height - 2); i += 2) {
518
0
    __m256i row0 = _mm256_castsi128_si256(
519
0
        _mm_loadu_si128((__m128i *)&src_ptr[i * src_pitch + 2]));
520
0
    __m256i row1 = _mm256_castsi128_si256(
521
0
        _mm_loadu_si128((__m128i *)&src_ptr[(i + 1) * src_pitch + 2]));
522
523
0
    s[0] = _mm256_inserti128_si256(row0, _mm256_castsi256_si128(row1), 1);
524
0
    s[1] = _mm256_alignr_epi8(s[0], s[0], 4);
525
526
0
    s[0] = _mm256_shuffle_epi8(s[0], mask);
527
0
    s[1] = _mm256_shuffle_epi8(s[1], mask);
528
529
0
    __m256i res = convolve_4tap(s, ff);
530
0
    res =
531
0
        _mm256_srai_epi32(_mm256_add_epi32(res, rounding), CONV8_ROUNDING_BITS);
532
533
0
    res = _mm256_packs_epi32(res, res);
534
0
    res = _mm256_min_epi16(res, clip_pixel);
535
0
    res = _mm256_max_epi16(res, zero);
536
537
0
    _mm_storel_epi64((__m128i *)&dst_ptr[i * dst_pitch],
538
0
                     _mm256_castsi256_si128(res));
539
0
    _mm_storel_epi64((__m128i *)&dst_ptr[(i + 1) * dst_pitch],
540
0
                     _mm256_extracti128_si256(res, 1));
541
0
  }
542
0
  if (height % 2 != 0) {
543
0
    i = height - 1;
544
0
    const __m256i row0_0 = _mm256_castsi128_si256(
545
0
        _mm_loadu_si128((__m128i *)&src_ptr[i * src_pitch + 2]));
546
0
    const __m256i row0_1 = _mm256_castsi128_si256(
547
0
        _mm_loadu_si128((__m128i *)&src_ptr[i * src_pitch + 6]));
548
549
0
    const __m256i r0 =
550
0
        _mm256_inserti128_si256(row0_0, _mm256_castsi256_si128(row0_1), 1);
551
552
0
    s[0] = _mm256_shuffle_epi8(r0, ip_mask_f2f3);
553
0
    s[1] = _mm256_shuffle_epi8(r0, ip_mask_f4f5);
554
555
0
    __m256i res = convolve_4tap(s, ff);
556
0
    res =
557
0
        _mm256_srai_epi32(_mm256_add_epi32(res, rounding), CONV8_ROUNDING_BITS);
558
559
0
    res = _mm256_packs_epi32(res, res);
560
0
    res = _mm256_min_epi16(res, clip_pixel);
561
0
    res = _mm256_max_epi16(res, zero);
562
563
0
    _mm_storel_epi64((__m128i *)&dst_ptr[i * dst_pitch],
564
0
                     _mm256_castsi256_si128(res));
565
0
  }
566
0
}
567
568
static void aom_highbd_filter_block1d8_h4_avx2(
569
    const uint16_t *src_ptr, ptrdiff_t src_pitch, uint16_t *dst_ptr,
570
0
    ptrdiff_t dst_pitch, uint32_t height, const int16_t *filter, int bd) {
571
0
  const __m256i rounding = _mm256_set1_epi32(1 << (CONV8_ROUNDING_BITS - 1));
572
0
  __m256i ff[2], s[2];
573
0
  uint32_t i = 0;
574
0
  const __m256i clip_pixel =
575
0
      _mm256_set1_epi16(bd == 10 ? 1023 : (bd == 12 ? 4095 : 255));
576
0
  const __m256i zero = _mm256_setzero_si256();
577
578
0
  static const uint8_t shuffle_mask[32] = { 0, 1, 8,  9,  2, 3, 10, 11,
579
0
                                            4, 5, 12, 13, 6, 7, 14, 15,
580
0
                                            0, 1, 8,  9,  2, 3, 10, 11,
581
0
                                            4, 5, 12, 13, 6, 7, 14, 15 };
582
583
0
  __m256i mask = _mm256_loadu_si256((__m256i *)shuffle_mask);
584
0
  __m256i ip_mask_f2f3 = _mm256_loadu_si256((__m256i *)ip_shuffle_f2f3);
585
0
  __m256i ip_mask_f4f5 = _mm256_loadu_si256((__m256i *)ip_shuffle_f4f5);
586
587
0
  pack_filters_4tap(filter, ff);
588
0
  src_ptr -= 3;
589
590
  /* Horizontal filter */
591
592
0
  for (i = 0; i <= (height - 2); i += 2) {
593
0
    const __m256i row0 =
594
0
        _mm256_loadu_si256((__m256i *)&src_ptr[i * src_pitch + 2]);
595
0
    __m256i row1 =
596
0
        _mm256_loadu_si256((__m256i *)&src_ptr[(i + 1) * src_pitch + 2]);
597
598
0
    const __m256i r0 =
599
0
        _mm256_inserti128_si256(row0, _mm256_castsi256_si128(row1), 1);
600
0
    const __m256i r1 = _mm256_permute2x128_si256(row0, row1, 0x31);
601
602
    // even pixels
603
0
    s[0] = r0;
604
0
    s[1] = _mm256_alignr_epi8(r1, r0, 4);
605
606
0
    __m256i res_even = convolve_4tap(s, ff);
607
0
    res_even = _mm256_srai_epi32(_mm256_add_epi32(res_even, rounding),
608
0
                                 CONV8_ROUNDING_BITS);
609
610
    // odd pixels
611
0
    s[0] = _mm256_alignr_epi8(r1, r0, 2);
612
0
    s[1] = _mm256_alignr_epi8(r1, r0, 6);
613
614
0
    __m256i res_odd = convolve_4tap(s, ff);
615
0
    res_odd = _mm256_srai_epi32(_mm256_add_epi32(res_odd, rounding),
616
0
                                CONV8_ROUNDING_BITS);
617
618
0
    __m256i res = _mm256_packs_epi32(res_even, res_odd);
619
0
    res = _mm256_shuffle_epi8(res, mask);
620
621
0
    res = _mm256_min_epi16(res, clip_pixel);
622
0
    res = _mm256_max_epi16(res, zero);
623
624
0
    _mm_storeu_si128((__m128i *)&dst_ptr[i * dst_pitch],
625
0
                     _mm256_castsi256_si128(res));
626
0
    _mm_storeu_si128((__m128i *)&dst_ptr[i * dst_pitch + dst_pitch],
627
0
                     _mm256_extracti128_si256(res, 1));
628
0
  }
629
630
0
  if (height % 2 != 0) {
631
0
    i = height - 1;
632
0
    const __m256i row0_0 =
633
0
        _mm256_loadu_si256((__m256i *)&src_ptr[i * src_pitch + 2]);
634
0
    const __m256i row0_1 =
635
0
        _mm256_loadu_si256((__m256i *)&src_ptr[i * src_pitch + 6]);
636
637
0
    const __m256i r0 =
638
0
        _mm256_inserti128_si256(row0_0, _mm256_castsi256_si128(row0_1), 1);
639
640
0
    s[0] = _mm256_shuffle_epi8(r0, ip_mask_f2f3);
641
0
    s[1] = _mm256_shuffle_epi8(r0, ip_mask_f4f5);
642
643
0
    __m256i res = convolve_4tap(s, ff);
644
0
    res =
645
0
        _mm256_srai_epi32(_mm256_add_epi32(res, rounding), CONV8_ROUNDING_BITS);
646
647
0
    res = _mm256_packs_epi32(res, res);
648
0
    res = _mm256_min_epi16(res, clip_pixel);
649
0
    res = _mm256_max_epi16(res, zero);
650
651
0
    _mm_storel_epi64((__m128i *)&dst_ptr[i * dst_pitch],
652
0
                     _mm256_castsi256_si128(res));
653
0
    _mm_storel_epi64((__m128i *)&dst_ptr[i * dst_pitch + 4],
654
0
                     _mm256_extracti128_si256(res, 1));
655
0
  }
656
0
}
657
658
static void aom_highbd_filter_block1d16_h4_avx2(
659
    const uint16_t *src_ptr, ptrdiff_t src_pitch, uint16_t *dst_ptr,
660
0
    ptrdiff_t dst_pitch, uint32_t height, const int16_t *filter, int bd) {
661
0
  aom_highbd_filter_block1d8_h4_avx2(src_ptr, src_pitch, dst_ptr, dst_pitch,
662
0
                                     height, filter, bd);
663
0
  aom_highbd_filter_block1d8_h4_avx2(src_ptr + 8, src_pitch, dst_ptr + 8,
664
0
                                     dst_pitch, height, filter, bd);
665
0
}
666
667
// -----------------------------------------------------------------------------
668
// 2-tap horizontal filtering
669
670
0
static inline void pack_2t_filter(const int16_t *filter, __m256i *f) {
671
0
  const __m128i h = _mm_loadu_si128((const __m128i *)filter);
672
0
  const __m256i hh = _mm256_insertf128_si256(_mm256_castsi128_si256(h), h, 1);
673
0
  const __m256i p = _mm256_set1_epi32(0x09080706);
674
0
  f[0] = _mm256_shuffle_epi8(hh, p);
675
0
}
676
677
// can be used by pack_8x2_2t_pixels() and pack_16x1_2t_pixels()
678
// the difference is s0/s1 specifies first and second rows or,
679
// first 16 samples and 8-sample shifted 16 samples
680
static inline void pack_16_2t_pixels(const __m256i *s0, const __m256i *s1,
681
0
                                     __m256i *sig) {
682
0
  const __m256i idx = _mm256_loadu_si256((const __m256i *)signal_index);
683
0
  const __m256i sf2 = _mm256_loadu_si256((const __m256i *)signal_pattern_2);
684
0
  __m256i x0 = _mm256_shuffle_epi8(*s0, sf2);
685
0
  __m256i x1 = _mm256_shuffle_epi8(*s1, sf2);
686
0
  __m256i r0 = _mm256_permutevar8x32_epi32(*s0, idx);
687
0
  __m256i r1 = _mm256_permutevar8x32_epi32(*s1, idx);
688
0
  r0 = _mm256_shuffle_epi8(r0, sf2);
689
0
  r1 = _mm256_shuffle_epi8(r1, sf2);
690
0
  sig[0] = _mm256_permute2x128_si256(x0, x1, 0x20);
691
0
  sig[1] = _mm256_permute2x128_si256(r0, r1, 0x20);
692
0
}
693
694
static inline void pack_8x2_2t_pixels(const uint16_t *src,
695
0
                                      const ptrdiff_t pitch, __m256i *sig) {
696
0
  const __m256i r0 = _mm256_loadu_si256((const __m256i *)src);
697
0
  const __m256i r1 = _mm256_loadu_si256((const __m256i *)(src + pitch));
698
0
  pack_16_2t_pixels(&r0, &r1, sig);
699
0
}
700
701
static inline void pack_16x1_2t_pixels(const uint16_t *src,
702
0
                                       __m256i *sig /*sig[2]*/) {
703
0
  const __m256i r0 = _mm256_loadu_si256((const __m256i *)src);
704
0
  const __m256i r1 = _mm256_loadu_si256((const __m256i *)(src + 8));
705
0
  pack_16_2t_pixels(&r0, &r1, sig);
706
0
}
707
708
static inline void pack_8x1_2t_pixels(const uint16_t *src,
709
0
                                      __m256i *sig /*sig[2]*/) {
710
0
  const __m256i idx = _mm256_loadu_si256((const __m256i *)signal_index);
711
0
  const __m256i sf2 = _mm256_loadu_si256((const __m256i *)signal_pattern_2);
712
0
  __m256i r0 = _mm256_loadu_si256((const __m256i *)src);
713
0
  __m256i x0 = _mm256_shuffle_epi8(r0, sf2);
714
0
  r0 = _mm256_permutevar8x32_epi32(r0, idx);
715
0
  r0 = _mm256_shuffle_epi8(r0, sf2);
716
0
  sig[0] = _mm256_permute2x128_si256(x0, r0, 0x20);
717
0
}
718
719
// can be used by filter_8x2_2t_pixels() and filter_16x1_2t_pixels()
720
static inline void filter_16_2t_pixels(const __m256i *sig, const __m256i *f,
721
0
                                       __m256i *y0, __m256i *y1) {
722
0
  const __m256i rounding = _mm256_set1_epi32(1 << (CONV8_ROUNDING_BITS - 1));
723
0
  __m256i x0 = _mm256_madd_epi16(sig[0], *f);
724
0
  __m256i x1 = _mm256_madd_epi16(sig[1], *f);
725
0
  x0 = _mm256_add_epi32(x0, rounding);
726
0
  x1 = _mm256_add_epi32(x1, rounding);
727
0
  *y0 = _mm256_srai_epi32(x0, CONV8_ROUNDING_BITS);
728
0
  *y1 = _mm256_srai_epi32(x1, CONV8_ROUNDING_BITS);
729
0
}
730
731
static inline void filter_8x1_2t_pixels(const __m256i *sig, const __m256i *f,
732
0
                                        __m256i *y0) {
733
0
  const __m256i rounding = _mm256_set1_epi32(1 << (CONV8_ROUNDING_BITS - 1));
734
0
  __m256i x0 = _mm256_madd_epi16(sig[0], *f);
735
0
  x0 = _mm256_add_epi32(x0, rounding);
736
0
  *y0 = _mm256_srai_epi32(x0, CONV8_ROUNDING_BITS);
737
0
}
738
739
static void aom_highbd_filter_block1d8_h2_avx2(
740
    const uint16_t *src_ptr, ptrdiff_t src_pitch, uint16_t *dst_ptr,
741
0
    ptrdiff_t dst_pitch, uint32_t height, const int16_t *filter, int bd) {
742
0
  __m256i signal[2], res0, res1;
743
0
  const __m256i max = _mm256_set1_epi16((1 << bd) - 1);
744
745
0
  __m256i ff;
746
0
  pack_2t_filter(filter, &ff);
747
748
0
  src_ptr -= 3;
749
0
  do {
750
0
    pack_8x2_2t_pixels(src_ptr, src_pitch, signal);
751
0
    filter_16_2t_pixels(signal, &ff, &res0, &res1);
752
0
    store_8x2_pixels(&res0, &res1, &max, dst_ptr, dst_pitch);
753
0
    height -= 2;
754
0
    src_ptr += src_pitch << 1;
755
0
    dst_ptr += dst_pitch << 1;
756
0
  } while (height > 1);
757
758
0
  if (height > 0) {
759
0
    pack_8x1_2t_pixels(src_ptr, signal);
760
0
    filter_8x1_2t_pixels(signal, &ff, &res0);
761
0
    store_8x1_pixels(&res0, &max, dst_ptr);
762
0
  }
763
0
}
764
765
static void aom_highbd_filter_block1d16_h2_avx2(
766
    const uint16_t *src_ptr, ptrdiff_t src_pitch, uint16_t *dst_ptr,
767
0
    ptrdiff_t dst_pitch, uint32_t height, const int16_t *filter, int bd) {
768
0
  __m256i signal[2], res0, res1;
769
0
  const __m256i max = _mm256_set1_epi16((1 << bd) - 1);
770
771
0
  __m256i ff;
772
0
  pack_2t_filter(filter, &ff);
773
774
0
  src_ptr -= 3;
775
0
  do {
776
0
    pack_16x1_2t_pixels(src_ptr, signal);
777
0
    filter_16_2t_pixels(signal, &ff, &res0, &res1);
778
0
    store_16x1_pixels(&res0, &res1, &max, dst_ptr);
779
0
    height -= 1;
780
0
    src_ptr += src_pitch;
781
0
    dst_ptr += dst_pitch;
782
0
  } while (height > 0);
783
0
}
784
785
// -----------------------------------------------------------------------------
786
// Vertical Filtering
787
788
0
static void pack_8x9_init(const uint16_t *src, ptrdiff_t pitch, __m256i *sig) {
789
0
  __m256i s0 = _mm256_castsi128_si256(_mm_loadu_si128((const __m128i *)src));
790
0
  __m256i s1 =
791
0
      _mm256_castsi128_si256(_mm_loadu_si128((const __m128i *)(src + pitch)));
792
0
  __m256i s2 = _mm256_castsi128_si256(
793
0
      _mm_loadu_si128((const __m128i *)(src + 2 * pitch)));
794
0
  __m256i s3 = _mm256_castsi128_si256(
795
0
      _mm_loadu_si128((const __m128i *)(src + 3 * pitch)));
796
0
  __m256i s4 = _mm256_castsi128_si256(
797
0
      _mm_loadu_si128((const __m128i *)(src + 4 * pitch)));
798
0
  __m256i s5 = _mm256_castsi128_si256(
799
0
      _mm_loadu_si128((const __m128i *)(src + 5 * pitch)));
800
0
  __m256i s6 = _mm256_castsi128_si256(
801
0
      _mm_loadu_si128((const __m128i *)(src + 6 * pitch)));
802
803
0
  s0 = _mm256_inserti128_si256(s0, _mm256_castsi256_si128(s1), 1);
804
0
  s1 = _mm256_inserti128_si256(s1, _mm256_castsi256_si128(s2), 1);
805
0
  s2 = _mm256_inserti128_si256(s2, _mm256_castsi256_si128(s3), 1);
806
0
  s3 = _mm256_inserti128_si256(s3, _mm256_castsi256_si128(s4), 1);
807
0
  s4 = _mm256_inserti128_si256(s4, _mm256_castsi256_si128(s5), 1);
808
0
  s5 = _mm256_inserti128_si256(s5, _mm256_castsi256_si128(s6), 1);
809
810
0
  sig[0] = _mm256_unpacklo_epi16(s0, s1);
811
0
  sig[4] = _mm256_unpackhi_epi16(s0, s1);
812
0
  sig[1] = _mm256_unpacklo_epi16(s2, s3);
813
0
  sig[5] = _mm256_unpackhi_epi16(s2, s3);
814
0
  sig[2] = _mm256_unpacklo_epi16(s4, s5);
815
0
  sig[6] = _mm256_unpackhi_epi16(s4, s5);
816
0
  sig[8] = s6;
817
0
}
818
819
static inline void pack_8x9_pixels(const uint16_t *src, ptrdiff_t pitch,
820
0
                                   __m256i *sig) {
821
  // base + 7th row
822
0
  __m256i s0 = _mm256_castsi128_si256(
823
0
      _mm_loadu_si128((const __m128i *)(src + 7 * pitch)));
824
  // base + 8th row
825
0
  __m256i s1 = _mm256_castsi128_si256(
826
0
      _mm_loadu_si128((const __m128i *)(src + 8 * pitch)));
827
0
  __m256i s2 = _mm256_inserti128_si256(sig[8], _mm256_castsi256_si128(s0), 1);
828
0
  __m256i s3 = _mm256_inserti128_si256(s0, _mm256_castsi256_si128(s1), 1);
829
0
  sig[3] = _mm256_unpacklo_epi16(s2, s3);
830
0
  sig[7] = _mm256_unpackhi_epi16(s2, s3);
831
0
  sig[8] = s1;
832
0
}
833
834
static inline void filter_8x9_pixels(const __m256i *sig, const __m256i *f,
835
0
                                     __m256i *y0, __m256i *y1) {
836
0
  filter_8x1_pixels(sig, f, y0);
837
0
  filter_8x1_pixels(&sig[4], f, y1);
838
0
}
839
840
0
static inline void update_pixels(__m256i *sig) {
841
0
  int i;
842
0
  for (i = 0; i < 3; ++i) {
843
0
    sig[i] = sig[i + 1];
844
0
    sig[i + 4] = sig[i + 5];
845
0
  }
846
0
}
847
848
static void aom_highbd_filter_block1d8_v8_avx2(
849
    const uint16_t *src_ptr, ptrdiff_t src_pitch, uint16_t *dst_ptr,
850
0
    ptrdiff_t dst_pitch, uint32_t height, const int16_t *filter, int bd) {
851
0
  __m256i signal[9], res0, res1;
852
0
  const __m256i max = _mm256_set1_epi16((1 << bd) - 1);
853
854
0
  __m256i ff[4];
855
0
  pack_filters(filter, ff);
856
857
0
  pack_8x9_init(src_ptr, src_pitch, signal);
858
859
0
  do {
860
0
    pack_8x9_pixels(src_ptr, src_pitch, signal);
861
862
0
    filter_8x9_pixels(signal, ff, &res0, &res1);
863
0
    store_8x2_pixels(&res0, &res1, &max, dst_ptr, dst_pitch);
864
0
    update_pixels(signal);
865
866
0
    src_ptr += src_pitch << 1;
867
0
    dst_ptr += dst_pitch << 1;
868
0
    height -= 2;
869
0
  } while (height > 0);
870
0
}
871
872
0
static void pack_16x9_init(const uint16_t *src, ptrdiff_t pitch, __m256i *sig) {
873
0
  __m256i u0, u1, u2, u3;
874
  // load 0-6 rows
875
0
  const __m256i s0 = _mm256_loadu_si256((const __m256i *)src);
876
0
  const __m256i s1 = _mm256_loadu_si256((const __m256i *)(src + pitch));
877
0
  const __m256i s2 = _mm256_loadu_si256((const __m256i *)(src + 2 * pitch));
878
0
  const __m256i s3 = _mm256_loadu_si256((const __m256i *)(src + 3 * pitch));
879
0
  const __m256i s4 = _mm256_loadu_si256((const __m256i *)(src + 4 * pitch));
880
0
  const __m256i s5 = _mm256_loadu_si256((const __m256i *)(src + 5 * pitch));
881
0
  const __m256i s6 = _mm256_loadu_si256((const __m256i *)(src + 6 * pitch));
882
883
0
  u0 = _mm256_permute2x128_si256(s0, s1, 0x20);  // 0, 1 low
884
0
  u1 = _mm256_permute2x128_si256(s0, s1, 0x31);  // 0, 1 high
885
886
0
  u2 = _mm256_permute2x128_si256(s1, s2, 0x20);  // 1, 2 low
887
0
  u3 = _mm256_permute2x128_si256(s1, s2, 0x31);  // 1, 2 high
888
889
0
  sig[0] = _mm256_unpacklo_epi16(u0, u2);
890
0
  sig[4] = _mm256_unpackhi_epi16(u0, u2);
891
892
0
  sig[8] = _mm256_unpacklo_epi16(u1, u3);
893
0
  sig[12] = _mm256_unpackhi_epi16(u1, u3);
894
895
0
  u0 = _mm256_permute2x128_si256(s2, s3, 0x20);
896
0
  u1 = _mm256_permute2x128_si256(s2, s3, 0x31);
897
898
0
  u2 = _mm256_permute2x128_si256(s3, s4, 0x20);
899
0
  u3 = _mm256_permute2x128_si256(s3, s4, 0x31);
900
901
0
  sig[1] = _mm256_unpacklo_epi16(u0, u2);
902
0
  sig[5] = _mm256_unpackhi_epi16(u0, u2);
903
904
0
  sig[9] = _mm256_unpacklo_epi16(u1, u3);
905
0
  sig[13] = _mm256_unpackhi_epi16(u1, u3);
906
907
0
  u0 = _mm256_permute2x128_si256(s4, s5, 0x20);
908
0
  u1 = _mm256_permute2x128_si256(s4, s5, 0x31);
909
910
0
  u2 = _mm256_permute2x128_si256(s5, s6, 0x20);
911
0
  u3 = _mm256_permute2x128_si256(s5, s6, 0x31);
912
913
0
  sig[2] = _mm256_unpacklo_epi16(u0, u2);
914
0
  sig[6] = _mm256_unpackhi_epi16(u0, u2);
915
916
0
  sig[10] = _mm256_unpacklo_epi16(u1, u3);
917
0
  sig[14] = _mm256_unpackhi_epi16(u1, u3);
918
919
0
  sig[16] = s6;
920
0
}
921
922
static void pack_16x9_pixels(const uint16_t *src, ptrdiff_t pitch,
923
0
                             __m256i *sig) {
924
  // base + 7th row
925
0
  const __m256i s7 = _mm256_loadu_si256((const __m256i *)(src + 7 * pitch));
926
  // base + 8th row
927
0
  const __m256i s8 = _mm256_loadu_si256((const __m256i *)(src + 8 * pitch));
928
929
0
  __m256i u0, u1, u2, u3;
930
0
  u0 = _mm256_permute2x128_si256(sig[16], s7, 0x20);
931
0
  u1 = _mm256_permute2x128_si256(sig[16], s7, 0x31);
932
933
0
  u2 = _mm256_permute2x128_si256(s7, s8, 0x20);
934
0
  u3 = _mm256_permute2x128_si256(s7, s8, 0x31);
935
936
0
  sig[3] = _mm256_unpacklo_epi16(u0, u2);
937
0
  sig[7] = _mm256_unpackhi_epi16(u0, u2);
938
939
0
  sig[11] = _mm256_unpacklo_epi16(u1, u3);
940
0
  sig[15] = _mm256_unpackhi_epi16(u1, u3);
941
942
0
  sig[16] = s8;
943
0
}
944
945
static inline void filter_16x9_pixels(const __m256i *sig, const __m256i *f,
946
0
                                      __m256i *y0, __m256i *y1) {
947
0
  __m256i res[4];
948
0
  int i;
949
0
  for (i = 0; i < 4; ++i) {
950
0
    filter_8x1_pixels(&sig[i << 2], f, &res[i]);
951
0
  }
952
953
0
  {
954
0
    const __m256i l0l1 = _mm256_packus_epi32(res[0], res[1]);
955
0
    const __m256i h0h1 = _mm256_packus_epi32(res[2], res[3]);
956
0
    *y0 = _mm256_permute2x128_si256(l0l1, h0h1, 0x20);
957
0
    *y1 = _mm256_permute2x128_si256(l0l1, h0h1, 0x31);
958
0
  }
959
0
}
960
961
static inline void store_16x2_pixels(const __m256i *y0, const __m256i *y1,
962
                                     const __m256i *mask, uint16_t *dst,
963
0
                                     ptrdiff_t pitch) {
964
0
  __m256i p = _mm256_min_epi16(*y0, *mask);
965
0
  _mm256_storeu_si256((__m256i *)dst, p);
966
0
  p = _mm256_min_epi16(*y1, *mask);
967
0
  _mm256_storeu_si256((__m256i *)(dst + pitch), p);
968
0
}
969
970
0
static void update_16x9_pixels(__m256i *sig) {
971
0
  update_pixels(&sig[0]);
972
0
  update_pixels(&sig[8]);
973
0
}
974
975
static void aom_highbd_filter_block1d16_v8_avx2(
976
    const uint16_t *src_ptr, ptrdiff_t src_pitch, uint16_t *dst_ptr,
977
0
    ptrdiff_t dst_pitch, uint32_t height, const int16_t *filter, int bd) {
978
0
  __m256i signal[17], res0, res1;
979
0
  const __m256i max = _mm256_set1_epi16((1 << bd) - 1);
980
981
0
  __m256i ff[4];
982
0
  pack_filters(filter, ff);
983
984
0
  pack_16x9_init(src_ptr, src_pitch, signal);
985
986
0
  do {
987
0
    pack_16x9_pixels(src_ptr, src_pitch, signal);
988
0
    filter_16x9_pixels(signal, ff, &res0, &res1);
989
0
    store_16x2_pixels(&res0, &res1, &max, dst_ptr, dst_pitch);
990
0
    update_16x9_pixels(signal);
991
992
0
    src_ptr += src_pitch << 1;
993
0
    dst_ptr += dst_pitch << 1;
994
0
    height -= 2;
995
0
  } while (height > 0);
996
0
}
997
998
static void aom_highbd_filter_block1d4_v4_avx2(
999
    const uint16_t *src_ptr, ptrdiff_t src_pitch, uint16_t *dst_ptr,
1000
0
    ptrdiff_t dst_pitch, uint32_t height, const int16_t *filter, int bd) {
1001
0
  const int bits = FILTER_BITS;
1002
1003
0
  const __m128i round_shift_bits = _mm_cvtsi32_si128(bits);
1004
0
  const __m256i round_const_bits = _mm256_set1_epi32((1 << bits) >> 1);
1005
0
  const __m256i clip_pixel =
1006
0
      _mm256_set1_epi32(bd == 10 ? 1023 : (bd == 12 ? 4095 : 255));
1007
0
  const __m256i zero = _mm256_setzero_si256();
1008
0
  uint32_t i;
1009
0
  __m256i s[2], ff[2];
1010
1011
0
  pack_filters_4tap(filter, ff);
1012
1013
0
  const uint16_t *data = src_ptr;
1014
  /* Vertical filter */
1015
0
  {
1016
0
    __m128i s2 = _mm_loadl_epi64((__m128i *)(data + 2 * src_pitch));
1017
0
    __m128i s3 = _mm_loadl_epi64((__m128i *)(data + 3 * src_pitch));
1018
1019
0
    __m256i s23 = _mm256_inserti128_si256(_mm256_castsi128_si256(s2), s3, 1);
1020
1021
0
    __m128i s4 = _mm_loadl_epi64((__m128i *)(data + 4 * src_pitch));
1022
1023
0
    __m256i s34 = _mm256_inserti128_si256(_mm256_castsi128_si256(s3), s4, 1);
1024
1025
0
    s[0] = _mm256_unpacklo_epi16(s23, s34);
1026
1027
0
    for (i = 0; i < height; i += 2) {
1028
0
      data = &src_ptr[i * src_pitch];
1029
1030
0
      __m128i s5 = _mm_loadl_epi64((__m128i *)(data + 5 * src_pitch));
1031
0
      __m128i s6 = _mm_loadl_epi64((__m128i *)(data + 6 * src_pitch));
1032
1033
0
      __m256i s45 = _mm256_inserti128_si256(_mm256_castsi128_si256(s4), s5, 1);
1034
0
      __m256i s56 = _mm256_inserti128_si256(_mm256_castsi128_si256(s5), s6, 1);
1035
1036
0
      s[1] = _mm256_unpacklo_epi16(s45, s56);
1037
1038
0
      const __m256i res_a = convolve_4tap(s, ff);
1039
1040
0
      __m256i res_a_round = _mm256_sra_epi32(
1041
0
          _mm256_add_epi32(res_a, round_const_bits), round_shift_bits);
1042
1043
0
      __m256i res_16bit = _mm256_min_epi32(res_a_round, clip_pixel);
1044
0
      res_16bit = _mm256_max_epi32(res_16bit, zero);
1045
0
      res_16bit = _mm256_packs_epi32(res_16bit, res_16bit);
1046
1047
0
      _mm_storel_epi64((__m128i *)&dst_ptr[i * dst_pitch],
1048
0
                       _mm256_castsi256_si128(res_16bit));
1049
0
      _mm_storel_epi64((__m128i *)&dst_ptr[i * dst_pitch + dst_pitch],
1050
0
                       _mm256_extracti128_si256(res_16bit, 1));
1051
1052
0
      s[0] = s[1];
1053
0
      s4 = s6;
1054
0
    }
1055
0
  }
1056
0
}
1057
1058
static void aom_highbd_filter_block1d8_v4_avx2(
1059
    const uint16_t *src_ptr, ptrdiff_t src_pitch, uint16_t *dst_ptr,
1060
0
    ptrdiff_t dst_pitch, uint32_t height, const int16_t *filter, int bd) {
1061
0
  const int bits = FILTER_BITS;
1062
1063
0
  const __m128i round_shift_bits = _mm_cvtsi32_si128(bits);
1064
0
  const __m256i round_const_bits = _mm256_set1_epi32((1 << bits) >> 1);
1065
0
  const __m256i clip_pixel =
1066
0
      _mm256_set1_epi16(bd == 10 ? 1023 : (bd == 12 ? 4095 : 255));
1067
0
  const __m256i zero = _mm256_setzero_si256();
1068
0
  __m256i s[4], ff[2];
1069
0
  uint32_t i;
1070
0
  pack_filters_4tap(filter, ff);
1071
1072
0
  const uint16_t *data = src_ptr;
1073
  /* Vertical filter */
1074
0
  {
1075
0
    __m128i s2 = _mm_loadu_si128((__m128i *)(data + 2 * src_pitch));
1076
0
    __m128i s3 = _mm_loadu_si128((__m128i *)(data + 3 * src_pitch));
1077
1078
0
    __m256i s23 = _mm256_inserti128_si256(_mm256_castsi128_si256(s2), s3, 1);
1079
1080
0
    __m128i s4 = _mm_loadu_si128((__m128i *)(data + 4 * src_pitch));
1081
1082
0
    __m256i s34 = _mm256_inserti128_si256(_mm256_castsi128_si256(s3), s4, 1);
1083
1084
0
    s[0] = _mm256_unpacklo_epi16(s23, s34);
1085
0
    s[2] = _mm256_unpackhi_epi16(s23, s34);
1086
1087
0
    for (i = 0; i < height; i += 2) {
1088
0
      data = &src_ptr[i * src_pitch];
1089
1090
0
      __m128i s5 = _mm_loadu_si128((__m128i *)(data + 5 * src_pitch));
1091
0
      __m128i s6 = _mm_loadu_si128((__m128i *)(data + 6 * src_pitch));
1092
1093
0
      __m256i s45 = _mm256_inserti128_si256(_mm256_castsi128_si256(s4), s5, 1);
1094
0
      __m256i s56 = _mm256_inserti128_si256(_mm256_castsi128_si256(s5), s6, 1);
1095
1096
0
      s[1] = _mm256_unpacklo_epi16(s45, s56);
1097
0
      s[3] = _mm256_unpackhi_epi16(s45, s56);
1098
1099
0
      const __m256i res_a = convolve_4tap(s, ff);
1100
1101
0
      __m256i res_a_round = _mm256_sra_epi32(
1102
0
          _mm256_add_epi32(res_a, round_const_bits), round_shift_bits);
1103
1104
0
      const __m256i res_b = convolve_4tap(s + 2, ff);
1105
0
      __m256i res_b_round = _mm256_sra_epi32(
1106
0
          _mm256_add_epi32(res_b, round_const_bits), round_shift_bits);
1107
1108
0
      __m256i res_16bit = _mm256_packs_epi32(res_a_round, res_b_round);
1109
0
      res_16bit = _mm256_min_epi16(res_16bit, clip_pixel);
1110
0
      res_16bit = _mm256_max_epi16(res_16bit, zero);
1111
1112
0
      _mm_storeu_si128((__m128i *)&dst_ptr[i * dst_pitch],
1113
0
                       _mm256_castsi256_si128(res_16bit));
1114
0
      _mm_storeu_si128((__m128i *)&dst_ptr[i * dst_pitch + dst_pitch],
1115
0
                       _mm256_extracti128_si256(res_16bit, 1));
1116
1117
0
      s[0] = s[1];
1118
0
      s[2] = s[3];
1119
0
      s4 = s6;
1120
0
    }
1121
0
  }
1122
0
}
1123
1124
static void aom_highbd_filter_block1d16_v4_avx2(
1125
    const uint16_t *src_ptr, ptrdiff_t src_pitch, uint16_t *dst_ptr,
1126
0
    ptrdiff_t dst_pitch, uint32_t height, const int16_t *filter, int bd) {
1127
0
  aom_highbd_filter_block1d8_v4_avx2(src_ptr, src_pitch, dst_ptr, dst_pitch,
1128
0
                                     height, filter, bd);
1129
1130
0
  aom_highbd_filter_block1d8_v4_avx2(src_ptr + 8, src_pitch, dst_ptr + 8,
1131
0
                                     dst_pitch, height, filter, bd);
1132
0
}
1133
1134
// -----------------------------------------------------------------------------
1135
// 2-tap vertical filtering
1136
1137
0
static void pack_16x2_init(const uint16_t *src, __m256i *sig) {
1138
0
  sig[2] = _mm256_loadu_si256((const __m256i *)src);
1139
0
}
1140
1141
static inline void pack_16x2_2t_pixels(const uint16_t *src, ptrdiff_t pitch,
1142
0
                                       __m256i *sig) {
1143
  // load the next row
1144
0
  const __m256i u = _mm256_loadu_si256((const __m256i *)(src + pitch));
1145
0
  sig[0] = _mm256_unpacklo_epi16(sig[2], u);
1146
0
  sig[1] = _mm256_unpackhi_epi16(sig[2], u);
1147
0
  sig[2] = u;
1148
0
}
1149
1150
static inline void filter_16x2_2t_pixels(const __m256i *sig, const __m256i *f,
1151
0
                                         __m256i *y0, __m256i *y1) {
1152
0
  filter_16_2t_pixels(sig, f, y0, y1);
1153
0
}
1154
1155
static void aom_highbd_filter_block1d16_v2_avx2(
1156
    const uint16_t *src_ptr, ptrdiff_t src_pitch, uint16_t *dst_ptr,
1157
0
    ptrdiff_t dst_pitch, uint32_t height, const int16_t *filter, int bd) {
1158
0
  __m256i signal[3], res0, res1;
1159
0
  const __m256i max = _mm256_set1_epi16((1 << bd) - 1);
1160
0
  __m256i ff;
1161
1162
0
  pack_2t_filter(filter, &ff);
1163
0
  pack_16x2_init(src_ptr, signal);
1164
1165
0
  do {
1166
0
    pack_16x2_2t_pixels(src_ptr, src_pitch, signal);
1167
0
    filter_16x2_2t_pixels(signal, &ff, &res0, &res1);
1168
0
    store_16x1_pixels(&res0, &res1, &max, dst_ptr);
1169
1170
0
    src_ptr += src_pitch;
1171
0
    dst_ptr += dst_pitch;
1172
0
    height -= 1;
1173
0
  } while (height > 0);
1174
0
}
1175
1176
0
static inline void pack_8x1_2t_filter(const int16_t *filter, __m128i *f) {
1177
0
  const __m128i h = _mm_loadu_si128((const __m128i *)filter);
1178
0
  const __m128i p = _mm_set1_epi32(0x09080706);
1179
0
  f[0] = _mm_shuffle_epi8(h, p);
1180
0
}
1181
1182
0
static void pack_8x2_init(const uint16_t *src, __m128i *sig) {
1183
0
  sig[2] = _mm_loadu_si128((const __m128i *)src);
1184
0
}
1185
1186
static inline void pack_8x2_2t_pixels_ver(const uint16_t *src, ptrdiff_t pitch,
1187
0
                                          __m128i *sig) {
1188
  // load the next row
1189
0
  const __m128i u = _mm_loadu_si128((const __m128i *)(src + pitch));
1190
0
  sig[0] = _mm_unpacklo_epi16(sig[2], u);
1191
0
  sig[1] = _mm_unpackhi_epi16(sig[2], u);
1192
0
  sig[2] = u;
1193
0
}
1194
1195
static inline void filter_8_2t_pixels(const __m128i *sig, const __m128i *f,
1196
0
                                      __m128i *y0, __m128i *y1) {
1197
0
  const __m128i rounding = _mm_set1_epi32(1 << (CONV8_ROUNDING_BITS - 1));
1198
0
  __m128i x0 = _mm_madd_epi16(sig[0], *f);
1199
0
  __m128i x1 = _mm_madd_epi16(sig[1], *f);
1200
0
  x0 = _mm_add_epi32(x0, rounding);
1201
0
  x1 = _mm_add_epi32(x1, rounding);
1202
0
  *y0 = _mm_srai_epi32(x0, CONV8_ROUNDING_BITS);
1203
0
  *y1 = _mm_srai_epi32(x1, CONV8_ROUNDING_BITS);
1204
0
}
1205
1206
static inline void store_8x1_2t_pixels_ver(const __m128i *y0, const __m128i *y1,
1207
0
                                           const __m128i *mask, uint16_t *dst) {
1208
0
  __m128i res = _mm_packus_epi32(*y0, *y1);
1209
0
  res = _mm_min_epi16(res, *mask);
1210
0
  _mm_storeu_si128((__m128i *)dst, res);
1211
0
}
1212
1213
static void aom_highbd_filter_block1d8_v2_avx2(
1214
    const uint16_t *src_ptr, ptrdiff_t src_pitch, uint16_t *dst_ptr,
1215
0
    ptrdiff_t dst_pitch, uint32_t height, const int16_t *filter, int bd) {
1216
0
  __m128i signal[3], res0, res1;
1217
0
  const __m128i max = _mm_set1_epi16((1 << bd) - 1);
1218
0
  __m128i ff;
1219
1220
0
  pack_8x1_2t_filter(filter, &ff);
1221
0
  pack_8x2_init(src_ptr, signal);
1222
1223
0
  do {
1224
0
    pack_8x2_2t_pixels_ver(src_ptr, src_pitch, signal);
1225
0
    filter_8_2t_pixels(signal, &ff, &res0, &res1);
1226
0
    store_8x1_2t_pixels_ver(&res0, &res1, &max, dst_ptr);
1227
1228
0
    src_ptr += src_pitch;
1229
0
    dst_ptr += dst_pitch;
1230
0
    height -= 1;
1231
0
  } while (height > 0);
1232
0
}
1233
1234
void aom_highbd_filter_block1d4_h8_sse2(const uint16_t *, ptrdiff_t, uint16_t *,
1235
                                        ptrdiff_t, uint32_t, const int16_t *,
1236
                                        int);
1237
void aom_highbd_filter_block1d4_h2_sse2(const uint16_t *, ptrdiff_t, uint16_t *,
1238
                                        ptrdiff_t, uint32_t, const int16_t *,
1239
                                        int);
1240
void aom_highbd_filter_block1d4_v8_sse2(const uint16_t *, ptrdiff_t, uint16_t *,
1241
                                        ptrdiff_t, uint32_t, const int16_t *,
1242
                                        int);
1243
void aom_highbd_filter_block1d4_v2_sse2(const uint16_t *, ptrdiff_t, uint16_t *,
1244
                                        ptrdiff_t, uint32_t, const int16_t *,
1245
                                        int);
1246
0
#define aom_highbd_filter_block1d4_h8_avx2 aom_highbd_filter_block1d4_h8_sse2
1247
0
#define aom_highbd_filter_block1d4_h2_avx2 aom_highbd_filter_block1d4_h2_sse2
1248
0
#define aom_highbd_filter_block1d4_v8_avx2 aom_highbd_filter_block1d4_v8_sse2
1249
0
#define aom_highbd_filter_block1d4_v2_avx2 aom_highbd_filter_block1d4_v2_sse2
1250
1251
HIGH_FUN_CONV_1D(horiz, x_step_q4, filter_x, h, src, , avx2)
1252
HIGH_FUN_CONV_1D(vert, y_step_q4, filter_y, v, src - src_stride * 3, , avx2)
1253
1254
#undef HIGHBD_FUNC
1255
#endif  // HAVE_X86_ASM