1/* 2 * Copyright (c) 2010 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 <string.h> 12#include "test/acm_random.h" 13#include "test/register_state_check.h" 14#include "test/util.h" 15#include "third_party/googletest/src/include/gtest/gtest.h" 16 17#include "./vpx_config.h" 18#include "./vp9_rtcd.h" 19#include "vp9/common/vp9_filter.h" 20#include "vpx_mem/vpx_mem.h" 21#include "vpx_ports/mem.h" 22 23namespace { 24typedef void (*convolve_fn_t)(const uint8_t *src, ptrdiff_t src_stride, 25 uint8_t *dst, ptrdiff_t dst_stride, 26 const int16_t *filter_x, int filter_x_stride, 27 const int16_t *filter_y, int filter_y_stride, 28 int w, int h); 29 30struct ConvolveFunctions { 31 ConvolveFunctions(convolve_fn_t h8, convolve_fn_t h8_avg, 32 convolve_fn_t v8, convolve_fn_t v8_avg, 33 convolve_fn_t hv8, convolve_fn_t hv8_avg) 34 : h8_(h8), v8_(v8), hv8_(hv8), h8_avg_(h8_avg), v8_avg_(v8_avg), 35 hv8_avg_(hv8_avg) {} 36 37 convolve_fn_t h8_; 38 convolve_fn_t v8_; 39 convolve_fn_t hv8_; 40 convolve_fn_t h8_avg_; 41 convolve_fn_t v8_avg_; 42 convolve_fn_t hv8_avg_; 43}; 44 45typedef std::tr1::tuple<int, int, const ConvolveFunctions*> convolve_param_t; 46 47// Reference 8-tap subpixel filter, slightly modified to fit into this test. 48#define VP9_FILTER_WEIGHT 128 49#define VP9_FILTER_SHIFT 7 50uint8_t clip_pixel(int x) { 51 return x < 0 ? 0 : 52 x > 255 ? 255 : 53 x; 54} 55 56void filter_block2d_8_c(const uint8_t *src_ptr, 57 const unsigned int src_stride, 58 const int16_t *HFilter, 59 const int16_t *VFilter, 60 uint8_t *dst_ptr, 61 unsigned int dst_stride, 62 unsigned int output_width, 63 unsigned int output_height) { 64 // Between passes, we use an intermediate buffer whose height is extended to 65 // have enough horizontally filtered values as input for the vertical pass. 66 // This buffer is allocated to be big enough for the largest block type we 67 // support. 68 const int kInterp_Extend = 4; 69 const unsigned int intermediate_height = 70 (kInterp_Extend - 1) + output_height + kInterp_Extend; 71 72 /* Size of intermediate_buffer is max_intermediate_height * filter_max_width, 73 * where max_intermediate_height = (kInterp_Extend - 1) + filter_max_height 74 * + kInterp_Extend 75 * = 3 + 16 + 4 76 * = 23 77 * and filter_max_width = 16 78 */ 79 uint8_t intermediate_buffer[71 * 64]; 80 const int intermediate_next_stride = 1 - intermediate_height * output_width; 81 82 // Horizontal pass (src -> transposed intermediate). 83 { 84 uint8_t *output_ptr = intermediate_buffer; 85 const int src_next_row_stride = src_stride - output_width; 86 unsigned int i, j; 87 src_ptr -= (kInterp_Extend - 1) * src_stride + (kInterp_Extend - 1); 88 for (i = 0; i < intermediate_height; ++i) { 89 for (j = 0; j < output_width; ++j) { 90 // Apply filter... 91 const int temp = (src_ptr[0] * HFilter[0]) + 92 (src_ptr[1] * HFilter[1]) + 93 (src_ptr[2] * HFilter[2]) + 94 (src_ptr[3] * HFilter[3]) + 95 (src_ptr[4] * HFilter[4]) + 96 (src_ptr[5] * HFilter[5]) + 97 (src_ptr[6] * HFilter[6]) + 98 (src_ptr[7] * HFilter[7]) + 99 (VP9_FILTER_WEIGHT >> 1); // Rounding 100 101 // Normalize back to 0-255... 102 *output_ptr = clip_pixel(temp >> VP9_FILTER_SHIFT); 103 ++src_ptr; 104 output_ptr += intermediate_height; 105 } 106 src_ptr += src_next_row_stride; 107 output_ptr += intermediate_next_stride; 108 } 109 } 110 111 // Vertical pass (transposed intermediate -> dst). 112 { 113 uint8_t *src_ptr = intermediate_buffer; 114 const int dst_next_row_stride = dst_stride - output_width; 115 unsigned int i, j; 116 for (i = 0; i < output_height; ++i) { 117 for (j = 0; j < output_width; ++j) { 118 // Apply filter... 119 const int temp = (src_ptr[0] * VFilter[0]) + 120 (src_ptr[1] * VFilter[1]) + 121 (src_ptr[2] * VFilter[2]) + 122 (src_ptr[3] * VFilter[3]) + 123 (src_ptr[4] * VFilter[4]) + 124 (src_ptr[5] * VFilter[5]) + 125 (src_ptr[6] * VFilter[6]) + 126 (src_ptr[7] * VFilter[7]) + 127 (VP9_FILTER_WEIGHT >> 1); // Rounding 128 129 // Normalize back to 0-255... 130 *dst_ptr++ = clip_pixel(temp >> VP9_FILTER_SHIFT); 131 src_ptr += intermediate_height; 132 } 133 src_ptr += intermediate_next_stride; 134 dst_ptr += dst_next_row_stride; 135 } 136 } 137} 138 139void block2d_average_c(uint8_t *src, 140 unsigned int src_stride, 141 uint8_t *output_ptr, 142 unsigned int output_stride, 143 unsigned int output_width, 144 unsigned int output_height) { 145 unsigned int i, j; 146 for (i = 0; i < output_height; ++i) { 147 for (j = 0; j < output_width; ++j) { 148 output_ptr[j] = (output_ptr[j] + src[i * src_stride + j] + 1) >> 1; 149 } 150 output_ptr += output_stride; 151 } 152} 153 154void filter_average_block2d_8_c(const uint8_t *src_ptr, 155 const unsigned int src_stride, 156 const int16_t *HFilter, 157 const int16_t *VFilter, 158 uint8_t *dst_ptr, 159 unsigned int dst_stride, 160 unsigned int output_width, 161 unsigned int output_height) { 162 uint8_t tmp[64 * 64]; 163 164 assert(output_width <= 64); 165 assert(output_height <= 64); 166 filter_block2d_8_c(src_ptr, src_stride, HFilter, VFilter, tmp, 64, 167 output_width, output_height); 168 block2d_average_c(tmp, 64, dst_ptr, dst_stride, 169 output_width, output_height); 170} 171 172class ConvolveTest : public ::testing::TestWithParam<convolve_param_t> { 173 public: 174 static void SetUpTestCase() { 175 // Force input_ to be unaligned, output to be 16 byte aligned. 176 input_ = reinterpret_cast<uint8_t*>( 177 vpx_memalign(kDataAlignment, kInputBufferSize + 1)) + 1; 178 output_ = reinterpret_cast<uint8_t*>( 179 vpx_memalign(kDataAlignment, kOutputBufferSize)); 180 } 181 182 static void TearDownTestCase() { 183 vpx_free(input_ - 1); 184 input_ = NULL; 185 vpx_free(output_); 186 output_ = NULL; 187 } 188 189 protected: 190 static const int kDataAlignment = 16; 191 static const int kOuterBlockSize = 256; 192 static const int kInputStride = kOuterBlockSize; 193 static const int kOutputStride = kOuterBlockSize; 194 static const int kMaxDimension = 64; 195 static const int kInputBufferSize = kOuterBlockSize * kOuterBlockSize; 196 static const int kOutputBufferSize = kOuterBlockSize * kOuterBlockSize; 197 198 int Width() const { return GET_PARAM(0); } 199 int Height() const { return GET_PARAM(1); } 200 int BorderLeft() const { 201 const int center = (kOuterBlockSize - Width()) / 2; 202 return (center + (kDataAlignment - 1)) & ~(kDataAlignment - 1); 203 } 204 int BorderTop() const { return (kOuterBlockSize - Height()) / 2; } 205 206 bool IsIndexInBorder(int i) { 207 return (i < BorderTop() * kOuterBlockSize || 208 i >= (BorderTop() + Height()) * kOuterBlockSize || 209 i % kOuterBlockSize < BorderLeft() || 210 i % kOuterBlockSize >= (BorderLeft() + Width())); 211 } 212 213 virtual void SetUp() { 214 UUT_ = GET_PARAM(2); 215 /* Set up guard blocks for an inner block centered in the outer block */ 216 for (int i = 0; i < kOutputBufferSize; ++i) { 217 if (IsIndexInBorder(i)) 218 output_[i] = 255; 219 else 220 output_[i] = 0; 221 } 222 223 ::libvpx_test::ACMRandom prng; 224 for (int i = 0; i < kInputBufferSize; ++i) 225 input_[i] = prng.Rand8Extremes(); 226 } 227 228 void SetConstantInput(int value) { 229 memset(input_, value, kInputBufferSize); 230 } 231 232 void CheckGuardBlocks() { 233 for (int i = 0; i < kOutputBufferSize; ++i) { 234 if (IsIndexInBorder(i)) 235 EXPECT_EQ(255, output_[i]); 236 } 237 } 238 239 uint8_t* input() const { 240 return input_ + BorderTop() * kOuterBlockSize + BorderLeft(); 241 } 242 243 uint8_t* output() const { 244 return output_ + BorderTop() * kOuterBlockSize + BorderLeft(); 245 } 246 247 const ConvolveFunctions* UUT_; 248 static uint8_t* input_; 249 static uint8_t* output_; 250}; 251uint8_t* ConvolveTest::input_ = NULL; 252uint8_t* ConvolveTest::output_ = NULL; 253 254TEST_P(ConvolveTest, GuardBlocks) { 255 CheckGuardBlocks(); 256} 257 258TEST_P(ConvolveTest, CopyHoriz) { 259 uint8_t* const in = input(); 260 uint8_t* const out = output(); 261 DECLARE_ALIGNED(256, const int16_t, filter8[8]) = {0, 0, 0, 128, 0, 0, 0, 0}; 262 263 REGISTER_STATE_CHECK( 264 UUT_->h8_(in, kInputStride, out, kOutputStride, filter8, 16, filter8, 16, 265 Width(), Height())); 266 267 CheckGuardBlocks(); 268 269 for (int y = 0; y < Height(); ++y) 270 for (int x = 0; x < Width(); ++x) 271 ASSERT_EQ(out[y * kOutputStride + x], in[y * kInputStride + x]) 272 << "(" << x << "," << y << ")"; 273} 274 275TEST_P(ConvolveTest, CopyVert) { 276 uint8_t* const in = input(); 277 uint8_t* const out = output(); 278 DECLARE_ALIGNED(256, const int16_t, filter8[8]) = {0, 0, 0, 128, 0, 0, 0, 0}; 279 280 REGISTER_STATE_CHECK( 281 UUT_->v8_(in, kInputStride, out, kOutputStride, filter8, 16, filter8, 16, 282 Width(), Height())); 283 284 CheckGuardBlocks(); 285 286 for (int y = 0; y < Height(); ++y) 287 for (int x = 0; x < Width(); ++x) 288 ASSERT_EQ(out[y * kOutputStride + x], in[y * kInputStride + x]) 289 << "(" << x << "," << y << ")"; 290} 291 292TEST_P(ConvolveTest, Copy2D) { 293 uint8_t* const in = input(); 294 uint8_t* const out = output(); 295 DECLARE_ALIGNED(256, const int16_t, filter8[8]) = {0, 0, 0, 128, 0, 0, 0, 0}; 296 297 REGISTER_STATE_CHECK( 298 UUT_->hv8_(in, kInputStride, out, kOutputStride, filter8, 16, filter8, 16, 299 Width(), Height())); 300 301 CheckGuardBlocks(); 302 303 for (int y = 0; y < Height(); ++y) 304 for (int x = 0; x < Width(); ++x) 305 ASSERT_EQ(out[y * kOutputStride + x], in[y * kInputStride + x]) 306 << "(" << x << "," << y << ")"; 307} 308 309const int16_t (*kTestFilterList[])[8] = { 310 vp9_bilinear_filters, 311 vp9_sub_pel_filters_8, 312 vp9_sub_pel_filters_8s, 313 vp9_sub_pel_filters_8lp 314}; 315const int kNumFilterBanks = sizeof(kTestFilterList) / 316 sizeof(kTestFilterList[0]); 317const int kNumFilters = 16; 318 319TEST(ConvolveTest, FiltersWontSaturateWhenAddedPairwise) { 320 for (int filter_bank = 0; filter_bank < kNumFilterBanks; ++filter_bank) { 321 const int16_t (*filters)[8] = kTestFilterList[filter_bank]; 322 for (int i = 0; i < kNumFilters; i++) { 323 const int p0 = filters[i][0] + filters[i][1]; 324 const int p1 = filters[i][2] + filters[i][3]; 325 const int p2 = filters[i][4] + filters[i][5]; 326 const int p3 = filters[i][6] + filters[i][7]; 327 EXPECT_LE(p0, 128); 328 EXPECT_LE(p1, 128); 329 EXPECT_LE(p2, 128); 330 EXPECT_LE(p3, 128); 331 EXPECT_LE(p0 + p3, 128); 332 EXPECT_LE(p0 + p3 + p1, 128); 333 EXPECT_LE(p0 + p3 + p1 + p2, 128); 334 EXPECT_EQ(p0 + p1 + p2 + p3, 128); 335 } 336 } 337} 338 339const int16_t kInvalidFilter[8] = { 0 }; 340 341TEST_P(ConvolveTest, MatchesReferenceSubpixelFilter) { 342 uint8_t* const in = input(); 343 uint8_t* const out = output(); 344 uint8_t ref[kOutputStride * kMaxDimension]; 345 346 347 for (int filter_bank = 0; filter_bank < kNumFilterBanks; ++filter_bank) { 348 const int16_t (*filters)[8] = kTestFilterList[filter_bank]; 349 350 for (int filter_x = 0; filter_x < kNumFilters; ++filter_x) { 351 for (int filter_y = 0; filter_y < kNumFilters; ++filter_y) { 352 filter_block2d_8_c(in, kInputStride, 353 filters[filter_x], filters[filter_y], 354 ref, kOutputStride, 355 Width(), Height()); 356 357 if (filters == vp9_sub_pel_filters_8lp || (filter_x && filter_y)) 358 REGISTER_STATE_CHECK( 359 UUT_->hv8_(in, kInputStride, out, kOutputStride, 360 filters[filter_x], 16, filters[filter_y], 16, 361 Width(), Height())); 362 else if (filter_y) 363 REGISTER_STATE_CHECK( 364 UUT_->v8_(in, kInputStride, out, kOutputStride, 365 kInvalidFilter, 16, filters[filter_y], 16, 366 Width(), Height())); 367 else 368 REGISTER_STATE_CHECK( 369 UUT_->h8_(in, kInputStride, out, kOutputStride, 370 filters[filter_x], 16, kInvalidFilter, 16, 371 Width(), Height())); 372 373 CheckGuardBlocks(); 374 375 for (int y = 0; y < Height(); ++y) 376 for (int x = 0; x < Width(); ++x) 377 ASSERT_EQ(ref[y * kOutputStride + x], out[y * kOutputStride + x]) 378 << "mismatch at (" << x << "," << y << "), " 379 << "filters (" << filter_bank << "," 380 << filter_x << "," << filter_y << ")"; 381 } 382 } 383 } 384} 385 386TEST_P(ConvolveTest, MatchesReferenceAveragingSubpixelFilter) { 387 uint8_t* const in = input(); 388 uint8_t* const out = output(); 389 uint8_t ref[kOutputStride * kMaxDimension]; 390 391 // Populate ref and out with some random data 392 ::libvpx_test::ACMRandom prng; 393 for (int y = 0; y < Height(); ++y) { 394 for (int x = 0; x < Width(); ++x) { 395 const uint8_t r = prng.Rand8Extremes(); 396 397 out[y * kOutputStride + x] = r; 398 ref[y * kOutputStride + x] = r; 399 } 400 } 401 402 const int kNumFilterBanks = sizeof(kTestFilterList) / 403 sizeof(kTestFilterList[0]); 404 405 for (int filter_bank = 0; filter_bank < kNumFilterBanks; ++filter_bank) { 406 const int16_t (*filters)[8] = kTestFilterList[filter_bank]; 407 const int kNumFilters = 16; 408 409 for (int filter_x = 0; filter_x < kNumFilters; ++filter_x) { 410 for (int filter_y = 0; filter_y < kNumFilters; ++filter_y) { 411 filter_average_block2d_8_c(in, kInputStride, 412 filters[filter_x], filters[filter_y], 413 ref, kOutputStride, 414 Width(), Height()); 415 416 if (filters == vp9_sub_pel_filters_8lp || (filter_x && filter_y)) 417 REGISTER_STATE_CHECK( 418 UUT_->hv8_avg_(in, kInputStride, out, kOutputStride, 419 filters[filter_x], 16, filters[filter_y], 16, 420 Width(), Height())); 421 else if (filter_y) 422 REGISTER_STATE_CHECK( 423 UUT_->v8_avg_(in, kInputStride, out, kOutputStride, 424 filters[filter_x], 16, filters[filter_y], 16, 425 Width(), Height())); 426 else 427 REGISTER_STATE_CHECK( 428 UUT_->h8_avg_(in, kInputStride, out, kOutputStride, 429 filters[filter_x], 16, filters[filter_y], 16, 430 Width(), Height())); 431 432 CheckGuardBlocks(); 433 434 for (int y = 0; y < Height(); ++y) 435 for (int x = 0; x < Width(); ++x) 436 ASSERT_EQ(ref[y * kOutputStride + x], out[y * kOutputStride + x]) 437 << "mismatch at (" << x << "," << y << "), " 438 << "filters (" << filter_bank << "," 439 << filter_x << "," << filter_y << ")"; 440 } 441 } 442 } 443} 444 445DECLARE_ALIGNED(256, const int16_t, kChangeFilters[16][8]) = { 446 { 0, 0, 0, 0, 0, 0, 0, 128}, 447 { 0, 0, 0, 0, 0, 0, 128}, 448 { 0, 0, 0, 0, 0, 128}, 449 { 0, 0, 0, 0, 128}, 450 { 0, 0, 0, 128}, 451 { 0, 0, 128}, 452 { 0, 128}, 453 { 128}, 454 { 0, 0, 0, 0, 0, 0, 0, 128}, 455 { 0, 0, 0, 0, 0, 0, 128}, 456 { 0, 0, 0, 0, 0, 128}, 457 { 0, 0, 0, 0, 128}, 458 { 0, 0, 0, 128}, 459 { 0, 0, 128}, 460 { 0, 128}, 461 { 128} 462}; 463 464/* This test exercises the horizontal and vertical filter functions. */ 465TEST_P(ConvolveTest, ChangeFilterWorks) { 466 uint8_t* const in = input(); 467 uint8_t* const out = output(); 468 469 /* Assume that the first input sample is at the 8/16th position. */ 470 const int kInitialSubPelOffset = 8; 471 472 /* Filters are 8-tap, so the first filter tap will be applied to the pixel 473 * at position -3 with respect to the current filtering position. Since 474 * kInitialSubPelOffset is set to 8, we first select sub-pixel filter 8, 475 * which is non-zero only in the last tap. So, applying the filter at the 476 * current input position will result in an output equal to the pixel at 477 * offset +4 (-3 + 7) with respect to the current filtering position. 478 */ 479 const int kPixelSelected = 4; 480 481 /* Assume that each output pixel requires us to step on by 17/16th pixels in 482 * the input. 483 */ 484 const int kInputPixelStep = 17; 485 486 /* The filters are setup in such a way that the expected output produces 487 * sets of 8 identical output samples. As the filter position moves to the 488 * next 1/16th pixel position the only active (=128) filter tap moves one 489 * position to the left, resulting in the same input pixel being replicated 490 * in to the output for 8 consecutive samples. After each set of 8 positions 491 * the filters select a different input pixel. kFilterPeriodAdjust below 492 * computes which input pixel is written to the output for a specified 493 * x or y position. 494 */ 495 496 /* Test the horizontal filter. */ 497 REGISTER_STATE_CHECK(UUT_->h8_(in, kInputStride, out, kOutputStride, 498 kChangeFilters[kInitialSubPelOffset], 499 kInputPixelStep, NULL, 0, Width(), Height())); 500 501 for (int x = 0; x < Width(); ++x) { 502 const int kFilterPeriodAdjust = (x >> 3) << 3; 503 const int ref_x = 504 kPixelSelected + ((kInitialSubPelOffset 505 + kFilterPeriodAdjust * kInputPixelStep) 506 >> SUBPEL_BITS); 507 ASSERT_EQ(in[ref_x], out[x]) << "x == " << x << "width = " << Width(); 508 } 509 510 /* Test the vertical filter. */ 511 REGISTER_STATE_CHECK(UUT_->v8_(in, kInputStride, out, kOutputStride, 512 NULL, 0, kChangeFilters[kInitialSubPelOffset], 513 kInputPixelStep, Width(), Height())); 514 515 for (int y = 0; y < Height(); ++y) { 516 const int kFilterPeriodAdjust = (y >> 3) << 3; 517 const int ref_y = 518 kPixelSelected + ((kInitialSubPelOffset 519 + kFilterPeriodAdjust * kInputPixelStep) 520 >> SUBPEL_BITS); 521 ASSERT_EQ(in[ref_y * kInputStride], out[y * kInputStride]) << "y == " << y; 522 } 523 524 /* Test the horizontal and vertical filters in combination. */ 525 REGISTER_STATE_CHECK(UUT_->hv8_(in, kInputStride, out, kOutputStride, 526 kChangeFilters[kInitialSubPelOffset], 527 kInputPixelStep, 528 kChangeFilters[kInitialSubPelOffset], 529 kInputPixelStep, 530 Width(), Height())); 531 532 for (int y = 0; y < Height(); ++y) { 533 const int kFilterPeriodAdjustY = (y >> 3) << 3; 534 const int ref_y = 535 kPixelSelected + ((kInitialSubPelOffset 536 + kFilterPeriodAdjustY * kInputPixelStep) 537 >> SUBPEL_BITS); 538 for (int x = 0; x < Width(); ++x) { 539 const int kFilterPeriodAdjustX = (x >> 3) << 3; 540 const int ref_x = 541 kPixelSelected + ((kInitialSubPelOffset 542 + kFilterPeriodAdjustX * kInputPixelStep) 543 >> SUBPEL_BITS); 544 545 ASSERT_EQ(in[ref_y * kInputStride + ref_x], out[y * kOutputStride + x]) 546 << "x == " << x << ", y == " << y; 547 } 548 } 549} 550 551/* This test exercises that enough rows and columns are filtered with every 552 possible initial fractional positions and scaling steps. */ 553TEST_P(ConvolveTest, CheckScalingFiltering) { 554 uint8_t* const in = input(); 555 uint8_t* const out = output(); 556 557 SetConstantInput(127); 558 559 for (int frac = 0; frac < 16; ++frac) { 560 for (int step = 1; step <= 32; ++step) { 561 /* Test the horizontal and vertical filters in combination. */ 562 REGISTER_STATE_CHECK(UUT_->hv8_(in, kInputStride, out, kOutputStride, 563 vp9_sub_pel_filters_8[frac], step, 564 vp9_sub_pel_filters_8[frac], step, 565 Width(), Height())); 566 567 CheckGuardBlocks(); 568 569 for (int y = 0; y < Height(); ++y) { 570 for (int x = 0; x < Width(); ++x) { 571 ASSERT_EQ(in[y * kInputStride + x], out[y * kOutputStride + x]) 572 << "x == " << x << ", y == " << y 573 << ", frac == " << frac << ", step == " << step; 574 } 575 } 576 } 577 } 578} 579 580using std::tr1::make_tuple; 581 582const ConvolveFunctions convolve8_c( 583 vp9_convolve8_horiz_c, vp9_convolve8_avg_horiz_c, 584 vp9_convolve8_vert_c, vp9_convolve8_avg_vert_c, 585 vp9_convolve8_c, vp9_convolve8_avg_c); 586 587INSTANTIATE_TEST_CASE_P(C, ConvolveTest, ::testing::Values( 588 make_tuple(4, 4, &convolve8_c), 589 make_tuple(8, 4, &convolve8_c), 590 make_tuple(4, 8, &convolve8_c), 591 make_tuple(8, 8, &convolve8_c), 592 make_tuple(16, 8, &convolve8_c), 593 make_tuple(8, 16, &convolve8_c), 594 make_tuple(16, 16, &convolve8_c), 595 make_tuple(32, 16, &convolve8_c), 596 make_tuple(16, 32, &convolve8_c), 597 make_tuple(32, 32, &convolve8_c), 598 make_tuple(64, 32, &convolve8_c), 599 make_tuple(32, 64, &convolve8_c), 600 make_tuple(64, 64, &convolve8_c))); 601 602#if HAVE_SSE2 603const ConvolveFunctions convolve8_sse2( 604 vp9_convolve8_horiz_sse2, vp9_convolve8_avg_horiz_sse2, 605 vp9_convolve8_vert_sse2, vp9_convolve8_avg_vert_sse2, 606 vp9_convolve8_sse2, vp9_convolve8_avg_sse2); 607 608INSTANTIATE_TEST_CASE_P(SSE2, ConvolveTest, ::testing::Values( 609 make_tuple(4, 4, &convolve8_sse2), 610 make_tuple(8, 4, &convolve8_sse2), 611 make_tuple(4, 8, &convolve8_sse2), 612 make_tuple(8, 8, &convolve8_sse2), 613 make_tuple(16, 8, &convolve8_sse2), 614 make_tuple(8, 16, &convolve8_sse2), 615 make_tuple(16, 16, &convolve8_sse2), 616 make_tuple(32, 16, &convolve8_sse2), 617 make_tuple(16, 32, &convolve8_sse2), 618 make_tuple(32, 32, &convolve8_sse2), 619 make_tuple(64, 32, &convolve8_sse2), 620 make_tuple(32, 64, &convolve8_sse2), 621 make_tuple(64, 64, &convolve8_sse2))); 622#endif 623 624#if HAVE_SSSE3 625const ConvolveFunctions convolve8_ssse3( 626 vp9_convolve8_horiz_ssse3, vp9_convolve8_avg_horiz_ssse3, 627 vp9_convolve8_vert_ssse3, vp9_convolve8_avg_vert_ssse3, 628 vp9_convolve8_ssse3, vp9_convolve8_avg_ssse3); 629 630INSTANTIATE_TEST_CASE_P(SSSE3, ConvolveTest, ::testing::Values( 631 make_tuple(4, 4, &convolve8_ssse3), 632 make_tuple(8, 4, &convolve8_ssse3), 633 make_tuple(4, 8, &convolve8_ssse3), 634 make_tuple(8, 8, &convolve8_ssse3), 635 make_tuple(16, 8, &convolve8_ssse3), 636 make_tuple(8, 16, &convolve8_ssse3), 637 make_tuple(16, 16, &convolve8_ssse3), 638 make_tuple(32, 16, &convolve8_ssse3), 639 make_tuple(16, 32, &convolve8_ssse3), 640 make_tuple(32, 32, &convolve8_ssse3), 641 make_tuple(64, 32, &convolve8_ssse3), 642 make_tuple(32, 64, &convolve8_ssse3), 643 make_tuple(64, 64, &convolve8_ssse3))); 644#endif 645 646#if HAVE_NEON 647const ConvolveFunctions convolve8_neon( 648 vp9_convolve8_horiz_neon, vp9_convolve8_avg_horiz_neon, 649 vp9_convolve8_vert_neon, vp9_convolve8_avg_vert_neon, 650 vp9_convolve8_neon, vp9_convolve8_avg_neon); 651 652INSTANTIATE_TEST_CASE_P(NEON, ConvolveTest, ::testing::Values( 653 make_tuple(4, 4, &convolve8_neon), 654 make_tuple(8, 4, &convolve8_neon), 655 make_tuple(4, 8, &convolve8_neon), 656 make_tuple(8, 8, &convolve8_neon), 657 make_tuple(16, 8, &convolve8_neon), 658 make_tuple(8, 16, &convolve8_neon), 659 make_tuple(16, 16, &convolve8_neon), 660 make_tuple(32, 16, &convolve8_neon), 661 make_tuple(16, 32, &convolve8_neon), 662 make_tuple(32, 32, &convolve8_neon), 663 make_tuple(64, 32, &convolve8_neon), 664 make_tuple(32, 64, &convolve8_neon), 665 make_tuple(64, 64, &convolve8_neon))); 666#endif 667 668#if HAVE_DSPR2 669const ConvolveFunctions convolve8_dspr2( 670 vp9_convolve8_horiz_dspr2, vp9_convolve8_avg_horiz_dspr2, 671 vp9_convolve8_vert_dspr2, vp9_convolve8_avg_vert_dspr2, 672 vp9_convolve8_dspr2, vp9_convolve8_avg_dspr2); 673 674INSTANTIATE_TEST_CASE_P(DSPR2, ConvolveTest, ::testing::Values( 675 make_tuple(4, 4, &convolve8_dspr2), 676 make_tuple(8, 4, &convolve8_dspr2), 677 make_tuple(4, 8, &convolve8_dspr2), 678 make_tuple(8, 8, &convolve8_dspr2), 679 make_tuple(16, 8, &convolve8_dspr2), 680 make_tuple(8, 16, &convolve8_dspr2), 681 make_tuple(16, 16, &convolve8_dspr2), 682 make_tuple(32, 16, &convolve8_dspr2), 683 make_tuple(16, 32, &convolve8_dspr2), 684 make_tuple(32, 32, &convolve8_dspr2), 685 make_tuple(64, 32, &convolve8_dspr2), 686 make_tuple(32, 64, &convolve8_dspr2), 687 make_tuple(64, 64, &convolve8_dspr2))); 688#endif 689} // namespace 690