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 17 #include "./vp9_rtcd.h" 18 #include "./vpx_dsp_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 "vp9/common/vp9_scan.h" 25 #include "vpx/vpx_codec.h" 26 #include "vpx/vpx_integer.h" 27 #include "vpx_ports/mem.h" 28 29 using libvpx_test::ACMRandom; 30 31 namespace { 32 33 const int kNumCoeffs = 64; 34 const double kPi = 3.141592653589793238462643383279502884; 35 36 const int kSignBiasMaxDiff255 = 1500; 37 const int kSignBiasMaxDiff15 = 10000; 38 39 typedef void (*FdctFunc)(const int16_t *in, tran_low_t *out, int stride); 40 typedef void (*IdctFunc)(const tran_low_t *in, uint8_t *out, int stride); 41 typedef void (*FhtFunc)(const int16_t *in, tran_low_t *out, int stride, 42 int tx_type); 43 typedef void (*IhtFunc)(const tran_low_t *in, uint8_t *out, int stride, 44 int tx_type); 45 46 typedef std::tr1::tuple<FdctFunc, IdctFunc, int, vpx_bit_depth_t> Dct8x8Param; 47 typedef std::tr1::tuple<FhtFunc, IhtFunc, int, vpx_bit_depth_t> Ht8x8Param; 48 typedef std::tr1::tuple<IdctFunc, IdctFunc, int, vpx_bit_depth_t> Idct8x8Param; 49 50 void reference_8x8_dct_1d(const double in[8], double out[8]) { 51 const double kInvSqrt2 = 0.707106781186547524400844362104; 52 for (int k = 0; k < 8; k++) { 53 out[k] = 0.0; 54 for (int n = 0; n < 8; n++) { 55 out[k] += in[n] * cos(kPi * (2 * n + 1) * k / 16.0); 56 } 57 if (k == 0) out[k] = out[k] * kInvSqrt2; 58 } 59 } 60 61 void reference_8x8_dct_2d(const int16_t input[kNumCoeffs], 62 double output[kNumCoeffs]) { 63 // First transform columns 64 for (int i = 0; i < 8; ++i) { 65 double temp_in[8], temp_out[8]; 66 for (int j = 0; j < 8; ++j) temp_in[j] = input[j * 8 + i]; 67 reference_8x8_dct_1d(temp_in, temp_out); 68 for (int j = 0; j < 8; ++j) output[j * 8 + i] = temp_out[j]; 69 } 70 // Then transform rows 71 for (int i = 0; i < 8; ++i) { 72 double temp_in[8], temp_out[8]; 73 for (int j = 0; j < 8; ++j) temp_in[j] = output[j + i * 8]; 74 reference_8x8_dct_1d(temp_in, temp_out); 75 // Scale by some magic number 76 for (int j = 0; j < 8; ++j) output[j + i * 8] = temp_out[j] * 2; 77 } 78 } 79 80 void fdct8x8_ref(const int16_t *in, tran_low_t *out, int stride, 81 int /*tx_type*/) { 82 vpx_fdct8x8_c(in, out, stride); 83 } 84 85 void fht8x8_ref(const int16_t *in, tran_low_t *out, int stride, int tx_type) { 86 vp9_fht8x8_c(in, out, stride, tx_type); 87 } 88 89 #if CONFIG_VP9_HIGHBITDEPTH 90 void idct8x8_10(const tran_low_t *in, uint8_t *out, int stride) { 91 vpx_highbd_idct8x8_64_add_c(in, CAST_TO_SHORTPTR(out), stride, 10); 92 } 93 94 void idct8x8_12(const tran_low_t *in, uint8_t *out, int stride) { 95 vpx_highbd_idct8x8_64_add_c(in, CAST_TO_SHORTPTR(out), stride, 12); 96 } 97 98 void iht8x8_10(const tran_low_t *in, uint8_t *out, int stride, int tx_type) { 99 vp9_highbd_iht8x8_64_add_c(in, CAST_TO_SHORTPTR(out), stride, tx_type, 10); 100 } 101 102 void iht8x8_12(const tran_low_t *in, uint8_t *out, int stride, int tx_type) { 103 vp9_highbd_iht8x8_64_add_c(in, CAST_TO_SHORTPTR(out), stride, tx_type, 12); 104 } 105 106 #if HAVE_SSE2 107 108 void idct8x8_12_add_10_c(const tran_low_t *in, uint8_t *out, int stride) { 109 vpx_highbd_idct8x8_12_add_c(in, CAST_TO_SHORTPTR(out), stride, 10); 110 } 111 112 void idct8x8_12_add_12_c(const tran_low_t *in, uint8_t *out, int stride) { 113 vpx_highbd_idct8x8_12_add_c(in, CAST_TO_SHORTPTR(out), stride, 12); 114 } 115 116 void idct8x8_12_add_10_sse2(const tran_low_t *in, uint8_t *out, int stride) { 117 vpx_highbd_idct8x8_12_add_sse2(in, CAST_TO_SHORTPTR(out), stride, 10); 118 } 119 120 void idct8x8_12_add_12_sse2(const tran_low_t *in, uint8_t *out, int stride) { 121 vpx_highbd_idct8x8_12_add_sse2(in, CAST_TO_SHORTPTR(out), stride, 12); 122 } 123 124 void idct8x8_64_add_10_sse2(const tran_low_t *in, uint8_t *out, int stride) { 125 vpx_highbd_idct8x8_64_add_sse2(in, CAST_TO_SHORTPTR(out), stride, 10); 126 } 127 128 void idct8x8_64_add_12_sse2(const tran_low_t *in, uint8_t *out, int stride) { 129 vpx_highbd_idct8x8_64_add_sse2(in, CAST_TO_SHORTPTR(out), stride, 12); 130 } 131 #endif // HAVE_SSE2 132 #endif // CONFIG_VP9_HIGHBITDEPTH 133 134 class FwdTrans8x8TestBase { 135 public: 136 virtual ~FwdTrans8x8TestBase() {} 137 138 protected: 139 virtual void RunFwdTxfm(int16_t *in, tran_low_t *out, int stride) = 0; 140 virtual void RunInvTxfm(tran_low_t *out, uint8_t *dst, int stride) = 0; 141 142 void RunSignBiasCheck() { 143 ACMRandom rnd(ACMRandom::DeterministicSeed()); 144 DECLARE_ALIGNED(16, int16_t, test_input_block[64]); 145 DECLARE_ALIGNED(16, tran_low_t, test_output_block[64]); 146 int count_sign_block[64][2]; 147 const int count_test_block = 100000; 148 149 memset(count_sign_block, 0, sizeof(count_sign_block)); 150 151 for (int i = 0; i < count_test_block; ++i) { 152 // Initialize a test block with input range [-255, 255]. 153 for (int j = 0; j < 64; ++j) { 154 test_input_block[j] = ((rnd.Rand16() >> (16 - bit_depth_)) & mask_) - 155 ((rnd.Rand16() >> (16 - bit_depth_)) & mask_); 156 } 157 ASM_REGISTER_STATE_CHECK( 158 RunFwdTxfm(test_input_block, test_output_block, pitch_)); 159 160 for (int j = 0; j < 64; ++j) { 161 if (test_output_block[j] < 0) { 162 ++count_sign_block[j][0]; 163 } else if (test_output_block[j] > 0) { 164 ++count_sign_block[j][1]; 165 } 166 } 167 } 168 169 for (int j = 0; j < 64; ++j) { 170 const int diff = abs(count_sign_block[j][0] - count_sign_block[j][1]); 171 const int max_diff = kSignBiasMaxDiff255; 172 EXPECT_LT(diff, max_diff << (bit_depth_ - 8)) 173 << "Error: 8x8 FDCT/FHT has a sign bias > " 174 << 1. * max_diff / count_test_block * 100 << "%" 175 << " for input range [-255, 255] at index " << j 176 << " count0: " << count_sign_block[j][0] 177 << " count1: " << count_sign_block[j][1] << " diff: " << diff; 178 } 179 180 memset(count_sign_block, 0, sizeof(count_sign_block)); 181 182 for (int i = 0; i < count_test_block; ++i) { 183 // Initialize a test block with input range [-mask_ / 16, mask_ / 16]. 184 for (int j = 0; j < 64; ++j) { 185 test_input_block[j] = 186 ((rnd.Rand16() & mask_) >> 4) - ((rnd.Rand16() & mask_) >> 4); 187 } 188 ASM_REGISTER_STATE_CHECK( 189 RunFwdTxfm(test_input_block, test_output_block, pitch_)); 190 191 for (int j = 0; j < 64; ++j) { 192 if (test_output_block[j] < 0) { 193 ++count_sign_block[j][0]; 194 } else if (test_output_block[j] > 0) { 195 ++count_sign_block[j][1]; 196 } 197 } 198 } 199 200 for (int j = 0; j < 64; ++j) { 201 const int diff = abs(count_sign_block[j][0] - count_sign_block[j][1]); 202 const int max_diff = kSignBiasMaxDiff15; 203 EXPECT_LT(diff, max_diff << (bit_depth_ - 8)) 204 << "Error: 8x8 FDCT/FHT has a sign bias > " 205 << 1. * max_diff / count_test_block * 100 << "%" 206 << " for input range [-15, 15] at index " << j 207 << " count0: " << count_sign_block[j][0] 208 << " count1: " << count_sign_block[j][1] << " diff: " << diff; 209 } 210 } 211 212 void RunRoundTripErrorCheck() { 213 ACMRandom rnd(ACMRandom::DeterministicSeed()); 214 int max_error = 0; 215 int total_error = 0; 216 const int count_test_block = 100000; 217 DECLARE_ALIGNED(16, int16_t, test_input_block[64]); 218 DECLARE_ALIGNED(16, tran_low_t, test_temp_block[64]); 219 DECLARE_ALIGNED(16, uint8_t, dst[64]); 220 DECLARE_ALIGNED(16, uint8_t, src[64]); 221 #if CONFIG_VP9_HIGHBITDEPTH 222 DECLARE_ALIGNED(16, uint16_t, dst16[64]); 223 DECLARE_ALIGNED(16, uint16_t, src16[64]); 224 #endif 225 226 for (int i = 0; i < count_test_block; ++i) { 227 // Initialize a test block with input range [-mask_, mask_]. 228 for (int j = 0; j < 64; ++j) { 229 if (bit_depth_ == VPX_BITS_8) { 230 src[j] = rnd.Rand8(); 231 dst[j] = rnd.Rand8(); 232 test_input_block[j] = src[j] - dst[j]; 233 #if CONFIG_VP9_HIGHBITDEPTH 234 } else { 235 src16[j] = rnd.Rand16() & mask_; 236 dst16[j] = rnd.Rand16() & mask_; 237 test_input_block[j] = src16[j] - dst16[j]; 238 #endif 239 } 240 } 241 242 ASM_REGISTER_STATE_CHECK( 243 RunFwdTxfm(test_input_block, test_temp_block, pitch_)); 244 for (int j = 0; j < 64; ++j) { 245 if (test_temp_block[j] > 0) { 246 test_temp_block[j] += 2; 247 test_temp_block[j] /= 4; 248 test_temp_block[j] *= 4; 249 } else { 250 test_temp_block[j] -= 2; 251 test_temp_block[j] /= 4; 252 test_temp_block[j] *= 4; 253 } 254 } 255 if (bit_depth_ == VPX_BITS_8) { 256 ASM_REGISTER_STATE_CHECK(RunInvTxfm(test_temp_block, dst, pitch_)); 257 #if CONFIG_VP9_HIGHBITDEPTH 258 } else { 259 ASM_REGISTER_STATE_CHECK( 260 RunInvTxfm(test_temp_block, CAST_TO_BYTEPTR(dst16), pitch_)); 261 #endif 262 } 263 264 for (int j = 0; j < 64; ++j) { 265 #if CONFIG_VP9_HIGHBITDEPTH 266 const int diff = 267 bit_depth_ == VPX_BITS_8 ? dst[j] - src[j] : dst16[j] - src16[j]; 268 #else 269 const int diff = dst[j] - src[j]; 270 #endif 271 const int error = diff * diff; 272 if (max_error < error) max_error = error; 273 total_error += error; 274 } 275 } 276 277 EXPECT_GE(1 << 2 * (bit_depth_ - 8), max_error) 278 << "Error: 8x8 FDCT/IDCT or FHT/IHT has an individual" 279 << " roundtrip error > 1"; 280 281 EXPECT_GE((count_test_block << 2 * (bit_depth_ - 8)) / 5, total_error) 282 << "Error: 8x8 FDCT/IDCT or FHT/IHT has average roundtrip " 283 << "error > 1/5 per block"; 284 } 285 286 void RunExtremalCheck() { 287 ACMRandom rnd(ACMRandom::DeterministicSeed()); 288 int max_error = 0; 289 int total_error = 0; 290 int total_coeff_error = 0; 291 const int count_test_block = 100000; 292 DECLARE_ALIGNED(16, int16_t, test_input_block[64]); 293 DECLARE_ALIGNED(16, tran_low_t, test_temp_block[64]); 294 DECLARE_ALIGNED(16, tran_low_t, ref_temp_block[64]); 295 DECLARE_ALIGNED(16, uint8_t, dst[64]); 296 DECLARE_ALIGNED(16, uint8_t, src[64]); 297 #if CONFIG_VP9_HIGHBITDEPTH 298 DECLARE_ALIGNED(16, uint16_t, dst16[64]); 299 DECLARE_ALIGNED(16, uint16_t, src16[64]); 300 #endif 301 302 for (int i = 0; i < count_test_block; ++i) { 303 // Initialize a test block with input range [-mask_, mask_]. 304 for (int j = 0; j < 64; ++j) { 305 if (bit_depth_ == VPX_BITS_8) { 306 if (i == 0) { 307 src[j] = 255; 308 dst[j] = 0; 309 } else if (i == 1) { 310 src[j] = 0; 311 dst[j] = 255; 312 } else { 313 src[j] = rnd.Rand8() % 2 ? 255 : 0; 314 dst[j] = rnd.Rand8() % 2 ? 255 : 0; 315 } 316 test_input_block[j] = src[j] - dst[j]; 317 #if CONFIG_VP9_HIGHBITDEPTH 318 } else { 319 if (i == 0) { 320 src16[j] = mask_; 321 dst16[j] = 0; 322 } else if (i == 1) { 323 src16[j] = 0; 324 dst16[j] = mask_; 325 } else { 326 src16[j] = rnd.Rand8() % 2 ? mask_ : 0; 327 dst16[j] = rnd.Rand8() % 2 ? mask_ : 0; 328 } 329 test_input_block[j] = src16[j] - dst16[j]; 330 #endif 331 } 332 } 333 334 ASM_REGISTER_STATE_CHECK( 335 RunFwdTxfm(test_input_block, test_temp_block, pitch_)); 336 ASM_REGISTER_STATE_CHECK( 337 fwd_txfm_ref(test_input_block, ref_temp_block, pitch_, tx_type_)); 338 if (bit_depth_ == VPX_BITS_8) { 339 ASM_REGISTER_STATE_CHECK(RunInvTxfm(test_temp_block, dst, pitch_)); 340 #if CONFIG_VP9_HIGHBITDEPTH 341 } else { 342 ASM_REGISTER_STATE_CHECK( 343 RunInvTxfm(test_temp_block, CAST_TO_BYTEPTR(dst16), pitch_)); 344 #endif 345 } 346 347 for (int j = 0; j < 64; ++j) { 348 #if CONFIG_VP9_HIGHBITDEPTH 349 const int diff = 350 bit_depth_ == VPX_BITS_8 ? dst[j] - src[j] : dst16[j] - src16[j]; 351 #else 352 const int diff = dst[j] - src[j]; 353 #endif 354 const int error = diff * diff; 355 if (max_error < error) max_error = error; 356 total_error += error; 357 358 const int coeff_diff = test_temp_block[j] - ref_temp_block[j]; 359 total_coeff_error += abs(coeff_diff); 360 } 361 362 EXPECT_GE(1 << 2 * (bit_depth_ - 8), max_error) 363 << "Error: Extremal 8x8 FDCT/IDCT or FHT/IHT has" 364 << "an individual roundtrip error > 1"; 365 366 EXPECT_GE((count_test_block << 2 * (bit_depth_ - 8)) / 5, total_error) 367 << "Error: Extremal 8x8 FDCT/IDCT or FHT/IHT has average" 368 << " roundtrip error > 1/5 per block"; 369 370 EXPECT_EQ(0, total_coeff_error) 371 << "Error: Extremal 8x8 FDCT/FHT has" 372 << "overflow issues in the intermediate steps > 1"; 373 } 374 } 375 376 void RunInvAccuracyCheck() { 377 ACMRandom rnd(ACMRandom::DeterministicSeed()); 378 const int count_test_block = 1000; 379 DECLARE_ALIGNED(16, int16_t, in[kNumCoeffs]); 380 DECLARE_ALIGNED(16, tran_low_t, coeff[kNumCoeffs]); 381 DECLARE_ALIGNED(16, uint8_t, dst[kNumCoeffs]); 382 DECLARE_ALIGNED(16, uint8_t, src[kNumCoeffs]); 383 #if CONFIG_VP9_HIGHBITDEPTH 384 DECLARE_ALIGNED(16, uint16_t, src16[kNumCoeffs]); 385 DECLARE_ALIGNED(16, uint16_t, dst16[kNumCoeffs]); 386 #endif 387 388 for (int i = 0; i < count_test_block; ++i) { 389 double out_r[kNumCoeffs]; 390 391 // Initialize a test block with input range [-255, 255]. 392 for (int j = 0; j < kNumCoeffs; ++j) { 393 if (bit_depth_ == VPX_BITS_8) { 394 src[j] = rnd.Rand8() % 2 ? 255 : 0; 395 dst[j] = src[j] > 0 ? 0 : 255; 396 in[j] = src[j] - dst[j]; 397 #if CONFIG_VP9_HIGHBITDEPTH 398 } else { 399 src16[j] = rnd.Rand8() % 2 ? mask_ : 0; 400 dst16[j] = src16[j] > 0 ? 0 : mask_; 401 in[j] = src16[j] - dst16[j]; 402 #endif 403 } 404 } 405 406 reference_8x8_dct_2d(in, out_r); 407 for (int j = 0; j < kNumCoeffs; ++j) { 408 coeff[j] = static_cast<tran_low_t>(round(out_r[j])); 409 } 410 411 if (bit_depth_ == VPX_BITS_8) { 412 ASM_REGISTER_STATE_CHECK(RunInvTxfm(coeff, dst, pitch_)); 413 #if CONFIG_VP9_HIGHBITDEPTH 414 } else { 415 ASM_REGISTER_STATE_CHECK( 416 RunInvTxfm(coeff, CAST_TO_BYTEPTR(dst16), pitch_)); 417 #endif 418 } 419 420 for (int j = 0; j < kNumCoeffs; ++j) { 421 #if CONFIG_VP9_HIGHBITDEPTH 422 const int diff = 423 bit_depth_ == VPX_BITS_8 ? dst[j] - src[j] : dst16[j] - src16[j]; 424 #else 425 const int diff = dst[j] - src[j]; 426 #endif 427 const uint32_t error = diff * diff; 428 EXPECT_GE(1u << 2 * (bit_depth_ - 8), error) 429 << "Error: 8x8 IDCT has error " << error << " at index " << j; 430 } 431 } 432 } 433 434 void RunFwdAccuracyCheck() { 435 ACMRandom rnd(ACMRandom::DeterministicSeed()); 436 const int count_test_block = 1000; 437 DECLARE_ALIGNED(16, int16_t, in[kNumCoeffs]); 438 DECLARE_ALIGNED(16, tran_low_t, coeff_r[kNumCoeffs]); 439 DECLARE_ALIGNED(16, tran_low_t, coeff[kNumCoeffs]); 440 441 for (int i = 0; i < count_test_block; ++i) { 442 double out_r[kNumCoeffs]; 443 444 // Initialize a test block with input range [-mask_, mask_]. 445 for (int j = 0; j < kNumCoeffs; ++j) { 446 in[j] = rnd.Rand8() % 2 == 0 ? mask_ : -mask_; 447 } 448 449 RunFwdTxfm(in, coeff, pitch_); 450 reference_8x8_dct_2d(in, out_r); 451 for (int j = 0; j < kNumCoeffs; ++j) { 452 coeff_r[j] = static_cast<tran_low_t>(round(out_r[j])); 453 } 454 455 for (int j = 0; j < kNumCoeffs; ++j) { 456 const int32_t diff = coeff[j] - coeff_r[j]; 457 const uint32_t error = diff * diff; 458 EXPECT_GE(9u << 2 * (bit_depth_ - 8), error) 459 << "Error: 8x8 DCT has error " << error << " at index " << j; 460 } 461 } 462 } 463 464 void CompareInvReference(IdctFunc ref_txfm, int thresh) { 465 ACMRandom rnd(ACMRandom::DeterministicSeed()); 466 const int count_test_block = 10000; 467 const int eob = 12; 468 DECLARE_ALIGNED(16, tran_low_t, coeff[kNumCoeffs]); 469 DECLARE_ALIGNED(16, uint8_t, dst[kNumCoeffs]); 470 DECLARE_ALIGNED(16, uint8_t, ref[kNumCoeffs]); 471 #if CONFIG_VP9_HIGHBITDEPTH 472 DECLARE_ALIGNED(16, uint16_t, dst16[kNumCoeffs]); 473 DECLARE_ALIGNED(16, uint16_t, ref16[kNumCoeffs]); 474 #endif 475 const int16_t *scan = vp9_default_scan_orders[TX_8X8].scan; 476 477 for (int i = 0; i < count_test_block; ++i) { 478 for (int j = 0; j < kNumCoeffs; ++j) { 479 if (j < eob) { 480 // Random values less than the threshold, either positive or negative 481 coeff[scan[j]] = rnd(thresh) * (1 - 2 * (i % 2)); 482 } else { 483 coeff[scan[j]] = 0; 484 } 485 if (bit_depth_ == VPX_BITS_8) { 486 dst[j] = 0; 487 ref[j] = 0; 488 #if CONFIG_VP9_HIGHBITDEPTH 489 } else { 490 dst16[j] = 0; 491 ref16[j] = 0; 492 #endif 493 } 494 } 495 if (bit_depth_ == VPX_BITS_8) { 496 ref_txfm(coeff, ref, pitch_); 497 ASM_REGISTER_STATE_CHECK(RunInvTxfm(coeff, dst, pitch_)); 498 #if CONFIG_VP9_HIGHBITDEPTH 499 } else { 500 ref_txfm(coeff, CAST_TO_BYTEPTR(ref16), pitch_); 501 ASM_REGISTER_STATE_CHECK( 502 RunInvTxfm(coeff, CAST_TO_BYTEPTR(dst16), pitch_)); 503 #endif 504 } 505 506 for (int j = 0; j < kNumCoeffs; ++j) { 507 #if CONFIG_VP9_HIGHBITDEPTH 508 const int diff = 509 bit_depth_ == VPX_BITS_8 ? dst[j] - ref[j] : dst16[j] - ref16[j]; 510 #else 511 const int diff = dst[j] - ref[j]; 512 #endif 513 const uint32_t error = diff * diff; 514 EXPECT_EQ(0u, error) << "Error: 8x8 IDCT has error " << error 515 << " at index " << j; 516 } 517 } 518 } 519 int pitch_; 520 int tx_type_; 521 FhtFunc fwd_txfm_ref; 522 vpx_bit_depth_t bit_depth_; 523 int mask_; 524 }; 525 526 class FwdTrans8x8DCT : public FwdTrans8x8TestBase, 527 public ::testing::TestWithParam<Dct8x8Param> { 528 public: 529 virtual ~FwdTrans8x8DCT() {} 530 531 virtual void SetUp() { 532 fwd_txfm_ = GET_PARAM(0); 533 inv_txfm_ = GET_PARAM(1); 534 tx_type_ = GET_PARAM(2); 535 pitch_ = 8; 536 fwd_txfm_ref = fdct8x8_ref; 537 bit_depth_ = GET_PARAM(3); 538 mask_ = (1 << bit_depth_) - 1; 539 } 540 541 virtual void TearDown() { libvpx_test::ClearSystemState(); } 542 543 protected: 544 void RunFwdTxfm(int16_t *in, tran_low_t *out, int stride) { 545 fwd_txfm_(in, out, stride); 546 } 547 void RunInvTxfm(tran_low_t *out, uint8_t *dst, int stride) { 548 inv_txfm_(out, dst, stride); 549 } 550 551 FdctFunc fwd_txfm_; 552 IdctFunc inv_txfm_; 553 }; 554 555 TEST_P(FwdTrans8x8DCT, SignBiasCheck) { RunSignBiasCheck(); } 556 557 TEST_P(FwdTrans8x8DCT, RoundTripErrorCheck) { RunRoundTripErrorCheck(); } 558 559 TEST_P(FwdTrans8x8DCT, ExtremalCheck) { RunExtremalCheck(); } 560 561 TEST_P(FwdTrans8x8DCT, FwdAccuracyCheck) { RunFwdAccuracyCheck(); } 562 563 TEST_P(FwdTrans8x8DCT, InvAccuracyCheck) { RunInvAccuracyCheck(); } 564 565 class FwdTrans8x8HT : public FwdTrans8x8TestBase, 566 public ::testing::TestWithParam<Ht8x8Param> { 567 public: 568 virtual ~FwdTrans8x8HT() {} 569 570 virtual void SetUp() { 571 fwd_txfm_ = GET_PARAM(0); 572 inv_txfm_ = GET_PARAM(1); 573 tx_type_ = GET_PARAM(2); 574 pitch_ = 8; 575 fwd_txfm_ref = fht8x8_ref; 576 bit_depth_ = GET_PARAM(3); 577 mask_ = (1 << bit_depth_) - 1; 578 } 579 580 virtual void TearDown() { libvpx_test::ClearSystemState(); } 581 582 protected: 583 void RunFwdTxfm(int16_t *in, tran_low_t *out, int stride) { 584 fwd_txfm_(in, out, stride, tx_type_); 585 } 586 void RunInvTxfm(tran_low_t *out, uint8_t *dst, int stride) { 587 inv_txfm_(out, dst, stride, tx_type_); 588 } 589 590 FhtFunc fwd_txfm_; 591 IhtFunc inv_txfm_; 592 }; 593 594 TEST_P(FwdTrans8x8HT, SignBiasCheck) { RunSignBiasCheck(); } 595 596 TEST_P(FwdTrans8x8HT, RoundTripErrorCheck) { RunRoundTripErrorCheck(); } 597 598 TEST_P(FwdTrans8x8HT, ExtremalCheck) { RunExtremalCheck(); } 599 600 class InvTrans8x8DCT : public FwdTrans8x8TestBase, 601 public ::testing::TestWithParam<Idct8x8Param> { 602 public: 603 virtual ~InvTrans8x8DCT() {} 604 605 virtual void SetUp() { 606 ref_txfm_ = GET_PARAM(0); 607 inv_txfm_ = GET_PARAM(1); 608 thresh_ = GET_PARAM(2); 609 pitch_ = 8; 610 bit_depth_ = GET_PARAM(3); 611 mask_ = (1 << bit_depth_) - 1; 612 } 613 614 virtual void TearDown() { libvpx_test::ClearSystemState(); } 615 616 protected: 617 void RunInvTxfm(tran_low_t *out, uint8_t *dst, int stride) { 618 inv_txfm_(out, dst, stride); 619 } 620 void RunFwdTxfm(int16_t * /*out*/, tran_low_t * /*dst*/, int /*stride*/) {} 621 622 IdctFunc ref_txfm_; 623 IdctFunc inv_txfm_; 624 int thresh_; 625 }; 626 627 TEST_P(InvTrans8x8DCT, CompareReference) { 628 CompareInvReference(ref_txfm_, thresh_); 629 } 630 631 using std::tr1::make_tuple; 632 633 #if CONFIG_VP9_HIGHBITDEPTH 634 INSTANTIATE_TEST_CASE_P( 635 C, FwdTrans8x8DCT, 636 ::testing::Values( 637 make_tuple(&vpx_fdct8x8_c, &vpx_idct8x8_64_add_c, 0, VPX_BITS_8), 638 make_tuple(&vpx_highbd_fdct8x8_c, &idct8x8_10, 0, VPX_BITS_10), 639 make_tuple(&vpx_highbd_fdct8x8_c, &idct8x8_12, 0, VPX_BITS_12))); 640 #else 641 INSTANTIATE_TEST_CASE_P(C, FwdTrans8x8DCT, 642 ::testing::Values(make_tuple(&vpx_fdct8x8_c, 643 &vpx_idct8x8_64_add_c, 0, 644 VPX_BITS_8))); 645 #endif // CONFIG_VP9_HIGHBITDEPTH 646 647 #if CONFIG_VP9_HIGHBITDEPTH 648 INSTANTIATE_TEST_CASE_P( 649 C, FwdTrans8x8HT, 650 ::testing::Values( 651 make_tuple(&vp9_fht8x8_c, &vp9_iht8x8_64_add_c, 0, VPX_BITS_8), 652 make_tuple(&vp9_highbd_fht8x8_c, &iht8x8_10, 0, VPX_BITS_10), 653 make_tuple(&vp9_highbd_fht8x8_c, &iht8x8_10, 1, VPX_BITS_10), 654 make_tuple(&vp9_highbd_fht8x8_c, &iht8x8_10, 2, VPX_BITS_10), 655 make_tuple(&vp9_highbd_fht8x8_c, &iht8x8_10, 3, VPX_BITS_10), 656 make_tuple(&vp9_highbd_fht8x8_c, &iht8x8_12, 0, VPX_BITS_12), 657 make_tuple(&vp9_highbd_fht8x8_c, &iht8x8_12, 1, VPX_BITS_12), 658 make_tuple(&vp9_highbd_fht8x8_c, &iht8x8_12, 2, VPX_BITS_12), 659 make_tuple(&vp9_highbd_fht8x8_c, &iht8x8_12, 3, VPX_BITS_12), 660 make_tuple(&vp9_fht8x8_c, &vp9_iht8x8_64_add_c, 1, VPX_BITS_8), 661 make_tuple(&vp9_fht8x8_c, &vp9_iht8x8_64_add_c, 2, VPX_BITS_8), 662 make_tuple(&vp9_fht8x8_c, &vp9_iht8x8_64_add_c, 3, VPX_BITS_8))); 663 #else 664 INSTANTIATE_TEST_CASE_P( 665 C, FwdTrans8x8HT, 666 ::testing::Values( 667 make_tuple(&vp9_fht8x8_c, &vp9_iht8x8_64_add_c, 0, VPX_BITS_8), 668 make_tuple(&vp9_fht8x8_c, &vp9_iht8x8_64_add_c, 1, VPX_BITS_8), 669 make_tuple(&vp9_fht8x8_c, &vp9_iht8x8_64_add_c, 2, VPX_BITS_8), 670 make_tuple(&vp9_fht8x8_c, &vp9_iht8x8_64_add_c, 3, VPX_BITS_8))); 671 #endif // CONFIG_VP9_HIGHBITDEPTH 672 673 #if HAVE_NEON && !CONFIG_EMULATE_HARDWARE 674 INSTANTIATE_TEST_CASE_P(NEON, FwdTrans8x8DCT, 675 ::testing::Values(make_tuple(&vpx_fdct8x8_neon, 676 &vpx_idct8x8_64_add_neon, 677 0, VPX_BITS_8))); 678 #if !CONFIG_VP9_HIGHBITDEPTH 679 INSTANTIATE_TEST_CASE_P( 680 NEON, FwdTrans8x8HT, 681 ::testing::Values( 682 make_tuple(&vp9_fht8x8_c, &vp9_iht8x8_64_add_neon, 0, VPX_BITS_8), 683 make_tuple(&vp9_fht8x8_c, &vp9_iht8x8_64_add_neon, 1, VPX_BITS_8), 684 make_tuple(&vp9_fht8x8_c, &vp9_iht8x8_64_add_neon, 2, VPX_BITS_8), 685 make_tuple(&vp9_fht8x8_c, &vp9_iht8x8_64_add_neon, 3, VPX_BITS_8))); 686 #endif // !CONFIG_VP9_HIGHBITDEPTH 687 #endif // HAVE_NEON && !CONFIG_EMULATE_HARDWARE 688 689 #if HAVE_SSE2 && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE 690 INSTANTIATE_TEST_CASE_P(SSE2, FwdTrans8x8DCT, 691 ::testing::Values(make_tuple(&vpx_fdct8x8_sse2, 692 &vpx_idct8x8_64_add_sse2, 693 0, VPX_BITS_8))); 694 INSTANTIATE_TEST_CASE_P( 695 SSE2, FwdTrans8x8HT, 696 ::testing::Values( 697 make_tuple(&vp9_fht8x8_sse2, &vp9_iht8x8_64_add_sse2, 0, VPX_BITS_8), 698 make_tuple(&vp9_fht8x8_sse2, &vp9_iht8x8_64_add_sse2, 1, VPX_BITS_8), 699 make_tuple(&vp9_fht8x8_sse2, &vp9_iht8x8_64_add_sse2, 2, VPX_BITS_8), 700 make_tuple(&vp9_fht8x8_sse2, &vp9_iht8x8_64_add_sse2, 3, VPX_BITS_8))); 701 #endif // HAVE_SSE2 && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE 702 703 #if HAVE_SSE2 && CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE 704 INSTANTIATE_TEST_CASE_P( 705 SSE2, FwdTrans8x8DCT, 706 ::testing::Values(make_tuple(&vpx_fdct8x8_sse2, &vpx_idct8x8_64_add_c, 0, 707 VPX_BITS_8), 708 make_tuple(&vpx_highbd_fdct8x8_c, &idct8x8_64_add_10_sse2, 709 12, VPX_BITS_10), 710 make_tuple(&vpx_highbd_fdct8x8_sse2, 711 &idct8x8_64_add_10_sse2, 12, VPX_BITS_10), 712 make_tuple(&vpx_highbd_fdct8x8_c, &idct8x8_64_add_12_sse2, 713 12, VPX_BITS_12), 714 make_tuple(&vpx_highbd_fdct8x8_sse2, 715 &idct8x8_64_add_12_sse2, 12, VPX_BITS_12))); 716 717 INSTANTIATE_TEST_CASE_P( 718 SSE2, FwdTrans8x8HT, 719 ::testing::Values( 720 make_tuple(&vp9_fht8x8_sse2, &vp9_iht8x8_64_add_c, 0, VPX_BITS_8), 721 make_tuple(&vp9_fht8x8_sse2, &vp9_iht8x8_64_add_c, 1, VPX_BITS_8), 722 make_tuple(&vp9_fht8x8_sse2, &vp9_iht8x8_64_add_c, 2, VPX_BITS_8), 723 make_tuple(&vp9_fht8x8_sse2, &vp9_iht8x8_64_add_c, 3, VPX_BITS_8))); 724 725 // Optimizations take effect at a threshold of 6201, so we use a value close to 726 // that to test both branches. 727 INSTANTIATE_TEST_CASE_P( 728 SSE2, InvTrans8x8DCT, 729 ::testing::Values( 730 make_tuple(&idct8x8_12_add_10_c, &idct8x8_12_add_10_sse2, 6225, 731 VPX_BITS_10), 732 make_tuple(&idct8x8_10, &idct8x8_64_add_10_sse2, 6225, VPX_BITS_10), 733 make_tuple(&idct8x8_12_add_12_c, &idct8x8_12_add_12_sse2, 6225, 734 VPX_BITS_12), 735 make_tuple(&idct8x8_12, &idct8x8_64_add_12_sse2, 6225, VPX_BITS_12))); 736 #endif // HAVE_SSE2 && CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE 737 738 #if HAVE_SSSE3 && ARCH_X86_64 && !CONFIG_VP9_HIGHBITDEPTH && \ 739 !CONFIG_EMULATE_HARDWARE 740 INSTANTIATE_TEST_CASE_P(SSSE3, FwdTrans8x8DCT, 741 ::testing::Values(make_tuple(&vpx_fdct8x8_ssse3, 742 &vpx_idct8x8_64_add_ssse3, 743 0, VPX_BITS_8))); 744 #endif 745 746 #if HAVE_MSA && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE 747 INSTANTIATE_TEST_CASE_P(MSA, FwdTrans8x8DCT, 748 ::testing::Values(make_tuple(&vpx_fdct8x8_msa, 749 &vpx_idct8x8_64_add_msa, 0, 750 VPX_BITS_8))); 751 INSTANTIATE_TEST_CASE_P( 752 MSA, FwdTrans8x8HT, 753 ::testing::Values( 754 make_tuple(&vp9_fht8x8_msa, &vp9_iht8x8_64_add_msa, 0, VPX_BITS_8), 755 make_tuple(&vp9_fht8x8_msa, &vp9_iht8x8_64_add_msa, 1, VPX_BITS_8), 756 make_tuple(&vp9_fht8x8_msa, &vp9_iht8x8_64_add_msa, 2, VPX_BITS_8), 757 make_tuple(&vp9_fht8x8_msa, &vp9_iht8x8_64_add_msa, 3, VPX_BITS_8))); 758 #endif // HAVE_MSA && !CONFIG_VP9_HIGHBITDEPTH && !CONFIG_EMULATE_HARDWARE 759 } // namespace 760