1 /* 2 * Copyright (c) 2014 The WebM project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #include <cmath> 12 #include <cstdlib> 13 #include <string> 14 15 #include "third_party/googletest/src/include/gtest/gtest.h" 16 17 #include "./vpx_config.h" 18 #include "./vp9_rtcd.h" 19 #include "test/acm_random.h" 20 #include "test/clear_system_state.h" 21 #include "test/register_state_check.h" 22 #include "test/util.h" 23 #include "vp9/common/vp9_entropy.h" 24 #include "vpx/vpx_codec.h" 25 #include "vpx/vpx_integer.h" 26 #include "vpx_dsp/vpx_dsp_common.h" 27 28 using libvpx_test::ACMRandom; 29 30 namespace { 31 const int kNumIterations = 1000; 32 33 typedef int64_t (*HBDBlockErrorFunc)(const tran_low_t *coeff, 34 const tran_low_t *dqcoeff, 35 intptr_t block_size, int64_t *ssz, 36 int bps); 37 38 typedef std::tr1::tuple<HBDBlockErrorFunc, HBDBlockErrorFunc, vpx_bit_depth_t> 39 BlockErrorParam; 40 41 typedef int64_t (*BlockErrorFunc)(const tran_low_t *coeff, 42 const tran_low_t *dqcoeff, 43 intptr_t block_size, int64_t *ssz); 44 45 template <BlockErrorFunc fn> 46 int64_t BlockError8BitWrapper(const tran_low_t *coeff, 47 const tran_low_t *dqcoeff, intptr_t block_size, 48 int64_t *ssz, int bps) { 49 EXPECT_EQ(bps, 8); 50 return fn(coeff, dqcoeff, block_size, ssz); 51 } 52 53 class BlockErrorTest : public ::testing::TestWithParam<BlockErrorParam> { 54 public: 55 virtual ~BlockErrorTest() {} 56 virtual void SetUp() { 57 error_block_op_ = GET_PARAM(0); 58 ref_error_block_op_ = GET_PARAM(1); 59 bit_depth_ = GET_PARAM(2); 60 } 61 62 virtual void TearDown() { libvpx_test::ClearSystemState(); } 63 64 protected: 65 vpx_bit_depth_t bit_depth_; 66 HBDBlockErrorFunc error_block_op_; 67 HBDBlockErrorFunc ref_error_block_op_; 68 }; 69 70 TEST_P(BlockErrorTest, OperationCheck) { 71 ACMRandom rnd(ACMRandom::DeterministicSeed()); 72 DECLARE_ALIGNED(16, tran_low_t, coeff[4096]); 73 DECLARE_ALIGNED(16, tran_low_t, dqcoeff[4096]); 74 int err_count_total = 0; 75 int first_failure = -1; 76 intptr_t block_size; 77 int64_t ssz; 78 int64_t ret; 79 int64_t ref_ssz; 80 int64_t ref_ret; 81 const int msb = bit_depth_ + 8 - 1; 82 for (int i = 0; i < kNumIterations; ++i) { 83 int err_count = 0; 84 block_size = 16 << (i % 9); // All block sizes from 4x4, 8x4 ..64x64 85 for (int j = 0; j < block_size; j++) { 86 // coeff and dqcoeff will always have at least the same sign, and this 87 // can be used for optimization, so generate test input precisely. 88 if (rnd(2)) { 89 // Positive number 90 coeff[j] = rnd(1 << msb); 91 dqcoeff[j] = rnd(1 << msb); 92 } else { 93 // Negative number 94 coeff[j] = -rnd(1 << msb); 95 dqcoeff[j] = -rnd(1 << msb); 96 } 97 } 98 ref_ret = 99 ref_error_block_op_(coeff, dqcoeff, block_size, &ref_ssz, bit_depth_); 100 ASM_REGISTER_STATE_CHECK( 101 ret = error_block_op_(coeff, dqcoeff, block_size, &ssz, bit_depth_)); 102 err_count += (ref_ret != ret) | (ref_ssz != ssz); 103 if (err_count && !err_count_total) { 104 first_failure = i; 105 } 106 err_count_total += err_count; 107 } 108 EXPECT_EQ(0, err_count_total) 109 << "Error: Error Block Test, C output doesn't match optimized output. " 110 << "First failed at test case " << first_failure; 111 } 112 113 TEST_P(BlockErrorTest, ExtremeValues) { 114 ACMRandom rnd(ACMRandom::DeterministicSeed()); 115 DECLARE_ALIGNED(16, tran_low_t, coeff[4096]); 116 DECLARE_ALIGNED(16, tran_low_t, dqcoeff[4096]); 117 int err_count_total = 0; 118 int first_failure = -1; 119 intptr_t block_size; 120 int64_t ssz; 121 int64_t ret; 122 int64_t ref_ssz; 123 int64_t ref_ret; 124 const int msb = bit_depth_ + 8 - 1; 125 int max_val = ((1 << msb) - 1); 126 for (int i = 0; i < kNumIterations; ++i) { 127 int err_count = 0; 128 int k = (i / 9) % 9; 129 130 // Change the maximum coeff value, to test different bit boundaries 131 if (k == 8 && (i % 9) == 0) { 132 max_val >>= 1; 133 } 134 block_size = 16 << (i % 9); // All block sizes from 4x4, 8x4 ..64x64 135 for (int j = 0; j < block_size; j++) { 136 if (k < 4) { 137 // Test at positive maximum values 138 coeff[j] = k % 2 ? max_val : 0; 139 dqcoeff[j] = (k >> 1) % 2 ? max_val : 0; 140 } else if (k < 8) { 141 // Test at negative maximum values 142 coeff[j] = k % 2 ? -max_val : 0; 143 dqcoeff[j] = (k >> 1) % 2 ? -max_val : 0; 144 } else { 145 if (rnd(2)) { 146 // Positive number 147 coeff[j] = rnd(1 << 14); 148 dqcoeff[j] = rnd(1 << 14); 149 } else { 150 // Negative number 151 coeff[j] = -rnd(1 << 14); 152 dqcoeff[j] = -rnd(1 << 14); 153 } 154 } 155 } 156 ref_ret = 157 ref_error_block_op_(coeff, dqcoeff, block_size, &ref_ssz, bit_depth_); 158 ASM_REGISTER_STATE_CHECK( 159 ret = error_block_op_(coeff, dqcoeff, block_size, &ssz, bit_depth_)); 160 err_count += (ref_ret != ret) | (ref_ssz != ssz); 161 if (err_count && !err_count_total) { 162 first_failure = i; 163 } 164 err_count_total += err_count; 165 } 166 EXPECT_EQ(0, err_count_total) 167 << "Error: Error Block Test, C output doesn't match optimized output. " 168 << "First failed at test case " << first_failure; 169 } 170 171 using std::tr1::make_tuple; 172 173 #if HAVE_SSE2 174 const BlockErrorParam sse2_block_error_tests[] = { 175 #if CONFIG_VP9_HIGHBITDEPTH 176 make_tuple(&vp9_highbd_block_error_sse2, &vp9_highbd_block_error_c, 177 VPX_BITS_10), 178 make_tuple(&vp9_highbd_block_error_sse2, &vp9_highbd_block_error_c, 179 VPX_BITS_12), 180 make_tuple(&vp9_highbd_block_error_sse2, &vp9_highbd_block_error_c, 181 VPX_BITS_8), 182 #endif // CONFIG_VP9_HIGHBITDEPTH 183 make_tuple(&BlockError8BitWrapper<vp9_block_error_sse2>, 184 &BlockError8BitWrapper<vp9_block_error_c>, VPX_BITS_8) 185 }; 186 187 INSTANTIATE_TEST_CASE_P(SSE2, BlockErrorTest, 188 ::testing::ValuesIn(sse2_block_error_tests)); 189 #endif // HAVE_SSE2 190 191 #if HAVE_AVX2 192 INSTANTIATE_TEST_CASE_P( 193 AVX2, BlockErrorTest, 194 ::testing::Values(make_tuple(&BlockError8BitWrapper<vp9_block_error_avx2>, 195 &BlockError8BitWrapper<vp9_block_error_c>, 196 VPX_BITS_8))); 197 #endif // HAVE_AVX2 198 } // namespace 199