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