blob: a6b442fbb048544b6fe1d5dac5efb1d0de8f9f33 [file] [log] [blame]
Peter de Rivaza7b2d092014-10-16 13:38:46 +01001/*
Yaowu Xu2ab7ff02016-09-02 12:04:54 -07002 * Copyright (c) 2016, Alliance for Open Media. All rights reserved
Peter de Rivaza7b2d092014-10-16 13:38:46 +01003 *
Yaowu Xu2ab7ff02016-09-02 12:04:54 -07004 * 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.
Johann123e8a62017-12-28 14:40:49 -080010 */
Peter de Rivaza7b2d092014-10-16 13:38:46 +010011
12#include <cmath>
13#include <cstdlib>
14#include <string>
sarahparkera543df52018-11-02 16:02:05 -070015#include <tuple>
Peter de Rivaza7b2d092014-10-16 13:38:46 +010016
Tom Finegan7a07ece2017-02-07 17:14:05 -080017#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
Peter de Rivaza7b2d092014-10-16 13:38:46 +010018
Tom Finegan60e653d2018-05-22 11:34:58 -070019#include "config/aom_config.h"
Tom Finegan44702c82018-05-22 13:00:39 -070020#include "config/av1_rtcd.h"
Tom Finegan60e653d2018-05-22 11:34:58 -070021
Peter de Rivaza7b2d092014-10-16 13:38:46 +010022#include "test/acm_random.h"
Peter de Rivaza7b2d092014-10-16 13:38:46 +010023#include "test/register_state_check.h"
24#include "test/util.h"
Yaowu Xuc27fc142016-08-22 16:08:15 -070025#include "av1/common/entropy.h"
Yaowu Xuf883b422016-08-30 14:01:10 -070026#include "aom/aom_codec.h"
27#include "aom/aom_integer.h"
Peter de Rivaza7b2d092014-10-16 13:38:46 +010028
Yaowu Xuc27fc142016-08-22 16:08:15 -070029using libaom_test::ACMRandom;
Peter de Rivaza7b2d092014-10-16 13:38:46 +010030
31namespace {
Peter de Rivaza7b2d092014-10-16 13:38:46 +010032const int kNumIterations = 1000;
33
chiyotsai65078e22021-09-29 10:36:53 -070034using ErrorBlockFunc = int64_t (*)(const tran_low_t *coeff,
35 const tran_low_t *dqcoeff,
36 intptr_t block_size, int64_t *ssz, int bps);
Peter de Rivaza7b2d092014-10-16 13:38:46 +010037
chiyotsai65078e22021-09-29 10:36:53 -070038using ErrorBlockFunc8Bits = int64_t (*)(const tran_low_t *coeff,
39 const tran_low_t *dqcoeff,
40 intptr_t block_size, int64_t *ssz);
Jerome Jiang44a8d5c2019-07-01 17:21:14 -070041
chiyotsai65078e22021-09-29 10:36:53 -070042using ErrorBlockLpFunc = int64_t (*)(const int16_t *coeff,
43 const int16_t *dqcoeff,
44 intptr_t block_size);
45
46using ErrorBlockParam =
47 std::tuple<ErrorBlockFunc, ErrorBlockFunc, aom_bit_depth_t>;
Peter de Rivaza7b2d092014-10-16 13:38:46 +010048
Jerome Jiang44a8d5c2019-07-01 17:21:14 -070049template <ErrorBlockFunc8Bits fn>
50int64_t BlockError8BitWrapper(const tran_low_t *coeff,
51 const tran_low_t *dqcoeff, intptr_t block_size,
52 int64_t *ssz, int bps) {
53 EXPECT_EQ(bps, 8);
54 return fn(coeff, dqcoeff, block_size, ssz);
55}
56
chiyotsai65078e22021-09-29 10:36:53 -070057template <ErrorBlockLpFunc fn>
58int64_t BlockErrorLpWrapper(const tran_low_t *coeff, const tran_low_t *dqcoeff,
59 intptr_t block_size, int64_t *ssz, int bps) {
60 EXPECT_EQ(bps, 8);
61 *ssz = -1;
62 return fn(reinterpret_cast<const int16_t *>(coeff),
63 reinterpret_cast<const int16_t *>(dqcoeff), block_size);
64}
65
clang-format3a826f12016-08-11 17:46:05 -070066class ErrorBlockTest : public ::testing::TestWithParam<ErrorBlockParam> {
Peter de Rivaza7b2d092014-10-16 13:38:46 +010067 public:
68 virtual ~ErrorBlockTest() {}
69 virtual void SetUp() {
clang-format3a826f12016-08-11 17:46:05 -070070 error_block_op_ = GET_PARAM(0);
Peter de Rivaza7b2d092014-10-16 13:38:46 +010071 ref_error_block_op_ = GET_PARAM(1);
clang-format3a826f12016-08-11 17:46:05 -070072 bit_depth_ = GET_PARAM(2);
Peter de Rivaza7b2d092014-10-16 13:38:46 +010073 }
74
chiyotsai6ddbede2021-06-30 14:24:15 -070075 virtual void TearDown() {}
Peter de Rivaza7b2d092014-10-16 13:38:46 +010076
77 protected:
Yaowu Xuf883b422016-08-30 14:01:10 -070078 aom_bit_depth_t bit_depth_;
Peter de Rivaza7b2d092014-10-16 13:38:46 +010079 ErrorBlockFunc error_block_op_;
80 ErrorBlockFunc ref_error_block_op_;
81};
chiyotsai9dfac722020-07-07 17:43:02 -070082GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ErrorBlockTest);
Peter de Rivaza7b2d092014-10-16 13:38:46 +010083
84TEST_P(ErrorBlockTest, OperationCheck) {
85 ACMRandom rnd(ACMRandom::DeterministicSeed());
James Zernfd3658b2015-05-02 13:24:16 -070086 DECLARE_ALIGNED(16, tran_low_t, coeff[4096]);
87 DECLARE_ALIGNED(16, tran_low_t, dqcoeff[4096]);
Peter de Rivaza7b2d092014-10-16 13:38:46 +010088 int err_count_total = 0;
89 int first_failure = -1;
90 intptr_t block_size;
91 int64_t ssz;
92 int64_t ret;
93 int64_t ref_ssz;
94 int64_t ref_ret;
Geza Loreaa8f8522015-10-15 18:28:31 +010095 const int msb = bit_depth_ + 8 - 1;
Peter de Rivaza7b2d092014-10-16 13:38:46 +010096 for (int i = 0; i < kNumIterations; ++i) {
97 int err_count = 0;
98 block_size = 16 << (i % 9); // All block sizes from 4x4, 8x4 ..64x64
99 for (int j = 0; j < block_size; j++) {
Geza Loreaa8f8522015-10-15 18:28:31 +0100100 // coeff and dqcoeff will always have at least the same sign, and this
101 // can be used for optimization, so generate test input precisely.
102 if (rnd(2)) {
103 // Positive number
clang-format3a826f12016-08-11 17:46:05 -0700104 coeff[j] = rnd(1 << msb);
Geza Loreaa8f8522015-10-15 18:28:31 +0100105 dqcoeff[j] = rnd(1 << msb);
106 } else {
107 // Negative number
clang-format3a826f12016-08-11 17:46:05 -0700108 coeff[j] = -rnd(1 << msb);
Geza Loreaa8f8522015-10-15 18:28:31 +0100109 dqcoeff[j] = -rnd(1 << msb);
110 }
Peter de Rivaza7b2d092014-10-16 13:38:46 +0100111 }
clang-format3a826f12016-08-11 17:46:05 -0700112 ref_ret =
113 ref_error_block_op_(coeff, dqcoeff, block_size, &ref_ssz, bit_depth_);
chiyotsaief261062021-07-01 14:01:45 -0700114 API_REGISTER_STATE_CHECK(
clang-format3a826f12016-08-11 17:46:05 -0700115 ret = error_block_op_(coeff, dqcoeff, block_size, &ssz, bit_depth_));
Peter de Rivaza7b2d092014-10-16 13:38:46 +0100116 err_count += (ref_ret != ret) | (ref_ssz != ssz);
117 if (err_count && !err_count_total) {
118 first_failure = i;
119 }
120 err_count_total += err_count;
121 }
122 EXPECT_EQ(0, err_count_total)
Geza Loreaa8f8522015-10-15 18:28:31 +0100123 << "Error: Error Block Test, C output doesn't match optimized output. "
Peter de Rivaza7b2d092014-10-16 13:38:46 +0100124 << "First failed at test case " << first_failure;
125}
126
127TEST_P(ErrorBlockTest, ExtremeValues) {
128 ACMRandom rnd(ACMRandom::DeterministicSeed());
James Zernfd3658b2015-05-02 13:24:16 -0700129 DECLARE_ALIGNED(16, tran_low_t, coeff[4096]);
130 DECLARE_ALIGNED(16, tran_low_t, dqcoeff[4096]);
Peter de Rivaza7b2d092014-10-16 13:38:46 +0100131 int err_count_total = 0;
132 int first_failure = -1;
133 intptr_t block_size;
134 int64_t ssz;
135 int64_t ret;
136 int64_t ref_ssz;
137 int64_t ref_ret;
Geza Loreaa8f8522015-10-15 18:28:31 +0100138 const int msb = bit_depth_ + 8 - 1;
139 int max_val = ((1 << msb) - 1);
Peter de Rivaza7b2d092014-10-16 13:38:46 +0100140 for (int i = 0; i < kNumIterations; ++i) {
141 int err_count = 0;
Geza Loreaa8f8522015-10-15 18:28:31 +0100142 int k = (i / 9) % 9;
Peter de Rivaza7b2d092014-10-16 13:38:46 +0100143
144 // Change the maximum coeff value, to test different bit boundaries
clang-format3a826f12016-08-11 17:46:05 -0700145 if (k == 8 && (i % 9) == 0) {
Peter de Rivaza7b2d092014-10-16 13:38:46 +0100146 max_val >>= 1;
147 }
148 block_size = 16 << (i % 9); // All block sizes from 4x4, 8x4 ..64x64
149 for (int j = 0; j < block_size; j++) {
Geza Loreaa8f8522015-10-15 18:28:31 +0100150 if (k < 4) {
151 // Test at positive maximum values
clang-format3a826f12016-08-11 17:46:05 -0700152 coeff[j] = k % 2 ? max_val : 0;
Geza Loreaa8f8522015-10-15 18:28:31 +0100153 dqcoeff[j] = (k >> 1) % 2 ? max_val : 0;
154 } else if (k < 8) {
155 // Test at negative maximum values
clang-format3a826f12016-08-11 17:46:05 -0700156 coeff[j] = k % 2 ? -max_val : 0;
Geza Loreaa8f8522015-10-15 18:28:31 +0100157 dqcoeff[j] = (k >> 1) % 2 ? -max_val : 0;
Peter de Rivaza7b2d092014-10-16 13:38:46 +0100158 } else {
Geza Loreaa8f8522015-10-15 18:28:31 +0100159 if (rnd(2)) {
160 // Positive number
clang-format3a826f12016-08-11 17:46:05 -0700161 coeff[j] = rnd(1 << 14);
Geza Loreaa8f8522015-10-15 18:28:31 +0100162 dqcoeff[j] = rnd(1 << 14);
163 } else {
164 // Negative number
clang-format3a826f12016-08-11 17:46:05 -0700165 coeff[j] = -rnd(1 << 14);
Geza Loreaa8f8522015-10-15 18:28:31 +0100166 dqcoeff[j] = -rnd(1 << 14);
167 }
Peter de Rivaza7b2d092014-10-16 13:38:46 +0100168 }
169 }
clang-format3a826f12016-08-11 17:46:05 -0700170 ref_ret =
171 ref_error_block_op_(coeff, dqcoeff, block_size, &ref_ssz, bit_depth_);
chiyotsaief261062021-07-01 14:01:45 -0700172 API_REGISTER_STATE_CHECK(
clang-format3a826f12016-08-11 17:46:05 -0700173 ret = error_block_op_(coeff, dqcoeff, block_size, &ssz, bit_depth_));
Peter de Rivaza7b2d092014-10-16 13:38:46 +0100174 err_count += (ref_ret != ret) | (ref_ssz != ssz);
175 if (err_count && !err_count_total) {
176 first_failure = i;
177 }
178 err_count_total += err_count;
179 }
180 EXPECT_EQ(0, err_count_total)
Geza Loreaa8f8522015-10-15 18:28:31 +0100181 << "Error: Error Block Test, C output doesn't match optimized output. "
Peter de Rivaza7b2d092014-10-16 13:38:46 +0100182 << "First failed at test case " << first_failure;
183}
184
Aniket Dhok3054fcf2019-02-12 10:15:23 +0530185TEST_P(ErrorBlockTest, DISABLED_Speed) {
186 ACMRandom rnd(ACMRandom::DeterministicSeed());
187 DECLARE_ALIGNED(16, tran_low_t, coeff[4096]);
188 DECLARE_ALIGNED(16, tran_low_t, dqcoeff[4096]);
189 intptr_t block_size;
190 int64_t ssz;
191 int num_iters = 100000;
192 int64_t ref_ssz;
193 int k;
194 const int msb = bit_depth_ + 8 - 1;
195 for (int i = 0; i < 9; ++i) {
196 block_size = 16 << (i % 9); // All block sizes from 4x4, 8x4 ..64x64
197 for (k = 0; k < 9; k++) {
198 for (int j = 0; j < block_size; j++) {
199 if (k < 5) {
200 if (rnd(2)) {
201 // Positive number
202 coeff[j] = rnd(1 << msb);
203 dqcoeff[j] = rnd(1 << msb);
204 } else {
205 // Negative number
206 coeff[j] = -rnd(1 << msb);
207 dqcoeff[j] = -rnd(1 << msb);
208 }
209 } else {
210 if (rnd(2)) {
211 // Positive number
212 coeff[j] = rnd(1 << 14);
213 dqcoeff[j] = rnd(1 << 14);
214 } else {
215 // Negative number
216 coeff[j] = -rnd(1 << 14);
217 dqcoeff[j] = -rnd(1 << 14);
218 }
219 }
220 }
221 aom_usec_timer ref_timer, test_timer;
222
223 aom_usec_timer_start(&ref_timer);
224 for (int i = 0; i < num_iters; ++i) {
225 ref_error_block_op_(coeff, dqcoeff, block_size, &ref_ssz, bit_depth_);
226 }
227 aom_usec_timer_mark(&ref_timer);
228 const int elapsed_time_c =
229 static_cast<int>(aom_usec_timer_elapsed(&ref_timer));
230
231 aom_usec_timer_start(&test_timer);
232 for (int i = 0; i < num_iters; ++i) {
233 error_block_op_(coeff, dqcoeff, block_size, &ssz, bit_depth_);
234 }
235 aom_usec_timer_mark(&test_timer);
236
237 const int elapsed_time_simd =
238 static_cast<int>(aom_usec_timer_elapsed(&test_timer));
239
240 printf(
241 " c_time=%d \t simd_time=%d \t "
242 "gain=%d \n",
243 elapsed_time_c, elapsed_time_simd,
244 (elapsed_time_c / elapsed_time_simd));
245 }
246 }
247}
248
sarahparkera543df52018-11-02 16:02:05 -0700249using std::make_tuple;
Peter de Rivaza7b2d092014-10-16 13:38:46 +0100250
Jerome Jiang58f2feb2019-07-22 16:29:51 -0700251#if (HAVE_SSE2)
James Zern6e632d32019-09-20 23:04:52 -0700252const ErrorBlockParam kErrorBlockTestParamsSse2[] = {
Jerome Jiang7683ed52019-09-17 15:10:25 -0700253#if CONFIG_AV1_HIGHBITDEPTH
James Zern6e632d32019-09-20 23:04:52 -0700254 make_tuple(&av1_highbd_block_error_sse2, &av1_highbd_block_error_c,
255 AOM_BITS_10),
256 make_tuple(&av1_highbd_block_error_sse2, &av1_highbd_block_error_c,
257 AOM_BITS_12),
258 make_tuple(&av1_highbd_block_error_sse2, &av1_highbd_block_error_c,
259 AOM_BITS_8),
Jerome Jiang7683ed52019-09-17 15:10:25 -0700260#endif
James Zern6e632d32019-09-20 23:04:52 -0700261 make_tuple(&BlockError8BitWrapper<av1_block_error_sse2>,
chiyotsai3f311042021-09-29 11:50:24 -0700262 &BlockError8BitWrapper<av1_block_error_c>, AOM_BITS_8),
263 make_tuple(&BlockErrorLpWrapper<av1_block_error_lp_sse2>,
264 &BlockErrorLpWrapper<av1_block_error_lp_c>, AOM_BITS_8)
James Zern6e632d32019-09-20 23:04:52 -0700265};
266
Cheng Chen96786fe2020-02-14 17:28:25 -0800267INSTANTIATE_TEST_SUITE_P(SSE2, ErrorBlockTest,
268 ::testing::ValuesIn(kErrorBlockTestParamsSse2));
Peter de Rivaza7b2d092014-10-16 13:38:46 +0100269#endif // HAVE_SSE2
Aniket Dhok3054fcf2019-02-12 10:15:23 +0530270
271#if (HAVE_AVX2)
James Zern6e632d32019-09-20 23:04:52 -0700272const ErrorBlockParam kErrorBlockTestParamsAvx2[] = {
Jerome Jiang7683ed52019-09-17 15:10:25 -0700273#if CONFIG_AV1_HIGHBITDEPTH
James Zern6e632d32019-09-20 23:04:52 -0700274 make_tuple(&av1_highbd_block_error_avx2, &av1_highbd_block_error_c,
275 AOM_BITS_10),
276 make_tuple(&av1_highbd_block_error_avx2, &av1_highbd_block_error_c,
277 AOM_BITS_12),
278 make_tuple(&av1_highbd_block_error_avx2, &av1_highbd_block_error_c,
279 AOM_BITS_8),
Jerome Jiang7683ed52019-09-17 15:10:25 -0700280#endif
James Zern6e632d32019-09-20 23:04:52 -0700281 make_tuple(&BlockError8BitWrapper<av1_block_error_avx2>,
chiyotsai65078e22021-09-29 10:36:53 -0700282 &BlockError8BitWrapper<av1_block_error_c>, AOM_BITS_8),
283 make_tuple(&BlockErrorLpWrapper<av1_block_error_lp_avx2>,
284 &BlockErrorLpWrapper<av1_block_error_lp_c>, AOM_BITS_8)
James Zern6e632d32019-09-20 23:04:52 -0700285};
286
Cheng Chen96786fe2020-02-14 17:28:25 -0800287INSTANTIATE_TEST_SUITE_P(AVX2, ErrorBlockTest,
288 ::testing::ValuesIn(kErrorBlockTestParamsAvx2));
Aniket Dhok3054fcf2019-02-12 10:15:23 +0530289#endif // HAVE_AVX2
Jerome Jiang44a8d5c2019-07-01 17:21:14 -0700290
Jerome Jiang44a8d5c2019-07-01 17:21:14 -0700291#if (HAVE_NEON)
chiyotsai65078e22021-09-29 10:36:53 -0700292const ErrorBlockParam kErrorBlockTestParamsNeon[] = {
293 make_tuple(&BlockError8BitWrapper<av1_block_error_neon>,
294 &BlockError8BitWrapper<av1_block_error_c>, AOM_BITS_8),
295 make_tuple(&BlockErrorLpWrapper<av1_block_error_lp_neon>,
296 &BlockErrorLpWrapper<av1_block_error_lp_c>, AOM_BITS_8)
297};
298
299INSTANTIATE_TEST_SUITE_P(NEON, ErrorBlockTest,
300 ::testing::ValuesIn(kErrorBlockTestParamsNeon));
Jerome Jiang44a8d5c2019-07-01 17:21:14 -0700301#endif // HAVE_NEON
Peter de Rivaza7b2d092014-10-16 13:38:46 +0100302} // namespace