1 /*
2 * Copyright (c) 2018, Alliance for Open Media. All rights reserved
3 *
4 * This source code is subject to the terms of the BSD 2 Clause License and
5 * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
6 * was not distributed with this source code in the LICENSE file, you can
7 * obtain it at www.aomedia.org/license/software. If the Alliance for Open
8 * Media Patent License 1.0 was not distributed with this source code in the
9 * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
10 */
11
12 #include <tuple>
13
14 #include "third_party/googletest/src/googletest/include/gtest/gtest.h"
15
16 #include "config/aom_config.h"
17 #include "config/aom_dsp_rtcd.h"
18
19 #include "aom_mem/aom_mem.h"
20 #include "aom_ports/aom_timer.h"
21 #include "av1/common/blockd.h"
22 #include "av1/common/pred_common.h"
23 #include "av1/common/reconintra.h"
24 #include "test/acm_random.h"
25 #include "test/clear_system_state.h"
26 #include "test/register_state_check.h"
27 #include "test/util.h"
28
29 namespace {
30
31 const int kZ1Start = 0;
32 const int kZ2Start = 90;
33 const int kZ3Start = 180;
34
35 const TX_SIZE kTxSize[] = { TX_4X4, TX_8X8, TX_16X16, TX_32X32, TX_64X64,
36 TX_4X8, TX_8X4, TX_8X16, TX_16X8, TX_16X32,
37 TX_32X16, TX_32X64, TX_64X32, TX_4X16, TX_16X4,
38 TX_8X32, TX_32X8, TX_16X64, TX_64X16 };
39
40 const char *const kTxSizeStrings[] = {
41 "TX_4X4", "TX_8X8", "TX_16X16", "TX_32X32", "TX_64X64",
42 "TX_4X8", "TX_8X4", "TX_8X16", "TX_16X8", "TX_16X32",
43 "TX_32X16", "TX_32X64", "TX_64X32", "TX_4X16", "TX_16X4",
44 "TX_8X32", "TX_32X8", "TX_16X64", "TX_64X16"
45 };
46
47 using libaom_test::ACMRandom;
48
49 typedef void (*DrPred_Hbd)(uint16_t *dst, ptrdiff_t stride, int bw, int bh,
50 const uint16_t *above, const uint16_t *left,
51 int upsample_above, int upsample_left, int dx,
52 int dy, int bd);
53
54 typedef void (*DrPred)(uint8_t *dst, ptrdiff_t stride, int bw, int bh,
55 const uint8_t *above, const uint8_t *left,
56 int upsample_above, int upsample_left, int dx, int dy,
57 int bd);
58
59 typedef void (*Z1_Lbd)(uint8_t *dst, ptrdiff_t stride, int bw, int bh,
60 const uint8_t *above, const uint8_t *left,
61 int upsample_above, int dx, int dy);
62 template <Z1_Lbd fn>
z1_wrapper(uint8_t * dst,ptrdiff_t stride,int bw,int bh,const uint8_t * above,const uint8_t * left,int upsample_above,int upsample_left,int dx,int dy,int bd)63 void z1_wrapper(uint8_t *dst, ptrdiff_t stride, int bw, int bh,
64 const uint8_t *above, const uint8_t *left, int upsample_above,
65 int upsample_left, int dx, int dy, int bd) {
66 (void)bd;
67 (void)upsample_left;
68 fn(dst, stride, bw, bh, above, left, upsample_above, dx, dy);
69 }
70
71 typedef void (*Z2_Lbd)(uint8_t *dst, ptrdiff_t stride, int bw, int bh,
72 const uint8_t *above, const uint8_t *left,
73 int upsample_above, int upsample_left, int dx, int dy);
74 template <Z2_Lbd fn>
z2_wrapper(uint8_t * dst,ptrdiff_t stride,int bw,int bh,const uint8_t * above,const uint8_t * left,int upsample_above,int upsample_left,int dx,int dy,int bd)75 void z2_wrapper(uint8_t *dst, ptrdiff_t stride, int bw, int bh,
76 const uint8_t *above, const uint8_t *left, int upsample_above,
77 int upsample_left, int dx, int dy, int bd) {
78 (void)bd;
79 (void)upsample_left;
80 fn(dst, stride, bw, bh, above, left, upsample_above, upsample_left, dx, dy);
81 }
82
83 typedef void (*Z3_Lbd)(uint8_t *dst, ptrdiff_t stride, int bw, int bh,
84 const uint8_t *above, const uint8_t *left,
85 int upsample_left, int dx, int dy);
86 template <Z3_Lbd fn>
z3_wrapper(uint8_t * dst,ptrdiff_t stride,int bw,int bh,const uint8_t * above,const uint8_t * left,int upsample_above,int upsample_left,int dx,int dy,int bd)87 void z3_wrapper(uint8_t *dst, ptrdiff_t stride, int bw, int bh,
88 const uint8_t *above, const uint8_t *left, int upsample_above,
89 int upsample_left, int dx, int dy, int bd) {
90 (void)bd;
91 (void)upsample_above;
92 fn(dst, stride, bw, bh, above, left, upsample_left, dx, dy);
93 }
94
95 typedef void (*Z1_Hbd)(uint16_t *dst, ptrdiff_t stride, int bw, int bh,
96 const uint16_t *above, const uint16_t *left,
97 int upsample_above, int dx, int dy, int bd);
98 template <Z1_Hbd fn>
z1_wrapper_hbd(uint16_t * dst,ptrdiff_t stride,int bw,int bh,const uint16_t * above,const uint16_t * left,int upsample_above,int upsample_left,int dx,int dy,int bd)99 void z1_wrapper_hbd(uint16_t *dst, ptrdiff_t stride, int bw, int bh,
100 const uint16_t *above, const uint16_t *left,
101 int upsample_above, int upsample_left, int dx, int dy,
102 int bd) {
103 (void)bd;
104 (void)upsample_left;
105 fn(dst, stride, bw, bh, above, left, upsample_above, dx, dy, bd);
106 }
107
108 typedef void (*Z2_Hbd)(uint16_t *dst, ptrdiff_t stride, int bw, int bh,
109 const uint16_t *above, const uint16_t *left,
110 int upsample_above, int upsample_left, int dx, int dy,
111 int bd);
112 template <Z2_Hbd fn>
z2_wrapper_hbd(uint16_t * dst,ptrdiff_t stride,int bw,int bh,const uint16_t * above,const uint16_t * left,int upsample_above,int upsample_left,int dx,int dy,int bd)113 void z2_wrapper_hbd(uint16_t *dst, ptrdiff_t stride, int bw, int bh,
114 const uint16_t *above, const uint16_t *left,
115 int upsample_above, int upsample_left, int dx, int dy,
116 int bd) {
117 (void)bd;
118 fn(dst, stride, bw, bh, above, left, upsample_above, upsample_left, dx, dy,
119 bd);
120 }
121
122 typedef void (*Z3_Hbd)(uint16_t *dst, ptrdiff_t stride, int bw, int bh,
123 const uint16_t *above, const uint16_t *left,
124 int upsample_left, int dx, int dy, int bd);
125 template <Z3_Hbd fn>
z3_wrapper_hbd(uint16_t * dst,ptrdiff_t stride,int bw,int bh,const uint16_t * above,const uint16_t * left,int upsample_above,int upsample_left,int dx,int dy,int bd)126 void z3_wrapper_hbd(uint16_t *dst, ptrdiff_t stride, int bw, int bh,
127 const uint16_t *above, const uint16_t *left,
128 int upsample_above, int upsample_left, int dx, int dy,
129 int bd) {
130 (void)bd;
131 (void)upsample_above;
132 fn(dst, stride, bw, bh, above, left, upsample_left, dx, dy, bd);
133 }
134
135 template <typename FuncType>
136 struct DrPredFunc {
DrPredFunc__anon1627808a0111::DrPredFunc137 DrPredFunc(FuncType pred = NULL, FuncType tst = NULL, int bit_depth_value = 0,
138 int start_angle_value = 0)
139 : ref_fn(pred), tst_fn(tst), bit_depth(bit_depth_value),
140 start_angle(start_angle_value) {}
141
142 FuncType ref_fn;
143 FuncType tst_fn;
144 int bit_depth;
145 int start_angle;
146 };
147
148 template <typename Pixel, typename FuncType>
149 class DrPredTest : public ::testing::TestWithParam<DrPredFunc<FuncType> > {
150 protected:
151 static const int kMaxNumTests = 10000;
152 static const int kIterations = 10;
153 static const int kDstStride = 64;
154 static const int kDstSize = kDstStride * kDstStride;
155 static const int kOffset = 16;
156 static const int kBufSize = ((2 * MAX_TX_SIZE) << 1) + 16;
157
DrPredTest()158 DrPredTest()
159 : enable_upsample_(0), upsample_above_(0), upsample_left_(0), bw_(0),
160 bh_(0), dx_(1), dy_(1), bd_(8), txsize_(TX_4X4) {
161 params_ = this->GetParam();
162 start_angle_ = params_.start_angle;
163 stop_angle_ = start_angle_ + 90;
164
165 dst_ref_ = &dst_ref_data_[0];
166 dst_tst_ = &dst_tst_data_[0];
167 dst_stride_ = kDstStride;
168 above_ = &above_data_[kOffset];
169 left_ = &left_data_[kOffset];
170
171 for (int i = 0; i < kBufSize; ++i) {
172 above_data_[i] = rng_.Rand8();
173 left_data_[i] = rng_.Rand8();
174 }
175
176 for (int i = 0; i < kDstSize; ++i) {
177 dst_ref_[i] = 0;
178 dst_tst_[i] = 0;
179 }
180 }
181
~DrPredTest()182 virtual ~DrPredTest() {}
183
Predict(bool speedtest,int tx)184 void Predict(bool speedtest, int tx) {
185 const int kNumTests = speedtest ? kMaxNumTests : 1;
186 aom_usec_timer timer;
187 int tst_time = 0;
188
189 bd_ = params_.bit_depth;
190
191 aom_usec_timer_start(&timer);
192 for (int k = 0; k < kNumTests; ++k) {
193 params_.ref_fn(dst_ref_, dst_stride_, bw_, bh_, above_, left_,
194 upsample_above_, upsample_left_, dx_, dy_, bd_);
195 }
196 aom_usec_timer_mark(&timer);
197 const int ref_time = static_cast<int>(aom_usec_timer_elapsed(&timer));
198
199 if (params_.tst_fn) {
200 aom_usec_timer_start(&timer);
201 for (int k = 0; k < kNumTests; ++k) {
202 ASM_REGISTER_STATE_CHECK(params_.tst_fn(dst_tst_, dst_stride_, bw_, bh_,
203 above_, left_, upsample_above_,
204 upsample_left_, dx_, dy_, bd_));
205 }
206 aom_usec_timer_mark(&timer);
207 tst_time = static_cast<int>(aom_usec_timer_elapsed(&timer));
208 } else {
209 for (int i = 0; i < kDstSize; ++i) {
210 dst_ref_[i] = dst_tst_[i];
211 }
212 }
213
214 OutputTimes(kNumTests, ref_time, tst_time, tx);
215 }
216
RunTest(bool speedtest,bool needsaturation,int p_angle)217 void RunTest(bool speedtest, bool needsaturation, int p_angle) {
218 bd_ = params_.bit_depth;
219
220 if (needsaturation) {
221 for (int i = 0; i < kBufSize; ++i) {
222 above_data_[i] = left_data_[i] = (1 << bd_) - 1;
223 }
224 }
225 for (int tx = 0; tx < TX_SIZES_ALL; ++tx) {
226 if (params_.tst_fn == NULL) {
227 for (int i = 0; i < kDstSize; ++i) {
228 dst_tst_[i] = (1 << bd_) - 1;
229 dst_ref_[i] = (1 << bd_) - 1;
230 }
231 } else {
232 for (int i = 0; i < kDstSize; ++i) {
233 dst_ref_[i] = 0;
234 dst_tst_[i] = 0;
235 }
236 }
237
238 bw_ = tx_size_wide[kTxSize[tx]];
239 bh_ = tx_size_high[kTxSize[tx]];
240
241 if (enable_upsample_) {
242 upsample_above_ =
243 av1_use_intra_edge_upsample(bw_, bh_, p_angle - 90, 0);
244 upsample_left_ =
245 av1_use_intra_edge_upsample(bw_, bh_, p_angle - 180, 0);
246 } else {
247 upsample_above_ = upsample_left_ = 0;
248 }
249
250 Predict(speedtest, tx);
251
252 for (int r = 0; r < bh_; ++r) {
253 for (int c = 0; c < bw_; ++c) {
254 ASSERT_EQ(dst_ref_[r * dst_stride_ + c],
255 dst_tst_[r * dst_stride_ + c])
256 << bw_ << "x" << bh_ << " r: " << r << " c: " << c
257 << " dx: " << dx_ << " dy: " << dy_
258 << " upsample_above: " << upsample_above_
259 << " upsample_left: " << upsample_left_;
260 }
261 }
262 }
263 }
264
OutputTimes(int num_tests,int ref_time,int tst_time,int tx)265 void OutputTimes(int num_tests, int ref_time, int tst_time, int tx) {
266 if (num_tests > 1) {
267 if (params_.tst_fn) {
268 const float x = static_cast<float>(ref_time) / tst_time;
269 printf("\t[%8s] :: ref time %6d, tst time %6d %3.2f\n",
270 kTxSizeStrings[tx], ref_time, tst_time, x);
271 } else {
272 printf("\t[%8s] :: ref time %6d\n", kTxSizeStrings[tx], ref_time);
273 }
274 }
275 }
276
277 Pixel dst_ref_data_[kDstSize];
278 Pixel dst_tst_data_[kDstSize];
279
280 Pixel left_data_[kBufSize];
281 Pixel dummy_data_[kBufSize];
282 Pixel above_data_[kBufSize];
283
284 Pixel *dst_ref_;
285 Pixel *dst_tst_;
286 Pixel *above_;
287 Pixel *left_;
288 int dst_stride_;
289
290 int enable_upsample_;
291 int upsample_above_;
292 int upsample_left_;
293 int bw_;
294 int bh_;
295 int dx_;
296 int dy_;
297 int bd_;
298 TX_SIZE txsize_;
299
300 int start_angle_;
301 int stop_angle_;
302
303 ACMRandom rng_;
304
305 DrPredFunc<FuncType> params_;
306 };
307
308 class LowbdDrPredTest : public DrPredTest<uint8_t, DrPred> {};
309
TEST_P(LowbdDrPredTest,SaturatedValues)310 TEST_P(LowbdDrPredTest, SaturatedValues) {
311 for (enable_upsample_ = 0; enable_upsample_ < 2; ++enable_upsample_) {
312 for (int angle = start_angle_; angle < stop_angle_; ++angle) {
313 dx_ = av1_get_dx(angle);
314 dy_ = av1_get_dy(angle);
315 if (dx_ && dy_) RunTest(false, true, angle);
316 }
317 }
318 }
319
320 using std::make_tuple;
321
322 INSTANTIATE_TEST_SUITE_P(
323 C, LowbdDrPredTest,
324 ::testing::Values(DrPredFunc<DrPred>(&z1_wrapper<av1_dr_prediction_z1_c>,
325 NULL, AOM_BITS_8, kZ1Start),
326 DrPredFunc<DrPred>(&z2_wrapper<av1_dr_prediction_z2_c>,
327 NULL, AOM_BITS_8, kZ2Start),
328 DrPredFunc<DrPred>(&z3_wrapper<av1_dr_prediction_z3_c>,
329 NULL, AOM_BITS_8, kZ3Start)));
330
331 #if CONFIG_AV1_HIGHBITDEPTH
332 class HighbdDrPredTest : public DrPredTest<uint16_t, DrPred_Hbd> {};
333
TEST_P(HighbdDrPredTest,SaturatedValues)334 TEST_P(HighbdDrPredTest, SaturatedValues) {
335 for (enable_upsample_ = 0; enable_upsample_ < 2; ++enable_upsample_) {
336 for (int angle = start_angle_; angle < stop_angle_; ++angle) {
337 dx_ = av1_get_dx(angle);
338 dy_ = av1_get_dy(angle);
339 if (dx_ && dy_) RunTest(false, true, angle);
340 }
341 }
342 }
343
344 INSTANTIATE_TEST_SUITE_P(
345 C, HighbdDrPredTest,
346 ::testing::Values(
347 DrPredFunc<DrPred_Hbd>(&z1_wrapper_hbd<av1_highbd_dr_prediction_z1_c>,
348 NULL, AOM_BITS_8, kZ1Start),
349 DrPredFunc<DrPred_Hbd>(&z1_wrapper_hbd<av1_highbd_dr_prediction_z1_c>,
350 NULL, AOM_BITS_10, kZ1Start),
351 DrPredFunc<DrPred_Hbd>(&z1_wrapper_hbd<av1_highbd_dr_prediction_z1_c>,
352 NULL, AOM_BITS_12, kZ1Start),
353 DrPredFunc<DrPred_Hbd>(&z2_wrapper_hbd<av1_highbd_dr_prediction_z2_c>,
354 NULL, AOM_BITS_8, kZ2Start),
355 DrPredFunc<DrPred_Hbd>(&z2_wrapper_hbd<av1_highbd_dr_prediction_z2_c>,
356 NULL, AOM_BITS_10, kZ2Start),
357 DrPredFunc<DrPred_Hbd>(&z2_wrapper_hbd<av1_highbd_dr_prediction_z2_c>,
358 NULL, AOM_BITS_12, kZ2Start),
359 DrPredFunc<DrPred_Hbd>(&z3_wrapper_hbd<av1_highbd_dr_prediction_z3_c>,
360 NULL, AOM_BITS_8, kZ3Start),
361 DrPredFunc<DrPred_Hbd>(&z3_wrapper_hbd<av1_highbd_dr_prediction_z3_c>,
362 NULL, AOM_BITS_10, kZ3Start),
363 DrPredFunc<DrPred_Hbd>(&z3_wrapper_hbd<av1_highbd_dr_prediction_z3_c>,
364 NULL, AOM_BITS_12, kZ3Start)));
365 #endif // CONFIG_AV1_HIGHBITDEPTH
366
367 #if HAVE_AVX2
368 INSTANTIATE_TEST_SUITE_P(
369 AVX2, LowbdDrPredTest,
370 ::testing::Values(DrPredFunc<DrPred>(&z1_wrapper<av1_dr_prediction_z1_c>,
371 &z1_wrapper<av1_dr_prediction_z1_avx2>,
372 AOM_BITS_8, kZ1Start),
373 DrPredFunc<DrPred>(&z2_wrapper<av1_dr_prediction_z2_c>,
374 &z2_wrapper<av1_dr_prediction_z2_avx2>,
375 AOM_BITS_8, kZ2Start),
376 DrPredFunc<DrPred>(&z3_wrapper<av1_dr_prediction_z3_c>,
377 &z3_wrapper<av1_dr_prediction_z3_avx2>,
378 AOM_BITS_8, kZ3Start)));
379
TEST_P(LowbdDrPredTest,DISABLED_Speed)380 TEST_P(LowbdDrPredTest, DISABLED_Speed) {
381 const int angles[] = { 3, 45, 87 };
382 for (enable_upsample_ = 0; enable_upsample_ < 2; ++enable_upsample_) {
383 for (int i = 0; i < 3; ++i) {
384 const int angle = angles[i] + start_angle_;
385 dx_ = av1_get_dx(angle);
386 dy_ = av1_get_dy(angle);
387 printf("enable_upsample: %d angle: %d ~~~~~~~~~~~~~~~\n",
388 enable_upsample_, angle);
389 if (dx_ && dy_) RunTest(true, false, angle);
390 }
391 }
392 }
393
TEST_P(LowbdDrPredTest,OperationCheck)394 TEST_P(LowbdDrPredTest, OperationCheck) {
395 if (params_.tst_fn == NULL) return;
396 // const int angles[] = { 3, 45, 81, 87, 93, 100, 145, 187, 199, 260 };
397 for (enable_upsample_ = 0; enable_upsample_ < 2; ++enable_upsample_) {
398 for (int angle = start_angle_; angle < stop_angle_; ++angle) {
399 dx_ = av1_get_dx(angle);
400 dy_ = av1_get_dy(angle);
401 if (dx_ && dy_) RunTest(false, false, angle);
402 }
403 }
404 }
405
406 #if CONFIG_AV1_HIGHBITDEPTH
407 INSTANTIATE_TEST_SUITE_P(
408 AVX2, HighbdDrPredTest,
409 ::testing::Values(DrPredFunc<DrPred_Hbd>(
410 &z1_wrapper_hbd<av1_highbd_dr_prediction_z1_c>,
411 &z1_wrapper_hbd<av1_highbd_dr_prediction_z1_avx2>,
412 AOM_BITS_8, kZ1Start),
413 DrPredFunc<DrPred_Hbd>(
414 &z1_wrapper_hbd<av1_highbd_dr_prediction_z1_c>,
415 &z1_wrapper_hbd<av1_highbd_dr_prediction_z1_avx2>,
416 AOM_BITS_10, kZ1Start),
417 DrPredFunc<DrPred_Hbd>(
418 &z1_wrapper_hbd<av1_highbd_dr_prediction_z1_c>,
419 &z1_wrapper_hbd<av1_highbd_dr_prediction_z1_avx2>,
420 AOM_BITS_12, kZ1Start),
421 DrPredFunc<DrPred_Hbd>(
422 &z2_wrapper_hbd<av1_highbd_dr_prediction_z2_c>,
423 &z2_wrapper_hbd<av1_highbd_dr_prediction_z2_avx2>,
424 AOM_BITS_8, kZ2Start),
425 DrPredFunc<DrPred_Hbd>(
426 &z2_wrapper_hbd<av1_highbd_dr_prediction_z2_c>,
427 &z2_wrapper_hbd<av1_highbd_dr_prediction_z2_avx2>,
428 AOM_BITS_10, kZ2Start),
429 DrPredFunc<DrPred_Hbd>(
430 &z2_wrapper_hbd<av1_highbd_dr_prediction_z2_c>,
431 &z2_wrapper_hbd<av1_highbd_dr_prediction_z2_avx2>,
432 AOM_BITS_12, kZ2Start),
433 DrPredFunc<DrPred_Hbd>(
434 &z3_wrapper_hbd<av1_highbd_dr_prediction_z3_c>,
435 &z3_wrapper_hbd<av1_highbd_dr_prediction_z3_avx2>,
436 AOM_BITS_8, kZ3Start),
437 DrPredFunc<DrPred_Hbd>(
438 &z3_wrapper_hbd<av1_highbd_dr_prediction_z3_c>,
439 &z3_wrapper_hbd<av1_highbd_dr_prediction_z3_avx2>,
440 AOM_BITS_10, kZ3Start),
441 DrPredFunc<DrPred_Hbd>(
442 &z3_wrapper_hbd<av1_highbd_dr_prediction_z3_c>,
443 &z3_wrapper_hbd<av1_highbd_dr_prediction_z3_avx2>,
444 AOM_BITS_12, kZ3Start)));
445
TEST_P(HighbdDrPredTest,DISABLED_Speed)446 TEST_P(HighbdDrPredTest, DISABLED_Speed) {
447 const int angles[] = { 3, 45, 87 };
448 for (enable_upsample_ = 0; enable_upsample_ < 2; ++enable_upsample_) {
449 for (int i = 0; i < 3; ++i) {
450 int angle = angles[i] + start_angle_;
451 dx_ = av1_get_dx(angle);
452 dy_ = av1_get_dy(angle);
453 printf("enable_upsample: %d angle: %d ~~~~~~~~~~~~~~~\n",
454 enable_upsample_, angle);
455 if (dx_ && dy_) RunTest(true, false, angle);
456 }
457 }
458 }
459
TEST_P(HighbdDrPredTest,OperationCheck)460 TEST_P(HighbdDrPredTest, OperationCheck) {
461 if (params_.tst_fn == NULL) return;
462 // const int angles[] = { 3, 45, 81, 87, 93, 100, 145, 187, 199, 260 };
463 for (enable_upsample_ = 0; enable_upsample_ < 2; ++enable_upsample_) {
464 for (int angle = start_angle_; angle < stop_angle_; angle++) {
465 dx_ = av1_get_dx(angle);
466 dy_ = av1_get_dy(angle);
467 if (dx_ && dy_) RunTest(false, false, angle);
468 }
469 }
470 }
471 #endif // CONFIG_AV1_HIGHBITDEPTH
472 #endif // HAVE_AVX2
473
474 } // namespace
475