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 <math.h>
12#include <stdlib.h>
13#include <string.h>
14#include "test/acm_random.h"
15#include "test/clear_system_state.h"
16#include "test/register_state_check.h"
17#include "test/util.h"
18#include "third_party/googletest/src/include/gtest/gtest.h"
19#include "./vpx_config.h"
20#include "./vp8_rtcd.h"
21#include "vpx/vpx_integer.h"
22#include "vpx_mem/vpx_mem.h"
23
24namespace {
25
26typedef void (*SixtapPredictFunc)(uint8_t *src_ptr,
27                                  int src_pixels_per_line,
28                                  int xoffset,
29                                  int yoffset,
30                                  uint8_t *dst_ptr,
31                                  int dst_pitch);
32
33typedef std::tr1::tuple<int, int, SixtapPredictFunc> SixtapPredictParam;
34
35class SixtapPredictTest
36    : public ::testing::TestWithParam<SixtapPredictParam> {
37 public:
38  static void SetUpTestCase() {
39    src_ = reinterpret_cast<uint8_t*>(vpx_memalign(kDataAlignment, kSrcSize));
40    dst_ = reinterpret_cast<uint8_t*>(vpx_memalign(kDataAlignment, kDstSize));
41    dst_c_ = reinterpret_cast<uint8_t*>(vpx_memalign(kDataAlignment, kDstSize));
42  }
43
44  static void TearDownTestCase() {
45    vpx_free(src_);
46    src_ = NULL;
47    vpx_free(dst_);
48    dst_ = NULL;
49    vpx_free(dst_c_);
50    dst_c_ = NULL;
51  }
52
53  virtual void TearDown() {
54    libvpx_test::ClearSystemState();
55  }
56
57 protected:
58  // Make test arrays big enough for 16x16 functions. Six-tap filters
59  // need 5 extra pixels outside of the macroblock.
60  static const int kSrcStride = 21;
61  static const int kDstStride = 16;
62  static const int kDataAlignment = 16;
63  static const int kSrcSize = kSrcStride * kSrcStride + 1;
64  static const int kDstSize = kDstStride * kDstStride;
65
66  virtual void SetUp() {
67    width_ = GET_PARAM(0);
68    height_ = GET_PARAM(1);
69    sixtap_predict_ = GET_PARAM(2);
70    memset(src_, 0, kSrcSize);
71    memset(dst_, 0, kDstSize);
72    memset(dst_c_, 0, kDstSize);
73  }
74
75  int width_;
76  int height_;
77  SixtapPredictFunc sixtap_predict_;
78  // The src stores the macroblock we will filter on, and makes it 1 byte larger
79  // in order to test unaligned access. The result is stored in dst and dst_c(c
80  // reference code result).
81  static uint8_t* src_;
82  static uint8_t* dst_;
83  static uint8_t* dst_c_;
84};
85
86uint8_t* SixtapPredictTest::src_ = NULL;
87uint8_t* SixtapPredictTest::dst_ = NULL;
88uint8_t* SixtapPredictTest::dst_c_ = NULL;
89
90TEST_P(SixtapPredictTest, TestWithPresetData) {
91  // Test input
92  static const uint8_t test_data[kSrcSize] = {
93    216, 184, 4, 191, 82, 92, 41, 0, 1, 226, 236, 172, 20, 182, 42, 226, 177,
94    79, 94, 77, 179, 203, 206, 198, 22, 192, 19, 75, 17, 192, 44, 233, 120,
95    48, 168, 203, 141, 210, 203, 143, 180, 184, 59, 201, 110, 102, 171, 32,
96    182, 10, 109, 105, 213, 60, 47, 236, 253, 67, 55, 14, 3, 99, 247, 124,
97    148, 159, 71, 34, 114, 19, 177, 38, 203, 237, 239, 58, 83, 155, 91, 10,
98    166, 201, 115, 124, 5, 163, 104, 2, 231, 160, 16, 234, 4, 8, 103, 153,
99    167, 174, 187, 26, 193, 109, 64, 141, 90, 48, 200, 174, 204, 36, 184,
100    114, 237, 43, 238, 242, 207, 86, 245, 182, 247, 6, 161, 251, 14, 8, 148,
101    182, 182, 79, 208, 120, 188, 17, 6, 23, 65, 206, 197, 13, 242, 126, 128,
102    224, 170, 110, 211, 121, 197, 200, 47, 188, 207, 208, 184, 221, 216, 76,
103    148, 143, 156, 100, 8, 89, 117, 14, 112, 183, 221, 54, 197, 208, 180, 69,
104    176, 94, 180, 131, 215, 121, 76, 7, 54, 28, 216, 238, 249, 176, 58, 142,
105    64, 215, 242, 72, 49, 104, 87, 161, 32, 52, 216, 230, 4, 141, 44, 181,
106    235, 224, 57, 195, 89, 134, 203, 144, 162, 163, 126, 156, 84, 185, 42,
107    148, 145, 29, 221, 194, 134, 52, 100, 166, 105, 60, 140, 110, 201, 184,
108    35, 181, 153, 93, 121, 243, 227, 68, 131, 134, 232, 2, 35, 60, 187, 77,
109    209, 76, 106, 174, 15, 241, 227, 115, 151, 77, 175, 36, 187, 121, 221,
110    223, 47, 118, 61, 168, 105, 32, 237, 236, 167, 213, 238, 202, 17, 170,
111    24, 226, 247, 131, 145, 6, 116, 117, 121, 11, 194, 41, 48, 126, 162, 13,
112    93, 209, 131, 154, 122, 237, 187, 103, 217, 99, 60, 200, 45, 78, 115, 69,
113    49, 106, 200, 194, 112, 60, 56, 234, 72, 251, 19, 120, 121, 182, 134, 215,
114    135, 10, 114, 2, 247, 46, 105, 209, 145, 165, 153, 191, 243, 12, 5, 36,
115    119, 206, 231, 231, 11, 32, 209, 83, 27, 229, 204, 149, 155, 83, 109, 35,
116    93, 223, 37, 84, 14, 142, 37, 160, 52, 191, 96, 40, 204, 101, 77, 67, 52,
117    53, 43, 63, 85, 253, 147, 113, 226, 96, 6, 125, 179, 115, 161, 17, 83,
118    198, 101, 98, 85, 139, 3, 137, 75, 99, 178, 23, 201, 255, 91, 253, 52,
119    134, 60, 138, 131, 208, 251, 101, 48, 2, 227, 228, 118, 132, 245, 202,
120    75, 91, 44, 160, 231, 47, 41, 50, 147, 220, 74, 92, 219, 165, 89, 16
121  };
122
123  // Expected result
124  static const uint8_t expected_dst[kDstSize] = {
125    117, 102, 74, 135, 42, 98, 175, 206, 70, 73, 222, 197, 50, 24, 39, 49, 38,
126    105, 90, 47, 169, 40, 171, 215, 200, 73, 109, 141, 53, 85, 177, 164, 79,
127    208, 124, 89, 212, 18, 81, 145, 151, 164, 217, 153, 91, 154, 102, 102,
128    159, 75, 164, 152, 136, 51, 213, 219, 186, 116, 193, 224, 186, 36, 231,
129    208, 84, 211, 155, 167, 35, 59, 42, 76, 216, 149, 73, 201, 78, 149, 184,
130    100, 96, 196, 189, 198, 188, 235, 195, 117, 129, 120, 129, 49, 25, 133,
131    113, 69, 221, 114, 70, 143, 99, 157, 108, 189, 140, 78, 6, 55, 65, 240,
132    255, 245, 184, 72, 90, 100, 116, 131, 39, 60, 234, 167, 33, 160, 88, 185,
133    200, 157, 159, 176, 127, 151, 138, 102, 168, 106, 170, 86, 82, 219, 189,
134    76, 33, 115, 197, 106, 96, 198, 136, 97, 141, 237, 151, 98, 137, 191,
135    185, 2, 57, 95, 142, 91, 255, 185, 97, 137, 76, 162, 94, 173, 131, 193,
136    161, 81, 106, 72, 135, 222, 234, 137, 66, 137, 106, 243, 210, 147, 95,
137    15, 137, 110, 85, 66, 16, 96, 167, 147, 150, 173, 203, 140, 118, 196,
138    84, 147, 160, 19, 95, 101, 123, 74, 132, 202, 82, 166, 12, 131, 166,
139    189, 170, 159, 85, 79, 66, 57, 152, 132, 203, 194, 0, 1, 56, 146, 180,
140    224, 156, 28, 83, 181, 79, 76, 80, 46, 160, 175, 59, 106, 43, 87, 75,
141    136, 85, 189, 46, 71, 200, 90
142  };
143
144  uint8_t *src = const_cast<uint8_t*>(test_data);
145
146  ASM_REGISTER_STATE_CHECK(
147      sixtap_predict_(&src[kSrcStride * 2 + 2 + 1], kSrcStride,
148                      2, 2, dst_, kDstStride));
149
150  for (int i = 0; i < height_; ++i)
151    for (int j = 0; j < width_; ++j)
152      ASSERT_EQ(expected_dst[i * kDstStride + j], dst_[i * kDstStride + j])
153          << "i==" << (i * width_ + j);
154}
155
156using libvpx_test::ACMRandom;
157
158TEST_P(SixtapPredictTest, TestWithRandomData) {
159  ACMRandom rnd(ACMRandom::DeterministicSeed());
160  for (int i = 0; i < kSrcSize; ++i)
161    src_[i] = rnd.Rand8();
162
163  // Run tests for all possible offsets.
164  for (int xoffset = 0; xoffset < 8; ++xoffset) {
165    for (int yoffset = 0; yoffset < 8; ++yoffset) {
166      // Call c reference function.
167      // Move start point to next pixel to test if the function reads
168      // unaligned data correctly.
169      vp8_sixtap_predict16x16_c(&src_[kSrcStride * 2 + 2 + 1], kSrcStride,
170                                xoffset, yoffset, dst_c_, kDstStride);
171
172      // Run test.
173      ASM_REGISTER_STATE_CHECK(
174          sixtap_predict_(&src_[kSrcStride * 2 + 2 + 1], kSrcStride,
175                          xoffset, yoffset, dst_, kDstStride));
176
177      for (int i = 0; i < height_; ++i)
178        for (int j = 0; j < width_; ++j)
179          ASSERT_EQ(dst_c_[i * kDstStride + j], dst_[i * kDstStride + j])
180              << "i==" << (i * width_ + j);
181    }
182  }
183}
184
185using std::tr1::make_tuple;
186
187const SixtapPredictFunc sixtap_16x16_c = vp8_sixtap_predict16x16_c;
188const SixtapPredictFunc sixtap_8x8_c = vp8_sixtap_predict8x8_c;
189const SixtapPredictFunc sixtap_8x4_c = vp8_sixtap_predict8x4_c;
190const SixtapPredictFunc sixtap_4x4_c = vp8_sixtap_predict4x4_c;
191INSTANTIATE_TEST_CASE_P(
192    C, SixtapPredictTest, ::testing::Values(
193        make_tuple(16, 16, sixtap_16x16_c),
194        make_tuple(8, 8, sixtap_8x8_c),
195        make_tuple(8, 4, sixtap_8x4_c),
196        make_tuple(4, 4, sixtap_4x4_c)));
197#if HAVE_NEON
198const SixtapPredictFunc sixtap_16x16_neon = vp8_sixtap_predict16x16_neon;
199const SixtapPredictFunc sixtap_8x8_neon = vp8_sixtap_predict8x8_neon;
200const SixtapPredictFunc sixtap_8x4_neon = vp8_sixtap_predict8x4_neon;
201INSTANTIATE_TEST_CASE_P(
202    DISABLED_NEON, SixtapPredictTest, ::testing::Values(
203        make_tuple(16, 16, sixtap_16x16_neon),
204        make_tuple(8, 8, sixtap_8x8_neon),
205        make_tuple(8, 4, sixtap_8x4_neon)));
206#endif
207#if HAVE_MMX
208const SixtapPredictFunc sixtap_16x16_mmx = vp8_sixtap_predict16x16_mmx;
209const SixtapPredictFunc sixtap_8x8_mmx = vp8_sixtap_predict8x8_mmx;
210const SixtapPredictFunc sixtap_8x4_mmx = vp8_sixtap_predict8x4_mmx;
211const SixtapPredictFunc sixtap_4x4_mmx = vp8_sixtap_predict4x4_mmx;
212INSTANTIATE_TEST_CASE_P(
213    MMX, SixtapPredictTest, ::testing::Values(
214        make_tuple(16, 16, sixtap_16x16_mmx),
215        make_tuple(8, 8, sixtap_8x8_mmx),
216        make_tuple(8, 4, sixtap_8x4_mmx),
217        make_tuple(4, 4, sixtap_4x4_mmx)));
218#endif
219#if HAVE_SSE2
220const SixtapPredictFunc sixtap_16x16_sse2 = vp8_sixtap_predict16x16_sse2;
221const SixtapPredictFunc sixtap_8x8_sse2 = vp8_sixtap_predict8x8_sse2;
222const SixtapPredictFunc sixtap_8x4_sse2 = vp8_sixtap_predict8x4_sse2;
223INSTANTIATE_TEST_CASE_P(
224    SSE2, SixtapPredictTest, ::testing::Values(
225        make_tuple(16, 16, sixtap_16x16_sse2),
226        make_tuple(8, 8, sixtap_8x8_sse2),
227        make_tuple(8, 4, sixtap_8x4_sse2)));
228#endif
229#if HAVE_SSSE3
230const SixtapPredictFunc sixtap_16x16_ssse3 = vp8_sixtap_predict16x16_ssse3;
231const SixtapPredictFunc sixtap_8x8_ssse3 = vp8_sixtap_predict8x8_ssse3;
232const SixtapPredictFunc sixtap_8x4_ssse3 = vp8_sixtap_predict8x4_ssse3;
233const SixtapPredictFunc sixtap_4x4_ssse3 = vp8_sixtap_predict4x4_ssse3;
234INSTANTIATE_TEST_CASE_P(
235    SSSE3, SixtapPredictTest, ::testing::Values(
236        make_tuple(16, 16, sixtap_16x16_ssse3),
237        make_tuple(8, 8, sixtap_8x8_ssse3),
238        make_tuple(8, 4, sixtap_8x4_ssse3),
239        make_tuple(4, 4, sixtap_4x4_ssse3)));
240#endif
241}  // namespace
242