2 * Copyright (c) 2016, Alliance for Open Media. All rights reserved
4 * This source code is subject to the terms of the BSD 2 Clause License and
5 * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
6 * was not distributed with this source code in the LICENSE file, you can
7 * obtain it at www.aomedia.org/license/software. If the Alliance for Open
8 * Media Patent License 1.0 was not distributed with this source code in the
9 * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
12 #include "third_party/googletest/src/googletest/include/gtest/gtest.h"
14 #include "./aom_config.h"
16 #include "./aom_dsp_rtcd.h"
17 #include "./av1_rtcd.h"
19 #include "aom_dsp/aom_dsp_common.h"
21 #include "av1/common/enums.h"
23 #include "test/acm_random.h"
24 #include "test/function_equivalence_test.h"
25 #include "test/register_state_check.h"
27 #define WEDGE_WEIGHT_BITS 6
28 #define MAX_MASK_VALUE (1 << (WEDGE_WEIGHT_BITS))
30 using libaom_test::ACMRandom
;
31 using libaom_test::FunctionEquivalenceTest
;
35 static const int16_t kInt13Max
= (1 << 12) - 1;
37 //////////////////////////////////////////////////////////////////////////////
38 // av1_wedge_sse_from_residuals - functionality
39 //////////////////////////////////////////////////////////////////////////////
41 class WedgeUtilsSSEFuncTest
: public testing::Test
{
43 WedgeUtilsSSEFuncTest() : rng_(ACMRandom::DeterministicSeed()) {}
45 static const int kIterations
= 1000;
50 static void equiv_blend_residuals(int16_t *r
, const int16_t *r0
,
51 const int16_t *r1
, const uint8_t *m
, int N
) {
52 for (int i
= 0; i
< N
; i
++) {
53 const int32_t m0
= m
[i
];
54 const int32_t m1
= MAX_MASK_VALUE
- m0
;
55 const int16_t R
= m0
* r0
[i
] + m1
* r1
[i
];
56 // Note that this rounding is designed to match the result
57 // you would get when actually blending the 2 predictors and computing
59 r
[i
] = ROUND_POWER_OF_TWO(R
- 1, WEDGE_WEIGHT_BITS
);
63 static uint64_t equiv_sse_from_residuals(const int16_t *r0
, const int16_t *r1
,
64 const uint8_t *m
, int N
) {
66 for (int i
= 0; i
< N
; i
++) {
67 const int32_t m0
= m
[i
];
68 const int32_t m1
= MAX_MASK_VALUE
- m0
;
69 const int16_t R
= m0
* r0
[i
] + m1
* r1
[i
];
70 const int32_t r
= ROUND_POWER_OF_TWO(R
- 1, WEDGE_WEIGHT_BITS
);
76 TEST_F(WedgeUtilsSSEFuncTest
, ResidualBlendingEquiv
) {
77 DECLARE_ALIGNED(32, uint8_t, s
[MAX_SB_SQUARE
]);
78 DECLARE_ALIGNED(32, uint8_t, p0
[MAX_SB_SQUARE
]);
79 DECLARE_ALIGNED(32, uint8_t, p1
[MAX_SB_SQUARE
]);
80 DECLARE_ALIGNED(32, uint8_t, p
[MAX_SB_SQUARE
]);
82 DECLARE_ALIGNED(32, int16_t, r0
[MAX_SB_SQUARE
]);
83 DECLARE_ALIGNED(32, int16_t, r1
[MAX_SB_SQUARE
]);
84 DECLARE_ALIGNED(32, int16_t, r_ref
[MAX_SB_SQUARE
]);
85 DECLARE_ALIGNED(32, int16_t, r_tst
[MAX_SB_SQUARE
]);
86 DECLARE_ALIGNED(32, uint8_t, m
[MAX_SB_SQUARE
]);
88 for (int iter
= 0; iter
< kIterations
&& !HasFatalFailure(); ++iter
) {
89 for (int i
= 0; i
< MAX_SB_SQUARE
; ++i
) {
91 m
[i
] = rng_(MAX_MASK_VALUE
+ 1);
94 const int w
= 1 << (rng_(MAX_SB_SIZE_LOG2
+ 1 - 3) + 3);
95 const int h
= 1 << (rng_(MAX_SB_SIZE_LOG2
+ 1 - 3) + 3);
98 for (int j
= 0; j
< N
; j
++) {
99 p0
[j
] = clamp(s
[j
] + rng_(33) - 16, 0, UINT8_MAX
);
100 p1
[j
] = clamp(s
[j
] + rng_(33) - 16, 0, UINT8_MAX
);
103 aom_blend_a64_mask(p
, w
, p0
, w
, p1
, w
, m
, w
, h
, w
, 0, 0);
105 aom_subtract_block(h
, w
, r0
, w
, s
, w
, p0
, w
);
106 aom_subtract_block(h
, w
, r1
, w
, s
, w
, p1
, w
);
108 aom_subtract_block(h
, w
, r_ref
, w
, s
, w
, p
, w
);
109 equiv_blend_residuals(r_tst
, r0
, r1
, m
, N
);
111 for (int i
= 0; i
< N
; ++i
) ASSERT_EQ(r_ref
[i
], r_tst
[i
]);
113 uint64_t ref_sse
= aom_sum_squares_i16(r_ref
, N
);
114 uint64_t tst_sse
= equiv_sse_from_residuals(r0
, r1
, m
, N
);
116 ASSERT_EQ(ref_sse
, tst_sse
);
120 static uint64_t sse_from_residuals(const int16_t *r0
, const int16_t *r1
,
121 const uint8_t *m
, int N
) {
123 for (int i
= 0; i
< N
; i
++) {
124 const int32_t m0
= m
[i
];
125 const int32_t m1
= MAX_MASK_VALUE
- m0
;
126 const int32_t r
= m0
* r0
[i
] + m1
* r1
[i
];
129 return ROUND_POWER_OF_TWO(acc
, 2 * WEDGE_WEIGHT_BITS
);
132 TEST_F(WedgeUtilsSSEFuncTest
, ResidualBlendingMethod
) {
133 DECLARE_ALIGNED(32, int16_t, r0
[MAX_SB_SQUARE
]);
134 DECLARE_ALIGNED(32, int16_t, r1
[MAX_SB_SQUARE
]);
135 DECLARE_ALIGNED(32, int16_t, d
[MAX_SB_SQUARE
]);
136 DECLARE_ALIGNED(32, uint8_t, m
[MAX_SB_SQUARE
]);
138 for (int iter
= 0; iter
< kIterations
&& !HasFatalFailure(); ++iter
) {
139 for (int i
= 0; i
< MAX_SB_SQUARE
; ++i
) {
140 r1
[i
] = rng_(2 * INT8_MAX
- 2 * INT8_MIN
+ 1) + 2 * INT8_MIN
;
141 d
[i
] = rng_(2 * INT8_MAX
- 2 * INT8_MIN
+ 1) + 2 * INT8_MIN
;
142 m
[i
] = rng_(MAX_MASK_VALUE
+ 1);
145 const int N
= 64 * (rng_(MAX_SB_SQUARE
/ 64) + 1);
147 for (int i
= 0; i
< N
; i
++) r0
[i
] = r1
[i
] + d
[i
];
149 const uint64_t ref_res
= sse_from_residuals(r0
, r1
, m
, N
);
150 const uint64_t tst_res
= av1_wedge_sse_from_residuals(r1
, d
, m
, N
);
152 ASSERT_EQ(ref_res
, tst_res
);
156 //////////////////////////////////////////////////////////////////////////////
157 // av1_wedge_sse_from_residuals - optimizations
158 //////////////////////////////////////////////////////////////////////////////
160 typedef uint64_t (*FSSE
)(const int16_t *r1
, const int16_t *d
, const uint8_t *m
,
162 typedef libaom_test::FuncParam
<FSSE
> TestFuncsFSSE
;
164 class WedgeUtilsSSEOptTest
: public FunctionEquivalenceTest
<FSSE
> {
166 static const int kIterations
= 10000;
169 TEST_P(WedgeUtilsSSEOptTest
, RandomValues
) {
170 DECLARE_ALIGNED(32, int16_t, r1
[MAX_SB_SQUARE
]);
171 DECLARE_ALIGNED(32, int16_t, d
[MAX_SB_SQUARE
]);
172 DECLARE_ALIGNED(32, uint8_t, m
[MAX_SB_SQUARE
]);
174 for (int iter
= 0; iter
< kIterations
&& !HasFatalFailure(); ++iter
) {
175 for (int i
= 0; i
< MAX_SB_SQUARE
; ++i
) {
176 r1
[i
] = rng_(2 * kInt13Max
+ 1) - kInt13Max
;
177 d
[i
] = rng_(2 * kInt13Max
+ 1) - kInt13Max
;
178 m
[i
] = rng_(MAX_MASK_VALUE
+ 1);
181 const int N
= 64 * (rng_(MAX_SB_SQUARE
/ 64) + 1);
183 const uint64_t ref_res
= params_
.ref_func(r1
, d
, m
, N
);
185 ASM_REGISTER_STATE_CHECK(tst_res
= params_
.tst_func(r1
, d
, m
, N
));
187 ASSERT_EQ(ref_res
, tst_res
);
191 TEST_P(WedgeUtilsSSEOptTest
, ExtremeValues
) {
192 DECLARE_ALIGNED(32, int16_t, r1
[MAX_SB_SQUARE
]);
193 DECLARE_ALIGNED(32, int16_t, d
[MAX_SB_SQUARE
]);
194 DECLARE_ALIGNED(32, uint8_t, m
[MAX_SB_SQUARE
]);
196 for (int iter
= 0; iter
< kIterations
&& !HasFatalFailure(); ++iter
) {
198 for (int i
= 0; i
< MAX_SB_SQUARE
; ++i
) r1
[i
] = kInt13Max
;
200 for (int i
= 0; i
< MAX_SB_SQUARE
; ++i
) r1
[i
] = -kInt13Max
;
204 for (int i
= 0; i
< MAX_SB_SQUARE
; ++i
) d
[i
] = kInt13Max
;
206 for (int i
= 0; i
< MAX_SB_SQUARE
; ++i
) d
[i
] = -kInt13Max
;
209 for (int i
= 0; i
< MAX_SB_SQUARE
; ++i
) m
[i
] = MAX_MASK_VALUE
;
211 const int N
= 64 * (rng_(MAX_SB_SQUARE
/ 64) + 1);
213 const uint64_t ref_res
= params_
.ref_func(r1
, d
, m
, N
);
215 ASM_REGISTER_STATE_CHECK(tst_res
= params_
.tst_func(r1
, d
, m
, N
));
217 ASSERT_EQ(ref_res
, tst_res
);
222 INSTANTIATE_TEST_CASE_P(
223 SSE2
, WedgeUtilsSSEOptTest
,
224 ::testing::Values(TestFuncsFSSE(av1_wedge_sse_from_residuals_c
,
225 av1_wedge_sse_from_residuals_sse2
)));
229 //////////////////////////////////////////////////////////////////////////////
230 // av1_wedge_sign_from_residuals
231 //////////////////////////////////////////////////////////////////////////////
233 typedef int (*FSign
)(const int16_t *ds
, const uint8_t *m
, int N
, int64_t limit
);
234 typedef libaom_test::FuncParam
<FSign
> TestFuncsFSign
;
236 class WedgeUtilsSignOptTest
: public FunctionEquivalenceTest
<FSign
> {
238 static const int kIterations
= 10000;
239 static const int kMaxSize
= 8196; // Size limited by SIMD implementation.
242 TEST_P(WedgeUtilsSignOptTest
, RandomValues
) {
243 DECLARE_ALIGNED(32, int16_t, r0
[MAX_SB_SQUARE
]);
244 DECLARE_ALIGNED(32, int16_t, r1
[MAX_SB_SQUARE
]);
245 DECLARE_ALIGNED(32, int16_t, ds
[MAX_SB_SQUARE
]);
246 DECLARE_ALIGNED(32, uint8_t, m
[MAX_SB_SQUARE
]);
248 for (int iter
= 0; iter
< kIterations
&& !HasFatalFailure(); ++iter
) {
249 for (int i
= 0; i
< MAX_SB_SQUARE
; ++i
) {
250 r0
[i
] = rng_(2 * kInt13Max
+ 1) - kInt13Max
;
251 r1
[i
] = rng_(2 * kInt13Max
+ 1) - kInt13Max
;
252 m
[i
] = rng_(MAX_MASK_VALUE
+ 1);
255 const int maxN
= AOMMIN(kMaxSize
, MAX_SB_SQUARE
);
256 const int N
= 64 * (rng_(maxN
/ 64 - 1) + 1);
259 limit
= (int64_t)aom_sum_squares_i16(r0
, N
);
260 limit
-= (int64_t)aom_sum_squares_i16(r1
, N
);
261 limit
*= (1 << WEDGE_WEIGHT_BITS
) / 2;
263 for (int i
= 0; i
< N
; i
++)
264 ds
[i
] = clamp(r0
[i
] * r0
[i
] - r1
[i
] * r1
[i
], INT16_MIN
, INT16_MAX
);
266 const int ref_res
= params_
.ref_func(ds
, m
, N
, limit
);
268 ASM_REGISTER_STATE_CHECK(tst_res
= params_
.tst_func(ds
, m
, N
, limit
));
270 ASSERT_EQ(ref_res
, tst_res
);
274 TEST_P(WedgeUtilsSignOptTest
, ExtremeValues
) {
275 DECLARE_ALIGNED(32, int16_t, r0
[MAX_SB_SQUARE
]);
276 DECLARE_ALIGNED(32, int16_t, r1
[MAX_SB_SQUARE
]);
277 DECLARE_ALIGNED(32, int16_t, ds
[MAX_SB_SQUARE
]);
278 DECLARE_ALIGNED(32, uint8_t, m
[MAX_SB_SQUARE
]);
280 for (int iter
= 0; iter
< kIterations
&& !HasFatalFailure(); ++iter
) {
283 for (int i
= 0; i
< MAX_SB_SQUARE
; ++i
) {
289 for (int i
= 0; i
< MAX_SB_SQUARE
; ++i
) {
295 for (int i
= 0; i
< MAX_SB_SQUARE
; ++i
) {
301 for (int i
= 0; i
< MAX_SB_SQUARE
; ++i
) {
308 for (int i
= 0; i
< MAX_SB_SQUARE
; ++i
) m
[i
] = MAX_MASK_VALUE
;
310 const int maxN
= AOMMIN(kMaxSize
, MAX_SB_SQUARE
);
311 const int N
= 64 * (rng_(maxN
/ 64 - 1) + 1);
314 limit
= (int64_t)aom_sum_squares_i16(r0
, N
);
315 limit
-= (int64_t)aom_sum_squares_i16(r1
, N
);
316 limit
*= (1 << WEDGE_WEIGHT_BITS
) / 2;
318 for (int i
= 0; i
< N
; i
++)
319 ds
[i
] = clamp(r0
[i
] * r0
[i
] - r1
[i
] * r1
[i
], INT16_MIN
, INT16_MAX
);
321 const int ref_res
= params_
.ref_func(ds
, m
, N
, limit
);
323 ASM_REGISTER_STATE_CHECK(tst_res
= params_
.tst_func(ds
, m
, N
, limit
));
325 ASSERT_EQ(ref_res
, tst_res
);
331 INSTANTIATE_TEST_CASE_P(
332 SSE2
, WedgeUtilsSignOptTest
,
333 ::testing::Values(TestFuncsFSign(av1_wedge_sign_from_residuals_c
,
334 av1_wedge_sign_from_residuals_sse2
)));
338 //////////////////////////////////////////////////////////////////////////////
339 // av1_wedge_compute_delta_squares
340 //////////////////////////////////////////////////////////////////////////////
342 typedef void (*FDS
)(int16_t *d
, const int16_t *a
, const int16_t *b
, int N
);
343 typedef libaom_test::FuncParam
<FDS
> TestFuncsFDS
;
345 class WedgeUtilsDeltaSquaresOptTest
: public FunctionEquivalenceTest
<FDS
> {
347 static const int kIterations
= 10000;
350 TEST_P(WedgeUtilsDeltaSquaresOptTest
, RandomValues
) {
351 DECLARE_ALIGNED(32, int16_t, a
[MAX_SB_SQUARE
]);
352 DECLARE_ALIGNED(32, int16_t, b
[MAX_SB_SQUARE
]);
353 DECLARE_ALIGNED(32, int16_t, d_ref
[MAX_SB_SQUARE
]);
354 DECLARE_ALIGNED(32, int16_t, d_tst
[MAX_SB_SQUARE
]);
356 for (int iter
= 0; iter
< kIterations
&& !HasFatalFailure(); ++iter
) {
357 for (int i
= 0; i
< MAX_SB_SQUARE
; ++i
) {
358 a
[i
] = rng_
.Rand16();
359 b
[i
] = rng_(2 * INT16_MAX
+ 1) - INT16_MAX
;
362 const int N
= 64 * (rng_(MAX_SB_SQUARE
/ 64) + 1);
364 memset(&d_ref
, INT16_MAX
, sizeof(d_ref
));
365 memset(&d_tst
, INT16_MAX
, sizeof(d_tst
));
367 params_
.ref_func(d_ref
, a
, b
, N
);
368 ASM_REGISTER_STATE_CHECK(params_
.tst_func(d_tst
, a
, b
, N
));
370 for (int i
= 0; i
< MAX_SB_SQUARE
; ++i
) ASSERT_EQ(d_ref
[i
], d_tst
[i
]);
376 INSTANTIATE_TEST_CASE_P(
377 SSE2
, WedgeUtilsDeltaSquaresOptTest
,
378 ::testing::Values(TestFuncsFDS(av1_wedge_compute_delta_squares_c
,
379 av1_wedge_compute_delta_squares_sse2
)));