blob: 8f6c86838e87014e7f38ae6074d4937a6eca74a4 [file] [log] [blame]
Angie Chiang87175ed2015-09-04 14:51:54 -07001/*
Yaowu Xu2ab7ff02016-09-02 12:04:54 -07002 * Copyright (c) 2016, Alliance for Open Media. All rights reserved
Angie Chiang87175ed2015-09-04 14:51:54 -07003 *
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.
10*/
Angie Chiang87175ed2015-09-04 14:51:54 -070011
12#include <math.h>
13#include <stdlib.h>
14#include <string.h>
15
16#include "third_party/googletest/src/include/gtest/gtest.h"
17
Yaowu Xuf883b422016-08-30 14:01:10 -070018#include "./av1_rtcd.h"
19#include "./aom_dsp_rtcd.h"
Angie Chiang87175ed2015-09-04 14:51:54 -070020#include "test/acm_random.h"
21#include "test/clear_system_state.h"
22#include "test/register_state_check.h"
23#include "test/util.h"
Yaowu Xuc27fc142016-08-22 16:08:15 -070024#include "av1/common/blockd.h"
25#include "av1/common/scan.h"
Yaowu Xuf883b422016-08-30 14:01:10 -070026#include "aom/aom_integer.h"
Yi Luoea1167c2016-10-31 16:22:08 -070027#include "aom_dsp/inv_txfm.h"
Angie Chiang87175ed2015-09-04 14:51:54 -070028
Yaowu Xuc27fc142016-08-22 16:08:15 -070029using libaom_test::ACMRandom;
Angie Chiang87175ed2015-09-04 14:51:54 -070030
31namespace {
Angie Chiang87175ed2015-09-04 14:51:54 -070032const double kInvSqrt2 = 0.707106781186547524400844362104;
33
34void reference_idct_1d(const double *in, double *out, int size) {
35 for (int n = 0; n < size; ++n) {
36 out[n] = 0;
37 for (int k = 0; k < size; ++k) {
38 if (k == 0)
39 out[n] += kInvSqrt2 * in[k] * cos(PI * (2 * n + 1) * k / (2 * size));
40 else
41 out[n] += in[k] * cos(PI * (2 * n + 1) * k / (2 * size));
42 }
43 }
44}
45
46typedef void (*IdctFuncRef)(const double *in, double *out, int size);
47typedef void (*IdctFunc)(const tran_low_t *in, tran_low_t *out);
48
49class TransTestBase {
50 public:
51 virtual ~TransTestBase() {}
52
53 protected:
54 void RunInvAccuracyCheck() {
clang-format3a826f12016-08-11 17:46:05 -070055 tran_low_t *input = new tran_low_t[txfm_size_];
Angie Chiang87175ed2015-09-04 14:51:54 -070056 tran_low_t *output = new tran_low_t[txfm_size_];
clang-format3a826f12016-08-11 17:46:05 -070057 double *ref_input = new double[txfm_size_];
Angie Chiang87175ed2015-09-04 14:51:54 -070058 double *ref_output = new double[txfm_size_];
59
60 ACMRandom rnd(ACMRandom::DeterministicSeed());
61 const int count_test_block = 5000;
clang-format3a826f12016-08-11 17:46:05 -070062 for (int ti = 0; ti < count_test_block; ++ti) {
Angie Chiang87175ed2015-09-04 14:51:54 -070063 for (int ni = 0; ni < txfm_size_; ++ni) {
64 input[ni] = rnd.Rand8() - rnd.Rand8();
65 ref_input[ni] = static_cast<double>(input[ni]);
66 }
67
68 fwd_txfm_(input, output);
69 fwd_txfm_ref_(ref_input, ref_output, txfm_size_);
70
71 for (int ni = 0; ni < txfm_size_; ++ni) {
72 EXPECT_LE(
73 abs(output[ni] - static_cast<tran_low_t>(round(ref_output[ni]))),
74 max_error_);
75 }
76 }
77
78 delete[] input;
79 delete[] output;
80 delete[] ref_input;
81 delete[] ref_output;
82 }
83
84 double max_error_;
85 int txfm_size_;
86 IdctFunc fwd_txfm_;
87 IdctFuncRef fwd_txfm_ref_;
88};
89
90typedef std::tr1::tuple<IdctFunc, IdctFuncRef, int, int> IdctParam;
Yaowu Xuf883b422016-08-30 14:01:10 -070091class AV1InvTxfm : public TransTestBase,
92 public ::testing::TestWithParam<IdctParam> {
Angie Chiang87175ed2015-09-04 14:51:54 -070093 public:
94 virtual void SetUp() {
95 fwd_txfm_ = GET_PARAM(0);
96 fwd_txfm_ref_ = GET_PARAM(1);
97 txfm_size_ = GET_PARAM(2);
98 max_error_ = GET_PARAM(3);
99 }
100 virtual void TearDown() {}
101};
102
Yaowu Xuf883b422016-08-30 14:01:10 -0700103TEST_P(AV1InvTxfm, RunInvAccuracyCheck) { RunInvAccuracyCheck(); }
Angie Chiang87175ed2015-09-04 14:51:54 -0700104
105INSTANTIATE_TEST_CASE_P(
Yaowu Xuf883b422016-08-30 14:01:10 -0700106 C, AV1InvTxfm,
Yi Luoea1167c2016-10-31 16:22:08 -0700107 ::testing::Values(IdctParam(&aom_idct4_c, &reference_idct_1d, 4, 1),
108 IdctParam(&aom_idct8_c, &reference_idct_1d, 8, 2),
109 IdctParam(&aom_idct16_c, &reference_idct_1d, 16, 4),
110 IdctParam(&aom_idct32_c, &reference_idct_1d, 32, 6)));
Angie Chiang87175ed2015-09-04 14:51:54 -0700111
James Zernba980612016-05-10 19:07:41 -0700112#if CONFIG_AV1_ENCODER
Angie Chiang87175ed2015-09-04 14:51:54 -0700113typedef void (*FwdTxfmFunc)(const int16_t *in, tran_low_t *out, int stride);
114typedef void (*InvTxfmFunc)(const tran_low_t *in, uint8_t *out, int stride);
clang-format3a826f12016-08-11 17:46:05 -0700115typedef std::tr1::tuple<FwdTxfmFunc, InvTxfmFunc, InvTxfmFunc, TX_SIZE, int>
116 PartialInvTxfmParam;
Angie Chiang87175ed2015-09-04 14:51:54 -0700117const int kMaxNumCoeffs = 1024;
Yaowu Xuf883b422016-08-30 14:01:10 -0700118class AV1PartialIDctTest
Angie Chiang87175ed2015-09-04 14:51:54 -0700119 : public ::testing::TestWithParam<PartialInvTxfmParam> {
120 public:
Yaowu Xuf883b422016-08-30 14:01:10 -0700121 virtual ~AV1PartialIDctTest() {}
Angie Chiang87175ed2015-09-04 14:51:54 -0700122 virtual void SetUp() {
123 ftxfm_ = GET_PARAM(0);
124 full_itxfm_ = GET_PARAM(1);
125 partial_itxfm_ = GET_PARAM(2);
clang-format3a826f12016-08-11 17:46:05 -0700126 tx_size_ = GET_PARAM(3);
Angie Chiang87175ed2015-09-04 14:51:54 -0700127 last_nonzero_ = GET_PARAM(4);
128 }
129
Yaowu Xuc27fc142016-08-22 16:08:15 -0700130 virtual void TearDown() { libaom_test::ClearSystemState(); }
Angie Chiang87175ed2015-09-04 14:51:54 -0700131
132 protected:
133 int last_nonzero_;
134 TX_SIZE tx_size_;
135 FwdTxfmFunc ftxfm_;
136 InvTxfmFunc full_itxfm_;
137 InvTxfmFunc partial_itxfm_;
138};
139
Angie Chianged8cd9a2016-10-21 16:44:47 -0700140#if !CONFIG_ADAPT_SCAN
Yaowu Xuf883b422016-08-30 14:01:10 -0700141TEST_P(AV1PartialIDctTest, RunQuantCheck) {
Angie Chiang87175ed2015-09-04 14:51:54 -0700142 int size;
143 switch (tx_size_) {
clang-format3a826f12016-08-11 17:46:05 -0700144 case TX_4X4: size = 4; break;
145 case TX_8X8: size = 8; break;
146 case TX_16X16: size = 16; break;
147 case TX_32X32: size = 32; break;
148 default: FAIL() << "Wrong Size!"; break;
Angie Chiang87175ed2015-09-04 14:51:54 -0700149 }
150 DECLARE_ALIGNED(16, tran_low_t, test_coef_block1[kMaxNumCoeffs]);
151 DECLARE_ALIGNED(16, tran_low_t, test_coef_block2[kMaxNumCoeffs]);
152 DECLARE_ALIGNED(16, uint8_t, dst1[kMaxNumCoeffs]);
153 DECLARE_ALIGNED(16, uint8_t, dst2[kMaxNumCoeffs]);
154
155 const int count_test_block = 1000;
156 const int block_size = size * size;
157
158 DECLARE_ALIGNED(16, int16_t, input_extreme_block[kMaxNumCoeffs]);
159 DECLARE_ALIGNED(16, tran_low_t, output_ref_block[kMaxNumCoeffs]);
160
161 int max_error = 0;
Urvang Joshi88a03bb2016-10-17 14:34:48 -0700162 for (int m = 0; m < count_test_block; ++m) {
Angie Chiang87175ed2015-09-04 14:51:54 -0700163 // clear out destination buffer
164 memset(dst1, 0, sizeof(*dst1) * block_size);
165 memset(dst2, 0, sizeof(*dst2) * block_size);
166 memset(test_coef_block1, 0, sizeof(*test_coef_block1) * block_size);
167 memset(test_coef_block2, 0, sizeof(*test_coef_block2) * block_size);
168
169 ACMRandom rnd(ACMRandom::DeterministicSeed());
170
Urvang Joshi88a03bb2016-10-17 14:34:48 -0700171 for (int n = 0; n < count_test_block; ++n) {
Angie Chiang87175ed2015-09-04 14:51:54 -0700172 // Initialize a test block with input range [-255, 255].
Urvang Joshi88a03bb2016-10-17 14:34:48 -0700173 if (n == 0) {
clang-format3a826f12016-08-11 17:46:05 -0700174 for (int j = 0; j < block_size; ++j) input_extreme_block[j] = 255;
Urvang Joshi88a03bb2016-10-17 14:34:48 -0700175 } else if (n == 1) {
clang-format3a826f12016-08-11 17:46:05 -0700176 for (int j = 0; j < block_size; ++j) input_extreme_block[j] = -255;
Angie Chiang87175ed2015-09-04 14:51:54 -0700177 } else {
178 for (int j = 0; j < block_size; ++j) {
179 input_extreme_block[j] = rnd.Rand8() % 2 ? 255 : -255;
180 }
181 }
182
183 ftxfm_(input_extreme_block, output_ref_block, size);
184
185 // quantization with maximum allowed step sizes
186 test_coef_block1[0] = (output_ref_block[0] / 1336) * 1336;
187 for (int j = 1; j < last_nonzero_; ++j)
Angie Chiangff6d8902016-10-21 11:02:09 -0700188 test_coef_block1[get_scan((const AV1_COMMON *)NULL, tx_size_, DCT_DCT,
189 0)
190 ->scan[j]] = (output_ref_block[j] / 1828) * 1828;
Angie Chiang87175ed2015-09-04 14:51:54 -0700191 }
192
193 ASM_REGISTER_STATE_CHECK(full_itxfm_(test_coef_block1, dst1, size));
194 ASM_REGISTER_STATE_CHECK(partial_itxfm_(test_coef_block1, dst2, size));
195
196 for (int j = 0; j < block_size; ++j) {
197 const int diff = dst1[j] - dst2[j];
198 const int error = diff * diff;
clang-format3a826f12016-08-11 17:46:05 -0700199 if (max_error < error) max_error = error;
Angie Chiang87175ed2015-09-04 14:51:54 -0700200 }
201 }
202
203 EXPECT_EQ(0, max_error)
204 << "Error: partial inverse transform produces different results";
205}
206
Yaowu Xuf883b422016-08-30 14:01:10 -0700207TEST_P(AV1PartialIDctTest, ResultsMatch) {
Angie Chiang87175ed2015-09-04 14:51:54 -0700208 ACMRandom rnd(ACMRandom::DeterministicSeed());
209 int size;
210 switch (tx_size_) {
clang-format3a826f12016-08-11 17:46:05 -0700211 case TX_4X4: size = 4; break;
212 case TX_8X8: size = 8; break;
213 case TX_16X16: size = 16; break;
214 case TX_32X32: size = 32; break;
215 default: FAIL() << "Wrong Size!"; break;
Angie Chiang87175ed2015-09-04 14:51:54 -0700216 }
217 DECLARE_ALIGNED(16, tran_low_t, test_coef_block1[kMaxNumCoeffs]);
218 DECLARE_ALIGNED(16, tran_low_t, test_coef_block2[kMaxNumCoeffs]);
219 DECLARE_ALIGNED(16, uint8_t, dst1[kMaxNumCoeffs]);
220 DECLARE_ALIGNED(16, uint8_t, dst2[kMaxNumCoeffs]);
221 const int count_test_block = 1000;
222 const int max_coeff = 32766 / 4;
223 const int block_size = size * size;
224 int max_error = 0;
225 for (int i = 0; i < count_test_block; ++i) {
226 // clear out destination buffer
227 memset(dst1, 0, sizeof(*dst1) * block_size);
228 memset(dst2, 0, sizeof(*dst2) * block_size);
229 memset(test_coef_block1, 0, sizeof(*test_coef_block1) * block_size);
230 memset(test_coef_block2, 0, sizeof(*test_coef_block2) * block_size);
231 int max_energy_leftover = max_coeff * max_coeff;
232 for (int j = 0; j < last_nonzero_; ++j) {
233 int16_t coef = static_cast<int16_t>(sqrt(1.0 * max_energy_leftover) *
234 (rnd.Rand16() - 32768) / 65536);
235 max_energy_leftover -= coef * coef;
236 if (max_energy_leftover < 0) {
237 max_energy_leftover = 0;
238 coef = 0;
239 }
Angie Chiangff6d8902016-10-21 11:02:09 -0700240 test_coef_block1[get_scan((const AV1_COMMON *)NULL, tx_size_, DCT_DCT, 0)
241 ->scan[j]] = coef;
Angie Chiang87175ed2015-09-04 14:51:54 -0700242 }
243
244 memcpy(test_coef_block2, test_coef_block1,
245 sizeof(*test_coef_block2) * block_size);
246
247 ASM_REGISTER_STATE_CHECK(full_itxfm_(test_coef_block1, dst1, size));
248 ASM_REGISTER_STATE_CHECK(partial_itxfm_(test_coef_block2, dst2, size));
249
250 for (int j = 0; j < block_size; ++j) {
251 const int diff = dst1[j] - dst2[j];
252 const int error = diff * diff;
clang-format3a826f12016-08-11 17:46:05 -0700253 if (max_error < error) max_error = error;
Angie Chiang87175ed2015-09-04 14:51:54 -0700254 }
255 }
256
257 EXPECT_EQ(0, max_error)
258 << "Error: partial inverse transform produces different results";
259}
Angie Chianged8cd9a2016-10-21 16:44:47 -0700260#endif
Angie Chiang87175ed2015-09-04 14:51:54 -0700261using std::tr1::make_tuple;
262
263INSTANTIATE_TEST_CASE_P(
Yaowu Xuf883b422016-08-30 14:01:10 -0700264 C, AV1PartialIDctTest,
Yi Luoea1167c2016-10-31 16:22:08 -0700265 ::testing::Values(make_tuple(&aom_fdct32x32_c, &aom_idct32x32_1024_add_c,
266 &aom_idct32x32_34_add_c, TX_32X32, 34),
267 make_tuple(&aom_fdct32x32_c, &aom_idct32x32_1024_add_c,
268 &aom_idct32x32_1_add_c, TX_32X32, 1),
269 make_tuple(&aom_fdct16x16_c, &aom_idct16x16_256_add_c,
270 &aom_idct16x16_10_add_c, TX_16X16, 10),
271 make_tuple(&aom_fdct16x16_c, &aom_idct16x16_256_add_c,
272 &aom_idct16x16_1_add_c, TX_16X16, 1),
273 make_tuple(&aom_fdct8x8_c, &aom_idct8x8_64_add_c,
274 &aom_idct8x8_12_add_c, TX_8X8, 12),
275 make_tuple(&aom_fdct8x8_c, &aom_idct8x8_64_add_c,
276 &aom_idct8x8_1_add_c, TX_8X8, 1),
277 make_tuple(&aom_fdct4x4_c, &aom_idct4x4_16_add_c,
278 &aom_idct4x4_1_add_c, TX_4X4, 1)));
James Zernba980612016-05-10 19:07:41 -0700279#endif // CONFIG_AV1_ENCODER
Angie Chiang87175ed2015-09-04 14:51:54 -0700280} // namespace