1/*
2 *  Copyright (c) 2013 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#include "./vp9_rtcd.h"
22#include "vp9/common/vp9_blockd.h"
23#include "vp9/common/vp9_scan.h"
24#include "vpx/vpx_integer.h"
25
26using libvpx_test::ACMRandom;
27
28namespace {
29typedef void (*fwd_txfm_t)(const int16_t *in, int16_t *out, int stride);
30typedef void (*inv_txfm_t)(const int16_t *in, uint8_t *out, int stride);
31typedef std::tr1::tuple<inv_txfm_t,
32                        inv_txfm_t,
33                        TX_SIZE, int> partial_itxfm_param_t;
34const int kMaxNumCoeffs = 1024;
35class PartialIDctTest : public ::testing::TestWithParam<partial_itxfm_param_t> {
36 public:
37  virtual ~PartialIDctTest() {}
38  virtual void SetUp() {
39    full_itxfm_ = GET_PARAM(0);
40    partial_itxfm_ = GET_PARAM(1);
41    tx_size_  = GET_PARAM(2);
42    last_nonzero_ = GET_PARAM(3);
43  }
44
45  virtual void TearDown() { libvpx_test::ClearSystemState(); }
46
47 protected:
48  int last_nonzero_;
49  TX_SIZE tx_size_;
50  inv_txfm_t full_itxfm_;
51  inv_txfm_t partial_itxfm_;
52};
53
54TEST_P(PartialIDctTest, ResultsMatch) {
55  ACMRandom rnd(ACMRandom::DeterministicSeed());
56  int size;
57  switch (tx_size_) {
58    case TX_4X4:
59      size = 4;
60      break;
61    case TX_8X8:
62      size = 8;
63      break;
64    case TX_16X16:
65      size = 16;
66      break;
67    case TX_32X32:
68      size = 32;
69      break;
70    default:
71      FAIL() << "Wrong Size!";
72      break;
73  }
74  DECLARE_ALIGNED_ARRAY(16, int16_t, test_coef_block1, kMaxNumCoeffs);
75  DECLARE_ALIGNED_ARRAY(16, int16_t, test_coef_block2, kMaxNumCoeffs);
76  DECLARE_ALIGNED_ARRAY(16, uint8_t, dst1, kMaxNumCoeffs);
77  DECLARE_ALIGNED_ARRAY(16, uint8_t, dst2, kMaxNumCoeffs);
78  const int count_test_block = 1000;
79  const int max_coeff = 32766 / 4;
80  const int block_size = size * size;
81  int max_error = 0;
82  for (int i = 0; i < count_test_block; ++i) {
83    // clear out destination buffer
84    memset(dst1, 0, sizeof(*dst1) * block_size);
85    memset(dst2, 0, sizeof(*dst2) * block_size);
86    memset(test_coef_block1, 0, sizeof(*test_coef_block1) * block_size);
87    memset(test_coef_block2, 0, sizeof(*test_coef_block2) * block_size);
88    int max_energy_leftover = max_coeff * max_coeff;
89    for (int j = 0; j < last_nonzero_; ++j) {
90      int16_t coef = static_cast<int16_t>(sqrt(1.0 * max_energy_leftover) *
91                                          (rnd.Rand16() - 32768) / 65536);
92      max_energy_leftover -= coef * coef;
93      if (max_energy_leftover < 0) {
94        max_energy_leftover = 0;
95        coef = 0;
96      }
97      test_coef_block1[vp9_default_scan_orders[tx_size_].scan[j]] = coef;
98    }
99
100    memcpy(test_coef_block2, test_coef_block1,
101           sizeof(*test_coef_block2) * block_size);
102
103    REGISTER_STATE_CHECK(full_itxfm_(test_coef_block1, dst1, size));
104    REGISTER_STATE_CHECK(partial_itxfm_(test_coef_block2, dst2, size));
105
106    for (int j = 0; j < block_size; ++j) {
107      const int diff = dst1[j] - dst2[j];
108      const int error = diff * diff;
109      if (max_error < error)
110        max_error = error;
111    }
112  }
113
114  EXPECT_EQ(0, max_error)
115      << "Error: partial inverse transform produces different results";
116}
117using std::tr1::make_tuple;
118
119INSTANTIATE_TEST_CASE_P(
120    C, PartialIDctTest,
121    ::testing::Values(
122        make_tuple(&vp9_idct32x32_1024_add_c,
123                   &vp9_idct32x32_34_add_c,
124                   TX_32X32, 34),
125        make_tuple(&vp9_idct32x32_1024_add_c,
126                   &vp9_idct32x32_1_add_c,
127                   TX_32X32, 1),
128        make_tuple(&vp9_idct16x16_256_add_c,
129                   &vp9_idct16x16_10_add_c,
130                   TX_16X16, 10),
131        make_tuple(&vp9_idct16x16_256_add_c,
132                   &vp9_idct16x16_1_add_c,
133                   TX_16X16, 1),
134        make_tuple(&vp9_idct8x8_64_add_c,
135                   &vp9_idct8x8_10_add_c,
136                   TX_8X8, 10),
137        make_tuple(&vp9_idct8x8_64_add_c,
138                   &vp9_idct8x8_1_add_c,
139                   TX_8X8, 1),
140        make_tuple(&vp9_idct4x4_16_add_c,
141                   &vp9_idct4x4_1_add_c,
142                   TX_4X4, 1)));
143#if HAVE_NEON
144INSTANTIATE_TEST_CASE_P(
145    NEON, PartialIDctTest,
146    ::testing::Values(
147        make_tuple(&vp9_idct32x32_1024_add_c,
148                   &vp9_idct32x32_1_add_neon,
149                   TX_32X32, 1),
150        make_tuple(&vp9_idct16x16_256_add_c,
151                   &vp9_idct16x16_10_add_neon,
152                   TX_16X16, 10),
153        make_tuple(&vp9_idct16x16_256_add_c,
154                   &vp9_idct16x16_1_add_neon,
155                   TX_16X16, 1),
156        make_tuple(&vp9_idct8x8_64_add_c,
157                   &vp9_idct8x8_10_add_neon,
158                   TX_8X8, 10),
159        make_tuple(&vp9_idct8x8_64_add_c,
160                   &vp9_idct8x8_1_add_neon,
161                   TX_8X8, 1),
162        make_tuple(&vp9_idct4x4_16_add_c,
163                   &vp9_idct4x4_1_add_neon,
164                   TX_4X4, 1)));
165#endif
166
167#if HAVE_SSE2
168INSTANTIATE_TEST_CASE_P(
169    SSE2, PartialIDctTest,
170    ::testing::Values(
171        make_tuple(&vp9_idct32x32_1024_add_c,
172                   &vp9_idct32x32_34_add_sse2,
173                   TX_32X32, 34),
174        make_tuple(&vp9_idct32x32_1024_add_c,
175                   &vp9_idct32x32_1_add_sse2,
176                   TX_32X32, 1),
177        make_tuple(&vp9_idct16x16_256_add_c,
178                   &vp9_idct16x16_10_add_sse2,
179                   TX_16X16, 10),
180        make_tuple(&vp9_idct16x16_256_add_c,
181                   &vp9_idct16x16_1_add_sse2,
182                   TX_16X16, 1),
183        make_tuple(&vp9_idct8x8_64_add_c,
184                   &vp9_idct8x8_10_add_sse2,
185                   TX_8X8, 10),
186        make_tuple(&vp9_idct8x8_64_add_c,
187                   &vp9_idct8x8_1_add_sse2,
188                   TX_8X8, 1),
189        make_tuple(&vp9_idct4x4_16_add_c,
190                   &vp9_idct4x4_1_add_sse2,
191                   TX_4X4, 1)));
192#endif
193}  // namespace
194