2 * Copyright (c) 2013 The WebM project authors. All Rights Reserved.
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.
15 #include "third_party/googletest/src/include/gtest/gtest.h"
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"
30 using libvpx_test::ACMRandom;
31 using std::make_tuple;
33 typedef void (*PredictFunc)(uint8_t *src_ptr, int src_pixels_per_line,
34 int xoffset, int yoffset, uint8_t *dst_ptr,
37 typedef std::tuple<int, int, PredictFunc> PredictParam;
39 class PredictTestBase : public AbstractBench,
40 public ::testing::TestWithParam<PredictParam> {
43 : width_(GET_PARAM(0)), height_(GET_PARAM(1)), predict_(GET_PARAM(2)),
44 src_(nullptr), padded_dst_(nullptr), dst_(nullptr), dst_c_(nullptr) {}
46 virtual void SetUp() {
47 src_ = new uint8_t[kSrcSize];
48 ASSERT_NE(src_, nullptr);
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);
55 reinterpret_cast<uint8_t *>(vpx_memalign(16, padded_dst_size_));
56 ASSERT_NE(padded_dst_, nullptr);
57 dst_ = padded_dst_ + (kBorderSize * dst_stride_) + kBorderSize;
59 dst_c_ = new uint8_t[16 * 16];
60 ASSERT_NE(dst_c_, nullptr);
62 memset(src_, 0, kSrcSize);
63 memset(padded_dst_, 128, padded_dst_size_);
64 memset(dst_c_, 0, 16 * 16);
67 virtual void TearDown() {
70 vpx_free(padded_dst_);
71 padded_dst_ = nullptr;
75 libvpx_test::ClearSystemState();
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;
95 bool CompareBuffers(const uint8_t *a, int a_stride, const uint8_t *b,
97 for (int height = 0; height < height_; ++height) {
98 EXPECT_EQ(0, memcmp(a + height * a_stride, b + height * b_stride,
100 << "Row " << height << " does not match.";
103 return !HasFailure();
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'.
109 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);
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'";
121 for (int pixel = 0; pixel < b - a - left_border; ++pixel) {
122 EXPECT_EQ(c, a[pixel]) << "Mismatch at " << pixel << " in top 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.";
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.";
144 for (int pixel = static_cast<int>(b - a + b_size); pixel < a_size;
146 EXPECT_EQ(c, a[pixel]) << "Mismatch at " << pixel << " in bottom border.";
149 return !HasFailure();
152 void TestWithRandomData(PredictFunc reference) {
153 ACMRandom rnd(ACMRandom::DeterministicSeed());
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
164 for (int i = 0; i < kSrcSize; ++i) {
165 src_[i] = rnd.Rand8();
167 reference(&src_[kSrcStride * 2 + 2], kSrcStride, xoffset, yoffset,
170 ASM_REGISTER_STATE_CHECK(predict_(&src_[kSrcStride * 2 + 2], kSrcStride,
171 xoffset, yoffset, dst_, dst_stride_));
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));
180 void TestWithUnalignedDst(PredictFunc reference) {
181 ACMRandom rnd(ACMRandom::DeterministicSeed());
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) {
190 for (int i = 0; i < kSrcSize; ++i) {
191 src_[i] = rnd.Rand8();
193 reference(&src_[kSrcStride * 2 + 2], kSrcStride, xoffset, yoffset,
196 for (int i = 1; i < 4; ++i) {
197 memset(padded_dst_, 128, padded_dst_size_);
199 ASM_REGISTER_STATE_CHECK(predict_(&src_[kSrcStride * 2 + 2],
200 kSrcStride, xoffset, yoffset,
201 dst_ + i, dst_stride_ + i));
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));
213 for (int xoffset = 0; xoffset < 8; ++xoffset) {
214 for (int yoffset = 0; yoffset < 8; ++yoffset) {
215 if (xoffset == 0 && yoffset == 0) {
219 predict_(&src_[kSrcStride * 2 + 2], kSrcStride, xoffset, yoffset, dst_,
226 class SixtapPredictTest : public PredictTestBase {};
228 TEST_P(SixtapPredictTest, TestWithRandomData) {
229 TestWithRandomData(vp8_sixtap_predict16x16_c);
231 TEST_P(SixtapPredictTest, TestWithUnalignedDst) {
232 TestWithUnalignedDst(vp8_sixtap_predict16x16_c);
235 TEST_P(SixtapPredictTest, TestWithPresetData) {
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
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,
293 ASM_REGISTER_STATE_CHECK(
294 predict_(const_cast<uint8_t *>(kTestData) + kSrcStride * 2 + 2,
295 kSrcStride, 2, 2, dst_, dst_stride_));
298 CompareBuffers(kExpectedDst, kExpectedDstStride, dst_, dst_stride_));
301 INSTANTIATE_TEST_SUITE_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)));
308 INSTANTIATE_TEST_SUITE_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)));
316 INSTANTIATE_TEST_SUITE_P(
317 MMX, SixtapPredictTest,
318 ::testing::Values(make_tuple(4, 4, &vp8_sixtap_predict4x4_mmx)));
321 INSTANTIATE_TEST_SUITE_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)));
328 INSTANTIATE_TEST_SUITE_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)));
336 INSTANTIATE_TEST_SUITE_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)));
345 INSTANTIATE_TEST_SUITE_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)));
353 class BilinearPredictTest : public PredictTestBase {};
355 TEST_P(BilinearPredictTest, TestWithRandomData) {
356 TestWithRandomData(vp8_bilinear_predict16x16_c);
358 TEST_P(BilinearPredictTest, TestWithUnalignedDst) {
359 TestWithUnalignedDst(vp8_bilinear_predict16x16_c);
361 TEST_P(BilinearPredictTest, DISABLED_Speed) {
362 const int kCountSpeedTestBlock = 5000000 / (width_ * height_);
363 RunNTimes(kCountSpeedTestBlock);
366 snprintf(title, sizeof(title), "%dx%d", width_, height_);
370 INSTANTIATE_TEST_SUITE_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)));
377 INSTANTIATE_TEST_SUITE_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)));
385 INSTANTIATE_TEST_SUITE_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)));
393 INSTANTIATE_TEST_SUITE_P(
394 SSSE3, BilinearPredictTest,
395 ::testing::Values(make_tuple(16, 16, &vp8_bilinear_predict16x16_ssse3),
396 make_tuple(8, 8, &vp8_bilinear_predict8x8_ssse3)));
399 INSTANTIATE_TEST_SUITE_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)));