a1e472a0aeae13b8bfc34300fcdc3a565d1fff0f
[platform/framework/web/crosswalk.git] / src / third_party / libvpx / source / libvpx / test / dct32x32_test.cc
1 /*
2  *  Copyright (c) 2012 The WebM project authors. All Rights Reserved.
3  *
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  */
10
11 #include <math.h>
12 #include <stdlib.h>
13 #include <string.h>
14
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"
20
21 extern "C" {
22 #include "./vpx_config.h"
23 #include "vp9/common/vp9_entropy.h"
24 #include "./vp9_rtcd.h"
25 }
26
27 #include "vpx/vpx_integer.h"
28
29 using libvpx_test::ACMRandom;
30
31 namespace {
32 #ifdef _MSC_VER
33 static int round(double x) {
34   if (x < 0)
35     return static_cast<int>(ceil(x - 0.5));
36   else
37     return static_cast<int>(floor(x + 0.5));
38 }
39 #endif
40
41 const int kNumCoeffs = 1024;
42 const double kPi = 3.141592653589793238462643383279502884;
43 void reference_32x32_dct_1d(const double in[32], double out[32], int stride) {
44   const double kInvSqrt2 = 0.707106781186547524400844362104;
45   for (int k = 0; k < 32; k++) {
46     out[k] = 0.0;
47     for (int n = 0; n < 32; n++)
48       out[k] += in[n] * cos(kPi * (2 * n + 1) * k / 64.0);
49     if (k == 0)
50       out[k] = out[k] * kInvSqrt2;
51   }
52 }
53
54 void reference_32x32_dct_2d(const int16_t input[kNumCoeffs],
55                             double output[kNumCoeffs]) {
56   // First transform columns
57   for (int i = 0; i < 32; ++i) {
58     double temp_in[32], temp_out[32];
59     for (int j = 0; j < 32; ++j)
60       temp_in[j] = input[j*32 + i];
61     reference_32x32_dct_1d(temp_in, temp_out, 1);
62     for (int j = 0; j < 32; ++j)
63       output[j * 32 + i] = temp_out[j];
64   }
65   // Then transform rows
66   for (int i = 0; i < 32; ++i) {
67     double temp_in[32], temp_out[32];
68     for (int j = 0; j < 32; ++j)
69       temp_in[j] = output[j + i*32];
70     reference_32x32_dct_1d(temp_in, temp_out, 1);
71     // Scale by some magic number
72     for (int j = 0; j < 32; ++j)
73       output[j + i * 32] = temp_out[j] / 4;
74   }
75 }
76
77 typedef void (*fwd_txfm_t)(const int16_t *in, int16_t *out, int stride);
78 typedef void (*inv_txfm_t)(const int16_t *in, uint8_t *out, int stride);
79
80 typedef std::tr1::tuple<fwd_txfm_t, inv_txfm_t, int> trans_32x32_param_t;
81
82 class Trans32x32Test : public ::testing::TestWithParam<trans_32x32_param_t> {
83  public:
84   virtual ~Trans32x32Test() {}
85   virtual void SetUp() {
86     fwd_txfm_ = GET_PARAM(0);
87     inv_txfm_ = GET_PARAM(1);
88     version_  = GET_PARAM(2);  // 0: high precision forward transform
89                                // 1: low precision version for rd loop
90   }
91
92   virtual void TearDown() { libvpx_test::ClearSystemState(); }
93
94  protected:
95   int version_;
96   fwd_txfm_t fwd_txfm_;
97   inv_txfm_t inv_txfm_;
98 };
99
100 TEST_P(Trans32x32Test, AccuracyCheck) {
101   ACMRandom rnd(ACMRandom::DeterministicSeed());
102   uint32_t max_error = 0;
103   int64_t total_error = 0;
104   const int count_test_block = 1000;
105   DECLARE_ALIGNED_ARRAY(16, int16_t, test_input_block, kNumCoeffs);
106   DECLARE_ALIGNED_ARRAY(16, int16_t, test_temp_block, kNumCoeffs);
107   DECLARE_ALIGNED_ARRAY(16, uint8_t, dst, kNumCoeffs);
108   DECLARE_ALIGNED_ARRAY(16, uint8_t, src, kNumCoeffs);
109
110   for (int i = 0; i < count_test_block; ++i) {
111     // Initialize a test block with input range [-255, 255].
112     for (int j = 0; j < kNumCoeffs; ++j) {
113       src[j] = rnd.Rand8();
114       dst[j] = rnd.Rand8();
115       test_input_block[j] = src[j] - dst[j];
116     }
117
118     REGISTER_STATE_CHECK(fwd_txfm_(test_input_block, test_temp_block, 32));
119     REGISTER_STATE_CHECK(inv_txfm_(test_temp_block, dst, 32));
120
121     for (int j = 0; j < kNumCoeffs; ++j) {
122       const uint32_t diff = dst[j] - src[j];
123       const uint32_t error = diff * diff;
124       if (max_error < error)
125         max_error = error;
126       total_error += error;
127     }
128   }
129
130   if (version_ == 1) {
131     max_error /= 2;
132     total_error /= 45;
133   }
134
135   EXPECT_GE(1u, max_error)
136       << "Error: 32x32 FDCT/IDCT has an individual round-trip error > 1";
137
138   EXPECT_GE(count_test_block, total_error)
139       << "Error: 32x32 FDCT/IDCT has average round-trip error > 1 per block";
140 }
141
142 TEST_P(Trans32x32Test, CoeffCheck) {
143   ACMRandom rnd(ACMRandom::DeterministicSeed());
144   const int count_test_block = 1000;
145
146   DECLARE_ALIGNED_ARRAY(16, int16_t, input_block, kNumCoeffs);
147   DECLARE_ALIGNED_ARRAY(16, int16_t, output_ref_block, kNumCoeffs);
148   DECLARE_ALIGNED_ARRAY(16, int16_t, output_block, kNumCoeffs);
149
150   for (int i = 0; i < count_test_block; ++i) {
151     for (int j = 0; j < kNumCoeffs; ++j)
152       input_block[j] = rnd.Rand8() - rnd.Rand8();
153
154     const int stride = 32;
155     vp9_fdct32x32_c(input_block, output_ref_block, stride);
156     REGISTER_STATE_CHECK(fwd_txfm_(input_block, output_block, stride));
157
158     if (version_ == 0) {
159       for (int j = 0; j < kNumCoeffs; ++j)
160         EXPECT_EQ(output_block[j], output_ref_block[j])
161             << "Error: 32x32 FDCT versions have mismatched coefficients";
162     } else {
163       for (int j = 0; j < kNumCoeffs; ++j)
164         EXPECT_GE(6, abs(output_block[j] - output_ref_block[j]))
165             << "Error: 32x32 FDCT rd has mismatched coefficients";
166     }
167   }
168 }
169
170 TEST_P(Trans32x32Test, MemCheck) {
171   ACMRandom rnd(ACMRandom::DeterministicSeed());
172   const int count_test_block = 2000;
173
174   DECLARE_ALIGNED_ARRAY(16, int16_t, input_block, kNumCoeffs);
175   DECLARE_ALIGNED_ARRAY(16, int16_t, input_extreme_block, kNumCoeffs);
176   DECLARE_ALIGNED_ARRAY(16, int16_t, output_ref_block, kNumCoeffs);
177   DECLARE_ALIGNED_ARRAY(16, int16_t, output_block, kNumCoeffs);
178
179   for (int i = 0; i < count_test_block; ++i) {
180     // Initialize a test block with input range [-255, 255].
181     for (int j = 0; j < kNumCoeffs; ++j) {
182       input_block[j] = rnd.Rand8() - rnd.Rand8();
183       input_extreme_block[j] = rnd.Rand8() & 1 ? 255 : -255;
184     }
185     if (i == 0)
186       for (int j = 0; j < kNumCoeffs; ++j)
187         input_extreme_block[j] = 255;
188     if (i == 1)
189       for (int j = 0; j < kNumCoeffs; ++j)
190         input_extreme_block[j] = -255;
191
192     const int stride = 32;
193     vp9_fdct32x32_c(input_extreme_block, output_ref_block, stride);
194     REGISTER_STATE_CHECK(fwd_txfm_(input_extreme_block, output_block, stride));
195
196     // The minimum quant value is 4.
197     for (int j = 0; j < kNumCoeffs; ++j) {
198       if (version_ == 0) {
199         EXPECT_EQ(output_block[j], output_ref_block[j])
200             << "Error: 32x32 FDCT versions have mismatched coefficients";
201       } else {
202         EXPECT_GE(6, abs(output_block[j] - output_ref_block[j]))
203             << "Error: 32x32 FDCT rd has mismatched coefficients";
204       }
205       EXPECT_GE(4 * DCT_MAX_VALUE, abs(output_ref_block[j]))
206           << "Error: 32x32 FDCT C has coefficient larger than 4*DCT_MAX_VALUE";
207       EXPECT_GE(4 * DCT_MAX_VALUE, abs(output_block[j]))
208           << "Error: 32x32 FDCT has coefficient larger than "
209           << "4*DCT_MAX_VALUE";
210     }
211   }
212 }
213
214 TEST_P(Trans32x32Test, InverseAccuracy) {
215   ACMRandom rnd(ACMRandom::DeterministicSeed());
216   const int count_test_block = 1000;
217   DECLARE_ALIGNED_ARRAY(16, int16_t, in, kNumCoeffs);
218   DECLARE_ALIGNED_ARRAY(16, int16_t, coeff, kNumCoeffs);
219   DECLARE_ALIGNED_ARRAY(16, uint8_t, dst, kNumCoeffs);
220   DECLARE_ALIGNED_ARRAY(16, uint8_t, src, kNumCoeffs);
221
222   for (int i = 0; i < count_test_block; ++i) {
223     double out_r[kNumCoeffs];
224
225     // Initialize a test block with input range [-255, 255]
226     for (int j = 0; j < kNumCoeffs; ++j) {
227       src[j] = rnd.Rand8();
228       dst[j] = rnd.Rand8();
229       in[j] = src[j] - dst[j];
230     }
231
232     reference_32x32_dct_2d(in, out_r);
233     for (int j = 0; j < kNumCoeffs; ++j)
234       coeff[j] = round(out_r[j]);
235     REGISTER_STATE_CHECK(inv_txfm_(coeff, dst, 32));
236     for (int j = 0; j < kNumCoeffs; ++j) {
237       const int diff = dst[j] - src[j];
238       const int error = diff * diff;
239       EXPECT_GE(1, error)
240           << "Error: 32x32 IDCT has error " << error
241           << " at index " << j;
242     }
243   }
244 }
245
246 using std::tr1::make_tuple;
247
248 INSTANTIATE_TEST_CASE_P(
249     C, Trans32x32Test,
250     ::testing::Values(
251         make_tuple(&vp9_fdct32x32_c, &vp9_idct32x32_1024_add_c, 0),
252         make_tuple(&vp9_fdct32x32_rd_c, &vp9_idct32x32_1024_add_c, 1)));
253
254 #if HAVE_SSE2
255 INSTANTIATE_TEST_CASE_P(
256     SSE2, Trans32x32Test,
257     ::testing::Values(
258         make_tuple(&vp9_fdct32x32_sse2,
259                    &vp9_idct32x32_1024_add_sse2, 0),
260         make_tuple(&vp9_fdct32x32_rd_sse2,
261                    &vp9_idct32x32_1024_add_sse2, 1)));
262 #endif
263
264 #if HAVE_AVX2
265 INSTANTIATE_TEST_CASE_P(
266     AVX2, Trans32x32Test,
267     ::testing::Values(
268         make_tuple(&vp9_fdct32x32_avx2,
269                    &vp9_idct32x32_1024_add_sse2, 0),
270         make_tuple(&vp9_fdct32x32_rd_avx2,
271                    &vp9_idct32x32_1024_add_sse2, 1)));
272 #endif
273 }  // namespace