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 VPX_TEST_BUFFER_H_
12 #define VPX_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:
Buffer(int width,int height,int top_padding,int left_padding,int right_padding,int bottom_padding)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_(nullptr) {}
35
Buffer(int width,int height,int top_padding,int left_padding,int right_padding,int bottom_padding,unsigned int alignment)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_(nullptr) {}
43
Buffer(int width,int height,int padding)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_(nullptr) {}
49
Buffer(int width,int height,int padding,unsigned int alignment)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_(nullptr) {}
55
~Buffer()56 ~Buffer() {
57 if (alignment_) {
58 vpx_free(raw_buffer_);
59 } else {
60 delete[] raw_buffer_;
61 }
62 }
63
64 T *TopLeftPixel() const;
65
stride()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
Init()105 bool Init() {
106 if (raw_buffer_ != nullptr) 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_NE(raw_buffer_, nullptr);
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>
TopLeftPixel()152 T *Buffer<T>::TopLeftPixel() const {
153 if (!raw_buffer_) return nullptr;
154 return raw_buffer_ + (top_padding_ * stride_) + left_padding_;
155 }
156
157 template <typename T>
Set(const T value)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>
Set(ACMRandom * rand_class,T (ACMRandom::* rand_func)())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>
Set(ACMRandom * rand_class,const T low,const T high)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>
CopyFrom(const Buffer<T> & a)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>
DumpBuffer()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>
HasPadding()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>
PrintDifference(const Buffer<T> & a)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>
SetPadding(const T padding_value)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>
CheckValues(const T value)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>
CheckPadding()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>
CheckValues(const Buffer<T> & a)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>
BufferSizesMatch(const Buffer<T> & a)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 // VPX_TEST_BUFFER_H_
383