vp9_block_error_test.cc 6.4 KB

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