1 /*
2 * Copyright(c) 2019 Netflix, Inc.
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 https://www.aomedia.org/license/software-license. 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 https://www.aomedia.org/license/patent-license.
10 */
11
12 /******************************************************************************
13 * @file DeblockTest.cc
14 *
15 * @brief Unit test for cdef tools:
16 * * svt_aom_lpf_{horizontal, vertical}_{4, 6, 8, 14}_sse2
17 * * svt_aom_highbd_lpf_{horizontal, vertical}_{4, 6, 8, 14}_sse2
18 *
19 * @author Cidana-Wenyao
20 *
21 ******************************************************************************/
22 #include <cmath>
23 #include <cstdlib>
24 #include <string>
25 #include "gtest/gtest.h"
26 // workaround to eliminate the compiling warning on linux
27 // The macro will conflict with definition in gtest.h
28 #ifdef __USE_GNU
29 #undef __USE_GNU // defined in EbThreads.h
30 #endif
31 #ifdef _GNU_SOURCE
32 #undef _GNU_SOURCE // defined in EbThreads.h
33 #endif
34 #include "EbDefinitions.h"
35 #include "aom_dsp_rtcd.h"
36 #include "random.h"
37 #include "util.h"
38 #include "EbUtility.h"
39 #include "EbDeblockingFilter.h"
40 #include "acm_random.h"
41 #include "EbDeblockingFilter_SSE2.h"
42 #include "EbDeblockingCommon.h"
43
44 using libaom_test::ACMRandom;
45 using ::testing::make_tuple;
46 namespace {
47
48 // define the common params
49 #define LOOP_PARAM \
50 int p, const uint8_t *blimit, const uint8_t *limit, const uint8_t *thresh
51
52 // typedef the function type and test param
53 using LbdLoopFilterFunc = void (*)(uint8_t *s, LOOP_PARAM);
54 using HbdLoopFilterFunc = void (*)(uint16_t *s, LOOP_PARAM, int bd);
55
56 using HbdLpfTestParam =
57 ::testing::tuple<HbdLoopFilterFunc, HbdLoopFilterFunc, int>;
58 using LdbLpfTestParam =
59 ::testing::tuple<LbdLoopFilterFunc, LbdLoopFilterFunc, int>;
60
get_outer_thresh(ACMRandom * rnd)61 uint8_t get_outer_thresh(ACMRandom *rnd) {
62 return static_cast<uint8_t>(rnd->PseudoUniform(3 * MAX_LOOP_FILTER + 5));
63 }
64
get_inner_thresh(ACMRandom * rnd)65 uint8_t get_inner_thresh(ACMRandom *rnd) {
66 return static_cast<uint8_t>(rnd->PseudoUniform(MAX_LOOP_FILTER + 1));
67 }
68
get_hev_thresh(ACMRandom * rnd)69 uint8_t get_hev_thresh(ACMRandom *rnd) {
70 return static_cast<uint8_t>(rnd->PseudoUniform(MAX_LOOP_FILTER + 1) >> 4);
71 }
72
73 /**
74 * @brief Unit test for deblocking assembly functions
75 *
76 * Test strategy:
77 * Feed src data generated randomly and all possible input,
78 * then check the dst buffer from target function and reference
79 * function.
80 *
81 * Expect result:
82 * The src buffer modified by deblocking from targeted function
83 * should be identical with the values from reference function.
84 *
85 * Test coverage:
86 * Test cases:
87 * blimit: [0, 3 * MAX_LOOP_FILTER + 4) as per spec 7.14
88 * limit: [0, MAX_LOOP_FILTER]
89 * hevThresh: [0, MAX_LOOP_FILTER] >> 4
90 * bitdepth: 8, 10, 12
91 *
92 */
93 template <typename Sample, typename FuncType, typename TestParamType>
94 class LoopFilterTest : public ::testing::TestWithParam<TestParamType> {
95 public:
96 enum LpfType { SINGLE };
~LoopFilterTest()97 virtual ~LoopFilterTest() {
98 }
99
SetUp()100 void SetUp() override {
101 lpf_tst_ = ::testing::get<0>(this->GetParam());
102 lpf_ref_ = ::testing::get<1>(this->GetParam());
103 bit_depth_ = ::testing::get<2>(this->GetParam());
104 mask_ = (1 << bit_depth_) - 1;
105 }
106
TearDown()107 void TearDown() override {
108 aom_clear_system_state();
109 }
110
init_buffer_with_value(uint8_t * buf,int length,uint8_t val)111 void init_buffer_with_value(uint8_t *buf, int length, uint8_t val) {
112 for (int i = 0; i < length; ++i)
113 buf[i] = val;
114 }
115
init_input_random(Sample * s,Sample * ref_s,ACMRandom * rnd)116 void init_input_random(Sample *s, Sample *ref_s, ACMRandom *rnd) {
117 for (int i = 0; i < kNumCoeffs; ++i) {
118 s[i] = rnd->Rand16() & mask_;
119 ref_s[i] = s[i];
120 }
121 }
122
run_lpf(LOOP_PARAM,int bd)123 virtual void run_lpf(LOOP_PARAM, int bd) {
124 (void)p;
125 (void)blimit;
126 (void)limit;
127 (void)thresh;
128 (void)bd;
129 }
130
run_test()131 void run_test() {
132 ACMRandom rnd(ACMRandom::DeterministicSeed());
133 const int count_test_block = 10000;
134 const int32_t p = kNumCoeffs / 32;
135 DECLARE_ALIGNED(16, Sample, tst_s[kNumCoeffs]);
136 DECLARE_ALIGNED(16, Sample, ref_s[kNumCoeffs]);
137 int err_count_total = 0;
138 int first_failure = -1;
139 start_tst_ = tst_s + 8 + p * 8;
140 start_ref_ = ref_s + 8 + p * 8;
141 for (int i = 0; i < count_test_block; ++i) {
142 int err_count = 0;
143 // randomly generate the threshold, limits
144 uint8_t tmp = get_outer_thresh(&rnd);
145 DECLARE_ALIGNED(16, uint8_t, blimit[16]);
146 init_buffer_with_value(blimit, 16, tmp);
147
148 DECLARE_ALIGNED(16, uint8_t, limit[16]);
149 tmp = get_inner_thresh(&rnd);
150 init_buffer_with_value(limit, 16, tmp);
151
152 DECLARE_ALIGNED(16, uint8_t, thresh[16]);
153 tmp = get_hev_thresh(&rnd);
154 init_buffer_with_value(thresh, 16, tmp);
155
156 // Initial sample data
157 init_input_random(tst_s, ref_s, &rnd);
158
159 // run the filters
160 run_lpf(p, blimit, limit, thresh, bit_depth_);
161
162 // check the result
163 for (int j = 0; j < kNumCoeffs; ++j)
164 err_count += ref_s[j] != tst_s[j];
165 if (err_count && !err_count_total)
166 first_failure = i;
167
168 err_count_total += err_count;
169 }
170 EXPECT_EQ(0, err_count_total)
171 << "Error: Loop8Test6Param, C output doesn't match SIMD "
172 "loopfilter output. "
173 << "First failed at test case " << first_failure;
174 }
175
176 protected:
177 int bit_depth_;
178 int mask_;
179 FuncType lpf_tst_;
180 FuncType lpf_ref_;
181 Sample *start_ref_;
182 Sample *start_tst_;
183 // loop filter type
184 LpfType lpf_type_;
185 // Horizontally and Vertically need 32x32:
186 // 8 Coeffs preceeding filtered section
187 // 16 Coefs within filtered section
188 // 8 Coeffs following filtered section
189 static const int kNumCoeffs = 32 * 32;
190 };
191
192 // class to test loop filter with low bitdepth
193 class LbdLoopFilterTest
194 : public LoopFilterTest<uint8_t, LbdLoopFilterFunc, LdbLpfTestParam> {
195 public:
LbdLoopFilterTest()196 LbdLoopFilterTest() {
197 lpf_type_ = SINGLE;
198 }
199
~LbdLoopFilterTest()200 virtual ~LbdLoopFilterTest() {
201 }
202
run_lpf(LOOP_PARAM,int bd)203 void run_lpf(LOOP_PARAM, int bd) override {
204 (void)bd;
205 lpf_tst_(start_tst_, p, blimit, limit, thresh);
206 lpf_ref_(start_ref_, p, blimit, limit, thresh);
207 }
208 };
209
TEST_P(LbdLoopFilterTest,MatchTestRandomData)210 TEST_P(LbdLoopFilterTest, MatchTestRandomData) {
211 run_test();
212 }
213
214 // class to test loop filter with high bitdepth
215 class HbdLoopFilterTest
216 : public LoopFilterTest<uint16_t, HbdLoopFilterFunc, HbdLpfTestParam> {
217 public:
HbdLoopFilterTest()218 HbdLoopFilterTest() {
219 lpf_type_ = SINGLE;
220 }
221
~HbdLoopFilterTest()222 virtual ~HbdLoopFilterTest() {
223 }
224
run_lpf(LOOP_PARAM,int bd)225 void run_lpf(LOOP_PARAM, int bd) override {
226 lpf_tst_(start_tst_, p, blimit, limit, thresh, bd);
227 lpf_ref_(start_ref_, p, blimit, limit, thresh, bd);
228 }
229 };
230
TEST_P(HbdLoopFilterTest,MatchTestRandomData)231 TEST_P(HbdLoopFilterTest, MatchTestRandomData) {
232 run_test();
233 }
234
235 // target and reference functions in different cases
236 /* clang-format off */
237 const HbdLpfTestParam kHbdLoop8Test6[] = {
238 make_tuple(&svt_aom_highbd_lpf_horizontal_4_sse2,
239 &svt_aom_highbd_lpf_horizontal_4_c, 8),
240 make_tuple(&svt_aom_highbd_lpf_horizontal_6_sse2,
241 &svt_aom_highbd_lpf_horizontal_6_c, 8),
242 make_tuple(&svt_aom_highbd_lpf_horizontal_8_sse2,
243 &svt_aom_highbd_lpf_horizontal_8_c, 8),
244 make_tuple(&svt_aom_highbd_lpf_horizontal_14_sse2,
245 &svt_aom_highbd_lpf_horizontal_14_c, 8),
246
247 make_tuple(&svt_aom_highbd_lpf_vertical_4_sse2,
248 &svt_aom_highbd_lpf_vertical_4_c, 8),
249 make_tuple(&svt_aom_highbd_lpf_vertical_6_sse2,
250 &svt_aom_highbd_lpf_vertical_6_c, 8),
251 make_tuple(&svt_aom_highbd_lpf_vertical_8_sse2,
252 &svt_aom_highbd_lpf_vertical_8_c, 8),
253 make_tuple(&svt_aom_highbd_lpf_vertical_14_sse2,
254 &svt_aom_highbd_lpf_vertical_14_c, 8),
255
256 make_tuple(&svt_aom_highbd_lpf_horizontal_4_sse2,
257 &svt_aom_highbd_lpf_horizontal_4_c, 10),
258 make_tuple(&svt_aom_highbd_lpf_horizontal_6_sse2,
259 &svt_aom_highbd_lpf_horizontal_6_c, 10),
260 make_tuple(&svt_aom_highbd_lpf_horizontal_8_sse2,
261 &svt_aom_highbd_lpf_horizontal_8_c, 10),
262 make_tuple(&svt_aom_highbd_lpf_horizontal_14_sse2,
263 &svt_aom_highbd_lpf_horizontal_14_c, 10),
264
265 make_tuple(&svt_aom_highbd_lpf_vertical_4_sse2,
266 &svt_aom_highbd_lpf_vertical_4_c, 10),
267 make_tuple(&svt_aom_highbd_lpf_vertical_6_sse2,
268 &svt_aom_highbd_lpf_vertical_6_c, 10),
269 make_tuple(&svt_aom_highbd_lpf_vertical_8_sse2,
270 &svt_aom_highbd_lpf_vertical_8_c, 10),
271 make_tuple(&svt_aom_highbd_lpf_vertical_14_sse2,
272 &svt_aom_highbd_lpf_vertical_14_c, 10),
273
274 make_tuple(&svt_aom_highbd_lpf_horizontal_4_sse2,
275 &svt_aom_highbd_lpf_horizontal_4_c, 12),
276 make_tuple(&svt_aom_highbd_lpf_horizontal_6_sse2,
277 &svt_aom_highbd_lpf_horizontal_6_c, 12),
278 make_tuple(&svt_aom_highbd_lpf_horizontal_8_sse2,
279 &svt_aom_highbd_lpf_horizontal_8_c, 12),
280 make_tuple(&svt_aom_highbd_lpf_horizontal_14_sse2,
281 &svt_aom_highbd_lpf_horizontal_14_c, 12),
282
283 make_tuple(&svt_aom_highbd_lpf_vertical_4_sse2,
284 &svt_aom_highbd_lpf_vertical_4_c, 12),
285 make_tuple(&svt_aom_highbd_lpf_vertical_6_sse2,
286 &svt_aom_highbd_lpf_vertical_6_c, 12),
287 make_tuple(&svt_aom_highbd_lpf_vertical_8_sse2,
288 &svt_aom_highbd_lpf_vertical_8_c, 12),
289 make_tuple(&svt_aom_highbd_lpf_vertical_14_sse2,
290 &svt_aom_highbd_lpf_vertical_14_c, 12)};
291
292 const LdbLpfTestParam kLoop8Test6[] = {
293 make_tuple(&svt_aom_lpf_horizontal_4_sse2, &svt_aom_lpf_horizontal_4_c, 8),
294 make_tuple(&svt_aom_lpf_vertical_4_sse2, &svt_aom_lpf_vertical_4_c, 8),
295 make_tuple(&svt_aom_lpf_horizontal_6_sse2, &svt_aom_lpf_horizontal_6_c, 8),
296 make_tuple(&svt_aom_lpf_vertical_6_sse2, &svt_aom_lpf_vertical_6_c, 8),
297 make_tuple(&svt_aom_lpf_horizontal_8_sse2, &svt_aom_lpf_horizontal_8_c, 8),
298 make_tuple(&svt_aom_lpf_vertical_8_sse2, &svt_aom_lpf_vertical_8_c, 8),
299 make_tuple(&svt_aom_lpf_horizontal_14_sse2, &svt_aom_lpf_horizontal_14_c, 8),
300 make_tuple(&svt_aom_lpf_vertical_14_sse2, &svt_aom_lpf_vertical_14_c, 8),
301 };
302 /* clang-format on */
303
304 INSTANTIATE_TEST_CASE_P(SSE2, LbdLoopFilterTest,
305 ::testing::ValuesIn(kLoop8Test6));
306 INSTANTIATE_TEST_CASE_P(SSE2, HbdLoopFilterTest,
307 ::testing::ValuesIn(kHbdLoop8Test6));
308 } // namespace
309