1 /* 2 * Copyright (c) 2013 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 <stdlib.h> 12 #include <string.h> 13 14 #include "third_party/googletest/src/include/gtest/gtest.h" 15 16 #include "./vp8_rtcd.h" 17 #include "./vpx_config.h" 18 #include "test/acm_random.h" 19 #include "test/clear_system_state.h" 20 #include "test/register_state_check.h" 21 #include "test/util.h" 22 #include "vpx/vpx_integer.h" 23 #include "vpx_mem/vpx_mem.h" 24 25 namespace { 26 27 using libvpx_test::ACMRandom; 28 using std::tr1::make_tuple; 29 30 typedef void (*PredictFunc)(uint8_t *src_ptr, int src_pixels_per_line, 31 int xoffset, int yoffset, uint8_t *dst_ptr, 32 int dst_pitch); 33 34 typedef std::tr1::tuple<int, int, PredictFunc> PredictParam; 35 36 class PredictTestBase : public ::testing::TestWithParam<PredictParam> { 37 public: 38 PredictTestBase() 39 : width_(GET_PARAM(0)), height_(GET_PARAM(1)), predict_(GET_PARAM(2)), 40 src_(NULL), padded_dst_(NULL), dst_(NULL), dst_c_(NULL) {} 41 42 virtual void SetUp() { 43 src_ = new uint8_t[kSrcSize]; 44 ASSERT_TRUE(src_ != NULL); 45 46 // padded_dst_ provides a buffer of kBorderSize around the destination 47 // memory to facilitate detecting out of bounds writes. 48 dst_stride_ = kBorderSize + width_ + kBorderSize; 49 padded_dst_size_ = dst_stride_ * (kBorderSize + height_ + kBorderSize); 50 padded_dst_ = 51 reinterpret_cast<uint8_t *>(vpx_memalign(16, padded_dst_size_)); 52 ASSERT_TRUE(padded_dst_ != NULL); 53 dst_ = padded_dst_ + (kBorderSize * dst_stride_) + kBorderSize; 54 55 dst_c_ = new uint8_t[16 * 16]; 56 ASSERT_TRUE(dst_c_ != NULL); 57 58 memset(src_, 0, kSrcSize); 59 memset(padded_dst_, 128, padded_dst_size_); 60 memset(dst_c_, 0, 16 * 16); 61 } 62 63 virtual void TearDown() { 64 delete[] src_; 65 src_ = NULL; 66 vpx_free(padded_dst_); 67 padded_dst_ = NULL; 68 dst_ = NULL; 69 delete[] dst_c_; 70 dst_c_ = NULL; 71 libvpx_test::ClearSystemState(); 72 } 73 74 protected: 75 // Make reference arrays big enough for 16x16 functions. Six-tap filters need 76 // 5 extra pixels outside of the macroblock. 77 static const int kSrcStride = 21; 78 static const int kSrcSize = kSrcStride * kSrcStride; 79 static const int kBorderSize = 16; 80 81 int width_; 82 int height_; 83 PredictFunc predict_; 84 uint8_t *src_; 85 uint8_t *padded_dst_; 86 uint8_t *dst_; 87 int padded_dst_size_; 88 uint8_t *dst_c_; 89 int dst_stride_; 90 91 bool CompareBuffers(const uint8_t *a, int a_stride, const uint8_t *b, 92 int b_stride) const { 93 for (int height = 0; height < height_; ++height) { 94 EXPECT_EQ(0, memcmp(a + height * a_stride, b + height * b_stride, 95 sizeof(*a) * width_)) 96 << "Row " << height << " does not match."; 97 } 98 99 return !HasFailure(); 100 } 101 102 // Given a block of memory 'a' with size 'a_size', determine if all regions 103 // excepting block 'b' described by 'b_stride', 'b_height', and 'b_width' 104 // match pixel value 'c'. 105 bool CheckBorder(const uint8_t *a, int a_size, const uint8_t *b, int b_width, 106 int b_height, int b_stride, uint8_t c) const { 107 const uint8_t *a_end = a + a_size; 108 const int b_size = (b_stride * b_height) + b_width; 109 const uint8_t *b_end = b + b_size; 110 const int left_border = (b_stride - b_width) / 2; 111 const int right_border = left_border + ((b_stride - b_width) % 2); 112 113 EXPECT_GE(b - left_border, a) << "'b' does not start within 'a'"; 114 EXPECT_LE(b_end + right_border, a_end) << "'b' does not end within 'a'"; 115 116 // Top border. 117 for (int pixel = 0; pixel < b - a - left_border; ++pixel) { 118 EXPECT_EQ(c, a[pixel]) << "Mismatch at " << pixel << " in top border."; 119 } 120 121 // Left border. 122 for (int height = 0; height < b_height; ++height) { 123 for (int width = left_border; width > 0; --width) { 124 EXPECT_EQ(c, b[height * b_stride - width]) 125 << "Mismatch at row " << height << " column " << left_border - width 126 << " in left border."; 127 } 128 } 129 130 // Right border. 131 for (int height = 0; height < b_height; ++height) { 132 for (int width = b_width; width < b_width + right_border; ++width) { 133 EXPECT_EQ(c, b[height * b_stride + width]) 134 << "Mismatch at row " << height << " column " << width - b_width 135 << " in right border."; 136 } 137 } 138 139 // Bottom border. 140 for (int pixel = static_cast<int>(b - a + b_size); pixel < a_size; 141 ++pixel) { 142 EXPECT_EQ(c, a[pixel]) << "Mismatch at " << pixel << " in bottom border."; 143 } 144 145 return !HasFailure(); 146 } 147 148 void TestWithRandomData(PredictFunc reference) { 149 ACMRandom rnd(ACMRandom::DeterministicSeed()); 150 151 // Run tests for almost all possible offsets. 152 for (int xoffset = 0; xoffset < 8; ++xoffset) { 153 for (int yoffset = 0; yoffset < 8; ++yoffset) { 154 if (xoffset == 0 && yoffset == 0) { 155 // This represents a copy which is not required to be handled by this 156 // module. 157 continue; 158 } 159 160 for (int i = 0; i < kSrcSize; ++i) { 161 src_[i] = rnd.Rand8(); 162 } 163 reference(&src_[kSrcStride * 2 + 2], kSrcStride, xoffset, yoffset, 164 dst_c_, 16); 165 166 ASM_REGISTER_STATE_CHECK(predict_(&src_[kSrcStride * 2 + 2], kSrcStride, 167 xoffset, yoffset, dst_, dst_stride_)); 168 169 ASSERT_TRUE(CompareBuffers(dst_c_, 16, dst_, dst_stride_)); 170 ASSERT_TRUE(CheckBorder(padded_dst_, padded_dst_size_, dst_, width_, 171 height_, dst_stride_, 128)); 172 } 173 } 174 } 175 176 void TestWithUnalignedDst(PredictFunc reference) { 177 ACMRandom rnd(ACMRandom::DeterministicSeed()); 178 179 // Only the 4x4 need to be able to handle unaligned writes. 180 if (width_ == 4 && height_ == 4) { 181 for (int xoffset = 0; xoffset < 8; ++xoffset) { 182 for (int yoffset = 0; yoffset < 8; ++yoffset) { 183 if (xoffset == 0 && yoffset == 0) { 184 continue; 185 } 186 for (int i = 0; i < kSrcSize; ++i) { 187 src_[i] = rnd.Rand8(); 188 } 189 reference(&src_[kSrcStride * 2 + 2], kSrcStride, xoffset, yoffset, 190 dst_c_, 16); 191 192 for (int i = 1; i < 4; ++i) { 193 memset(padded_dst_, 128, padded_dst_size_); 194 195 ASM_REGISTER_STATE_CHECK(predict_(&src_[kSrcStride * 2 + 2], 196 kSrcStride, xoffset, yoffset, 197 dst_ + i, dst_stride_ + i)); 198 199 ASSERT_TRUE(CompareBuffers(dst_c_, 16, dst_ + i, dst_stride_ + i)); 200 ASSERT_TRUE(CheckBorder(padded_dst_, padded_dst_size_, dst_ + i, 201 width_, height_, dst_stride_ + i, 128)); 202 } 203 } 204 } 205 } 206 } 207 }; 208 209 class SixtapPredictTest : public PredictTestBase {}; 210 211 TEST_P(SixtapPredictTest, TestWithRandomData) { 212 TestWithRandomData(vp8_sixtap_predict16x16_c); 213 } 214 TEST_P(SixtapPredictTest, TestWithUnalignedDst) { 215 TestWithUnalignedDst(vp8_sixtap_predict16x16_c); 216 } 217 218 TEST_P(SixtapPredictTest, TestWithPresetData) { 219 // Test input 220 static const uint8_t kTestData[kSrcSize] = { 221 184, 4, 191, 82, 92, 41, 0, 1, 226, 236, 172, 20, 182, 42, 226, 222 177, 79, 94, 77, 179, 203, 206, 198, 22, 192, 19, 75, 17, 192, 44, 223 233, 120, 48, 168, 203, 141, 210, 203, 143, 180, 184, 59, 201, 110, 102, 224 171, 32, 182, 10, 109, 105, 213, 60, 47, 236, 253, 67, 55, 14, 3, 225 99, 247, 124, 148, 159, 71, 34, 114, 19, 177, 38, 203, 237, 239, 58, 226 83, 155, 91, 10, 166, 201, 115, 124, 5, 163, 104, 2, 231, 160, 16, 227 234, 4, 8, 103, 153, 167, 174, 187, 26, 193, 109, 64, 141, 90, 48, 228 200, 174, 204, 36, 184, 114, 237, 43, 238, 242, 207, 86, 245, 182, 247, 229 6, 161, 251, 14, 8, 148, 182, 182, 79, 208, 120, 188, 17, 6, 23, 230 65, 206, 197, 13, 242, 126, 128, 224, 170, 110, 211, 121, 197, 200, 47, 231 188, 207, 208, 184, 221, 216, 76, 148, 143, 156, 100, 8, 89, 117, 14, 232 112, 183, 221, 54, 197, 208, 180, 69, 176, 94, 180, 131, 215, 121, 76, 233 7, 54, 28, 216, 238, 249, 176, 58, 142, 64, 215, 242, 72, 49, 104, 234 87, 161, 32, 52, 216, 230, 4, 141, 44, 181, 235, 224, 57, 195, 89, 235 134, 203, 144, 162, 163, 126, 156, 84, 185, 42, 148, 145, 29, 221, 194, 236 134, 52, 100, 166, 105, 60, 140, 110, 201, 184, 35, 181, 153, 93, 121, 237 243, 227, 68, 131, 134, 232, 2, 35, 60, 187, 77, 209, 76, 106, 174, 238 15, 241, 227, 115, 151, 77, 175, 36, 187, 121, 221, 223, 47, 118, 61, 239 168, 105, 32, 237, 236, 167, 213, 238, 202, 17, 170, 24, 226, 247, 131, 240 145, 6, 116, 117, 121, 11, 194, 41, 48, 126, 162, 13, 93, 209, 131, 241 154, 122, 237, 187, 103, 217, 99, 60, 200, 45, 78, 115, 69, 49, 106, 242 200, 194, 112, 60, 56, 234, 72, 251, 19, 120, 121, 182, 134, 215, 135, 243 10, 114, 2, 247, 46, 105, 209, 145, 165, 153, 191, 243, 12, 5, 36, 244 119, 206, 231, 231, 11, 32, 209, 83, 27, 229, 204, 149, 155, 83, 109, 245 35, 93, 223, 37, 84, 14, 142, 37, 160, 52, 191, 96, 40, 204, 101, 246 77, 67, 52, 53, 43, 63, 85, 253, 147, 113, 226, 96, 6, 125, 179, 247 115, 161, 17, 83, 198, 101, 98, 85, 139, 3, 137, 75, 99, 178, 23, 248 201, 255, 91, 253, 52, 134, 60, 138, 131, 208, 251, 101, 48, 2, 227, 249 228, 118, 132, 245, 202, 75, 91, 44, 160, 231, 47, 41, 50, 147, 220, 250 74, 92, 219, 165, 89, 16 251 }; 252 253 // Expected results for xoffset = 2 and yoffset = 2. 254 static const int kExpectedDstStride = 16; 255 static const uint8_t kExpectedDst[256] = { 256 117, 102, 74, 135, 42, 98, 175, 206, 70, 73, 222, 197, 50, 24, 39, 257 49, 38, 105, 90, 47, 169, 40, 171, 215, 200, 73, 109, 141, 53, 85, 258 177, 164, 79, 208, 124, 89, 212, 18, 81, 145, 151, 164, 217, 153, 91, 259 154, 102, 102, 159, 75, 164, 152, 136, 51, 213, 219, 186, 116, 193, 224, 260 186, 36, 231, 208, 84, 211, 155, 167, 35, 59, 42, 76, 216, 149, 73, 261 201, 78, 149, 184, 100, 96, 196, 189, 198, 188, 235, 195, 117, 129, 120, 262 129, 49, 25, 133, 113, 69, 221, 114, 70, 143, 99, 157, 108, 189, 140, 263 78, 6, 55, 65, 240, 255, 245, 184, 72, 90, 100, 116, 131, 39, 60, 264 234, 167, 33, 160, 88, 185, 200, 157, 159, 176, 127, 151, 138, 102, 168, 265 106, 170, 86, 82, 219, 189, 76, 33, 115, 197, 106, 96, 198, 136, 97, 266 141, 237, 151, 98, 137, 191, 185, 2, 57, 95, 142, 91, 255, 185, 97, 267 137, 76, 162, 94, 173, 131, 193, 161, 81, 106, 72, 135, 222, 234, 137, 268 66, 137, 106, 243, 210, 147, 95, 15, 137, 110, 85, 66, 16, 96, 167, 269 147, 150, 173, 203, 140, 118, 196, 84, 147, 160, 19, 95, 101, 123, 74, 270 132, 202, 82, 166, 12, 131, 166, 189, 170, 159, 85, 79, 66, 57, 152, 271 132, 203, 194, 0, 1, 56, 146, 180, 224, 156, 28, 83, 181, 79, 76, 272 80, 46, 160, 175, 59, 106, 43, 87, 75, 136, 85, 189, 46, 71, 200, 273 90 274 }; 275 276 ASM_REGISTER_STATE_CHECK( 277 predict_(const_cast<uint8_t *>(kTestData) + kSrcStride * 2 + 2, 278 kSrcStride, 2, 2, dst_, dst_stride_)); 279 280 ASSERT_TRUE( 281 CompareBuffers(kExpectedDst, kExpectedDstStride, dst_, dst_stride_)); 282 } 283 284 INSTANTIATE_TEST_CASE_P( 285 C, SixtapPredictTest, 286 ::testing::Values(make_tuple(16, 16, &vp8_sixtap_predict16x16_c), 287 make_tuple(8, 8, &vp8_sixtap_predict8x8_c), 288 make_tuple(8, 4, &vp8_sixtap_predict8x4_c), 289 make_tuple(4, 4, &vp8_sixtap_predict4x4_c))); 290 #if HAVE_NEON 291 INSTANTIATE_TEST_CASE_P( 292 NEON, SixtapPredictTest, 293 ::testing::Values(make_tuple(16, 16, &vp8_sixtap_predict16x16_neon), 294 make_tuple(8, 8, &vp8_sixtap_predict8x8_neon), 295 make_tuple(8, 4, &vp8_sixtap_predict8x4_neon), 296 make_tuple(4, 4, &vp8_sixtap_predict4x4_neon))); 297 #endif 298 #if HAVE_MMX 299 INSTANTIATE_TEST_CASE_P( 300 MMX, SixtapPredictTest, 301 ::testing::Values(make_tuple(4, 4, &vp8_sixtap_predict4x4_mmx))); 302 #endif 303 #if HAVE_SSE2 304 INSTANTIATE_TEST_CASE_P( 305 SSE2, SixtapPredictTest, 306 ::testing::Values(make_tuple(16, 16, &vp8_sixtap_predict16x16_sse2), 307 make_tuple(8, 8, &vp8_sixtap_predict8x8_sse2), 308 make_tuple(8, 4, &vp8_sixtap_predict8x4_sse2))); 309 #endif 310 #if HAVE_SSSE3 311 INSTANTIATE_TEST_CASE_P( 312 SSSE3, SixtapPredictTest, 313 ::testing::Values(make_tuple(16, 16, &vp8_sixtap_predict16x16_ssse3), 314 make_tuple(8, 8, &vp8_sixtap_predict8x8_ssse3), 315 make_tuple(8, 4, &vp8_sixtap_predict8x4_ssse3), 316 make_tuple(4, 4, &vp8_sixtap_predict4x4_ssse3))); 317 #endif 318 #if HAVE_MSA 319 INSTANTIATE_TEST_CASE_P( 320 MSA, SixtapPredictTest, 321 ::testing::Values(make_tuple(16, 16, &vp8_sixtap_predict16x16_msa), 322 make_tuple(8, 8, &vp8_sixtap_predict8x8_msa), 323 make_tuple(8, 4, &vp8_sixtap_predict8x4_msa), 324 make_tuple(4, 4, &vp8_sixtap_predict4x4_msa))); 325 #endif 326 327 #if HAVE_MMI 328 INSTANTIATE_TEST_CASE_P( 329 MMI, SixtapPredictTest, 330 ::testing::Values(make_tuple(16, 16, &vp8_sixtap_predict16x16_mmi), 331 make_tuple(8, 8, &vp8_sixtap_predict8x8_mmi), 332 make_tuple(8, 4, &vp8_sixtap_predict8x4_mmi), 333 make_tuple(4, 4, &vp8_sixtap_predict4x4_mmi))); 334 #endif 335 336 class BilinearPredictTest : public PredictTestBase {}; 337 338 TEST_P(BilinearPredictTest, TestWithRandomData) { 339 TestWithRandomData(vp8_bilinear_predict16x16_c); 340 } 341 TEST_P(BilinearPredictTest, TestWithUnalignedDst) { 342 TestWithUnalignedDst(vp8_bilinear_predict16x16_c); 343 } 344 345 INSTANTIATE_TEST_CASE_P( 346 C, BilinearPredictTest, 347 ::testing::Values(make_tuple(16, 16, &vp8_bilinear_predict16x16_c), 348 make_tuple(8, 8, &vp8_bilinear_predict8x8_c), 349 make_tuple(8, 4, &vp8_bilinear_predict8x4_c), 350 make_tuple(4, 4, &vp8_bilinear_predict4x4_c))); 351 #if HAVE_NEON 352 INSTANTIATE_TEST_CASE_P( 353 NEON, BilinearPredictTest, 354 ::testing::Values(make_tuple(16, 16, &vp8_bilinear_predict16x16_neon), 355 make_tuple(8, 8, &vp8_bilinear_predict8x8_neon), 356 make_tuple(8, 4, &vp8_bilinear_predict8x4_neon), 357 make_tuple(4, 4, &vp8_bilinear_predict4x4_neon))); 358 #endif 359 #if HAVE_MMX 360 INSTANTIATE_TEST_CASE_P( 361 MMX, BilinearPredictTest, 362 ::testing::Values(make_tuple(8, 4, &vp8_bilinear_predict8x4_mmx), 363 make_tuple(4, 4, &vp8_bilinear_predict4x4_mmx))); 364 #endif 365 #if HAVE_SSE2 366 INSTANTIATE_TEST_CASE_P( 367 SSE2, BilinearPredictTest, 368 ::testing::Values(make_tuple(16, 16, &vp8_bilinear_predict16x16_sse2), 369 make_tuple(8, 8, &vp8_bilinear_predict8x8_sse2))); 370 #endif 371 #if HAVE_SSSE3 372 INSTANTIATE_TEST_CASE_P( 373 SSSE3, BilinearPredictTest, 374 ::testing::Values(make_tuple(16, 16, &vp8_bilinear_predict16x16_ssse3), 375 make_tuple(8, 8, &vp8_bilinear_predict8x8_ssse3))); 376 #endif 377 #if HAVE_MSA 378 INSTANTIATE_TEST_CASE_P( 379 MSA, BilinearPredictTest, 380 ::testing::Values(make_tuple(16, 16, &vp8_bilinear_predict16x16_msa), 381 make_tuple(8, 8, &vp8_bilinear_predict8x8_msa), 382 make_tuple(8, 4, &vp8_bilinear_predict8x4_msa), 383 make_tuple(4, 4, &vp8_bilinear_predict4x4_msa))); 384 #endif 385 } // namespace 386