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