Added vp9_fdct8x8_neon(), vp9_fdct8x8_1_neon()
[aom.git] / test / fdct8x8_test.cc
blob567e5f6986511f64c0577915ba9caa2081f0c3e5
1 /*
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.
9 */
11 #include <math.h>
12 #include <stdlib.h>
13 #include <string.h>
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"
25 extern "C" {
26 void vp9_idct8x8_64_add_c(const int16_t *input, uint8_t *output, int pitch);
29 using libvpx_test::ACMRandom;
31 namespace {
32 typedef void (*FdctFunc)(const int16_t *in, int16_t *out, int stride);
33 typedef void (*IdctFunc)(const int16_t *in, uint8_t *out, int stride);
34 typedef void (*FhtFunc)(const int16_t *in, int16_t *out, int stride,
35 int tx_type);
36 typedef void (*IhtFunc)(const int16_t *in, uint8_t *out, int stride,
37 int tx_type);
39 typedef std::tr1::tuple<FdctFunc, IdctFunc, int> Dct8x8Param;
40 typedef std::tr1::tuple<FhtFunc, IhtFunc, int> Ht8x8Param;
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 {
51 public:
52 virtual ~FwdTrans8x8TestBase() {}
54 protected:
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();
71 ASM_REGISTER_STATE_CHECK(
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]
91 << " diff: " << diff;
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 ASM_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());
126 int max_error = 0;
127 int total_error = 0;
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 ASM_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;
149 } else {
150 test_temp_block[j] -= 2;
151 test_temp_block[j] /= 4;
152 test_temp_block[j] *= 4;
155 ASM_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)
162 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());
178 int max_error = 0;
179 int total_error = 0;
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) {
191 if (i == 0) {
192 src[j] = 255;
193 dst[j] = 0;
194 } else if (i == 1) {
195 src[j] = 0;
196 dst[j] = 255;
197 } else {
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 ASM_REGISTER_STATE_CHECK(
206 RunFwdTxfm(test_input_block, test_temp_block, pitch_));
207 ASM_REGISTER_STATE_CHECK(
208 fwd_txfm_ref(test_input_block, ref_temp_block, pitch_, tx_type_));
209 ASM_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)
216 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";
237 int pitch_;
238 int tx_type_;
239 FhtFunc fwd_txfm_ref;
242 class FwdTrans8x8DCT
243 : public FwdTrans8x8TestBase,
244 public ::testing::TestWithParam<Dct8x8Param> {
245 public:
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);
252 pitch_ = 8;
253 fwd_txfm_ref = fdct8x8_ref;
256 virtual void TearDown() { libvpx_test::ClearSystemState(); }
258 protected:
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);
266 FdctFunc fwd_txfm_;
267 IdctFunc inv_txfm_;
270 TEST_P(FwdTrans8x8DCT, SignBiasCheck) {
271 RunSignBiasCheck();
274 TEST_P(FwdTrans8x8DCT, RoundTripErrorCheck) {
275 RunRoundTripErrorCheck();
278 TEST_P(FwdTrans8x8DCT, ExtremalCheck) {
279 RunExtremalCheck();
282 class FwdTrans8x8HT
283 : public FwdTrans8x8TestBase,
284 public ::testing::TestWithParam<Ht8x8Param> {
285 public:
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);
292 pitch_ = 8;
293 fwd_txfm_ref = fht8x8_ref;
296 virtual void TearDown() { libvpx_test::ClearSystemState(); }
298 protected:
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_);
306 FhtFunc fwd_txfm_;
307 IhtFunc inv_txfm_;
310 TEST_P(FwdTrans8x8HT, SignBiasCheck) {
311 RunSignBiasCheck();
314 TEST_P(FwdTrans8x8HT, RoundTripErrorCheck) {
315 RunRoundTripErrorCheck();
318 TEST_P(FwdTrans8x8HT, ExtremalCheck) {
319 RunExtremalCheck();
322 using std::tr1::make_tuple;
324 INSTANTIATE_TEST_CASE_P(
325 C, FwdTrans8x8DCT,
326 ::testing::Values(
327 make_tuple(&vp9_fdct8x8_c, &vp9_idct8x8_64_add_c, 0)));
328 INSTANTIATE_TEST_CASE_P(
329 C, FwdTrans8x8HT,
330 ::testing::Values(
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)));
336 #if HAVE_NEON_ASM
337 INSTANTIATE_TEST_CASE_P(
338 NEON, FwdTrans8x8DCT,
339 ::testing::Values(
340 make_tuple(&vp9_fdct8x8_neon, &vp9_idct8x8_64_add_neon, 0)));
341 INSTANTIATE_TEST_CASE_P(
342 DISABLED_NEON, FwdTrans8x8HT,
343 ::testing::Values(
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)));
348 #endif
350 #if HAVE_SSE2
351 INSTANTIATE_TEST_CASE_P(
352 SSE2, FwdTrans8x8DCT,
353 ::testing::Values(
354 make_tuple(&vp9_fdct8x8_sse2, &vp9_idct8x8_64_add_sse2, 0)));
355 INSTANTIATE_TEST_CASE_P(
356 SSE2, FwdTrans8x8HT,
357 ::testing::Values(
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)));
362 #endif
364 #if HAVE_SSSE3 && ARCH_X86_64
365 INSTANTIATE_TEST_CASE_P(
366 SSSE3, FwdTrans8x8DCT,
367 ::testing::Values(
368 make_tuple(&vp9_fdct8x8_ssse3, &vp9_idct8x8_64_add_ssse3, 0)));
369 #endif
370 } // namespace