Home | History | Annotate | Download | only in test
      1 /*
      2  *  Copyright (c) 2016 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 #ifndef TEST_BUFFER_H_
     12 #define TEST_BUFFER_H_
     13 
     14 #include <stdio.h>
     15 
     16 #include <limits>
     17 
     18 #include "third_party/googletest/src/include/gtest/gtest.h"
     19 
     20 #include "test/acm_random.h"
     21 #include "vpx/vpx_integer.h"
     22 #include "vpx_mem/vpx_mem.h"
     23 
     24 namespace libvpx_test {
     25 
     26 template <typename T>
     27 class Buffer {
     28  public:
     29   Buffer(int width, int height, int top_padding, int left_padding,
     30          int right_padding, int bottom_padding)
     31       : width_(width), height_(height), top_padding_(top_padding),
     32         left_padding_(left_padding), right_padding_(right_padding),
     33         bottom_padding_(bottom_padding), alignment_(0), padding_value_(0),
     34         stride_(0), raw_size_(0), num_elements_(0), raw_buffer_(NULL) {}
     35 
     36   Buffer(int width, int height, int top_padding, int left_padding,
     37          int right_padding, int bottom_padding, unsigned int alignment)
     38       : width_(width), height_(height), top_padding_(top_padding),
     39         left_padding_(left_padding), right_padding_(right_padding),
     40         bottom_padding_(bottom_padding), alignment_(alignment),
     41         padding_value_(0), stride_(0), raw_size_(0), num_elements_(0),
     42         raw_buffer_(NULL) {}
     43 
     44   Buffer(int width, int height, int padding)
     45       : width_(width), height_(height), top_padding_(padding),
     46         left_padding_(padding), right_padding_(padding),
     47         bottom_padding_(padding), alignment_(0), padding_value_(0), stride_(0),
     48         raw_size_(0), num_elements_(0), raw_buffer_(NULL) {}
     49 
     50   Buffer(int width, int height, int padding, unsigned int alignment)
     51       : width_(width), height_(height), top_padding_(padding),
     52         left_padding_(padding), right_padding_(padding),
     53         bottom_padding_(padding), alignment_(alignment), padding_value_(0),
     54         stride_(0), raw_size_(0), num_elements_(0), raw_buffer_(NULL) {}
     55 
     56   ~Buffer() {
     57     if (alignment_) {
     58       vpx_free(raw_buffer_);
     59     } else {
     60       delete[] raw_buffer_;
     61     }
     62   }
     63 
     64   T *TopLeftPixel() const;
     65 
     66   int stride() const { return stride_; }
     67 
     68   // Set the buffer (excluding padding) to 'value'.
     69   void Set(const T value);
     70 
     71   // Set the buffer (excluding padding) to the output of ACMRandom function
     72   // 'rand_func'.
     73   void Set(ACMRandom *rand_class, T (ACMRandom::*rand_func)());
     74 
     75   // Set the buffer (excluding padding) to the output of ACMRandom function
     76   // 'RandRange' with range 'low' to 'high' which typically must be within
     77   // testing::internal::Random::kMaxRange (1u << 31). However, because we want
     78   // to allow negative low (and high) values, it is restricted to INT32_MAX
     79   // here.
     80   void Set(ACMRandom *rand_class, const T low, const T high);
     81 
     82   // Copy the contents of Buffer 'a' (excluding padding).
     83   void CopyFrom(const Buffer<T> &a);
     84 
     85   void DumpBuffer() const;
     86 
     87   // Highlight the differences between two buffers if they are the same size.
     88   void PrintDifference(const Buffer<T> &a) const;
     89 
     90   bool HasPadding() const;
     91 
     92   // Sets all the values in the buffer to 'padding_value'.
     93   void SetPadding(const T padding_value);
     94 
     95   // Checks if all the values (excluding padding) are equal to 'value' if the
     96   // Buffers are the same size.
     97   bool CheckValues(const T value) const;
     98 
     99   // Check that padding matches the expected value or there is no padding.
    100   bool CheckPadding() const;
    101 
    102   // Compare the non-padding portion of two buffers if they are the same size.
    103   bool CheckValues(const Buffer<T> &a) const;
    104 
    105   bool Init() {
    106     if (raw_buffer_ != NULL) return false;
    107     EXPECT_GT(width_, 0);
    108     EXPECT_GT(height_, 0);
    109     EXPECT_GE(top_padding_, 0);
    110     EXPECT_GE(left_padding_, 0);
    111     EXPECT_GE(right_padding_, 0);
    112     EXPECT_GE(bottom_padding_, 0);
    113     stride_ = left_padding_ + width_ + right_padding_;
    114     num_elements_ = stride_ * (top_padding_ + height_ + bottom_padding_);
    115     raw_size_ = num_elements_ * sizeof(T);
    116     if (alignment_) {
    117       EXPECT_GE(alignment_, sizeof(T));
    118       // Ensure alignment of the first value will be preserved.
    119       EXPECT_EQ((left_padding_ * sizeof(T)) % alignment_, 0u);
    120       // Ensure alignment of the subsequent rows will be preserved when there is
    121       // a stride.
    122       if (stride_ != width_) {
    123         EXPECT_EQ((stride_ * sizeof(T)) % alignment_, 0u);
    124       }
    125       raw_buffer_ = reinterpret_cast<T *>(vpx_memalign(alignment_, raw_size_));
    126     } else {
    127       raw_buffer_ = new (std::nothrow) T[num_elements_];
    128     }
    129     EXPECT_TRUE(raw_buffer_ != NULL);
    130     SetPadding(std::numeric_limits<T>::max());
    131     return !::testing::Test::HasFailure();
    132   }
    133 
    134  private:
    135   bool BufferSizesMatch(const Buffer<T> &a) const;
    136 
    137   const int width_;
    138   const int height_;
    139   const int top_padding_;
    140   const int left_padding_;
    141   const int right_padding_;
    142   const int bottom_padding_;
    143   const unsigned int alignment_;
    144   T padding_value_;
    145   int stride_;
    146   int raw_size_;
    147   int num_elements_;
    148   T *raw_buffer_;
    149 };
    150 
    151 template <typename T>
    152 T *Buffer<T>::TopLeftPixel() const {
    153   if (!raw_buffer_) return NULL;
    154   return raw_buffer_ + (top_padding_ * stride_) + left_padding_;
    155 }
    156 
    157 template <typename T>
    158 void Buffer<T>::Set(const T value) {
    159   if (!raw_buffer_) return;
    160   T *src = TopLeftPixel();
    161   for (int height = 0; height < height_; ++height) {
    162     for (int width = 0; width < width_; ++width) {
    163       src[width] = value;
    164     }
    165     src += stride_;
    166   }
    167 }
    168 
    169 template <typename T>
    170 void Buffer<T>::Set(ACMRandom *rand_class, T (ACMRandom::*rand_func)()) {
    171   if (!raw_buffer_) return;
    172   T *src = TopLeftPixel();
    173   for (int height = 0; height < height_; ++height) {
    174     for (int width = 0; width < width_; ++width) {
    175       src[width] = (*rand_class.*rand_func)();
    176     }
    177     src += stride_;
    178   }
    179 }
    180 
    181 template <typename T>
    182 void Buffer<T>::Set(ACMRandom *rand_class, const T low, const T high) {
    183   if (!raw_buffer_) return;
    184 
    185   EXPECT_LE(low, high);
    186   EXPECT_LE(static_cast<int64_t>(high) - low,
    187             std::numeric_limits<int32_t>::max());
    188 
    189   T *src = TopLeftPixel();
    190   for (int height = 0; height < height_; ++height) {
    191     for (int width = 0; width < width_; ++width) {
    192       // 'low' will be promoted to unsigned given the return type of RandRange.
    193       // Store the value as an int to avoid unsigned overflow warnings when
    194       // 'low' is negative.
    195       const int32_t value =
    196           static_cast<int32_t>((*rand_class).RandRange(high - low));
    197       src[width] = static_cast<T>(value + low);
    198     }
    199     src += stride_;
    200   }
    201 }
    202 
    203 template <typename T>
    204 void Buffer<T>::CopyFrom(const Buffer<T> &a) {
    205   if (!raw_buffer_) return;
    206   if (!BufferSizesMatch(a)) return;
    207 
    208   T *a_src = a.TopLeftPixel();
    209   T *b_src = this->TopLeftPixel();
    210   for (int height = 0; height < height_; ++height) {
    211     for (int width = 0; width < width_; ++width) {
    212       b_src[width] = a_src[width];
    213     }
    214     a_src += a.stride();
    215     b_src += this->stride();
    216   }
    217 }
    218 
    219 template <typename T>
    220 void Buffer<T>::DumpBuffer() const {
    221   if (!raw_buffer_) return;
    222   for (int height = 0; height < height_ + top_padding_ + bottom_padding_;
    223        ++height) {
    224     for (int width = 0; width < stride_; ++width) {
    225       printf("%4d", raw_buffer_[height + width * stride_]);
    226     }
    227     printf("\n");
    228   }
    229 }
    230 
    231 template <typename T>
    232 bool Buffer<T>::HasPadding() const {
    233   if (!raw_buffer_) return false;
    234   return top_padding_ || left_padding_ || right_padding_ || bottom_padding_;
    235 }
    236 
    237 template <typename T>
    238 void Buffer<T>::PrintDifference(const Buffer<T> &a) const {
    239   if (!raw_buffer_) return;
    240   if (!BufferSizesMatch(a)) return;
    241 
    242   T *a_src = a.TopLeftPixel();
    243   T *b_src = TopLeftPixel();
    244 
    245   printf("This buffer:\n");
    246   for (int height = 0; height < height_; ++height) {
    247     for (int width = 0; width < width_; ++width) {
    248       if (a_src[width] != b_src[width]) {
    249         printf("*%3d", b_src[width]);
    250       } else {
    251         printf("%4d", b_src[width]);
    252       }
    253     }
    254     printf("\n");
    255     a_src += a.stride();
    256     b_src += this->stride();
    257   }
    258 
    259   a_src = a.TopLeftPixel();
    260   b_src = TopLeftPixel();
    261 
    262   printf("Reference buffer:\n");
    263   for (int height = 0; height < height_; ++height) {
    264     for (int width = 0; width < width_; ++width) {
    265       if (a_src[width] != b_src[width]) {
    266         printf("*%3d", a_src[width]);
    267       } else {
    268         printf("%4d", a_src[width]);
    269       }
    270     }
    271     printf("\n");
    272     a_src += a.stride();
    273     b_src += this->stride();
    274   }
    275 }
    276 
    277 template <typename T>
    278 void Buffer<T>::SetPadding(const T padding_value) {
    279   if (!raw_buffer_) return;
    280   padding_value_ = padding_value;
    281 
    282   T *src = raw_buffer_;
    283   for (int i = 0; i < num_elements_; ++i) {
    284     src[i] = padding_value;
    285   }
    286 }
    287 
    288 template <typename T>
    289 bool Buffer<T>::CheckValues(const T value) const {
    290   if (!raw_buffer_) return false;
    291   T *src = TopLeftPixel();
    292   for (int height = 0; height < height_; ++height) {
    293     for (int width = 0; width < width_; ++width) {
    294       if (value != src[width]) {
    295         return false;
    296       }
    297     }
    298     src += stride_;
    299   }
    300   return true;
    301 }
    302 
    303 template <typename T>
    304 bool Buffer<T>::CheckPadding() const {
    305   if (!raw_buffer_) return false;
    306   if (!HasPadding()) return true;
    307 
    308   // Top padding.
    309   T const *top = raw_buffer_;
    310   for (int i = 0; i < stride_ * top_padding_; ++i) {
    311     if (padding_value_ != top[i]) {
    312       return false;
    313     }
    314   }
    315 
    316   // Left padding.
    317   T const *left = TopLeftPixel() - left_padding_;
    318   for (int height = 0; height < height_; ++height) {
    319     for (int width = 0; width < left_padding_; ++width) {
    320       if (padding_value_ != left[width]) {
    321         return false;
    322       }
    323     }
    324     left += stride_;
    325   }
    326 
    327   // Right padding.
    328   T const *right = TopLeftPixel() + width_;
    329   for (int height = 0; height < height_; ++height) {
    330     for (int width = 0; width < right_padding_; ++width) {
    331       if (padding_value_ != right[width]) {
    332         return false;
    333       }
    334     }
    335     right += stride_;
    336   }
    337 
    338   // Bottom padding
    339   T const *bottom = raw_buffer_ + (top_padding_ + height_) * stride_;
    340   for (int i = 0; i < stride_ * bottom_padding_; ++i) {
    341     if (padding_value_ != bottom[i]) {
    342       return false;
    343     }
    344   }
    345 
    346   return true;
    347 }
    348 
    349 template <typename T>
    350 bool Buffer<T>::CheckValues(const Buffer<T> &a) const {
    351   if (!raw_buffer_) return false;
    352   if (!BufferSizesMatch(a)) return false;
    353 
    354   T *a_src = a.TopLeftPixel();
    355   T *b_src = this->TopLeftPixel();
    356   for (int height = 0; height < height_; ++height) {
    357     for (int width = 0; width < width_; ++width) {
    358       if (a_src[width] != b_src[width]) {
    359         return false;
    360       }
    361     }
    362     a_src += a.stride();
    363     b_src += this->stride();
    364   }
    365   return true;
    366 }
    367 
    368 template <typename T>
    369 bool Buffer<T>::BufferSizesMatch(const Buffer<T> &a) const {
    370   if (!raw_buffer_) return false;
    371   if (a.width_ != this->width_ || a.height_ != this->height_) {
    372     printf(
    373         "Reference buffer of size %dx%d does not match this buffer which is "
    374         "size %dx%d\n",
    375         a.width_, a.height_, this->width_, this->height_);
    376     return false;
    377   }
    378 
    379   return true;
    380 }
    381 }  // namespace libvpx_test
    382 #endif  // TEST_BUFFER_H_
    383