2 * Copyright (c) 2013 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_blockd.h"
23 #include "vp9/common/vp9_scan.h"
24 #include "vpx/vpx_integer.h"
26 using libvpx_test::ACMRandom;
29 typedef void (*FwdTxfmFunc)(const int16_t *in, tran_low_t *out, int stride);
30 typedef void (*InvTxfmFunc)(const tran_low_t *in, uint8_t *out, int stride);
31 typedef std::tr1::tuple<FwdTxfmFunc,
34 TX_SIZE, int> PartialInvTxfmParam;
35 const int kMaxNumCoeffs = 1024;
36 class PartialIDctTest : public ::testing::TestWithParam<PartialInvTxfmParam> {
38 virtual ~PartialIDctTest() {}
39 virtual void SetUp() {
40 ftxfm_ = GET_PARAM(0);
41 full_itxfm_ = GET_PARAM(1);
42 partial_itxfm_ = GET_PARAM(2);
43 tx_size_ = GET_PARAM(3);
44 last_nonzero_ = GET_PARAM(4);
47 virtual void TearDown() { libvpx_test::ClearSystemState(); }
53 InvTxfmFunc full_itxfm_;
54 InvTxfmFunc partial_itxfm_;
57 TEST_P(PartialIDctTest, RunQuantCheck) {
58 ACMRandom rnd(ACMRandom::DeterministicSeed());
74 FAIL() << "Wrong Size!";
77 DECLARE_ALIGNED_ARRAY(16, tran_low_t, test_coef_block1, kMaxNumCoeffs);
78 DECLARE_ALIGNED_ARRAY(16, tran_low_t, test_coef_block2, kMaxNumCoeffs);
79 DECLARE_ALIGNED_ARRAY(16, uint8_t, dst1, kMaxNumCoeffs);
80 DECLARE_ALIGNED_ARRAY(16, uint8_t, dst2, kMaxNumCoeffs);
82 const int count_test_block = 1000;
83 const int block_size = size * size;
85 DECLARE_ALIGNED_ARRAY(16, int16_t, input_extreme_block, kMaxNumCoeffs);
86 DECLARE_ALIGNED_ARRAY(16, tran_low_t, output_ref_block, kMaxNumCoeffs);
89 for (int i = 0; i < count_test_block; ++i) {
90 // clear out destination buffer
91 memset(dst1, 0, sizeof(*dst1) * block_size);
92 memset(dst2, 0, sizeof(*dst2) * block_size);
93 memset(test_coef_block1, 0, sizeof(*test_coef_block1) * block_size);
94 memset(test_coef_block2, 0, sizeof(*test_coef_block2) * block_size);
96 ACMRandom rnd(ACMRandom::DeterministicSeed());
98 for (int i = 0; i < count_test_block; ++i) {
99 // Initialize a test block with input range [-255, 255].
101 for (int j = 0; j < block_size; ++j)
102 input_extreme_block[j] = 255;
104 for (int j = 0; j < block_size; ++j)
105 input_extreme_block[j] = -255;
107 for (int j = 0; j < block_size; ++j) {
108 input_extreme_block[j] = rnd.Rand8() % 2 ? 255 : -255;
112 ftxfm_(input_extreme_block, output_ref_block, size);
114 // quantization with maximum allowed step sizes
115 test_coef_block1[0] = (output_ref_block[0] / 1336) * 1336;
116 for (int j = 1; j < last_nonzero_; ++j)
117 test_coef_block1[vp9_default_scan_orders[tx_size_].scan[j]]
118 = (output_ref_block[j] / 1828) * 1828;
121 ASM_REGISTER_STATE_CHECK(full_itxfm_(test_coef_block1, dst1, size));
122 ASM_REGISTER_STATE_CHECK(partial_itxfm_(test_coef_block1, dst2, size));
124 for (int j = 0; j < block_size; ++j) {
125 const int diff = dst1[j] - dst2[j];
126 const int error = diff * diff;
127 if (max_error < error)
132 EXPECT_EQ(0, max_error)
133 << "Error: partial inverse transform produces different results";
136 TEST_P(PartialIDctTest, ResultsMatch) {
137 ACMRandom rnd(ACMRandom::DeterministicSeed());
153 FAIL() << "Wrong Size!";
156 DECLARE_ALIGNED_ARRAY(16, tran_low_t, test_coef_block1, kMaxNumCoeffs);
157 DECLARE_ALIGNED_ARRAY(16, tran_low_t, test_coef_block2, kMaxNumCoeffs);
158 DECLARE_ALIGNED_ARRAY(16, uint8_t, dst1, kMaxNumCoeffs);
159 DECLARE_ALIGNED_ARRAY(16, uint8_t, dst2, kMaxNumCoeffs);
160 const int count_test_block = 1000;
161 const int max_coeff = 32766 / 4;
162 const int block_size = size * size;
164 for (int i = 0; i < count_test_block; ++i) {
165 // clear out destination buffer
166 memset(dst1, 0, sizeof(*dst1) * block_size);
167 memset(dst2, 0, sizeof(*dst2) * block_size);
168 memset(test_coef_block1, 0, sizeof(*test_coef_block1) * block_size);
169 memset(test_coef_block2, 0, sizeof(*test_coef_block2) * block_size);
170 int max_energy_leftover = max_coeff * max_coeff;
171 for (int j = 0; j < last_nonzero_; ++j) {
172 int16_t coef = static_cast<int16_t>(sqrt(1.0 * max_energy_leftover) *
173 (rnd.Rand16() - 32768) / 65536);
174 max_energy_leftover -= coef * coef;
175 if (max_energy_leftover < 0) {
176 max_energy_leftover = 0;
179 test_coef_block1[vp9_default_scan_orders[tx_size_].scan[j]] = coef;
182 memcpy(test_coef_block2, test_coef_block1,
183 sizeof(*test_coef_block2) * block_size);
185 ASM_REGISTER_STATE_CHECK(full_itxfm_(test_coef_block1, dst1, size));
186 ASM_REGISTER_STATE_CHECK(partial_itxfm_(test_coef_block2, dst2, size));
188 for (int j = 0; j < block_size; ++j) {
189 const int diff = dst1[j] - dst2[j];
190 const int error = diff * diff;
191 if (max_error < error)
196 EXPECT_EQ(0, max_error)
197 << "Error: partial inverse transform produces different results";
199 using std::tr1::make_tuple;
201 INSTANTIATE_TEST_CASE_P(
204 make_tuple(&vp9_fdct32x32_c,
205 &vp9_idct32x32_1024_add_c,
206 &vp9_idct32x32_34_add_c,
208 make_tuple(&vp9_fdct32x32_c,
209 &vp9_idct32x32_1024_add_c,
210 &vp9_idct32x32_1_add_c,
212 make_tuple(&vp9_fdct16x16_c,
213 &vp9_idct16x16_256_add_c,
214 &vp9_idct16x16_10_add_c,
216 make_tuple(&vp9_fdct16x16_c,
217 &vp9_idct16x16_256_add_c,
218 &vp9_idct16x16_1_add_c,
220 make_tuple(&vp9_fdct8x8_c,
221 &vp9_idct8x8_64_add_c,
222 &vp9_idct8x8_12_add_c,
224 make_tuple(&vp9_fdct8x8_c,
225 &vp9_idct8x8_64_add_c,
226 &vp9_idct8x8_1_add_c,
228 make_tuple(&vp9_fdct4x4_c,
229 &vp9_idct4x4_16_add_c,
230 &vp9_idct4x4_1_add_c,
234 INSTANTIATE_TEST_CASE_P(
235 NEON, PartialIDctTest,
237 make_tuple(&vp9_fdct32x32_c,
238 &vp9_idct32x32_1024_add_c,
239 &vp9_idct32x32_1_add_neon,
241 make_tuple(&vp9_fdct16x16_c,
242 &vp9_idct16x16_256_add_c,
243 &vp9_idct16x16_10_add_neon,
245 make_tuple(&vp9_fdct16x16_c,
246 &vp9_idct16x16_256_add_c,
247 &vp9_idct16x16_1_add_neon,
249 make_tuple(&vp9_fdct8x8_c,
250 &vp9_idct8x8_64_add_c,
251 &vp9_idct8x8_12_add_neon,
253 make_tuple(&vp9_fdct8x8_c,
254 &vp9_idct8x8_64_add_c,
255 &vp9_idct8x8_1_add_neon,
257 make_tuple(&vp9_fdct4x4_c,
258 &vp9_idct4x4_16_add_c,
259 &vp9_idct4x4_1_add_neon,
263 #if HAVE_SSE2 && !CONFIG_VP9_HIGHBITDEPTH
264 INSTANTIATE_TEST_CASE_P(
265 SSE2, PartialIDctTest,
267 make_tuple(&vp9_fdct32x32_c,
268 &vp9_idct32x32_1024_add_c,
269 &vp9_idct32x32_34_add_sse2,
271 make_tuple(&vp9_fdct32x32_c,
272 &vp9_idct32x32_1024_add_c,
273 &vp9_idct32x32_1_add_sse2,
275 make_tuple(&vp9_fdct16x16_c,
276 &vp9_idct16x16_256_add_c,
277 &vp9_idct16x16_10_add_sse2,
279 make_tuple(&vp9_fdct16x16_c,
280 &vp9_idct16x16_256_add_c,
281 &vp9_idct16x16_1_add_sse2,
283 make_tuple(&vp9_fdct8x8_c,
284 &vp9_idct8x8_64_add_c,
285 &vp9_idct8x8_12_add_sse2,
287 make_tuple(&vp9_fdct8x8_c,
288 &vp9_idct8x8_64_add_c,
289 &vp9_idct8x8_1_add_sse2,
291 make_tuple(&vp9_fdct4x4_c,
292 &vp9_idct4x4_16_add_c,
293 &vp9_idct4x4_1_add_sse2,
297 #if HAVE_SSSE3 && ARCH_X86_64 && !CONFIG_VP9_HIGHBITDEPTH
298 INSTANTIATE_TEST_CASE_P(
299 SSSE3_64, PartialIDctTest,
301 make_tuple(&vp9_fdct8x8_c,
302 &vp9_idct8x8_64_add_c,
303 &vp9_idct8x8_12_add_ssse3,
307 #if HAVE_SSSE3 && !CONFIG_VP9_HIGHBITDEPTH
308 INSTANTIATE_TEST_CASE_P(
309 SSSE3, PartialIDctTest,
311 make_tuple(&vp9_fdct16x16_c,
312 &vp9_idct16x16_256_add_c,
313 &vp9_idct16x16_10_add_ssse3,