| OLD | NEW |
| (Empty) | |
| 1 /* |
| 2 * Copyright (c) 2012 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 <math.h> |
| 12 #include <stdlib.h> |
| 13 #include <string.h> |
| 14 |
| 15 #include "third_party/googletest/src/include/gtest/gtest.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 |
| 21 #include "./vpx_config.h" |
| 22 #include "./vp9_rtcd.h" |
| 23 #include "vp9/common/vp9_entropy.h" |
| 24 #include "vpx/vpx_codec.h" |
| 25 #include "vpx/vpx_integer.h" |
| 26 |
| 27 using libvpx_test::ACMRandom; |
| 28 |
| 29 namespace { |
| 30 #ifdef _MSC_VER |
| 31 static int round(double x) { |
| 32 if (x < 0) |
| 33 return static_cast<int>(ceil(x - 0.5)); |
| 34 else |
| 35 return static_cast<int>(floor(x + 0.5)); |
| 36 } |
| 37 #endif |
| 38 |
| 39 const int kNumCoeffs = 1024; |
| 40 const double kPi = 3.141592653589793238462643383279502884; |
| 41 void reference_32x32_dct_1d(const double in[32], double out[32]) { |
| 42 const double kInvSqrt2 = 0.707106781186547524400844362104; |
| 43 for (int k = 0; k < 32; k++) { |
| 44 out[k] = 0.0; |
| 45 for (int n = 0; n < 32; n++) |
| 46 out[k] += in[n] * cos(kPi * (2 * n + 1) * k / 64.0); |
| 47 if (k == 0) |
| 48 out[k] = out[k] * kInvSqrt2; |
| 49 } |
| 50 } |
| 51 |
| 52 void reference_32x32_dct_2d(const int16_t input[kNumCoeffs], |
| 53 double output[kNumCoeffs]) { |
| 54 // First transform columns |
| 55 for (int i = 0; i < 32; ++i) { |
| 56 double temp_in[32], temp_out[32]; |
| 57 for (int j = 0; j < 32; ++j) |
| 58 temp_in[j] = input[j*32 + i]; |
| 59 reference_32x32_dct_1d(temp_in, temp_out); |
| 60 for (int j = 0; j < 32; ++j) |
| 61 output[j * 32 + i] = temp_out[j]; |
| 62 } |
| 63 // Then transform rows |
| 64 for (int i = 0; i < 32; ++i) { |
| 65 double temp_in[32], temp_out[32]; |
| 66 for (int j = 0; j < 32; ++j) |
| 67 temp_in[j] = output[j + i*32]; |
| 68 reference_32x32_dct_1d(temp_in, temp_out); |
| 69 // Scale by some magic number |
| 70 for (int j = 0; j < 32; ++j) |
| 71 output[j + i * 32] = temp_out[j] / 4; |
| 72 } |
| 73 } |
| 74 |
| 75 typedef void (*FwdTxfmFunc)(const int16_t *in, tran_low_t *out, int stride); |
| 76 typedef void (*InvTxfmFunc)(const tran_low_t *in, uint8_t *out, int stride); |
| 77 |
| 78 typedef std::tr1::tuple<FwdTxfmFunc, InvTxfmFunc, int, vpx_bit_depth_t> |
| 79 Trans32x32Param; |
| 80 |
| 81 #if CONFIG_VP9_HIGHBITDEPTH |
| 82 void idct32x32_8(const tran_low_t *in, uint8_t *out, int stride) { |
| 83 vp9_highbd_idct32x32_1024_add_c(in, out, stride, 8); |
| 84 } |
| 85 |
| 86 void idct32x32_10(const tran_low_t *in, uint8_t *out, int stride) { |
| 87 vp9_highbd_idct32x32_1024_add_c(in, out, stride, 10); |
| 88 } |
| 89 |
| 90 void idct32x32_12(const tran_low_t *in, uint8_t *out, int stride) { |
| 91 vp9_highbd_idct32x32_1024_add_c(in, out, stride, 12); |
| 92 } |
| 93 #endif // CONFIG_VP9_HIGHBITDEPTH |
| 94 |
| 95 class Trans32x32Test : public ::testing::TestWithParam<Trans32x32Param> { |
| 96 public: |
| 97 virtual ~Trans32x32Test() {} |
| 98 virtual void SetUp() { |
| 99 fwd_txfm_ = GET_PARAM(0); |
| 100 inv_txfm_ = GET_PARAM(1); |
| 101 version_ = GET_PARAM(2); // 0: high precision forward transform |
| 102 // 1: low precision version for rd loop |
| 103 bit_depth_ = GET_PARAM(3); |
| 104 mask_ = (1 << bit_depth_) - 1; |
| 105 } |
| 106 |
| 107 virtual void TearDown() { libvpx_test::ClearSystemState(); } |
| 108 |
| 109 protected: |
| 110 int version_; |
| 111 vpx_bit_depth_t bit_depth_; |
| 112 int mask_; |
| 113 FwdTxfmFunc fwd_txfm_; |
| 114 InvTxfmFunc inv_txfm_; |
| 115 }; |
| 116 |
| 117 TEST_P(Trans32x32Test, AccuracyCheck) { |
| 118 ACMRandom rnd(ACMRandom::DeterministicSeed()); |
| 119 uint32_t max_error = 0; |
| 120 int64_t total_error = 0; |
| 121 const int count_test_block = 10000; |
| 122 DECLARE_ALIGNED(16, int16_t, test_input_block[kNumCoeffs]); |
| 123 DECLARE_ALIGNED(16, tran_low_t, test_temp_block[kNumCoeffs]); |
| 124 DECLARE_ALIGNED(16, uint8_t, dst[kNumCoeffs]); |
| 125 DECLARE_ALIGNED(16, uint8_t, src[kNumCoeffs]); |
| 126 #if CONFIG_VP9_HIGHBITDEPTH |
| 127 DECLARE_ALIGNED(16, uint16_t, dst16[kNumCoeffs]); |
| 128 DECLARE_ALIGNED(16, uint16_t, src16[kNumCoeffs]); |
| 129 #endif |
| 130 |
| 131 for (int i = 0; i < count_test_block; ++i) { |
| 132 // Initialize a test block with input range [-mask_, mask_]. |
| 133 for (int j = 0; j < kNumCoeffs; ++j) { |
| 134 if (bit_depth_ == VPX_BITS_8) { |
| 135 src[j] = rnd.Rand8(); |
| 136 dst[j] = rnd.Rand8(); |
| 137 test_input_block[j] = src[j] - dst[j]; |
| 138 #if CONFIG_VP9_HIGHBITDEPTH |
| 139 } else { |
| 140 src16[j] = rnd.Rand16() & mask_; |
| 141 dst16[j] = rnd.Rand16() & mask_; |
| 142 test_input_block[j] = src16[j] - dst16[j]; |
| 143 #endif |
| 144 } |
| 145 } |
| 146 |
| 147 ASM_REGISTER_STATE_CHECK(fwd_txfm_(test_input_block, test_temp_block, 32)); |
| 148 if (bit_depth_ == VPX_BITS_8) { |
| 149 ASM_REGISTER_STATE_CHECK(inv_txfm_(test_temp_block, dst, 32)); |
| 150 #if CONFIG_VP9_HIGHBITDEPTH |
| 151 } else { |
| 152 ASM_REGISTER_STATE_CHECK(inv_txfm_(test_temp_block, |
| 153 CONVERT_TO_BYTEPTR(dst16), 32)); |
| 154 #endif |
| 155 } |
| 156 |
| 157 for (int j = 0; j < kNumCoeffs; ++j) { |
| 158 #if CONFIG_VP9_HIGHBITDEPTH |
| 159 const uint32_t diff = |
| 160 bit_depth_ == VPX_BITS_8 ? dst[j] - src[j] : dst16[j] - src16[j]; |
| 161 #else |
| 162 const uint32_t diff = dst[j] - src[j]; |
| 163 #endif |
| 164 const uint32_t error = diff * diff; |
| 165 if (max_error < error) |
| 166 max_error = error; |
| 167 total_error += error; |
| 168 } |
| 169 } |
| 170 |
| 171 if (version_ == 1) { |
| 172 max_error /= 2; |
| 173 total_error /= 45; |
| 174 } |
| 175 |
| 176 EXPECT_GE(1u << 2 * (bit_depth_ - 8), max_error) |
| 177 << "Error: 32x32 FDCT/IDCT has an individual round-trip error > 1"; |
| 178 |
| 179 EXPECT_GE(count_test_block << 2 * (bit_depth_ - 8), total_error) |
| 180 << "Error: 32x32 FDCT/IDCT has average round-trip error > 1 per block"; |
| 181 } |
| 182 |
| 183 TEST_P(Trans32x32Test, CoeffCheck) { |
| 184 ACMRandom rnd(ACMRandom::DeterministicSeed()); |
| 185 const int count_test_block = 1000; |
| 186 |
| 187 DECLARE_ALIGNED(16, int16_t, input_block[kNumCoeffs]); |
| 188 DECLARE_ALIGNED(16, tran_low_t, output_ref_block[kNumCoeffs]); |
| 189 DECLARE_ALIGNED(16, tran_low_t, output_block[kNumCoeffs]); |
| 190 |
| 191 for (int i = 0; i < count_test_block; ++i) { |
| 192 for (int j = 0; j < kNumCoeffs; ++j) |
| 193 input_block[j] = (rnd.Rand16() & mask_) - (rnd.Rand16() & mask_); |
| 194 |
| 195 const int stride = 32; |
| 196 vp9_fdct32x32_c(input_block, output_ref_block, stride); |
| 197 ASM_REGISTER_STATE_CHECK(fwd_txfm_(input_block, output_block, stride)); |
| 198 |
| 199 if (version_ == 0) { |
| 200 for (int j = 0; j < kNumCoeffs; ++j) |
| 201 EXPECT_EQ(output_block[j], output_ref_block[j]) |
| 202 << "Error: 32x32 FDCT versions have mismatched coefficients"; |
| 203 } else { |
| 204 for (int j = 0; j < kNumCoeffs; ++j) |
| 205 EXPECT_GE(6, abs(output_block[j] - output_ref_block[j])) |
| 206 << "Error: 32x32 FDCT rd has mismatched coefficients"; |
| 207 } |
| 208 } |
| 209 } |
| 210 |
| 211 TEST_P(Trans32x32Test, MemCheck) { |
| 212 ACMRandom rnd(ACMRandom::DeterministicSeed()); |
| 213 const int count_test_block = 2000; |
| 214 |
| 215 DECLARE_ALIGNED(16, int16_t, input_extreme_block[kNumCoeffs]); |
| 216 DECLARE_ALIGNED(16, tran_low_t, output_ref_block[kNumCoeffs]); |
| 217 DECLARE_ALIGNED(16, tran_low_t, output_block[kNumCoeffs]); |
| 218 |
| 219 for (int i = 0; i < count_test_block; ++i) { |
| 220 // Initialize a test block with input range [-mask_, mask_]. |
| 221 for (int j = 0; j < kNumCoeffs; ++j) { |
| 222 input_extreme_block[j] = rnd.Rand8() & 1 ? mask_ : -mask_; |
| 223 } |
| 224 if (i == 0) { |
| 225 for (int j = 0; j < kNumCoeffs; ++j) |
| 226 input_extreme_block[j] = mask_; |
| 227 } else if (i == 1) { |
| 228 for (int j = 0; j < kNumCoeffs; ++j) |
| 229 input_extreme_block[j] = -mask_; |
| 230 } |
| 231 |
| 232 const int stride = 32; |
| 233 vp9_fdct32x32_c(input_extreme_block, output_ref_block, stride); |
| 234 ASM_REGISTER_STATE_CHECK( |
| 235 fwd_txfm_(input_extreme_block, output_block, stride)); |
| 236 |
| 237 // The minimum quant value is 4. |
| 238 for (int j = 0; j < kNumCoeffs; ++j) { |
| 239 if (version_ == 0) { |
| 240 EXPECT_EQ(output_block[j], output_ref_block[j]) |
| 241 << "Error: 32x32 FDCT versions have mismatched coefficients"; |
| 242 } else { |
| 243 EXPECT_GE(6, abs(output_block[j] - output_ref_block[j])) |
| 244 << "Error: 32x32 FDCT rd has mismatched coefficients"; |
| 245 } |
| 246 EXPECT_GE(4 * DCT_MAX_VALUE << (bit_depth_ - 8), abs(output_ref_block[j])) |
| 247 << "Error: 32x32 FDCT C has coefficient larger than 4*DCT_MAX_VALUE"; |
| 248 EXPECT_GE(4 * DCT_MAX_VALUE << (bit_depth_ - 8), abs(output_block[j])) |
| 249 << "Error: 32x32 FDCT has coefficient larger than " |
| 250 << "4*DCT_MAX_VALUE"; |
| 251 } |
| 252 } |
| 253 } |
| 254 |
| 255 TEST_P(Trans32x32Test, InverseAccuracy) { |
| 256 ACMRandom rnd(ACMRandom::DeterministicSeed()); |
| 257 const int count_test_block = 1000; |
| 258 DECLARE_ALIGNED(16, int16_t, in[kNumCoeffs]); |
| 259 DECLARE_ALIGNED(16, tran_low_t, coeff[kNumCoeffs]); |
| 260 DECLARE_ALIGNED(16, uint8_t, dst[kNumCoeffs]); |
| 261 DECLARE_ALIGNED(16, uint8_t, src[kNumCoeffs]); |
| 262 #if CONFIG_VP9_HIGHBITDEPTH |
| 263 DECLARE_ALIGNED(16, uint16_t, dst16[kNumCoeffs]); |
| 264 DECLARE_ALIGNED(16, uint16_t, src16[kNumCoeffs]); |
| 265 #endif |
| 266 |
| 267 for (int i = 0; i < count_test_block; ++i) { |
| 268 double out_r[kNumCoeffs]; |
| 269 |
| 270 // Initialize a test block with input range [-255, 255] |
| 271 for (int j = 0; j < kNumCoeffs; ++j) { |
| 272 if (bit_depth_ == VPX_BITS_8) { |
| 273 src[j] = rnd.Rand8(); |
| 274 dst[j] = rnd.Rand8(); |
| 275 in[j] = src[j] - dst[j]; |
| 276 #if CONFIG_VP9_HIGHBITDEPTH |
| 277 } else { |
| 278 src16[j] = rnd.Rand16() & mask_; |
| 279 dst16[j] = rnd.Rand16() & mask_; |
| 280 in[j] = src16[j] - dst16[j]; |
| 281 #endif |
| 282 } |
| 283 } |
| 284 |
| 285 reference_32x32_dct_2d(in, out_r); |
| 286 for (int j = 0; j < kNumCoeffs; ++j) |
| 287 coeff[j] = static_cast<tran_low_t>(round(out_r[j])); |
| 288 if (bit_depth_ == VPX_BITS_8) { |
| 289 ASM_REGISTER_STATE_CHECK(inv_txfm_(coeff, dst, 32)); |
| 290 #if CONFIG_VP9_HIGHBITDEPTH |
| 291 } else { |
| 292 ASM_REGISTER_STATE_CHECK(inv_txfm_(coeff, CONVERT_TO_BYTEPTR(dst16), 32)); |
| 293 #endif |
| 294 } |
| 295 for (int j = 0; j < kNumCoeffs; ++j) { |
| 296 #if CONFIG_VP9_HIGHBITDEPTH |
| 297 const int diff = |
| 298 bit_depth_ == VPX_BITS_8 ? dst[j] - src[j] : dst16[j] - src16[j]; |
| 299 #else |
| 300 const int diff = dst[j] - src[j]; |
| 301 #endif |
| 302 const int error = diff * diff; |
| 303 EXPECT_GE(1, error) |
| 304 << "Error: 32x32 IDCT has error " << error |
| 305 << " at index " << j; |
| 306 } |
| 307 } |
| 308 } |
| 309 |
| 310 using std::tr1::make_tuple; |
| 311 |
| 312 #if CONFIG_VP9_HIGHBITDEPTH |
| 313 INSTANTIATE_TEST_CASE_P( |
| 314 C, Trans32x32Test, |
| 315 ::testing::Values( |
| 316 make_tuple(&vp9_highbd_fdct32x32_c, |
| 317 &idct32x32_10, 0, VPX_BITS_10), |
| 318 make_tuple(&vp9_highbd_fdct32x32_rd_c, |
| 319 &idct32x32_10, 1, VPX_BITS_10), |
| 320 make_tuple(&vp9_highbd_fdct32x32_c, |
| 321 &idct32x32_12, 0, VPX_BITS_12), |
| 322 make_tuple(&vp9_highbd_fdct32x32_rd_c, |
| 323 &idct32x32_12, 1, VPX_BITS_12), |
| 324 make_tuple(&vp9_fdct32x32_c, |
| 325 &vp9_idct32x32_1024_add_c, 0, VPX_BITS_8), |
| 326 make_tuple(&vp9_fdct32x32_rd_c, |
| 327 &vp9_idct32x32_1024_add_c, 1, VPX_BITS_8))); |
| 328 #else |
| 329 INSTANTIATE_TEST_CASE_P( |
| 330 C, Trans32x32Test, |
| 331 ::testing::Values( |
| 332 make_tuple(&vp9_fdct32x32_c, |
| 333 &vp9_idct32x32_1024_add_c, 0, VPX_BITS_8), |
| 334 make_tuple(&vp9_fdct32x32_rd_c, |
| 335 &vp9_idct32x32_1024_add_c, 1, VPX_BITS_8))); |
| 336 #endif // CONFIG_VP9_HIGHBITDEPTH |
| 337 |
| 338 #if HAVE_NEON_ASM && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE |
| 339 INSTANTIATE_TEST_CASE_P( |
| 340 NEON, Trans32x32Test, |
| 341 ::testing::Values( |
| 342 make_tuple(&vp9_fdct32x32_c, |
| 343 &vp9_idct32x32_1024_add_neon, 0, VPX_BITS_8), |
| 344 make_tuple(&vp9_fdct32x32_rd_c, |
| 345 &vp9_idct32x32_1024_add_neon, 1, VPX_BITS_8))); |
| 346 #endif // HAVE_NEON_ASM && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE |
| 347 |
| 348 #if HAVE_SSE2 && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE |
| 349 INSTANTIATE_TEST_CASE_P( |
| 350 SSE2, Trans32x32Test, |
| 351 ::testing::Values( |
| 352 make_tuple(&vp9_fdct32x32_sse2, |
| 353 &vp9_idct32x32_1024_add_sse2, 0, VPX_BITS_8), |
| 354 make_tuple(&vp9_fdct32x32_rd_sse2, |
| 355 &vp9_idct32x32_1024_add_sse2, 1, VPX_BITS_8))); |
| 356 #endif // HAVE_SSE2 && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE |
| 357 |
| 358 #if HAVE_SSE2 && CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE |
| 359 INSTANTIATE_TEST_CASE_P( |
| 360 SSE2, Trans32x32Test, |
| 361 ::testing::Values( |
| 362 make_tuple(&vp9_highbd_fdct32x32_sse2, &idct32x32_10, 0, VPX_BITS_10), |
| 363 make_tuple(&vp9_highbd_fdct32x32_rd_sse2, &idct32x32_10, 1, |
| 364 VPX_BITS_10), |
| 365 make_tuple(&vp9_highbd_fdct32x32_sse2, &idct32x32_12, 0, VPX_BITS_12), |
| 366 make_tuple(&vp9_highbd_fdct32x32_rd_sse2, &idct32x32_12, 1, |
| 367 VPX_BITS_12), |
| 368 make_tuple(&vp9_fdct32x32_sse2, &vp9_idct32x32_1024_add_c, 0, |
| 369 VPX_BITS_8), |
| 370 make_tuple(&vp9_fdct32x32_rd_sse2, &vp9_idct32x32_1024_add_c, 1, |
| 371 VPX_BITS_8))); |
| 372 #endif // HAVE_SSE2 && CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE |
| 373 |
| 374 #if HAVE_AVX2 && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE |
| 375 INSTANTIATE_TEST_CASE_P( |
| 376 AVX2, Trans32x32Test, |
| 377 ::testing::Values( |
| 378 make_tuple(&vp9_fdct32x32_avx2, |
| 379 &vp9_idct32x32_1024_add_sse2, 0, VPX_BITS_8), |
| 380 make_tuple(&vp9_fdct32x32_rd_avx2, |
| 381 &vp9_idct32x32_1024_add_sse2, 1, VPX_BITS_8))); |
| 382 #endif // HAVE_AVX2 && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE |
| 383 |
| 384 #if HAVE_MSA && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE |
| 385 INSTANTIATE_TEST_CASE_P( |
| 386 MSA, Trans32x32Test, |
| 387 ::testing::Values( |
| 388 make_tuple(&vp9_fdct32x32_c, |
| 389 &vp9_idct32x32_1024_add_msa, 0, VPX_BITS_8))); |
| 390 #endif // HAVE_MSA && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE |
| 391 } // namespace |
| OLD | NEW |