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 12 #include <string.h> 13 #include "test/acm_random.h" 14 #include "test/clear_system_state.h" 15 #include "test/register_state_check.h" 16 #include "third_party/googletest/src/include/gtest/gtest.h" 17 18 #include "./vpx_config.h" 19 #include "./vp8_rtcd.h" 20 #include "vp8/common/blockd.h" 21 #include "vpx_mem/vpx_mem.h" 22 23 namespace { 24 25 using libvpx_test::ACMRandom; 26 27 class IntraPredBase { 28 public: 29 virtual ~IntraPredBase() { libvpx_test::ClearSystemState(); } 30 31 protected: 32 void SetupMacroblock(MACROBLOCKD *mbptr, 33 MODE_INFO *miptr, 34 uint8_t *data, 35 int block_size, 36 int stride, 37 int num_planes) { 38 mbptr_ = mbptr; 39 miptr_ = miptr; 40 mbptr_->up_available = 1; 41 mbptr_->left_available = 1; 42 mbptr_->mode_info_context = miptr_; 43 stride_ = stride; 44 block_size_ = block_size; 45 num_planes_ = num_planes; 46 for (int p = 0; p < num_planes; p++) 47 data_ptr_[p] = data + stride * (block_size + 1) * p + 48 stride + block_size; 49 } 50 51 void FillRandom() { 52 // Fill edges with random data 53 ACMRandom rnd(ACMRandom::DeterministicSeed()); 54 for (int p = 0; p < num_planes_; p++) { 55 for (int x = -1 ; x <= block_size_; x++) 56 data_ptr_[p][x - stride_] = rnd.Rand8(); 57 for (int y = 0; y < block_size_; y++) 58 data_ptr_[p][y * stride_ - 1] = rnd.Rand8(); 59 } 60 } 61 62 virtual void Predict(MB_PREDICTION_MODE mode) = 0; 63 64 void SetLeftUnavailable() { 65 mbptr_->left_available = 0; 66 for (int p = 0; p < num_planes_; p++) 67 for (int i = -1; i < block_size_; ++i) 68 data_ptr_[p][stride_ * i - 1] = 129; 69 } 70 71 void SetTopUnavailable() { 72 mbptr_->up_available = 0; 73 for (int p = 0; p < num_planes_; p++) 74 memset(&data_ptr_[p][-1 - stride_], 127, block_size_ + 2); 75 } 76 77 void SetTopLeftUnavailable() { 78 SetLeftUnavailable(); 79 SetTopUnavailable(); 80 } 81 82 int BlockSizeLog2Min1() const { 83 switch (block_size_) { 84 case 16: 85 return 3; 86 case 8: 87 return 2; 88 default: 89 return 0; 90 } 91 } 92 93 // check DC prediction output against a reference 94 void CheckDCPrediction() const { 95 for (int p = 0; p < num_planes_; p++) { 96 // calculate expected DC 97 int expected; 98 if (mbptr_->up_available || mbptr_->left_available) { 99 int sum = 0, shift = BlockSizeLog2Min1() + mbptr_->up_available + 100 mbptr_->left_available; 101 if (mbptr_->up_available) 102 for (int x = 0; x < block_size_; x++) 103 sum += data_ptr_[p][x - stride_]; 104 if (mbptr_->left_available) 105 for (int y = 0; y < block_size_; y++) 106 sum += data_ptr_[p][y * stride_ - 1]; 107 expected = (sum + (1 << (shift - 1))) >> shift; 108 } else { 109 expected = 0x80; 110 } 111 // check that all subsequent lines are equal to the first 112 for (int y = 1; y < block_size_; ++y) 113 ASSERT_EQ(0, memcmp(data_ptr_[p], &data_ptr_[p][y * stride_], 114 block_size_)); 115 // within the first line, ensure that each pixel has the same value 116 for (int x = 1; x < block_size_; ++x) 117 ASSERT_EQ(data_ptr_[p][0], data_ptr_[p][x]); 118 // now ensure that that pixel has the expected (DC) value 119 ASSERT_EQ(expected, data_ptr_[p][0]); 120 } 121 } 122 123 // check V prediction output against a reference 124 void CheckVPrediction() const { 125 // check that all lines equal the top border 126 for (int p = 0; p < num_planes_; p++) 127 for (int y = 0; y < block_size_; y++) 128 ASSERT_EQ(0, memcmp(&data_ptr_[p][-stride_], 129 &data_ptr_[p][y * stride_], block_size_)); 130 } 131 132 // check H prediction output against a reference 133 void CheckHPrediction() const { 134 // for each line, ensure that each pixel is equal to the left border 135 for (int p = 0; p < num_planes_; p++) 136 for (int y = 0; y < block_size_; y++) 137 for (int x = 0; x < block_size_; x++) 138 ASSERT_EQ(data_ptr_[p][-1 + y * stride_], 139 data_ptr_[p][x + y * stride_]); 140 } 141 142 static int ClipByte(int value) { 143 if (value > 255) 144 return 255; 145 else if (value < 0) 146 return 0; 147 return value; 148 } 149 150 // check TM prediction output against a reference 151 void CheckTMPrediction() const { 152 for (int p = 0; p < num_planes_; p++) 153 for (int y = 0; y < block_size_; y++) 154 for (int x = 0; x < block_size_; x++) { 155 const int expected = ClipByte(data_ptr_[p][x - stride_] 156 + data_ptr_[p][stride_ * y - 1] 157 - data_ptr_[p][-1 - stride_]); 158 ASSERT_EQ(expected, data_ptr_[p][y * stride_ + x]); 159 } 160 } 161 162 // Actual test 163 void RunTest() { 164 { 165 SCOPED_TRACE("DC_PRED"); 166 FillRandom(); 167 Predict(DC_PRED); 168 CheckDCPrediction(); 169 } 170 { 171 SCOPED_TRACE("DC_PRED LEFT"); 172 FillRandom(); 173 SetLeftUnavailable(); 174 Predict(DC_PRED); 175 CheckDCPrediction(); 176 } 177 { 178 SCOPED_TRACE("DC_PRED TOP"); 179 FillRandom(); 180 SetTopUnavailable(); 181 Predict(DC_PRED); 182 CheckDCPrediction(); 183 } 184 { 185 SCOPED_TRACE("DC_PRED TOP_LEFT"); 186 FillRandom(); 187 SetTopLeftUnavailable(); 188 Predict(DC_PRED); 189 CheckDCPrediction(); 190 } 191 { 192 SCOPED_TRACE("H_PRED"); 193 FillRandom(); 194 Predict(H_PRED); 195 CheckHPrediction(); 196 } 197 { 198 SCOPED_TRACE("V_PRED"); 199 FillRandom(); 200 Predict(V_PRED); 201 CheckVPrediction(); 202 } 203 { 204 SCOPED_TRACE("TM_PRED"); 205 FillRandom(); 206 Predict(TM_PRED); 207 CheckTMPrediction(); 208 } 209 } 210 211 MACROBLOCKD *mbptr_; 212 MODE_INFO *miptr_; 213 uint8_t *data_ptr_[2]; // in the case of Y, only [0] is used 214 int stride_; 215 int block_size_; 216 int num_planes_; 217 }; 218 219 typedef void (*intra_pred_y_fn_t)(MACROBLOCKD *x, 220 uint8_t *yabove_row, 221 uint8_t *yleft, 222 int left_stride, 223 uint8_t *ypred_ptr, 224 int y_stride); 225 226 class IntraPredYTest 227 : public IntraPredBase, 228 public ::testing::TestWithParam<intra_pred_y_fn_t> { 229 public: 230 static void SetUpTestCase() { 231 mb_ = reinterpret_cast<MACROBLOCKD*>( 232 vpx_memalign(32, sizeof(MACROBLOCKD))); 233 mi_ = reinterpret_cast<MODE_INFO*>( 234 vpx_memalign(32, sizeof(MODE_INFO))); 235 data_array_ = reinterpret_cast<uint8_t*>( 236 vpx_memalign(kDataAlignment, kDataBufferSize)); 237 } 238 239 static void TearDownTestCase() { 240 vpx_free(data_array_); 241 vpx_free(mi_); 242 vpx_free(mb_); 243 data_array_ = NULL; 244 } 245 246 protected: 247 static const int kBlockSize = 16; 248 static const int kDataAlignment = 16; 249 static const int kStride = kBlockSize * 3; 250 // We use 48 so that the data pointer of the first pixel in each row of 251 // each macroblock is 16-byte aligned, and this gives us access to the 252 // top-left and top-right corner pixels belonging to the top-left/right 253 // macroblocks. 254 // We use 17 lines so we have one line above us for top-prediction. 255 static const int kDataBufferSize = kStride * (kBlockSize + 1); 256 257 virtual void SetUp() { 258 pred_fn_ = GetParam(); 259 SetupMacroblock(mb_, mi_, data_array_, kBlockSize, kStride, 1); 260 } 261 262 virtual void Predict(MB_PREDICTION_MODE mode) { 263 mbptr_->mode_info_context->mbmi.mode = mode; 264 REGISTER_STATE_CHECK(pred_fn_(mbptr_, 265 data_ptr_[0] - kStride, 266 data_ptr_[0] - 1, kStride, 267 data_ptr_[0], kStride)); 268 } 269 270 intra_pred_y_fn_t pred_fn_; 271 static uint8_t* data_array_; 272 static MACROBLOCKD * mb_; 273 static MODE_INFO *mi_; 274 }; 275 276 MACROBLOCKD* IntraPredYTest::mb_ = NULL; 277 MODE_INFO* IntraPredYTest::mi_ = NULL; 278 uint8_t* IntraPredYTest::data_array_ = NULL; 279 280 TEST_P(IntraPredYTest, IntraPredTests) { 281 RunTest(); 282 } 283 284 INSTANTIATE_TEST_CASE_P(C, IntraPredYTest, 285 ::testing::Values( 286 vp8_build_intra_predictors_mby_s_c)); 287 #if HAVE_SSE2 288 INSTANTIATE_TEST_CASE_P(SSE2, IntraPredYTest, 289 ::testing::Values( 290 vp8_build_intra_predictors_mby_s_sse2)); 291 #endif 292 #if HAVE_SSSE3 293 INSTANTIATE_TEST_CASE_P(SSSE3, IntraPredYTest, 294 ::testing::Values( 295 vp8_build_intra_predictors_mby_s_ssse3)); 296 #endif 297 298 typedef void (*intra_pred_uv_fn_t)(MACROBLOCKD *x, 299 uint8_t *uabove_row, 300 uint8_t *vabove_row, 301 uint8_t *uleft, 302 uint8_t *vleft, 303 int left_stride, 304 uint8_t *upred_ptr, 305 uint8_t *vpred_ptr, 306 int pred_stride); 307 308 class IntraPredUVTest 309 : public IntraPredBase, 310 public ::testing::TestWithParam<intra_pred_uv_fn_t> { 311 public: 312 static void SetUpTestCase() { 313 mb_ = reinterpret_cast<MACROBLOCKD*>( 314 vpx_memalign(32, sizeof(MACROBLOCKD))); 315 mi_ = reinterpret_cast<MODE_INFO*>( 316 vpx_memalign(32, sizeof(MODE_INFO))); 317 data_array_ = reinterpret_cast<uint8_t*>( 318 vpx_memalign(kDataAlignment, kDataBufferSize)); 319 } 320 321 static void TearDownTestCase() { 322 vpx_free(data_array_); 323 vpx_free(mi_); 324 vpx_free(mb_); 325 data_array_ = NULL; 326 } 327 328 protected: 329 static const int kBlockSize = 8; 330 static const int kDataAlignment = 8; 331 static const int kStride = kBlockSize * 3; 332 // We use 24 so that the data pointer of the first pixel in each row of 333 // each macroblock is 8-byte aligned, and this gives us access to the 334 // top-left and top-right corner pixels belonging to the top-left/right 335 // macroblocks. 336 // We use 9 lines so we have one line above us for top-prediction. 337 // [0] = U, [1] = V 338 static const int kDataBufferSize = 2 * kStride * (kBlockSize + 1); 339 340 virtual void SetUp() { 341 pred_fn_ = GetParam(); 342 SetupMacroblock(mb_, mi_, data_array_, kBlockSize, kStride, 2); 343 } 344 345 virtual void Predict(MB_PREDICTION_MODE mode) { 346 mbptr_->mode_info_context->mbmi.uv_mode = mode; 347 pred_fn_(mbptr_, data_ptr_[0] - kStride, data_ptr_[1] - kStride, 348 data_ptr_[0] - 1, data_ptr_[1] - 1, kStride, 349 data_ptr_[0], data_ptr_[1], kStride); 350 } 351 352 intra_pred_uv_fn_t pred_fn_; 353 // We use 24 so that the data pointer of the first pixel in each row of 354 // each macroblock is 8-byte aligned, and this gives us access to the 355 // top-left and top-right corner pixels belonging to the top-left/right 356 // macroblocks. 357 // We use 9 lines so we have one line above us for top-prediction. 358 // [0] = U, [1] = V 359 static uint8_t* data_array_; 360 static MACROBLOCKD* mb_; 361 static MODE_INFO* mi_; 362 }; 363 364 MACROBLOCKD* IntraPredUVTest::mb_ = NULL; 365 MODE_INFO* IntraPredUVTest::mi_ = NULL; 366 uint8_t* IntraPredUVTest::data_array_ = NULL; 367 368 TEST_P(IntraPredUVTest, IntraPredTests) { 369 RunTest(); 370 } 371 372 INSTANTIATE_TEST_CASE_P(C, IntraPredUVTest, 373 ::testing::Values( 374 vp8_build_intra_predictors_mbuv_s_c)); 375 #if HAVE_SSE2 376 INSTANTIATE_TEST_CASE_P(SSE2, IntraPredUVTest, 377 ::testing::Values( 378 vp8_build_intra_predictors_mbuv_s_sse2)); 379 #endif 380 #if HAVE_SSSE3 381 INSTANTIATE_TEST_CASE_P(SSSE3, IntraPredUVTest, 382 ::testing::Values( 383 vp8_build_intra_predictors_mbuv_s_ssse3)); 384 #endif 385 386 } // namespace 387