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