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