1 /*
2 * Copyright (c) 2022 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 #include <immintrin.h> // AVX2
11 #include "./vpx_dsp_rtcd.h"
12 #include "vpx/vpx_integer.h"
13
calc_final_4(const __m256i * const sums,uint32_t sad_array[4])14 static VPX_FORCE_INLINE void calc_final_4(const __m256i *const sums /*[4]*/,
15 uint32_t sad_array[4]) {
16 const __m256i t0 = _mm256_hadd_epi32(sums[0], sums[1]);
17 const __m256i t1 = _mm256_hadd_epi32(sums[2], sums[3]);
18 const __m256i t2 = _mm256_hadd_epi32(t0, t1);
19 const __m128i sum = _mm_add_epi32(_mm256_castsi256_si128(t2),
20 _mm256_extractf128_si256(t2, 1));
21 _mm_storeu_si128((__m128i *)sad_array, sum);
22 }
23
highbd_sad64xHx4d(__m256i * sums_16,const uint16_t * src,int src_stride,uint16_t * refs[4],int ref_stride,int height)24 static VPX_FORCE_INLINE void highbd_sad64xHx4d(__m256i *sums_16 /*[4]*/,
25 const uint16_t *src,
26 int src_stride,
27 uint16_t *refs[4],
28 int ref_stride, int height) {
29 int i;
30 for (i = 0; i < height; ++i) {
31 // load src and all ref[]
32 const __m256i s0 = _mm256_load_si256((const __m256i *)src);
33 const __m256i s1 = _mm256_load_si256((const __m256i *)(src + 16));
34 const __m256i s2 = _mm256_load_si256((const __m256i *)(src + 32));
35 const __m256i s3 = _mm256_load_si256((const __m256i *)(src + 48));
36 int x;
37
38 for (x = 0; x < 4; ++x) {
39 __m256i r[4];
40 r[0] = _mm256_loadu_si256((const __m256i *)refs[x]);
41 r[1] = _mm256_loadu_si256((const __m256i *)(refs[x] + 16));
42 r[2] = _mm256_loadu_si256((const __m256i *)(refs[x] + 32));
43 r[3] = _mm256_loadu_si256((const __m256i *)(refs[x] + 48));
44
45 // absolute differences between every ref[] to src
46 r[0] = _mm256_abs_epi16(_mm256_sub_epi16(r[0], s0));
47 r[1] = _mm256_abs_epi16(_mm256_sub_epi16(r[1], s1));
48 r[2] = _mm256_abs_epi16(_mm256_sub_epi16(r[2], s2));
49 r[3] = _mm256_abs_epi16(_mm256_sub_epi16(r[3], s3));
50
51 // sum every abs diff
52 sums_16[x] = _mm256_add_epi16(sums_16[x], _mm256_add_epi16(r[0], r[1]));
53 sums_16[x] = _mm256_add_epi16(sums_16[x], _mm256_add_epi16(r[2], r[3]));
54 }
55
56 src += src_stride;
57 refs[0] += ref_stride;
58 refs[1] += ref_stride;
59 refs[2] += ref_stride;
60 refs[3] += ref_stride;
61 }
62 }
63
64 #define HIGHBD_SAD64XNX4D(n) \
65 void vpx_highbd_sad64x##n##x4d_avx2(const uint8_t *src_ptr, int src_stride, \
66 const uint8_t *const ref_array[4], \
67 int ref_stride, uint32_t sad_array[4]) { \
68 const uint16_t *src = CONVERT_TO_SHORTPTR(src_ptr); \
69 uint16_t *refs[4]; \
70 __m256i sums_16[4]; \
71 __m256i sums_32[4]; \
72 int i; \
73 \
74 refs[0] = CONVERT_TO_SHORTPTR(ref_array[0]); \
75 refs[1] = CONVERT_TO_SHORTPTR(ref_array[1]); \
76 refs[2] = CONVERT_TO_SHORTPTR(ref_array[2]); \
77 refs[3] = CONVERT_TO_SHORTPTR(ref_array[3]); \
78 sums_32[0] = _mm256_setzero_si256(); \
79 sums_32[1] = _mm256_setzero_si256(); \
80 sums_32[2] = _mm256_setzero_si256(); \
81 sums_32[3] = _mm256_setzero_si256(); \
82 \
83 for (i = 0; i < (n / 2); ++i) { \
84 sums_16[0] = _mm256_setzero_si256(); \
85 sums_16[1] = _mm256_setzero_si256(); \
86 sums_16[2] = _mm256_setzero_si256(); \
87 sums_16[3] = _mm256_setzero_si256(); \
88 \
89 highbd_sad64xHx4d(sums_16, src, src_stride, refs, ref_stride, 2); \
90 \
91 /* sums_16 will outrange after 2 rows, so add current sums_16 to \
92 * sums_32*/ \
93 sums_32[0] = _mm256_add_epi32( \
94 sums_32[0], \
95 _mm256_add_epi32( \
96 _mm256_cvtepu16_epi32(_mm256_castsi256_si128(sums_16[0])), \
97 _mm256_cvtepu16_epi32( \
98 _mm256_extractf128_si256(sums_16[0], 1)))); \
99 sums_32[1] = _mm256_add_epi32( \
100 sums_32[1], \
101 _mm256_add_epi32( \
102 _mm256_cvtepu16_epi32(_mm256_castsi256_si128(sums_16[1])), \
103 _mm256_cvtepu16_epi32( \
104 _mm256_extractf128_si256(sums_16[1], 1)))); \
105 sums_32[2] = _mm256_add_epi32( \
106 sums_32[2], \
107 _mm256_add_epi32( \
108 _mm256_cvtepu16_epi32(_mm256_castsi256_si128(sums_16[2])), \
109 _mm256_cvtepu16_epi32( \
110 _mm256_extractf128_si256(sums_16[2], 1)))); \
111 sums_32[3] = _mm256_add_epi32( \
112 sums_32[3], \
113 _mm256_add_epi32( \
114 _mm256_cvtepu16_epi32(_mm256_castsi256_si128(sums_16[3])), \
115 _mm256_cvtepu16_epi32( \
116 _mm256_extractf128_si256(sums_16[3], 1)))); \
117 \
118 src += src_stride << 1; \
119 } \
120 calc_final_4(sums_32, sad_array); \
121 }
122
123 // 64x64
124 HIGHBD_SAD64XNX4D(64)
125
126 // 64x32
127 HIGHBD_SAD64XNX4D(32)
128
highbd_sad32xHx4d(__m256i * sums_16,const uint16_t * src,int src_stride,uint16_t * refs[4],int ref_stride,int height)129 static VPX_FORCE_INLINE void highbd_sad32xHx4d(__m256i *sums_16 /*[4]*/,
130 const uint16_t *src,
131 int src_stride,
132 uint16_t *refs[4],
133 int ref_stride, int height) {
134 int i;
135 for (i = 0; i < height; i++) {
136 __m256i r[8];
137
138 // load src and all ref[]
139 const __m256i s = _mm256_load_si256((const __m256i *)src);
140 const __m256i s2 = _mm256_load_si256((const __m256i *)(src + 16));
141 r[0] = _mm256_loadu_si256((const __m256i *)refs[0]);
142 r[1] = _mm256_loadu_si256((const __m256i *)(refs[0] + 16));
143 r[2] = _mm256_loadu_si256((const __m256i *)refs[1]);
144 r[3] = _mm256_loadu_si256((const __m256i *)(refs[1] + 16));
145 r[4] = _mm256_loadu_si256((const __m256i *)refs[2]);
146 r[5] = _mm256_loadu_si256((const __m256i *)(refs[2] + 16));
147 r[6] = _mm256_loadu_si256((const __m256i *)refs[3]);
148 r[7] = _mm256_loadu_si256((const __m256i *)(refs[3] + 16));
149
150 // absolute differences between every ref[] to src
151 r[0] = _mm256_abs_epi16(_mm256_sub_epi16(r[0], s));
152 r[1] = _mm256_abs_epi16(_mm256_sub_epi16(r[1], s2));
153 r[2] = _mm256_abs_epi16(_mm256_sub_epi16(r[2], s));
154 r[3] = _mm256_abs_epi16(_mm256_sub_epi16(r[3], s2));
155 r[4] = _mm256_abs_epi16(_mm256_sub_epi16(r[4], s));
156 r[5] = _mm256_abs_epi16(_mm256_sub_epi16(r[5], s2));
157 r[6] = _mm256_abs_epi16(_mm256_sub_epi16(r[6], s));
158 r[7] = _mm256_abs_epi16(_mm256_sub_epi16(r[7], s2));
159
160 // sum every abs diff
161 sums_16[0] = _mm256_add_epi16(sums_16[0], _mm256_add_epi16(r[0], r[1]));
162 sums_16[1] = _mm256_add_epi16(sums_16[1], _mm256_add_epi16(r[2], r[3]));
163 sums_16[2] = _mm256_add_epi16(sums_16[2], _mm256_add_epi16(r[4], r[5]));
164 sums_16[3] = _mm256_add_epi16(sums_16[3], _mm256_add_epi16(r[6], r[7]));
165
166 src += src_stride;
167 refs[0] += ref_stride;
168 refs[1] += ref_stride;
169 refs[2] += ref_stride;
170 refs[3] += ref_stride;
171 }
172 }
173
174 #define HIGHBD_SAD32XNX4D(n) \
175 void vpx_highbd_sad32x##n##x4d_avx2(const uint8_t *src_ptr, int src_stride, \
176 const uint8_t *const ref_array[4], \
177 int ref_stride, uint32_t sad_array[4]) { \
178 const uint16_t *src = CONVERT_TO_SHORTPTR(src_ptr); \
179 uint16_t *refs[4]; \
180 __m256i sums_16[4]; \
181 __m256i sums_32[4]; \
182 int i; \
183 \
184 refs[0] = CONVERT_TO_SHORTPTR(ref_array[0]); \
185 refs[1] = CONVERT_TO_SHORTPTR(ref_array[1]); \
186 refs[2] = CONVERT_TO_SHORTPTR(ref_array[2]); \
187 refs[3] = CONVERT_TO_SHORTPTR(ref_array[3]); \
188 sums_32[0] = _mm256_setzero_si256(); \
189 sums_32[1] = _mm256_setzero_si256(); \
190 sums_32[2] = _mm256_setzero_si256(); \
191 sums_32[3] = _mm256_setzero_si256(); \
192 \
193 for (i = 0; i < (n / 8); ++i) { \
194 sums_16[0] = _mm256_setzero_si256(); \
195 sums_16[1] = _mm256_setzero_si256(); \
196 sums_16[2] = _mm256_setzero_si256(); \
197 sums_16[3] = _mm256_setzero_si256(); \
198 \
199 highbd_sad32xHx4d(sums_16, src, src_stride, refs, ref_stride, 8); \
200 \
201 /* sums_16 will outrange after 8 rows, so add current sums_16 to \
202 * sums_32*/ \
203 sums_32[0] = _mm256_add_epi32( \
204 sums_32[0], \
205 _mm256_add_epi32( \
206 _mm256_cvtepu16_epi32(_mm256_castsi256_si128(sums_16[0])), \
207 _mm256_cvtepu16_epi32( \
208 _mm256_extractf128_si256(sums_16[0], 1)))); \
209 sums_32[1] = _mm256_add_epi32( \
210 sums_32[1], \
211 _mm256_add_epi32( \
212 _mm256_cvtepu16_epi32(_mm256_castsi256_si128(sums_16[1])), \
213 _mm256_cvtepu16_epi32( \
214 _mm256_extractf128_si256(sums_16[1], 1)))); \
215 sums_32[2] = _mm256_add_epi32( \
216 sums_32[2], \
217 _mm256_add_epi32( \
218 _mm256_cvtepu16_epi32(_mm256_castsi256_si128(sums_16[2])), \
219 _mm256_cvtepu16_epi32( \
220 _mm256_extractf128_si256(sums_16[2], 1)))); \
221 sums_32[3] = _mm256_add_epi32( \
222 sums_32[3], \
223 _mm256_add_epi32( \
224 _mm256_cvtepu16_epi32(_mm256_castsi256_si128(sums_16[3])), \
225 _mm256_cvtepu16_epi32( \
226 _mm256_extractf128_si256(sums_16[3], 1)))); \
227 \
228 src += src_stride << 3; \
229 } \
230 calc_final_4(sums_32, sad_array); \
231 }
232
233 // 32x64
234 HIGHBD_SAD32XNX4D(64)
235
236 // 32x32
237 HIGHBD_SAD32XNX4D(32)
238
239 // 32x16
240 HIGHBD_SAD32XNX4D(16)
241
highbd_sad16xHx4d(__m256i * sums_16,const uint16_t * src,int src_stride,uint16_t * refs[4],int ref_stride,int height)242 static VPX_FORCE_INLINE void highbd_sad16xHx4d(__m256i *sums_16 /*[4]*/,
243 const uint16_t *src,
244 int src_stride,
245 uint16_t *refs[4],
246 int ref_stride, int height) {
247 int i;
248 for (i = 0; i < height; i++) {
249 __m256i r[4];
250
251 // load src and all ref[]
252 const __m256i s = _mm256_load_si256((const __m256i *)src);
253 r[0] = _mm256_loadu_si256((const __m256i *)refs[0]);
254 r[1] = _mm256_loadu_si256((const __m256i *)refs[1]);
255 r[2] = _mm256_loadu_si256((const __m256i *)refs[2]);
256 r[3] = _mm256_loadu_si256((const __m256i *)refs[3]);
257
258 // absolute differences between every ref[] to src
259 r[0] = _mm256_abs_epi16(_mm256_sub_epi16(r[0], s));
260 r[1] = _mm256_abs_epi16(_mm256_sub_epi16(r[1], s));
261 r[2] = _mm256_abs_epi16(_mm256_sub_epi16(r[2], s));
262 r[3] = _mm256_abs_epi16(_mm256_sub_epi16(r[3], s));
263
264 // sum every abs diff
265 sums_16[0] = _mm256_add_epi16(sums_16[0], r[0]);
266 sums_16[1] = _mm256_add_epi16(sums_16[1], r[1]);
267 sums_16[2] = _mm256_add_epi16(sums_16[2], r[2]);
268 sums_16[3] = _mm256_add_epi16(sums_16[3], r[3]);
269
270 src += src_stride;
271 refs[0] += ref_stride;
272 refs[1] += ref_stride;
273 refs[2] += ref_stride;
274 refs[3] += ref_stride;
275 }
276 }
277
vpx_highbd_sad16x32x4d_avx2(const uint8_t * src_ptr,int src_stride,const uint8_t * const ref_array[4],int ref_stride,uint32_t sad_array[4])278 void vpx_highbd_sad16x32x4d_avx2(const uint8_t *src_ptr, int src_stride,
279 const uint8_t *const ref_array[4],
280 int ref_stride, uint32_t sad_array[4]) {
281 const uint16_t *src = CONVERT_TO_SHORTPTR(src_ptr);
282 uint16_t *refs[4];
283 __m256i sums_16[4];
284 __m256i sums_32[4];
285 int i;
286
287 refs[0] = CONVERT_TO_SHORTPTR(ref_array[0]);
288 refs[1] = CONVERT_TO_SHORTPTR(ref_array[1]);
289 refs[2] = CONVERT_TO_SHORTPTR(ref_array[2]);
290 refs[3] = CONVERT_TO_SHORTPTR(ref_array[3]);
291 sums_32[0] = _mm256_setzero_si256();
292 sums_32[1] = _mm256_setzero_si256();
293 sums_32[2] = _mm256_setzero_si256();
294 sums_32[3] = _mm256_setzero_si256();
295
296 for (i = 0; i < 2; ++i) {
297 sums_16[0] = _mm256_setzero_si256();
298 sums_16[1] = _mm256_setzero_si256();
299 sums_16[2] = _mm256_setzero_si256();
300 sums_16[3] = _mm256_setzero_si256();
301
302 highbd_sad16xHx4d(sums_16, src, src_stride, refs, ref_stride, 16);
303
304 // sums_16 will outrange after 16 rows, so add current sums_16 to sums_32
305 sums_32[0] = _mm256_add_epi32(
306 sums_32[0],
307 _mm256_add_epi32(
308 _mm256_cvtepu16_epi32(_mm256_castsi256_si128(sums_16[0])),
309 _mm256_cvtepu16_epi32(_mm256_extractf128_si256(sums_16[0], 1))));
310 sums_32[1] = _mm256_add_epi32(
311 sums_32[1],
312 _mm256_add_epi32(
313 _mm256_cvtepu16_epi32(_mm256_castsi256_si128(sums_16[1])),
314 _mm256_cvtepu16_epi32(_mm256_extractf128_si256(sums_16[1], 1))));
315 sums_32[2] = _mm256_add_epi32(
316 sums_32[2],
317 _mm256_add_epi32(
318 _mm256_cvtepu16_epi32(_mm256_castsi256_si128(sums_16[2])),
319 _mm256_cvtepu16_epi32(_mm256_extractf128_si256(sums_16[2], 1))));
320 sums_32[3] = _mm256_add_epi32(
321 sums_32[3],
322 _mm256_add_epi32(
323 _mm256_cvtepu16_epi32(_mm256_castsi256_si128(sums_16[3])),
324 _mm256_cvtepu16_epi32(_mm256_extractf128_si256(sums_16[3], 1))));
325
326 src += src_stride << 4;
327 }
328 calc_final_4(sums_32, sad_array);
329 }
330
vpx_highbd_sad16x16x4d_avx2(const uint8_t * src_ptr,int src_stride,const uint8_t * const ref_array[4],int ref_stride,uint32_t sad_array[4])331 void vpx_highbd_sad16x16x4d_avx2(const uint8_t *src_ptr, int src_stride,
332 const uint8_t *const ref_array[4],
333 int ref_stride, uint32_t sad_array[4]) {
334 const uint16_t *src = CONVERT_TO_SHORTPTR(src_ptr);
335 uint16_t *refs[4];
336 __m256i sums_16[4];
337
338 refs[0] = CONVERT_TO_SHORTPTR(ref_array[0]);
339 refs[1] = CONVERT_TO_SHORTPTR(ref_array[1]);
340 refs[2] = CONVERT_TO_SHORTPTR(ref_array[2]);
341 refs[3] = CONVERT_TO_SHORTPTR(ref_array[3]);
342 sums_16[0] = _mm256_setzero_si256();
343 sums_16[1] = _mm256_setzero_si256();
344 sums_16[2] = _mm256_setzero_si256();
345 sums_16[3] = _mm256_setzero_si256();
346
347 highbd_sad16xHx4d(sums_16, src, src_stride, refs, ref_stride, 16);
348
349 {
350 __m256i sums_32[4];
351 sums_32[0] = _mm256_add_epi32(
352 _mm256_cvtepu16_epi32(_mm256_castsi256_si128(sums_16[0])),
353 _mm256_cvtepu16_epi32(_mm256_extractf128_si256(sums_16[0], 1)));
354 sums_32[1] = _mm256_add_epi32(
355 _mm256_cvtepu16_epi32(_mm256_castsi256_si128(sums_16[1])),
356 _mm256_cvtepu16_epi32(_mm256_extractf128_si256(sums_16[1], 1)));
357 sums_32[2] = _mm256_add_epi32(
358 _mm256_cvtepu16_epi32(_mm256_castsi256_si128(sums_16[2])),
359 _mm256_cvtepu16_epi32(_mm256_extractf128_si256(sums_16[2], 1)));
360 sums_32[3] = _mm256_add_epi32(
361 _mm256_cvtepu16_epi32(_mm256_castsi256_si128(sums_16[3])),
362 _mm256_cvtepu16_epi32(_mm256_extractf128_si256(sums_16[3], 1)));
363 calc_final_4(sums_32, sad_array);
364 }
365 }
366
vpx_highbd_sad16x8x4d_avx2(const uint8_t * src_ptr,int src_stride,const uint8_t * const ref_array[4],int ref_stride,uint32_t sad_array[4])367 void vpx_highbd_sad16x8x4d_avx2(const uint8_t *src_ptr, int src_stride,
368 const uint8_t *const ref_array[4],
369 int ref_stride, uint32_t sad_array[4]) {
370 const uint16_t *src = CONVERT_TO_SHORTPTR(src_ptr);
371 uint16_t *refs[4];
372 __m256i sums_16[4];
373
374 refs[0] = CONVERT_TO_SHORTPTR(ref_array[0]);
375 refs[1] = CONVERT_TO_SHORTPTR(ref_array[1]);
376 refs[2] = CONVERT_TO_SHORTPTR(ref_array[2]);
377 refs[3] = CONVERT_TO_SHORTPTR(ref_array[3]);
378 sums_16[0] = _mm256_setzero_si256();
379 sums_16[1] = _mm256_setzero_si256();
380 sums_16[2] = _mm256_setzero_si256();
381 sums_16[3] = _mm256_setzero_si256();
382
383 highbd_sad16xHx4d(sums_16, src, src_stride, refs, ref_stride, 8);
384
385 {
386 __m256i sums_32[4];
387 sums_32[0] = _mm256_add_epi32(
388 _mm256_cvtepu16_epi32(_mm256_castsi256_si128(sums_16[0])),
389 _mm256_cvtepu16_epi32(_mm256_extractf128_si256(sums_16[0], 1)));
390 sums_32[1] = _mm256_add_epi32(
391 _mm256_cvtepu16_epi32(_mm256_castsi256_si128(sums_16[1])),
392 _mm256_cvtepu16_epi32(_mm256_extractf128_si256(sums_16[1], 1)));
393 sums_32[2] = _mm256_add_epi32(
394 _mm256_cvtepu16_epi32(_mm256_castsi256_si128(sums_16[2])),
395 _mm256_cvtepu16_epi32(_mm256_extractf128_si256(sums_16[2], 1)));
396 sums_32[3] = _mm256_add_epi32(
397 _mm256_cvtepu16_epi32(_mm256_castsi256_si128(sums_16[3])),
398 _mm256_cvtepu16_epi32(_mm256_extractf128_si256(sums_16[3], 1)));
399 calc_final_4(sums_32, sad_array);
400 }
401 }
402