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