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