xref: /aosp_15_r20/external/libaom/test/transform_test_base.h (revision 77c1e3ccc04c968bd2bc212e87364f250e820521)
1*77c1e3ccSAndroid Build Coastguard Worker /*
2*77c1e3ccSAndroid Build Coastguard Worker  * Copyright (c) 2016, Alliance for Open Media. All rights reserved.
3*77c1e3ccSAndroid Build Coastguard Worker  *
4*77c1e3ccSAndroid Build Coastguard Worker  * This source code is subject to the terms of the BSD 2 Clause License and
5*77c1e3ccSAndroid Build Coastguard Worker  * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
6*77c1e3ccSAndroid Build Coastguard Worker  * was not distributed with this source code in the LICENSE file, you can
7*77c1e3ccSAndroid Build Coastguard Worker  * obtain it at www.aomedia.org/license/software. If the Alliance for Open
8*77c1e3ccSAndroid Build Coastguard Worker  * Media Patent License 1.0 was not distributed with this source code in the
9*77c1e3ccSAndroid Build Coastguard Worker  * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
10*77c1e3ccSAndroid Build Coastguard Worker  */
11*77c1e3ccSAndroid Build Coastguard Worker 
12*77c1e3ccSAndroid Build Coastguard Worker #ifndef AOM_TEST_TRANSFORM_TEST_BASE_H_
13*77c1e3ccSAndroid Build Coastguard Worker #define AOM_TEST_TRANSFORM_TEST_BASE_H_
14*77c1e3ccSAndroid Build Coastguard Worker 
15*77c1e3ccSAndroid Build Coastguard Worker #include "gtest/gtest.h"
16*77c1e3ccSAndroid Build Coastguard Worker 
17*77c1e3ccSAndroid Build Coastguard Worker #include "aom/aom_codec.h"
18*77c1e3ccSAndroid Build Coastguard Worker #include "aom_dsp/txfm_common.h"
19*77c1e3ccSAndroid Build Coastguard Worker #include "aom_mem/aom_mem.h"
20*77c1e3ccSAndroid Build Coastguard Worker #include "test/acm_random.h"
21*77c1e3ccSAndroid Build Coastguard Worker 
22*77c1e3ccSAndroid Build Coastguard Worker namespace libaom_test {
23*77c1e3ccSAndroid Build Coastguard Worker 
24*77c1e3ccSAndroid Build Coastguard Worker //  Note:
25*77c1e3ccSAndroid Build Coastguard Worker //   Same constant are defined in av1/common/av1_entropy.h and
26*77c1e3ccSAndroid Build Coastguard Worker //   av1/common/entropy.h.  Goal is to make this base class
27*77c1e3ccSAndroid Build Coastguard Worker //   to use for future codec transform testing.  But including
28*77c1e3ccSAndroid Build Coastguard Worker //   either of them would lead to compiling error when we do
29*77c1e3ccSAndroid Build Coastguard Worker //   unit test for another codec. Suggest to move the definition
30*77c1e3ccSAndroid Build Coastguard Worker //   to a aom header file.
31*77c1e3ccSAndroid Build Coastguard Worker const int kDctMaxValue = 16384;
32*77c1e3ccSAndroid Build Coastguard Worker 
33*77c1e3ccSAndroid Build Coastguard Worker template <typename OutputType>
34*77c1e3ccSAndroid Build Coastguard Worker using FhtFunc = void (*)(const int16_t *in, OutputType *out, int stride,
35*77c1e3ccSAndroid Build Coastguard Worker                          TxfmParam *txfm_param);
36*77c1e3ccSAndroid Build Coastguard Worker 
37*77c1e3ccSAndroid Build Coastguard Worker template <typename OutputType>
38*77c1e3ccSAndroid Build Coastguard Worker using IhtFunc = void (*)(const tran_low_t *in, uint8_t *out, int stride,
39*77c1e3ccSAndroid Build Coastguard Worker                          const TxfmParam *txfm_param);
40*77c1e3ccSAndroid Build Coastguard Worker 
41*77c1e3ccSAndroid Build Coastguard Worker template <typename OutType>
42*77c1e3ccSAndroid Build Coastguard Worker class TransformTestBase {
43*77c1e3ccSAndroid Build Coastguard Worker  public:
44*77c1e3ccSAndroid Build Coastguard Worker   virtual ~TransformTestBase() = default;
45*77c1e3ccSAndroid Build Coastguard Worker 
46*77c1e3ccSAndroid Build Coastguard Worker  protected:
47*77c1e3ccSAndroid Build Coastguard Worker   virtual void RunFwdTxfm(const int16_t *in, OutType *out, int stride) = 0;
48*77c1e3ccSAndroid Build Coastguard Worker 
49*77c1e3ccSAndroid Build Coastguard Worker   virtual void RunInvTxfm(const OutType *out, uint8_t *dst, int stride) = 0;
50*77c1e3ccSAndroid Build Coastguard Worker 
RunAccuracyCheck(uint32_t ref_max_error,double ref_avg_error)51*77c1e3ccSAndroid Build Coastguard Worker   void RunAccuracyCheck(uint32_t ref_max_error, double ref_avg_error) {
52*77c1e3ccSAndroid Build Coastguard Worker     ACMRandom rnd(ACMRandom::DeterministicSeed());
53*77c1e3ccSAndroid Build Coastguard Worker     uint32_t max_error = 0;
54*77c1e3ccSAndroid Build Coastguard Worker     int64_t total_error = 0;
55*77c1e3ccSAndroid Build Coastguard Worker     const int count_test_block = 10000;
56*77c1e3ccSAndroid Build Coastguard Worker 
57*77c1e3ccSAndroid Build Coastguard Worker     int16_t *test_input_block = reinterpret_cast<int16_t *>(
58*77c1e3ccSAndroid Build Coastguard Worker         aom_memalign(16, sizeof(int16_t) * num_coeffs_));
59*77c1e3ccSAndroid Build Coastguard Worker     ASSERT_NE(test_input_block, nullptr);
60*77c1e3ccSAndroid Build Coastguard Worker     OutType *test_temp_block = reinterpret_cast<OutType *>(
61*77c1e3ccSAndroid Build Coastguard Worker         aom_memalign(16, sizeof(test_temp_block[0]) * num_coeffs_));
62*77c1e3ccSAndroid Build Coastguard Worker     ASSERT_NE(test_temp_block, nullptr);
63*77c1e3ccSAndroid Build Coastguard Worker     uint8_t *dst = reinterpret_cast<uint8_t *>(
64*77c1e3ccSAndroid Build Coastguard Worker         aom_memalign(16, sizeof(uint8_t) * num_coeffs_));
65*77c1e3ccSAndroid Build Coastguard Worker     ASSERT_NE(dst, nullptr);
66*77c1e3ccSAndroid Build Coastguard Worker     uint8_t *src = reinterpret_cast<uint8_t *>(
67*77c1e3ccSAndroid Build Coastguard Worker         aom_memalign(16, sizeof(uint8_t) * num_coeffs_));
68*77c1e3ccSAndroid Build Coastguard Worker     ASSERT_NE(src, nullptr);
69*77c1e3ccSAndroid Build Coastguard Worker     uint16_t *dst16 = reinterpret_cast<uint16_t *>(
70*77c1e3ccSAndroid Build Coastguard Worker         aom_memalign(16, sizeof(uint16_t) * num_coeffs_));
71*77c1e3ccSAndroid Build Coastguard Worker     ASSERT_NE(dst16, nullptr);
72*77c1e3ccSAndroid Build Coastguard Worker     uint16_t *src16 = reinterpret_cast<uint16_t *>(
73*77c1e3ccSAndroid Build Coastguard Worker         aom_memalign(16, sizeof(uint16_t) * num_coeffs_));
74*77c1e3ccSAndroid Build Coastguard Worker     ASSERT_NE(src16, nullptr);
75*77c1e3ccSAndroid Build Coastguard Worker 
76*77c1e3ccSAndroid Build Coastguard Worker     for (int i = 0; i < count_test_block; ++i) {
77*77c1e3ccSAndroid Build Coastguard Worker       // Initialize a test block with input range [-255, 255].
78*77c1e3ccSAndroid Build Coastguard Worker       for (int j = 0; j < num_coeffs_; ++j) {
79*77c1e3ccSAndroid Build Coastguard Worker         if (bit_depth_ == AOM_BITS_8) {
80*77c1e3ccSAndroid Build Coastguard Worker           src[j] = rnd.Rand8();
81*77c1e3ccSAndroid Build Coastguard Worker           dst[j] = rnd.Rand8();
82*77c1e3ccSAndroid Build Coastguard Worker           test_input_block[j] = src[j] - dst[j];
83*77c1e3ccSAndroid Build Coastguard Worker         } else {
84*77c1e3ccSAndroid Build Coastguard Worker           src16[j] = rnd.Rand16() & mask_;
85*77c1e3ccSAndroid Build Coastguard Worker           dst16[j] = rnd.Rand16() & mask_;
86*77c1e3ccSAndroid Build Coastguard Worker           test_input_block[j] = src16[j] - dst16[j];
87*77c1e3ccSAndroid Build Coastguard Worker         }
88*77c1e3ccSAndroid Build Coastguard Worker       }
89*77c1e3ccSAndroid Build Coastguard Worker 
90*77c1e3ccSAndroid Build Coastguard Worker       API_REGISTER_STATE_CHECK(
91*77c1e3ccSAndroid Build Coastguard Worker           RunFwdTxfm(test_input_block, test_temp_block, pitch_));
92*77c1e3ccSAndroid Build Coastguard Worker       if (bit_depth_ == AOM_BITS_8) {
93*77c1e3ccSAndroid Build Coastguard Worker         API_REGISTER_STATE_CHECK(RunInvTxfm(test_temp_block, dst, pitch_));
94*77c1e3ccSAndroid Build Coastguard Worker       } else {
95*77c1e3ccSAndroid Build Coastguard Worker         API_REGISTER_STATE_CHECK(
96*77c1e3ccSAndroid Build Coastguard Worker             RunInvTxfm(test_temp_block, CONVERT_TO_BYTEPTR(dst16), pitch_));
97*77c1e3ccSAndroid Build Coastguard Worker       }
98*77c1e3ccSAndroid Build Coastguard Worker 
99*77c1e3ccSAndroid Build Coastguard Worker       for (int j = 0; j < num_coeffs_; ++j) {
100*77c1e3ccSAndroid Build Coastguard Worker         const int diff =
101*77c1e3ccSAndroid Build Coastguard Worker             bit_depth_ == AOM_BITS_8 ? dst[j] - src[j] : dst16[j] - src16[j];
102*77c1e3ccSAndroid Build Coastguard Worker         const uint32_t error = diff * diff;
103*77c1e3ccSAndroid Build Coastguard Worker         if (max_error < error) max_error = error;
104*77c1e3ccSAndroid Build Coastguard Worker         total_error += error;
105*77c1e3ccSAndroid Build Coastguard Worker       }
106*77c1e3ccSAndroid Build Coastguard Worker     }
107*77c1e3ccSAndroid Build Coastguard Worker 
108*77c1e3ccSAndroid Build Coastguard Worker     double avg_error = total_error * 1. / count_test_block / num_coeffs_;
109*77c1e3ccSAndroid Build Coastguard Worker 
110*77c1e3ccSAndroid Build Coastguard Worker     EXPECT_GE(ref_max_error, max_error)
111*77c1e3ccSAndroid Build Coastguard Worker         << "Error: FHT/IHT has an individual round trip error > "
112*77c1e3ccSAndroid Build Coastguard Worker         << ref_max_error;
113*77c1e3ccSAndroid Build Coastguard Worker 
114*77c1e3ccSAndroid Build Coastguard Worker     EXPECT_GE(ref_avg_error, avg_error)
115*77c1e3ccSAndroid Build Coastguard Worker         << "Error: FHT/IHT has average round trip error > " << ref_avg_error
116*77c1e3ccSAndroid Build Coastguard Worker         << " per block";
117*77c1e3ccSAndroid Build Coastguard Worker 
118*77c1e3ccSAndroid Build Coastguard Worker     aom_free(test_input_block);
119*77c1e3ccSAndroid Build Coastguard Worker     aom_free(test_temp_block);
120*77c1e3ccSAndroid Build Coastguard Worker     aom_free(dst);
121*77c1e3ccSAndroid Build Coastguard Worker     aom_free(src);
122*77c1e3ccSAndroid Build Coastguard Worker     aom_free(dst16);
123*77c1e3ccSAndroid Build Coastguard Worker     aom_free(src16);
124*77c1e3ccSAndroid Build Coastguard Worker   }
125*77c1e3ccSAndroid Build Coastguard Worker 
RunCoeffCheck()126*77c1e3ccSAndroid Build Coastguard Worker   void RunCoeffCheck() {
127*77c1e3ccSAndroid Build Coastguard Worker     ACMRandom rnd(ACMRandom::DeterministicSeed());
128*77c1e3ccSAndroid Build Coastguard Worker     const int count_test_block = 5000;
129*77c1e3ccSAndroid Build Coastguard Worker 
130*77c1e3ccSAndroid Build Coastguard Worker     // Use a stride value which is not the width of any transform, to catch
131*77c1e3ccSAndroid Build Coastguard Worker     // cases where the transforms use the stride incorrectly.
132*77c1e3ccSAndroid Build Coastguard Worker     int stride = 96;
133*77c1e3ccSAndroid Build Coastguard Worker 
134*77c1e3ccSAndroid Build Coastguard Worker     int16_t *input_block = reinterpret_cast<int16_t *>(
135*77c1e3ccSAndroid Build Coastguard Worker         aom_memalign(16, sizeof(int16_t) * stride * height_));
136*77c1e3ccSAndroid Build Coastguard Worker     ASSERT_NE(input_block, nullptr);
137*77c1e3ccSAndroid Build Coastguard Worker     OutType *output_ref_block = reinterpret_cast<OutType *>(
138*77c1e3ccSAndroid Build Coastguard Worker         aom_memalign(16, sizeof(output_ref_block[0]) * num_coeffs_));
139*77c1e3ccSAndroid Build Coastguard Worker     ASSERT_NE(output_ref_block, nullptr);
140*77c1e3ccSAndroid Build Coastguard Worker     OutType *output_block = reinterpret_cast<OutType *>(
141*77c1e3ccSAndroid Build Coastguard Worker         aom_memalign(16, sizeof(output_block[0]) * num_coeffs_));
142*77c1e3ccSAndroid Build Coastguard Worker     ASSERT_NE(output_block, nullptr);
143*77c1e3ccSAndroid Build Coastguard Worker 
144*77c1e3ccSAndroid Build Coastguard Worker     for (int i = 0; i < count_test_block; ++i) {
145*77c1e3ccSAndroid Build Coastguard Worker       int j, k;
146*77c1e3ccSAndroid Build Coastguard Worker       for (j = 0; j < height_; ++j) {
147*77c1e3ccSAndroid Build Coastguard Worker         for (k = 0; k < pitch_; ++k) {
148*77c1e3ccSAndroid Build Coastguard Worker           int in_idx = j * stride + k;
149*77c1e3ccSAndroid Build Coastguard Worker           int out_idx = j * pitch_ + k;
150*77c1e3ccSAndroid Build Coastguard Worker           input_block[in_idx] = (rnd.Rand16() & mask_) - (rnd.Rand16() & mask_);
151*77c1e3ccSAndroid Build Coastguard Worker           if (bit_depth_ == AOM_BITS_8) {
152*77c1e3ccSAndroid Build Coastguard Worker             output_block[out_idx] = output_ref_block[out_idx] = rnd.Rand8();
153*77c1e3ccSAndroid Build Coastguard Worker           } else {
154*77c1e3ccSAndroid Build Coastguard Worker             output_block[out_idx] = output_ref_block[out_idx] =
155*77c1e3ccSAndroid Build Coastguard Worker                 rnd.Rand16() & mask_;
156*77c1e3ccSAndroid Build Coastguard Worker           }
157*77c1e3ccSAndroid Build Coastguard Worker         }
158*77c1e3ccSAndroid Build Coastguard Worker       }
159*77c1e3ccSAndroid Build Coastguard Worker 
160*77c1e3ccSAndroid Build Coastguard Worker       fwd_txfm_ref(input_block, output_ref_block, stride, &txfm_param_);
161*77c1e3ccSAndroid Build Coastguard Worker       API_REGISTER_STATE_CHECK(RunFwdTxfm(input_block, output_block, stride));
162*77c1e3ccSAndroid Build Coastguard Worker 
163*77c1e3ccSAndroid Build Coastguard Worker       // The minimum quant value is 4.
164*77c1e3ccSAndroid Build Coastguard Worker       for (j = 0; j < height_; ++j) {
165*77c1e3ccSAndroid Build Coastguard Worker         for (k = 0; k < pitch_; ++k) {
166*77c1e3ccSAndroid Build Coastguard Worker           int out_idx = j * pitch_ + k;
167*77c1e3ccSAndroid Build Coastguard Worker           ASSERT_EQ(output_block[out_idx], output_ref_block[out_idx])
168*77c1e3ccSAndroid Build Coastguard Worker               << "Error: not bit-exact result at index: " << out_idx
169*77c1e3ccSAndroid Build Coastguard Worker               << " at test block: " << i;
170*77c1e3ccSAndroid Build Coastguard Worker         }
171*77c1e3ccSAndroid Build Coastguard Worker       }
172*77c1e3ccSAndroid Build Coastguard Worker     }
173*77c1e3ccSAndroid Build Coastguard Worker     aom_free(input_block);
174*77c1e3ccSAndroid Build Coastguard Worker     aom_free(output_ref_block);
175*77c1e3ccSAndroid Build Coastguard Worker     aom_free(output_block);
176*77c1e3ccSAndroid Build Coastguard Worker   }
177*77c1e3ccSAndroid Build Coastguard Worker 
RunInvCoeffCheck()178*77c1e3ccSAndroid Build Coastguard Worker   void RunInvCoeffCheck() {
179*77c1e3ccSAndroid Build Coastguard Worker     ACMRandom rnd(ACMRandom::DeterministicSeed());
180*77c1e3ccSAndroid Build Coastguard Worker     const int count_test_block = 5000;
181*77c1e3ccSAndroid Build Coastguard Worker 
182*77c1e3ccSAndroid Build Coastguard Worker     // Use a stride value which is not the width of any transform, to catch
183*77c1e3ccSAndroid Build Coastguard Worker     // cases where the transforms use the stride incorrectly.
184*77c1e3ccSAndroid Build Coastguard Worker     int stride = 96;
185*77c1e3ccSAndroid Build Coastguard Worker 
186*77c1e3ccSAndroid Build Coastguard Worker     int16_t *input_block = reinterpret_cast<int16_t *>(
187*77c1e3ccSAndroid Build Coastguard Worker         aom_memalign(16, sizeof(int16_t) * num_coeffs_));
188*77c1e3ccSAndroid Build Coastguard Worker     ASSERT_NE(input_block, nullptr);
189*77c1e3ccSAndroid Build Coastguard Worker     OutType *trans_block = reinterpret_cast<OutType *>(
190*77c1e3ccSAndroid Build Coastguard Worker         aom_memalign(16, sizeof(trans_block[0]) * num_coeffs_));
191*77c1e3ccSAndroid Build Coastguard Worker     ASSERT_NE(trans_block, nullptr);
192*77c1e3ccSAndroid Build Coastguard Worker     uint8_t *output_block = reinterpret_cast<uint8_t *>(
193*77c1e3ccSAndroid Build Coastguard Worker         aom_memalign(16, sizeof(uint8_t) * stride * height_));
194*77c1e3ccSAndroid Build Coastguard Worker     ASSERT_NE(output_block, nullptr);
195*77c1e3ccSAndroid Build Coastguard Worker     uint8_t *output_ref_block = reinterpret_cast<uint8_t *>(
196*77c1e3ccSAndroid Build Coastguard Worker         aom_memalign(16, sizeof(uint8_t) * stride * height_));
197*77c1e3ccSAndroid Build Coastguard Worker     ASSERT_NE(output_ref_block, nullptr);
198*77c1e3ccSAndroid Build Coastguard Worker 
199*77c1e3ccSAndroid Build Coastguard Worker     for (int i = 0; i < count_test_block; ++i) {
200*77c1e3ccSAndroid Build Coastguard Worker       // Initialize a test block with input range [-mask_, mask_].
201*77c1e3ccSAndroid Build Coastguard Worker       int j, k;
202*77c1e3ccSAndroid Build Coastguard Worker       for (j = 0; j < height_; ++j) {
203*77c1e3ccSAndroid Build Coastguard Worker         for (k = 0; k < pitch_; ++k) {
204*77c1e3ccSAndroid Build Coastguard Worker           int in_idx = j * pitch_ + k;
205*77c1e3ccSAndroid Build Coastguard Worker           int out_idx = j * stride + k;
206*77c1e3ccSAndroid Build Coastguard Worker           input_block[in_idx] = (rnd.Rand16() & mask_) - (rnd.Rand16() & mask_);
207*77c1e3ccSAndroid Build Coastguard Worker           output_ref_block[out_idx] = rnd.Rand16() & mask_;
208*77c1e3ccSAndroid Build Coastguard Worker           output_block[out_idx] = output_ref_block[out_idx];
209*77c1e3ccSAndroid Build Coastguard Worker         }
210*77c1e3ccSAndroid Build Coastguard Worker       }
211*77c1e3ccSAndroid Build Coastguard Worker 
212*77c1e3ccSAndroid Build Coastguard Worker       fwd_txfm_ref(input_block, trans_block, pitch_, &txfm_param_);
213*77c1e3ccSAndroid Build Coastguard Worker 
214*77c1e3ccSAndroid Build Coastguard Worker       inv_txfm_ref(trans_block, output_ref_block, stride, &txfm_param_);
215*77c1e3ccSAndroid Build Coastguard Worker       API_REGISTER_STATE_CHECK(RunInvTxfm(trans_block, output_block, stride));
216*77c1e3ccSAndroid Build Coastguard Worker 
217*77c1e3ccSAndroid Build Coastguard Worker       for (j = 0; j < height_; ++j) {
218*77c1e3ccSAndroid Build Coastguard Worker         for (k = 0; k < pitch_; ++k) {
219*77c1e3ccSAndroid Build Coastguard Worker           int out_idx = j * stride + k;
220*77c1e3ccSAndroid Build Coastguard Worker           ASSERT_EQ(output_block[out_idx], output_ref_block[out_idx])
221*77c1e3ccSAndroid Build Coastguard Worker               << "Error: not bit-exact result at index: " << out_idx
222*77c1e3ccSAndroid Build Coastguard Worker               << " j = " << j << " k = " << k << " at test block: " << i;
223*77c1e3ccSAndroid Build Coastguard Worker         }
224*77c1e3ccSAndroid Build Coastguard Worker       }
225*77c1e3ccSAndroid Build Coastguard Worker     }
226*77c1e3ccSAndroid Build Coastguard Worker     aom_free(input_block);
227*77c1e3ccSAndroid Build Coastguard Worker     aom_free(trans_block);
228*77c1e3ccSAndroid Build Coastguard Worker     aom_free(output_ref_block);
229*77c1e3ccSAndroid Build Coastguard Worker     aom_free(output_block);
230*77c1e3ccSAndroid Build Coastguard Worker   }
231*77c1e3ccSAndroid Build Coastguard Worker 
RunMemCheck()232*77c1e3ccSAndroid Build Coastguard Worker   void RunMemCheck() {
233*77c1e3ccSAndroid Build Coastguard Worker     ACMRandom rnd(ACMRandom::DeterministicSeed());
234*77c1e3ccSAndroid Build Coastguard Worker     const int count_test_block = 5000;
235*77c1e3ccSAndroid Build Coastguard Worker 
236*77c1e3ccSAndroid Build Coastguard Worker     int16_t *input_extreme_block = reinterpret_cast<int16_t *>(
237*77c1e3ccSAndroid Build Coastguard Worker         aom_memalign(16, sizeof(int16_t) * num_coeffs_));
238*77c1e3ccSAndroid Build Coastguard Worker     ASSERT_NE(input_extreme_block, nullptr);
239*77c1e3ccSAndroid Build Coastguard Worker     OutType *output_ref_block = reinterpret_cast<OutType *>(
240*77c1e3ccSAndroid Build Coastguard Worker         aom_memalign(16, sizeof(output_ref_block[0]) * num_coeffs_));
241*77c1e3ccSAndroid Build Coastguard Worker     ASSERT_NE(output_ref_block, nullptr);
242*77c1e3ccSAndroid Build Coastguard Worker     OutType *output_block = reinterpret_cast<OutType *>(
243*77c1e3ccSAndroid Build Coastguard Worker         aom_memalign(16, sizeof(output_block[0]) * num_coeffs_));
244*77c1e3ccSAndroid Build Coastguard Worker     ASSERT_NE(output_block, nullptr);
245*77c1e3ccSAndroid Build Coastguard Worker 
246*77c1e3ccSAndroid Build Coastguard Worker     for (int i = 0; i < count_test_block; ++i) {
247*77c1e3ccSAndroid Build Coastguard Worker       // Initialize a test block with input range [-mask_, mask_].
248*77c1e3ccSAndroid Build Coastguard Worker       for (int j = 0; j < num_coeffs_; ++j) {
249*77c1e3ccSAndroid Build Coastguard Worker         input_extreme_block[j] = rnd.Rand8() % 2 ? mask_ : -mask_;
250*77c1e3ccSAndroid Build Coastguard Worker       }
251*77c1e3ccSAndroid Build Coastguard Worker       if (i == 0) {
252*77c1e3ccSAndroid Build Coastguard Worker         for (int j = 0; j < num_coeffs_; ++j) input_extreme_block[j] = mask_;
253*77c1e3ccSAndroid Build Coastguard Worker       } else if (i == 1) {
254*77c1e3ccSAndroid Build Coastguard Worker         for (int j = 0; j < num_coeffs_; ++j) input_extreme_block[j] = -mask_;
255*77c1e3ccSAndroid Build Coastguard Worker       }
256*77c1e3ccSAndroid Build Coastguard Worker 
257*77c1e3ccSAndroid Build Coastguard Worker       fwd_txfm_ref(input_extreme_block, output_ref_block, pitch_, &txfm_param_);
258*77c1e3ccSAndroid Build Coastguard Worker       API_REGISTER_STATE_CHECK(
259*77c1e3ccSAndroid Build Coastguard Worker           RunFwdTxfm(input_extreme_block, output_block, pitch_));
260*77c1e3ccSAndroid Build Coastguard Worker 
261*77c1e3ccSAndroid Build Coastguard Worker       int row_length = FindRowLength();
262*77c1e3ccSAndroid Build Coastguard Worker       // The minimum quant value is 4.
263*77c1e3ccSAndroid Build Coastguard Worker       for (int j = 0; j < num_coeffs_; ++j) {
264*77c1e3ccSAndroid Build Coastguard Worker         ASSERT_EQ(output_block[j], output_ref_block[j])
265*77c1e3ccSAndroid Build Coastguard Worker             << "Not bit-exact at test index: " << i << ", "
266*77c1e3ccSAndroid Build Coastguard Worker             << "j = " << j << std::endl;
267*77c1e3ccSAndroid Build Coastguard Worker         EXPECT_GE(row_length * kDctMaxValue << (bit_depth_ - 8),
268*77c1e3ccSAndroid Build Coastguard Worker                   abs(output_block[j]))
269*77c1e3ccSAndroid Build Coastguard Worker             << "Error: NxN FDCT has coefficient larger than N*DCT_MAX_VALUE";
270*77c1e3ccSAndroid Build Coastguard Worker       }
271*77c1e3ccSAndroid Build Coastguard Worker     }
272*77c1e3ccSAndroid Build Coastguard Worker     aom_free(input_extreme_block);
273*77c1e3ccSAndroid Build Coastguard Worker     aom_free(output_ref_block);
274*77c1e3ccSAndroid Build Coastguard Worker     aom_free(output_block);
275*77c1e3ccSAndroid Build Coastguard Worker   }
276*77c1e3ccSAndroid Build Coastguard Worker 
RunInvAccuracyCheck(int limit)277*77c1e3ccSAndroid Build Coastguard Worker   void RunInvAccuracyCheck(int limit) {
278*77c1e3ccSAndroid Build Coastguard Worker     ACMRandom rnd(ACMRandom::DeterministicSeed());
279*77c1e3ccSAndroid Build Coastguard Worker     const int count_test_block = 1000;
280*77c1e3ccSAndroid Build Coastguard Worker 
281*77c1e3ccSAndroid Build Coastguard Worker     int16_t *in = reinterpret_cast<int16_t *>(
282*77c1e3ccSAndroid Build Coastguard Worker         aom_memalign(16, sizeof(int16_t) * num_coeffs_));
283*77c1e3ccSAndroid Build Coastguard Worker     ASSERT_NE(in, nullptr);
284*77c1e3ccSAndroid Build Coastguard Worker     OutType *coeff = reinterpret_cast<OutType *>(
285*77c1e3ccSAndroid Build Coastguard Worker         aom_memalign(16, sizeof(coeff[0]) * num_coeffs_));
286*77c1e3ccSAndroid Build Coastguard Worker     ASSERT_NE(coeff, nullptr);
287*77c1e3ccSAndroid Build Coastguard Worker     uint8_t *dst = reinterpret_cast<uint8_t *>(
288*77c1e3ccSAndroid Build Coastguard Worker         aom_memalign(16, sizeof(uint8_t) * num_coeffs_));
289*77c1e3ccSAndroid Build Coastguard Worker     ASSERT_NE(dst, nullptr);
290*77c1e3ccSAndroid Build Coastguard Worker     uint8_t *src = reinterpret_cast<uint8_t *>(
291*77c1e3ccSAndroid Build Coastguard Worker         aom_memalign(16, sizeof(uint8_t) * num_coeffs_));
292*77c1e3ccSAndroid Build Coastguard Worker     ASSERT_NE(src, nullptr);
293*77c1e3ccSAndroid Build Coastguard Worker 
294*77c1e3ccSAndroid Build Coastguard Worker     uint16_t *dst16 = reinterpret_cast<uint16_t *>(
295*77c1e3ccSAndroid Build Coastguard Worker         aom_memalign(16, sizeof(uint16_t) * num_coeffs_));
296*77c1e3ccSAndroid Build Coastguard Worker     ASSERT_NE(dst16, nullptr);
297*77c1e3ccSAndroid Build Coastguard Worker     uint16_t *src16 = reinterpret_cast<uint16_t *>(
298*77c1e3ccSAndroid Build Coastguard Worker         aom_memalign(16, sizeof(uint16_t) * num_coeffs_));
299*77c1e3ccSAndroid Build Coastguard Worker     ASSERT_NE(src16, nullptr);
300*77c1e3ccSAndroid Build Coastguard Worker 
301*77c1e3ccSAndroid Build Coastguard Worker     for (int i = 0; i < count_test_block; ++i) {
302*77c1e3ccSAndroid Build Coastguard Worker       // Initialize a test block with input range [-mask_, mask_].
303*77c1e3ccSAndroid Build Coastguard Worker       for (int j = 0; j < num_coeffs_; ++j) {
304*77c1e3ccSAndroid Build Coastguard Worker         if (bit_depth_ == AOM_BITS_8) {
305*77c1e3ccSAndroid Build Coastguard Worker           src[j] = rnd.Rand8();
306*77c1e3ccSAndroid Build Coastguard Worker           dst[j] = rnd.Rand8();
307*77c1e3ccSAndroid Build Coastguard Worker           in[j] = src[j] - dst[j];
308*77c1e3ccSAndroid Build Coastguard Worker         } else {
309*77c1e3ccSAndroid Build Coastguard Worker           src16[j] = rnd.Rand16() & mask_;
310*77c1e3ccSAndroid Build Coastguard Worker           dst16[j] = rnd.Rand16() & mask_;
311*77c1e3ccSAndroid Build Coastguard Worker           in[j] = src16[j] - dst16[j];
312*77c1e3ccSAndroid Build Coastguard Worker         }
313*77c1e3ccSAndroid Build Coastguard Worker       }
314*77c1e3ccSAndroid Build Coastguard Worker 
315*77c1e3ccSAndroid Build Coastguard Worker       fwd_txfm_ref(in, coeff, pitch_, &txfm_param_);
316*77c1e3ccSAndroid Build Coastguard Worker 
317*77c1e3ccSAndroid Build Coastguard Worker       if (bit_depth_ == AOM_BITS_8) {
318*77c1e3ccSAndroid Build Coastguard Worker         API_REGISTER_STATE_CHECK(RunInvTxfm(coeff, dst, pitch_));
319*77c1e3ccSAndroid Build Coastguard Worker       } else {
320*77c1e3ccSAndroid Build Coastguard Worker         API_REGISTER_STATE_CHECK(
321*77c1e3ccSAndroid Build Coastguard Worker             RunInvTxfm(coeff, CONVERT_TO_BYTEPTR(dst16), pitch_));
322*77c1e3ccSAndroid Build Coastguard Worker       }
323*77c1e3ccSAndroid Build Coastguard Worker 
324*77c1e3ccSAndroid Build Coastguard Worker       for (int j = 0; j < num_coeffs_; ++j) {
325*77c1e3ccSAndroid Build Coastguard Worker         const int diff =
326*77c1e3ccSAndroid Build Coastguard Worker             bit_depth_ == AOM_BITS_8 ? dst[j] - src[j] : dst16[j] - src16[j];
327*77c1e3ccSAndroid Build Coastguard Worker         const uint32_t error = diff * diff;
328*77c1e3ccSAndroid Build Coastguard Worker         ASSERT_GE(static_cast<uint32_t>(limit), error)
329*77c1e3ccSAndroid Build Coastguard Worker             << "Error: 4x4 IDCT has error " << error << " at index " << j;
330*77c1e3ccSAndroid Build Coastguard Worker       }
331*77c1e3ccSAndroid Build Coastguard Worker     }
332*77c1e3ccSAndroid Build Coastguard Worker     aom_free(in);
333*77c1e3ccSAndroid Build Coastguard Worker     aom_free(coeff);
334*77c1e3ccSAndroid Build Coastguard Worker     aom_free(dst);
335*77c1e3ccSAndroid Build Coastguard Worker     aom_free(src);
336*77c1e3ccSAndroid Build Coastguard Worker     aom_free(src16);
337*77c1e3ccSAndroid Build Coastguard Worker     aom_free(dst16);
338*77c1e3ccSAndroid Build Coastguard Worker   }
339*77c1e3ccSAndroid Build Coastguard Worker 
340*77c1e3ccSAndroid Build Coastguard Worker   int pitch_;
341*77c1e3ccSAndroid Build Coastguard Worker   int height_;
342*77c1e3ccSAndroid Build Coastguard Worker   FhtFunc<OutType> fwd_txfm_ref;
343*77c1e3ccSAndroid Build Coastguard Worker   IhtFunc<OutType> inv_txfm_ref;
344*77c1e3ccSAndroid Build Coastguard Worker   aom_bit_depth_t bit_depth_;
345*77c1e3ccSAndroid Build Coastguard Worker   int mask_;
346*77c1e3ccSAndroid Build Coastguard Worker   int num_coeffs_;
347*77c1e3ccSAndroid Build Coastguard Worker   TxfmParam txfm_param_;
348*77c1e3ccSAndroid Build Coastguard Worker 
349*77c1e3ccSAndroid Build Coastguard Worker  private:
350*77c1e3ccSAndroid Build Coastguard Worker   //  Assume transform size is 4x4, 8x8, 16x16,...
FindRowLength()351*77c1e3ccSAndroid Build Coastguard Worker   int FindRowLength() const {
352*77c1e3ccSAndroid Build Coastguard Worker     int row = 4;
353*77c1e3ccSAndroid Build Coastguard Worker     if (16 == num_coeffs_) {
354*77c1e3ccSAndroid Build Coastguard Worker       row = 4;
355*77c1e3ccSAndroid Build Coastguard Worker     } else if (64 == num_coeffs_) {
356*77c1e3ccSAndroid Build Coastguard Worker       row = 8;
357*77c1e3ccSAndroid Build Coastguard Worker     } else if (256 == num_coeffs_) {
358*77c1e3ccSAndroid Build Coastguard Worker       row = 16;
359*77c1e3ccSAndroid Build Coastguard Worker     } else if (1024 == num_coeffs_) {
360*77c1e3ccSAndroid Build Coastguard Worker       row = 32;
361*77c1e3ccSAndroid Build Coastguard Worker     }
362*77c1e3ccSAndroid Build Coastguard Worker     return row;
363*77c1e3ccSAndroid Build Coastguard Worker   }
364*77c1e3ccSAndroid Build Coastguard Worker };
365*77c1e3ccSAndroid Build Coastguard Worker 
366*77c1e3ccSAndroid Build Coastguard Worker }  // namespace libaom_test
367*77c1e3ccSAndroid Build Coastguard Worker 
368*77c1e3ccSAndroid Build Coastguard Worker #endif  // AOM_TEST_TRANSFORM_TEST_BASE_H_
369