2 * Copyright (c) 2017, Alliance for Open Media. All rights reserved
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.
12 #include "third_party/googletest/src/googletest/include/gtest/gtest.h"
14 #include "config/aom_config.h"
15 #include "config/aom_dsp_rtcd.h"
16 #include "config/av1_rtcd.h"
18 #include "aom/aom_codec.h"
19 #include "aom_ports/aom_timer.h"
20 #include "av1/encoder/encoder.h"
21 #include "av1/common/scan.h"
22 #include "test/acm_random.h"
23 #include "test/clear_system_state.h"
24 #include "test/register_state_check.h"
25 #include "test/util.h"
28 using libaom_test::ACMRandom
;
30 #define QUAN_PARAM_LIST \
31 const tran_low_t *coeff_ptr, intptr_t n_coeffs, const int16_t *zbin_ptr, \
32 const int16_t *round_ptr, const int16_t *quant_ptr, \
33 const int16_t *quant_shift_ptr, tran_low_t *qcoeff_ptr, \
34 tran_low_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr, \
35 const int16_t *scan, const int16_t *iscan
37 typedef void (*QuantizeFunc
)(QUAN_PARAM_LIST
);
38 typedef void (*QuantizeFuncHbd
)(QUAN_PARAM_LIST
, int log_scale
);
40 #define HBD_QUAN_FUNC \
41 fn(coeff_ptr, n_coeffs, zbin_ptr, round_ptr, quant_ptr, quant_shift_ptr, \
42 qcoeff_ptr, dqcoeff_ptr, dequant_ptr, eob_ptr, scan, iscan, log_scale)
44 #define LBD_QUAN_FUNC \
45 fn(coeff_ptr, n_coeffs, zbin_ptr, round_ptr, quant_ptr, quant_shift_ptr, \
46 qcoeff_ptr, dqcoeff_ptr, dequant_ptr, eob_ptr, scan, iscan)
48 template <QuantizeFuncHbd fn
>
49 void highbd_quan16x16_wrapper(QUAN_PARAM_LIST
) {
50 const int log_scale
= 0;
54 template <QuantizeFuncHbd fn
>
55 void highbd_quan32x32_wrapper(QUAN_PARAM_LIST
) {
56 const int log_scale
= 1;
60 template <QuantizeFuncHbd fn
>
61 void highbd_quan64x64_wrapper(QUAN_PARAM_LIST
) {
62 const int log_scale
= 2;
66 typedef enum { TYPE_B
, TYPE_DC
, TYPE_FP
} QuantType
;
68 using ::testing::tuple
;
69 typedef tuple
<QuantizeFunc
, QuantizeFunc
, TX_SIZE
, QuantType
, aom_bit_depth_t
>
77 const int kTestNum
= 1000;
79 class QuantizeTest
: public ::testing::TestWithParam
<QuantizeParam
> {
82 : quant_ref_(GET_PARAM(0)), quant_(GET_PARAM(1)), tx_size_(GET_PARAM(2)),
83 type_(GET_PARAM(3)), bd_(GET_PARAM(4)) {}
85 virtual ~QuantizeTest() {}
87 virtual void SetUp() {
88 qtab_
= reinterpret_cast<QuanTable
*>(aom_memalign(32, sizeof(*qtab_
)));
89 const int n_coeffs
= coeff_num();
90 coeff_
= reinterpret_cast<tran_low_t
*>(
91 aom_memalign(32, 6 * n_coeffs
* sizeof(tran_low_t
)));
95 virtual void TearDown() {
100 libaom_test::ClearSystemState();
103 void InitQuantizer() {
104 av1_build_quantizer(bd_
, 0, 0, 0, 0, 0, &qtab_
->quant
, &qtab_
->dequant
);
107 void QuantizeRun(bool is_loop
, int q
= 0, int test_num
= 1) {
108 tran_low_t
*coeff_ptr
= coeff_
;
109 const intptr_t n_coeffs
= coeff_num();
111 tran_low_t
*qcoeff_ref
= coeff_ptr
+ n_coeffs
;
112 tran_low_t
*dqcoeff_ref
= qcoeff_ref
+ n_coeffs
;
114 tran_low_t
*qcoeff
= dqcoeff_ref
+ n_coeffs
;
115 tran_low_t
*dqcoeff
= qcoeff
+ n_coeffs
;
116 uint16_t *eob
= (uint16_t *)(dqcoeff
+ n_coeffs
);
118 // Testing uses 2-D DCT scan order table
119 const SCAN_ORDER
*const sc
= get_default_scan(tx_size_
, DCT_DCT
);
121 // Testing uses luminance quantization table
122 const int16_t *zbin
= qtab_
->quant
.y_zbin
[q
];
124 const int16_t *round
= 0;
125 const int16_t *quant
= 0;
126 if (type_
== TYPE_B
) {
127 round
= qtab_
->quant
.y_round
[q
];
128 quant
= qtab_
->quant
.y_quant
[q
];
129 } else if (type_
== TYPE_FP
) {
130 round
= qtab_
->quant
.y_round_fp
[q
];
131 quant
= qtab_
->quant
.y_quant_fp
[q
];
134 const int16_t *quant_shift
= qtab_
->quant
.y_quant_shift
[q
];
135 const int16_t *dequant
= qtab_
->dequant
.y_dequant_QTX
[q
];
137 for (int i
= 0; i
< test_num
; ++i
) {
138 if (is_loop
) FillCoeffRandom();
140 memset(qcoeff_ref
, 0, 5 * n_coeffs
* sizeof(*qcoeff_ref
));
142 quant_ref_(coeff_ptr
, n_coeffs
, zbin
, round
, quant
, quant_shift
,
143 qcoeff_ref
, dqcoeff_ref
, dequant
, &eob
[0], sc
->scan
,
146 ASM_REGISTER_STATE_CHECK(quant_(coeff_ptr
, n_coeffs
, zbin
, round
, quant
,
147 quant_shift
, qcoeff
, dqcoeff
, dequant
,
148 &eob
[1], sc
->scan
, sc
->iscan
));
150 for (int j
= 0; j
< n_coeffs
; ++j
) {
151 ASSERT_EQ(qcoeff_ref
[j
], qcoeff
[j
])
152 << "Q mismatch on test: " << i
<< " at position: " << j
153 << " Q: " << q
<< " coeff: " << coeff_ptr
[j
];
156 for (int j
= 0; j
< n_coeffs
; ++j
) {
157 ASSERT_EQ(dqcoeff_ref
[j
], dqcoeff
[j
])
158 << "Dq mismatch on test: " << i
<< " at position: " << j
159 << " Q: " << q
<< " coeff: " << coeff_ptr
[j
];
162 ASSERT_EQ(eob
[0], eob
[1])
163 << "eobs mismatch on test: " << i
<< " Q: " << q
;
167 void CompareResults(const tran_low_t
*buf_ref
, const tran_low_t
*buf
,
168 int size
, const char *text
, int q
, int number
) {
170 for (i
= 0; i
< size
; ++i
) {
171 ASSERT_EQ(buf_ref
[i
], buf
[i
]) << text
<< " mismatch on test: " << number
172 << " at position: " << i
<< " Q: " << q
;
176 int coeff_num() const { return av1_get_max_eob(tx_size_
); }
178 void FillCoeff(tran_low_t c
) {
179 const int n_coeffs
= coeff_num();
180 for (int i
= 0; i
< n_coeffs
; ++i
) {
185 void FillCoeffRandom() {
186 const int n_coeffs
= coeff_num();
188 int num
= rnd_
.Rand16() % n_coeffs
;
189 for (int i
= 0; i
< num
; ++i
) {
190 coeff_
[i
] = GetRandomCoeff();
194 void FillCoeffZero() { FillCoeff(0); }
196 void FillCoeffConstant() {
197 tran_low_t c
= GetRandomCoeff();
203 coeff_
[0] = GetRandomCoeff();
206 void FillDcLargeNegative() {
208 // Generate a qcoeff which contains 512/-512 (0x0100/0xFE00) to catch issues
209 // like BUG=883 where the constant being compared was incorrectly
214 tran_low_t
GetRandomCoeff() {
216 if (bd_
== AOM_BITS_8
) {
218 clamp(static_cast<int16_t>(rnd_
.Rand16()), INT16_MIN
+ 1, INT16_MAX
);
220 tran_low_t min
= -(1 << (7 + bd_
));
221 tran_low_t max
= -min
- 1;
222 coeff
= clamp(static_cast<tran_low_t
>(rnd_
.Rand31()), min
, max
);
230 QuantizeFunc quant_ref_
;
237 TEST_P(QuantizeTest
, ZeroInput
) {
242 TEST_P(QuantizeTest
, LargeNegativeInput
) {
243 FillDcLargeNegative();
244 QuantizeRun(false, 0, 1);
247 TEST_P(QuantizeTest
, DcOnlyInput
) {
249 QuantizeRun(false, 0, 1);
252 TEST_P(QuantizeTest
, RandomInput
) { QuantizeRun(true, 0, kTestNum
); }
254 TEST_P(QuantizeTest
, MultipleQ
) {
255 for (int q
= 0; q
< QINDEX_RANGE
; ++q
) {
256 QuantizeRun(true, q
, kTestNum
);
260 // Force the coeff to be half the value of the dequant. This exposes a
261 // mismatch found in av1_quantize_fp_sse2().
262 TEST_P(QuantizeTest
, CoeffHalfDequant
) {
264 QuantizeRun(false, 25, 1);
267 TEST_P(QuantizeTest
, DISABLED_Speed
) {
268 tran_low_t
*coeff_ptr
= coeff_
;
269 const intptr_t n_coeffs
= coeff_num();
271 tran_low_t
*qcoeff_ref
= coeff_ptr
+ n_coeffs
;
272 tran_low_t
*dqcoeff_ref
= qcoeff_ref
+ n_coeffs
;
274 tran_low_t
*qcoeff
= dqcoeff_ref
+ n_coeffs
;
275 tran_low_t
*dqcoeff
= qcoeff
+ n_coeffs
;
276 uint16_t *eob
= (uint16_t *)(dqcoeff
+ n_coeffs
);
278 // Testing uses 2-D DCT scan order table
279 const SCAN_ORDER
*const sc
= get_default_scan(tx_size_
, DCT_DCT
);
281 // Testing uses luminance quantization table
283 const int16_t *zbin
= qtab_
->quant
.y_zbin
[q
];
284 const int16_t *round_fp
= qtab_
->quant
.y_round_fp
[q
];
285 const int16_t *quant_fp
= qtab_
->quant
.y_quant_fp
[q
];
286 const int16_t *quant_shift
= qtab_
->quant
.y_quant_shift
[q
];
287 const int16_t *dequant
= qtab_
->dequant
.y_dequant_QTX
[q
];
288 const int kNumTests
= 5000000;
289 aom_usec_timer timer
;
293 aom_usec_timer_start(&timer
);
294 for (int n
= 0; n
< kNumTests
; ++n
) {
295 quant_(coeff_ptr
, n_coeffs
, zbin
, round_fp
, quant_fp
, quant_shift
, qcoeff
,
296 dqcoeff
, dequant
, eob
, sc
->scan
, sc
->iscan
);
298 aom_usec_timer_mark(&timer
);
300 const int elapsed_time
= static_cast<int>(aom_usec_timer_elapsed(&timer
));
301 printf("Elapsed time: %d us\n", elapsed_time
);
304 using ::testing::make_tuple
;
307 const QuantizeParam kQParamArrayAvx2
[] = {
308 make_tuple(&av1_quantize_fp_c
, &av1_quantize_fp_avx2
, TX_16X16
, TYPE_FP
,
310 make_tuple(&av1_quantize_fp_c
, &av1_quantize_fp_avx2
, TX_4X16
, TYPE_FP
,
312 make_tuple(&av1_quantize_fp_c
, &av1_quantize_fp_avx2
, TX_16X4
, TYPE_FP
,
314 make_tuple(&av1_quantize_fp_c
, &av1_quantize_fp_avx2
, TX_32X8
, TYPE_FP
,
316 make_tuple(&av1_quantize_fp_c
, &av1_quantize_fp_avx2
, TX_8X32
, TYPE_FP
,
318 make_tuple(&av1_quantize_fp_32x32_c
, &av1_quantize_fp_32x32_avx2
, TX_32X32
,
319 TYPE_FP
, AOM_BITS_8
),
320 make_tuple(&av1_quantize_fp_32x32_c
, &av1_quantize_fp_32x32_avx2
, TX_16X64
,
321 TYPE_FP
, AOM_BITS_8
),
322 make_tuple(&av1_quantize_fp_32x32_c
, &av1_quantize_fp_32x32_avx2
, TX_64X16
,
323 TYPE_FP
, AOM_BITS_8
),
324 make_tuple(&av1_quantize_fp_64x64_c
, &av1_quantize_fp_64x64_avx2
, TX_64X64
,
325 TYPE_FP
, AOM_BITS_8
),
326 make_tuple(&highbd_quan16x16_wrapper
<av1_highbd_quantize_fp_c
>,
327 &highbd_quan16x16_wrapper
<av1_highbd_quantize_fp_avx2
>, TX_16X16
,
328 TYPE_FP
, AOM_BITS_8
),
329 make_tuple(&highbd_quan16x16_wrapper
<av1_highbd_quantize_fp_c
>,
330 &highbd_quan16x16_wrapper
<av1_highbd_quantize_fp_avx2
>, TX_16X16
,
331 TYPE_FP
, AOM_BITS_10
),
332 make_tuple(&highbd_quan16x16_wrapper
<av1_highbd_quantize_fp_c
>,
333 &highbd_quan16x16_wrapper
<av1_highbd_quantize_fp_avx2
>, TX_16X16
,
334 TYPE_FP
, AOM_BITS_12
),
335 make_tuple(&highbd_quan32x32_wrapper
<av1_highbd_quantize_fp_c
>,
336 &highbd_quan32x32_wrapper
<av1_highbd_quantize_fp_avx2
>, TX_32X32
,
337 TYPE_FP
, AOM_BITS_8
),
338 make_tuple(&highbd_quan32x32_wrapper
<av1_highbd_quantize_fp_c
>,
339 &highbd_quan32x32_wrapper
<av1_highbd_quantize_fp_avx2
>, TX_32X32
,
340 TYPE_FP
, AOM_BITS_10
),
341 make_tuple(&highbd_quan32x32_wrapper
<av1_highbd_quantize_fp_c
>,
342 &highbd_quan32x32_wrapper
<av1_highbd_quantize_fp_avx2
>, TX_32X32
,
343 TYPE_FP
, AOM_BITS_12
),
344 make_tuple(&highbd_quan64x64_wrapper
<av1_highbd_quantize_fp_c
>,
345 &highbd_quan64x64_wrapper
<av1_highbd_quantize_fp_avx2
>, TX_64X64
,
346 TYPE_FP
, AOM_BITS_8
),
347 make_tuple(&highbd_quan64x64_wrapper
<av1_highbd_quantize_fp_c
>,
348 &highbd_quan64x64_wrapper
<av1_highbd_quantize_fp_avx2
>, TX_64X64
,
349 TYPE_FP
, AOM_BITS_10
),
350 make_tuple(&highbd_quan64x64_wrapper
<av1_highbd_quantize_fp_c
>,
351 &highbd_quan64x64_wrapper
<av1_highbd_quantize_fp_avx2
>, TX_64X64
,
352 TYPE_FP
, AOM_BITS_12
),
353 make_tuple(&aom_highbd_quantize_b_c
, &aom_highbd_quantize_b_avx2
, TX_16X16
,
355 make_tuple(&aom_highbd_quantize_b_c
, &aom_highbd_quantize_b_avx2
, TX_16X16
,
356 TYPE_B
, AOM_BITS_10
),
357 make_tuple(&aom_highbd_quantize_b_c
, &aom_highbd_quantize_b_avx2
, TX_16X16
,
358 TYPE_B
, AOM_BITS_12
),
361 INSTANTIATE_TEST_CASE_P(AVX2
, QuantizeTest
,
362 ::testing::ValuesIn(kQParamArrayAvx2
));
366 const QuantizeParam kQParamArraySSE2
[] = {
367 make_tuple(&av1_quantize_fp_c
, &av1_quantize_fp_sse2
, TX_16X16
, TYPE_FP
,
369 make_tuple(&av1_quantize_fp_c
, &av1_quantize_fp_sse2
, TX_4X16
, TYPE_FP
,
371 make_tuple(&av1_quantize_fp_c
, &av1_quantize_fp_sse2
, TX_16X4
, TYPE_FP
,
373 make_tuple(&av1_quantize_fp_c
, &av1_quantize_fp_sse2
, TX_8X32
, TYPE_FP
,
375 make_tuple(&av1_quantize_fp_c
, &av1_quantize_fp_sse2
, TX_32X8
, TYPE_FP
,
377 make_tuple(&aom_quantize_b_c
, &aom_quantize_b_sse2
, TX_16X16
, TYPE_B
,
379 make_tuple(&aom_highbd_quantize_b_c
, &aom_highbd_quantize_b_sse2
, TX_16X16
,
381 make_tuple(&aom_highbd_quantize_b_c
, &aom_highbd_quantize_b_sse2
, TX_16X16
,
382 TYPE_B
, AOM_BITS_10
),
383 make_tuple(&aom_highbd_quantize_b_c
, &aom_highbd_quantize_b_sse2
, TX_16X16
,
384 TYPE_B
, AOM_BITS_12
),
385 make_tuple(&aom_highbd_quantize_b_32x32_c
, &aom_highbd_quantize_b_32x32_sse2
,
386 TX_32X32
, TYPE_B
, AOM_BITS_8
),
387 make_tuple(&aom_highbd_quantize_b_32x32_c
, &aom_highbd_quantize_b_32x32_sse2
,
388 TX_32X32
, TYPE_B
, AOM_BITS_10
),
389 make_tuple(&aom_highbd_quantize_b_32x32_c
, &aom_highbd_quantize_b_32x32_sse2
,
390 TX_32X32
, TYPE_B
, AOM_BITS_12
),
393 INSTANTIATE_TEST_CASE_P(SSE2
, QuantizeTest
,
394 ::testing::ValuesIn(kQParamArraySSE2
));
397 #if HAVE_SSSE3 && ARCH_X86_64
398 INSTANTIATE_TEST_CASE_P(
400 ::testing::Values(make_tuple(&aom_quantize_b_c
, &aom_quantize_b_ssse3
,
401 TX_16X16
, TYPE_B
, AOM_BITS_8
)));
403 // Like libvpx, the ssse3 and avx quantize tests do not pass.
404 // https://bugs.chromium.org/p/webm/issues/detail?id=1448
405 INSTANTIATE_TEST_CASE_P(
406 DISABLED_SSSE3_32x32
, QuantizeTest
,
407 ::testing::Values(make_tuple(&aom_quantize_b_32x32_c
,
408 &aom_quantize_b_32x32_ssse3
, TX_16X16
, TYPE_B
,
411 #endif // HAVE_SSSE3 && ARCH_X86_64
413 #if HAVE_AVX && ARCH_X86_64
414 INSTANTIATE_TEST_CASE_P(
417 make_tuple(&aom_quantize_b_c
, &aom_quantize_b_avx
, TX_16X16
, TYPE_B
,
419 // Although these tests will not pass against _c, test them against each
420 // other so there is some minor checking.
421 make_tuple(&aom_quantize_b_32x32_ssse3
, &aom_quantize_b_32x32_avx
,
422 TX_32X32
, TYPE_B
, AOM_BITS_8
)));
424 #endif // HAVE_AVX && ARCH_X86_64