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