OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2012 The WebM project authors. All Rights Reserved. | 2 * Copyright (c) 2012 The WebM project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
11 #include <math.h> | 11 #include <math.h> |
12 #include <stdlib.h> | 12 #include <stdlib.h> |
13 #include <string.h> | 13 #include <string.h> |
14 | 14 |
15 #include "third_party/googletest/src/include/gtest/gtest.h" | 15 #include "third_party/googletest/src/include/gtest/gtest.h" |
16 #include "test/acm_random.h" | 16 #include "test/acm_random.h" |
17 #include "test/clear_system_state.h" | 17 #include "test/clear_system_state.h" |
18 #include "test/register_state_check.h" | 18 #include "test/register_state_check.h" |
19 #include "test/util.h" | 19 #include "test/util.h" |
20 | 20 |
21 #include "./vp9_rtcd.h" | 21 #include "./vp9_rtcd.h" |
22 #include "vp9/common/vp9_entropy.h" | 22 #include "vp9/common/vp9_entropy.h" |
| 23 #include "vpx/vpx_codec.h" |
23 #include "vpx/vpx_integer.h" | 24 #include "vpx/vpx_integer.h" |
24 | 25 |
25 extern "C" { | 26 const int kNumCoeffs = 64; |
26 void vp9_idct8x8_64_add_c(const int16_t *input, uint8_t *output, int pitch); | 27 const double kPi = 3.141592653589793238462643383279502884; |
| 28 void reference_8x8_dct_1d(const double in[8], double out[8], int stride) { |
| 29 const double kInvSqrt2 = 0.707106781186547524400844362104; |
| 30 for (int k = 0; k < 8; k++) { |
| 31 out[k] = 0.0; |
| 32 for (int n = 0; n < 8; n++) |
| 33 out[k] += in[n] * cos(kPi * (2 * n + 1) * k / 16.0); |
| 34 if (k == 0) |
| 35 out[k] = out[k] * kInvSqrt2; |
| 36 } |
| 37 } |
| 38 |
| 39 void reference_8x8_dct_2d(const int16_t input[kNumCoeffs], |
| 40 double output[kNumCoeffs]) { |
| 41 // First transform columns |
| 42 for (int i = 0; i < 8; ++i) { |
| 43 double temp_in[8], temp_out[8]; |
| 44 for (int j = 0; j < 8; ++j) |
| 45 temp_in[j] = input[j*8 + i]; |
| 46 reference_8x8_dct_1d(temp_in, temp_out, 1); |
| 47 for (int j = 0; j < 8; ++j) |
| 48 output[j * 8 + i] = temp_out[j]; |
| 49 } |
| 50 // Then transform rows |
| 51 for (int i = 0; i < 8; ++i) { |
| 52 double temp_in[8], temp_out[8]; |
| 53 for (int j = 0; j < 8; ++j) |
| 54 temp_in[j] = output[j + i*8]; |
| 55 reference_8x8_dct_1d(temp_in, temp_out, 1); |
| 56 // Scale by some magic number |
| 57 for (int j = 0; j < 8; ++j) |
| 58 output[j + i * 8] = temp_out[j] * 2; |
| 59 } |
27 } | 60 } |
28 | 61 |
29 using libvpx_test::ACMRandom; | 62 using libvpx_test::ACMRandom; |
30 | 63 |
31 namespace { | 64 namespace { |
32 typedef void (*FdctFunc)(const int16_t *in, int16_t *out, int stride); | 65 typedef void (*FdctFunc)(const int16_t *in, tran_low_t *out, int stride); |
33 typedef void (*IdctFunc)(const int16_t *in, uint8_t *out, int stride); | 66 typedef void (*IdctFunc)(const tran_low_t *in, uint8_t *out, int stride); |
34 typedef void (*FhtFunc)(const int16_t *in, int16_t *out, int stride, | 67 typedef void (*FhtFunc)(const int16_t *in, tran_low_t *out, int stride, |
35 int tx_type); | 68 int tx_type); |
36 typedef void (*IhtFunc)(const int16_t *in, uint8_t *out, int stride, | 69 typedef void (*IhtFunc)(const tran_low_t *in, uint8_t *out, int stride, |
37 int tx_type); | 70 int tx_type); |
38 | 71 |
39 typedef std::tr1::tuple<FdctFunc, IdctFunc, int> Dct8x8Param; | 72 typedef std::tr1::tuple<FdctFunc, IdctFunc, int, vpx_bit_depth_t> Dct8x8Param; |
40 typedef std::tr1::tuple<FhtFunc, IhtFunc, int> Ht8x8Param; | 73 typedef std::tr1::tuple<FhtFunc, IhtFunc, int, vpx_bit_depth_t> Ht8x8Param; |
41 | 74 |
42 void fdct8x8_ref(const int16_t *in, int16_t *out, int stride, int /*tx_type*/) { | 75 void fdct8x8_ref(const int16_t *in, tran_low_t *out, int stride, int tx_type) { |
43 vp9_fdct8x8_c(in, out, stride); | 76 vp9_fdct8x8_c(in, out, stride); |
44 } | 77 } |
45 | 78 |
46 void fht8x8_ref(const int16_t *in, int16_t *out, int stride, int tx_type) { | 79 void fht8x8_ref(const int16_t *in, tran_low_t *out, int stride, int tx_type) { |
47 vp9_fht8x8_c(in, out, stride, tx_type); | 80 vp9_fht8x8_c(in, out, stride, tx_type); |
48 } | 81 } |
49 | 82 |
| 83 #if CONFIG_VP9_HIGHBITDEPTH |
| 84 void idct8x8_10(const tran_low_t *in, uint8_t *out, int stride) { |
| 85 vp9_high_idct8x8_64_add_c(in, out, stride, 10); |
| 86 } |
| 87 |
| 88 void idct8x8_12(const tran_low_t *in, uint8_t *out, int stride) { |
| 89 vp9_high_idct8x8_64_add_c(in, out, stride, 12); |
| 90 } |
| 91 |
| 92 void iht8x8_10(const tran_low_t *in, uint8_t *out, int stride, int tx_type) { |
| 93 vp9_high_iht8x8_64_add_c(in, out, stride, tx_type, 10); |
| 94 } |
| 95 |
| 96 void iht8x8_12(const tran_low_t *in, uint8_t *out, int stride, int tx_type) { |
| 97 vp9_high_iht8x8_64_add_c(in, out, stride, tx_type, 12); |
| 98 } |
| 99 #endif |
| 100 |
50 class FwdTrans8x8TestBase { | 101 class FwdTrans8x8TestBase { |
51 public: | 102 public: |
52 virtual ~FwdTrans8x8TestBase() {} | 103 virtual ~FwdTrans8x8TestBase() {} |
53 | 104 |
54 protected: | 105 protected: |
55 virtual void RunFwdTxfm(int16_t *in, int16_t *out, int stride) = 0; | 106 virtual void RunFwdTxfm(int16_t *in, tran_low_t *out, int stride) = 0; |
56 virtual void RunInvTxfm(int16_t *out, uint8_t *dst, int stride) = 0; | 107 virtual void RunInvTxfm(tran_low_t *out, uint8_t *dst, int stride) = 0; |
57 | 108 |
58 void RunSignBiasCheck() { | 109 void RunSignBiasCheck() { |
59 ACMRandom rnd(ACMRandom::DeterministicSeed()); | 110 ACMRandom rnd(ACMRandom::DeterministicSeed()); |
60 DECLARE_ALIGNED_ARRAY(16, int16_t, test_input_block, 64); | 111 DECLARE_ALIGNED_ARRAY(16, int16_t, test_input_block, 64); |
61 DECLARE_ALIGNED_ARRAY(16, int16_t, test_output_block, 64); | 112 DECLARE_ALIGNED_ARRAY(16, tran_low_t, test_output_block, 64); |
62 int count_sign_block[64][2]; | 113 int count_sign_block[64][2]; |
63 const int count_test_block = 100000; | 114 const int count_test_block = 100000; |
64 | 115 |
65 memset(count_sign_block, 0, sizeof(count_sign_block)); | 116 memset(count_sign_block, 0, sizeof(count_sign_block)); |
66 | 117 |
67 for (int i = 0; i < count_test_block; ++i) { | 118 for (int i = 0; i < count_test_block; ++i) { |
68 // Initialize a test block with input range [-255, 255]. | 119 // Initialize a test block with input range [-255, 255]. |
69 for (int j = 0; j < 64; ++j) | 120 for (int j = 0; j < 64; ++j) |
70 test_input_block[j] = rnd.Rand8() - rnd.Rand8(); | 121 test_input_block[j] = ((rnd.Rand16() >> (16 - bit_depth_)) & mask_) - |
| 122 ((rnd.Rand16() >> (16 - bit_depth_)) & mask_); |
71 ASM_REGISTER_STATE_CHECK( | 123 ASM_REGISTER_STATE_CHECK( |
72 RunFwdTxfm(test_input_block, test_output_block, pitch_)); | 124 RunFwdTxfm(test_input_block, test_output_block, pitch_)); |
73 | 125 |
74 for (int j = 0; j < 64; ++j) { | 126 for (int j = 0; j < 64; ++j) { |
75 if (test_output_block[j] < 0) | 127 if (test_output_block[j] < 0) |
76 ++count_sign_block[j][0]; | 128 ++count_sign_block[j][0]; |
77 else if (test_output_block[j] > 0) | 129 else if (test_output_block[j] > 0) |
78 ++count_sign_block[j][1]; | 130 ++count_sign_block[j][1]; |
79 } | 131 } |
80 } | 132 } |
81 | 133 |
82 for (int j = 0; j < 64; ++j) { | 134 for (int j = 0; j < 64; ++j) { |
83 const int diff = abs(count_sign_block[j][0] - count_sign_block[j][1]); | 135 const int diff = abs(count_sign_block[j][0] - count_sign_block[j][1]); |
84 const int max_diff = 1125; | 136 const int max_diff = 1125; |
85 EXPECT_LT(diff, max_diff) | 137 EXPECT_LT(diff, max_diff << (bit_depth_ - 8)) |
86 << "Error: 8x8 FDCT/FHT has a sign bias > " | 138 << "Error: 8x8 FDCT/FHT has a sign bias > " |
87 << 1. * max_diff / count_test_block * 100 << "%" | 139 << 1. * max_diff / count_test_block * 100 << "%" |
88 << " for input range [-255, 255] at index " << j | 140 << " for input range [-255, 255] at index " << j |
89 << " count0: " << count_sign_block[j][0] | 141 << " count0: " << count_sign_block[j][0] |
90 << " count1: " << count_sign_block[j][1] | 142 << " count1: " << count_sign_block[j][1] |
91 << " diff: " << diff; | 143 << " diff: " << diff; |
92 } | 144 } |
93 | 145 |
94 memset(count_sign_block, 0, sizeof(count_sign_block)); | 146 memset(count_sign_block, 0, sizeof(count_sign_block)); |
95 | 147 |
96 for (int i = 0; i < count_test_block; ++i) { | 148 for (int i = 0; i < count_test_block; ++i) { |
97 // Initialize a test block with input range [-15, 15]. | 149 // Initialize a test block with input range [-15, 15]. |
98 for (int j = 0; j < 64; ++j) | 150 for (int j = 0; j < 64; ++j) |
99 test_input_block[j] = (rnd.Rand8() >> 4) - (rnd.Rand8() >> 4); | 151 test_input_block[j] = (rnd.Rand8() >> 4) - (rnd.Rand8() >> 4); |
100 ASM_REGISTER_STATE_CHECK( | 152 ASM_REGISTER_STATE_CHECK( |
101 RunFwdTxfm(test_input_block, test_output_block, pitch_)); | 153 RunFwdTxfm(test_input_block, test_output_block, pitch_)); |
102 | 154 |
103 for (int j = 0; j < 64; ++j) { | 155 for (int j = 0; j < 64; ++j) { |
104 if (test_output_block[j] < 0) | 156 if (test_output_block[j] < 0) |
105 ++count_sign_block[j][0]; | 157 ++count_sign_block[j][0]; |
106 else if (test_output_block[j] > 0) | 158 else if (test_output_block[j] > 0) |
107 ++count_sign_block[j][1]; | 159 ++count_sign_block[j][1]; |
108 } | 160 } |
109 } | 161 } |
110 | 162 |
111 for (int j = 0; j < 64; ++j) { | 163 for (int j = 0; j < 64; ++j) { |
112 const int diff = abs(count_sign_block[j][0] - count_sign_block[j][1]); | 164 const int diff = abs(count_sign_block[j][0] - count_sign_block[j][1]); |
113 const int max_diff = 10000; | 165 const int max_diff = 10000; |
114 EXPECT_LT(diff, max_diff) | 166 EXPECT_LT(diff, max_diff << (bit_depth_ - 8)) |
115 << "Error: 4x4 FDCT/FHT has a sign bias > " | 167 << "Error: 4x4 FDCT/FHT has a sign bias > " |
116 << 1. * max_diff / count_test_block * 100 << "%" | 168 << 1. * max_diff / count_test_block * 100 << "%" |
117 << " for input range [-15, 15] at index " << j | 169 << " for input range [-15, 15] at index " << j |
118 << " count0: " << count_sign_block[j][0] | 170 << " count0: " << count_sign_block[j][0] |
119 << " count1: " << count_sign_block[j][1] | 171 << " count1: " << count_sign_block[j][1] |
120 << " diff: " << diff; | 172 << " diff: " << diff; |
121 } | 173 } |
122 } | 174 } |
123 | 175 |
124 void RunRoundTripErrorCheck() { | 176 void RunRoundTripErrorCheck() { |
125 ACMRandom rnd(ACMRandom::DeterministicSeed()); | 177 ACMRandom rnd(ACMRandom::DeterministicSeed()); |
126 int max_error = 0; | 178 int max_error = 0; |
127 int total_error = 0; | 179 int total_error = 0; |
128 const int count_test_block = 100000; | 180 const int count_test_block = 100000; |
129 DECLARE_ALIGNED_ARRAY(16, int16_t, test_input_block, 64); | 181 DECLARE_ALIGNED_ARRAY(16, int16_t, test_input_block, 64); |
130 DECLARE_ALIGNED_ARRAY(16, int16_t, test_temp_block, 64); | 182 DECLARE_ALIGNED_ARRAY(16, tran_low_t, test_temp_block, 64); |
131 DECLARE_ALIGNED_ARRAY(16, uint8_t, dst, 64); | 183 DECLARE_ALIGNED_ARRAY(16, uint8_t, dst, 64); |
132 DECLARE_ALIGNED_ARRAY(16, uint8_t, src, 64); | 184 DECLARE_ALIGNED_ARRAY(16, uint8_t, src, 64); |
| 185 #if CONFIG_VP9_HIGHBITDEPTH |
| 186 DECLARE_ALIGNED_ARRAY(16, uint16_t, dst16, 64); |
| 187 DECLARE_ALIGNED_ARRAY(16, uint16_t, src16, 64); |
| 188 #endif |
133 | 189 |
134 for (int i = 0; i < count_test_block; ++i) { | 190 for (int i = 0; i < count_test_block; ++i) { |
135 // Initialize a test block with input range [-255, 255]. | 191 // Initialize a test block with input range [-255, 255]. |
136 for (int j = 0; j < 64; ++j) { | 192 for (int j = 0; j < 64; ++j) { |
137 src[j] = rnd.Rand8(); | 193 if (bit_depth_ == VPX_BITS_8) { |
138 dst[j] = rnd.Rand8(); | 194 src[j] = rnd.Rand8(); |
139 test_input_block[j] = src[j] - dst[j]; | 195 dst[j] = rnd.Rand8(); |
| 196 test_input_block[j] = src[j] - dst[j]; |
| 197 #if CONFIG_VP9_HIGHBITDEPTH |
| 198 } else { |
| 199 src16[j] = rnd.Rand16() & mask_; |
| 200 dst16[j] = rnd.Rand16() & mask_; |
| 201 test_input_block[j] = src16[j] - dst16[j]; |
| 202 #endif |
| 203 } |
140 } | 204 } |
141 | 205 |
142 ASM_REGISTER_STATE_CHECK( | 206 ASM_REGISTER_STATE_CHECK( |
143 RunFwdTxfm(test_input_block, test_temp_block, pitch_)); | 207 RunFwdTxfm(test_input_block, test_temp_block, pitch_)); |
144 for (int j = 0; j < 64; ++j) { | 208 for (int j = 0; j < 64; ++j) { |
145 if (test_temp_block[j] > 0) { | 209 if (test_temp_block[j] > 0) { |
146 test_temp_block[j] += 2; | 210 test_temp_block[j] += 2; |
147 test_temp_block[j] /= 4; | 211 test_temp_block[j] /= 4; |
148 test_temp_block[j] *= 4; | 212 test_temp_block[j] *= 4; |
149 } else { | 213 } else { |
150 test_temp_block[j] -= 2; | 214 test_temp_block[j] -= 2; |
151 test_temp_block[j] /= 4; | 215 test_temp_block[j] /= 4; |
152 test_temp_block[j] *= 4; | 216 test_temp_block[j] *= 4; |
153 } | 217 } |
154 } | 218 } |
155 ASM_REGISTER_STATE_CHECK( | 219 if (bit_depth_ == VPX_BITS_8) { |
156 RunInvTxfm(test_temp_block, dst, pitch_)); | 220 ASM_REGISTER_STATE_CHECK( |
| 221 RunInvTxfm(test_temp_block, dst, pitch_)); |
| 222 #if CONFIG_VP9_HIGHBITDEPTH |
| 223 } else { |
| 224 ASM_REGISTER_STATE_CHECK( |
| 225 RunInvTxfm(test_temp_block, CONVERT_TO_BYTEPTR(dst16), pitch_)); |
| 226 #endif |
| 227 } |
157 | 228 |
158 for (int j = 0; j < 64; ++j) { | 229 for (int j = 0; j < 64; ++j) { |
| 230 #if CONFIG_VP9_HIGHBITDEPTH |
| 231 const int diff = |
| 232 bit_depth_ == VPX_BITS_8 ? dst[j] - src[j] : dst16[j] - src16[j]; |
| 233 #else |
159 const int diff = dst[j] - src[j]; | 234 const int diff = dst[j] - src[j]; |
| 235 #endif |
160 const int error = diff * diff; | 236 const int error = diff * diff; |
161 if (max_error < error) | 237 if (max_error < error) |
162 max_error = error; | 238 max_error = error; |
163 total_error += error; | 239 total_error += error; |
164 } | 240 } |
165 } | 241 } |
166 | 242 |
167 EXPECT_GE(1, max_error) | 243 EXPECT_GE(1 << 2 * (bit_depth_ - 8), max_error) |
168 << "Error: 8x8 FDCT/IDCT or FHT/IHT has an individual" | 244 << "Error: 8x8 FDCT/IDCT or FHT/IHT has an individual" |
169 << " roundtrip error > 1"; | 245 << " roundtrip error > 1"; |
170 | 246 |
171 EXPECT_GE(count_test_block/5, total_error) | 247 EXPECT_GE((count_test_block << 2 * (bit_depth_ - 8))/5, total_error) |
172 << "Error: 8x8 FDCT/IDCT or FHT/IHT has average roundtrip " | 248 << "Error: 8x8 FDCT/IDCT or FHT/IHT has average roundtrip " |
173 << "error > 1/5 per block"; | 249 << "error > 1/5 per block"; |
174 } | 250 } |
175 | 251 |
176 void RunExtremalCheck() { | 252 void RunExtremalCheck() { |
177 ACMRandom rnd(ACMRandom::DeterministicSeed()); | 253 ACMRandom rnd(ACMRandom::DeterministicSeed()); |
178 int max_error = 0; | 254 int max_error = 0; |
179 int total_error = 0; | 255 int total_error = 0; |
180 int total_coeff_error = 0; | 256 int total_coeff_error = 0; |
181 const int count_test_block = 100000; | 257 const int count_test_block = 100000; |
182 DECLARE_ALIGNED_ARRAY(16, int16_t, test_input_block, 64); | 258 DECLARE_ALIGNED_ARRAY(16, int16_t, test_input_block, 64); |
183 DECLARE_ALIGNED_ARRAY(16, int16_t, test_temp_block, 64); | 259 DECLARE_ALIGNED_ARRAY(16, tran_low_t, test_temp_block, 64); |
184 DECLARE_ALIGNED_ARRAY(16, int16_t, ref_temp_block, 64); | 260 DECLARE_ALIGNED_ARRAY(16, tran_low_t, ref_temp_block, 64); |
185 DECLARE_ALIGNED_ARRAY(16, uint8_t, dst, 64); | 261 DECLARE_ALIGNED_ARRAY(16, uint8_t, dst, 64); |
186 DECLARE_ALIGNED_ARRAY(16, uint8_t, src, 64); | 262 DECLARE_ALIGNED_ARRAY(16, uint8_t, src, 64); |
| 263 #if CONFIG_VP9_HIGHBITDEPTH |
| 264 DECLARE_ALIGNED_ARRAY(16, uint16_t, dst16, 64); |
| 265 DECLARE_ALIGNED_ARRAY(16, uint16_t, src16, 64); |
| 266 #endif |
187 | 267 |
188 for (int i = 0; i < count_test_block; ++i) { | 268 for (int i = 0; i < count_test_block; ++i) { |
189 // Initialize a test block with input range [-255, 255]. | 269 // Initialize a test block with input range [-mask_, mask_]. |
190 for (int j = 0; j < 64; ++j) { | 270 for (int j = 0; j < 64; ++j) { |
191 if (i == 0) { | 271 if (bit_depth_ == VPX_BITS_8) { |
192 src[j] = 255; | 272 if (i == 0) { |
193 dst[j] = 0; | 273 src[j] = 255; |
194 } else if (i == 1) { | 274 dst[j] = 0; |
195 src[j] = 0; | 275 } else if (i == 1) { |
196 dst[j] = 255; | 276 src[j] = 0; |
| 277 dst[j] = 255; |
| 278 } else { |
| 279 src[j] = rnd.Rand8() % 2 ? 255 : 0; |
| 280 dst[j] = rnd.Rand8() % 2 ? 255 : 0; |
| 281 } |
| 282 test_input_block[j] = src[j] - dst[j]; |
| 283 #if CONFIG_VP9_HIGHBITDEPTH |
197 } else { | 284 } else { |
198 src[j] = rnd.Rand8() % 2 ? 255 : 0; | 285 if (i == 0) { |
199 dst[j] = rnd.Rand8() % 2 ? 255 : 0; | 286 src16[j] = mask_; |
| 287 dst16[j] = 0; |
| 288 } else if (i == 1) { |
| 289 src16[j] = 0; |
| 290 dst16[j] = mask_; |
| 291 } else { |
| 292 src16[j] = rnd.Rand8() % 2 ? mask_ : 0; |
| 293 dst16[j] = rnd.Rand8() % 2 ? mask_ : 0; |
| 294 } |
| 295 test_input_block[j] = src16[j] - dst16[j]; |
| 296 #endif |
200 } | 297 } |
201 | |
202 test_input_block[j] = src[j] - dst[j]; | |
203 } | 298 } |
204 | 299 |
205 ASM_REGISTER_STATE_CHECK( | 300 ASM_REGISTER_STATE_CHECK( |
206 RunFwdTxfm(test_input_block, test_temp_block, pitch_)); | 301 RunFwdTxfm(test_input_block, test_temp_block, pitch_)); |
207 ASM_REGISTER_STATE_CHECK( | 302 ASM_REGISTER_STATE_CHECK( |
208 fwd_txfm_ref(test_input_block, ref_temp_block, pitch_, tx_type_)); | 303 fwd_txfm_ref(test_input_block, ref_temp_block, pitch_, tx_type_)); |
209 ASM_REGISTER_STATE_CHECK( | 304 if (bit_depth_ == VPX_BITS_8) { |
210 RunInvTxfm(test_temp_block, dst, pitch_)); | 305 ASM_REGISTER_STATE_CHECK( |
| 306 RunInvTxfm(test_temp_block, dst, pitch_)); |
| 307 #if CONFIG_VP9_HIGHBITDEPTH |
| 308 } else { |
| 309 ASM_REGISTER_STATE_CHECK( |
| 310 RunInvTxfm(test_temp_block, CONVERT_TO_BYTEPTR(dst16), pitch_)); |
| 311 #endif |
| 312 } |
211 | 313 |
212 for (int j = 0; j < 64; ++j) { | 314 for (int j = 0; j < 64; ++j) { |
| 315 #if CONFIG_VP9_HIGHBITDEPTH |
| 316 const int diff = |
| 317 bit_depth_ == VPX_BITS_8 ? dst[j] - src[j] : dst16[j] - src16[j]; |
| 318 #else |
213 const int diff = dst[j] - src[j]; | 319 const int diff = dst[j] - src[j]; |
| 320 #endif |
214 const int error = diff * diff; | 321 const int error = diff * diff; |
215 if (max_error < error) | 322 if (max_error < error) |
216 max_error = error; | 323 max_error = error; |
217 total_error += error; | 324 total_error += error; |
218 | 325 |
219 const int coeff_diff = test_temp_block[j] - ref_temp_block[j]; | 326 const int coeff_diff = test_temp_block[j] - ref_temp_block[j]; |
220 total_coeff_error += abs(coeff_diff); | 327 total_coeff_error += abs(coeff_diff); |
221 } | 328 } |
222 | 329 |
223 EXPECT_GE(1, max_error) | 330 EXPECT_GE(1 << 2 * (bit_depth_ - 8), max_error) |
224 << "Error: Extremal 8x8 FDCT/IDCT or FHT/IHT has" | 331 << "Error: Extremal 8x8 FDCT/IDCT or FHT/IHT has" |
225 << "an individual roundtrip error > 1"; | 332 << "an individual roundtrip error > 1"; |
226 | 333 |
227 EXPECT_GE(count_test_block/5, total_error) | 334 EXPECT_GE((count_test_block << 2 * (bit_depth_ - 8))/5, total_error) |
228 << "Error: Extremal 8x8 FDCT/IDCT or FHT/IHT has average" | 335 << "Error: Extremal 8x8 FDCT/IDCT or FHT/IHT has average" |
229 << " roundtrip error > 1/5 per block"; | 336 << " roundtrip error > 1/5 per block"; |
230 | 337 |
231 EXPECT_EQ(0, total_coeff_error) | 338 EXPECT_EQ(0, total_coeff_error) |
232 << "Error: Extremal 8x8 FDCT/FHT has" | 339 << "Error: Extremal 8x8 FDCT/FHT has" |
233 << "overflow issues in the intermediate steps > 1"; | 340 << "overflow issues in the intermediate steps > 1"; |
234 } | 341 } |
235 } | 342 } |
236 | 343 |
| 344 void RunInvAccuracyCheck() { |
| 345 ACMRandom rnd(ACMRandom::DeterministicSeed()); |
| 346 const int count_test_block = 1000; |
| 347 DECLARE_ALIGNED_ARRAY(16, int16_t, in, kNumCoeffs); |
| 348 DECLARE_ALIGNED_ARRAY(16, tran_low_t, coeff, kNumCoeffs); |
| 349 DECLARE_ALIGNED_ARRAY(16, uint8_t, dst, kNumCoeffs); |
| 350 DECLARE_ALIGNED_ARRAY(16, uint8_t, src, kNumCoeffs); |
| 351 #if CONFIG_VP9_HIGHBITDEPTH |
| 352 DECLARE_ALIGNED_ARRAY(16, uint16_t, src16, kNumCoeffs); |
| 353 DECLARE_ALIGNED_ARRAY(16, uint16_t, dst16, kNumCoeffs); |
| 354 #endif |
| 355 |
| 356 for (int i = 0; i < count_test_block; ++i) { |
| 357 double out_r[kNumCoeffs]; |
| 358 |
| 359 // Initialize a test block with input range [-255, 255]. |
| 360 for (int j = 0; j < kNumCoeffs; ++j) { |
| 361 if (bit_depth_ == VPX_BITS_8) { |
| 362 src[j] = rnd.Rand8() % 2 ? 255 : 0; |
| 363 dst[j] = src[j] > 0 ? 0 : 255; |
| 364 in[j] = src[j] - dst[j]; |
| 365 #if CONFIG_VP9_HIGHBITDEPTH |
| 366 } else { |
| 367 src16[j] = rnd.Rand8() % 2 ? mask_ : 0; |
| 368 dst16[j] = src16[j] > 0 ? 0 : mask_; |
| 369 in[j] = src16[j] - dst16[j]; |
| 370 #endif |
| 371 } |
| 372 } |
| 373 |
| 374 reference_8x8_dct_2d(in, out_r); |
| 375 for (int j = 0; j < kNumCoeffs; ++j) |
| 376 coeff[j] = static_cast<tran_low_t>(round(out_r[j])); |
| 377 |
| 378 if (bit_depth_ == VPX_BITS_8) { |
| 379 ASM_REGISTER_STATE_CHECK(RunInvTxfm(coeff, dst, pitch_)); |
| 380 #if CONFIG_VP9_HIGHBITDEPTH |
| 381 } else { |
| 382 ASM_REGISTER_STATE_CHECK(RunInvTxfm(coeff, CONVERT_TO_BYTEPTR(dst16), |
| 383 pitch_)); |
| 384 #endif |
| 385 } |
| 386 |
| 387 for (int j = 0; j < kNumCoeffs; ++j) { |
| 388 #if CONFIG_VP9_HIGHBITDEPTH |
| 389 const uint32_t diff = |
| 390 bit_depth_ == VPX_BITS_8 ? dst[j] - src[j] : dst16[j] - src16[j]; |
| 391 #else |
| 392 const uint32_t diff = dst[j] - src[j]; |
| 393 #endif |
| 394 const uint32_t error = diff * diff; |
| 395 EXPECT_GE(1u << 2 * (bit_depth_ - 8), error) |
| 396 << "Error: 8x8 IDCT has error " << error |
| 397 << " at index " << j; |
| 398 } |
| 399 } |
| 400 } |
| 401 |
| 402 void RunFwdAccuracyCheck() { |
| 403 ACMRandom rnd(ACMRandom::DeterministicSeed()); |
| 404 const int count_test_block = 1000; |
| 405 DECLARE_ALIGNED_ARRAY(16, int16_t, in, kNumCoeffs); |
| 406 DECLARE_ALIGNED_ARRAY(16, tran_low_t, coeff_r, kNumCoeffs); |
| 407 DECLARE_ALIGNED_ARRAY(16, tran_low_t, coeff, kNumCoeffs); |
| 408 |
| 409 for (int i = 0; i < count_test_block; ++i) { |
| 410 double out_r[kNumCoeffs]; |
| 411 |
| 412 // Initialize a test block with input range [-mask_, mask_]. |
| 413 for (int j = 0; j < kNumCoeffs; ++j) |
| 414 in[j] = rnd.Rand8() % 2 == 0 ? mask_ : -mask_; |
| 415 |
| 416 RunFwdTxfm(in, coeff, pitch_); |
| 417 reference_8x8_dct_2d(in, out_r); |
| 418 for (int j = 0; j < kNumCoeffs; ++j) |
| 419 coeff_r[j] = static_cast<tran_low_t>(round(out_r[j])); |
| 420 |
| 421 for (int j = 0; j < kNumCoeffs; ++j) { |
| 422 const uint32_t diff = coeff[j] - coeff_r[j]; |
| 423 const uint32_t error = diff * diff; |
| 424 EXPECT_GE(9u << 2 * (bit_depth_ - 8), error) |
| 425 << "Error: 8x8 DCT has error " << error |
| 426 << " at index " << j; |
| 427 } |
| 428 } |
| 429 } |
237 int pitch_; | 430 int pitch_; |
238 int tx_type_; | 431 int tx_type_; |
239 FhtFunc fwd_txfm_ref; | 432 FhtFunc fwd_txfm_ref; |
| 433 vpx_bit_depth_t bit_depth_; |
| 434 int mask_; |
240 }; | 435 }; |
241 | 436 |
242 class FwdTrans8x8DCT | 437 class FwdTrans8x8DCT |
243 : public FwdTrans8x8TestBase, | 438 : public FwdTrans8x8TestBase, |
244 public ::testing::TestWithParam<Dct8x8Param> { | 439 public ::testing::TestWithParam<Dct8x8Param> { |
245 public: | 440 public: |
246 virtual ~FwdTrans8x8DCT() {} | 441 virtual ~FwdTrans8x8DCT() {} |
247 | 442 |
248 virtual void SetUp() { | 443 virtual void SetUp() { |
249 fwd_txfm_ = GET_PARAM(0); | 444 fwd_txfm_ = GET_PARAM(0); |
250 inv_txfm_ = GET_PARAM(1); | 445 inv_txfm_ = GET_PARAM(1); |
251 tx_type_ = GET_PARAM(2); | 446 tx_type_ = GET_PARAM(2); |
252 pitch_ = 8; | 447 pitch_ = 8; |
253 fwd_txfm_ref = fdct8x8_ref; | 448 fwd_txfm_ref = fdct8x8_ref; |
| 449 bit_depth_ = GET_PARAM(3); |
| 450 mask_ = (1 << bit_depth_) - 1; |
254 } | 451 } |
255 | 452 |
256 virtual void TearDown() { libvpx_test::ClearSystemState(); } | 453 virtual void TearDown() { libvpx_test::ClearSystemState(); } |
257 | 454 |
258 protected: | 455 protected: |
259 void RunFwdTxfm(int16_t *in, int16_t *out, int stride) { | 456 void RunFwdTxfm(int16_t *in, tran_low_t *out, int stride) { |
260 fwd_txfm_(in, out, stride); | 457 fwd_txfm_(in, out, stride); |
261 } | 458 } |
262 void RunInvTxfm(int16_t *out, uint8_t *dst, int stride) { | 459 void RunInvTxfm(tran_low_t *out, uint8_t *dst, int stride) { |
263 inv_txfm_(out, dst, stride); | 460 inv_txfm_(out, dst, stride); |
264 } | 461 } |
265 | 462 |
266 FdctFunc fwd_txfm_; | 463 FdctFunc fwd_txfm_; |
267 IdctFunc inv_txfm_; | 464 IdctFunc inv_txfm_; |
268 }; | 465 }; |
269 | 466 |
270 TEST_P(FwdTrans8x8DCT, SignBiasCheck) { | 467 TEST_P(FwdTrans8x8DCT, SignBiasCheck) { |
271 RunSignBiasCheck(); | 468 RunSignBiasCheck(); |
272 } | 469 } |
273 | 470 |
274 TEST_P(FwdTrans8x8DCT, RoundTripErrorCheck) { | 471 TEST_P(FwdTrans8x8DCT, RoundTripErrorCheck) { |
275 RunRoundTripErrorCheck(); | 472 RunRoundTripErrorCheck(); |
276 } | 473 } |
277 | 474 |
278 TEST_P(FwdTrans8x8DCT, ExtremalCheck) { | 475 TEST_P(FwdTrans8x8DCT, ExtremalCheck) { |
279 RunExtremalCheck(); | 476 RunExtremalCheck(); |
280 } | 477 } |
281 | 478 |
| 479 TEST_P(FwdTrans8x8DCT, FwdAccuracyCheck) { |
| 480 RunFwdAccuracyCheck(); |
| 481 } |
| 482 |
| 483 TEST_P(FwdTrans8x8DCT, InvAccuracyCheck) { |
| 484 RunInvAccuracyCheck(); |
| 485 } |
| 486 |
282 class FwdTrans8x8HT | 487 class FwdTrans8x8HT |
283 : public FwdTrans8x8TestBase, | 488 : public FwdTrans8x8TestBase, |
284 public ::testing::TestWithParam<Ht8x8Param> { | 489 public ::testing::TestWithParam<Ht8x8Param> { |
285 public: | 490 public: |
286 virtual ~FwdTrans8x8HT() {} | 491 virtual ~FwdTrans8x8HT() {} |
287 | 492 |
288 virtual void SetUp() { | 493 virtual void SetUp() { |
289 fwd_txfm_ = GET_PARAM(0); | 494 fwd_txfm_ = GET_PARAM(0); |
290 inv_txfm_ = GET_PARAM(1); | 495 inv_txfm_ = GET_PARAM(1); |
291 tx_type_ = GET_PARAM(2); | 496 tx_type_ = GET_PARAM(2); |
292 pitch_ = 8; | 497 pitch_ = 8; |
293 fwd_txfm_ref = fht8x8_ref; | 498 fwd_txfm_ref = fht8x8_ref; |
| 499 bit_depth_ = GET_PARAM(3); |
| 500 mask_ = (1 << bit_depth_) - 1; |
294 } | 501 } |
295 | 502 |
296 virtual void TearDown() { libvpx_test::ClearSystemState(); } | 503 virtual void TearDown() { libvpx_test::ClearSystemState(); } |
297 | 504 |
298 protected: | 505 protected: |
299 void RunFwdTxfm(int16_t *in, int16_t *out, int stride) { | 506 void RunFwdTxfm(int16_t *in, tran_low_t *out, int stride) { |
300 fwd_txfm_(in, out, stride, tx_type_); | 507 fwd_txfm_(in, out, stride, tx_type_); |
301 } | 508 } |
302 void RunInvTxfm(int16_t *out, uint8_t *dst, int stride) { | 509 void RunInvTxfm(tran_low_t *out, uint8_t *dst, int stride) { |
303 inv_txfm_(out, dst, stride, tx_type_); | 510 inv_txfm_(out, dst, stride, tx_type_); |
304 } | 511 } |
305 | 512 |
306 FhtFunc fwd_txfm_; | 513 FhtFunc fwd_txfm_; |
307 IhtFunc inv_txfm_; | 514 IhtFunc inv_txfm_; |
308 }; | 515 }; |
309 | 516 |
310 TEST_P(FwdTrans8x8HT, SignBiasCheck) { | 517 TEST_P(FwdTrans8x8HT, SignBiasCheck) { |
311 RunSignBiasCheck(); | 518 RunSignBiasCheck(); |
312 } | 519 } |
313 | 520 |
314 TEST_P(FwdTrans8x8HT, RoundTripErrorCheck) { | 521 TEST_P(FwdTrans8x8HT, RoundTripErrorCheck) { |
315 RunRoundTripErrorCheck(); | 522 RunRoundTripErrorCheck(); |
316 } | 523 } |
317 | 524 |
318 TEST_P(FwdTrans8x8HT, ExtremalCheck) { | 525 TEST_P(FwdTrans8x8HT, ExtremalCheck) { |
319 RunExtremalCheck(); | 526 RunExtremalCheck(); |
320 } | 527 } |
321 | 528 |
322 using std::tr1::make_tuple; | 529 using std::tr1::make_tuple; |
323 | 530 |
| 531 #if CONFIG_VP9_HIGHBITDEPTH |
324 INSTANTIATE_TEST_CASE_P( | 532 INSTANTIATE_TEST_CASE_P( |
325 C, FwdTrans8x8DCT, | 533 C, FwdTrans8x8DCT, |
326 ::testing::Values( | 534 ::testing::Values( |
327 make_tuple(&vp9_fdct8x8_c, &vp9_idct8x8_64_add_c, 0))); | 535 make_tuple(&vp9_high_fdct8x8_c, &idct8x8_10, 0, VPX_BITS_10), |
| 536 make_tuple(&vp9_high_fdct8x8_c, &idct8x8_12, 0, VPX_BITS_12), |
| 537 make_tuple(&vp9_fdct8x8_c, &vp9_idct8x8_64_add_c, 0, VPX_BITS_8))); |
| 538 #else |
| 539 INSTANTIATE_TEST_CASE_P( |
| 540 C, FwdTrans8x8DCT, |
| 541 ::testing::Values( |
| 542 make_tuple(&vp9_fdct8x8_c, &vp9_idct8x8_64_add_c, 0, VPX_BITS_8))); |
| 543 #endif |
| 544 |
| 545 #if CONFIG_VP9_HIGHBITDEPTH |
328 INSTANTIATE_TEST_CASE_P( | 546 INSTANTIATE_TEST_CASE_P( |
329 C, FwdTrans8x8HT, | 547 C, FwdTrans8x8HT, |
330 ::testing::Values( | 548 ::testing::Values( |
331 make_tuple(&vp9_fht8x8_c, &vp9_iht8x8_64_add_c, 0), | 549 make_tuple(&vp9_high_fht8x8_c, &iht8x8_10, 0, VPX_BITS_10), |
332 make_tuple(&vp9_fht8x8_c, &vp9_iht8x8_64_add_c, 1), | 550 make_tuple(&vp9_high_fht8x8_c, &iht8x8_10, 1, VPX_BITS_10), |
333 make_tuple(&vp9_fht8x8_c, &vp9_iht8x8_64_add_c, 2), | 551 make_tuple(&vp9_high_fht8x8_c, &iht8x8_10, 2, VPX_BITS_10), |
334 make_tuple(&vp9_fht8x8_c, &vp9_iht8x8_64_add_c, 3))); | 552 make_tuple(&vp9_high_fht8x8_c, &iht8x8_10, 3, VPX_BITS_10), |
| 553 make_tuple(&vp9_high_fht8x8_c, &iht8x8_12, 0, VPX_BITS_12), |
| 554 make_tuple(&vp9_high_fht8x8_c, &iht8x8_12, 1, VPX_BITS_12), |
| 555 make_tuple(&vp9_high_fht8x8_c, &iht8x8_12, 2, VPX_BITS_12), |
| 556 make_tuple(&vp9_high_fht8x8_c, &iht8x8_12, 3, VPX_BITS_12), |
| 557 make_tuple(&vp9_fht8x8_c, &vp9_iht8x8_64_add_c, 0, VPX_BITS_8), |
| 558 make_tuple(&vp9_fht8x8_c, &vp9_iht8x8_64_add_c, 1, VPX_BITS_8), |
| 559 make_tuple(&vp9_fht8x8_c, &vp9_iht8x8_64_add_c, 2, VPX_BITS_8), |
| 560 make_tuple(&vp9_fht8x8_c, &vp9_iht8x8_64_add_c, 3, VPX_BITS_8))); |
| 561 #else |
| 562 INSTANTIATE_TEST_CASE_P( |
| 563 C, FwdTrans8x8HT, |
| 564 ::testing::Values( |
| 565 make_tuple(&vp9_fht8x8_c, &vp9_iht8x8_64_add_c, 0, VPX_BITS_8), |
| 566 make_tuple(&vp9_fht8x8_c, &vp9_iht8x8_64_add_c, 1, VPX_BITS_8), |
| 567 make_tuple(&vp9_fht8x8_c, &vp9_iht8x8_64_add_c, 2, VPX_BITS_8), |
| 568 make_tuple(&vp9_fht8x8_c, &vp9_iht8x8_64_add_c, 3, VPX_BITS_8))); |
| 569 #endif |
335 | 570 |
336 #if HAVE_NEON_ASM | 571 #if HAVE_NEON_ASM && !CONFIG_VP9_HIGHBITDEPTH |
337 INSTANTIATE_TEST_CASE_P( | 572 INSTANTIATE_TEST_CASE_P( |
338 NEON, FwdTrans8x8DCT, | 573 NEON, FwdTrans8x8DCT, |
339 ::testing::Values( | 574 ::testing::Values( |
340 make_tuple(&vp9_fdct8x8_neon, &vp9_idct8x8_64_add_neon, 0))); | 575 make_tuple(&vp9_fdct8x8_neon, &vp9_idct8x8_64_add_neon, 0, |
| 576 VPX_BITS_8))); |
341 INSTANTIATE_TEST_CASE_P( | 577 INSTANTIATE_TEST_CASE_P( |
342 DISABLED_NEON, FwdTrans8x8HT, | 578 DISABLED_NEON, FwdTrans8x8HT, |
343 ::testing::Values( | 579 ::testing::Values( |
344 make_tuple(&vp9_fht8x8_c, &vp9_iht8x8_64_add_neon, 0), | 580 make_tuple(&vp9_fht8x8_c, &vp9_iht8x8_64_add_neon, 0, VPX_BITS_8), |
345 make_tuple(&vp9_fht8x8_c, &vp9_iht8x8_64_add_neon, 1), | 581 make_tuple(&vp9_fht8x8_c, &vp9_iht8x8_64_add_neon, 1, VPX_BITS_8), |
346 make_tuple(&vp9_fht8x8_c, &vp9_iht8x8_64_add_neon, 2), | 582 make_tuple(&vp9_fht8x8_c, &vp9_iht8x8_64_add_neon, 2, VPX_BITS_8), |
347 make_tuple(&vp9_fht8x8_c, &vp9_iht8x8_64_add_neon, 3))); | 583 make_tuple(&vp9_fht8x8_c, &vp9_iht8x8_64_add_neon, 3, VPX_BITS_8))); |
348 #endif | 584 #endif |
349 | 585 |
350 #if HAVE_SSE2 | 586 #if HAVE_SSE2 && !CONFIG_VP9_HIGHBITDEPTH |
351 INSTANTIATE_TEST_CASE_P( | 587 INSTANTIATE_TEST_CASE_P( |
352 SSE2, FwdTrans8x8DCT, | 588 SSE2, FwdTrans8x8DCT, |
353 ::testing::Values( | 589 ::testing::Values( |
354 make_tuple(&vp9_fdct8x8_sse2, &vp9_idct8x8_64_add_sse2, 0))); | 590 make_tuple(&vp9_fdct8x8_sse2, &vp9_idct8x8_64_add_sse2, 0, |
| 591 VPX_BITS_8))); |
355 INSTANTIATE_TEST_CASE_P( | 592 INSTANTIATE_TEST_CASE_P( |
356 SSE2, FwdTrans8x8HT, | 593 SSE2, FwdTrans8x8HT, |
357 ::testing::Values( | 594 ::testing::Values( |
358 make_tuple(&vp9_fht8x8_sse2, &vp9_iht8x8_64_add_sse2, 0), | 595 make_tuple(&vp9_fht8x8_sse2, &vp9_iht8x8_64_add_sse2, 0, VPX_BITS_8), |
359 make_tuple(&vp9_fht8x8_sse2, &vp9_iht8x8_64_add_sse2, 1), | 596 make_tuple(&vp9_fht8x8_sse2, &vp9_iht8x8_64_add_sse2, 1, VPX_BITS_8), |
360 make_tuple(&vp9_fht8x8_sse2, &vp9_iht8x8_64_add_sse2, 2), | 597 make_tuple(&vp9_fht8x8_sse2, &vp9_iht8x8_64_add_sse2, 2, VPX_BITS_8), |
361 make_tuple(&vp9_fht8x8_sse2, &vp9_iht8x8_64_add_sse2, 3))); | 598 make_tuple(&vp9_fht8x8_sse2, &vp9_iht8x8_64_add_sse2, 3, VPX_BITS_8))); |
362 #endif | 599 #endif |
363 | 600 |
364 #if HAVE_SSSE3 && ARCH_X86_64 | 601 #if HAVE_SSSE3 && ARCH_X86_64 && !CONFIG_VP9_HIGHBITDEPTH |
365 INSTANTIATE_TEST_CASE_P( | 602 INSTANTIATE_TEST_CASE_P( |
366 SSSE3, FwdTrans8x8DCT, | 603 SSSE3, FwdTrans8x8DCT, |
367 ::testing::Values( | 604 ::testing::Values( |
368 make_tuple(&vp9_fdct8x8_ssse3, &vp9_idct8x8_64_add_ssse3, 0))); | 605 make_tuple(&vp9_fdct8x8_ssse3, &vp9_idct8x8_64_add_ssse3, 0, |
| 606 VPX_BITS_8))); |
369 #endif | 607 #endif |
370 } // namespace | 608 } // namespace |
OLD | NEW |