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