1 /*
2 * Copyright (c) 2010 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 <stdio.h>
13
14 #include "./vpx_dsp_rtcd.h"
15 #include "vpx_dsp/x86/convolve.h"
16 #include "vpx_dsp/x86/convolve_avx2.h"
17 #include "vpx_dsp/x86/convolve_sse2.h"
18 #include "vpx_dsp/x86/convolve_ssse3.h"
19 #include "vpx_ports/mem.h"
20
21 // filters for 16_h8
22 DECLARE_ALIGNED(32, static const uint8_t,
23 filt1_global_avx2[32]) = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5,
24 6, 6, 7, 7, 8, 0, 1, 1, 2, 2, 3,
25 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 };
26
27 DECLARE_ALIGNED(32, static const uint8_t,
28 filt2_global_avx2[32]) = { 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7,
29 8, 8, 9, 9, 10, 2, 3, 3, 4, 4, 5,
30 5, 6, 6, 7, 7, 8, 8, 9, 9, 10 };
31
32 DECLARE_ALIGNED(32, static const uint8_t, filt3_global_avx2[32]) = {
33 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12,
34 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12
35 };
36
37 DECLARE_ALIGNED(32, static const uint8_t, filt4_global_avx2[32]) = {
38 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14,
39 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14
40 };
41
42 DECLARE_ALIGNED(32, static const uint8_t, filt_d4_global_avx2[64]) = {
43 0, 1, 2, 3, 1, 2, 3, 4, 2, 3, 4, 5, 3, 4, 5, 6, 0, 1, 2, 3, 1, 2,
44 3, 4, 2, 3, 4, 5, 3, 4, 5, 6, 4, 5, 6, 7, 5, 6, 7, 8, 6, 7, 8, 9,
45 7, 8, 9, 10, 4, 5, 6, 7, 5, 6, 7, 8, 6, 7, 8, 9, 7, 8, 9, 10,
46 };
47
48 #define CALC_CONVOLVE8_HORZ_ROW \
49 srcReg = mm256_loadu2_si128(src_ptr - 3, src_ptr - 3 + src_pitch); \
50 s1[0] = _mm256_shuffle_epi8(srcReg, filt[0]); \
51 s1[1] = _mm256_shuffle_epi8(srcReg, filt[1]); \
52 s1[2] = _mm256_shuffle_epi8(srcReg, filt[2]); \
53 s1[3] = _mm256_shuffle_epi8(srcReg, filt[3]); \
54 s1[0] = convolve8_16_avx2(s1, f1); \
55 s1[0] = _mm256_packus_epi16(s1[0], s1[0]); \
56 src_ptr += src_stride; \
57 _mm_storel_epi64((__m128i *)&output_ptr[0], _mm256_castsi256_si128(s1[0])); \
58 output_ptr += output_pitch; \
59 _mm_storel_epi64((__m128i *)&output_ptr[0], \
60 _mm256_extractf128_si256(s1[0], 1)); \
61 output_ptr += output_pitch;
62
vpx_filter_block1d16_h8_x_avx2(const uint8_t * src_ptr,ptrdiff_t src_pixels_per_line,uint8_t * output_ptr,ptrdiff_t output_pitch,uint32_t output_height,const int16_t * filter,const int avg)63 static INLINE void vpx_filter_block1d16_h8_x_avx2(
64 const uint8_t *src_ptr, ptrdiff_t src_pixels_per_line, uint8_t *output_ptr,
65 ptrdiff_t output_pitch, uint32_t output_height, const int16_t *filter,
66 const int avg) {
67 __m128i outReg1, outReg2;
68 __m256i outReg32b1, outReg32b2;
69 unsigned int i;
70 ptrdiff_t src_stride, dst_stride;
71 __m256i f[4], filt[4], s[4];
72
73 shuffle_filter_avx2(filter, f);
74 filt[0] = _mm256_load_si256((__m256i const *)filt1_global_avx2);
75 filt[1] = _mm256_load_si256((__m256i const *)filt2_global_avx2);
76 filt[2] = _mm256_load_si256((__m256i const *)filt3_global_avx2);
77 filt[3] = _mm256_load_si256((__m256i const *)filt4_global_avx2);
78
79 // multiple the size of the source and destination stride by two
80 src_stride = src_pixels_per_line << 1;
81 dst_stride = output_pitch << 1;
82 for (i = output_height; i > 1; i -= 2) {
83 __m256i srcReg;
84
85 // load the 2 strides of source
86 srcReg = mm256_loadu2_si128(src_ptr - 3, src_ptr + src_pixels_per_line - 3);
87
88 // filter the source buffer
89 s[0] = _mm256_shuffle_epi8(srcReg, filt[0]);
90 s[1] = _mm256_shuffle_epi8(srcReg, filt[1]);
91 s[2] = _mm256_shuffle_epi8(srcReg, filt[2]);
92 s[3] = _mm256_shuffle_epi8(srcReg, filt[3]);
93 outReg32b1 = convolve8_16_avx2(s, f);
94
95 // reading 2 strides of the next 16 bytes
96 // (part of it was being read by earlier read)
97 srcReg = mm256_loadu2_si128(src_ptr + 5, src_ptr + src_pixels_per_line + 5);
98
99 // filter the source buffer
100 s[0] = _mm256_shuffle_epi8(srcReg, filt[0]);
101 s[1] = _mm256_shuffle_epi8(srcReg, filt[1]);
102 s[2] = _mm256_shuffle_epi8(srcReg, filt[2]);
103 s[3] = _mm256_shuffle_epi8(srcReg, filt[3]);
104 outReg32b2 = convolve8_16_avx2(s, f);
105
106 // shrink to 8 bit each 16 bits, the low and high 64-bits of each lane
107 // contain the first and second convolve result respectively
108 outReg32b1 = _mm256_packus_epi16(outReg32b1, outReg32b2);
109
110 src_ptr += src_stride;
111
112 if (avg) {
113 const __m256i outReg = mm256_loadu2_si128(
114 (__m128i *)output_ptr, (__m128i *)(output_ptr + output_pitch));
115 outReg32b1 = _mm256_avg_epu8(outReg32b1, outReg);
116 }
117 mm256_store2_si128((__m128i *)output_ptr,
118 (__m128i *)(output_ptr + output_pitch), &outReg32b1);
119 output_ptr += dst_stride;
120 }
121
122 // if the number of strides is odd.
123 // process only 16 bytes
124 if (i > 0) {
125 const __m128i srcReg1 = _mm_loadu_si128((const __m128i *)(src_ptr - 3));
126 const __m128i srcReg2 = _mm_loadu_si128((const __m128i *)(src_ptr + 5));
127 const __m256i srcReg =
128 _mm256_inserti128_si256(_mm256_castsi128_si256(srcReg1), srcReg2, 1);
129
130 // filter the source buffer
131 s[0] = _mm256_shuffle_epi8(srcReg, filt[0]);
132 s[1] = _mm256_shuffle_epi8(srcReg, filt[1]);
133 s[2] = _mm256_shuffle_epi8(srcReg, filt[2]);
134 s[3] = _mm256_shuffle_epi8(srcReg, filt[3]);
135
136 // The low and high 128-bits of each lane contain the first and second
137 // convolve result respectively
138 outReg32b1 = convolve8_16_avx2(s, f);
139 outReg1 = _mm256_castsi256_si128(outReg32b1);
140 outReg2 = _mm256_extractf128_si256(outReg32b1, 1);
141
142 // shrink to 8 bit each 16 bits
143 outReg1 = _mm_packus_epi16(outReg1, outReg2);
144
145 // average if necessary
146 if (avg) {
147 outReg1 = _mm_avg_epu8(outReg1, _mm_load_si128((__m128i *)output_ptr));
148 }
149
150 // save 16 bytes
151 _mm_store_si128((__m128i *)output_ptr, outReg1);
152 }
153 }
154
vpx_filter_block1d16_h8_avx2(const uint8_t * src_ptr,ptrdiff_t src_stride,uint8_t * output_ptr,ptrdiff_t dst_stride,uint32_t output_height,const int16_t * filter)155 static void vpx_filter_block1d16_h8_avx2(
156 const uint8_t *src_ptr, ptrdiff_t src_stride, uint8_t *output_ptr,
157 ptrdiff_t dst_stride, uint32_t output_height, const int16_t *filter) {
158 vpx_filter_block1d16_h8_x_avx2(src_ptr, src_stride, output_ptr, dst_stride,
159 output_height, filter, 0);
160 }
161
vpx_filter_block1d16_h8_avg_avx2(const uint8_t * src_ptr,ptrdiff_t src_stride,uint8_t * output_ptr,ptrdiff_t dst_stride,uint32_t output_height,const int16_t * filter)162 static void vpx_filter_block1d16_h8_avg_avx2(
163 const uint8_t *src_ptr, ptrdiff_t src_stride, uint8_t *output_ptr,
164 ptrdiff_t dst_stride, uint32_t output_height, const int16_t *filter) {
165 vpx_filter_block1d16_h8_x_avx2(src_ptr, src_stride, output_ptr, dst_stride,
166 output_height, filter, 1);
167 }
168
vpx_filter_block1d8_h8_avx2(const uint8_t * src_ptr,ptrdiff_t src_pitch,uint8_t * output_ptr,ptrdiff_t output_pitch,uint32_t output_height,const int16_t * filter)169 static void vpx_filter_block1d8_h8_avx2(
170 const uint8_t *src_ptr, ptrdiff_t src_pitch, uint8_t *output_ptr,
171 ptrdiff_t output_pitch, uint32_t output_height, const int16_t *filter) {
172 __m256i filt[4], f1[4], s1[4], srcReg;
173 __m128i f[4], s[4];
174 int y = output_height;
175
176 // Multiply the size of the source stride by two
177 const ptrdiff_t src_stride = src_pitch << 1;
178
179 shuffle_filter_avx2(filter, f1);
180 filt[0] = _mm256_load_si256((__m256i const *)filt1_global_avx2);
181 filt[1] = _mm256_load_si256((__m256i const *)filt2_global_avx2);
182 filt[2] = _mm256_load_si256((__m256i const *)filt3_global_avx2);
183 filt[3] = _mm256_load_si256((__m256i const *)filt4_global_avx2);
184
185 // Process next 4 rows
186 while (y > 3) {
187 CALC_CONVOLVE8_HORZ_ROW
188 CALC_CONVOLVE8_HORZ_ROW
189 y -= 4;
190 }
191
192 // If remaining, then process 2 rows at a time
193 while (y > 1) {
194 CALC_CONVOLVE8_HORZ_ROW
195 y -= 2;
196 }
197
198 // For the remaining height.
199 if (y > 0) {
200 const __m128i src_reg_128 = _mm_loadu_si128((const __m128i *)(src_ptr - 3));
201
202 f[0] = _mm256_castsi256_si128(f1[0]);
203 f[1] = _mm256_castsi256_si128(f1[1]);
204 f[2] = _mm256_castsi256_si128(f1[2]);
205 f[3] = _mm256_castsi256_si128(f1[3]);
206
207 // filter the source buffer
208 s[0] = _mm_shuffle_epi8(src_reg_128, _mm256_castsi256_si128(filt[0]));
209 s[1] = _mm_shuffle_epi8(src_reg_128, _mm256_castsi256_si128(filt[1]));
210 s[2] = _mm_shuffle_epi8(src_reg_128, _mm256_castsi256_si128(filt[2]));
211 s[3] = _mm_shuffle_epi8(src_reg_128, _mm256_castsi256_si128(filt[3]));
212 s[0] = convolve8_8_ssse3(s, f);
213
214 // Saturate 16bit value to 8bit.
215 s[0] = _mm_packus_epi16(s[0], s[0]);
216
217 // Save only 8 bytes
218 _mm_storel_epi64((__m128i *)&output_ptr[0], s[0]);
219 }
220 }
221
vpx_filter_block1d16_v8_x_avx2(const uint8_t * src_ptr,ptrdiff_t src_pitch,uint8_t * output_ptr,ptrdiff_t out_pitch,uint32_t output_height,const int16_t * filter,const int avg)222 static INLINE void vpx_filter_block1d16_v8_x_avx2(
223 const uint8_t *src_ptr, ptrdiff_t src_pitch, uint8_t *output_ptr,
224 ptrdiff_t out_pitch, uint32_t output_height, const int16_t *filter,
225 const int avg) {
226 __m256i srcRegHead1;
227 unsigned int i;
228 ptrdiff_t src_stride, dst_stride;
229 __m256i f[4], s1[4], s2[4];
230
231 shuffle_filter_avx2(filter, f);
232
233 // multiple the size of the source and destination stride by two
234 src_stride = src_pitch << 1;
235 dst_stride = out_pitch << 1;
236
237 {
238 __m128i s[6];
239 __m256i s32b[6];
240
241 // load 16 bytes 7 times in stride of src_pitch
242 s[0] = _mm_loadu_si128((const __m128i *)(src_ptr + 0 * src_pitch));
243 s[1] = _mm_loadu_si128((const __m128i *)(src_ptr + 1 * src_pitch));
244 s[2] = _mm_loadu_si128((const __m128i *)(src_ptr + 2 * src_pitch));
245 s[3] = _mm_loadu_si128((const __m128i *)(src_ptr + 3 * src_pitch));
246 s[4] = _mm_loadu_si128((const __m128i *)(src_ptr + 4 * src_pitch));
247 s[5] = _mm_loadu_si128((const __m128i *)(src_ptr + 5 * src_pitch));
248 srcRegHead1 = _mm256_castsi128_si256(
249 _mm_loadu_si128((const __m128i *)(src_ptr + 6 * src_pitch)));
250
251 // have each consecutive loads on the same 256 register
252 s32b[0] = _mm256_inserti128_si256(_mm256_castsi128_si256(s[0]), s[1], 1);
253 s32b[1] = _mm256_inserti128_si256(_mm256_castsi128_si256(s[1]), s[2], 1);
254 s32b[2] = _mm256_inserti128_si256(_mm256_castsi128_si256(s[2]), s[3], 1);
255 s32b[3] = _mm256_inserti128_si256(_mm256_castsi128_si256(s[3]), s[4], 1);
256 s32b[4] = _mm256_inserti128_si256(_mm256_castsi128_si256(s[4]), s[5], 1);
257 s32b[5] = _mm256_inserti128_si256(_mm256_castsi128_si256(s[5]),
258 _mm256_castsi256_si128(srcRegHead1), 1);
259
260 // merge every two consecutive registers except the last one
261 // the first lanes contain values for filtering odd rows (1,3,5...) and
262 // the second lanes contain values for filtering even rows (2,4,6...)
263 s1[0] = _mm256_unpacklo_epi8(s32b[0], s32b[1]);
264 s2[0] = _mm256_unpackhi_epi8(s32b[0], s32b[1]);
265 s1[1] = _mm256_unpacklo_epi8(s32b[2], s32b[3]);
266 s2[1] = _mm256_unpackhi_epi8(s32b[2], s32b[3]);
267 s1[2] = _mm256_unpacklo_epi8(s32b[4], s32b[5]);
268 s2[2] = _mm256_unpackhi_epi8(s32b[4], s32b[5]);
269 }
270
271 // The output_height is always a multiple of two.
272 assert(!(output_height & 1));
273
274 for (i = output_height; i > 1; i -= 2) {
275 __m256i srcRegHead2, srcRegHead3;
276
277 // load the next 2 loads of 16 bytes and have every two
278 // consecutive loads in the same 256 bit register
279 srcRegHead2 = _mm256_castsi128_si256(
280 _mm_loadu_si128((const __m128i *)(src_ptr + 7 * src_pitch)));
281 srcRegHead1 = _mm256_inserti128_si256(
282 srcRegHead1, _mm256_castsi256_si128(srcRegHead2), 1);
283 srcRegHead3 = _mm256_castsi128_si256(
284 _mm_loadu_si128((const __m128i *)(src_ptr + 8 * src_pitch)));
285 srcRegHead2 = _mm256_inserti128_si256(
286 srcRegHead2, _mm256_castsi256_si128(srcRegHead3), 1);
287
288 // merge the two new consecutive registers
289 // the first lane contain values for filtering odd rows (1,3,5...) and
290 // the second lane contain values for filtering even rows (2,4,6...)
291 s1[3] = _mm256_unpacklo_epi8(srcRegHead1, srcRegHead2);
292 s2[3] = _mm256_unpackhi_epi8(srcRegHead1, srcRegHead2);
293
294 s1[0] = convolve8_16_avx2(s1, f);
295 s2[0] = convolve8_16_avx2(s2, f);
296
297 // shrink to 8 bit each 16 bits, the low and high 64-bits of each lane
298 // contain the first and second convolve result respectively
299 s1[0] = _mm256_packus_epi16(s1[0], s2[0]);
300
301 src_ptr += src_stride;
302
303 // average if necessary
304 if (avg) {
305 const __m256i outReg = mm256_loadu2_si128(
306 (__m128i *)output_ptr, (__m128i *)(output_ptr + out_pitch));
307 s1[0] = _mm256_avg_epu8(s1[0], outReg);
308 }
309
310 mm256_store2_si128((__m128i *)output_ptr,
311 (__m128i *)(output_ptr + out_pitch), s1);
312
313 output_ptr += dst_stride;
314
315 // shift down by two rows
316 s1[0] = s1[1];
317 s2[0] = s2[1];
318 s1[1] = s1[2];
319 s2[1] = s2[2];
320 s1[2] = s1[3];
321 s2[2] = s2[3];
322 srcRegHead1 = srcRegHead3;
323 }
324 }
325
vpx_filter_block1d16_v8_avx2(const uint8_t * src_ptr,ptrdiff_t src_stride,uint8_t * dst_ptr,ptrdiff_t dst_stride,uint32_t height,const int16_t * filter)326 static void vpx_filter_block1d16_v8_avx2(const uint8_t *src_ptr,
327 ptrdiff_t src_stride, uint8_t *dst_ptr,
328 ptrdiff_t dst_stride, uint32_t height,
329 const int16_t *filter) {
330 vpx_filter_block1d16_v8_x_avx2(src_ptr, src_stride, dst_ptr, dst_stride,
331 height, filter, 0);
332 }
333
vpx_filter_block1d16_v8_avg_avx2(const uint8_t * src_ptr,ptrdiff_t src_stride,uint8_t * dst_ptr,ptrdiff_t dst_stride,uint32_t height,const int16_t * filter)334 static void vpx_filter_block1d16_v8_avg_avx2(
335 const uint8_t *src_ptr, ptrdiff_t src_stride, uint8_t *dst_ptr,
336 ptrdiff_t dst_stride, uint32_t height, const int16_t *filter) {
337 vpx_filter_block1d16_v8_x_avx2(src_ptr, src_stride, dst_ptr, dst_stride,
338 height, filter, 1);
339 }
340
vpx_filter_block1d16_h4_avx2(const uint8_t * src_ptr,ptrdiff_t src_stride,uint8_t * dst_ptr,ptrdiff_t dst_stride,uint32_t height,const int16_t * kernel)341 static void vpx_filter_block1d16_h4_avx2(const uint8_t *src_ptr,
342 ptrdiff_t src_stride, uint8_t *dst_ptr,
343 ptrdiff_t dst_stride, uint32_t height,
344 const int16_t *kernel) {
345 // We will cast the kernel from 16-bit words to 8-bit words, and then extract
346 // the middle four elements of the kernel into two registers in the form
347 // ... k[3] k[2] k[3] k[2]
348 // ... k[5] k[4] k[5] k[4]
349 // Then we shuffle the source into
350 // ... s[1] s[0] s[0] s[-1]
351 // ... s[3] s[2] s[2] s[1]
352 // Calling multiply and add gives us half of the sum. Calling add gives us
353 // first half of the output. Repeat again to get the second half of the
354 // output. Finally we shuffle again to combine the two outputs.
355 // Since avx2 allows us to use 256-bit buffer, we can do this two rows at a
356 // time.
357
358 __m128i kernel_reg; // Kernel
359 __m256i kernel_reg_256, kernel_reg_23,
360 kernel_reg_45; // Segments of the kernel used
361 const __m256i reg_32 = _mm256_set1_epi16(32); // Used for rounding
362 const ptrdiff_t unrolled_src_stride = src_stride << 1;
363 const ptrdiff_t unrolled_dst_stride = dst_stride << 1;
364 int h;
365
366 __m256i src_reg, src_reg_shift_0, src_reg_shift_2;
367 __m256i dst_first, dst_second;
368 __m256i tmp_0, tmp_1;
369 __m256i idx_shift_0 =
370 _mm256_setr_epi8(0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 0, 1, 1,
371 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8);
372 __m256i idx_shift_2 =
373 _mm256_setr_epi8(2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 2, 3, 3,
374 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10);
375
376 // Start one pixel before as we need tap/2 - 1 = 1 sample from the past
377 src_ptr -= 1;
378
379 // Load Kernel
380 kernel_reg = _mm_loadu_si128((const __m128i *)kernel);
381 kernel_reg = _mm_srai_epi16(kernel_reg, 1);
382 kernel_reg = _mm_packs_epi16(kernel_reg, kernel_reg);
383 kernel_reg_256 = _mm256_broadcastsi128_si256(kernel_reg);
384 kernel_reg_23 =
385 _mm256_shuffle_epi8(kernel_reg_256, _mm256_set1_epi16(0x0302u));
386 kernel_reg_45 =
387 _mm256_shuffle_epi8(kernel_reg_256, _mm256_set1_epi16(0x0504u));
388
389 for (h = height; h >= 2; h -= 2) {
390 // Load the source
391 src_reg = mm256_loadu2_si128(src_ptr, src_ptr + src_stride);
392 src_reg_shift_0 = _mm256_shuffle_epi8(src_reg, idx_shift_0);
393 src_reg_shift_2 = _mm256_shuffle_epi8(src_reg, idx_shift_2);
394
395 // Partial result for first half
396 tmp_0 = _mm256_maddubs_epi16(src_reg_shift_0, kernel_reg_23);
397 tmp_1 = _mm256_maddubs_epi16(src_reg_shift_2, kernel_reg_45);
398 dst_first = _mm256_adds_epi16(tmp_0, tmp_1);
399
400 // Do again to get the second half of dst
401 // Load the source
402 src_reg = mm256_loadu2_si128(src_ptr + 8, src_ptr + src_stride + 8);
403 src_reg_shift_0 = _mm256_shuffle_epi8(src_reg, idx_shift_0);
404 src_reg_shift_2 = _mm256_shuffle_epi8(src_reg, idx_shift_2);
405
406 // Partial result for second half
407 tmp_0 = _mm256_maddubs_epi16(src_reg_shift_0, kernel_reg_23);
408 tmp_1 = _mm256_maddubs_epi16(src_reg_shift_2, kernel_reg_45);
409 dst_second = _mm256_adds_epi16(tmp_0, tmp_1);
410
411 // Round each result
412 dst_first = mm256_round_epi16(&dst_first, ®_32, 6);
413 dst_second = mm256_round_epi16(&dst_second, ®_32, 6);
414
415 // Finally combine to get the final dst
416 dst_first = _mm256_packus_epi16(dst_first, dst_second);
417 mm256_store2_si128((__m128i *)dst_ptr, (__m128i *)(dst_ptr + dst_stride),
418 &dst_first);
419
420 src_ptr += unrolled_src_stride;
421 dst_ptr += unrolled_dst_stride;
422 }
423
424 // Repeat for the last row if needed
425 if (h > 0) {
426 src_reg = _mm256_loadu_si256((const __m256i *)src_ptr);
427 // Reorder into 2 1 1 2
428 src_reg = _mm256_permute4x64_epi64(src_reg, 0x94);
429
430 src_reg_shift_0 = _mm256_shuffle_epi8(src_reg, idx_shift_0);
431 src_reg_shift_2 = _mm256_shuffle_epi8(src_reg, idx_shift_2);
432
433 tmp_0 = _mm256_maddubs_epi16(src_reg_shift_0, kernel_reg_23);
434 tmp_1 = _mm256_maddubs_epi16(src_reg_shift_2, kernel_reg_45);
435 dst_first = _mm256_adds_epi16(tmp_0, tmp_1);
436
437 dst_first = mm256_round_epi16(&dst_first, ®_32, 6);
438
439 dst_first = _mm256_packus_epi16(dst_first, dst_first);
440 dst_first = _mm256_permute4x64_epi64(dst_first, 0x8);
441
442 _mm_store_si128((__m128i *)dst_ptr, _mm256_castsi256_si128(dst_first));
443 }
444 }
445
vpx_filter_block1d16_v4_avx2(const uint8_t * src_ptr,ptrdiff_t src_stride,uint8_t * dst_ptr,ptrdiff_t dst_stride,uint32_t height,const int16_t * kernel)446 static void vpx_filter_block1d16_v4_avx2(const uint8_t *src_ptr,
447 ptrdiff_t src_stride, uint8_t *dst_ptr,
448 ptrdiff_t dst_stride, uint32_t height,
449 const int16_t *kernel) {
450 // We will load two rows of pixels as 8-bit words, rearrange them into the
451 // form
452 // ... s[1,0] s[0,0] s[0,0] s[-1,0]
453 // so that we can call multiply and add with the kernel partial output. Then
454 // we can call add with another row to get the output.
455
456 // Register for source s[-1:3, :]
457 __m256i src_reg_1, src_reg_2, src_reg_3;
458 // Interleaved rows of the source. lo is first half, hi second
459 __m256i src_reg_m10, src_reg_01, src_reg_12, src_reg_23;
460 __m256i src_reg_m1001_lo, src_reg_m1001_hi, src_reg_1223_lo, src_reg_1223_hi;
461
462 __m128i kernel_reg; // Kernel
463 __m256i kernel_reg_256, kernel_reg_23,
464 kernel_reg_45; // Segments of the kernel used
465
466 // Result after multiply and add
467 __m256i res_reg_m1001_lo, res_reg_1223_lo, res_reg_m1001_hi, res_reg_1223_hi;
468 __m256i res_reg, res_reg_lo, res_reg_hi;
469
470 const __m256i reg_32 = _mm256_set1_epi16(32); // Used for rounding
471
472 // We will compute the result two rows at a time
473 const ptrdiff_t src_stride_unrolled = src_stride << 1;
474 const ptrdiff_t dst_stride_unrolled = dst_stride << 1;
475 int h;
476
477 // Load Kernel
478 kernel_reg = _mm_loadu_si128((const __m128i *)kernel);
479 kernel_reg = _mm_srai_epi16(kernel_reg, 1);
480 kernel_reg = _mm_packs_epi16(kernel_reg, kernel_reg);
481 kernel_reg_256 = _mm256_broadcastsi128_si256(kernel_reg);
482 kernel_reg_23 =
483 _mm256_shuffle_epi8(kernel_reg_256, _mm256_set1_epi16(0x0302u));
484 kernel_reg_45 =
485 _mm256_shuffle_epi8(kernel_reg_256, _mm256_set1_epi16(0x0504u));
486
487 // Row -1 to row 0
488 src_reg_m10 = mm256_loadu2_si128((const __m128i *)src_ptr,
489 (const __m128i *)(src_ptr + src_stride));
490
491 // Row 0 to row 1
492 src_reg_1 = _mm256_castsi128_si256(
493 _mm_loadu_si128((const __m128i *)(src_ptr + src_stride * 2)));
494 src_reg_01 = _mm256_permute2x128_si256(src_reg_m10, src_reg_1, 0x21);
495
496 // First three rows
497 src_reg_m1001_lo = _mm256_unpacklo_epi8(src_reg_m10, src_reg_01);
498 src_reg_m1001_hi = _mm256_unpackhi_epi8(src_reg_m10, src_reg_01);
499
500 for (h = height; h > 1; h -= 2) {
501 src_reg_2 = _mm256_castsi128_si256(
502 _mm_loadu_si128((const __m128i *)(src_ptr + src_stride * 3)));
503
504 src_reg_12 = _mm256_inserti128_si256(src_reg_1,
505 _mm256_castsi256_si128(src_reg_2), 1);
506
507 src_reg_3 = _mm256_castsi128_si256(
508 _mm_loadu_si128((const __m128i *)(src_ptr + src_stride * 4)));
509
510 src_reg_23 = _mm256_inserti128_si256(src_reg_2,
511 _mm256_castsi256_si128(src_reg_3), 1);
512
513 // Last three rows
514 src_reg_1223_lo = _mm256_unpacklo_epi8(src_reg_12, src_reg_23);
515 src_reg_1223_hi = _mm256_unpackhi_epi8(src_reg_12, src_reg_23);
516
517 // Output from first half
518 res_reg_m1001_lo = _mm256_maddubs_epi16(src_reg_m1001_lo, kernel_reg_23);
519 res_reg_1223_lo = _mm256_maddubs_epi16(src_reg_1223_lo, kernel_reg_45);
520 res_reg_lo = _mm256_adds_epi16(res_reg_m1001_lo, res_reg_1223_lo);
521
522 // Output from second half
523 res_reg_m1001_hi = _mm256_maddubs_epi16(src_reg_m1001_hi, kernel_reg_23);
524 res_reg_1223_hi = _mm256_maddubs_epi16(src_reg_1223_hi, kernel_reg_45);
525 res_reg_hi = _mm256_adds_epi16(res_reg_m1001_hi, res_reg_1223_hi);
526
527 // Round the words
528 res_reg_lo = mm256_round_epi16(&res_reg_lo, ®_32, 6);
529 res_reg_hi = mm256_round_epi16(&res_reg_hi, ®_32, 6);
530
531 // Combine to get the result
532 res_reg = _mm256_packus_epi16(res_reg_lo, res_reg_hi);
533
534 // Save the result
535 mm256_store2_si128((__m128i *)dst_ptr, (__m128i *)(dst_ptr + dst_stride),
536 &res_reg);
537
538 // Update the source by two rows
539 src_ptr += src_stride_unrolled;
540 dst_ptr += dst_stride_unrolled;
541
542 src_reg_m1001_lo = src_reg_1223_lo;
543 src_reg_m1001_hi = src_reg_1223_hi;
544 src_reg_1 = src_reg_3;
545 }
546 }
547
vpx_filter_block1d8_h4_avx2(const uint8_t * src_ptr,ptrdiff_t src_stride,uint8_t * dst_ptr,ptrdiff_t dst_stride,uint32_t height,const int16_t * kernel)548 static void vpx_filter_block1d8_h4_avx2(const uint8_t *src_ptr,
549 ptrdiff_t src_stride, uint8_t *dst_ptr,
550 ptrdiff_t dst_stride, uint32_t height,
551 const int16_t *kernel) {
552 // We will cast the kernel from 16-bit words to 8-bit words, and then extract
553 // the middle four elements of the kernel into two registers in the form
554 // ... k[3] k[2] k[3] k[2]
555 // ... k[5] k[4] k[5] k[4]
556 // Then we shuffle the source into
557 // ... s[1] s[0] s[0] s[-1]
558 // ... s[3] s[2] s[2] s[1]
559 // Calling multiply and add gives us half of the sum. Calling add gives us
560 // first half of the output. Repeat again to get the second half of the
561 // output. Finally we shuffle again to combine the two outputs.
562 // Since avx2 allows us to use 256-bit buffer, we can do this two rows at a
563 // time.
564
565 __m128i kernel_reg_128; // Kernel
566 __m256i kernel_reg, kernel_reg_23,
567 kernel_reg_45; // Segments of the kernel used
568 const __m256i reg_32 = _mm256_set1_epi16(32); // Used for rounding
569 const ptrdiff_t unrolled_src_stride = src_stride << 1;
570 const ptrdiff_t unrolled_dst_stride = dst_stride << 1;
571 int h;
572
573 __m256i idx_shift_0 =
574 _mm256_setr_epi8(0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 0, 1, 1,
575 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8);
576 __m256i idx_shift_2 =
577 _mm256_setr_epi8(2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 2, 3, 3,
578 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10);
579
580 // Start one pixel before as we need tap/2 - 1 = 1 sample from the past
581 src_ptr -= 1;
582
583 // Load Kernel
584 kernel_reg_128 = _mm_loadu_si128((const __m128i *)kernel);
585 kernel_reg_128 = _mm_srai_epi16(kernel_reg_128, 1);
586 kernel_reg_128 = _mm_packs_epi16(kernel_reg_128, kernel_reg_128);
587 kernel_reg = _mm256_broadcastsi128_si256(kernel_reg_128);
588 kernel_reg_23 = _mm256_shuffle_epi8(kernel_reg, _mm256_set1_epi16(0x0302u));
589 kernel_reg_45 = _mm256_shuffle_epi8(kernel_reg, _mm256_set1_epi16(0x0504u));
590
591 for (h = height; h >= 2; h -= 2) {
592 // Load the source
593 const __m256i src_reg = mm256_loadu2_si128(src_ptr, src_ptr + src_stride);
594 __m256i dst_reg;
595 __m256i tmp_0, tmp_1;
596 const __m256i src_reg_shift_0 = _mm256_shuffle_epi8(src_reg, idx_shift_0);
597 const __m256i src_reg_shift_2 = _mm256_shuffle_epi8(src_reg, idx_shift_2);
598
599 // Get the output
600 tmp_0 = _mm256_maddubs_epi16(src_reg_shift_0, kernel_reg_23);
601 tmp_1 = _mm256_maddubs_epi16(src_reg_shift_2, kernel_reg_45);
602 dst_reg = _mm256_adds_epi16(tmp_0, tmp_1);
603
604 // Round the result
605 dst_reg = mm256_round_epi16(&dst_reg, ®_32, 6);
606
607 // Finally combine to get the final dst
608 dst_reg = _mm256_packus_epi16(dst_reg, dst_reg);
609 mm256_storeu2_epi64((__m128i *)dst_ptr, (__m128i *)(dst_ptr + dst_stride),
610 &dst_reg);
611
612 src_ptr += unrolled_src_stride;
613 dst_ptr += unrolled_dst_stride;
614 }
615
616 // Repeat for the last row if needed
617 if (h > 0) {
618 const __m128i src_reg = _mm_loadu_si128((const __m128i *)src_ptr);
619 __m128i dst_reg;
620 const __m128i reg_32_128 = _mm_set1_epi16(32); // Used for rounding
621 __m128i tmp_0, tmp_1;
622
623 __m128i src_reg_shift_0 =
624 _mm_shuffle_epi8(src_reg, _mm256_castsi256_si128(idx_shift_0));
625 __m128i src_reg_shift_2 =
626 _mm_shuffle_epi8(src_reg, _mm256_castsi256_si128(idx_shift_2));
627
628 tmp_0 = _mm_maddubs_epi16(src_reg_shift_0,
629 _mm256_castsi256_si128(kernel_reg_23));
630 tmp_1 = _mm_maddubs_epi16(src_reg_shift_2,
631 _mm256_castsi256_si128(kernel_reg_45));
632 dst_reg = _mm_adds_epi16(tmp_0, tmp_1);
633
634 dst_reg = mm_round_epi16_sse2(&dst_reg, ®_32_128, 6);
635
636 dst_reg = _mm_packus_epi16(dst_reg, _mm_setzero_si128());
637
638 _mm_storel_epi64((__m128i *)dst_ptr, dst_reg);
639 }
640 }
641
vpx_filter_block1d8_v4_avx2(const uint8_t * src_ptr,ptrdiff_t src_stride,uint8_t * dst_ptr,ptrdiff_t dst_stride,uint32_t height,const int16_t * kernel)642 static void vpx_filter_block1d8_v4_avx2(const uint8_t *src_ptr,
643 ptrdiff_t src_stride, uint8_t *dst_ptr,
644 ptrdiff_t dst_stride, uint32_t height,
645 const int16_t *kernel) {
646 // We will load two rows of pixels as 8-bit words, rearrange them into the
647 // form
648 // ... s[1,0] s[0,0] s[0,0] s[-1,0]
649 // so that we can call multiply and add with the kernel partial output. Then
650 // we can call add with another row to get the output.
651
652 // Register for source s[-1:3, :]
653 __m256i src_reg_1, src_reg_2, src_reg_3;
654 // Interleaved rows of the source. lo is first half, hi second
655 __m256i src_reg_m10, src_reg_01, src_reg_12, src_reg_23;
656 __m256i src_reg_m1001, src_reg_1223;
657
658 __m128i kernel_reg_128; // Kernel
659 __m256i kernel_reg, kernel_reg_23,
660 kernel_reg_45; // Segments of the kernel used
661
662 // Result after multiply and add
663 __m256i res_reg_m1001, res_reg_1223;
664 __m256i res_reg;
665
666 const __m256i reg_32 = _mm256_set1_epi16(32); // Used for rounding
667
668 // We will compute the result two rows at a time
669 const ptrdiff_t src_stride_unrolled = src_stride << 1;
670 const ptrdiff_t dst_stride_unrolled = dst_stride << 1;
671 int h;
672
673 // Load Kernel
674 kernel_reg_128 = _mm_loadu_si128((const __m128i *)kernel);
675 kernel_reg_128 = _mm_srai_epi16(kernel_reg_128, 1);
676 kernel_reg_128 = _mm_packs_epi16(kernel_reg_128, kernel_reg_128);
677 kernel_reg = _mm256_broadcastsi128_si256(kernel_reg_128);
678 kernel_reg_23 = _mm256_shuffle_epi8(kernel_reg, _mm256_set1_epi16(0x0302u));
679 kernel_reg_45 = _mm256_shuffle_epi8(kernel_reg, _mm256_set1_epi16(0x0504u));
680
681 // Row -1 to row 0
682 src_reg_m10 = mm256_loadu2_epi64((const __m128i *)src_ptr,
683 (const __m128i *)(src_ptr + src_stride));
684
685 // Row 0 to row 1
686 src_reg_1 = _mm256_castsi128_si256(
687 _mm_loadu_si128((const __m128i *)(src_ptr + src_stride * 2)));
688 src_reg_01 = _mm256_permute2x128_si256(src_reg_m10, src_reg_1, 0x21);
689
690 // First three rows
691 src_reg_m1001 = _mm256_unpacklo_epi8(src_reg_m10, src_reg_01);
692
693 for (h = height; h > 1; h -= 2) {
694 src_reg_2 = _mm256_castsi128_si256(
695 _mm_loadl_epi64((const __m128i *)(src_ptr + src_stride * 3)));
696
697 src_reg_12 = _mm256_inserti128_si256(src_reg_1,
698 _mm256_castsi256_si128(src_reg_2), 1);
699
700 src_reg_3 = _mm256_castsi128_si256(
701 _mm_loadl_epi64((const __m128i *)(src_ptr + src_stride * 4)));
702
703 src_reg_23 = _mm256_inserti128_si256(src_reg_2,
704 _mm256_castsi256_si128(src_reg_3), 1);
705
706 // Last three rows
707 src_reg_1223 = _mm256_unpacklo_epi8(src_reg_12, src_reg_23);
708
709 // Output
710 res_reg_m1001 = _mm256_maddubs_epi16(src_reg_m1001, kernel_reg_23);
711 res_reg_1223 = _mm256_maddubs_epi16(src_reg_1223, kernel_reg_45);
712 res_reg = _mm256_adds_epi16(res_reg_m1001, res_reg_1223);
713
714 // Round the words
715 res_reg = mm256_round_epi16(&res_reg, ®_32, 6);
716
717 // Combine to get the result
718 res_reg = _mm256_packus_epi16(res_reg, res_reg);
719
720 // Save the result
721 mm256_storeu2_epi64((__m128i *)dst_ptr, (__m128i *)(dst_ptr + dst_stride),
722 &res_reg);
723
724 // Update the source by two rows
725 src_ptr += src_stride_unrolled;
726 dst_ptr += dst_stride_unrolled;
727
728 src_reg_m1001 = src_reg_1223;
729 src_reg_1 = src_reg_3;
730 }
731 }
732
vpx_filter_block1d4_h4_avx2(const uint8_t * src_ptr,ptrdiff_t src_stride,uint8_t * dst_ptr,ptrdiff_t dst_stride,uint32_t height,const int16_t * kernel)733 static void vpx_filter_block1d4_h4_avx2(const uint8_t *src_ptr,
734 ptrdiff_t src_stride, uint8_t *dst_ptr,
735 ptrdiff_t dst_stride, uint32_t height,
736 const int16_t *kernel) {
737 // We will cast the kernel from 16-bit words to 8-bit words, and then extract
738 // the middle four elements of the kernel into a single register in the form
739 // k[5:2] k[5:2] k[5:2] k[5:2]
740 // Then we shuffle the source into
741 // s[5:2] s[4:1] s[3:0] s[2:-1]
742 // Calling multiply and add gives us half of the sum next to each other.
743 // Calling horizontal add then gives us the output.
744 // Since avx2 has 256-bit register, we can do 2 rows at a time.
745
746 __m128i kernel_reg_128; // Kernel
747 __m256i kernel_reg;
748 const __m256i reg_32 = _mm256_set1_epi16(32); // Used for rounding
749 int h;
750 const ptrdiff_t unrolled_src_stride = src_stride << 1;
751 const ptrdiff_t unrolled_dst_stride = dst_stride << 1;
752
753 __m256i shuf_idx =
754 _mm256_setr_epi8(0, 1, 2, 3, 1, 2, 3, 4, 2, 3, 4, 5, 3, 4, 5, 6, 0, 1, 2,
755 3, 1, 2, 3, 4, 2, 3, 4, 5, 3, 4, 5, 6);
756
757 // Start one pixel before as we need tap/2 - 1 = 1 sample from the past
758 src_ptr -= 1;
759
760 // Load Kernel
761 kernel_reg_128 = _mm_loadu_si128((const __m128i *)kernel);
762 kernel_reg_128 = _mm_srai_epi16(kernel_reg_128, 1);
763 kernel_reg_128 = _mm_packs_epi16(kernel_reg_128, kernel_reg_128);
764 kernel_reg = _mm256_broadcastsi128_si256(kernel_reg_128);
765 kernel_reg = _mm256_shuffle_epi8(kernel_reg, _mm256_set1_epi32(0x05040302u));
766
767 for (h = height; h > 1; h -= 2) {
768 // Load the source
769 const __m256i src_reg = mm256_loadu2_epi64(
770 (const __m128i *)src_ptr, (const __m128i *)(src_ptr + src_stride));
771 const __m256i src_reg_shuf = _mm256_shuffle_epi8(src_reg, shuf_idx);
772
773 // Get the result
774 __m256i dst = _mm256_maddubs_epi16(src_reg_shuf, kernel_reg);
775 dst = _mm256_hadds_epi16(dst, _mm256_setzero_si256());
776
777 // Round result
778 dst = mm256_round_epi16(&dst, ®_32, 6);
779
780 // Pack to 8-bits
781 dst = _mm256_packus_epi16(dst, _mm256_setzero_si256());
782
783 // Save
784 mm256_storeu2_epi32((__m128i *const)dst_ptr,
785 (__m128i *const)(dst_ptr + dst_stride), &dst);
786
787 src_ptr += unrolled_src_stride;
788 dst_ptr += unrolled_dst_stride;
789 }
790
791 if (h > 0) {
792 // Load the source
793 const __m128i reg_32_128 = _mm_set1_epi16(32); // Used for rounding
794 __m128i src_reg = _mm_loadl_epi64((const __m128i *)src_ptr);
795 __m128i src_reg_shuf =
796 _mm_shuffle_epi8(src_reg, _mm256_castsi256_si128(shuf_idx));
797
798 // Get the result
799 __m128i dst =
800 _mm_maddubs_epi16(src_reg_shuf, _mm256_castsi256_si128(kernel_reg));
801 dst = _mm_hadds_epi16(dst, _mm_setzero_si128());
802
803 // Round result
804 dst = mm_round_epi16_sse2(&dst, ®_32_128, 6);
805
806 // Pack to 8-bits
807 dst = _mm_packus_epi16(dst, _mm_setzero_si128());
808 *((int *)(dst_ptr)) = _mm_cvtsi128_si32(dst);
809 }
810 }
811
vpx_filter_block1d4_v4_avx2(const uint8_t * src_ptr,ptrdiff_t src_stride,uint8_t * dst_ptr,ptrdiff_t dst_stride,uint32_t height,const int16_t * kernel)812 static void vpx_filter_block1d4_v4_avx2(const uint8_t *src_ptr,
813 ptrdiff_t src_stride, uint8_t *dst_ptr,
814 ptrdiff_t dst_stride, uint32_t height,
815 const int16_t *kernel) {
816 // We will load two rows of pixels as 8-bit words, rearrange them into the
817 // form
818 // ... s[3,0] s[2,0] s[1,0] s[0,0] s[2,0] s[1,0] s[0,0] s[-1,0]
819 // so that we can call multiply and add with the kernel to get partial output.
820 // Calling horizontal add then gives us the completely output
821
822 // Register for source s[-1:3, :]
823 __m256i src_reg_1, src_reg_2, src_reg_3;
824 // Interleaved rows of the source. lo is first half, hi second
825 __m256i src_reg_m10, src_reg_01, src_reg_12, src_reg_23;
826 __m256i src_reg_m1001, src_reg_1223, src_reg_m1012_1023;
827
828 __m128i kernel_reg_128; // Kernel
829 __m256i kernel_reg;
830
831 // Result after multiply and add
832 __m256i res_reg;
833
834 const __m256i reg_32 = _mm256_set1_epi16(32); // Used for rounding
835
836 // We will compute the result two rows at a time
837 const ptrdiff_t src_stride_unrolled = src_stride << 1;
838 const ptrdiff_t dst_stride_unrolled = dst_stride << 1;
839 int h;
840
841 // Load Kernel
842 kernel_reg_128 = _mm_loadu_si128((const __m128i *)kernel);
843 kernel_reg_128 = _mm_srai_epi16(kernel_reg_128, 1);
844 kernel_reg_128 = _mm_packs_epi16(kernel_reg_128, kernel_reg_128);
845 kernel_reg = _mm256_broadcastsi128_si256(kernel_reg_128);
846 kernel_reg = _mm256_shuffle_epi8(kernel_reg, _mm256_set1_epi32(0x05040302u));
847
848 // Row -1 to row 0
849 src_reg_m10 = mm256_loadu2_si128((const __m128i *)src_ptr,
850 (const __m128i *)(src_ptr + src_stride));
851
852 // Row 0 to row 1
853 src_reg_1 = _mm256_castsi128_si256(
854 _mm_loadu_si128((const __m128i *)(src_ptr + src_stride * 2)));
855 src_reg_01 = _mm256_permute2x128_si256(src_reg_m10, src_reg_1, 0x21);
856
857 // First three rows
858 src_reg_m1001 = _mm256_unpacklo_epi8(src_reg_m10, src_reg_01);
859
860 for (h = height; h > 1; h -= 2) {
861 src_reg_2 = _mm256_castsi128_si256(
862 _mm_loadl_epi64((const __m128i *)(src_ptr + src_stride * 3)));
863
864 src_reg_12 = _mm256_inserti128_si256(src_reg_1,
865 _mm256_castsi256_si128(src_reg_2), 1);
866
867 src_reg_3 = _mm256_castsi128_si256(
868 _mm_loadl_epi64((const __m128i *)(src_ptr + src_stride * 4)));
869
870 src_reg_23 = _mm256_inserti128_si256(src_reg_2,
871 _mm256_castsi256_si128(src_reg_3), 1);
872
873 // Last three rows
874 src_reg_1223 = _mm256_unpacklo_epi8(src_reg_12, src_reg_23);
875
876 // Combine all the rows
877 src_reg_m1012_1023 = _mm256_unpacklo_epi16(src_reg_m1001, src_reg_1223);
878
879 // Output
880 res_reg = _mm256_maddubs_epi16(src_reg_m1012_1023, kernel_reg);
881 res_reg = _mm256_hadds_epi16(res_reg, _mm256_setzero_si256());
882
883 // Round the words
884 res_reg = mm256_round_epi16(&res_reg, ®_32, 6);
885
886 // Combine to get the result
887 res_reg = _mm256_packus_epi16(res_reg, res_reg);
888
889 // Save the result
890 mm256_storeu2_epi32((__m128i *)dst_ptr, (__m128i *)(dst_ptr + dst_stride),
891 &res_reg);
892
893 // Update the source by two rows
894 src_ptr += src_stride_unrolled;
895 dst_ptr += dst_stride_unrolled;
896
897 src_reg_m1001 = src_reg_1223;
898 src_reg_1 = src_reg_3;
899 }
900 }
901
vpx_filter_block1d8_v8_avx2(const uint8_t * src_ptr,ptrdiff_t src_pitch,uint8_t * output_ptr,ptrdiff_t out_pitch,uint32_t output_height,const int16_t * filter)902 static void vpx_filter_block1d8_v8_avx2(
903 const uint8_t *src_ptr, ptrdiff_t src_pitch, uint8_t *output_ptr,
904 ptrdiff_t out_pitch, uint32_t output_height, const int16_t *filter) {
905 __m256i f[4], ss[4];
906 __m256i r[8];
907 __m128i s[9];
908
909 unsigned int y = output_height;
910 // Multiply the size of the source stride by two
911 const ptrdiff_t src_stride = src_pitch << 1;
912
913 // The output_height is always a multiple of two.
914 assert(!(output_height & 1));
915
916 shuffle_filter_avx2(filter, f);
917 s[0] = _mm_loadl_epi64((const __m128i *)(src_ptr + 0 * src_pitch));
918 s[1] = _mm_loadl_epi64((const __m128i *)(src_ptr + 1 * src_pitch));
919 s[2] = _mm_loadl_epi64((const __m128i *)(src_ptr + 2 * src_pitch));
920 s[3] = _mm_loadl_epi64((const __m128i *)(src_ptr + 3 * src_pitch));
921 s[4] = _mm_loadl_epi64((const __m128i *)(src_ptr + 4 * src_pitch));
922 s[5] = _mm_loadl_epi64((const __m128i *)(src_ptr + 5 * src_pitch));
923 s[6] = _mm_loadl_epi64((const __m128i *)(src_ptr + 6 * src_pitch));
924
925 // merge the result together
926 // r[0]: 0 0 0 0 0 0 0 0 r17 r16 r15 r14 r13 r12 r11 r10 | 0 0 0 0 0 0 0 0
927 // r07 r06 r05 r04 r03 r02 r01 r00
928 r[0] = _mm256_inserti128_si256(_mm256_castsi128_si256(s[0]), s[1], 1);
929
930 // r[1]: 0 0 0 0 0 0 0 0 r27 r26 r25 r24 r23 r22 r21 r20 | 0 0 0 0 0 0 0 0
931 // r17 r16 r15 r14 r13 r12 r11 r10
932 r[1] = _mm256_inserti128_si256(_mm256_castsi128_si256(s[1]), s[2], 1);
933
934 // r[2]: 0 0 0 0 0 0 0 0 r37 r36 r35 r34 r33 r32 r31 r30 | 0 0 0 0 0 0 0 0
935 // r27 r26 r25 r24 r23 r22 r21 r20
936 r[2] = _mm256_inserti128_si256(_mm256_castsi128_si256(s[2]), s[3], 1);
937
938 // r[3]: 0 0 0 0 0 0 0 0 r47 r46 r45 r44 r43 r42 r41 r40 | 0 0 0 0 0 0 0 0
939 // r37 r36 r35 r34 r33 r32 r31 r30
940 r[3] = _mm256_inserti128_si256(_mm256_castsi128_si256(s[3]), s[4], 1);
941
942 // r[4]: 0 0 0 0 0 0 0 0 r57 r56 r55 r54 r53 r52 r51 r50 | 0 0 0 0 0 0 0 0
943 // r47 r46 r45 r44 r43 r42 r41 r40
944 r[4] = _mm256_inserti128_si256(_mm256_castsi128_si256(s[4]), s[5], 1);
945
946 // r[5]: 0 0 0 0 0 0 0 0 r67 r66 r65 r64 r63 r62 r61 r60 | 0 0 0 0 0 0 0 0
947 // r57 r56 r55 r54 r53 r52 r51 r50
948 r[5] = _mm256_inserti128_si256(_mm256_castsi128_si256(s[5]), s[6], 1);
949
950 // Merge together
951 // ss[0]: |r27 r17|.......|r21 r11|r20 r10 || r17 r07|.....|r12 r02|r11
952 // r01|r10 r00|
953 ss[0] = _mm256_unpacklo_epi8(r[0], r[1]);
954
955 // ss[0]: |r47 r37|.......|r41 r31|r40 r30 || r37 r27|.....|r32 r22|r31
956 // r21|r30 r20|
957 ss[1] = _mm256_unpacklo_epi8(r[2], r[3]);
958
959 // ss[2]: |r67 r57|.......|r61 r51|r60 r50 || r57 r47|.....|r52 r42|r51
960 // r41|r50 r40|
961 ss[2] = _mm256_unpacklo_epi8(r[4], r[5]);
962
963 // Process 2 rows at a time
964 do {
965 s[7] = _mm_loadl_epi64((const __m128i *)(src_ptr + 7 * src_pitch));
966 s[8] = _mm_loadl_epi64((const __m128i *)(src_ptr + 8 * src_pitch));
967
968 // r[6]: 0 0 0 0 0 0 0 0 r77 r76 r75 r74 r73 r72 r71 r70 | 0 0 0 0 0 0 0
969 // 0 r67 r66 r65 r64 r63 r62 r61 r60
970 r[6] = _mm256_inserti128_si256(_mm256_castsi128_si256(s[6]), s[7], 1);
971 // r[7]: 0 0 0 0 0 0 0 0 r87 r86 r85 r84 r83 r82 r81 r80 | 0 0 0 0 0 0 0
972 // 0 r77 r76 r75 r74 r73 r72 r71 r70
973 r[7] = _mm256_inserti128_si256(_mm256_castsi128_si256(s[7]), s[8], 1);
974
975 // ss[3] : | r87 r77 | .......| r81 r71 | r80 r70 || r77 r67 | .....| r72
976 // r62 | r71 r61|r70 r60|
977 ss[3] = _mm256_unpacklo_epi8(r[6], r[7]);
978 ss[0] = convolve8_16_avx2(ss, f);
979 ss[0] = _mm256_packus_epi16(ss[0], ss[0]);
980 src_ptr += src_stride;
981
982 /* shift down two rows */
983 s[6] = s[8];
984 _mm_storel_epi64((__m128i *)&output_ptr[0], _mm256_castsi256_si128(ss[0]));
985 output_ptr += out_pitch;
986 _mm_storel_epi64((__m128i *)&output_ptr[0],
987 _mm256_extractf128_si256(ss[0], 1));
988 output_ptr += out_pitch;
989 ss[0] = ss[1];
990 ss[1] = ss[2];
991 ss[2] = ss[3];
992 y -= 2;
993 } while (y > 1);
994 }
995
vpx_filter_block1d4_h8_avx2(const uint8_t * src_ptr,ptrdiff_t src_pitch,uint8_t * output_ptr,ptrdiff_t output_pitch,uint32_t output_height,const int16_t * filter)996 static void vpx_filter_block1d4_h8_avx2(
997 const uint8_t *src_ptr, ptrdiff_t src_pitch, uint8_t *output_ptr,
998 ptrdiff_t output_pitch, uint32_t output_height, const int16_t *filter) {
999 __m128i filtersReg;
1000 __m256i addFilterReg64_256bit;
1001 unsigned int y = output_height;
1002
1003 assert(output_height > 1);
1004
1005 addFilterReg64_256bit = _mm256_set1_epi16(32);
1006
1007 // f7 f6 f5 f4 f3 f2 f1 f0 (16 bit)
1008 filtersReg = _mm_loadu_si128((const __m128i *)filter);
1009
1010 // converting the 16 bit (short) to 8 bit (byte) and have the same data
1011 // in both lanes of 128 bit register.
1012 // f7 f6 f5 f4 f3 f2 f1 f0 || f7 f6 f5 f4 f3 f2 f1 f0 (8 bit each)
1013 filtersReg = _mm_packs_epi16(filtersReg, filtersReg);
1014
1015 {
1016 ptrdiff_t src_stride;
1017 __m256i filt1Reg, filt2Reg, firstFilters, secondFilters;
1018 // have the same data in both lanes of a 256 bit register
1019 // f7 f6 f5 f4 f3 f2 f1 f0 f7 f6 f5 f4 f3 f2 f1 f0 | f7 f6 f5 f4 f3 f2 f1 f0
1020 // f7 f6 f5 f4 f3 f2 f1 f0 (8bit each)
1021 const __m256i filtersReg32 = _mm256_broadcastsi128_si256(filtersReg);
1022
1023 // duplicate only the first 32 bits
1024 // f3 f2 f1 f0|f3 f2 f1 f0|f3 f2 f1 f0|f3 f2 f1 f0 | f3 f2 f1 f0|f3 f2 f1
1025 // f0|f3 f2 f1 f0|f3 f2 f1 f0
1026 firstFilters = _mm256_shuffle_epi32(filtersReg32, 0);
1027 // duplicate only the second 32 bits
1028 // f7 f6 f5 f4|f7 f6 f5 f4|f7 f6 f5 f4|f7 f6 f5 f4 | f7 f6 f5 f4|f7 f6 f5
1029 // f4|f7 f6 f5 f4|f7 f6 f5 f4
1030 secondFilters = _mm256_shuffle_epi32(filtersReg32, 0x55);
1031
1032 // s6 s5 s4 s3 s5 s4 s3 s2 s4 s3 s2 s1 s3 s2 s1 s0 | s6 s5 s4 s3 s5 s4 s3
1033 // s2 s4 s3 s2 s1 s3 s2 s1 s0
1034 filt1Reg = _mm256_load_si256((__m256i const *)filt_d4_global_avx2);
1035
1036 // s10 s9 s8 s7 s9 s8 s7 s6 s8 s7 s6 s5 s7 s6 s5 s4 | s10 s9 s8 s7 s9 s8 s7
1037 // s6 s8 s7 s6 s5 s7 s6 s5 s4
1038 filt2Reg = _mm256_load_si256((__m256i const *)(filt_d4_global_avx2 + 32));
1039
1040 // multiple the size of the source and destination stride by two
1041 src_stride = src_pitch << 1;
1042
1043 do {
1044 __m256i srcRegFilt32b1_1, srcRegFilt32b2, srcReg32b1;
1045 // load the 2 strides of source
1046 // r115 r114 ...... r15 r14 r13 r12 r11 r10 | r015 r014 r013 ...... r07
1047 // r06 r05 r04 r03 r02 r01 r00
1048 srcReg32b1 = mm256_loadu2_si128(src_ptr - 3, src_ptr - 3 + src_pitch);
1049
1050 // filter the source buffer
1051 // r16 r15 r14 r13 r15 r14 r13 r12 r14 r13 r12 r11 r13 r12 r11 r10 | r06
1052 // r05 r04 r03 r05 r04 r03 r02 r04 r03 r02 r01 r03 r02 r01 r00
1053 srcRegFilt32b1_1 = _mm256_shuffle_epi8(srcReg32b1, filt1Reg);
1054
1055 // multiply 4 adjacent elements with the filter and add the result
1056 // ...|f3*r14+f2*r13|f1*r13+f0*r12|f3*r13+f2*r12|f1*r11+f0*r10||...
1057 // |f1*r03+f0*r02|f3*r04+f2*r03|f1*r02+f0*r01|f3*r03+f2*r02|f1*r01+f0*r00
1058 srcRegFilt32b1_1 = _mm256_maddubs_epi16(srcRegFilt32b1_1, firstFilters);
1059
1060 // filter the source buffer
1061 // r110 r19 r18 r17|r19 r18 r17 r16|r18 r17 r16 r15|r17 r16 r15 r14||r010
1062 // r09 r08 r07|r09 r08 r07 r06|r08 r07 r06 r05|r07 r06 r05 r04
1063 srcRegFilt32b2 = _mm256_shuffle_epi8(srcReg32b1, filt2Reg);
1064
1065 // multiply 4 adjacent elements with the filter and add the result
1066 // r010 r09 r08 r07|r9 r08 r07 r06|r08 r07 r06 r05|r07 r06 r05 r04||r010
1067 // r09 r08 r07|r9 r08 r07 r06|r08 r07 r06 r05|r07 r06 r05 r04
1068 srcRegFilt32b2 = _mm256_maddubs_epi16(srcRegFilt32b2, secondFilters);
1069
1070 srcRegFilt32b1_1 =
1071 _mm256_add_epi16(srcRegFilt32b1_1, addFilterReg64_256bit);
1072 srcRegFilt32b1_1 = _mm256_adds_epi16(srcRegFilt32b1_1, srcRegFilt32b2);
1073
1074 srcRegFilt32b1_1 =
1075 _mm256_hadds_epi16(srcRegFilt32b1_1, _mm256_setzero_si256());
1076
1077 // 0 0 0 0 R13 R12 R11 R10 || 0 0 0 0 R03 R02 R01 R00 (16bit)
1078 srcRegFilt32b1_1 = _mm256_srai_epi16(srcRegFilt32b1_1, 7);
1079
1080 // 8zeros 0 0 0 0 R13 R12 R11 R10 || 8zeros 0 0 0 0 R03 R02 R01 R00 (8bit)
1081 srcRegFilt32b1_1 =
1082 _mm256_packus_epi16(srcRegFilt32b1_1, _mm256_setzero_si256());
1083
1084 src_ptr += src_stride;
1085 // save first row 4 values
1086 *((int *)&output_ptr[0]) =
1087 _mm_cvtsi128_si32(_mm256_castsi256_si128(srcRegFilt32b1_1));
1088 output_ptr += output_pitch;
1089
1090 // save second row 4 values
1091 *((int *)&output_ptr[0]) =
1092 _mm_cvtsi128_si32(_mm256_extractf128_si256(srcRegFilt32b1_1, 1));
1093 output_ptr += output_pitch;
1094
1095 y = y - 2;
1096 } while (y > 1);
1097
1098 // For remaining height
1099 if (y > 0) {
1100 __m128i srcReg1, srcRegFilt1_1, addFilterReg64;
1101 __m128i srcRegFilt2;
1102
1103 addFilterReg64 = _mm_set1_epi32((int)0x0400040u);
1104
1105 srcReg1 = _mm_loadu_si128((const __m128i *)(src_ptr - 3));
1106
1107 // filter the source buffer
1108 srcRegFilt1_1 =
1109 _mm_shuffle_epi8(srcReg1, _mm256_castsi256_si128(filt1Reg));
1110
1111 // multiply 4 adjacent elements with the filter and add the result
1112 srcRegFilt1_1 = _mm_maddubs_epi16(srcRegFilt1_1,
1113 _mm256_castsi256_si128(firstFilters));
1114
1115 // filter the source buffer
1116 srcRegFilt2 = _mm_shuffle_epi8(srcReg1, _mm256_castsi256_si128(filt2Reg));
1117
1118 // multiply 4 adjacent elements with the filter and add the result
1119 srcRegFilt2 =
1120 _mm_maddubs_epi16(srcRegFilt2, _mm256_castsi256_si128(secondFilters));
1121
1122 srcRegFilt1_1 = _mm_adds_epi16(srcRegFilt1_1, srcRegFilt2);
1123 srcRegFilt1_1 = _mm_hadds_epi16(srcRegFilt1_1, _mm_setzero_si128());
1124 // shift by 6 bit each 16 bit
1125 srcRegFilt1_1 = _mm_adds_epi16(srcRegFilt1_1, addFilterReg64);
1126 srcRegFilt1_1 = _mm_srai_epi16(srcRegFilt1_1, 7);
1127
1128 // shrink to 8 bit each 16 bits, the first lane contain the first
1129 // convolve result and the second lane contain the second convolve result
1130 srcRegFilt1_1 = _mm_packus_epi16(srcRegFilt1_1, _mm_setzero_si128());
1131
1132 // save 4 bytes
1133 *((int *)(output_ptr)) = _mm_cvtsi128_si32(srcRegFilt1_1);
1134 }
1135 }
1136 }
1137
vpx_filter_block1d4_v8_avx2(const uint8_t * src_ptr,ptrdiff_t src_pitch,uint8_t * output_ptr,ptrdiff_t out_pitch,uint32_t output_height,const int16_t * filter)1138 static void vpx_filter_block1d4_v8_avx2(
1139 const uint8_t *src_ptr, ptrdiff_t src_pitch, uint8_t *output_ptr,
1140 ptrdiff_t out_pitch, uint32_t output_height, const int16_t *filter) {
1141 __m256i f[4], ss[4];
1142 __m256i r[9], rr[2];
1143 __m128i s[11];
1144
1145 unsigned int y = output_height;
1146 // Multiply the size of the source stride by four
1147 const ptrdiff_t src_stride = src_pitch << 2;
1148 const ptrdiff_t out_stride = out_pitch << 2;
1149
1150 // The output_height is always a multiple of two.
1151 assert(!(output_height & 0x01));
1152
1153 shuffle_filter_avx2(filter, f);
1154
1155 s[0] = _mm_loadl_epi64((const __m128i *)(src_ptr + 0 * src_pitch));
1156 s[1] = _mm_loadl_epi64((const __m128i *)(src_ptr + 1 * src_pitch));
1157 s[2] = _mm_loadl_epi64((const __m128i *)(src_ptr + 2 * src_pitch));
1158 s[3] = _mm_loadl_epi64((const __m128i *)(src_ptr + 3 * src_pitch));
1159 s[4] = _mm_loadl_epi64((const __m128i *)(src_ptr + 4 * src_pitch));
1160 s[5] = _mm_loadl_epi64((const __m128i *)(src_ptr + 5 * src_pitch));
1161 s[6] = _mm_loadl_epi64((const __m128i *)(src_ptr + 6 * src_pitch));
1162
1163 r[0] = _mm256_inserti128_si256(_mm256_castsi128_si256(s[0]), s[2], 1);
1164 r[1] = _mm256_inserti128_si256(_mm256_castsi128_si256(s[1]), s[3], 1);
1165 r[2] = _mm256_inserti128_si256(_mm256_castsi128_si256(s[2]), s[4], 1);
1166 r[3] = _mm256_inserti128_si256(_mm256_castsi128_si256(s[3]), s[5], 1);
1167 r[4] = _mm256_inserti128_si256(_mm256_castsi128_si256(s[4]), s[6], 1);
1168
1169 // r37.....r24..r33..r31 r30 r23 r22 r21 r20|r17....r14 r07..r05 r04 r13 r12
1170 // r11 r10 r03 r02 r01 r00
1171 rr[0] = _mm256_unpacklo_epi32(r[0], r[1]);
1172
1173 // r47.....r34..r43..r41 r40 r33 r32 r31 r30|r27....r24 r17..r15 r14 r23 r22
1174 // r21 r20 r13 r12 r11 r10
1175 rr[1] = _mm256_unpacklo_epi32(r[1], r[2]);
1176
1177 // r43 r33....r40 r30|r33 r23....r30 r20||r23 r13....r20 r10|r13 r03....r10
1178 // r00|
1179 ss[0] = _mm256_unpacklo_epi8(rr[0], rr[1]);
1180
1181 // r37.....r24..r33..r31 r30 r23 r22 r21 r20||r17....r14 r07..r05 r04 r13 r12
1182 // r11 r10 r03 r02 r01 r00
1183 rr[0] = _mm256_unpacklo_epi32(r[2], r[3]);
1184
1185 // r47.....r34..r43..r41 r40 r33 r32 r31 r30|r27....r24 r17..r15 r14 r23 r22
1186 // r21 r20 r13 r12 r11 r10
1187 rr[1] = _mm256_unpacklo_epi32(r[3], r[4]);
1188
1189 // r63 r53....r60 r50|r53 r43....r50 r40||r43 r33....r40 r30|r33 r23....r30
1190 // r20|
1191 ss[1] = _mm256_unpacklo_epi8(rr[0], rr[1]);
1192 // Process 4 rows at a time
1193 while (y >= 4) {
1194 s[7] = _mm_loadl_epi64((const __m128i *)(src_ptr + 7 * src_pitch));
1195 s[8] = _mm_loadl_epi64((const __m128i *)(src_ptr + 8 * src_pitch));
1196 s[9] = _mm_loadl_epi64((const __m128i *)(src_ptr + 9 * src_pitch));
1197 s[10] = _mm_loadl_epi64((const __m128i *)(src_ptr + 10 * src_pitch));
1198
1199 r[5] = _mm256_inserti128_si256(_mm256_castsi128_si256(s[5]), s[7], 1);
1200 r[6] = _mm256_inserti128_si256(_mm256_castsi128_si256(s[6]), s[8], 1);
1201 rr[0] = _mm256_unpacklo_epi32(r[4], r[5]);
1202 rr[1] = _mm256_unpacklo_epi32(r[5], r[6]);
1203 ss[2] = _mm256_unpacklo_epi8(rr[0], rr[1]);
1204
1205 r[7] = _mm256_inserti128_si256(_mm256_castsi128_si256(s[7]), s[9], 1);
1206 r[8] = _mm256_inserti128_si256(_mm256_castsi128_si256(s[8]), s[10], 1);
1207 rr[0] = _mm256_unpacklo_epi32(r[6], r[7]);
1208 rr[1] = _mm256_unpacklo_epi32(r[7], r[8]);
1209 ss[3] = _mm256_unpacklo_epi8(rr[0], rr[1]);
1210
1211 ss[0] = convolve8_16_avx2(ss, f);
1212
1213 // r3 r2 r3 r2 r1 r0 r1 r0
1214 ss[0] = _mm256_packus_epi16(ss[0], ss[0]);
1215 src_ptr += src_stride;
1216
1217 mm256_storeu2_epi32((__m128i *const)output_ptr,
1218 (__m128i *const)(output_ptr + (2 * out_pitch)), ss);
1219
1220 ss[0] = _mm256_srli_si256(ss[0], 4);
1221
1222 mm256_storeu2_epi32((__m128i *const)(output_ptr + (1 * out_pitch)),
1223 (__m128i *const)(output_ptr + (3 * out_pitch)), ss);
1224
1225 output_ptr += out_stride;
1226
1227 ss[0] = ss[2];
1228 ss[1] = ss[3];
1229
1230 s[6] = s[10];
1231 s[5] = s[9];
1232
1233 r[4] = r[8];
1234 y -= 4;
1235 }
1236
1237 // Process 2 rows
1238 if (y == 2) {
1239 __m128i ss1[4], f1[4], r1[4];
1240
1241 s[4] = _mm_loadl_epi64((const __m128i *)(src_ptr + 4 * src_pitch));
1242 s[7] = _mm_loadl_epi64((const __m128i *)(src_ptr + 7 * src_pitch));
1243 s[8] = _mm_loadl_epi64((const __m128i *)(src_ptr + 8 * src_pitch));
1244
1245 f1[0] = _mm256_castsi256_si128(f[0]);
1246 f1[1] = _mm256_castsi256_si128(f[1]);
1247 f1[2] = _mm256_castsi256_si128(f[2]);
1248 f1[3] = _mm256_castsi256_si128(f[3]);
1249
1250 r1[0] = _mm_unpacklo_epi32(s[4], s[5]);
1251 r1[1] = _mm_unpacklo_epi32(s[5], s[6]);
1252
1253 // R7-6 xxxx .. . . x| r73 r72 r71 r70 r63 r62 r61 r60
1254 r1[2] = _mm_unpacklo_epi32(s[6], s[7]);
1255
1256 // R8-7 xxxx .. . . x| r83 r82 r81 r80 r73 r72 r71 r70
1257 r1[3] = _mm_unpacklo_epi32(s[7], s[8]);
1258
1259 // r23 r13....r20 r10|r13 r03....r10 r00
1260 ss1[0] = _mm256_castsi256_si128(ss[0]);
1261
1262 // r43 r33....r40 r30|r33 r23....r30 r20
1263 ss1[1] = _mm256_castsi256_si128(ss[1]);
1264
1265 // r63 r53....r60 r50|r53 r43....r50 r40
1266 ss1[2] = _mm_unpacklo_epi8(r1[0], r1[1]);
1267
1268 // r83 r73....r80 r70|r73 r63....r70 r60
1269 ss1[3] = _mm_unpacklo_epi8(r1[2], r1[3]);
1270
1271 ss1[0] = convolve8_8_ssse3(ss1, f1);
1272
1273 // r1 r0 r1 r0
1274 ss1[0] = _mm_packus_epi16(ss1[0], ss1[0]);
1275
1276 // Save first row 4 values
1277 *((int *)&output_ptr[0]) = _mm_cvtsi128_si32(ss1[0]);
1278 output_ptr += out_pitch;
1279
1280 ss1[0] = _mm_srli_si128(ss1[0], 4);
1281 // Save second row 4 values
1282 *((int *)&output_ptr[0]) = _mm_cvtsi128_si32(ss1[0]);
1283 }
1284 }
1285
1286 #if HAVE_AVX2 && HAVE_SSSE3
1287 #if VPX_ARCH_X86_64
1288 filter8_1dfunction vpx_filter_block1d8_v8_intrin_ssse3;
1289 filter8_1dfunction vpx_filter_block1d8_h8_intrin_ssse3;
1290 filter8_1dfunction vpx_filter_block1d4_h8_intrin_ssse3;
1291 #else // VPX_ARCH_X86
1292 filter8_1dfunction vpx_filter_block1d8_v8_ssse3;
1293 filter8_1dfunction vpx_filter_block1d8_h8_ssse3;
1294 filter8_1dfunction vpx_filter_block1d4_h8_ssse3;
1295 #endif // VPX_ARCH_X86_64
1296 filter8_1dfunction vpx_filter_block1d8_v8_avg_ssse3;
1297 filter8_1dfunction vpx_filter_block1d8_h8_avg_ssse3;
1298 filter8_1dfunction vpx_filter_block1d4_v8_avg_ssse3;
1299 filter8_1dfunction vpx_filter_block1d4_h8_avg_ssse3;
1300 #define vpx_filter_block1d8_v8_avg_avx2 vpx_filter_block1d8_v8_avg_ssse3
1301 #define vpx_filter_block1d8_h8_avg_avx2 vpx_filter_block1d8_h8_avg_ssse3
1302 #define vpx_filter_block1d4_v8_avg_avx2 vpx_filter_block1d4_v8_avg_ssse3
1303 #define vpx_filter_block1d4_h8_avg_avx2 vpx_filter_block1d4_h8_avg_ssse3
1304 filter8_1dfunction vpx_filter_block1d16_v2_ssse3;
1305 filter8_1dfunction vpx_filter_block1d16_h2_ssse3;
1306 filter8_1dfunction vpx_filter_block1d8_v2_ssse3;
1307 filter8_1dfunction vpx_filter_block1d8_h2_ssse3;
1308 filter8_1dfunction vpx_filter_block1d4_v2_ssse3;
1309 filter8_1dfunction vpx_filter_block1d4_h2_ssse3;
1310 #define vpx_filter_block1d16_v2_avx2 vpx_filter_block1d16_v2_ssse3
1311 #define vpx_filter_block1d16_h2_avx2 vpx_filter_block1d16_h2_ssse3
1312 #define vpx_filter_block1d8_v2_avx2 vpx_filter_block1d8_v2_ssse3
1313 #define vpx_filter_block1d8_h2_avx2 vpx_filter_block1d8_h2_ssse3
1314 #define vpx_filter_block1d4_v2_avx2 vpx_filter_block1d4_v2_ssse3
1315 #define vpx_filter_block1d4_h2_avx2 vpx_filter_block1d4_h2_ssse3
1316 filter8_1dfunction vpx_filter_block1d16_v2_avg_ssse3;
1317 filter8_1dfunction vpx_filter_block1d16_h2_avg_ssse3;
1318 filter8_1dfunction vpx_filter_block1d8_v2_avg_ssse3;
1319 filter8_1dfunction vpx_filter_block1d8_h2_avg_ssse3;
1320 filter8_1dfunction vpx_filter_block1d4_v2_avg_ssse3;
1321 filter8_1dfunction vpx_filter_block1d4_h2_avg_ssse3;
1322 #define vpx_filter_block1d16_v2_avg_avx2 vpx_filter_block1d16_v2_avg_ssse3
1323 #define vpx_filter_block1d16_h2_avg_avx2 vpx_filter_block1d16_h2_avg_ssse3
1324 #define vpx_filter_block1d8_v2_avg_avx2 vpx_filter_block1d8_v2_avg_ssse3
1325 #define vpx_filter_block1d8_h2_avg_avx2 vpx_filter_block1d8_h2_avg_ssse3
1326 #define vpx_filter_block1d4_v2_avg_avx2 vpx_filter_block1d4_v2_avg_ssse3
1327 #define vpx_filter_block1d4_h2_avg_avx2 vpx_filter_block1d4_h2_avg_ssse3
1328
1329 #define vpx_filter_block1d16_v4_avg_avx2 vpx_filter_block1d16_v8_avg_avx2
1330 #define vpx_filter_block1d16_h4_avg_avx2 vpx_filter_block1d16_h8_avg_avx2
1331 #define vpx_filter_block1d8_v4_avg_avx2 vpx_filter_block1d8_v8_avg_avx2
1332 #define vpx_filter_block1d8_h4_avg_avx2 vpx_filter_block1d8_h8_avg_avx2
1333 #define vpx_filter_block1d4_v4_avg_avx2 vpx_filter_block1d4_v8_avg_avx2
1334 #define vpx_filter_block1d4_h4_avg_avx2 vpx_filter_block1d4_h8_avg_avx2
1335 // void vpx_convolve8_horiz_avx2(const uint8_t *src, ptrdiff_t src_stride,
1336 // uint8_t *dst, ptrdiff_t dst_stride,
1337 // const InterpKernel *filter, int x0_q4,
1338 // int32_t x_step_q4, int y0_q4, int y_step_q4,
1339 // int w, int h);
1340 // void vpx_convolve8_vert_avx2(const uint8_t *src, ptrdiff_t src_stride,
1341 // uint8_t *dst, ptrdiff_t dst_stride,
1342 // const InterpKernel *filter, int x0_q4,
1343 // int32_t x_step_q4, int y0_q4, int y_step_q4,
1344 // int w, int h);
1345 // void vpx_convolve8_avg_horiz_avx2(const uint8_t *src, ptrdiff_t src_stride,
1346 // uint8_t *dst, ptrdiff_t dst_stride,
1347 // const InterpKernel *filter, int x0_q4,
1348 // int32_t x_step_q4, int y0_q4,
1349 // int y_step_q4, int w, int h);
1350 // void vpx_convolve8_avg_vert_avx2(const uint8_t *src, ptrdiff_t src_stride,
1351 // uint8_t *dst, ptrdiff_t dst_stride,
1352 // const InterpKernel *filter, int x0_q4,
1353 // int32_t x_step_q4, int y0_q4,
1354 // int y_step_q4, int w, int h);
1355 FUN_CONV_1D(horiz, x0_q4, x_step_q4, h, src, , avx2, 0)
1356 FUN_CONV_1D(vert, y0_q4, y_step_q4, v, src - src_stride * (num_taps / 2 - 1), ,
1357 avx2, 0)
1358 FUN_CONV_1D(avg_horiz, x0_q4, x_step_q4, h, src, avg_, avx2, 1)
1359 FUN_CONV_1D(avg_vert, y0_q4, y_step_q4, v,
1360 src - src_stride * (num_taps / 2 - 1), avg_, avx2, 1)
1361
1362 // void vpx_convolve8_avx2(const uint8_t *src, ptrdiff_t src_stride,
1363 // uint8_t *dst, ptrdiff_t dst_stride,
1364 // const InterpKernel *filter, int x0_q4,
1365 // int32_t x_step_q4, int y0_q4, int y_step_q4,
1366 // int w, int h);
1367 // void vpx_convolve8_avg_avx2(const uint8_t *src, ptrdiff_t src_stride,
1368 // uint8_t *dst, ptrdiff_t dst_stride,
1369 // const InterpKernel *filter, int x0_q4,
1370 // int32_t x_step_q4, int y0_q4, int y_step_q4,
1371 // int w, int h);
1372 FUN_CONV_2D(, avx2, 0)
1373 FUN_CONV_2D(avg_, avx2, 1)
1374 #endif // HAVE_AX2 && HAVE_SSSE3
1375