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
23namespace libvpx_test {
24
25template <typename T>
26class Buffer {
27 public:
28  Buffer(int width, int height, int top_padding, int left_padding,
29         int right_padding, int bottom_padding)
30      : width_(width), height_(height), top_padding_(top_padding),
31        left_padding_(left_padding), right_padding_(right_padding),
32        bottom_padding_(bottom_padding) {
33    Init();
34  }
35
36  Buffer(int width, int height, int padding)
37      : width_(width), height_(height), top_padding_(padding),
38        left_padding_(padding), right_padding_(padding),
39        bottom_padding_(padding) {
40    Init();
41  }
42
43  ~Buffer() { delete[] raw_buffer_; }
44
45  T *TopLeftPixel() const;
46
47  int stride() const { return stride_; }
48
49  // Set the buffer (excluding padding) to 'value'.
50  void Set(const int value);
51
52  // Set the buffer (excluding padding) to the output of ACMRandom function 'b'.
53  void Set(ACMRandom *rand_class, T (ACMRandom::*rand_func)());
54
55  // Copy the contents of Buffer 'a' (excluding padding).
56  void CopyFrom(const Buffer<T> &a);
57
58  void DumpBuffer() const;
59
60  // Highlight the differences between two buffers if they are the same size.
61  void PrintDifference(const Buffer<T> &a) const;
62
63  bool HasPadding() const;
64
65  // Sets all the values in the buffer to 'padding_value'.
66  void SetPadding(const int padding_value);
67
68  // Checks if all the values (excluding padding) are equal to 'value' if the
69  // Buffers are the same size.
70  bool CheckValues(const int value) const;
71
72  // Check that padding matches the expected value or there is no padding.
73  bool CheckPadding() const;
74
75  // Compare the non-padding portion of two buffers if they are the same size.
76  bool CheckValues(const Buffer<T> &a) const;
77
78 private:
79  void Init() {
80    ASSERT_GT(width_, 0);
81    ASSERT_GT(height_, 0);
82    ASSERT_GE(top_padding_, 0);
83    ASSERT_GE(left_padding_, 0);
84    ASSERT_GE(right_padding_, 0);
85    ASSERT_GE(bottom_padding_, 0);
86    stride_ = left_padding_ + width_ + right_padding_;
87    raw_size_ = stride_ * (top_padding_ + height_ + bottom_padding_);
88    raw_buffer_ = new (std::nothrow) T[raw_size_];
89    ASSERT_TRUE(raw_buffer_ != NULL);
90    SetPadding(std::numeric_limits<T>::max());
91  }
92
93  bool BufferSizesMatch(const Buffer<T> &a) const;
94
95  const int width_;
96  const int height_;
97  const int top_padding_;
98  const int left_padding_;
99  const int right_padding_;
100  const int bottom_padding_;
101  int padding_value_;
102  int stride_;
103  int raw_size_;
104  T *raw_buffer_;
105};
106
107template <typename T>
108T *Buffer<T>::TopLeftPixel() const {
109  return raw_buffer_ + (top_padding_ * stride()) + left_padding_;
110}
111
112template <typename T>
113void Buffer<T>::Set(const int value) {
114  T *src = TopLeftPixel();
115  for (int height = 0; height < height_; ++height) {
116    for (int width = 0; width < width_; ++width) {
117      src[width] = value;
118    }
119    src += stride();
120  }
121}
122
123template <typename T>
124void Buffer<T>::Set(ACMRandom *rand_class, T (ACMRandom::*rand_func)()) {
125  T *src = TopLeftPixel();
126  for (int height = 0; height < height_; ++height) {
127    for (int width = 0; width < width_; ++width) {
128      src[width] = (*rand_class.*rand_func)();
129    }
130    src += stride();
131  }
132}
133
134template <typename T>
135void Buffer<T>::CopyFrom(const Buffer<T> &a) {
136  if (!BufferSizesMatch(a)) {
137    return;
138  }
139
140  T *a_src = a.TopLeftPixel();
141  T *b_src = this->TopLeftPixel();
142  for (int height = 0; height < height_; ++height) {
143    for (int width = 0; width < width_; ++width) {
144      b_src[width] = a_src[width];
145    }
146    a_src += a.stride();
147    b_src += this->stride();
148  }
149}
150
151template <typename T>
152void Buffer<T>::DumpBuffer() const {
153  for (int height = 0; height < height_ + top_padding_ + bottom_padding_;
154       ++height) {
155    for (int width = 0; width < stride(); ++width) {
156      printf("%4d", raw_buffer_[height + width * stride()]);
157    }
158    printf("\n");
159  }
160}
161
162template <typename T>
163bool Buffer<T>::HasPadding() const {
164  return top_padding_ || left_padding_ || right_padding_ || bottom_padding_;
165}
166
167template <typename T>
168void Buffer<T>::PrintDifference(const Buffer<T> &a) const {
169  if (!BufferSizesMatch(a)) {
170    return;
171  }
172
173  T *a_src = a.TopLeftPixel();
174  T *b_src = TopLeftPixel();
175
176  printf("This buffer:\n");
177  for (int height = 0; height < height_; ++height) {
178    for (int width = 0; width < width_; ++width) {
179      if (a_src[width] != b_src[width]) {
180        printf("*%3d", b_src[width]);
181      } else {
182        printf("%4d", b_src[width]);
183      }
184    }
185    printf("\n");
186    a_src += a.stride();
187    b_src += this->stride();
188  }
189
190  a_src = a.TopLeftPixel();
191  b_src = TopLeftPixel();
192
193  printf("Reference buffer:\n");
194  for (int height = 0; height < height_; ++height) {
195    for (int width = 0; width < width_; ++width) {
196      if (a_src[width] != b_src[width]) {
197        printf("*%3d", a_src[width]);
198      } else {
199        printf("%4d", a_src[width]);
200      }
201    }
202    printf("\n");
203    a_src += a.stride();
204    b_src += this->stride();
205  }
206}
207
208template <typename T>
209void Buffer<T>::SetPadding(const int padding_value) {
210  padding_value_ = padding_value;
211
212  T *src = raw_buffer_;
213  for (int i = 0; i < raw_size_; ++i) {
214    src[i] = padding_value;
215  }
216}
217
218template <typename T>
219bool Buffer<T>::CheckValues(const int value) const {
220  T *src = TopLeftPixel();
221  for (int height = 0; height < height_; ++height) {
222    for (int width = 0; width < width_; ++width) {
223      if (value != src[width]) {
224        return false;
225      }
226    }
227    src += stride();
228  }
229  return true;
230}
231
232template <typename T>
233bool Buffer<T>::CheckPadding() const {
234  if (!HasPadding()) {
235    return true;
236  }
237
238  // Top padding.
239  T const *top = raw_buffer_;
240  for (int i = 0; i < stride() * top_padding_; ++i) {
241    if (padding_value_ != top[i]) {
242      return false;
243    }
244  }
245
246  // Left padding.
247  T const *left = TopLeftPixel() - left_padding_;
248  for (int height = 0; height < height_; ++height) {
249    for (int width = 0; width < left_padding_; ++width) {
250      if (padding_value_ != left[width]) {
251        return false;
252      }
253    }
254    left += stride();
255  }
256
257  // Right padding.
258  T const *right = TopLeftPixel() + width_;
259  for (int height = 0; height < height_; ++height) {
260    for (int width = 0; width < right_padding_; ++width) {
261      if (padding_value_ != right[width]) {
262        return false;
263      }
264    }
265    right += stride();
266  }
267
268  // Bottom padding
269  T const *bottom = raw_buffer_ + (top_padding_ + height_) * stride();
270  for (int i = 0; i < stride() * bottom_padding_; ++i) {
271    if (padding_value_ != bottom[i]) {
272      return false;
273    }
274  }
275
276  return true;
277}
278
279template <typename T>
280bool Buffer<T>::CheckValues(const Buffer<T> &a) const {
281  if (!BufferSizesMatch(a)) {
282    return false;
283  }
284
285  T *a_src = a.TopLeftPixel();
286  T *b_src = this->TopLeftPixel();
287  for (int height = 0; height < height_; ++height) {
288    for (int width = 0; width < width_; ++width) {
289      if (a_src[width] != b_src[width]) {
290        return false;
291      }
292    }
293    a_src += a.stride();
294    b_src += this->stride();
295  }
296  return true;
297}
298
299template <typename T>
300bool Buffer<T>::BufferSizesMatch(const Buffer<T> &a) const {
301  if (a.width_ != this->width_ || a.height_ != this->height_) {
302    printf(
303        "Reference buffer of size %dx%d does not match this buffer which is "
304        "size %dx%d\n",
305        a.width_, a.height_, this->width_, this->height_);
306    return false;
307  }
308
309  return true;
310}
311}  // namespace libvpx_test
312#endif  // TEST_BUFFER_H_
313