predict_test.cc 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  1. /*
  2. * Copyright (c) 2013 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. #include <stdlib.h>
  11. #include <string.h>
  12. #include <tuple>
  13. #include "third_party/googletest/src/include/gtest/gtest.h"
  14. #include "./vp8_rtcd.h"
  15. #include "./vpx_config.h"
  16. #include "test/acm_random.h"
  17. #include "test/bench.h"
  18. #include "test/clear_system_state.h"
  19. #include "test/register_state_check.h"
  20. #include "test/util.h"
  21. #include "vpx/vpx_integer.h"
  22. #include "vpx_mem/vpx_mem.h"
  23. #include "vpx_ports/msvc.h"
  24. namespace {
  25. using libvpx_test::ACMRandom;
  26. using std::make_tuple;
  27. typedef void (*PredictFunc)(uint8_t *src_ptr, int src_pixels_per_line,
  28. int xoffset, int yoffset, uint8_t *dst_ptr,
  29. int dst_pitch);
  30. typedef std::tuple<int, int, PredictFunc> PredictParam;
  31. class PredictTestBase : public AbstractBench,
  32. public ::testing::TestWithParam<PredictParam> {
  33. public:
  34. PredictTestBase()
  35. : width_(GET_PARAM(0)), height_(GET_PARAM(1)), predict_(GET_PARAM(2)),
  36. src_(NULL), padded_dst_(NULL), dst_(NULL), dst_c_(NULL) {}
  37. virtual void SetUp() {
  38. src_ = new uint8_t[kSrcSize];
  39. ASSERT_TRUE(src_ != NULL);
  40. // padded_dst_ provides a buffer of kBorderSize around the destination
  41. // memory to facilitate detecting out of bounds writes.
  42. dst_stride_ = kBorderSize + width_ + kBorderSize;
  43. padded_dst_size_ = dst_stride_ * (kBorderSize + height_ + kBorderSize);
  44. padded_dst_ =
  45. reinterpret_cast<uint8_t *>(vpx_memalign(16, padded_dst_size_));
  46. ASSERT_TRUE(padded_dst_ != NULL);
  47. dst_ = padded_dst_ + (kBorderSize * dst_stride_) + kBorderSize;
  48. dst_c_ = new uint8_t[16 * 16];
  49. ASSERT_TRUE(dst_c_ != NULL);
  50. memset(src_, 0, kSrcSize);
  51. memset(padded_dst_, 128, padded_dst_size_);
  52. memset(dst_c_, 0, 16 * 16);
  53. }
  54. virtual void TearDown() {
  55. delete[] src_;
  56. src_ = NULL;
  57. vpx_free(padded_dst_);
  58. padded_dst_ = NULL;
  59. dst_ = NULL;
  60. delete[] dst_c_;
  61. dst_c_ = NULL;
  62. libvpx_test::ClearSystemState();
  63. }
  64. protected:
  65. // Make reference arrays big enough for 16x16 functions. Six-tap filters need
  66. // 5 extra pixels outside of the macroblock.
  67. static const int kSrcStride = 21;
  68. static const int kSrcSize = kSrcStride * kSrcStride;
  69. static const int kBorderSize = 16;
  70. int width_;
  71. int height_;
  72. PredictFunc predict_;
  73. uint8_t *src_;
  74. uint8_t *padded_dst_;
  75. uint8_t *dst_;
  76. int padded_dst_size_;
  77. uint8_t *dst_c_;
  78. int dst_stride_;
  79. bool CompareBuffers(const uint8_t *a, int a_stride, const uint8_t *b,
  80. int b_stride) const {
  81. for (int height = 0; height < height_; ++height) {
  82. EXPECT_EQ(0, memcmp(a + height * a_stride, b + height * b_stride,
  83. sizeof(*a) * width_))
  84. << "Row " << height << " does not match.";
  85. }
  86. return !HasFailure();
  87. }
  88. // Given a block of memory 'a' with size 'a_size', determine if all regions
  89. // excepting block 'b' described by 'b_stride', 'b_height', and 'b_width'
  90. // match pixel value 'c'.
  91. bool CheckBorder(const uint8_t *a, int a_size, const uint8_t *b, int b_width,
  92. int b_height, int b_stride, uint8_t c) const {
  93. const uint8_t *a_end = a + a_size;
  94. const int b_size = (b_stride * b_height) + b_width;
  95. const uint8_t *b_end = b + b_size;
  96. const int left_border = (b_stride - b_width) / 2;
  97. const int right_border = left_border + ((b_stride - b_width) % 2);
  98. EXPECT_GE(b - left_border, a) << "'b' does not start within 'a'";
  99. EXPECT_LE(b_end + right_border, a_end) << "'b' does not end within 'a'";
  100. // Top border.
  101. for (int pixel = 0; pixel < b - a - left_border; ++pixel) {
  102. EXPECT_EQ(c, a[pixel]) << "Mismatch at " << pixel << " in top border.";
  103. }
  104. // Left border.
  105. for (int height = 0; height < b_height; ++height) {
  106. for (int width = left_border; width > 0; --width) {
  107. EXPECT_EQ(c, b[height * b_stride - width])
  108. << "Mismatch at row " << height << " column " << left_border - width
  109. << " in left border.";
  110. }
  111. }
  112. // Right border.
  113. for (int height = 0; height < b_height; ++height) {
  114. for (int width = b_width; width < b_width + right_border; ++width) {
  115. EXPECT_EQ(c, b[height * b_stride + width])
  116. << "Mismatch at row " << height << " column " << width - b_width
  117. << " in right border.";
  118. }
  119. }
  120. // Bottom border.
  121. for (int pixel = static_cast<int>(b - a + b_size); pixel < a_size;
  122. ++pixel) {
  123. EXPECT_EQ(c, a[pixel]) << "Mismatch at " << pixel << " in bottom border.";
  124. }
  125. return !HasFailure();
  126. }
  127. void TestWithRandomData(PredictFunc reference) {
  128. ACMRandom rnd(ACMRandom::DeterministicSeed());
  129. // Run tests for almost all possible offsets.
  130. for (int xoffset = 0; xoffset < 8; ++xoffset) {
  131. for (int yoffset = 0; yoffset < 8; ++yoffset) {
  132. if (xoffset == 0 && yoffset == 0) {
  133. // This represents a copy which is not required to be handled by this
  134. // module.
  135. continue;
  136. }
  137. for (int i = 0; i < kSrcSize; ++i) {
  138. src_[i] = rnd.Rand8();
  139. }
  140. reference(&src_[kSrcStride * 2 + 2], kSrcStride, xoffset, yoffset,
  141. dst_c_, 16);
  142. ASM_REGISTER_STATE_CHECK(predict_(&src_[kSrcStride * 2 + 2], kSrcStride,
  143. xoffset, yoffset, dst_, dst_stride_));
  144. ASSERT_TRUE(CompareBuffers(dst_c_, 16, dst_, dst_stride_));
  145. ASSERT_TRUE(CheckBorder(padded_dst_, padded_dst_size_, dst_, width_,
  146. height_, dst_stride_, 128));
  147. }
  148. }
  149. }
  150. void TestWithUnalignedDst(PredictFunc reference) {
  151. ACMRandom rnd(ACMRandom::DeterministicSeed());
  152. // Only the 4x4 need to be able to handle unaligned writes.
  153. if (width_ == 4 && height_ == 4) {
  154. for (int xoffset = 0; xoffset < 8; ++xoffset) {
  155. for (int yoffset = 0; yoffset < 8; ++yoffset) {
  156. if (xoffset == 0 && yoffset == 0) {
  157. continue;
  158. }
  159. for (int i = 0; i < kSrcSize; ++i) {
  160. src_[i] = rnd.Rand8();
  161. }
  162. reference(&src_[kSrcStride * 2 + 2], kSrcStride, xoffset, yoffset,
  163. dst_c_, 16);
  164. for (int i = 1; i < 4; ++i) {
  165. memset(padded_dst_, 128, padded_dst_size_);
  166. ASM_REGISTER_STATE_CHECK(predict_(&src_[kSrcStride * 2 + 2],
  167. kSrcStride, xoffset, yoffset,
  168. dst_ + i, dst_stride_ + i));
  169. ASSERT_TRUE(CompareBuffers(dst_c_, 16, dst_ + i, dst_stride_ + i));
  170. ASSERT_TRUE(CheckBorder(padded_dst_, padded_dst_size_, dst_ + i,
  171. width_, height_, dst_stride_ + i, 128));
  172. }
  173. }
  174. }
  175. }
  176. }
  177. void Run() {
  178. for (int xoffset = 0; xoffset < 8; ++xoffset) {
  179. for (int yoffset = 0; yoffset < 8; ++yoffset) {
  180. if (xoffset == 0 && yoffset == 0) {
  181. continue;
  182. }
  183. predict_(&src_[kSrcStride * 2 + 2], kSrcStride, xoffset, yoffset, dst_,
  184. dst_stride_);
  185. }
  186. }
  187. }
  188. }; // namespace
  189. class SixtapPredictTest : public PredictTestBase {};
  190. TEST_P(SixtapPredictTest, TestWithRandomData) {
  191. TestWithRandomData(vp8_sixtap_predict16x16_c);
  192. }
  193. TEST_P(SixtapPredictTest, TestWithUnalignedDst) {
  194. TestWithUnalignedDst(vp8_sixtap_predict16x16_c);
  195. }
  196. TEST_P(SixtapPredictTest, TestWithPresetData) {
  197. // Test input
  198. static const uint8_t kTestData[kSrcSize] = {
  199. 184, 4, 191, 82, 92, 41, 0, 1, 226, 236, 172, 20, 182, 42, 226,
  200. 177, 79, 94, 77, 179, 203, 206, 198, 22, 192, 19, 75, 17, 192, 44,
  201. 233, 120, 48, 168, 203, 141, 210, 203, 143, 180, 184, 59, 201, 110, 102,
  202. 171, 32, 182, 10, 109, 105, 213, 60, 47, 236, 253, 67, 55, 14, 3,
  203. 99, 247, 124, 148, 159, 71, 34, 114, 19, 177, 38, 203, 237, 239, 58,
  204. 83, 155, 91, 10, 166, 201, 115, 124, 5, 163, 104, 2, 231, 160, 16,
  205. 234, 4, 8, 103, 153, 167, 174, 187, 26, 193, 109, 64, 141, 90, 48,
  206. 200, 174, 204, 36, 184, 114, 237, 43, 238, 242, 207, 86, 245, 182, 247,
  207. 6, 161, 251, 14, 8, 148, 182, 182, 79, 208, 120, 188, 17, 6, 23,
  208. 65, 206, 197, 13, 242, 126, 128, 224, 170, 110, 211, 121, 197, 200, 47,
  209. 188, 207, 208, 184, 221, 216, 76, 148, 143, 156, 100, 8, 89, 117, 14,
  210. 112, 183, 221, 54, 197, 208, 180, 69, 176, 94, 180, 131, 215, 121, 76,
  211. 7, 54, 28, 216, 238, 249, 176, 58, 142, 64, 215, 242, 72, 49, 104,
  212. 87, 161, 32, 52, 216, 230, 4, 141, 44, 181, 235, 224, 57, 195, 89,
  213. 134, 203, 144, 162, 163, 126, 156, 84, 185, 42, 148, 145, 29, 221, 194,
  214. 134, 52, 100, 166, 105, 60, 140, 110, 201, 184, 35, 181, 153, 93, 121,
  215. 243, 227, 68, 131, 134, 232, 2, 35, 60, 187, 77, 209, 76, 106, 174,
  216. 15, 241, 227, 115, 151, 77, 175, 36, 187, 121, 221, 223, 47, 118, 61,
  217. 168, 105, 32, 237, 236, 167, 213, 238, 202, 17, 170, 24, 226, 247, 131,
  218. 145, 6, 116, 117, 121, 11, 194, 41, 48, 126, 162, 13, 93, 209, 131,
  219. 154, 122, 237, 187, 103, 217, 99, 60, 200, 45, 78, 115, 69, 49, 106,
  220. 200, 194, 112, 60, 56, 234, 72, 251, 19, 120, 121, 182, 134, 215, 135,
  221. 10, 114, 2, 247, 46, 105, 209, 145, 165, 153, 191, 243, 12, 5, 36,
  222. 119, 206, 231, 231, 11, 32, 209, 83, 27, 229, 204, 149, 155, 83, 109,
  223. 35, 93, 223, 37, 84, 14, 142, 37, 160, 52, 191, 96, 40, 204, 101,
  224. 77, 67, 52, 53, 43, 63, 85, 253, 147, 113, 226, 96, 6, 125, 179,
  225. 115, 161, 17, 83, 198, 101, 98, 85, 139, 3, 137, 75, 99, 178, 23,
  226. 201, 255, 91, 253, 52, 134, 60, 138, 131, 208, 251, 101, 48, 2, 227,
  227. 228, 118, 132, 245, 202, 75, 91, 44, 160, 231, 47, 41, 50, 147, 220,
  228. 74, 92, 219, 165, 89, 16
  229. };
  230. // Expected results for xoffset = 2 and yoffset = 2.
  231. static const int kExpectedDstStride = 16;
  232. static const uint8_t kExpectedDst[256] = {
  233. 117, 102, 74, 135, 42, 98, 175, 206, 70, 73, 222, 197, 50, 24, 39,
  234. 49, 38, 105, 90, 47, 169, 40, 171, 215, 200, 73, 109, 141, 53, 85,
  235. 177, 164, 79, 208, 124, 89, 212, 18, 81, 145, 151, 164, 217, 153, 91,
  236. 154, 102, 102, 159, 75, 164, 152, 136, 51, 213, 219, 186, 116, 193, 224,
  237. 186, 36, 231, 208, 84, 211, 155, 167, 35, 59, 42, 76, 216, 149, 73,
  238. 201, 78, 149, 184, 100, 96, 196, 189, 198, 188, 235, 195, 117, 129, 120,
  239. 129, 49, 25, 133, 113, 69, 221, 114, 70, 143, 99, 157, 108, 189, 140,
  240. 78, 6, 55, 65, 240, 255, 245, 184, 72, 90, 100, 116, 131, 39, 60,
  241. 234, 167, 33, 160, 88, 185, 200, 157, 159, 176, 127, 151, 138, 102, 168,
  242. 106, 170, 86, 82, 219, 189, 76, 33, 115, 197, 106, 96, 198, 136, 97,
  243. 141, 237, 151, 98, 137, 191, 185, 2, 57, 95, 142, 91, 255, 185, 97,
  244. 137, 76, 162, 94, 173, 131, 193, 161, 81, 106, 72, 135, 222, 234, 137,
  245. 66, 137, 106, 243, 210, 147, 95, 15, 137, 110, 85, 66, 16, 96, 167,
  246. 147, 150, 173, 203, 140, 118, 196, 84, 147, 160, 19, 95, 101, 123, 74,
  247. 132, 202, 82, 166, 12, 131, 166, 189, 170, 159, 85, 79, 66, 57, 152,
  248. 132, 203, 194, 0, 1, 56, 146, 180, 224, 156, 28, 83, 181, 79, 76,
  249. 80, 46, 160, 175, 59, 106, 43, 87, 75, 136, 85, 189, 46, 71, 200,
  250. 90
  251. };
  252. ASM_REGISTER_STATE_CHECK(
  253. predict_(const_cast<uint8_t *>(kTestData) + kSrcStride * 2 + 2,
  254. kSrcStride, 2, 2, dst_, dst_stride_));
  255. ASSERT_TRUE(
  256. CompareBuffers(kExpectedDst, kExpectedDstStride, dst_, dst_stride_));
  257. }
  258. INSTANTIATE_TEST_CASE_P(
  259. C, SixtapPredictTest,
  260. ::testing::Values(make_tuple(16, 16, &vp8_sixtap_predict16x16_c),
  261. make_tuple(8, 8, &vp8_sixtap_predict8x8_c),
  262. make_tuple(8, 4, &vp8_sixtap_predict8x4_c),
  263. make_tuple(4, 4, &vp8_sixtap_predict4x4_c)));
  264. #if HAVE_NEON
  265. INSTANTIATE_TEST_CASE_P(
  266. NEON, SixtapPredictTest,
  267. ::testing::Values(make_tuple(16, 16, &vp8_sixtap_predict16x16_neon),
  268. make_tuple(8, 8, &vp8_sixtap_predict8x8_neon),
  269. make_tuple(8, 4, &vp8_sixtap_predict8x4_neon),
  270. make_tuple(4, 4, &vp8_sixtap_predict4x4_neon)));
  271. #endif
  272. #if HAVE_MMX
  273. INSTANTIATE_TEST_CASE_P(
  274. MMX, SixtapPredictTest,
  275. ::testing::Values(make_tuple(4, 4, &vp8_sixtap_predict4x4_mmx)));
  276. #endif
  277. #if HAVE_SSE2
  278. INSTANTIATE_TEST_CASE_P(
  279. SSE2, SixtapPredictTest,
  280. ::testing::Values(make_tuple(16, 16, &vp8_sixtap_predict16x16_sse2),
  281. make_tuple(8, 8, &vp8_sixtap_predict8x8_sse2),
  282. make_tuple(8, 4, &vp8_sixtap_predict8x4_sse2)));
  283. #endif
  284. #if HAVE_SSSE3
  285. INSTANTIATE_TEST_CASE_P(
  286. SSSE3, SixtapPredictTest,
  287. ::testing::Values(make_tuple(16, 16, &vp8_sixtap_predict16x16_ssse3),
  288. make_tuple(8, 8, &vp8_sixtap_predict8x8_ssse3),
  289. make_tuple(8, 4, &vp8_sixtap_predict8x4_ssse3),
  290. make_tuple(4, 4, &vp8_sixtap_predict4x4_ssse3)));
  291. #endif
  292. #if HAVE_MSA
  293. INSTANTIATE_TEST_CASE_P(
  294. MSA, SixtapPredictTest,
  295. ::testing::Values(make_tuple(16, 16, &vp8_sixtap_predict16x16_msa),
  296. make_tuple(8, 8, &vp8_sixtap_predict8x8_msa),
  297. make_tuple(8, 4, &vp8_sixtap_predict8x4_msa),
  298. make_tuple(4, 4, &vp8_sixtap_predict4x4_msa)));
  299. #endif
  300. #if HAVE_MMI
  301. INSTANTIATE_TEST_CASE_P(
  302. MMI, SixtapPredictTest,
  303. ::testing::Values(make_tuple(16, 16, &vp8_sixtap_predict16x16_mmi),
  304. make_tuple(8, 8, &vp8_sixtap_predict8x8_mmi),
  305. make_tuple(8, 4, &vp8_sixtap_predict8x4_mmi),
  306. make_tuple(4, 4, &vp8_sixtap_predict4x4_mmi)));
  307. #endif
  308. class BilinearPredictTest : public PredictTestBase {};
  309. TEST_P(BilinearPredictTest, TestWithRandomData) {
  310. TestWithRandomData(vp8_bilinear_predict16x16_c);
  311. }
  312. TEST_P(BilinearPredictTest, TestWithUnalignedDst) {
  313. TestWithUnalignedDst(vp8_bilinear_predict16x16_c);
  314. }
  315. TEST_P(BilinearPredictTest, DISABLED_Speed) {
  316. const int kCountSpeedTestBlock = 5000000 / (width_ * height_);
  317. RunNTimes(kCountSpeedTestBlock);
  318. char title[16];
  319. snprintf(title, sizeof(title), "%dx%d", width_, height_);
  320. PrintMedian(title);
  321. }
  322. INSTANTIATE_TEST_CASE_P(
  323. C, BilinearPredictTest,
  324. ::testing::Values(make_tuple(16, 16, &vp8_bilinear_predict16x16_c),
  325. make_tuple(8, 8, &vp8_bilinear_predict8x8_c),
  326. make_tuple(8, 4, &vp8_bilinear_predict8x4_c),
  327. make_tuple(4, 4, &vp8_bilinear_predict4x4_c)));
  328. #if HAVE_NEON
  329. INSTANTIATE_TEST_CASE_P(
  330. NEON, BilinearPredictTest,
  331. ::testing::Values(make_tuple(16, 16, &vp8_bilinear_predict16x16_neon),
  332. make_tuple(8, 8, &vp8_bilinear_predict8x8_neon),
  333. make_tuple(8, 4, &vp8_bilinear_predict8x4_neon),
  334. make_tuple(4, 4, &vp8_bilinear_predict4x4_neon)));
  335. #endif
  336. #if HAVE_SSE2
  337. INSTANTIATE_TEST_CASE_P(
  338. SSE2, BilinearPredictTest,
  339. ::testing::Values(make_tuple(16, 16, &vp8_bilinear_predict16x16_sse2),
  340. make_tuple(8, 8, &vp8_bilinear_predict8x8_sse2),
  341. make_tuple(8, 4, &vp8_bilinear_predict8x4_sse2),
  342. make_tuple(4, 4, &vp8_bilinear_predict4x4_sse2)));
  343. #endif
  344. #if HAVE_SSSE3
  345. INSTANTIATE_TEST_CASE_P(
  346. SSSE3, BilinearPredictTest,
  347. ::testing::Values(make_tuple(16, 16, &vp8_bilinear_predict16x16_ssse3),
  348. make_tuple(8, 8, &vp8_bilinear_predict8x8_ssse3)));
  349. #endif
  350. #if HAVE_MSA
  351. INSTANTIATE_TEST_CASE_P(
  352. MSA, BilinearPredictTest,
  353. ::testing::Values(make_tuple(16, 16, &vp8_bilinear_predict16x16_msa),
  354. make_tuple(8, 8, &vp8_bilinear_predict8x8_msa),
  355. make_tuple(8, 4, &vp8_bilinear_predict8x4_msa),
  356. make_tuple(4, 4, &vp8_bilinear_predict4x4_msa)));
  357. #endif
  358. } // namespace