xref: /aosp_15_r20/external/libvpx/test/comp_avg_pred_test.cc (revision fb1b10ab9aebc7c7068eedab379b749d7e3900be)
1 /*
2  *  Copyright (c) 2017 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 "gtest/gtest.h"
12 
13 #include "./vpx_dsp_rtcd.h"
14 
15 #include "test/acm_random.h"
16 #include "test/buffer.h"
17 #include "test/register_state_check.h"
18 #include "vpx_config.h"
19 #include "vpx_ports/vpx_timer.h"
20 
21 namespace {
22 
23 using ::libvpx_test::ACMRandom;
24 using ::libvpx_test::Buffer;
25 
26 template <typename Pixel>
avg_with_rounding(Pixel a,Pixel b)27 Pixel avg_with_rounding(Pixel a, Pixel b) {
28   return (a + b + 1) >> 1;
29 }
30 
31 template <typename Pixel>
reference_pred(const Buffer<Pixel> & pred,const Buffer<Pixel> & ref,int width,int height,Buffer<Pixel> * avg)32 void reference_pred(const Buffer<Pixel> &pred, const Buffer<Pixel> &ref,
33                     int width, int height, Buffer<Pixel> *avg) {
34   ASSERT_NE(avg->TopLeftPixel(), nullptr);
35   ASSERT_NE(pred.TopLeftPixel(), nullptr);
36   ASSERT_NE(ref.TopLeftPixel(), nullptr);
37 
38   for (int y = 0; y < height; ++y) {
39     for (int x = 0; x < width; ++x) {
40       avg->TopLeftPixel()[y * avg->stride() + x] =
41           avg_with_rounding<Pixel>(pred.TopLeftPixel()[y * pred.stride() + x],
42                                    ref.TopLeftPixel()[y * ref.stride() + x]);
43     }
44   }
45 }
46 
47 using AvgPredFunc = void (*)(uint8_t *a, const uint8_t *b, int w, int h,
48                              const uint8_t *c, int c_stride);
49 
50 template <int bitdepth, typename Pixel>
51 class AvgPredTest : public ::testing::TestWithParam<AvgPredFunc> {
52  public:
SetUp()53   void SetUp() override {
54     avg_pred_func_ = GetParam();
55     rnd_.Reset(ACMRandom::DeterministicSeed());
56   }
57 
58   void TestSizeCombinations();
59   void TestCompareReferenceRandom();
60   void TestSpeed();
61 
62  protected:
63   AvgPredFunc avg_pred_func_;
64   ACMRandom rnd_;
65 };
66 
67 template <int bitdepth, typename Pixel>
TestSizeCombinations()68 void AvgPredTest<bitdepth, Pixel>::TestSizeCombinations() {
69   // This is called as part of the sub pixel variance. As such it must be one of
70   // the variance block sizes.
71   for (int width_pow = 2; width_pow <= 6; ++width_pow) {
72     for (int height_pow = width_pow - 1; height_pow <= width_pow + 1;
73          ++height_pow) {
74       // Don't test 4x2 or 64x128
75       if (height_pow == 1 || height_pow == 7) continue;
76 
77       // The sse2 special-cases when ref width == stride, so make sure to test
78       // it.
79       for (int ref_padding = 0; ref_padding < 2; ref_padding++) {
80         const int width = 1 << width_pow;
81         const int height = 1 << height_pow;
82         // Only the reference buffer may have a stride not equal to width.
83         Buffer<Pixel> ref = Buffer<Pixel>(width, height, ref_padding ? 8 : 0);
84         ASSERT_TRUE(ref.Init());
85         Buffer<Pixel> pred = Buffer<Pixel>(width, height, 0, 32);
86         ASSERT_TRUE(pred.Init());
87         Buffer<Pixel> avg_ref = Buffer<Pixel>(width, height, 0, 32);
88         ASSERT_TRUE(avg_ref.Init());
89         Buffer<Pixel> avg_chk = Buffer<Pixel>(width, height, 0, 32);
90         ASSERT_TRUE(avg_chk.Init());
91         const int bitdepth_mask = (1 << bitdepth) - 1;
92         for (int h = 0; h < height; ++h) {
93           for (int w = 0; w < width; ++w) {
94             ref.TopLeftPixel()[w + h * width] = rnd_.Rand16() & bitdepth_mask;
95           }
96         }
97         for (int h = 0; h < height; ++h) {
98           for (int w = 0; w < width; ++w) {
99             pred.TopLeftPixel()[w + h * width] = rnd_.Rand16() & bitdepth_mask;
100           }
101         }
102 
103         reference_pred<Pixel>(pred, ref, width, height, &avg_ref);
104         ASM_REGISTER_STATE_CHECK(avg_pred_func_(
105             (uint8_t *)avg_chk.TopLeftPixel(), (uint8_t *)pred.TopLeftPixel(),
106             width, height, (uint8_t *)ref.TopLeftPixel(), ref.stride()));
107 
108         EXPECT_TRUE(avg_chk.CheckValues(avg_ref));
109         if (HasFailure()) {
110           printf("Width: %d Height: %d\n", width, height);
111           avg_chk.PrintDifference(avg_ref);
112           return;
113         }
114       }
115     }
116   }
117 }
118 
119 template <int bitdepth, typename Pixel>
TestCompareReferenceRandom()120 void AvgPredTest<bitdepth, Pixel>::TestCompareReferenceRandom() {
121   const int width = 64;
122   const int height = 32;
123   Buffer<Pixel> ref = Buffer<Pixel>(width, height, 8);
124   ASSERT_TRUE(ref.Init());
125   Buffer<Pixel> pred = Buffer<Pixel>(width, height, 0, 32);
126   ASSERT_TRUE(pred.Init());
127   Buffer<Pixel> avg_ref = Buffer<Pixel>(width, height, 0, 32);
128   ASSERT_TRUE(avg_ref.Init());
129   Buffer<Pixel> avg_chk = Buffer<Pixel>(width, height, 0, 32);
130   ASSERT_TRUE(avg_chk.Init());
131 
132   for (int i = 0; i < 500; ++i) {
133     const int bitdepth_mask = (1 << bitdepth) - 1;
134     for (int h = 0; h < height; ++h) {
135       for (int w = 0; w < width; ++w) {
136         ref.TopLeftPixel()[w + h * width] = rnd_.Rand16() & bitdepth_mask;
137       }
138     }
139     for (int h = 0; h < height; ++h) {
140       for (int w = 0; w < width; ++w) {
141         pred.TopLeftPixel()[w + h * width] = rnd_.Rand16() & bitdepth_mask;
142       }
143     }
144 
145     reference_pred<Pixel>(pred, ref, width, height, &avg_ref);
146     ASM_REGISTER_STATE_CHECK(avg_pred_func_(
147         (uint8_t *)avg_chk.TopLeftPixel(), (uint8_t *)pred.TopLeftPixel(),
148         width, height, (uint8_t *)ref.TopLeftPixel(), ref.stride()));
149     EXPECT_TRUE(avg_chk.CheckValues(avg_ref));
150     if (HasFailure()) {
151       printf("Width: %d Height: %d\n", width, height);
152       avg_chk.PrintDifference(avg_ref);
153       return;
154     }
155   }
156 }
157 
158 template <int bitdepth, typename Pixel>
TestSpeed()159 void AvgPredTest<bitdepth, Pixel>::TestSpeed() {
160   for (int width_pow = 2; width_pow <= 6; ++width_pow) {
161     for (int height_pow = width_pow - 1; height_pow <= width_pow + 1;
162          ++height_pow) {
163       // Don't test 4x2 or 64x128
164       if (height_pow == 1 || height_pow == 7) continue;
165 
166       for (int ref_padding = 0; ref_padding < 2; ref_padding++) {
167         const int width = 1 << width_pow;
168         const int height = 1 << height_pow;
169         Buffer<Pixel> ref = Buffer<Pixel>(width, height, ref_padding ? 8 : 0);
170         ASSERT_TRUE(ref.Init());
171         Buffer<Pixel> pred = Buffer<Pixel>(width, height, 0, 32);
172         ASSERT_TRUE(pred.Init());
173         Buffer<Pixel> avg = Buffer<Pixel>(width, height, 0, 32);
174         ASSERT_TRUE(avg.Init());
175         const int bitdepth_mask = (1 << bitdepth) - 1;
176         for (int h = 0; h < height; ++h) {
177           for (int w = 0; w < width; ++w) {
178             ref.TopLeftPixel()[w + h * width] = rnd_.Rand16() & bitdepth_mask;
179           }
180         }
181         for (int h = 0; h < height; ++h) {
182           for (int w = 0; w < width; ++w) {
183             pred.TopLeftPixel()[w + h * width] = rnd_.Rand16() & bitdepth_mask;
184           }
185         }
186 
187         vpx_usec_timer timer;
188         vpx_usec_timer_start(&timer);
189         for (int i = 0; i < 100000000 / (width * height); ++i) {
190           avg_pred_func_((uint8_t *)avg.TopLeftPixel(),
191                          (uint8_t *)pred.TopLeftPixel(), width, height,
192                          (uint8_t *)ref.TopLeftPixel(), ref.stride());
193         }
194         vpx_usec_timer_mark(&timer);
195 
196         const int elapsed_time =
197             static_cast<int>(vpx_usec_timer_elapsed(&timer));
198         printf("Average Test (ref_padding: %d) %dx%d time: %5d us\n",
199                ref_padding, width, height, elapsed_time);
200       }
201     }
202   }
203 }
204 
205 using AvgPredTestLBD = AvgPredTest<8, uint8_t>;
206 
TEST_P(AvgPredTestLBD,SizeCombinations)207 TEST_P(AvgPredTestLBD, SizeCombinations) { TestSizeCombinations(); }
208 
TEST_P(AvgPredTestLBD,CompareReferenceRandom)209 TEST_P(AvgPredTestLBD, CompareReferenceRandom) { TestCompareReferenceRandom(); }
210 
TEST_P(AvgPredTestLBD,DISABLED_Speed)211 TEST_P(AvgPredTestLBD, DISABLED_Speed) { TestSpeed(); }
212 
213 INSTANTIATE_TEST_SUITE_P(C, AvgPredTestLBD,
214                          ::testing::Values(&vpx_comp_avg_pred_c));
215 
216 #if HAVE_SSE2
217 INSTANTIATE_TEST_SUITE_P(SSE2, AvgPredTestLBD,
218                          ::testing::Values(&vpx_comp_avg_pred_sse2));
219 #endif  // HAVE_SSE2
220 
221 #if HAVE_AVX2
222 INSTANTIATE_TEST_SUITE_P(AVX2, AvgPredTestLBD,
223                          ::testing::Values(&vpx_comp_avg_pred_avx2));
224 #endif  // HAVE_AVX2
225 
226 #if HAVE_NEON
227 INSTANTIATE_TEST_SUITE_P(NEON, AvgPredTestLBD,
228                          ::testing::Values(&vpx_comp_avg_pred_neon));
229 #endif  // HAVE_NEON
230 
231 #if HAVE_VSX
232 INSTANTIATE_TEST_SUITE_P(VSX, AvgPredTestLBD,
233                          ::testing::Values(&vpx_comp_avg_pred_vsx));
234 #endif  // HAVE_VSX
235 
236 #if HAVE_LSX
237 INSTANTIATE_TEST_SUITE_P(LSX, AvgPredTestLBD,
238                          ::testing::Values(&vpx_comp_avg_pred_lsx));
239 #endif  // HAVE_LSX
240 
241 #if CONFIG_VP9_HIGHBITDEPTH
242 using HighbdAvgPredFunc = void (*)(uint16_t *a, const uint16_t *b, int w, int h,
243                                    const uint16_t *c, int c_stride);
244 
245 template <HighbdAvgPredFunc fn>
highbd_wrapper(uint8_t * a,const uint8_t * b,int w,int h,const uint8_t * c,int c_stride)246 void highbd_wrapper(uint8_t *a, const uint8_t *b, int w, int h,
247                     const uint8_t *c, int c_stride) {
248   fn((uint16_t *)a, (const uint16_t *)b, w, h, (const uint16_t *)c, c_stride);
249 }
250 
251 using AvgPredTestHBD = AvgPredTest<12, uint16_t>;
252 
TEST_P(AvgPredTestHBD,SizeCombinations)253 TEST_P(AvgPredTestHBD, SizeCombinations) { TestSizeCombinations(); }
254 
TEST_P(AvgPredTestHBD,CompareReferenceRandom)255 TEST_P(AvgPredTestHBD, CompareReferenceRandom) { TestCompareReferenceRandom(); }
256 
TEST_P(AvgPredTestHBD,DISABLED_Speed)257 TEST_P(AvgPredTestHBD, DISABLED_Speed) { TestSpeed(); }
258 
259 INSTANTIATE_TEST_SUITE_P(
260     C, AvgPredTestHBD,
261     ::testing::Values(&highbd_wrapper<vpx_highbd_comp_avg_pred_c>));
262 
263 #if HAVE_SSE2
264 INSTANTIATE_TEST_SUITE_P(
265     SSE2, AvgPredTestHBD,
266     ::testing::Values(&highbd_wrapper<vpx_highbd_comp_avg_pred_sse2>));
267 #endif  // HAVE_SSE2
268 
269 #if HAVE_NEON
270 INSTANTIATE_TEST_SUITE_P(
271     NEON, AvgPredTestHBD,
272     ::testing::Values(&highbd_wrapper<vpx_highbd_comp_avg_pred_neon>));
273 #endif  // HAVE_NEON
274 
275 #endif  // CONFIG_VP9_HIGHBITDEPTH
276 }  // namespace
277