Home | History | Annotate | Download | only in test
      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