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