xref: /aosp_15_r20/external/libvpx/test/convolve_test.cc (revision fb1b10ab9aebc7c7068eedab379b749d7e3900be)
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 <string.h>
12 #include <tuple>
13 
14 #include "gtest/gtest.h"
15 
16 #include "./vp9_rtcd.h"
17 #include "./vpx_config.h"
18 #include "./vpx_dsp_rtcd.h"
19 #include "test/acm_random.h"
20 #include "test/clear_system_state.h"
21 #include "test/register_state_check.h"
22 #include "test/util.h"
23 #include "vp9/common/vp9_common.h"
24 #include "vp9/common/vp9_filter.h"
25 #include "vpx_dsp/vpx_dsp_common.h"
26 #include "vpx_dsp/vpx_filter.h"
27 #include "vpx_mem/vpx_mem.h"
28 #include "vpx_ports/mem.h"
29 #include "vpx_ports/vpx_timer.h"
30 
31 namespace {
32 
33 static const unsigned int kMaxDimension = 64;
34 
35 typedef void (*ConvolveFunc)(const uint8_t *src, ptrdiff_t src_stride,
36                              uint8_t *dst, ptrdiff_t dst_stride,
37                              const InterpKernel *filter, int x0_q4,
38                              int x_step_q4, int y0_q4, int y_step_q4, int w,
39                              int h);
40 
41 typedef void (*WrapperFilterBlock2d8Func)(
42     const uint8_t *src_ptr, const unsigned int src_stride,
43     const int16_t *hfilter, const int16_t *vfilter, uint8_t *dst_ptr,
44     unsigned int dst_stride, unsigned int output_width,
45     unsigned int output_height, int use_highbd);
46 
47 struct ConvolveFunctions {
ConvolveFunctions__anon7a986e190111::ConvolveFunctions48   ConvolveFunctions(ConvolveFunc copy, ConvolveFunc avg, ConvolveFunc h8,
49                     ConvolveFunc h8_avg, ConvolveFunc v8, ConvolveFunc v8_avg,
50                     ConvolveFunc hv8, ConvolveFunc hv8_avg, ConvolveFunc sh8,
51                     ConvolveFunc sh8_avg, ConvolveFunc sv8,
52                     ConvolveFunc sv8_avg, ConvolveFunc shv8,
53                     ConvolveFunc shv8_avg, int bd)
54       : use_highbd_(bd) {
55     copy_[0] = copy;
56     copy_[1] = avg;
57     h8_[0] = h8;
58     h8_[1] = h8_avg;
59     v8_[0] = v8;
60     v8_[1] = v8_avg;
61     hv8_[0] = hv8;
62     hv8_[1] = hv8_avg;
63     sh8_[0] = sh8;
64     sh8_[1] = sh8_avg;
65     sv8_[0] = sv8;
66     sv8_[1] = sv8_avg;
67     shv8_[0] = shv8;
68     shv8_[1] = shv8_avg;
69   }
70 
71   ConvolveFunc copy_[2];
72   ConvolveFunc h8_[2];
73   ConvolveFunc v8_[2];
74   ConvolveFunc hv8_[2];
75   ConvolveFunc sh8_[2];   // scaled horiz
76   ConvolveFunc sv8_[2];   // scaled vert
77   ConvolveFunc shv8_[2];  // scaled horiz/vert
78   int use_highbd_;  // 0 if high bitdepth not used, else the actual bit depth.
79 };
80 
81 typedef std::tuple<int, int, const ConvolveFunctions *> ConvolveParam;
82 
83 #define ALL_SIZES(convolve_fn)                                            \
84   make_tuple(4, 4, &convolve_fn), make_tuple(8, 4, &convolve_fn),         \
85       make_tuple(4, 8, &convolve_fn), make_tuple(8, 8, &convolve_fn),     \
86       make_tuple(16, 8, &convolve_fn), make_tuple(8, 16, &convolve_fn),   \
87       make_tuple(16, 16, &convolve_fn), make_tuple(32, 16, &convolve_fn), \
88       make_tuple(16, 32, &convolve_fn), make_tuple(32, 32, &convolve_fn), \
89       make_tuple(64, 32, &convolve_fn), make_tuple(32, 64, &convolve_fn), \
90       make_tuple(64, 64, &convolve_fn)
91 
92 // Reference 8-tap subpixel filter, slightly modified to fit into this test.
93 #define VP9_FILTER_WEIGHT 128
94 #define VP9_FILTER_SHIFT 7
clip_pixel(int x)95 uint8_t clip_pixel(int x) { return x < 0 ? 0 : x > 255 ? 255 : x; }
96 
filter_block2d_8_c(const uint8_t * src_ptr,const unsigned int src_stride,const int16_t * hfilter,const int16_t * vfilter,uint8_t * dst_ptr,unsigned int dst_stride,unsigned int output_width,unsigned int output_height)97 void filter_block2d_8_c(const uint8_t *src_ptr, const unsigned int src_stride,
98                         const int16_t *hfilter, const int16_t *vfilter,
99                         uint8_t *dst_ptr, unsigned int dst_stride,
100                         unsigned int output_width, unsigned int output_height) {
101   // Between passes, we use an intermediate buffer whose height is extended to
102   // have enough horizontally filtered values as input for the vertical pass.
103   // This buffer is allocated to be big enough for the largest block type we
104   // support.
105   const int kInterp_Extend = 4;
106   const unsigned int intermediate_height =
107       (kInterp_Extend - 1) + output_height + kInterp_Extend;
108   unsigned int i, j;
109 
110   // Size of intermediate_buffer is max_intermediate_height * filter_max_width,
111   // where max_intermediate_height = (kInterp_Extend - 1) + filter_max_height
112   //                                 + kInterp_Extend
113   //                               = 3 + 16 + 4
114   //                               = 23
115   // and filter_max_width          = 16
116   //
117   uint8_t intermediate_buffer[71 * kMaxDimension];
118   vp9_zero(intermediate_buffer);
119   const int intermediate_next_stride =
120       1 - static_cast<int>(intermediate_height * output_width);
121 
122   // Horizontal pass (src -> transposed intermediate).
123   uint8_t *output_ptr = intermediate_buffer;
124   const int src_next_row_stride = src_stride - output_width;
125   src_ptr -= (kInterp_Extend - 1) * src_stride + (kInterp_Extend - 1);
126   for (i = 0; i < intermediate_height; ++i) {
127     for (j = 0; j < output_width; ++j) {
128       // Apply filter...
129       const int temp = (src_ptr[0] * hfilter[0]) + (src_ptr[1] * hfilter[1]) +
130                        (src_ptr[2] * hfilter[2]) + (src_ptr[3] * hfilter[3]) +
131                        (src_ptr[4] * hfilter[4]) + (src_ptr[5] * hfilter[5]) +
132                        (src_ptr[6] * hfilter[6]) + (src_ptr[7] * hfilter[7]) +
133                        (VP9_FILTER_WEIGHT >> 1);  // Rounding
134 
135       // Normalize back to 0-255...
136       *output_ptr = clip_pixel(temp >> VP9_FILTER_SHIFT);
137       ++src_ptr;
138       output_ptr += intermediate_height;
139     }
140     src_ptr += src_next_row_stride;
141     output_ptr += intermediate_next_stride;
142   }
143 
144   // Vertical pass (transposed intermediate -> dst).
145   src_ptr = intermediate_buffer;
146   const int dst_next_row_stride = dst_stride - output_width;
147   for (i = 0; i < output_height; ++i) {
148     for (j = 0; j < output_width; ++j) {
149       // Apply filter...
150       const int temp = (src_ptr[0] * vfilter[0]) + (src_ptr[1] * vfilter[1]) +
151                        (src_ptr[2] * vfilter[2]) + (src_ptr[3] * vfilter[3]) +
152                        (src_ptr[4] * vfilter[4]) + (src_ptr[5] * vfilter[5]) +
153                        (src_ptr[6] * vfilter[6]) + (src_ptr[7] * vfilter[7]) +
154                        (VP9_FILTER_WEIGHT >> 1);  // Rounding
155 
156       // Normalize back to 0-255...
157       *dst_ptr++ = clip_pixel(temp >> VP9_FILTER_SHIFT);
158       src_ptr += intermediate_height;
159     }
160     src_ptr += intermediate_next_stride;
161     dst_ptr += dst_next_row_stride;
162   }
163 }
164 
block2d_average_c(uint8_t * src,unsigned int src_stride,uint8_t * output_ptr,unsigned int output_stride,unsigned int output_width,unsigned int output_height)165 void block2d_average_c(uint8_t *src, unsigned int src_stride,
166                        uint8_t *output_ptr, unsigned int output_stride,
167                        unsigned int output_width, unsigned int output_height) {
168   unsigned int i, j;
169   for (i = 0; i < output_height; ++i) {
170     for (j = 0; j < output_width; ++j) {
171       output_ptr[j] = (output_ptr[j] + src[i * src_stride + j] + 1) >> 1;
172     }
173     output_ptr += output_stride;
174   }
175 }
176 
filter_average_block2d_8_c(const uint8_t * src_ptr,const unsigned int src_stride,const int16_t * hfilter,const int16_t * vfilter,uint8_t * dst_ptr,unsigned int dst_stride,unsigned int output_width,unsigned int output_height)177 void filter_average_block2d_8_c(const uint8_t *src_ptr,
178                                 const unsigned int src_stride,
179                                 const int16_t *hfilter, const int16_t *vfilter,
180                                 uint8_t *dst_ptr, unsigned int dst_stride,
181                                 unsigned int output_width,
182                                 unsigned int output_height) {
183   uint8_t tmp[kMaxDimension * kMaxDimension];
184 
185   assert(output_width <= kMaxDimension);
186   assert(output_height <= kMaxDimension);
187   filter_block2d_8_c(src_ptr, src_stride, hfilter, vfilter, tmp, 64,
188                      output_width, output_height);
189   block2d_average_c(tmp, 64, dst_ptr, dst_stride, output_width, output_height);
190 }
191 
192 #if CONFIG_VP9_HIGHBITDEPTH
highbd_filter_block2d_8_c(const uint16_t * src_ptr,const unsigned int src_stride,const int16_t * hfilter,const int16_t * vfilter,uint16_t * dst_ptr,unsigned int dst_stride,unsigned int output_width,unsigned int output_height,int bd)193 void highbd_filter_block2d_8_c(const uint16_t *src_ptr,
194                                const unsigned int src_stride,
195                                const int16_t *hfilter, const int16_t *vfilter,
196                                uint16_t *dst_ptr, unsigned int dst_stride,
197                                unsigned int output_width,
198                                unsigned int output_height, int bd) {
199   // Between passes, we use an intermediate buffer whose height is extended to
200   // have enough horizontally filtered values as input for the vertical pass.
201   // This buffer is allocated to be big enough for the largest block type we
202   // support.
203   const int kInterp_Extend = 4;
204   const unsigned int intermediate_height =
205       (kInterp_Extend - 1) + output_height + kInterp_Extend;
206 
207   /* Size of intermediate_buffer is max_intermediate_height * filter_max_width,
208    * where max_intermediate_height = (kInterp_Extend - 1) + filter_max_height
209    *                                 + kInterp_Extend
210    *                               = 3 + 16 + 4
211    *                               = 23
212    * and filter_max_width = 16
213    */
214   uint16_t intermediate_buffer[71 * kMaxDimension];
215   const int intermediate_next_stride =
216       1 - static_cast<int>(intermediate_height * output_width);
217 
218   vp9_zero(intermediate_buffer);
219 
220   // Horizontal pass (src -> transposed intermediate).
221   {
222     uint16_t *output_ptr = intermediate_buffer;
223     const int src_next_row_stride = src_stride - output_width;
224     unsigned int i, j;
225     src_ptr -= (kInterp_Extend - 1) * src_stride + (kInterp_Extend - 1);
226     for (i = 0; i < intermediate_height; ++i) {
227       for (j = 0; j < output_width; ++j) {
228         // Apply filter...
229         const int temp = (src_ptr[0] * hfilter[0]) + (src_ptr[1] * hfilter[1]) +
230                          (src_ptr[2] * hfilter[2]) + (src_ptr[3] * hfilter[3]) +
231                          (src_ptr[4] * hfilter[4]) + (src_ptr[5] * hfilter[5]) +
232                          (src_ptr[6] * hfilter[6]) + (src_ptr[7] * hfilter[7]) +
233                          (VP9_FILTER_WEIGHT >> 1);  // Rounding
234 
235         // Normalize back to 0-255...
236         *output_ptr = clip_pixel_highbd(temp >> VP9_FILTER_SHIFT, bd);
237         ++src_ptr;
238         output_ptr += intermediate_height;
239       }
240       src_ptr += src_next_row_stride;
241       output_ptr += intermediate_next_stride;
242     }
243   }
244 
245   // Vertical pass (transposed intermediate -> dst).
246   {
247     src_ptr = intermediate_buffer;
248     const int dst_next_row_stride = dst_stride - output_width;
249     unsigned int i, j;
250     for (i = 0; i < output_height; ++i) {
251       for (j = 0; j < output_width; ++j) {
252         // Apply filter...
253         const int temp = (src_ptr[0] * vfilter[0]) + (src_ptr[1] * vfilter[1]) +
254                          (src_ptr[2] * vfilter[2]) + (src_ptr[3] * vfilter[3]) +
255                          (src_ptr[4] * vfilter[4]) + (src_ptr[5] * vfilter[5]) +
256                          (src_ptr[6] * vfilter[6]) + (src_ptr[7] * vfilter[7]) +
257                          (VP9_FILTER_WEIGHT >> 1);  // Rounding
258 
259         // Normalize back to 0-255...
260         *dst_ptr++ = clip_pixel_highbd(temp >> VP9_FILTER_SHIFT, bd);
261         src_ptr += intermediate_height;
262       }
263       src_ptr += intermediate_next_stride;
264       dst_ptr += dst_next_row_stride;
265     }
266   }
267 }
268 
highbd_block2d_average_c(uint16_t * src,unsigned int src_stride,uint16_t * output_ptr,unsigned int output_stride,unsigned int output_width,unsigned int output_height)269 void highbd_block2d_average_c(uint16_t *src, unsigned int src_stride,
270                               uint16_t *output_ptr, unsigned int output_stride,
271                               unsigned int output_width,
272                               unsigned int output_height) {
273   unsigned int i, j;
274   for (i = 0; i < output_height; ++i) {
275     for (j = 0; j < output_width; ++j) {
276       output_ptr[j] = (output_ptr[j] + src[i * src_stride + j] + 1) >> 1;
277     }
278     output_ptr += output_stride;
279   }
280 }
281 
highbd_filter_average_block2d_8_c(const uint16_t * src_ptr,const unsigned int src_stride,const int16_t * hfilter,const int16_t * vfilter,uint16_t * dst_ptr,unsigned int dst_stride,unsigned int output_width,unsigned int output_height,int bd)282 void highbd_filter_average_block2d_8_c(
283     const uint16_t *src_ptr, const unsigned int src_stride,
284     const int16_t *hfilter, const int16_t *vfilter, uint16_t *dst_ptr,
285     unsigned int dst_stride, unsigned int output_width,
286     unsigned int output_height, int bd) {
287   uint16_t tmp[kMaxDimension * kMaxDimension];
288 
289   assert(output_width <= kMaxDimension);
290   assert(output_height <= kMaxDimension);
291   highbd_filter_block2d_8_c(src_ptr, src_stride, hfilter, vfilter, tmp, 64,
292                             output_width, output_height, bd);
293   highbd_block2d_average_c(tmp, 64, dst_ptr, dst_stride, output_width,
294                            output_height);
295 }
296 #endif  // CONFIG_VP9_HIGHBITDEPTH
297 
wrapper_filter_average_block2d_8_c(const uint8_t * src_ptr,const unsigned int src_stride,const int16_t * hfilter,const int16_t * vfilter,uint8_t * dst_ptr,unsigned int dst_stride,unsigned int output_width,unsigned int output_height,int use_highbd)298 void wrapper_filter_average_block2d_8_c(
299     const uint8_t *src_ptr, const unsigned int src_stride,
300     const int16_t *hfilter, const int16_t *vfilter, uint8_t *dst_ptr,
301     unsigned int dst_stride, unsigned int output_width,
302     unsigned int output_height, int use_highbd) {
303 #if CONFIG_VP9_HIGHBITDEPTH
304   if (use_highbd == 0) {
305     filter_average_block2d_8_c(src_ptr, src_stride, hfilter, vfilter, dst_ptr,
306                                dst_stride, output_width, output_height);
307   } else {
308     highbd_filter_average_block2d_8_c(CAST_TO_SHORTPTR(src_ptr), src_stride,
309                                       hfilter, vfilter,
310                                       CAST_TO_SHORTPTR(dst_ptr), dst_stride,
311                                       output_width, output_height, use_highbd);
312   }
313 #else
314   ASSERT_EQ(0, use_highbd);
315   filter_average_block2d_8_c(src_ptr, src_stride, hfilter, vfilter, dst_ptr,
316                              dst_stride, output_width, output_height);
317 #endif
318 }
319 
wrapper_filter_block2d_8_c(const uint8_t * src_ptr,const unsigned int src_stride,const int16_t * hfilter,const int16_t * vfilter,uint8_t * dst_ptr,unsigned int dst_stride,unsigned int output_width,unsigned int output_height,int use_highbd)320 void wrapper_filter_block2d_8_c(const uint8_t *src_ptr,
321                                 const unsigned int src_stride,
322                                 const int16_t *hfilter, const int16_t *vfilter,
323                                 uint8_t *dst_ptr, unsigned int dst_stride,
324                                 unsigned int output_width,
325                                 unsigned int output_height, int use_highbd) {
326 #if CONFIG_VP9_HIGHBITDEPTH
327   if (use_highbd == 0) {
328     filter_block2d_8_c(src_ptr, src_stride, hfilter, vfilter, dst_ptr,
329                        dst_stride, output_width, output_height);
330   } else {
331     highbd_filter_block2d_8_c(CAST_TO_SHORTPTR(src_ptr), src_stride, hfilter,
332                               vfilter, CAST_TO_SHORTPTR(dst_ptr), dst_stride,
333                               output_width, output_height, use_highbd);
334   }
335 #else
336   ASSERT_EQ(0, use_highbd);
337   filter_block2d_8_c(src_ptr, src_stride, hfilter, vfilter, dst_ptr, dst_stride,
338                      output_width, output_height);
339 #endif
340 }
341 
342 class ConvolveTest : public ::testing::TestWithParam<ConvolveParam> {
343  public:
SetUpTestSuite()344   static void SetUpTestSuite() {
345     // Force input_ to be unaligned, output to be 16 byte aligned.
346     input_ = reinterpret_cast<uint8_t *>(
347                  vpx_memalign(kDataAlignment, kInputBufferSize + 1)) +
348              1;
349     output_ = reinterpret_cast<uint8_t *>(
350         vpx_memalign(kDataAlignment, kOutputBufferSize));
351     output_ref_ = reinterpret_cast<uint8_t *>(
352         vpx_memalign(kDataAlignment, kOutputBufferSize));
353 #if CONFIG_VP9_HIGHBITDEPTH
354     input16_ = reinterpret_cast<uint16_t *>(vpx_memalign(
355                    kDataAlignment, (kInputBufferSize + 1) * sizeof(uint16_t))) +
356                1;
357     output16_ = reinterpret_cast<uint16_t *>(
358         vpx_memalign(kDataAlignment, (kOutputBufferSize) * sizeof(uint16_t)));
359     output16_ref_ = reinterpret_cast<uint16_t *>(
360         vpx_memalign(kDataAlignment, (kOutputBufferSize) * sizeof(uint16_t)));
361 #endif
362   }
363 
TearDown()364   void TearDown() override { libvpx_test::ClearSystemState(); }
365 
TearDownTestSuite()366   static void TearDownTestSuite() {
367     vpx_free(input_ - 1);
368     input_ = nullptr;
369     vpx_free(output_);
370     output_ = nullptr;
371     vpx_free(output_ref_);
372     output_ref_ = nullptr;
373 #if CONFIG_VP9_HIGHBITDEPTH
374     vpx_free(input16_ - 1);
375     input16_ = nullptr;
376     vpx_free(output16_);
377     output16_ = nullptr;
378     vpx_free(output16_ref_);
379     output16_ref_ = nullptr;
380 #endif
381   }
382 
383  protected:
384   static const int kDataAlignment = 16;
385   static const int kOuterBlockSize = 256;
386   static const int kInputStride = kOuterBlockSize;
387   static const int kOutputStride = kOuterBlockSize;
388   static const int kInputBufferSize = kOuterBlockSize * kOuterBlockSize;
389   static const int kOutputBufferSize = kOuterBlockSize * kOuterBlockSize;
390 
Width() const391   int Width() const { return GET_PARAM(0); }
Height() const392   int Height() const { return GET_PARAM(1); }
BorderLeft() const393   int BorderLeft() const {
394     const int center = (kOuterBlockSize - Width()) / 2;
395     return (center + (kDataAlignment - 1)) & ~(kDataAlignment - 1);
396   }
BorderTop() const397   int BorderTop() const { return (kOuterBlockSize - Height()) / 2; }
398 
IsIndexInBorder(int i)399   bool IsIndexInBorder(int i) {
400     return (i < BorderTop() * kOuterBlockSize ||
401             i >= (BorderTop() + Height()) * kOuterBlockSize ||
402             i % kOuterBlockSize < BorderLeft() ||
403             i % kOuterBlockSize >= (BorderLeft() + Width()));
404   }
405 
SetUp()406   void SetUp() override {
407     UUT_ = GET_PARAM(2);
408 #if CONFIG_VP9_HIGHBITDEPTH
409     if (UUT_->use_highbd_ != 0) {
410       mask_ = (1 << UUT_->use_highbd_) - 1;
411     } else {
412       mask_ = 255;
413     }
414 #endif
415     /* Set up guard blocks for an inner block centered in the outer block */
416     for (int i = 0; i < kOutputBufferSize; ++i) {
417       if (IsIndexInBorder(i)) {
418         output_[i] = 255;
419 #if CONFIG_VP9_HIGHBITDEPTH
420         output16_[i] = mask_;
421 #endif
422       } else {
423         output_[i] = 0;
424 #if CONFIG_VP9_HIGHBITDEPTH
425         output16_[i] = 0;
426 #endif
427       }
428     }
429 
430     ::libvpx_test::ACMRandom prng;
431     for (int i = 0; i < kInputBufferSize; ++i) {
432       if (i & 1) {
433         input_[i] = 255;
434 #if CONFIG_VP9_HIGHBITDEPTH
435         input16_[i] = mask_;
436 #endif
437       } else {
438         input_[i] = prng.Rand8Extremes();
439 #if CONFIG_VP9_HIGHBITDEPTH
440         input16_[i] = prng.Rand16() & mask_;
441 #endif
442       }
443     }
444   }
445 
SetConstantInput(int value)446   void SetConstantInput(int value) {
447     memset(input_, value, kInputBufferSize);
448 #if CONFIG_VP9_HIGHBITDEPTH
449     vpx_memset16(input16_, value, kInputBufferSize);
450 #endif
451   }
452 
CopyOutputToRef()453   void CopyOutputToRef() {
454     memcpy(output_ref_, output_, kOutputBufferSize);
455 #if CONFIG_VP9_HIGHBITDEPTH
456     memcpy(output16_ref_, output16_,
457            kOutputBufferSize * sizeof(output16_ref_[0]));
458 #endif
459   }
460 
CheckGuardBlocks()461   void CheckGuardBlocks() {
462     for (int i = 0; i < kOutputBufferSize; ++i) {
463       if (IsIndexInBorder(i)) {
464         EXPECT_EQ(255, output_[i]);
465       }
466     }
467   }
468 
input() const469   uint8_t *input() const {
470     const int offset = BorderTop() * kOuterBlockSize + BorderLeft();
471 #if CONFIG_VP9_HIGHBITDEPTH
472     if (UUT_->use_highbd_ == 0) {
473       return input_ + offset;
474     } else {
475       return CAST_TO_BYTEPTR(input16_ + offset);
476     }
477 #else
478     return input_ + offset;
479 #endif
480   }
481 
output() const482   uint8_t *output() const {
483     const int offset = BorderTop() * kOuterBlockSize + BorderLeft();
484 #if CONFIG_VP9_HIGHBITDEPTH
485     if (UUT_->use_highbd_ == 0) {
486       return output_ + offset;
487     } else {
488       return CAST_TO_BYTEPTR(output16_ + offset);
489     }
490 #else
491     return output_ + offset;
492 #endif
493   }
494 
output_ref() const495   uint8_t *output_ref() const {
496     const int offset = BorderTop() * kOuterBlockSize + BorderLeft();
497 #if CONFIG_VP9_HIGHBITDEPTH
498     if (UUT_->use_highbd_ == 0) {
499       return output_ref_ + offset;
500     } else {
501       return CAST_TO_BYTEPTR(output16_ref_ + offset);
502     }
503 #else
504     return output_ref_ + offset;
505 #endif
506   }
507 
lookup(uint8_t * list,int index) const508   uint16_t lookup(uint8_t *list, int index) const {
509 #if CONFIG_VP9_HIGHBITDEPTH
510     if (UUT_->use_highbd_ == 0) {
511       return list[index];
512     } else {
513       return CAST_TO_SHORTPTR(list)[index];
514     }
515 #else
516     return list[index];
517 #endif
518   }
519 
assign_val(uint8_t * list,int index,uint16_t val) const520   void assign_val(uint8_t *list, int index, uint16_t val) const {
521 #if CONFIG_VP9_HIGHBITDEPTH
522     if (UUT_->use_highbd_ == 0) {
523       list[index] = (uint8_t)val;
524     } else {
525       CAST_TO_SHORTPTR(list)[index] = val;
526     }
527 #else
528     list[index] = (uint8_t)val;
529 #endif
530   }
531 
532   const ConvolveFunctions *UUT_;
533   static uint8_t *input_;
534   static uint8_t *output_;
535   static uint8_t *output_ref_;
536 #if CONFIG_VP9_HIGHBITDEPTH
537   static uint16_t *input16_;
538   static uint16_t *output16_;
539   static uint16_t *output16_ref_;
540   int mask_;
541 #endif
542 };
543 
544 uint8_t *ConvolveTest::input_ = nullptr;
545 uint8_t *ConvolveTest::output_ = nullptr;
546 uint8_t *ConvolveTest::output_ref_ = nullptr;
547 #if CONFIG_VP9_HIGHBITDEPTH
548 uint16_t *ConvolveTest::input16_ = nullptr;
549 uint16_t *ConvolveTest::output16_ = nullptr;
550 uint16_t *ConvolveTest::output16_ref_ = nullptr;
551 #endif
552 
TEST_P(ConvolveTest,GuardBlocks)553 TEST_P(ConvolveTest, GuardBlocks) { CheckGuardBlocks(); }
554 
TEST_P(ConvolveTest,DISABLED_Copy_Speed)555 TEST_P(ConvolveTest, DISABLED_Copy_Speed) {
556   const uint8_t *const in = input();
557   uint8_t *const out = output();
558   const int kNumTests = 5000000;
559   const int width = Width();
560   const int height = Height();
561   vpx_usec_timer timer;
562 
563   vpx_usec_timer_start(&timer);
564   for (int n = 0; n < kNumTests; ++n) {
565     UUT_->copy_[0](in, kInputStride, out, kOutputStride, nullptr, 0, 0, 0, 0,
566                    width, height);
567   }
568   vpx_usec_timer_mark(&timer);
569 
570   const int elapsed_time = static_cast<int>(vpx_usec_timer_elapsed(&timer));
571   printf("convolve_copy_%dx%d_%d: %d us\n", width, height,
572          UUT_->use_highbd_ ? UUT_->use_highbd_ : 8, elapsed_time);
573 }
574 
TEST_P(ConvolveTest,DISABLED_Avg_Speed)575 TEST_P(ConvolveTest, DISABLED_Avg_Speed) {
576   const uint8_t *const in = input();
577   uint8_t *const out = output();
578   const int kNumTests = 5000000;
579   const int width = Width();
580   const int height = Height();
581   vpx_usec_timer timer;
582 
583   vpx_usec_timer_start(&timer);
584   for (int n = 0; n < kNumTests; ++n) {
585     UUT_->copy_[1](in, kInputStride, out, kOutputStride, nullptr, 0, 0, 0, 0,
586                    width, height);
587   }
588   vpx_usec_timer_mark(&timer);
589 
590   const int elapsed_time = static_cast<int>(vpx_usec_timer_elapsed(&timer));
591   printf("convolve_avg_%dx%d_%d: %d us\n", width, height,
592          UUT_->use_highbd_ ? UUT_->use_highbd_ : 8, elapsed_time);
593 }
594 
TEST_P(ConvolveTest,DISABLED_Scale_Speed)595 TEST_P(ConvolveTest, DISABLED_Scale_Speed) {
596   const uint8_t *const in = input();
597   uint8_t *const out = output();
598   const InterpKernel *const eighttap = vp9_filter_kernels[EIGHTTAP];
599   const int kNumTests = 5000000;
600   const int width = Width();
601   const int height = Height();
602   vpx_usec_timer timer;
603 
604   SetConstantInput(127);
605 
606   vpx_usec_timer_start(&timer);
607   for (int n = 0; n < kNumTests; ++n) {
608     UUT_->shv8_[0](in, kInputStride, out, kOutputStride, eighttap, 8, 16, 8, 16,
609                    width, height);
610   }
611   vpx_usec_timer_mark(&timer);
612 
613   const int elapsed_time = static_cast<int>(vpx_usec_timer_elapsed(&timer));
614   printf("convolve_scale_%dx%d_%d: %d us\n", width, height,
615          UUT_->use_highbd_ ? UUT_->use_highbd_ : 8, elapsed_time);
616 }
617 
TEST_P(ConvolveTest,DISABLED_8Tap_Speed)618 TEST_P(ConvolveTest, DISABLED_8Tap_Speed) {
619   const uint8_t *const in = input();
620   uint8_t *const out = output();
621   const InterpKernel *const eighttap = vp9_filter_kernels[EIGHTTAP_SHARP];
622   const int kNumTests = 5000000;
623   const int width = Width();
624   const int height = Height();
625   vpx_usec_timer timer;
626 
627   SetConstantInput(127);
628 
629   vpx_usec_timer_start(&timer);
630   for (int n = 0; n < kNumTests; ++n) {
631     UUT_->hv8_[0](in, kInputStride, out, kOutputStride, eighttap, 8, 16, 8, 16,
632                   width, height);
633   }
634   vpx_usec_timer_mark(&timer);
635 
636   const int elapsed_time = static_cast<int>(vpx_usec_timer_elapsed(&timer));
637   printf("convolve8_%dx%d_%d: %d us\n", width, height,
638          UUT_->use_highbd_ ? UUT_->use_highbd_ : 8, elapsed_time);
639 }
640 
TEST_P(ConvolveTest,DISABLED_8Tap_Horiz_Speed)641 TEST_P(ConvolveTest, DISABLED_8Tap_Horiz_Speed) {
642   const uint8_t *const in = input();
643   uint8_t *const out = output();
644   const InterpKernel *const eighttap = vp9_filter_kernels[EIGHTTAP_SHARP];
645   const int kNumTests = 5000000;
646   const int width = Width();
647   const int height = Height();
648   vpx_usec_timer timer;
649 
650   SetConstantInput(127);
651 
652   vpx_usec_timer_start(&timer);
653   for (int n = 0; n < kNumTests; ++n) {
654     UUT_->h8_[0](in, kInputStride, out, kOutputStride, eighttap, 8, 16, 8, 16,
655                  width, height);
656   }
657   vpx_usec_timer_mark(&timer);
658 
659   const int elapsed_time = static_cast<int>(vpx_usec_timer_elapsed(&timer));
660   printf("convolve8_horiz_%dx%d_%d: %d us\n", width, height,
661          UUT_->use_highbd_ ? UUT_->use_highbd_ : 8, elapsed_time);
662 }
663 
TEST_P(ConvolveTest,DISABLED_8Tap_Vert_Speed)664 TEST_P(ConvolveTest, DISABLED_8Tap_Vert_Speed) {
665   const uint8_t *const in = input();
666   uint8_t *const out = output();
667   const InterpKernel *const eighttap = vp9_filter_kernels[EIGHTTAP_SHARP];
668   const int kNumTests = 5000000;
669   const int width = Width();
670   const int height = Height();
671   vpx_usec_timer timer;
672 
673   SetConstantInput(127);
674 
675   vpx_usec_timer_start(&timer);
676   for (int n = 0; n < kNumTests; ++n) {
677     UUT_->v8_[0](in, kInputStride, out, kOutputStride, eighttap, 8, 16, 8, 16,
678                  width, height);
679   }
680   vpx_usec_timer_mark(&timer);
681 
682   const int elapsed_time = static_cast<int>(vpx_usec_timer_elapsed(&timer));
683   printf("convolve8_vert_%dx%d_%d: %d us\n", width, height,
684          UUT_->use_highbd_ ? UUT_->use_highbd_ : 8, elapsed_time);
685 }
686 
TEST_P(ConvolveTest,DISABLED_4Tap_Speed)687 TEST_P(ConvolveTest, DISABLED_4Tap_Speed) {
688   const uint8_t *const in = input();
689   uint8_t *const out = output();
690   const InterpKernel *const fourtap = vp9_filter_kernels[FOURTAP];
691   const int kNumTests = 5000000;
692   const int width = Width();
693   const int height = Height();
694   vpx_usec_timer timer;
695 
696   SetConstantInput(127);
697 
698   vpx_usec_timer_start(&timer);
699   for (int n = 0; n < kNumTests; ++n) {
700     UUT_->hv8_[0](in, kInputStride, out, kOutputStride, fourtap, 8, 16, 8, 16,
701                   width, height);
702   }
703   vpx_usec_timer_mark(&timer);
704 
705   const int elapsed_time = static_cast<int>(vpx_usec_timer_elapsed(&timer));
706   printf("convolve4_%dx%d_%d: %d us\n", width, height,
707          UUT_->use_highbd_ ? UUT_->use_highbd_ : 8, elapsed_time);
708 }
709 
TEST_P(ConvolveTest,DISABLED_4Tap_Horiz_Speed)710 TEST_P(ConvolveTest, DISABLED_4Tap_Horiz_Speed) {
711   const uint8_t *const in = input();
712   uint8_t *const out = output();
713   const InterpKernel *const fourtap = vp9_filter_kernels[FOURTAP];
714   const int kNumTests = 5000000;
715   const int width = Width();
716   const int height = Height();
717   vpx_usec_timer timer;
718 
719   SetConstantInput(127);
720 
721   vpx_usec_timer_start(&timer);
722   for (int n = 0; n < kNumTests; ++n) {
723     UUT_->h8_[0](in, kInputStride, out, kOutputStride, fourtap, 8, 16, 8, 16,
724                  width, height);
725   }
726   vpx_usec_timer_mark(&timer);
727 
728   const int elapsed_time = static_cast<int>(vpx_usec_timer_elapsed(&timer));
729   printf("convolve4_horiz_%dx%d_%d: %d us\n", width, height,
730          UUT_->use_highbd_ ? UUT_->use_highbd_ : 8, elapsed_time);
731 }
732 
TEST_P(ConvolveTest,DISABLED_4Tap_Vert_Speed)733 TEST_P(ConvolveTest, DISABLED_4Tap_Vert_Speed) {
734   const uint8_t *const in = input();
735   uint8_t *const out = output();
736   const InterpKernel *const fourtap = vp9_filter_kernels[FOURTAP];
737   const int kNumTests = 5000000;
738   const int width = Width();
739   const int height = Height();
740   vpx_usec_timer timer;
741 
742   SetConstantInput(127);
743 
744   vpx_usec_timer_start(&timer);
745   for (int n = 0; n < kNumTests; ++n) {
746     UUT_->v8_[0](in, kInputStride, out, kOutputStride, fourtap, 8, 16, 8, 16,
747                  width, height);
748   }
749   vpx_usec_timer_mark(&timer);
750 
751   const int elapsed_time = static_cast<int>(vpx_usec_timer_elapsed(&timer));
752   printf("convolve4_vert_%dx%d_%d: %d us\n", width, height,
753          UUT_->use_highbd_ ? UUT_->use_highbd_ : 8, elapsed_time);
754 }
TEST_P(ConvolveTest,DISABLED_8Tap_Avg_Speed)755 TEST_P(ConvolveTest, DISABLED_8Tap_Avg_Speed) {
756   const uint8_t *const in = input();
757   uint8_t *const out = output();
758   const InterpKernel *const eighttap = vp9_filter_kernels[EIGHTTAP_SHARP];
759   const int kNumTests = 5000000;
760   const int width = Width();
761   const int height = Height();
762   vpx_usec_timer timer;
763 
764   SetConstantInput(127);
765 
766   vpx_usec_timer_start(&timer);
767   for (int n = 0; n < kNumTests; ++n) {
768     UUT_->hv8_[1](in, kInputStride, out, kOutputStride, eighttap, 8, 16, 8, 16,
769                   width, height);
770   }
771   vpx_usec_timer_mark(&timer);
772 
773   const int elapsed_time = static_cast<int>(vpx_usec_timer_elapsed(&timer));
774   printf("convolve8_avg_%dx%d_%d: %d us\n", width, height,
775          UUT_->use_highbd_ ? UUT_->use_highbd_ : 8, elapsed_time);
776 }
777 
TEST_P(ConvolveTest,Copy)778 TEST_P(ConvolveTest, Copy) {
779   uint8_t *const in = input();
780   uint8_t *const out = output();
781 
782   ASM_REGISTER_STATE_CHECK(UUT_->copy_[0](in, kInputStride, out, kOutputStride,
783                                           nullptr, 0, 0, 0, 0, Width(),
784                                           Height()));
785 
786   CheckGuardBlocks();
787 
788   for (int y = 0; y < Height(); ++y) {
789     for (int x = 0; x < Width(); ++x)
790       ASSERT_EQ(lookup(out, y * kOutputStride + x),
791                 lookup(in, y * kInputStride + x))
792           << "(" << x << "," << y << ")";
793   }
794 }
795 
TEST_P(ConvolveTest,Avg)796 TEST_P(ConvolveTest, Avg) {
797   uint8_t *const in = input();
798   uint8_t *const out = output();
799   uint8_t *const out_ref = output_ref();
800   CopyOutputToRef();
801 
802   ASM_REGISTER_STATE_CHECK(UUT_->copy_[1](in, kInputStride, out, kOutputStride,
803                                           nullptr, 0, 0, 0, 0, Width(),
804                                           Height()));
805 
806   CheckGuardBlocks();
807 
808   for (int y = 0; y < Height(); ++y) {
809     for (int x = 0; x < Width(); ++x)
810       ASSERT_EQ(lookup(out, y * kOutputStride + x),
811                 ROUND_POWER_OF_TWO(lookup(in, y * kInputStride + x) +
812                                        lookup(out_ref, y * kOutputStride + x),
813                                    1))
814           << "(" << x << "," << y << ")";
815   }
816 }
817 
TEST_P(ConvolveTest,CopyHoriz)818 TEST_P(ConvolveTest, CopyHoriz) {
819   uint8_t *const in = input();
820   uint8_t *const out = output();
821 
822   ASM_REGISTER_STATE_CHECK(UUT_->sh8_[0](in, kInputStride, out, kOutputStride,
823                                          vp9_filter_kernels[0], 0, 16, 0, 16,
824                                          Width(), Height()));
825 
826   CheckGuardBlocks();
827 
828   for (int y = 0; y < Height(); ++y) {
829     for (int x = 0; x < Width(); ++x)
830       ASSERT_EQ(lookup(out, y * kOutputStride + x),
831                 lookup(in, y * kInputStride + x))
832           << "(" << x << "," << y << ")";
833   }
834 }
835 
TEST_P(ConvolveTest,CopyVert)836 TEST_P(ConvolveTest, CopyVert) {
837   uint8_t *const in = input();
838   uint8_t *const out = output();
839 
840   ASM_REGISTER_STATE_CHECK(UUT_->sv8_[0](in, kInputStride, out, kOutputStride,
841                                          vp9_filter_kernels[0], 0, 16, 0, 16,
842                                          Width(), Height()));
843 
844   CheckGuardBlocks();
845 
846   for (int y = 0; y < Height(); ++y) {
847     for (int x = 0; x < Width(); ++x)
848       ASSERT_EQ(lookup(out, y * kOutputStride + x),
849                 lookup(in, y * kInputStride + x))
850           << "(" << x << "," << y << ")";
851   }
852 }
853 
TEST_P(ConvolveTest,Copy2D)854 TEST_P(ConvolveTest, Copy2D) {
855   uint8_t *const in = input();
856   uint8_t *const out = output();
857 
858   ASM_REGISTER_STATE_CHECK(UUT_->shv8_[0](in, kInputStride, out, kOutputStride,
859                                           vp9_filter_kernels[0], 0, 16, 0, 16,
860                                           Width(), Height()));
861 
862   CheckGuardBlocks();
863 
864   for (int y = 0; y < Height(); ++y) {
865     for (int x = 0; x < Width(); ++x)
866       ASSERT_EQ(lookup(out, y * kOutputStride + x),
867                 lookup(in, y * kInputStride + x))
868           << "(" << x << "," << y << ")";
869   }
870 }
871 
872 const int kNumFilterBanks = 5;
873 const int kNumFilters = 16;
874 
TEST(ConvolveTest,FiltersWontSaturateWhenAddedPairwise)875 TEST(ConvolveTest, FiltersWontSaturateWhenAddedPairwise) {
876   for (int filter_bank = 0; filter_bank < kNumFilterBanks; ++filter_bank) {
877     const InterpKernel *filters =
878         vp9_filter_kernels[static_cast<INTERP_FILTER>(filter_bank)];
879     for (int i = 0; i < kNumFilters; i++) {
880       const int p0 = filters[i][0] + filters[i][1];
881       const int p1 = filters[i][2] + filters[i][3];
882       const int p2 = filters[i][4] + filters[i][5];
883       const int p3 = filters[i][6] + filters[i][7];
884       EXPECT_LE(p0, 128);
885       EXPECT_LE(p1, 128);
886       EXPECT_LE(p2, 128);
887       EXPECT_LE(p3, 128);
888       EXPECT_LE(p0 + p3, 128);
889       EXPECT_LE(p0 + p3 + p1, 128);
890       EXPECT_LE(p0 + p3 + p1 + p2, 128);
891       EXPECT_EQ(p0 + p1 + p2 + p3, 128);
892     }
893   }
894 }
895 
896 const WrapperFilterBlock2d8Func wrapper_filter_block2d_8[2] = {
897   wrapper_filter_block2d_8_c, wrapper_filter_average_block2d_8_c
898 };
899 
TEST_P(ConvolveTest,MatchesReferenceSubpixelFilter)900 TEST_P(ConvolveTest, MatchesReferenceSubpixelFilter) {
901   for (int i = 0; i < 2; ++i) {
902     uint8_t *const in = input();
903     uint8_t *const out = output();
904 #if CONFIG_VP9_HIGHBITDEPTH
905     uint8_t ref8[kOutputStride * kMaxDimension];
906     uint16_t ref16[kOutputStride * kMaxDimension];
907     uint8_t *ref;
908     if (UUT_->use_highbd_ == 0) {
909       ref = ref8;
910     } else {
911       ref = CAST_TO_BYTEPTR(ref16);
912     }
913 #else
914     uint8_t ref[kOutputStride * kMaxDimension];
915 #endif
916 
917     // Populate ref and out with some random data
918     ::libvpx_test::ACMRandom prng;
919     for (int y = 0; y < Height(); ++y) {
920       for (int x = 0; x < Width(); ++x) {
921         uint16_t r;
922 #if CONFIG_VP9_HIGHBITDEPTH
923         if (UUT_->use_highbd_ == 0 || UUT_->use_highbd_ == 8) {
924           r = prng.Rand8Extremes();
925         } else {
926           r = prng.Rand16() & mask_;
927         }
928 #else
929         r = prng.Rand8Extremes();
930 #endif
931 
932         assign_val(out, y * kOutputStride + x, r);
933         assign_val(ref, y * kOutputStride + x, r);
934       }
935     }
936 
937     for (int filter_bank = 0; filter_bank < kNumFilterBanks; ++filter_bank) {
938       const InterpKernel *filters =
939           vp9_filter_kernels[static_cast<INTERP_FILTER>(filter_bank)];
940 
941       for (int filter_x = 0; filter_x < kNumFilters; ++filter_x) {
942         for (int filter_y = 0; filter_y < kNumFilters; ++filter_y) {
943           wrapper_filter_block2d_8[i](in, kInputStride, filters[filter_x],
944                                       filters[filter_y], ref, kOutputStride,
945                                       Width(), Height(), UUT_->use_highbd_);
946 
947           if (filter_x && filter_y)
948             ASM_REGISTER_STATE_CHECK(
949                 UUT_->hv8_[i](in, kInputStride, out, kOutputStride, filters,
950                               filter_x, 16, filter_y, 16, Width(), Height()));
951           else if (filter_y)
952             ASM_REGISTER_STATE_CHECK(
953                 UUT_->v8_[i](in, kInputStride, out, kOutputStride, filters, 0,
954                              16, filter_y, 16, Width(), Height()));
955           else if (filter_x)
956             ASM_REGISTER_STATE_CHECK(
957                 UUT_->h8_[i](in, kInputStride, out, kOutputStride, filters,
958                              filter_x, 16, 0, 16, Width(), Height()));
959           else
960             ASM_REGISTER_STATE_CHECK(
961                 UUT_->copy_[i](in, kInputStride, out, kOutputStride, nullptr, 0,
962                                0, 0, 0, Width(), Height()));
963 
964           CheckGuardBlocks();
965 
966           for (int y = 0; y < Height(); ++y) {
967             for (int x = 0; x < Width(); ++x)
968               ASSERT_EQ(lookup(ref, y * kOutputStride + x),
969                         lookup(out, y * kOutputStride + x))
970                   << "mismatch at (" << x << "," << y << "), "
971                   << "filters (" << filter_bank << "," << filter_x << ","
972                   << filter_y << ")";
973           }
974         }
975       }
976     }
977   }
978 }
979 
TEST_P(ConvolveTest,FilterExtremes)980 TEST_P(ConvolveTest, FilterExtremes) {
981   uint8_t *const in = input();
982   uint8_t *const out = output();
983 #if CONFIG_VP9_HIGHBITDEPTH
984   uint8_t ref8[kOutputStride * kMaxDimension];
985   uint16_t ref16[kOutputStride * kMaxDimension];
986   uint8_t *ref;
987   if (UUT_->use_highbd_ == 0) {
988     ref = ref8;
989   } else {
990     ref = CAST_TO_BYTEPTR(ref16);
991   }
992 #else
993   uint8_t ref[kOutputStride * kMaxDimension];
994 #endif
995 
996   // Populate ref and out with some random data
997   ::libvpx_test::ACMRandom prng;
998   for (int y = 0; y < Height(); ++y) {
999     for (int x = 0; x < Width(); ++x) {
1000       uint16_t r;
1001 #if CONFIG_VP9_HIGHBITDEPTH
1002       if (UUT_->use_highbd_ == 0 || UUT_->use_highbd_ == 8) {
1003         r = prng.Rand8Extremes();
1004       } else {
1005         r = prng.Rand16() & mask_;
1006       }
1007 #else
1008       r = prng.Rand8Extremes();
1009 #endif
1010       assign_val(out, y * kOutputStride + x, r);
1011       assign_val(ref, y * kOutputStride + x, r);
1012     }
1013   }
1014 
1015   for (int axis = 0; axis < 2; axis++) {
1016     int seed_val = 0;
1017     while (seed_val < 256) {
1018       for (int y = 0; y < 8; ++y) {
1019         for (int x = 0; x < 8; ++x) {
1020 #if CONFIG_VP9_HIGHBITDEPTH
1021           assign_val(in, y * kOutputStride + x - SUBPEL_TAPS / 2 + 1,
1022                      ((seed_val >> (axis ? y : x)) & 1) * mask_);
1023 #else
1024           assign_val(in, y * kOutputStride + x - SUBPEL_TAPS / 2 + 1,
1025                      ((seed_val >> (axis ? y : x)) & 1) * 255);
1026 #endif
1027           if (axis) seed_val++;
1028         }
1029         if (axis) {
1030           seed_val -= 8;
1031         } else {
1032           seed_val++;
1033         }
1034       }
1035       if (axis) seed_val += 8;
1036 
1037       for (int filter_bank = 0; filter_bank < kNumFilterBanks; ++filter_bank) {
1038         const InterpKernel *filters =
1039             vp9_filter_kernels[static_cast<INTERP_FILTER>(filter_bank)];
1040         for (int filter_x = 0; filter_x < kNumFilters; ++filter_x) {
1041           for (int filter_y = 0; filter_y < kNumFilters; ++filter_y) {
1042             wrapper_filter_block2d_8_c(in, kInputStride, filters[filter_x],
1043                                        filters[filter_y], ref, kOutputStride,
1044                                        Width(), Height(), UUT_->use_highbd_);
1045             if (filter_x && filter_y)
1046               ASM_REGISTER_STATE_CHECK(
1047                   UUT_->hv8_[0](in, kInputStride, out, kOutputStride, filters,
1048                                 filter_x, 16, filter_y, 16, Width(), Height()));
1049             else if (filter_y)
1050               ASM_REGISTER_STATE_CHECK(
1051                   UUT_->v8_[0](in, kInputStride, out, kOutputStride, filters, 0,
1052                                16, filter_y, 16, Width(), Height()));
1053             else if (filter_x)
1054               ASM_REGISTER_STATE_CHECK(
1055                   UUT_->h8_[0](in, kInputStride, out, kOutputStride, filters,
1056                                filter_x, 16, 0, 16, Width(), Height()));
1057             else
1058               ASM_REGISTER_STATE_CHECK(
1059                   UUT_->copy_[0](in, kInputStride, out, kOutputStride, nullptr,
1060                                  0, 0, 0, 0, Width(), Height()));
1061 
1062             for (int y = 0; y < Height(); ++y) {
1063               for (int x = 0; x < Width(); ++x)
1064                 ASSERT_EQ(lookup(ref, y * kOutputStride + x),
1065                           lookup(out, y * kOutputStride + x))
1066                     << "mismatch at (" << x << "," << y << "), "
1067                     << "filters (" << filter_bank << "," << filter_x << ","
1068                     << filter_y << ")";
1069             }
1070           }
1071         }
1072       }
1073     }
1074   }
1075 }
1076 
1077 /* This test exercises that enough rows and columns are filtered with every
1078    possible initial fractional positions and scaling steps. */
1079 #if !CONFIG_VP9_HIGHBITDEPTH
1080 static const ConvolveFunc scaled_2d_c_funcs[2] = { vpx_scaled_2d_c,
1081                                                    vpx_scaled_avg_2d_c };
1082 
TEST_P(ConvolveTest,CheckScalingFiltering)1083 TEST_P(ConvolveTest, CheckScalingFiltering) {
1084   uint8_t *const in = input();
1085   uint8_t *const out = output();
1086   uint8_t ref[kOutputStride * kMaxDimension];
1087 
1088   ::libvpx_test::ACMRandom prng;
1089   for (int y = 0; y < Height(); ++y) {
1090     for (int x = 0; x < Width(); ++x) {
1091       const uint16_t r = prng.Rand8Extremes();
1092       assign_val(in, y * kInputStride + x, r);
1093     }
1094   }
1095 
1096   for (int i = 0; i < 2; ++i) {
1097     for (INTERP_FILTER filter_type = 0; filter_type < 4; ++filter_type) {
1098       const InterpKernel *const eighttap = vp9_filter_kernels[filter_type];
1099       for (int frac = 0; frac < 16; ++frac) {
1100         for (int step = 1; step <= 32; ++step) {
1101           /* Test the horizontal and vertical filters in combination. */
1102           scaled_2d_c_funcs[i](in, kInputStride, ref, kOutputStride, eighttap,
1103                                frac, step, frac, step, Width(), Height());
1104           ASM_REGISTER_STATE_CHECK(
1105               UUT_->shv8_[i](in, kInputStride, out, kOutputStride, eighttap,
1106                              frac, step, frac, step, Width(), Height()));
1107 
1108           CheckGuardBlocks();
1109 
1110           for (int y = 0; y < Height(); ++y) {
1111             for (int x = 0; x < Width(); ++x) {
1112               ASSERT_EQ(lookup(ref, y * kOutputStride + x),
1113                         lookup(out, y * kOutputStride + x))
1114                   << "x == " << x << ", y == " << y << ", frac == " << frac
1115                   << ", step == " << step;
1116             }
1117           }
1118         }
1119       }
1120     }
1121   }
1122 }
1123 #endif
1124 
1125 using std::make_tuple;
1126 
1127 #if CONFIG_VP9_HIGHBITDEPTH
1128 #define WRAP(func, bd)                                                       \
1129   void wrap_##func##_##bd(                                                   \
1130       const uint8_t *src, ptrdiff_t src_stride, uint8_t *dst,                \
1131       ptrdiff_t dst_stride, const InterpKernel *filter, int x0_q4,           \
1132       int x_step_q4, int y0_q4, int y_step_q4, int w, int h) {               \
1133     vpx_highbd_##func(reinterpret_cast<const uint16_t *>(src), src_stride,   \
1134                       reinterpret_cast<uint16_t *>(dst), dst_stride, filter, \
1135                       x0_q4, x_step_q4, y0_q4, y_step_q4, w, h, bd);         \
1136   }
1137 
1138 #if HAVE_SSE2 && VPX_ARCH_X86_64
1139 WRAP(convolve_copy_sse2, 8)
1140 WRAP(convolve_avg_sse2, 8)
1141 WRAP(convolve_copy_sse2, 10)
1142 WRAP(convolve_avg_sse2, 10)
1143 WRAP(convolve_copy_sse2, 12)
1144 WRAP(convolve_avg_sse2, 12)
1145 WRAP(convolve8_horiz_sse2, 8)
1146 WRAP(convolve8_avg_horiz_sse2, 8)
1147 WRAP(convolve8_vert_sse2, 8)
1148 WRAP(convolve8_avg_vert_sse2, 8)
1149 WRAP(convolve8_sse2, 8)
1150 WRAP(convolve8_avg_sse2, 8)
1151 WRAP(convolve8_horiz_sse2, 10)
1152 WRAP(convolve8_avg_horiz_sse2, 10)
1153 WRAP(convolve8_vert_sse2, 10)
1154 WRAP(convolve8_avg_vert_sse2, 10)
1155 WRAP(convolve8_sse2, 10)
1156 WRAP(convolve8_avg_sse2, 10)
1157 WRAP(convolve8_horiz_sse2, 12)
1158 WRAP(convolve8_avg_horiz_sse2, 12)
1159 WRAP(convolve8_vert_sse2, 12)
1160 WRAP(convolve8_avg_vert_sse2, 12)
1161 WRAP(convolve8_sse2, 12)
1162 WRAP(convolve8_avg_sse2, 12)
1163 #endif  // HAVE_SSE2 && VPX_ARCH_X86_64
1164 
1165 #if HAVE_AVX2
1166 WRAP(convolve_copy_avx2, 8)
1167 WRAP(convolve_avg_avx2, 8)
1168 WRAP(convolve8_horiz_avx2, 8)
1169 WRAP(convolve8_avg_horiz_avx2, 8)
1170 WRAP(convolve8_vert_avx2, 8)
1171 WRAP(convolve8_avg_vert_avx2, 8)
1172 WRAP(convolve8_avx2, 8)
1173 WRAP(convolve8_avg_avx2, 8)
1174 
1175 WRAP(convolve_copy_avx2, 10)
1176 WRAP(convolve_avg_avx2, 10)
1177 WRAP(convolve8_avx2, 10)
1178 WRAP(convolve8_horiz_avx2, 10)
1179 WRAP(convolve8_vert_avx2, 10)
1180 WRAP(convolve8_avg_avx2, 10)
1181 WRAP(convolve8_avg_horiz_avx2, 10)
1182 WRAP(convolve8_avg_vert_avx2, 10)
1183 
1184 WRAP(convolve_copy_avx2, 12)
1185 WRAP(convolve_avg_avx2, 12)
1186 WRAP(convolve8_avx2, 12)
1187 WRAP(convolve8_horiz_avx2, 12)
1188 WRAP(convolve8_vert_avx2, 12)
1189 WRAP(convolve8_avg_avx2, 12)
1190 WRAP(convolve8_avg_horiz_avx2, 12)
1191 WRAP(convolve8_avg_vert_avx2, 12)
1192 #endif  // HAVE_AVX2
1193 
1194 #if HAVE_NEON
1195 WRAP(convolve_copy_neon, 8)
1196 WRAP(convolve_avg_neon, 8)
1197 WRAP(convolve_copy_neon, 10)
1198 WRAP(convolve_avg_neon, 10)
1199 WRAP(convolve_copy_neon, 12)
1200 WRAP(convolve_avg_neon, 12)
1201 WRAP(convolve8_horiz_neon, 8)
1202 WRAP(convolve8_avg_horiz_neon, 8)
1203 WRAP(convolve8_vert_neon, 8)
1204 WRAP(convolve8_avg_vert_neon, 8)
1205 WRAP(convolve8_neon, 8)
1206 WRAP(convolve8_avg_neon, 8)
1207 WRAP(convolve8_horiz_neon, 10)
1208 WRAP(convolve8_avg_horiz_neon, 10)
1209 WRAP(convolve8_vert_neon, 10)
1210 WRAP(convolve8_avg_vert_neon, 10)
1211 WRAP(convolve8_neon, 10)
1212 WRAP(convolve8_avg_neon, 10)
1213 WRAP(convolve8_horiz_neon, 12)
1214 WRAP(convolve8_avg_horiz_neon, 12)
1215 WRAP(convolve8_vert_neon, 12)
1216 WRAP(convolve8_avg_vert_neon, 12)
1217 WRAP(convolve8_neon, 12)
1218 WRAP(convolve8_avg_neon, 12)
1219 #endif  // HAVE_NEON
1220 
1221 #if HAVE_SVE
1222 WRAP(convolve8_horiz_sve, 8)
1223 WRAP(convolve8_avg_horiz_sve, 8)
1224 WRAP(convolve8_horiz_sve, 10)
1225 WRAP(convolve8_avg_horiz_sve, 10)
1226 WRAP(convolve8_horiz_sve, 12)
1227 WRAP(convolve8_avg_horiz_sve, 12)
1228 #endif  // HAVE_SVE
1229 
1230 #if HAVE_SVE2
1231 WRAP(convolve8_sve2, 8)
1232 WRAP(convolve8_avg_sve2, 8)
1233 WRAP(convolve8_vert_sve2, 8)
1234 WRAP(convolve8_avg_vert_sve2, 8)
1235 WRAP(convolve8_sve2, 10)
1236 WRAP(convolve8_avg_sve2, 10)
1237 WRAP(convolve8_vert_sve2, 10)
1238 WRAP(convolve8_avg_vert_sve2, 10)
1239 WRAP(convolve8_sve2, 12)
1240 WRAP(convolve8_avg_sve2, 12)
1241 WRAP(convolve8_vert_sve2, 12)
1242 WRAP(convolve8_avg_vert_sve2, 12)
1243 #endif  // HAVE_SVE2
1244 
1245 WRAP(convolve_copy_c, 8)
1246 WRAP(convolve_avg_c, 8)
1247 WRAP(convolve8_horiz_c, 8)
1248 WRAP(convolve8_avg_horiz_c, 8)
1249 WRAP(convolve8_vert_c, 8)
1250 WRAP(convolve8_avg_vert_c, 8)
1251 WRAP(convolve8_c, 8)
1252 WRAP(convolve8_avg_c, 8)
1253 WRAP(convolve_copy_c, 10)
1254 WRAP(convolve_avg_c, 10)
1255 WRAP(convolve8_horiz_c, 10)
1256 WRAP(convolve8_avg_horiz_c, 10)
1257 WRAP(convolve8_vert_c, 10)
1258 WRAP(convolve8_avg_vert_c, 10)
1259 WRAP(convolve8_c, 10)
1260 WRAP(convolve8_avg_c, 10)
1261 WRAP(convolve_copy_c, 12)
1262 WRAP(convolve_avg_c, 12)
1263 WRAP(convolve8_horiz_c, 12)
1264 WRAP(convolve8_avg_horiz_c, 12)
1265 WRAP(convolve8_vert_c, 12)
1266 WRAP(convolve8_avg_vert_c, 12)
1267 WRAP(convolve8_c, 12)
1268 WRAP(convolve8_avg_c, 12)
1269 #undef WRAP
1270 
1271 const ConvolveFunctions convolve8_c(
1272     wrap_convolve_copy_c_8, wrap_convolve_avg_c_8, wrap_convolve8_horiz_c_8,
1273     wrap_convolve8_avg_horiz_c_8, wrap_convolve8_vert_c_8,
1274     wrap_convolve8_avg_vert_c_8, wrap_convolve8_c_8, wrap_convolve8_avg_c_8,
1275     wrap_convolve8_horiz_c_8, wrap_convolve8_avg_horiz_c_8,
1276     wrap_convolve8_vert_c_8, wrap_convolve8_avg_vert_c_8, wrap_convolve8_c_8,
1277     wrap_convolve8_avg_c_8, 8);
1278 const ConvolveFunctions convolve10_c(
1279     wrap_convolve_copy_c_10, wrap_convolve_avg_c_10, wrap_convolve8_horiz_c_10,
1280     wrap_convolve8_avg_horiz_c_10, wrap_convolve8_vert_c_10,
1281     wrap_convolve8_avg_vert_c_10, wrap_convolve8_c_10, wrap_convolve8_avg_c_10,
1282     wrap_convolve8_horiz_c_10, wrap_convolve8_avg_horiz_c_10,
1283     wrap_convolve8_vert_c_10, wrap_convolve8_avg_vert_c_10, wrap_convolve8_c_10,
1284     wrap_convolve8_avg_c_10, 10);
1285 const ConvolveFunctions convolve12_c(
1286     wrap_convolve_copy_c_12, wrap_convolve_avg_c_12, wrap_convolve8_horiz_c_12,
1287     wrap_convolve8_avg_horiz_c_12, wrap_convolve8_vert_c_12,
1288     wrap_convolve8_avg_vert_c_12, wrap_convolve8_c_12, wrap_convolve8_avg_c_12,
1289     wrap_convolve8_horiz_c_12, wrap_convolve8_avg_horiz_c_12,
1290     wrap_convolve8_vert_c_12, wrap_convolve8_avg_vert_c_12, wrap_convolve8_c_12,
1291     wrap_convolve8_avg_c_12, 12);
1292 const ConvolveParam kArrayConvolve_c[] = { ALL_SIZES(convolve8_c),
1293                                            ALL_SIZES(convolve10_c),
1294                                            ALL_SIZES(convolve12_c) };
1295 
1296 #else
1297 const ConvolveFunctions convolve8_c(
1298     vpx_convolve_copy_c, vpx_convolve_avg_c, vpx_convolve8_horiz_c,
1299     vpx_convolve8_avg_horiz_c, vpx_convolve8_vert_c, vpx_convolve8_avg_vert_c,
1300     vpx_convolve8_c, vpx_convolve8_avg_c, vpx_scaled_horiz_c,
1301     vpx_scaled_avg_horiz_c, vpx_scaled_vert_c, vpx_scaled_avg_vert_c,
1302     vpx_scaled_2d_c, vpx_scaled_avg_2d_c, 0);
1303 const ConvolveParam kArrayConvolve_c[] = { ALL_SIZES(convolve8_c) };
1304 #endif
1305 INSTANTIATE_TEST_SUITE_P(C, ConvolveTest,
1306                          ::testing::ValuesIn(kArrayConvolve_c));
1307 
1308 #if HAVE_SSE2 && VPX_ARCH_X86_64
1309 #if CONFIG_VP9_HIGHBITDEPTH
1310 const ConvolveFunctions convolve8_sse2(
1311     wrap_convolve_copy_sse2_8, wrap_convolve_avg_sse2_8,
1312     wrap_convolve8_horiz_sse2_8, wrap_convolve8_avg_horiz_sse2_8,
1313     wrap_convolve8_vert_sse2_8, wrap_convolve8_avg_vert_sse2_8,
1314     wrap_convolve8_sse2_8, wrap_convolve8_avg_sse2_8,
1315     wrap_convolve8_horiz_sse2_8, wrap_convolve8_avg_horiz_sse2_8,
1316     wrap_convolve8_vert_sse2_8, wrap_convolve8_avg_vert_sse2_8,
1317     wrap_convolve8_sse2_8, wrap_convolve8_avg_sse2_8, 8);
1318 const ConvolveFunctions convolve10_sse2(
1319     wrap_convolve_copy_sse2_10, wrap_convolve_avg_sse2_10,
1320     wrap_convolve8_horiz_sse2_10, wrap_convolve8_avg_horiz_sse2_10,
1321     wrap_convolve8_vert_sse2_10, wrap_convolve8_avg_vert_sse2_10,
1322     wrap_convolve8_sse2_10, wrap_convolve8_avg_sse2_10,
1323     wrap_convolve8_horiz_sse2_10, wrap_convolve8_avg_horiz_sse2_10,
1324     wrap_convolve8_vert_sse2_10, wrap_convolve8_avg_vert_sse2_10,
1325     wrap_convolve8_sse2_10, wrap_convolve8_avg_sse2_10, 10);
1326 const ConvolveFunctions convolve12_sse2(
1327     wrap_convolve_copy_sse2_12, wrap_convolve_avg_sse2_12,
1328     wrap_convolve8_horiz_sse2_12, wrap_convolve8_avg_horiz_sse2_12,
1329     wrap_convolve8_vert_sse2_12, wrap_convolve8_avg_vert_sse2_12,
1330     wrap_convolve8_sse2_12, wrap_convolve8_avg_sse2_12,
1331     wrap_convolve8_horiz_sse2_12, wrap_convolve8_avg_horiz_sse2_12,
1332     wrap_convolve8_vert_sse2_12, wrap_convolve8_avg_vert_sse2_12,
1333     wrap_convolve8_sse2_12, wrap_convolve8_avg_sse2_12, 12);
1334 const ConvolveParam kArrayConvolve_sse2[] = { ALL_SIZES(convolve8_sse2),
1335                                               ALL_SIZES(convolve10_sse2),
1336                                               ALL_SIZES(convolve12_sse2) };
1337 #else
1338 const ConvolveFunctions convolve8_sse2(
1339     vpx_convolve_copy_sse2, vpx_convolve_avg_sse2, vpx_convolve8_horiz_sse2,
1340     vpx_convolve8_avg_horiz_sse2, vpx_convolve8_vert_sse2,
1341     vpx_convolve8_avg_vert_sse2, vpx_convolve8_sse2, vpx_convolve8_avg_sse2,
1342     vpx_scaled_horiz_c, vpx_scaled_avg_horiz_c, vpx_scaled_vert_c,
1343     vpx_scaled_avg_vert_c, vpx_scaled_2d_c, vpx_scaled_avg_2d_c, 0);
1344 
1345 const ConvolveParam kArrayConvolve_sse2[] = { ALL_SIZES(convolve8_sse2) };
1346 #endif  // CONFIG_VP9_HIGHBITDEPTH
1347 INSTANTIATE_TEST_SUITE_P(SSE2, ConvolveTest,
1348                          ::testing::ValuesIn(kArrayConvolve_sse2));
1349 #endif
1350 
1351 #if HAVE_SSSE3
1352 const ConvolveFunctions convolve8_ssse3(
1353     vpx_convolve_copy_c, vpx_convolve_avg_c, vpx_convolve8_horiz_ssse3,
1354     vpx_convolve8_avg_horiz_ssse3, vpx_convolve8_vert_ssse3,
1355     vpx_convolve8_avg_vert_ssse3, vpx_convolve8_ssse3, vpx_convolve8_avg_ssse3,
1356     vpx_scaled_horiz_c, vpx_scaled_avg_horiz_c, vpx_scaled_vert_c,
1357     vpx_scaled_avg_vert_c, vpx_scaled_2d_ssse3, vpx_scaled_avg_2d_c, 0);
1358 
1359 const ConvolveParam kArrayConvolve8_ssse3[] = { ALL_SIZES(convolve8_ssse3) };
1360 INSTANTIATE_TEST_SUITE_P(SSSE3, ConvolveTest,
1361                          ::testing::ValuesIn(kArrayConvolve8_ssse3));
1362 #endif
1363 
1364 #if HAVE_AVX2
1365 #if CONFIG_VP9_HIGHBITDEPTH
1366 const ConvolveFunctions convolve8_avx2(
1367     wrap_convolve_copy_avx2_8, wrap_convolve_avg_avx2_8,
1368     wrap_convolve8_horiz_avx2_8, wrap_convolve8_avg_horiz_avx2_8,
1369     wrap_convolve8_vert_avx2_8, wrap_convolve8_avg_vert_avx2_8,
1370     wrap_convolve8_avx2_8, wrap_convolve8_avg_avx2_8, wrap_convolve8_horiz_c_8,
1371     wrap_convolve8_avg_horiz_c_8, wrap_convolve8_vert_c_8,
1372     wrap_convolve8_avg_vert_c_8, wrap_convolve8_c_8, wrap_convolve8_avg_c_8, 8);
1373 const ConvolveFunctions convolve10_avx2(
1374     wrap_convolve_copy_avx2_10, wrap_convolve_avg_avx2_10,
1375     wrap_convolve8_horiz_avx2_10, wrap_convolve8_avg_horiz_avx2_10,
1376     wrap_convolve8_vert_avx2_10, wrap_convolve8_avg_vert_avx2_10,
1377     wrap_convolve8_avx2_10, wrap_convolve8_avg_avx2_10,
1378     wrap_convolve8_horiz_c_10, wrap_convolve8_avg_horiz_c_10,
1379     wrap_convolve8_vert_c_10, wrap_convolve8_avg_vert_c_10, wrap_convolve8_c_10,
1380     wrap_convolve8_avg_c_10, 10);
1381 const ConvolveFunctions convolve12_avx2(
1382     wrap_convolve_copy_avx2_12, wrap_convolve_avg_avx2_12,
1383     wrap_convolve8_horiz_avx2_12, wrap_convolve8_avg_horiz_avx2_12,
1384     wrap_convolve8_vert_avx2_12, wrap_convolve8_avg_vert_avx2_12,
1385     wrap_convolve8_avx2_12, wrap_convolve8_avg_avx2_12,
1386     wrap_convolve8_horiz_c_12, wrap_convolve8_avg_horiz_c_12,
1387     wrap_convolve8_vert_c_12, wrap_convolve8_avg_vert_c_12, wrap_convolve8_c_12,
1388     wrap_convolve8_avg_c_12, 12);
1389 const ConvolveParam kArrayConvolve8_avx2[] = { ALL_SIZES(convolve8_avx2),
1390                                                ALL_SIZES(convolve10_avx2),
1391                                                ALL_SIZES(convolve12_avx2) };
1392 INSTANTIATE_TEST_SUITE_P(AVX2, ConvolveTest,
1393                          ::testing::ValuesIn(kArrayConvolve8_avx2));
1394 #else   // !CONFIG_VP9_HIGHBITDEPTH
1395 const ConvolveFunctions convolve8_avx2(
1396     vpx_convolve_copy_c, vpx_convolve_avg_c, vpx_convolve8_horiz_avx2,
1397     vpx_convolve8_avg_horiz_avx2, vpx_convolve8_vert_avx2,
1398     vpx_convolve8_avg_vert_avx2, vpx_convolve8_avx2, vpx_convolve8_avg_avx2,
1399     vpx_scaled_horiz_c, vpx_scaled_avg_horiz_c, vpx_scaled_vert_c,
1400     vpx_scaled_avg_vert_c, vpx_scaled_2d_c, vpx_scaled_avg_2d_c, 0);
1401 const ConvolveParam kArrayConvolve8_avx2[] = { ALL_SIZES(convolve8_avx2) };
1402 INSTANTIATE_TEST_SUITE_P(AVX2, ConvolveTest,
1403                          ::testing::ValuesIn(kArrayConvolve8_avx2));
1404 #endif  // CONFIG_VP9_HIGHBITDEPTH
1405 #endif  // HAVE_AVX2
1406 
1407 #if HAVE_NEON
1408 #if CONFIG_VP9_HIGHBITDEPTH
1409 const ConvolveFunctions convolve8_neon(
1410     wrap_convolve_copy_neon_8, wrap_convolve_avg_neon_8,
1411     wrap_convolve8_horiz_neon_8, wrap_convolve8_avg_horiz_neon_8,
1412     wrap_convolve8_vert_neon_8, wrap_convolve8_avg_vert_neon_8,
1413     wrap_convolve8_neon_8, wrap_convolve8_avg_neon_8,
1414     wrap_convolve8_horiz_neon_8, wrap_convolve8_avg_horiz_neon_8,
1415     wrap_convolve8_vert_neon_8, wrap_convolve8_avg_vert_neon_8,
1416     wrap_convolve8_neon_8, wrap_convolve8_avg_neon_8, 8);
1417 const ConvolveFunctions convolve10_neon(
1418     wrap_convolve_copy_neon_10, wrap_convolve_avg_neon_10,
1419     wrap_convolve8_horiz_neon_10, wrap_convolve8_avg_horiz_neon_10,
1420     wrap_convolve8_vert_neon_10, wrap_convolve8_avg_vert_neon_10,
1421     wrap_convolve8_neon_10, wrap_convolve8_avg_neon_10,
1422     wrap_convolve8_horiz_neon_10, wrap_convolve8_avg_horiz_neon_10,
1423     wrap_convolve8_vert_neon_10, wrap_convolve8_avg_vert_neon_10,
1424     wrap_convolve8_neon_10, wrap_convolve8_avg_neon_10, 10);
1425 const ConvolveFunctions convolve12_neon(
1426     wrap_convolve_copy_neon_12, wrap_convolve_avg_neon_12,
1427     wrap_convolve8_horiz_neon_12, wrap_convolve8_avg_horiz_neon_12,
1428     wrap_convolve8_vert_neon_12, wrap_convolve8_avg_vert_neon_12,
1429     wrap_convolve8_neon_12, wrap_convolve8_avg_neon_12,
1430     wrap_convolve8_horiz_neon_12, wrap_convolve8_avg_horiz_neon_12,
1431     wrap_convolve8_vert_neon_12, wrap_convolve8_avg_vert_neon_12,
1432     wrap_convolve8_neon_12, wrap_convolve8_avg_neon_12, 12);
1433 const ConvolveParam kArrayConvolve_neon[] = { ALL_SIZES(convolve8_neon),
1434                                               ALL_SIZES(convolve10_neon),
1435                                               ALL_SIZES(convolve12_neon) };
1436 #else
1437 const ConvolveFunctions convolve8_neon(
1438     vpx_convolve_copy_neon, vpx_convolve_avg_neon, vpx_convolve8_horiz_neon,
1439     vpx_convolve8_avg_horiz_neon, vpx_convolve8_vert_neon,
1440     vpx_convolve8_avg_vert_neon, vpx_convolve8_neon, vpx_convolve8_avg_neon,
1441     vpx_scaled_horiz_c, vpx_scaled_avg_horiz_c, vpx_scaled_vert_c,
1442     vpx_scaled_avg_vert_c, vpx_scaled_2d_neon, vpx_scaled_avg_2d_c, 0);
1443 
1444 const ConvolveParam kArrayConvolve_neon[] = { ALL_SIZES(convolve8_neon) };
1445 #endif  // CONFIG_VP9_HIGHBITDEPTH
1446 INSTANTIATE_TEST_SUITE_P(NEON, ConvolveTest,
1447                          ::testing::ValuesIn(kArrayConvolve_neon));
1448 #endif  // HAVE_NEON
1449 
1450 #if HAVE_NEON_DOTPROD
1451 const ConvolveFunctions convolve8_neon_dotprod(
1452     vpx_convolve_copy_c, vpx_convolve_avg_c, vpx_convolve8_horiz_neon_dotprod,
1453     vpx_convolve8_avg_horiz_neon_dotprod, vpx_convolve8_vert_neon_dotprod,
1454     vpx_convolve8_avg_vert_neon_dotprod, vpx_convolve8_neon_dotprod,
1455     vpx_convolve8_avg_neon_dotprod, vpx_scaled_horiz_c, vpx_scaled_avg_horiz_c,
1456     vpx_scaled_vert_c, vpx_scaled_avg_vert_c, vpx_scaled_2d_c,
1457     vpx_scaled_avg_2d_c, 0);
1458 
1459 const ConvolveParam kArrayConvolve_neon_dotprod[] = { ALL_SIZES(
1460     convolve8_neon_dotprod) };
1461 INSTANTIATE_TEST_SUITE_P(NEON_DOTPROD, ConvolveTest,
1462                          ::testing::ValuesIn(kArrayConvolve_neon_dotprod));
1463 #endif  // HAVE_NEON_DOTPROD
1464 
1465 #if HAVE_SVE
1466 #if CONFIG_VP9_HIGHBITDEPTH
1467 const ConvolveFunctions convolve8_sve(
1468     wrap_convolve_copy_c_8, wrap_convolve_avg_c_8, wrap_convolve8_horiz_sve_8,
1469     wrap_convolve8_avg_horiz_sve_8, wrap_convolve8_vert_c_8,
1470     wrap_convolve8_avg_vert_c_8, wrap_convolve8_c_8, wrap_convolve8_avg_c_8,
1471     wrap_convolve8_horiz_c_8, wrap_convolve8_avg_horiz_c_8,
1472     wrap_convolve8_vert_c_8, wrap_convolve8_avg_vert_c_8, wrap_convolve8_c_8,
1473     wrap_convolve8_avg_c_8, 8);
1474 const ConvolveFunctions convolve10_sve(
1475     wrap_convolve_copy_c_10, wrap_convolve_avg_c_10,
1476     wrap_convolve8_horiz_sve_10, wrap_convolve8_avg_horiz_sve_10,
1477     wrap_convolve8_vert_c_10, wrap_convolve8_avg_vert_c_10, wrap_convolve8_c_10,
1478     wrap_convolve8_avg_c_10, wrap_convolve8_horiz_c_10,
1479     wrap_convolve8_avg_horiz_c_10, wrap_convolve8_vert_c_10,
1480     wrap_convolve8_avg_vert_c_10, wrap_convolve8_c_10, wrap_convolve8_avg_c_10,
1481     10);
1482 const ConvolveFunctions convolve12_sve(
1483     wrap_convolve_copy_c_12, wrap_convolve_avg_c_12,
1484     wrap_convolve8_horiz_sve_12, wrap_convolve8_avg_horiz_sve_12,
1485     wrap_convolve8_vert_c_12, wrap_convolve8_avg_vert_c_12, wrap_convolve8_c_12,
1486     wrap_convolve8_avg_c_12, wrap_convolve8_horiz_c_12,
1487     wrap_convolve8_avg_horiz_c_12, wrap_convolve8_vert_c_12,
1488     wrap_convolve8_avg_vert_c_12, wrap_convolve8_c_12, wrap_convolve8_avg_c_12,
1489     12);
1490 
1491 const ConvolveParam kArrayConvolve_sve[] = { ALL_SIZES(convolve8_sve),
1492                                              ALL_SIZES(convolve10_sve),
1493                                              ALL_SIZES(convolve12_sve) };
1494 INSTANTIATE_TEST_SUITE_P(SVE, ConvolveTest,
1495                          ::testing::ValuesIn(kArrayConvolve_sve));
1496 #endif  // CONFIG_VP9_HIGHBITDEPTH
1497 #endif  // HAVE_SVE
1498 
1499 #if HAVE_SVE2
1500 #if CONFIG_VP9_HIGHBITDEPTH
1501 const ConvolveFunctions convolve8_sve2(
1502     wrap_convolve_copy_c_8, wrap_convolve_avg_c_8, wrap_convolve8_horiz_c_8,
1503     wrap_convolve8_avg_horiz_c_8, wrap_convolve8_vert_sve2_8,
1504     wrap_convolve8_avg_vert_sve2_8, wrap_convolve8_sve2_8,
1505     wrap_convolve8_avg_sve2_8, wrap_convolve8_horiz_c_8,
1506     wrap_convolve8_avg_horiz_c_8, wrap_convolve8_vert_c_8,
1507     wrap_convolve8_avg_vert_c_8, wrap_convolve8_c_8, wrap_convolve8_avg_c_8, 8);
1508 const ConvolveFunctions convolve10_sve2(
1509     wrap_convolve_copy_c_10, wrap_convolve_avg_c_10, wrap_convolve8_horiz_c_10,
1510     wrap_convolve8_avg_horiz_c_10, wrap_convolve8_vert_sve2_10,
1511     wrap_convolve8_avg_vert_sve2_10, wrap_convolve8_sve2_10,
1512     wrap_convolve8_avg_sve2_10, wrap_convolve8_horiz_c_10,
1513     wrap_convolve8_avg_horiz_c_10, wrap_convolve8_vert_c_10,
1514     wrap_convolve8_avg_vert_c_10, wrap_convolve8_c_10, wrap_convolve8_avg_c_10,
1515     10);
1516 const ConvolveFunctions convolve12_sve2(
1517     wrap_convolve_copy_c_12, wrap_convolve_avg_c_12, wrap_convolve8_horiz_c_12,
1518     wrap_convolve8_avg_horiz_c_12, wrap_convolve8_vert_sve2_12,
1519     wrap_convolve8_avg_vert_sve2_12, wrap_convolve8_sve2_12,
1520     wrap_convolve8_avg_sve2_12, wrap_convolve8_horiz_c_12,
1521     wrap_convolve8_avg_horiz_c_12, wrap_convolve8_vert_c_12,
1522     wrap_convolve8_avg_vert_c_12, wrap_convolve8_c_12, wrap_convolve8_avg_c_12,
1523     12);
1524 
1525 const ConvolveParam kArrayConvolve_sve2[] = { ALL_SIZES(convolve8_sve2),
1526                                               ALL_SIZES(convolve10_sve2),
1527                                               ALL_SIZES(convolve12_sve2) };
1528 INSTANTIATE_TEST_SUITE_P(SVE2, ConvolveTest,
1529                          ::testing::ValuesIn(kArrayConvolve_sve2));
1530 #endif  // CONFIG_VP9_HIGHBITDEPTH
1531 #endif  // HAVE_SVE2
1532 
1533 #if HAVE_NEON_I8MM
1534 const ConvolveFunctions convolve8_neon_i8mm(
1535     vpx_convolve_copy_c, vpx_convolve_avg_c, vpx_convolve8_horiz_neon_i8mm,
1536     vpx_convolve8_avg_horiz_neon_i8mm, vpx_convolve8_vert_neon_i8mm,
1537     vpx_convolve8_avg_vert_neon_i8mm, vpx_convolve8_neon_i8mm,
1538     vpx_convolve8_avg_neon_i8mm, vpx_scaled_horiz_c, vpx_scaled_avg_horiz_c,
1539     vpx_scaled_vert_c, vpx_scaled_avg_vert_c, vpx_scaled_2d_c,
1540     vpx_scaled_avg_2d_c, 0);
1541 
1542 const ConvolveParam kArrayConvolve_neon_i8mm[] = { ALL_SIZES(
1543     convolve8_neon_i8mm) };
1544 INSTANTIATE_TEST_SUITE_P(NEON_I8MM, ConvolveTest,
1545                          ::testing::ValuesIn(kArrayConvolve_neon_i8mm));
1546 #endif  // HAVE_NEON_I8MM
1547 
1548 #if HAVE_DSPR2
1549 const ConvolveFunctions convolve8_dspr2(
1550     vpx_convolve_copy_dspr2, vpx_convolve_avg_dspr2, vpx_convolve8_horiz_dspr2,
1551     vpx_convolve8_avg_horiz_dspr2, vpx_convolve8_vert_dspr2,
1552     vpx_convolve8_avg_vert_dspr2, vpx_convolve8_dspr2, vpx_convolve8_avg_dspr2,
1553     vpx_scaled_horiz_c, vpx_scaled_avg_horiz_c, vpx_scaled_vert_c,
1554     vpx_scaled_avg_vert_c, vpx_scaled_2d_c, vpx_scaled_avg_2d_c, 0);
1555 
1556 const ConvolveParam kArrayConvolve8_dspr2[] = { ALL_SIZES(convolve8_dspr2) };
1557 INSTANTIATE_TEST_SUITE_P(DSPR2, ConvolveTest,
1558                          ::testing::ValuesIn(kArrayConvolve8_dspr2));
1559 #endif  // HAVE_DSPR2
1560 
1561 #if HAVE_MSA
1562 const ConvolveFunctions convolve8_msa(
1563     vpx_convolve_copy_msa, vpx_convolve_avg_msa, vpx_convolve8_horiz_msa,
1564     vpx_convolve8_avg_horiz_msa, vpx_convolve8_vert_msa,
1565     vpx_convolve8_avg_vert_msa, vpx_convolve8_msa, vpx_convolve8_avg_msa,
1566     vpx_scaled_horiz_c, vpx_scaled_avg_horiz_c, vpx_scaled_vert_c,
1567     vpx_scaled_avg_vert_c, vpx_scaled_2d_msa, vpx_scaled_avg_2d_c, 0);
1568 
1569 const ConvolveParam kArrayConvolve8_msa[] = { ALL_SIZES(convolve8_msa) };
1570 INSTANTIATE_TEST_SUITE_P(MSA, ConvolveTest,
1571                          ::testing::ValuesIn(kArrayConvolve8_msa));
1572 #endif  // HAVE_MSA
1573 
1574 #if HAVE_LSX
1575 const ConvolveFunctions convolve8_lsx(
1576     vpx_convolve_copy_lsx, vpx_convolve_avg_lsx, vpx_convolve8_horiz_lsx,
1577     vpx_convolve8_avg_horiz_lsx, vpx_convolve8_vert_lsx,
1578     vpx_convolve8_avg_vert_lsx, vpx_convolve8_lsx, vpx_convolve8_avg_lsx,
1579     vpx_scaled_horiz_c, vpx_scaled_avg_horiz_c, vpx_scaled_vert_c,
1580     vpx_scaled_avg_vert_c, vpx_scaled_2d_c, vpx_scaled_avg_2d_c, 0);
1581 
1582 const ConvolveParam kArrayConvolve8_lsx[] = { ALL_SIZES(convolve8_lsx) };
1583 INSTANTIATE_TEST_SUITE_P(LSX, ConvolveTest,
1584                          ::testing::ValuesIn(kArrayConvolve8_lsx));
1585 #endif  // HAVE_LSX
1586 
1587 #if HAVE_VSX
1588 const ConvolveFunctions convolve8_vsx(
1589     vpx_convolve_copy_vsx, vpx_convolve_avg_vsx, vpx_convolve8_horiz_vsx,
1590     vpx_convolve8_avg_horiz_vsx, vpx_convolve8_vert_vsx,
1591     vpx_convolve8_avg_vert_vsx, vpx_convolve8_vsx, vpx_convolve8_avg_vsx,
1592     vpx_scaled_horiz_c, vpx_scaled_avg_horiz_c, vpx_scaled_vert_c,
1593     vpx_scaled_avg_vert_c, vpx_scaled_2d_c, vpx_scaled_avg_2d_c, 0);
1594 const ConvolveParam kArrayConvolve_vsx[] = { ALL_SIZES(convolve8_vsx) };
1595 INSTANTIATE_TEST_SUITE_P(VSX, ConvolveTest,
1596                          ::testing::ValuesIn(kArrayConvolve_vsx));
1597 #endif  // HAVE_VSX
1598 
1599 #if HAVE_MMI
1600 const ConvolveFunctions convolve8_mmi(
1601     vpx_convolve_copy_c, vpx_convolve_avg_mmi, vpx_convolve8_horiz_mmi,
1602     vpx_convolve8_avg_horiz_mmi, vpx_convolve8_vert_mmi,
1603     vpx_convolve8_avg_vert_mmi, vpx_convolve8_mmi, vpx_convolve8_avg_mmi,
1604     vpx_scaled_horiz_c, vpx_scaled_avg_horiz_c, vpx_scaled_vert_c,
1605     vpx_scaled_avg_vert_c, vpx_scaled_2d_c, vpx_scaled_avg_2d_c, 0);
1606 const ConvolveParam kArrayConvolve_mmi[] = { ALL_SIZES(convolve8_mmi) };
1607 INSTANTIATE_TEST_SUITE_P(MMI, ConvolveTest,
1608                          ::testing::ValuesIn(kArrayConvolve_mmi));
1609 #endif  // HAVE_MMI
1610 }  // namespace
1611