encodetxb_test.cc (10360B)
1 /* 2 * Copyright (c) 2017, 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 12 #include <stdint.h> 13 #include <stdio.h> 14 #include <string.h> 15 #include <tuple> 16 17 #include "gtest/gtest.h" 18 19 #include "config/aom_config.h" 20 #include "config/av1_rtcd.h" 21 22 #include "aom_ports/aom_timer.h" 23 #include "aom_ports/mem.h" 24 #include "av1/common/av1_common_int.h" 25 #include "av1/common/idct.h" 26 #include "av1/common/scan.h" 27 #include "av1/common/txb_common.h" 28 #include "test/acm_random.h" 29 #include "test/register_state_check.h" 30 #include "test/util.h" 31 32 namespace { 33 using libaom_test::ACMRandom; 34 35 using GetNzMapContextsFunc = void (*)(const uint8_t *const levels, 36 const int16_t *const scan, 37 const uint16_t eob, const TX_SIZE tx_size, 38 const TX_CLASS tx_class, 39 int8_t *const coeff_contexts); 40 41 class EncodeTxbTest : public ::testing::TestWithParam<GetNzMapContextsFunc> { 42 public: 43 EncodeTxbTest() : get_nz_map_contexts_func_(GetParam()) {} 44 45 ~EncodeTxbTest() override = default; 46 47 void SetUp() override { 48 coeff_contexts_ref_ = reinterpret_cast<int8_t *>( 49 aom_memalign(16, sizeof(*coeff_contexts_ref_) * MAX_TX_SQUARE)); 50 ASSERT_NE(coeff_contexts_ref_, nullptr); 51 coeff_contexts_ = reinterpret_cast<int8_t *>( 52 aom_memalign(16, sizeof(*coeff_contexts_) * MAX_TX_SQUARE)); 53 ASSERT_NE(coeff_contexts_, nullptr); 54 } 55 56 void TearDown() override { 57 aom_free(coeff_contexts_ref_); 58 aom_free(coeff_contexts_); 59 } 60 61 void GetNzMapContextsRun() { 62 const int kNumTests = 10; 63 int result = 0; 64 65 for (int is_inter = 0; is_inter < 2; ++is_inter) { 66 for (int tx_type = DCT_DCT; tx_type < TX_TYPES; ++tx_type) { 67 const TX_CLASS tx_class = tx_type_to_class[tx_type]; 68 for (int tx_size = TX_4X4; tx_size < TX_SIZES_ALL; ++tx_size) { 69 const int bhl = get_txb_bhl((TX_SIZE)tx_size); 70 const int width = get_txb_wide((TX_SIZE)tx_size); 71 const int height = get_txb_high((TX_SIZE)tx_size); 72 const int real_width = tx_size_wide[tx_size]; 73 const int real_height = tx_size_high[tx_size]; 74 const int16_t *const scan = av1_scan_orders[tx_size][tx_type].scan; 75 76 levels_ = set_levels(levels_buf_, height); 77 for (int i = 0; i < kNumTests && !result; ++i) { 78 for (int eob = 1; eob <= width * height && !result; ++eob) { 79 InitDataWithEob(scan, bhl, eob); 80 81 av1_get_nz_map_contexts_c(levels_, scan, eob, (TX_SIZE)tx_size, 82 tx_class, coeff_contexts_ref_); 83 get_nz_map_contexts_func_(levels_, scan, eob, (TX_SIZE)tx_size, 84 tx_class, coeff_contexts_); 85 86 result = Compare(scan, eob); 87 88 EXPECT_EQ(result, 0) 89 << " tx_class " << (int)tx_class << " width " << real_width 90 << " height " << real_height << " eob " << eob; 91 } 92 } 93 } 94 } 95 } 96 } 97 98 void SpeedTestGetNzMapContextsRun() { 99 const int kNumTests = 2000000000; 100 aom_usec_timer timer; 101 aom_usec_timer timer_ref; 102 103 printf("Note: Only test the largest possible eob case!\n"); 104 for (int tx_size = TX_4X4; tx_size < TX_SIZES_ALL; ++tx_size) { 105 const int bhl = get_txb_bhl((TX_SIZE)tx_size); 106 const int width = get_txb_wide((TX_SIZE)tx_size); 107 const int height = get_txb_high((TX_SIZE)tx_size); 108 const int real_width = tx_size_wide[tx_size]; 109 const int real_height = tx_size_high[tx_size]; 110 const TX_TYPE tx_type = DCT_DCT; 111 const TX_CLASS tx_class = tx_type_to_class[tx_type]; 112 const int16_t *const scan = av1_scan_orders[tx_size][tx_type].scan; 113 const int eob = width * height; 114 const int numTests = kNumTests / (width * height); 115 116 levels_ = set_levels(levels_buf_, height); 117 InitDataWithEob(scan, bhl, eob); 118 119 aom_usec_timer_start(&timer_ref); 120 for (int i = 0; i < numTests; ++i) { 121 av1_get_nz_map_contexts_c(levels_, scan, eob, (TX_SIZE)tx_size, 122 tx_class, coeff_contexts_ref_); 123 } 124 aom_usec_timer_mark(&timer_ref); 125 126 levels_ = set_levels(levels_buf_, height); 127 InitDataWithEob(scan, bhl, eob); 128 129 aom_usec_timer_start(&timer); 130 for (int i = 0; i < numTests; ++i) { 131 get_nz_map_contexts_func_(levels_, scan, eob, (TX_SIZE)tx_size, 132 tx_class, coeff_contexts_); 133 } 134 aom_usec_timer_mark(&timer); 135 136 const int elapsed_time_ref = 137 static_cast<int>(aom_usec_timer_elapsed(&timer_ref)); 138 const int elapsed_time = static_cast<int>(aom_usec_timer_elapsed(&timer)); 139 140 printf("get_nz_map_contexts_%2dx%2d: %7.1f ms ref %7.1f ms gain %4.2f\n", 141 real_width, real_height, elapsed_time / 1000.0, 142 elapsed_time_ref / 1000.0, 143 (elapsed_time_ref * 1.0) / (elapsed_time * 1.0)); 144 } 145 } 146 147 private: 148 void InitDataWithEob(const int16_t *const scan, const int bhl, 149 const int eob) { 150 memset(levels_buf_, 0, sizeof(levels_buf_)); 151 memset(coeff_contexts_, 0, sizeof(*coeff_contexts_) * MAX_TX_SQUARE); 152 153 for (int c = 0; c < eob; ++c) { 154 levels_[get_padded_idx(scan[c], bhl)] = 155 static_cast<uint8_t>(clamp(rnd_.Rand8(), 0, INT8_MAX)); 156 coeff_contexts_[scan[c]] = static_cast<int8_t>(rnd_.Rand16() >> 1); 157 } 158 159 memcpy(coeff_contexts_ref_, coeff_contexts_, 160 sizeof(*coeff_contexts_) * MAX_TX_SQUARE); 161 } 162 163 bool Compare(const int16_t *const scan, const int eob) const { 164 bool result = false; 165 if (memcmp(coeff_contexts_, coeff_contexts_ref_, 166 sizeof(*coeff_contexts_ref_) * MAX_TX_SQUARE)) { 167 for (int i = 0; i < eob; i++) { 168 const int pos = scan[i]; 169 if (coeff_contexts_ref_[pos] != coeff_contexts_[pos]) { 170 printf("coeff_contexts_[%d] diff:%6d (ref),%6d (opt)\n", pos, 171 coeff_contexts_ref_[pos], coeff_contexts_[pos]); 172 result = true; 173 break; 174 } 175 } 176 } 177 return result; 178 } 179 180 GetNzMapContextsFunc get_nz_map_contexts_func_; 181 ACMRandom rnd_; 182 uint8_t levels_buf_[TX_PAD_2D]; 183 uint8_t *levels_; 184 int8_t *coeff_contexts_ref_; 185 int8_t *coeff_contexts_; 186 }; 187 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EncodeTxbTest); 188 189 TEST_P(EncodeTxbTest, GetNzMapContexts) { GetNzMapContextsRun(); } 190 191 TEST_P(EncodeTxbTest, DISABLED_SpeedTestGetNzMapContexts) { 192 SpeedTestGetNzMapContextsRun(); 193 } 194 195 #if HAVE_SSE2 196 INSTANTIATE_TEST_SUITE_P(SSE2, EncodeTxbTest, 197 ::testing::Values(av1_get_nz_map_contexts_sse2)); 198 #endif 199 200 #if HAVE_NEON 201 INSTANTIATE_TEST_SUITE_P(NEON, EncodeTxbTest, 202 ::testing::Values(av1_get_nz_map_contexts_neon)); 203 #endif 204 205 using av1_txb_init_levels_func = void (*)(const tran_low_t *const coeff, 206 const int width, const int height, 207 uint8_t *const levels); 208 209 using TxbInitLevelParam = std::tuple<av1_txb_init_levels_func, int>; 210 211 class EncodeTxbInitLevelTest 212 : public ::testing::TestWithParam<TxbInitLevelParam> { 213 public: 214 ~EncodeTxbInitLevelTest() override = default; 215 void RunTest(av1_txb_init_levels_func test_func, int tx_size, int is_speed); 216 }; 217 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EncodeTxbInitLevelTest); 218 219 void EncodeTxbInitLevelTest::RunTest(av1_txb_init_levels_func test_func, 220 int tx_size, int is_speed) { 221 const int width = get_txb_wide((TX_SIZE)tx_size); 222 const int height = get_txb_high((TX_SIZE)tx_size); 223 tran_low_t coeff[MAX_TX_SQUARE]; 224 225 uint8_t levels_buf[2][TX_PAD_2D]; 226 uint8_t *const levels0 = set_levels(levels_buf[0], height); 227 uint8_t *const levels1 = set_levels(levels_buf[1], height); 228 229 ACMRandom rnd(ACMRandom::DeterministicSeed()); 230 for (int i = 0; i < width * height; i++) { 231 coeff[i] = rnd.Rand16Signed(); 232 } 233 for (int i = 0; i < TX_PAD_2D; i++) { 234 levels_buf[0][i] = rnd.Rand8(); 235 levels_buf[1][i] = rnd.Rand8(); 236 } 237 const int run_times = is_speed ? (width * height) * 10000 : 1; 238 aom_usec_timer timer; 239 aom_usec_timer_start(&timer); 240 for (int i = 0; i < run_times; ++i) { 241 av1_txb_init_levels_c(coeff, width, height, levels0); 242 } 243 const double t1 = get_time_mark(&timer); 244 aom_usec_timer_start(&timer); 245 for (int i = 0; i < run_times; ++i) { 246 test_func(coeff, width, height, levels1); 247 } 248 const double t2 = get_time_mark(&timer); 249 if (is_speed) { 250 printf("init %3dx%-3d:%7.2f/%7.2fns", width, height, t1, t2); 251 printf("(%3.2f)\n", t1 / t2); 252 } 253 const int stride = width + TX_PAD_HOR; 254 for (int r = 0; r < height + TX_PAD_VER; ++r) { 255 for (int c = 0; c < stride; ++c) { 256 ASSERT_EQ(levels_buf[0][c + r * stride], levels_buf[1][c + r * stride]) 257 << "[" << r << "," << c << "] " << run_times << width << "x" 258 << height; 259 } 260 } 261 } 262 263 TEST_P(EncodeTxbInitLevelTest, match) { 264 RunTest(GET_PARAM(0), GET_PARAM(1), 0); 265 } 266 267 TEST_P(EncodeTxbInitLevelTest, DISABLED_Speed) { 268 RunTest(GET_PARAM(0), GET_PARAM(1), 1); 269 } 270 271 #if HAVE_SSE4_1 272 INSTANTIATE_TEST_SUITE_P( 273 SSE4_1, EncodeTxbInitLevelTest, 274 ::testing::Combine(::testing::Values(&av1_txb_init_levels_sse4_1), 275 ::testing::Range(0, static_cast<int>(TX_SIZES_ALL), 1))); 276 #endif 277 #if HAVE_AVX2 278 INSTANTIATE_TEST_SUITE_P( 279 AVX2, EncodeTxbInitLevelTest, 280 ::testing::Combine(::testing::Values(&av1_txb_init_levels_avx2), 281 ::testing::Range(0, static_cast<int>(TX_SIZES_ALL), 1))); 282 #endif 283 #if HAVE_NEON 284 INSTANTIATE_TEST_SUITE_P( 285 NEON, EncodeTxbInitLevelTest, 286 ::testing::Combine(::testing::Values(&av1_txb_init_levels_neon), 287 ::testing::Range(0, static_cast<int>(TX_SIZES_ALL), 1))); 288 #endif 289 } // namespace