buffer.h 11 KB

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