av1_quantize_test.cc (10030B)
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 #include <stdlib.h> 12 13 #include "gtest/gtest.h" 14 15 #include "config/aom_config.h" 16 #include "config/av1_rtcd.h" 17 18 #include "test/acm_random.h" 19 #include "test/register_state_check.h" 20 #include "av1/common/scan.h" 21 #include "av1/encoder/av1_quantize.h" 22 23 namespace { 24 25 using QuantizeFpFunc = void (*)( 26 const tran_low_t *coeff_ptr, intptr_t count, const int16_t *zbin_ptr, 27 const int16_t *round_ptr, const int16_t *quant_ptr, 28 const int16_t *quant_shift_ptr, tran_low_t *qcoeff_ptr, 29 tran_low_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr, 30 const int16_t *scan, const int16_t *iscan, int log_scale); 31 32 struct QuantizeFuncParams { 33 QuantizeFuncParams(QuantizeFpFunc qF = nullptr, 34 QuantizeFpFunc qRefF = nullptr, int count = 16) 35 : qFunc(qF), qFuncRef(qRefF), coeffCount(count) {} 36 QuantizeFpFunc qFunc; 37 QuantizeFpFunc qFuncRef; 38 int coeffCount; 39 }; 40 41 using libaom_test::ACMRandom; 42 43 const int numTests = 1000; 44 const int maxSize = 1024; 45 const int roundFactorRange = 127; 46 const int dequantRange = 32768; 47 const int coeffRange = (1 << 20) - 1; 48 49 class AV1QuantizeTest : public ::testing::TestWithParam<QuantizeFuncParams> { 50 public: 51 void RunQuantizeTest() { 52 ACMRandom rnd(ACMRandom::DeterministicSeed()); 53 DECLARE_ALIGNED(16, tran_low_t, coeff_ptr[maxSize]); 54 DECLARE_ALIGNED(16, int16_t, zbin_ptr[8]); 55 DECLARE_ALIGNED(16, int16_t, round_ptr[8]); 56 DECLARE_ALIGNED(16, int16_t, quant_ptr[8]); 57 DECLARE_ALIGNED(16, int16_t, quant_shift_ptr[8]); 58 DECLARE_ALIGNED(16, tran_low_t, qcoeff_ptr[maxSize]); 59 DECLARE_ALIGNED(16, tran_low_t, dqcoeff_ptr[maxSize]); 60 DECLARE_ALIGNED(16, tran_low_t, ref_qcoeff_ptr[maxSize]); 61 DECLARE_ALIGNED(16, tran_low_t, ref_dqcoeff_ptr[maxSize]); 62 DECLARE_ALIGNED(16, int16_t, dequant_ptr[8]); 63 uint16_t eob; 64 uint16_t ref_eob; 65 int err_count_total = 0; 66 int first_failure = -1; 67 int count = params_.coeffCount; 68 const TX_SIZE txSize = getTxSize(count); 69 int log_scale = (txSize == TX_32X32); 70 QuantizeFpFunc quanFunc = params_.qFunc; 71 QuantizeFpFunc quanFuncRef = params_.qFuncRef; 72 73 const SCAN_ORDER scanOrder = av1_scan_orders[txSize][DCT_DCT]; 74 for (int i = 0; i < numTests; i++) { 75 int err_count = 0; 76 ref_eob = eob = UINT16_MAX; 77 for (int j = 0; j < count; j++) { 78 coeff_ptr[j] = rnd(coeffRange); 79 } 80 81 for (int j = 0; j < 2; j++) { 82 zbin_ptr[j] = rnd.Rand16Signed(); 83 quant_shift_ptr[j] = rnd.Rand16Signed(); 84 // int16_t positive 85 dequant_ptr[j] = abs(rnd(dequantRange)); 86 quant_ptr[j] = static_cast<int16_t>((1 << 16) / dequant_ptr[j]); 87 round_ptr[j] = (abs(rnd(roundFactorRange)) * dequant_ptr[j]) >> 7; 88 } 89 for (int j = 2; j < 8; ++j) { 90 zbin_ptr[j] = zbin_ptr[1]; 91 quant_shift_ptr[j] = quant_shift_ptr[1]; 92 dequant_ptr[j] = dequant_ptr[1]; 93 quant_ptr[j] = quant_ptr[1]; 94 round_ptr[j] = round_ptr[1]; 95 } 96 quanFuncRef(coeff_ptr, count, zbin_ptr, round_ptr, quant_ptr, 97 quant_shift_ptr, ref_qcoeff_ptr, ref_dqcoeff_ptr, dequant_ptr, 98 &ref_eob, scanOrder.scan, scanOrder.iscan, log_scale); 99 100 API_REGISTER_STATE_CHECK( 101 quanFunc(coeff_ptr, count, zbin_ptr, round_ptr, quant_ptr, 102 quant_shift_ptr, qcoeff_ptr, dqcoeff_ptr, dequant_ptr, &eob, 103 scanOrder.scan, scanOrder.iscan, log_scale)); 104 105 for (int j = 0; j < count; ++j) { 106 err_count += (ref_qcoeff_ptr[j] != qcoeff_ptr[j]) | 107 (ref_dqcoeff_ptr[j] != dqcoeff_ptr[j]); 108 ASSERT_EQ(ref_qcoeff_ptr[j], qcoeff_ptr[j]) 109 << "qcoeff error: i = " << i << " j = " << j << "\n"; 110 EXPECT_EQ(ref_dqcoeff_ptr[j], dqcoeff_ptr[j]) 111 << "dqcoeff error: i = " << i << " j = " << j << "\n"; 112 } 113 EXPECT_EQ(ref_eob, eob) << "eob error: " 114 << "i = " << i << "\n"; 115 err_count += (ref_eob != eob); 116 if (err_count && !err_count_total) { 117 first_failure = i; 118 } 119 err_count_total += err_count; 120 } 121 EXPECT_EQ(0, err_count_total) 122 << "Error: Quantization Test, C output doesn't match SSE2 output. " 123 << "First failed at test case " << first_failure; 124 } 125 126 void RunEobTest() { 127 ACMRandom rnd(ACMRandom::DeterministicSeed()); 128 DECLARE_ALIGNED(16, tran_low_t, coeff_ptr[maxSize]); 129 DECLARE_ALIGNED(16, int16_t, zbin_ptr[8]); 130 DECLARE_ALIGNED(16, int16_t, round_ptr[8]); 131 DECLARE_ALIGNED(16, int16_t, quant_ptr[8]); 132 DECLARE_ALIGNED(16, int16_t, quant_shift_ptr[8]); 133 DECLARE_ALIGNED(16, tran_low_t, qcoeff_ptr[maxSize]); 134 DECLARE_ALIGNED(16, tran_low_t, dqcoeff_ptr[maxSize]); 135 DECLARE_ALIGNED(16, tran_low_t, ref_qcoeff_ptr[maxSize]); 136 DECLARE_ALIGNED(16, tran_low_t, ref_dqcoeff_ptr[maxSize]); 137 DECLARE_ALIGNED(16, int16_t, dequant_ptr[8]); 138 uint16_t eob; 139 uint16_t ref_eob; 140 int count = params_.coeffCount; 141 const TX_SIZE txSize = getTxSize(count); 142 int log_scale = (txSize == TX_32X32); 143 QuantizeFpFunc quanFunc = params_.qFunc; 144 QuantizeFpFunc quanFuncRef = params_.qFuncRef; 145 const SCAN_ORDER scanOrder = av1_scan_orders[txSize][DCT_DCT]; 146 147 for (int i = 0; i < numTests; i++) { 148 ref_eob = eob = UINT16_MAX; 149 for (int j = 0; j < count; j++) { 150 coeff_ptr[j] = 0; 151 } 152 153 coeff_ptr[rnd(count)] = rnd(coeffRange); 154 coeff_ptr[rnd(count)] = rnd(coeffRange); 155 coeff_ptr[rnd(count)] = rnd(coeffRange); 156 157 for (int j = 0; j < 2; j++) { 158 zbin_ptr[j] = rnd.Rand16Signed(); 159 quant_shift_ptr[j] = rnd.Rand16Signed(); 160 // int16_t positive 161 dequant_ptr[j] = abs(rnd(dequantRange)); 162 quant_ptr[j] = (1 << 16) / dequant_ptr[j]; 163 round_ptr[j] = (abs(rnd(roundFactorRange)) * dequant_ptr[j]) >> 7; 164 } 165 for (int j = 2; j < 8; ++j) { 166 zbin_ptr[j] = zbin_ptr[1]; 167 quant_shift_ptr[j] = quant_shift_ptr[1]; 168 dequant_ptr[j] = dequant_ptr[1]; 169 quant_ptr[j] = quant_ptr[1]; 170 round_ptr[j] = round_ptr[1]; 171 } 172 173 quanFuncRef(coeff_ptr, count, zbin_ptr, round_ptr, quant_ptr, 174 quant_shift_ptr, ref_qcoeff_ptr, ref_dqcoeff_ptr, dequant_ptr, 175 &ref_eob, scanOrder.scan, scanOrder.iscan, log_scale); 176 177 API_REGISTER_STATE_CHECK( 178 quanFunc(coeff_ptr, count, zbin_ptr, round_ptr, quant_ptr, 179 quant_shift_ptr, qcoeff_ptr, dqcoeff_ptr, dequant_ptr, &eob, 180 scanOrder.scan, scanOrder.iscan, log_scale)); 181 EXPECT_EQ(ref_eob, eob) << "eob error: " 182 << "i = " << i << "\n"; 183 } 184 } 185 186 void SetUp() override { params_ = GetParam(); } 187 188 ~AV1QuantizeTest() override = default; 189 190 private: 191 TX_SIZE getTxSize(int count) { 192 switch (count) { 193 case 16: return TX_4X4; 194 case 64: return TX_8X8; 195 case 256: return TX_16X16; 196 case 1024: return TX_32X32; 197 default: return TX_4X4; 198 } 199 } 200 201 QuantizeFuncParams params_; 202 }; 203 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AV1QuantizeTest); 204 205 TEST_P(AV1QuantizeTest, BitExactCheck) { RunQuantizeTest(); } 206 TEST_P(AV1QuantizeTest, EobVerify) { RunEobTest(); } 207 208 TEST(AV1QuantizeTest, QuantizeFpNoQmatrix) { 209 // Here we use a uniform quantizer as an example 210 const int16_t dequant_ptr[2] = { 78, 93 }; // quantize step 211 const int16_t round_ptr[2] = { 39, 46 }; // round ~= dequant / 2 212 213 // quant ~= 2^16 / dequant. This is a 16-bit fixed point representation of the 214 // inverse of quantize step. 215 const int16_t quant_ptr[2] = { 840, 704 }; 216 int log_scale = 0; 217 int coeff_count = 4; 218 const tran_low_t coeff_ptr[4] = { -449, 624, -14, 24 }; 219 const tran_low_t ref_qcoeff_ptr[4] = { -6, 7, 0, 0 }; 220 const tran_low_t ref_dqcoeff_ptr[4] = { -468, 651, 0, 0 }; 221 const int16_t scan[4] = { 0, 1, 2, 3 }; 222 tran_low_t qcoeff_ptr[4]; 223 tran_low_t dqcoeff_ptr[4]; 224 int eob = av1_quantize_fp_no_qmatrix(quant_ptr, dequant_ptr, round_ptr, 225 log_scale, scan, coeff_count, coeff_ptr, 226 qcoeff_ptr, dqcoeff_ptr); 227 EXPECT_EQ(eob, 2); 228 for (int i = 0; i < coeff_count; ++i) { 229 EXPECT_EQ(qcoeff_ptr[i], ref_qcoeff_ptr[i]); 230 EXPECT_EQ(dqcoeff_ptr[i], ref_dqcoeff_ptr[i]); 231 } 232 } 233 234 #if HAVE_SSE4_1 235 const QuantizeFuncParams qfps[4] = { 236 QuantizeFuncParams(&av1_highbd_quantize_fp_sse4_1, &av1_highbd_quantize_fp_c, 237 16), 238 QuantizeFuncParams(&av1_highbd_quantize_fp_sse4_1, &av1_highbd_quantize_fp_c, 239 64), 240 QuantizeFuncParams(&av1_highbd_quantize_fp_sse4_1, &av1_highbd_quantize_fp_c, 241 256), 242 QuantizeFuncParams(&av1_highbd_quantize_fp_sse4_1, &av1_highbd_quantize_fp_c, 243 1024), 244 }; 245 246 INSTANTIATE_TEST_SUITE_P(SSE4_1, AV1QuantizeTest, ::testing::ValuesIn(qfps)); 247 #endif // HAVE_SSE4_1 248 249 #if HAVE_AVX2 250 const QuantizeFuncParams qfps_avx2[4] = { 251 QuantizeFuncParams(&av1_highbd_quantize_fp_avx2, &av1_highbd_quantize_fp_c, 252 16), 253 QuantizeFuncParams(&av1_highbd_quantize_fp_avx2, &av1_highbd_quantize_fp_c, 254 64), 255 QuantizeFuncParams(&av1_highbd_quantize_fp_avx2, &av1_highbd_quantize_fp_c, 256 256), 257 QuantizeFuncParams(&av1_highbd_quantize_fp_avx2, &av1_highbd_quantize_fp_c, 258 1024), 259 }; 260 261 INSTANTIATE_TEST_SUITE_P(AVX2, AV1QuantizeTest, ::testing::ValuesIn(qfps_avx2)); 262 #endif // HAVE_AVX2 263 264 } // namespace