• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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