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