• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2016, Alliance for Open Media. All rights reserved
3  *
4  * This source code is subject to the terms of the BSD 2 Clause License and
5  * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
6  * was not distributed with this source code in the LICENSE file, you can
7  * obtain it at www.aomedia.org/license/software. If the Alliance for Open
8  * Media Patent License 1.0 was not distributed with this source code in the
9  * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
10  */
11 
12 #include <cmath>
13 #include <cstdlib>
14 #include <string>
15 #include <tuple>
16 
17 #include "third_party/googletest/src/googletest/include/gtest/gtest.h"
18 
19 #include "config/aom_config.h"
20 #include "config/av1_rtcd.h"
21 
22 #include "test/acm_random.h"
23 #include "test/register_state_check.h"
24 #include "test/util.h"
25 #include "av1/common/entropy.h"
26 #include "aom/aom_codec.h"
27 #include "aom/aom_integer.h"
28 
29 using libaom_test::ACMRandom;
30 
31 namespace {
32 const int kNumIterations = 1000;
33 
34 typedef int64_t (*ErrorBlockFunc)(const tran_low_t *coeff,
35                                   const tran_low_t *dqcoeff,
36                                   intptr_t block_size, int64_t *ssz, int bps);
37 
38 typedef int64_t (*ErrorBlockFunc8Bits)(const tran_low_t *coeff,
39                                        const tran_low_t *dqcoeff,
40                                        intptr_t block_size, int64_t *ssz);
41 
42 typedef std::tuple<ErrorBlockFunc, ErrorBlockFunc, aom_bit_depth_t>
43     ErrorBlockParam;
44 
45 template <ErrorBlockFunc8Bits fn>
BlockError8BitWrapper(const tran_low_t * coeff,const tran_low_t * dqcoeff,intptr_t block_size,int64_t * ssz,int bps)46 int64_t BlockError8BitWrapper(const tran_low_t *coeff,
47                               const tran_low_t *dqcoeff, intptr_t block_size,
48                               int64_t *ssz, int bps) {
49   EXPECT_EQ(bps, 8);
50   return fn(coeff, dqcoeff, block_size, ssz);
51 }
52 
53 class ErrorBlockTest : public ::testing::TestWithParam<ErrorBlockParam> {
54  public:
~ErrorBlockTest()55   virtual ~ErrorBlockTest() {}
SetUp()56   virtual void SetUp() {
57     error_block_op_ = GET_PARAM(0);
58     ref_error_block_op_ = GET_PARAM(1);
59     bit_depth_ = GET_PARAM(2);
60   }
61 
TearDown()62   virtual void TearDown() {}
63 
64  protected:
65   aom_bit_depth_t bit_depth_;
66   ErrorBlockFunc error_block_op_;
67   ErrorBlockFunc ref_error_block_op_;
68 };
69 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ErrorBlockTest);
70 
TEST_P(ErrorBlockTest,OperationCheck)71 TEST_P(ErrorBlockTest, OperationCheck) {
72   ACMRandom rnd(ACMRandom::DeterministicSeed());
73   DECLARE_ALIGNED(16, tran_low_t, coeff[4096]);
74   DECLARE_ALIGNED(16, tran_low_t, dqcoeff[4096]);
75   int err_count_total = 0;
76   int first_failure = -1;
77   intptr_t block_size;
78   int64_t ssz;
79   int64_t ret;
80   int64_t ref_ssz;
81   int64_t ref_ret;
82   const int msb = bit_depth_ + 8 - 1;
83   for (int i = 0; i < kNumIterations; ++i) {
84     int err_count = 0;
85     block_size = 16 << (i % 9);  // All block sizes from 4x4, 8x4 ..64x64
86     for (int j = 0; j < block_size; j++) {
87       // coeff and dqcoeff will always have at least the same sign, and this
88       // can be used for optimization, so generate test input precisely.
89       if (rnd(2)) {
90         // Positive number
91         coeff[j] = rnd(1 << msb);
92         dqcoeff[j] = rnd(1 << msb);
93       } else {
94         // Negative number
95         coeff[j] = -rnd(1 << msb);
96         dqcoeff[j] = -rnd(1 << msb);
97       }
98     }
99     ref_ret =
100         ref_error_block_op_(coeff, dqcoeff, block_size, &ref_ssz, bit_depth_);
101     API_REGISTER_STATE_CHECK(
102         ret = error_block_op_(coeff, dqcoeff, block_size, &ssz, bit_depth_));
103     err_count += (ref_ret != ret) | (ref_ssz != ssz);
104     if (err_count && !err_count_total) {
105       first_failure = i;
106     }
107     err_count_total += err_count;
108   }
109   EXPECT_EQ(0, err_count_total)
110       << "Error: Error Block Test, C output doesn't match optimized output. "
111       << "First failed at test case " << first_failure;
112 }
113 
TEST_P(ErrorBlockTest,ExtremeValues)114 TEST_P(ErrorBlockTest, ExtremeValues) {
115   ACMRandom rnd(ACMRandom::DeterministicSeed());
116   DECLARE_ALIGNED(16, tran_low_t, coeff[4096]);
117   DECLARE_ALIGNED(16, tran_low_t, dqcoeff[4096]);
118   int err_count_total = 0;
119   int first_failure = -1;
120   intptr_t block_size;
121   int64_t ssz;
122   int64_t ret;
123   int64_t ref_ssz;
124   int64_t ref_ret;
125   const int msb = bit_depth_ + 8 - 1;
126   int max_val = ((1 << msb) - 1);
127   for (int i = 0; i < kNumIterations; ++i) {
128     int err_count = 0;
129     int k = (i / 9) % 9;
130 
131     // Change the maximum coeff value, to test different bit boundaries
132     if (k == 8 && (i % 9) == 0) {
133       max_val >>= 1;
134     }
135     block_size = 16 << (i % 9);  // All block sizes from 4x4, 8x4 ..64x64
136     for (int j = 0; j < block_size; j++) {
137       if (k < 4) {
138         // Test at positive maximum values
139         coeff[j] = k % 2 ? max_val : 0;
140         dqcoeff[j] = (k >> 1) % 2 ? max_val : 0;
141       } else if (k < 8) {
142         // Test at negative maximum values
143         coeff[j] = k % 2 ? -max_val : 0;
144         dqcoeff[j] = (k >> 1) % 2 ? -max_val : 0;
145       } else {
146         if (rnd(2)) {
147           // Positive number
148           coeff[j] = rnd(1 << 14);
149           dqcoeff[j] = rnd(1 << 14);
150         } else {
151           // Negative number
152           coeff[j] = -rnd(1 << 14);
153           dqcoeff[j] = -rnd(1 << 14);
154         }
155       }
156     }
157     ref_ret =
158         ref_error_block_op_(coeff, dqcoeff, block_size, &ref_ssz, bit_depth_);
159     API_REGISTER_STATE_CHECK(
160         ret = error_block_op_(coeff, dqcoeff, block_size, &ssz, bit_depth_));
161     err_count += (ref_ret != ret) | (ref_ssz != ssz);
162     if (err_count && !err_count_total) {
163       first_failure = i;
164     }
165     err_count_total += err_count;
166   }
167   EXPECT_EQ(0, err_count_total)
168       << "Error: Error Block Test, C output doesn't match optimized output. "
169       << "First failed at test case " << first_failure;
170 }
171 
TEST_P(ErrorBlockTest,DISABLED_Speed)172 TEST_P(ErrorBlockTest, DISABLED_Speed) {
173   ACMRandom rnd(ACMRandom::DeterministicSeed());
174   DECLARE_ALIGNED(16, tran_low_t, coeff[4096]);
175   DECLARE_ALIGNED(16, tran_low_t, dqcoeff[4096]);
176   intptr_t block_size;
177   int64_t ssz;
178   int num_iters = 100000;
179   int64_t ref_ssz;
180   int k;
181   const int msb = bit_depth_ + 8 - 1;
182   for (int i = 0; i < 9; ++i) {
183     block_size = 16 << (i % 9);  // All block sizes from 4x4, 8x4 ..64x64
184     for (k = 0; k < 9; k++) {
185       for (int j = 0; j < block_size; j++) {
186         if (k < 5) {
187           if (rnd(2)) {
188             // Positive number
189             coeff[j] = rnd(1 << msb);
190             dqcoeff[j] = rnd(1 << msb);
191           } else {
192             // Negative number
193             coeff[j] = -rnd(1 << msb);
194             dqcoeff[j] = -rnd(1 << msb);
195           }
196         } else {
197           if (rnd(2)) {
198             // Positive number
199             coeff[j] = rnd(1 << 14);
200             dqcoeff[j] = rnd(1 << 14);
201           } else {
202             // Negative number
203             coeff[j] = -rnd(1 << 14);
204             dqcoeff[j] = -rnd(1 << 14);
205           }
206         }
207       }
208       aom_usec_timer ref_timer, test_timer;
209 
210       aom_usec_timer_start(&ref_timer);
211       for (int i = 0; i < num_iters; ++i) {
212         ref_error_block_op_(coeff, dqcoeff, block_size, &ref_ssz, bit_depth_);
213       }
214       aom_usec_timer_mark(&ref_timer);
215       const int elapsed_time_c =
216           static_cast<int>(aom_usec_timer_elapsed(&ref_timer));
217 
218       aom_usec_timer_start(&test_timer);
219       for (int i = 0; i < num_iters; ++i) {
220         error_block_op_(coeff, dqcoeff, block_size, &ssz, bit_depth_);
221       }
222       aom_usec_timer_mark(&test_timer);
223 
224       const int elapsed_time_simd =
225           static_cast<int>(aom_usec_timer_elapsed(&test_timer));
226 
227       printf(
228           " c_time=%d \t simd_time=%d \t "
229           "gain=%d \n",
230           elapsed_time_c, elapsed_time_simd,
231           (elapsed_time_c / elapsed_time_simd));
232     }
233   }
234 }
235 
236 using std::make_tuple;
237 
238 #if (HAVE_SSE2)
239 const ErrorBlockParam kErrorBlockTestParamsSse2[] = {
240 #if CONFIG_AV1_HIGHBITDEPTH
241   make_tuple(&av1_highbd_block_error_sse2, &av1_highbd_block_error_c,
242              AOM_BITS_10),
243   make_tuple(&av1_highbd_block_error_sse2, &av1_highbd_block_error_c,
244              AOM_BITS_12),
245   make_tuple(&av1_highbd_block_error_sse2, &av1_highbd_block_error_c,
246              AOM_BITS_8),
247 #endif
248   make_tuple(&BlockError8BitWrapper<av1_block_error_sse2>,
249              &BlockError8BitWrapper<av1_block_error_c>, AOM_BITS_8)
250 };
251 
252 INSTANTIATE_TEST_SUITE_P(SSE2, ErrorBlockTest,
253                          ::testing::ValuesIn(kErrorBlockTestParamsSse2));
254 #endif  // HAVE_SSE2
255 
256 #if (HAVE_AVX2)
257 const ErrorBlockParam kErrorBlockTestParamsAvx2[] = {
258 #if CONFIG_AV1_HIGHBITDEPTH
259   make_tuple(&av1_highbd_block_error_avx2, &av1_highbd_block_error_c,
260              AOM_BITS_10),
261   make_tuple(&av1_highbd_block_error_avx2, &av1_highbd_block_error_c,
262              AOM_BITS_12),
263   make_tuple(&av1_highbd_block_error_avx2, &av1_highbd_block_error_c,
264              AOM_BITS_8),
265 #endif
266   make_tuple(&BlockError8BitWrapper<av1_block_error_avx2>,
267              &BlockError8BitWrapper<av1_block_error_c>, AOM_BITS_8)
268 };
269 
270 INSTANTIATE_TEST_SUITE_P(AVX2, ErrorBlockTest,
271                          ::testing::ValuesIn(kErrorBlockTestParamsAvx2));
272 #endif  // HAVE_AVX2
273 
274 #if (HAVE_MSA)
275 INSTANTIATE_TEST_SUITE_P(
276     MSA, ErrorBlockTest,
277     ::testing::Values(make_tuple(&BlockError8BitWrapper<av1_block_error_msa>,
278                                  &BlockError8BitWrapper<av1_block_error_c>,
279                                  AOM_BITS_8)));
280 #endif  // HAVE_MSA
281 
282 #if (HAVE_NEON)
283 INSTANTIATE_TEST_SUITE_P(
284     NEON, ErrorBlockTest,
285     ::testing::Values(make_tuple(&BlockError8BitWrapper<av1_block_error_neon>,
286                                  &BlockError8BitWrapper<av1_block_error_c>,
287                                  AOM_BITS_8)));
288 #endif  // HAVE_NEON
289 }  // namespace
290