2 * Copyright (c) 2012 The WebM project authors. All Rights Reserved.
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.
15 #include "third_party/googletest/src/include/gtest/gtest.h"
16 #include "test/acm_random.h"
17 #include "test/clear_system_state.h"
18 #include "test/register_state_check.h"
19 #include "test/util.h"
21 #include "./vp9_rtcd.h"
22 #include "vp9/common/vp9_entropy.h"
23 #include "vpx/vpx_integer.h"
26 void vp9_idct8x8_64_add_c(const int16_t *input
, uint8_t *output
, int pitch
);
29 using libvpx_test::ACMRandom
;
32 typedef void (*fdct_t
)(const int16_t *in
, int16_t *out
, int stride
);
33 typedef void (*idct_t
)(const int16_t *in
, uint8_t *out
, int stride
);
34 typedef void (*fht_t
) (const int16_t *in
, int16_t *out
, int stride
,
36 typedef void (*iht_t
) (const int16_t *in
, uint8_t *out
, int stride
,
39 typedef std::tr1::tuple
<fdct_t
, idct_t
, int> dct_8x8_param_t
;
40 typedef std::tr1::tuple
<fht_t
, iht_t
, int> ht_8x8_param_t
;
42 void fdct8x8_ref(const int16_t *in
, int16_t *out
, int stride
, int tx_type
) {
43 vp9_fdct8x8_c(in
, out
, stride
);
46 void fht8x8_ref(const int16_t *in
, int16_t *out
, int stride
, int tx_type
) {
47 vp9_fht8x8_c(in
, out
, stride
, tx_type
);
50 class FwdTrans8x8TestBase
{
52 virtual ~FwdTrans8x8TestBase() {}
55 virtual void RunFwdTxfm(int16_t *in
, int16_t *out
, int stride
) = 0;
56 virtual void RunInvTxfm(int16_t *out
, uint8_t *dst
, int stride
) = 0;
58 void RunSignBiasCheck() {
59 ACMRandom
rnd(ACMRandom::DeterministicSeed());
60 DECLARE_ALIGNED_ARRAY(16, int16_t, test_input_block
, 64);
61 DECLARE_ALIGNED_ARRAY(16, int16_t, test_output_block
, 64);
62 int count_sign_block
[64][2];
63 const int count_test_block
= 100000;
65 memset(count_sign_block
, 0, sizeof(count_sign_block
));
67 for (int i
= 0; i
< count_test_block
; ++i
) {
68 // Initialize a test block with input range [-255, 255].
69 for (int j
= 0; j
< 64; ++j
)
70 test_input_block
[j
] = rnd
.Rand8() - rnd
.Rand8();
72 RunFwdTxfm(test_input_block
, test_output_block
, pitch_
));
74 for (int j
= 0; j
< 64; ++j
) {
75 if (test_output_block
[j
] < 0)
76 ++count_sign_block
[j
][0];
77 else if (test_output_block
[j
] > 0)
78 ++count_sign_block
[j
][1];
82 for (int j
= 0; j
< 64; ++j
) {
83 const int diff
= abs(count_sign_block
[j
][0] - count_sign_block
[j
][1]);
84 const int max_diff
= 1125;
85 EXPECT_LT(diff
, max_diff
)
86 << "Error: 8x8 FDCT/FHT has a sign bias > "
87 << 1. * max_diff
/ count_test_block
* 100 << "%"
88 << " for input range [-255, 255] at index " << j
89 << " count0: " << count_sign_block
[j
][0]
90 << " count1: " << count_sign_block
[j
][1]
94 memset(count_sign_block
, 0, sizeof(count_sign_block
));
96 for (int i
= 0; i
< count_test_block
; ++i
) {
97 // Initialize a test block with input range [-15, 15].
98 for (int j
= 0; j
< 64; ++j
)
99 test_input_block
[j
] = (rnd
.Rand8() >> 4) - (rnd
.Rand8() >> 4);
100 REGISTER_STATE_CHECK(
101 RunFwdTxfm(test_input_block
, test_output_block
, pitch_
));
103 for (int j
= 0; j
< 64; ++j
) {
104 if (test_output_block
[j
] < 0)
105 ++count_sign_block
[j
][0];
106 else if (test_output_block
[j
] > 0)
107 ++count_sign_block
[j
][1];
111 for (int j
= 0; j
< 64; ++j
) {
112 const int diff
= abs(count_sign_block
[j
][0] - count_sign_block
[j
][1]);
113 const int max_diff
= 10000;
114 EXPECT_LT(diff
, max_diff
)
115 << "Error: 4x4 FDCT/FHT has a sign bias > "
116 << 1. * max_diff
/ count_test_block
* 100 << "%"
117 << " for input range [-15, 15] at index " << j
118 << " count0: " << count_sign_block
[j
][0]
119 << " count1: " << count_sign_block
[j
][1]
120 << " diff: " << diff
;
124 void RunRoundTripErrorCheck() {
125 ACMRandom
rnd(ACMRandom::DeterministicSeed());
128 const int count_test_block
= 100000;
129 DECLARE_ALIGNED_ARRAY(16, int16_t, test_input_block
, 64);
130 DECLARE_ALIGNED_ARRAY(16, int16_t, test_temp_block
, 64);
131 DECLARE_ALIGNED_ARRAY(16, uint8_t, dst
, 64);
132 DECLARE_ALIGNED_ARRAY(16, uint8_t, src
, 64);
134 for (int i
= 0; i
< count_test_block
; ++i
) {
135 // Initialize a test block with input range [-255, 255].
136 for (int j
= 0; j
< 64; ++j
) {
137 src
[j
] = rnd
.Rand8();
138 dst
[j
] = rnd
.Rand8();
139 test_input_block
[j
] = src
[j
] - dst
[j
];
142 REGISTER_STATE_CHECK(
143 RunFwdTxfm(test_input_block
, test_temp_block
, pitch_
));
144 for (int j
= 0; j
< 64; ++j
) {
145 if (test_temp_block
[j
] > 0) {
146 test_temp_block
[j
] += 2;
147 test_temp_block
[j
] /= 4;
148 test_temp_block
[j
] *= 4;
150 test_temp_block
[j
] -= 2;
151 test_temp_block
[j
] /= 4;
152 test_temp_block
[j
] *= 4;
155 REGISTER_STATE_CHECK(
156 RunInvTxfm(test_temp_block
, dst
, pitch_
));
158 for (int j
= 0; j
< 64; ++j
) {
159 const int diff
= dst
[j
] - src
[j
];
160 const int error
= diff
* diff
;
161 if (max_error
< error
)
163 total_error
+= error
;
167 EXPECT_GE(1, max_error
)
168 << "Error: 8x8 FDCT/IDCT or FHT/IHT has an individual"
169 << " roundtrip error > 1";
171 EXPECT_GE(count_test_block
/5, total_error
)
172 << "Error: 8x8 FDCT/IDCT or FHT/IHT has average roundtrip "
173 << "error > 1/5 per block";
176 void RunExtremalCheck() {
177 ACMRandom
rnd(ACMRandom::DeterministicSeed());
180 int total_coeff_error
= 0;
181 const int count_test_block
= 100000;
182 DECLARE_ALIGNED_ARRAY(16, int16_t, test_input_block
, 64);
183 DECLARE_ALIGNED_ARRAY(16, int16_t, test_temp_block
, 64);
184 DECLARE_ALIGNED_ARRAY(16, int16_t, ref_temp_block
, 64);
185 DECLARE_ALIGNED_ARRAY(16, uint8_t, dst
, 64);
186 DECLARE_ALIGNED_ARRAY(16, uint8_t, src
, 64);
188 for (int i
= 0; i
< count_test_block
; ++i
) {
189 // Initialize a test block with input range [-255, 255].
190 for (int j
= 0; j
< 64; ++j
) {
198 src
[j
] = rnd
.Rand8() % 2 ? 255 : 0;
199 dst
[j
] = rnd
.Rand8() % 2 ? 255 : 0;
202 test_input_block
[j
] = src
[j
] - dst
[j
];
205 REGISTER_STATE_CHECK(
206 RunFwdTxfm(test_input_block
, test_temp_block
, pitch_
));
207 REGISTER_STATE_CHECK(
208 fwd_txfm_ref(test_input_block
, ref_temp_block
, pitch_
, tx_type_
));
209 REGISTER_STATE_CHECK(
210 RunInvTxfm(test_temp_block
, dst
, pitch_
));
212 for (int j
= 0; j
< 64; ++j
) {
213 const int diff
= dst
[j
] - src
[j
];
214 const int error
= diff
* diff
;
215 if (max_error
< error
)
217 total_error
+= error
;
219 const int coeff_diff
= test_temp_block
[j
] - ref_temp_block
[j
];
220 total_coeff_error
+= abs(coeff_diff
);
223 EXPECT_GE(1, max_error
)
224 << "Error: Extremal 8x8 FDCT/IDCT or FHT/IHT has"
225 << "an individual roundtrip error > 1";
227 EXPECT_GE(count_test_block
/5, total_error
)
228 << "Error: Extremal 8x8 FDCT/IDCT or FHT/IHT has average"
229 << " roundtrip error > 1/5 per block";
231 EXPECT_EQ(0, total_coeff_error
)
232 << "Error: Extremal 8x8 FDCT/FHT has"
233 << "overflow issues in the intermediate steps > 1";
243 : public FwdTrans8x8TestBase
,
244 public ::testing::TestWithParam
<dct_8x8_param_t
> {
246 virtual ~FwdTrans8x8DCT() {}
248 virtual void SetUp() {
249 fwd_txfm_
= GET_PARAM(0);
250 inv_txfm_
= GET_PARAM(1);
251 tx_type_
= GET_PARAM(2);
253 fwd_txfm_ref
= fdct8x8_ref
;
256 virtual void TearDown() { libvpx_test::ClearSystemState(); }
259 void RunFwdTxfm(int16_t *in
, int16_t *out
, int stride
) {
260 fwd_txfm_(in
, out
, stride
);
262 void RunInvTxfm(int16_t *out
, uint8_t *dst
, int stride
) {
263 inv_txfm_(out
, dst
, stride
);
270 TEST_P(FwdTrans8x8DCT
, SignBiasCheck
) {
274 TEST_P(FwdTrans8x8DCT
, RoundTripErrorCheck
) {
275 RunRoundTripErrorCheck();
278 TEST_P(FwdTrans8x8DCT
, ExtremalCheck
) {
283 : public FwdTrans8x8TestBase
,
284 public ::testing::TestWithParam
<ht_8x8_param_t
> {
286 virtual ~FwdTrans8x8HT() {}
288 virtual void SetUp() {
289 fwd_txfm_
= GET_PARAM(0);
290 inv_txfm_
= GET_PARAM(1);
291 tx_type_
= GET_PARAM(2);
293 fwd_txfm_ref
= fht8x8_ref
;
296 virtual void TearDown() { libvpx_test::ClearSystemState(); }
299 void RunFwdTxfm(int16_t *in
, int16_t *out
, int stride
) {
300 fwd_txfm_(in
, out
, stride
, tx_type_
);
302 void RunInvTxfm(int16_t *out
, uint8_t *dst
, int stride
) {
303 inv_txfm_(out
, dst
, stride
, tx_type_
);
310 TEST_P(FwdTrans8x8HT
, SignBiasCheck
) {
314 TEST_P(FwdTrans8x8HT
, RoundTripErrorCheck
) {
315 RunRoundTripErrorCheck();
318 TEST_P(FwdTrans8x8HT
, ExtremalCheck
) {
322 using std::tr1::make_tuple
;
324 INSTANTIATE_TEST_CASE_P(
327 make_tuple(&vp9_fdct8x8_c
, &vp9_idct8x8_64_add_c
, 0)));
328 INSTANTIATE_TEST_CASE_P(
331 make_tuple(&vp9_fht8x8_c
, &vp9_iht8x8_64_add_c
, 0),
332 make_tuple(&vp9_fht8x8_c
, &vp9_iht8x8_64_add_c
, 1),
333 make_tuple(&vp9_fht8x8_c
, &vp9_iht8x8_64_add_c
, 2),
334 make_tuple(&vp9_fht8x8_c
, &vp9_iht8x8_64_add_c
, 3)));
337 INSTANTIATE_TEST_CASE_P(
338 NEON
, FwdTrans8x8DCT
,
340 make_tuple(&vp9_fdct8x8_c
, &vp9_idct8x8_64_add_neon
, 0)));
341 INSTANTIATE_TEST_CASE_P(
342 DISABLED_NEON
, FwdTrans8x8HT
,
344 make_tuple(&vp9_fht8x8_c
, &vp9_iht8x8_64_add_neon
, 0),
345 make_tuple(&vp9_fht8x8_c
, &vp9_iht8x8_64_add_neon
, 1),
346 make_tuple(&vp9_fht8x8_c
, &vp9_iht8x8_64_add_neon
, 2),
347 make_tuple(&vp9_fht8x8_c
, &vp9_iht8x8_64_add_neon
, 3)));
351 INSTANTIATE_TEST_CASE_P(
352 SSE2
, FwdTrans8x8DCT
,
354 make_tuple(&vp9_fdct8x8_sse2
, &vp9_idct8x8_64_add_sse2
, 0)));
355 INSTANTIATE_TEST_CASE_P(
358 make_tuple(&vp9_fht8x8_sse2
, &vp9_iht8x8_64_add_sse2
, 0),
359 make_tuple(&vp9_fht8x8_sse2
, &vp9_iht8x8_64_add_sse2
, 1),
360 make_tuple(&vp9_fht8x8_sse2
, &vp9_iht8x8_64_add_sse2
, 2),
361 make_tuple(&vp9_fht8x8_sse2
, &vp9_iht8x8_64_add_sse2
, 3)));
364 #if HAVE_SSSE3 && ARCH_X86_64
365 INSTANTIATE_TEST_CASE_P(
366 SSSE3
, FwdTrans8x8DCT
,
368 make_tuple(&vp9_fdct8x8_ssse3
, &vp9_idct8x8_64_add_ssse3
, 0)));
372 INSTANTIATE_TEST_CASE_P(
373 AVX2
, FwdTrans8x8DCT
,
375 make_tuple(&vp9_fdct8x8_avx2
, &vp9_idct8x8_64_add_c
, 0)));
376 INSTANTIATE_TEST_CASE_P(
379 make_tuple(&vp9_fht8x8_avx2
, &vp9_iht8x8_64_add_c
, 0),
380 make_tuple(&vp9_fht8x8_avx2
, &vp9_iht8x8_64_add_c
, 1),
381 make_tuple(&vp9_fht8x8_avx2
, &vp9_iht8x8_64_add_c
, 2),
382 make_tuple(&vp9_fht8x8_avx2
, &vp9_iht8x8_64_add_c
, 3)));