]> granicus.if.org Git - libvpx/blob - test/hadamard_test.cc
neon hadamard 16x16
[libvpx] / test / hadamard_test.cc
1 /*
2  *  Copyright (c) 2016 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 <algorithm>
12
13 #include "third_party/googletest/src/include/gtest/gtest.h"
14
15 #include "./vpx_dsp_rtcd.h"
16
17 #include "test/acm_random.h"
18 #include "test/register_state_check.h"
19
20 namespace {
21
22 using ::libvpx_test::ACMRandom;
23
24 typedef void (*HadamardFunc)(const int16_t *a, int a_stride, int16_t *b);
25
26 void hadamard_loop(const int16_t *a, int a_stride, int16_t *out) {
27   int16_t b[8];
28   for (int i = 0; i < 8; i += 2) {
29     b[i + 0] = a[i * a_stride] + a[(i + 1) * a_stride];
30     b[i + 1] = a[i * a_stride] - a[(i + 1) * a_stride];
31   }
32   int16_t c[8];
33   for (int i = 0; i < 8; i += 4) {
34     c[i + 0] = b[i + 0] + b[i + 2];
35     c[i + 1] = b[i + 1] + b[i + 3];
36     c[i + 2] = b[i + 0] - b[i + 2];
37     c[i + 3] = b[i + 1] - b[i + 3];
38   }
39   out[0] = c[0] + c[4];
40   out[7] = c[1] + c[5];
41   out[3] = c[2] + c[6];
42   out[4] = c[3] + c[7];
43   out[2] = c[0] - c[4];
44   out[6] = c[1] - c[5];
45   out[1] = c[2] - c[6];
46   out[5] = c[3] - c[7];
47 }
48
49 void reference_hadamard8x8(const int16_t *a, int a_stride, int16_t *b) {
50   int16_t buf[64];
51   for (int i = 0; i < 8; ++i) {
52     hadamard_loop(a + i, a_stride, buf + i * 8);
53   }
54
55   for (int i = 0; i < 8; ++i) {
56     hadamard_loop(buf + i, 8, b + i * 8);
57   }
58 }
59
60 void reference_hadamard16x16(const int16_t *a, int a_stride, int16_t *b) {
61   /* The source is a 16x16 block. The destination is rearranged to 8x32.
62    * Input is 9 bit. */
63   reference_hadamard8x8(a + 0 + 0 * a_stride, a_stride, b + 0);
64   reference_hadamard8x8(a + 8 + 0 * a_stride, a_stride, b + 64);
65   reference_hadamard8x8(a + 0 + 8 * a_stride, a_stride, b + 128);
66   reference_hadamard8x8(a + 8 + 8 * a_stride, a_stride, b + 192);
67
68   /* Overlay the 8x8 blocks and combine. */
69   for (int i = 0; i < 64; ++i) {
70     /* 8x8 steps the range up to 15 bits. */
71     const int16_t a0 = b[0];
72     const int16_t a1 = b[64];
73     const int16_t a2 = b[128];
74     const int16_t a3 = b[192];
75
76     /* Prevent the result from escaping int16_t. */
77     const int16_t b0 = (a0 + a1) >> 1;
78     const int16_t b1 = (a0 - a1) >> 1;
79     const int16_t b2 = (a2 + a3) >> 1;
80     const int16_t b3 = (a2 - a3) >> 1;
81
82     /* Store a 16 bit value. */
83     b[  0] = b0 + b2;
84     b[ 64] = b1 + b3;
85     b[128] = b0 - b2;
86     b[192] = b1 - b3;
87
88     ++b;
89   }
90 }
91
92 class HadamardTestBase : public ::testing::TestWithParam<HadamardFunc> {
93  public:
94   virtual void SetUp() {
95     h_func_ = GetParam();
96     rnd_.Reset(ACMRandom::DeterministicSeed());
97   }
98
99  protected:
100   HadamardFunc h_func_;
101   ACMRandom rnd_;
102 };
103
104 class Hadamard8x8Test : public HadamardTestBase {};
105
106 TEST_P(Hadamard8x8Test, CompareReferenceRandom) {
107   DECLARE_ALIGNED(16, int16_t, a[64]);
108   DECLARE_ALIGNED(16, int16_t, b[64]);
109   int16_t b_ref[64];
110   for (int i = 0; i < 64; ++i) {
111     a[i] = rnd_.Rand9Signed();
112   }
113   memset(b, 0, sizeof(b));
114   memset(b_ref, 0, sizeof(b_ref));
115
116   reference_hadamard8x8(a, 8, b_ref);
117   ASM_REGISTER_STATE_CHECK(h_func_(a, 8, b));
118
119   // The order of the output is not important. Sort before checking.
120   std::sort(b, b + 64);
121   std::sort(b_ref, b_ref + 64);
122   EXPECT_EQ(0, memcmp(b, b_ref, sizeof(b)));
123 }
124
125 TEST_P(Hadamard8x8Test, VaryStride) {
126   DECLARE_ALIGNED(16, int16_t, a[64 * 8]);
127   DECLARE_ALIGNED(16, int16_t, b[64]);
128   int16_t b_ref[64];
129   for (int i = 0; i < 64 * 8; ++i) {
130     a[i] = rnd_.Rand9Signed();
131   }
132
133   for (int i = 8; i < 64; i += 8) {
134     memset(b, 0, sizeof(b));
135     memset(b_ref, 0, sizeof(b_ref));
136
137     reference_hadamard8x8(a, i, b_ref);
138     ASM_REGISTER_STATE_CHECK(h_func_(a, i, b));
139
140     // The order of the output is not important. Sort before checking.
141     std::sort(b, b + 64);
142     std::sort(b_ref, b_ref + 64);
143     EXPECT_EQ(0, memcmp(b, b_ref, sizeof(b)));
144   }
145 }
146
147 INSTANTIATE_TEST_CASE_P(C, Hadamard8x8Test,
148                         ::testing::Values(&vpx_hadamard_8x8_c));
149
150 #if HAVE_SSE2
151 INSTANTIATE_TEST_CASE_P(SSE2, Hadamard8x8Test,
152                         ::testing::Values(&vpx_hadamard_8x8_sse2));
153 #endif  // HAVE_SSE2
154
155 #if HAVE_SSSE3 && CONFIG_USE_X86INC && ARCH_X86_64
156 INSTANTIATE_TEST_CASE_P(SSSE3, Hadamard8x8Test,
157                         ::testing::Values(&vpx_hadamard_8x8_ssse3));
158 #endif  // HAVE_SSSE3 && CONFIG_USE_X86INC && ARCH_X86_64
159
160 #if HAVE_NEON
161 INSTANTIATE_TEST_CASE_P(NEON, Hadamard8x8Test,
162                         ::testing::Values(&vpx_hadamard_8x8_neon));
163 #endif  // HAVE_NEON
164
165 class Hadamard16x16Test : public HadamardTestBase {};
166
167 TEST_P(Hadamard16x16Test, CompareReferenceRandom) {
168   DECLARE_ALIGNED(16, int16_t, a[16 * 16]);
169   DECLARE_ALIGNED(16, int16_t, b[16 * 16]);
170   int16_t b_ref[16 * 16];
171   for (int i = 0; i < 16 * 16; ++i) {
172     a[i] = rnd_.Rand9Signed();
173   }
174   memset(b, 0, sizeof(b));
175   memset(b_ref, 0, sizeof(b_ref));
176
177   reference_hadamard16x16(a, 16, b_ref);
178   ASM_REGISTER_STATE_CHECK(h_func_(a, 16, b));
179
180   // The order of the output is not important. Sort before checking.
181   std::sort(b, b + 16 * 16);
182   std::sort(b_ref, b_ref + 16 * 16);
183   EXPECT_EQ(0, memcmp(b, b_ref, sizeof(b)));
184 }
185
186 TEST_P(Hadamard16x16Test, VaryStride) {
187   DECLARE_ALIGNED(16, int16_t, a[16 * 16 * 8]);
188   DECLARE_ALIGNED(16, int16_t, b[16 * 16]);
189   int16_t b_ref[16 * 16];
190   for (int i = 0; i < 16 * 16 * 8; ++i) {
191     a[i] = rnd_.Rand9Signed();
192   }
193
194   for (int i = 8; i < 64; i += 8) {
195     memset(b, 0, sizeof(b));
196     memset(b_ref, 0, sizeof(b_ref));
197
198     reference_hadamard16x16(a, i, b_ref);
199     ASM_REGISTER_STATE_CHECK(h_func_(a, i, b));
200
201     // The order of the output is not important. Sort before checking.
202     std::sort(b, b + 16 * 16);
203     std::sort(b_ref, b_ref + 16 * 16);
204     EXPECT_EQ(0, memcmp(b, b_ref, sizeof(b)));
205   }
206 }
207
208 INSTANTIATE_TEST_CASE_P(C, Hadamard16x16Test,
209                         ::testing::Values(&vpx_hadamard_16x16_c));
210
211 #if HAVE_SSE2
212 INSTANTIATE_TEST_CASE_P(SSE2, Hadamard16x16Test,
213                         ::testing::Values(&vpx_hadamard_16x16_sse2));
214 #endif  // HAVE_SSE2
215
216 #if HAVE_NEON
217 INSTANTIATE_TEST_CASE_P(NEON, Hadamard16x16Test,
218                         ::testing::Values(&vpx_hadamard_16x16_neon));
219 #endif  // HAVE_NEON
220 }  // namespace