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 <limits.h> 12 #include <stdio.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_config.h" 19 #include "./vpx_dsp_rtcd.h" 20 21 #include "test/acm_random.h" 22 #include "test/clear_system_state.h" 23 #include "test/register_state_check.h" 24 #include "test/util.h" 25 #include "vpx_mem/vpx_mem.h" 26 #include "vpx_ports/vpx_timer.h" 27 28 using libvpx_test::ACMRandom; 29 30 namespace { 31 class AverageTestBase : public ::testing::Test { 32 public: 33 AverageTestBase(int width, int height) : width_(width), height_(height) {} 34 35 static void SetUpTestCase() { 36 source_data_ = reinterpret_cast<uint8_t *>( 37 vpx_memalign(kDataAlignment, kDataBlockSize)); 38 } 39 40 static void TearDownTestCase() { 41 vpx_free(source_data_); 42 source_data_ = NULL; 43 } 44 45 virtual void TearDown() { libvpx_test::ClearSystemState(); } 46 47 protected: 48 // Handle blocks up to 4 blocks 64x64 with stride up to 128 49 static const int kDataAlignment = 16; 50 static const int kDataBlockSize = 64 * 128; 51 52 virtual void SetUp() { 53 source_stride_ = (width_ + 31) & ~31; 54 rnd_.Reset(ACMRandom::DeterministicSeed()); 55 } 56 57 // Sum Pixels 58 static unsigned int ReferenceAverage8x8(const uint8_t *source, int pitch) { 59 unsigned int average = 0; 60 for (int h = 0; h < 8; ++h) { 61 for (int w = 0; w < 8; ++w) average += source[h * pitch + w]; 62 } 63 return ((average + 32) >> 6); 64 } 65 66 static unsigned int ReferenceAverage4x4(const uint8_t *source, int pitch) { 67 unsigned int average = 0; 68 for (int h = 0; h < 4; ++h) { 69 for (int w = 0; w < 4; ++w) average += source[h * pitch + w]; 70 } 71 return ((average + 8) >> 4); 72 } 73 74 void FillConstant(uint8_t fill_constant) { 75 for (int i = 0; i < width_ * height_; ++i) { 76 source_data_[i] = fill_constant; 77 } 78 } 79 80 void FillRandom() { 81 for (int i = 0; i < width_ * height_; ++i) { 82 source_data_[i] = rnd_.Rand8(); 83 } 84 } 85 86 int width_, height_; 87 static uint8_t *source_data_; 88 int source_stride_; 89 90 ACMRandom rnd_; 91 }; 92 typedef unsigned int (*AverageFunction)(const uint8_t *s, int pitch); 93 94 typedef std::tr1::tuple<int, int, int, int, AverageFunction> AvgFunc; 95 96 class AverageTest : public AverageTestBase, 97 public ::testing::WithParamInterface<AvgFunc> { 98 public: 99 AverageTest() : AverageTestBase(GET_PARAM(0), GET_PARAM(1)) {} 100 101 protected: 102 void CheckAverages() { 103 const int block_size = GET_PARAM(3); 104 unsigned int expected = 0; 105 if (block_size == 8) { 106 expected = 107 ReferenceAverage8x8(source_data_ + GET_PARAM(2), source_stride_); 108 } else if (block_size == 4) { 109 expected = 110 ReferenceAverage4x4(source_data_ + GET_PARAM(2), source_stride_); 111 } 112 113 ASM_REGISTER_STATE_CHECK( 114 GET_PARAM(4)(source_data_ + GET_PARAM(2), source_stride_)); 115 unsigned int actual = 116 GET_PARAM(4)(source_data_ + GET_PARAM(2), source_stride_); 117 118 EXPECT_EQ(expected, actual); 119 } 120 }; 121 122 typedef void (*IntProRowFunc)(int16_t hbuf[16], uint8_t const *ref, 123 const int ref_stride, const int height); 124 125 typedef std::tr1::tuple<int, IntProRowFunc, IntProRowFunc> IntProRowParam; 126 127 class IntProRowTest : public AverageTestBase, 128 public ::testing::WithParamInterface<IntProRowParam> { 129 public: 130 IntProRowTest() 131 : AverageTestBase(16, GET_PARAM(0)), hbuf_asm_(NULL), hbuf_c_(NULL) { 132 asm_func_ = GET_PARAM(1); 133 c_func_ = GET_PARAM(2); 134 } 135 136 protected: 137 virtual void SetUp() { 138 hbuf_asm_ = reinterpret_cast<int16_t *>( 139 vpx_memalign(kDataAlignment, sizeof(*hbuf_asm_) * 16)); 140 hbuf_c_ = reinterpret_cast<int16_t *>( 141 vpx_memalign(kDataAlignment, sizeof(*hbuf_c_) * 16)); 142 } 143 144 virtual void TearDown() { 145 vpx_free(hbuf_c_); 146 hbuf_c_ = NULL; 147 vpx_free(hbuf_asm_); 148 hbuf_asm_ = NULL; 149 } 150 151 void RunComparison() { 152 ASM_REGISTER_STATE_CHECK(c_func_(hbuf_c_, source_data_, 0, height_)); 153 ASM_REGISTER_STATE_CHECK(asm_func_(hbuf_asm_, source_data_, 0, height_)); 154 EXPECT_EQ(0, memcmp(hbuf_c_, hbuf_asm_, sizeof(*hbuf_c_) * 16)) 155 << "Output mismatch"; 156 } 157 158 private: 159 IntProRowFunc asm_func_; 160 IntProRowFunc c_func_; 161 int16_t *hbuf_asm_; 162 int16_t *hbuf_c_; 163 }; 164 165 typedef int16_t (*IntProColFunc)(uint8_t const *ref, const int width); 166 167 typedef std::tr1::tuple<int, IntProColFunc, IntProColFunc> IntProColParam; 168 169 class IntProColTest : public AverageTestBase, 170 public ::testing::WithParamInterface<IntProColParam> { 171 public: 172 IntProColTest() : AverageTestBase(GET_PARAM(0), 1), sum_asm_(0), sum_c_(0) { 173 asm_func_ = GET_PARAM(1); 174 c_func_ = GET_PARAM(2); 175 } 176 177 protected: 178 void RunComparison() { 179 ASM_REGISTER_STATE_CHECK(sum_c_ = c_func_(source_data_, width_)); 180 ASM_REGISTER_STATE_CHECK(sum_asm_ = asm_func_(source_data_, width_)); 181 EXPECT_EQ(sum_c_, sum_asm_) << "Output mismatch"; 182 } 183 184 private: 185 IntProColFunc asm_func_; 186 IntProColFunc c_func_; 187 int16_t sum_asm_; 188 int16_t sum_c_; 189 }; 190 191 typedef int (*SatdFunc)(const tran_low_t *coeffs, int length); 192 typedef std::tr1::tuple<int, SatdFunc> SatdTestParam; 193 194 class SatdTest : public ::testing::Test, 195 public ::testing::WithParamInterface<SatdTestParam> { 196 protected: 197 virtual void SetUp() { 198 satd_size_ = GET_PARAM(0); 199 satd_func_ = GET_PARAM(1); 200 rnd_.Reset(ACMRandom::DeterministicSeed()); 201 src_ = reinterpret_cast<tran_low_t *>( 202 vpx_memalign(16, sizeof(*src_) * satd_size_)); 203 ASSERT_TRUE(src_ != NULL); 204 } 205 206 virtual void TearDown() { 207 libvpx_test::ClearSystemState(); 208 vpx_free(src_); 209 } 210 211 void FillConstant(const tran_low_t val) { 212 for (int i = 0; i < satd_size_; ++i) src_[i] = val; 213 } 214 215 void FillRandom() { 216 for (int i = 0; i < satd_size_; ++i) { 217 const int16_t tmp = rnd_.Rand16(); 218 src_[i] = (tran_low_t)tmp; 219 } 220 } 221 222 void Check(const int expected) { 223 int total; 224 ASM_REGISTER_STATE_CHECK(total = satd_func_(src_, satd_size_)); 225 EXPECT_EQ(expected, total); 226 } 227 228 int satd_size_; 229 230 private: 231 tran_low_t *src_; 232 SatdFunc satd_func_; 233 ACMRandom rnd_; 234 }; 235 236 typedef int64_t (*BlockErrorFunc)(const tran_low_t *coeff, 237 const tran_low_t *dqcoeff, int block_size); 238 typedef std::tr1::tuple<int, BlockErrorFunc> BlockErrorTestFPParam; 239 240 class BlockErrorTestFP 241 : public ::testing::Test, 242 public ::testing::WithParamInterface<BlockErrorTestFPParam> { 243 protected: 244 virtual void SetUp() { 245 txfm_size_ = GET_PARAM(0); 246 block_error_func_ = GET_PARAM(1); 247 rnd_.Reset(ACMRandom::DeterministicSeed()); 248 coeff_ = reinterpret_cast<tran_low_t *>( 249 vpx_memalign(16, sizeof(*coeff_) * txfm_size_)); 250 dqcoeff_ = reinterpret_cast<tran_low_t *>( 251 vpx_memalign(16, sizeof(*dqcoeff_) * txfm_size_)); 252 ASSERT_TRUE(coeff_ != NULL); 253 ASSERT_TRUE(dqcoeff_ != NULL); 254 } 255 256 virtual void TearDown() { 257 libvpx_test::ClearSystemState(); 258 vpx_free(coeff_); 259 vpx_free(dqcoeff_); 260 } 261 262 void FillConstant(const tran_low_t coeff_val, const tran_low_t dqcoeff_val) { 263 for (int i = 0; i < txfm_size_; ++i) coeff_[i] = coeff_val; 264 for (int i = 0; i < txfm_size_; ++i) dqcoeff_[i] = dqcoeff_val; 265 } 266 267 void FillRandom() { 268 // Just two fixed seeds 269 rnd_.Reset(0xb0b9); 270 for (int i = 0; i < txfm_size_; ++i) coeff_[i] = rnd_.Rand16() >> 1; 271 rnd_.Reset(0xb0c8); 272 for (int i = 0; i < txfm_size_; ++i) dqcoeff_[i] = rnd_.Rand16() >> 1; 273 } 274 275 void Check(const int64_t expected) { 276 int64_t total; 277 ASM_REGISTER_STATE_CHECK( 278 total = block_error_func_(coeff_, dqcoeff_, txfm_size_)); 279 EXPECT_EQ(expected, total); 280 } 281 282 int txfm_size_; 283 284 private: 285 tran_low_t *coeff_; 286 tran_low_t *dqcoeff_; 287 BlockErrorFunc block_error_func_; 288 ACMRandom rnd_; 289 }; 290 291 uint8_t *AverageTestBase::source_data_ = NULL; 292 293 TEST_P(AverageTest, MinValue) { 294 FillConstant(0); 295 CheckAverages(); 296 } 297 298 TEST_P(AverageTest, MaxValue) { 299 FillConstant(255); 300 CheckAverages(); 301 } 302 303 TEST_P(AverageTest, Random) { 304 // The reference frame, but not the source frame, may be unaligned for 305 // certain types of searches. 306 for (int i = 0; i < 1000; i++) { 307 FillRandom(); 308 CheckAverages(); 309 } 310 } 311 312 TEST_P(IntProRowTest, MinValue) { 313 FillConstant(0); 314 RunComparison(); 315 } 316 317 TEST_P(IntProRowTest, MaxValue) { 318 FillConstant(255); 319 RunComparison(); 320 } 321 322 TEST_P(IntProRowTest, Random) { 323 FillRandom(); 324 RunComparison(); 325 } 326 327 TEST_P(IntProColTest, MinValue) { 328 FillConstant(0); 329 RunComparison(); 330 } 331 332 TEST_P(IntProColTest, MaxValue) { 333 FillConstant(255); 334 RunComparison(); 335 } 336 337 TEST_P(IntProColTest, Random) { 338 FillRandom(); 339 RunComparison(); 340 } 341 342 TEST_P(SatdTest, MinValue) { 343 const int kMin = -32640; 344 const int expected = -kMin * satd_size_; 345 FillConstant(kMin); 346 Check(expected); 347 } 348 349 TEST_P(SatdTest, MaxValue) { 350 const int kMax = 32640; 351 const int expected = kMax * satd_size_; 352 FillConstant(kMax); 353 Check(expected); 354 } 355 356 TEST_P(SatdTest, Random) { 357 int expected; 358 switch (satd_size_) { 359 case 16: expected = 205298; break; 360 case 64: expected = 1113950; break; 361 case 256: expected = 4268415; break; 362 case 1024: expected = 16954082; break; 363 default: 364 FAIL() << "Invalid satd size (" << satd_size_ 365 << ") valid: 16/64/256/1024"; 366 } 367 FillRandom(); 368 Check(expected); 369 } 370 371 TEST_P(SatdTest, DISABLED_Speed) { 372 const int kCountSpeedTestBlock = 20000; 373 vpx_usec_timer timer; 374 DECLARE_ALIGNED(16, tran_low_t, coeff[1024]); 375 const int blocksize = GET_PARAM(0); 376 377 vpx_usec_timer_start(&timer); 378 for (int i = 0; i < kCountSpeedTestBlock; ++i) { 379 GET_PARAM(1)(coeff, blocksize); 380 } 381 vpx_usec_timer_mark(&timer); 382 const int elapsed_time = static_cast<int>(vpx_usec_timer_elapsed(&timer)); 383 printf("blocksize: %4d time: %4d us\n", blocksize, elapsed_time); 384 } 385 386 TEST_P(BlockErrorTestFP, MinValue) { 387 const int64_t kMin = -32640; 388 const int64_t expected = kMin * kMin * txfm_size_; 389 FillConstant(kMin, 0); 390 Check(expected); 391 } 392 393 TEST_P(BlockErrorTestFP, MaxValue) { 394 const int64_t kMax = 32640; 395 const int64_t expected = kMax * kMax * txfm_size_; 396 FillConstant(kMax, 0); 397 Check(expected); 398 } 399 400 TEST_P(BlockErrorTestFP, Random) { 401 int64_t expected; 402 switch (txfm_size_) { 403 case 16: expected = 2051681432; break; 404 case 64: expected = 11075114379; break; 405 case 256: expected = 44386271116; break; 406 case 1024: expected = 184774996089; break; 407 default: 408 FAIL() << "Invalid satd size (" << txfm_size_ 409 << ") valid: 16/64/256/1024"; 410 } 411 FillRandom(); 412 Check(expected); 413 } 414 415 TEST_P(BlockErrorTestFP, DISABLED_Speed) { 416 const int kCountSpeedTestBlock = 20000; 417 vpx_usec_timer timer; 418 DECLARE_ALIGNED(16, tran_low_t, coeff[1024]); 419 DECLARE_ALIGNED(16, tran_low_t, dqcoeff[1024]); 420 const int blocksize = GET_PARAM(0); 421 422 vpx_usec_timer_start(&timer); 423 for (int i = 0; i < kCountSpeedTestBlock; ++i) { 424 GET_PARAM(1)(coeff, dqcoeff, blocksize); 425 } 426 vpx_usec_timer_mark(&timer); 427 const int elapsed_time = static_cast<int>(vpx_usec_timer_elapsed(&timer)); 428 printf("blocksize: %4d time: %4d us\n", blocksize, elapsed_time); 429 } 430 431 using std::tr1::make_tuple; 432 433 INSTANTIATE_TEST_CASE_P( 434 C, AverageTest, 435 ::testing::Values(make_tuple(16, 16, 1, 8, &vpx_avg_8x8_c), 436 make_tuple(16, 16, 1, 4, &vpx_avg_4x4_c))); 437 438 INSTANTIATE_TEST_CASE_P(C, SatdTest, 439 ::testing::Values(make_tuple(16, &vpx_satd_c), 440 make_tuple(64, &vpx_satd_c), 441 make_tuple(256, &vpx_satd_c), 442 make_tuple(1024, &vpx_satd_c))); 443 444 INSTANTIATE_TEST_CASE_P( 445 C, BlockErrorTestFP, 446 ::testing::Values(make_tuple(16, &vp9_block_error_fp_c), 447 make_tuple(64, &vp9_block_error_fp_c), 448 make_tuple(256, &vp9_block_error_fp_c), 449 make_tuple(1024, &vp9_block_error_fp_c))); 450 451 #if HAVE_SSE2 452 INSTANTIATE_TEST_CASE_P( 453 SSE2, AverageTest, 454 ::testing::Values(make_tuple(16, 16, 0, 8, &vpx_avg_8x8_sse2), 455 make_tuple(16, 16, 5, 8, &vpx_avg_8x8_sse2), 456 make_tuple(32, 32, 15, 8, &vpx_avg_8x8_sse2), 457 make_tuple(16, 16, 0, 4, &vpx_avg_4x4_sse2), 458 make_tuple(16, 16, 5, 4, &vpx_avg_4x4_sse2), 459 make_tuple(32, 32, 15, 4, &vpx_avg_4x4_sse2))); 460 461 INSTANTIATE_TEST_CASE_P( 462 SSE2, IntProRowTest, 463 ::testing::Values(make_tuple(16, &vpx_int_pro_row_sse2, &vpx_int_pro_row_c), 464 make_tuple(32, &vpx_int_pro_row_sse2, &vpx_int_pro_row_c), 465 make_tuple(64, &vpx_int_pro_row_sse2, 466 &vpx_int_pro_row_c))); 467 468 INSTANTIATE_TEST_CASE_P( 469 SSE2, IntProColTest, 470 ::testing::Values(make_tuple(16, &vpx_int_pro_col_sse2, &vpx_int_pro_col_c), 471 make_tuple(32, &vpx_int_pro_col_sse2, &vpx_int_pro_col_c), 472 make_tuple(64, &vpx_int_pro_col_sse2, 473 &vpx_int_pro_col_c))); 474 475 INSTANTIATE_TEST_CASE_P(SSE2, SatdTest, 476 ::testing::Values(make_tuple(16, &vpx_satd_sse2), 477 make_tuple(64, &vpx_satd_sse2), 478 make_tuple(256, &vpx_satd_sse2), 479 make_tuple(1024, &vpx_satd_sse2))); 480 481 INSTANTIATE_TEST_CASE_P( 482 SSE2, BlockErrorTestFP, 483 ::testing::Values(make_tuple(16, &vp9_block_error_fp_sse2), 484 make_tuple(64, &vp9_block_error_fp_sse2), 485 make_tuple(256, &vp9_block_error_fp_sse2), 486 make_tuple(1024, &vp9_block_error_fp_sse2))); 487 #endif // HAVE_SSE2 488 489 #if HAVE_AVX2 490 INSTANTIATE_TEST_CASE_P(AVX2, SatdTest, 491 ::testing::Values(make_tuple(16, &vpx_satd_avx2), 492 make_tuple(64, &vpx_satd_avx2), 493 make_tuple(256, &vpx_satd_avx2), 494 make_tuple(1024, &vpx_satd_avx2))); 495 496 INSTANTIATE_TEST_CASE_P( 497 AVX2, BlockErrorTestFP, 498 ::testing::Values(make_tuple(16, &vp9_block_error_fp_avx2), 499 make_tuple(64, &vp9_block_error_fp_avx2), 500 make_tuple(256, &vp9_block_error_fp_avx2), 501 make_tuple(1024, &vp9_block_error_fp_avx2))); 502 #endif 503 504 #if HAVE_NEON 505 INSTANTIATE_TEST_CASE_P( 506 NEON, AverageTest, 507 ::testing::Values(make_tuple(16, 16, 0, 8, &vpx_avg_8x8_neon), 508 make_tuple(16, 16, 5, 8, &vpx_avg_8x8_neon), 509 make_tuple(32, 32, 15, 8, &vpx_avg_8x8_neon), 510 make_tuple(16, 16, 0, 4, &vpx_avg_4x4_neon), 511 make_tuple(16, 16, 5, 4, &vpx_avg_4x4_neon), 512 make_tuple(32, 32, 15, 4, &vpx_avg_4x4_neon))); 513 514 INSTANTIATE_TEST_CASE_P( 515 NEON, IntProRowTest, 516 ::testing::Values(make_tuple(16, &vpx_int_pro_row_neon, &vpx_int_pro_row_c), 517 make_tuple(32, &vpx_int_pro_row_neon, &vpx_int_pro_row_c), 518 make_tuple(64, &vpx_int_pro_row_neon, 519 &vpx_int_pro_row_c))); 520 521 INSTANTIATE_TEST_CASE_P( 522 NEON, IntProColTest, 523 ::testing::Values(make_tuple(16, &vpx_int_pro_col_neon, &vpx_int_pro_col_c), 524 make_tuple(32, &vpx_int_pro_col_neon, &vpx_int_pro_col_c), 525 make_tuple(64, &vpx_int_pro_col_neon, 526 &vpx_int_pro_col_c))); 527 528 INSTANTIATE_TEST_CASE_P(NEON, SatdTest, 529 ::testing::Values(make_tuple(16, &vpx_satd_neon), 530 make_tuple(64, &vpx_satd_neon), 531 make_tuple(256, &vpx_satd_neon), 532 make_tuple(1024, &vpx_satd_neon))); 533 534 // TODO(jianj): Remove the highbitdepth flag once the SIMD functions are 535 // in place. 536 #if !CONFIG_VP9_HIGHBITDEPTH 537 INSTANTIATE_TEST_CASE_P( 538 NEON, BlockErrorTestFP, 539 ::testing::Values(make_tuple(16, &vp9_block_error_fp_neon), 540 make_tuple(64, &vp9_block_error_fp_neon), 541 make_tuple(256, &vp9_block_error_fp_neon), 542 make_tuple(1024, &vp9_block_error_fp_neon))); 543 #endif // !CONFIG_VP9_HIGHBITDEPTH 544 #endif // HAVE_NEON 545 546 #if HAVE_MSA 547 INSTANTIATE_TEST_CASE_P( 548 MSA, AverageTest, 549 ::testing::Values(make_tuple(16, 16, 0, 8, &vpx_avg_8x8_msa), 550 make_tuple(16, 16, 5, 8, &vpx_avg_8x8_msa), 551 make_tuple(32, 32, 15, 8, &vpx_avg_8x8_msa), 552 make_tuple(16, 16, 0, 4, &vpx_avg_4x4_msa), 553 make_tuple(16, 16, 5, 4, &vpx_avg_4x4_msa), 554 make_tuple(32, 32, 15, 4, &vpx_avg_4x4_msa))); 555 556 INSTANTIATE_TEST_CASE_P( 557 MSA, IntProRowTest, 558 ::testing::Values(make_tuple(16, &vpx_int_pro_row_msa, &vpx_int_pro_row_c), 559 make_tuple(32, &vpx_int_pro_row_msa, &vpx_int_pro_row_c), 560 make_tuple(64, &vpx_int_pro_row_msa, 561 &vpx_int_pro_row_c))); 562 563 INSTANTIATE_TEST_CASE_P( 564 MSA, IntProColTest, 565 ::testing::Values(make_tuple(16, &vpx_int_pro_col_msa, &vpx_int_pro_col_c), 566 make_tuple(32, &vpx_int_pro_col_msa, &vpx_int_pro_col_c), 567 make_tuple(64, &vpx_int_pro_col_msa, 568 &vpx_int_pro_col_c))); 569 570 // TODO(jingning): Remove the highbitdepth flag once the SIMD functions are 571 // in place. 572 #if !CONFIG_VP9_HIGHBITDEPTH 573 INSTANTIATE_TEST_CASE_P(MSA, SatdTest, 574 ::testing::Values(make_tuple(16, &vpx_satd_msa), 575 make_tuple(64, &vpx_satd_msa), 576 make_tuple(256, &vpx_satd_msa), 577 make_tuple(1024, &vpx_satd_msa))); 578 #endif // !CONFIG_VP9_HIGHBITDEPTH 579 #endif // HAVE_MSA 580 581 } // namespace 582