1 /*
2 * Copyright (c) 2023 The WebM project authors. All rights reserved.
3 * Copyright (c) 2023, Alliance for Open Media. All rights reserved.
4 *
5 * This source code is subject to the terms of the BSD 2 Clause License and
6 * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
7 * was not distributed with this source code in the LICENSE file, you can
8 * obtain it at www.aomedia.org/license/software. If the Alliance for Open
9 * Media Patent License 1.0 was not distributed with this source code in the
10 * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
11 */
12
13 #include <stdlib.h>
14 #include <string.h>
15
16 #include "gtest/gtest.h"
17
18 #include "config/aom_config.h"
19 #include "config/aom_dsp_rtcd.h"
20 #include "aom_ports/mem.h"
21 #include "test/acm_random.h"
22 #include "test/register_state_check.h"
23 #include "test/util.h"
24
25 namespace {
26
27 using ::libaom_test::ACMRandom;
28
29 typedef void (*MinMaxFunc)(const uint8_t *a, int a_stride, const uint8_t *b,
30 int b_stride, int *min, int *max);
31
32 class MinMaxTest : public ::testing::TestWithParam<MinMaxFunc> {
33 public:
SetUp()34 void SetUp() override {
35 mm_func_ = GetParam();
36 rnd_.Reset(ACMRandom::DeterministicSeed());
37 }
38
39 protected:
40 MinMaxFunc mm_func_;
41 ACMRandom rnd_;
42 };
43
reference_minmax(const uint8_t * a,int a_stride,const uint8_t * b,int b_stride,int * min_ret,int * max_ret)44 void reference_minmax(const uint8_t *a, int a_stride, const uint8_t *b,
45 int b_stride, int *min_ret, int *max_ret) {
46 int min = 255;
47 int max = 0;
48 for (int i = 0; i < 8; i++) {
49 for (int j = 0; j < 8; j++) {
50 const int diff = abs(a[i * a_stride + j] - b[i * b_stride + j]);
51 if (min > diff) min = diff;
52 if (max < diff) max = diff;
53 }
54 }
55
56 *min_ret = min;
57 *max_ret = max;
58 }
59
TEST_P(MinMaxTest,MinValue)60 TEST_P(MinMaxTest, MinValue) {
61 for (int i = 0; i < 64; i++) {
62 uint8_t a[64], b[64];
63 memset(a, 0, sizeof(a));
64 memset(b, 255, sizeof(b));
65 b[i] = i; // Set a minimum difference of i.
66
67 int min, max;
68 API_REGISTER_STATE_CHECK(mm_func_(a, 8, b, 8, &min, &max));
69 EXPECT_EQ(255, max);
70 EXPECT_EQ(i, min);
71 }
72 }
73
TEST_P(MinMaxTest,MaxValue)74 TEST_P(MinMaxTest, MaxValue) {
75 for (int i = 0; i < 64; i++) {
76 uint8_t a[64], b[64];
77 memset(a, 0, sizeof(a));
78 memset(b, 0, sizeof(b));
79 b[i] = i; // Set a maximum difference of i.
80
81 int min, max;
82 API_REGISTER_STATE_CHECK(mm_func_(a, 8, b, 8, &min, &max));
83 EXPECT_EQ(i, max);
84 EXPECT_EQ(0, min);
85 }
86 }
87
TEST_P(MinMaxTest,CompareReference)88 TEST_P(MinMaxTest, CompareReference) {
89 uint8_t a[64], b[64];
90 for (int j = 0; j < 64; j++) {
91 a[j] = rnd_.Rand8();
92 b[j] = rnd_.Rand8();
93 }
94
95 int min_ref, max_ref, min, max;
96 reference_minmax(a, 8, b, 8, &min_ref, &max_ref);
97 API_REGISTER_STATE_CHECK(mm_func_(a, 8, b, 8, &min, &max));
98 EXPECT_EQ(max_ref, max);
99 EXPECT_EQ(min_ref, min);
100 }
101
TEST_P(MinMaxTest,CompareReferenceAndVaryStride)102 TEST_P(MinMaxTest, CompareReferenceAndVaryStride) {
103 uint8_t a[8 * 64], b[8 * 64];
104 for (int i = 0; i < 8 * 64; i++) {
105 a[i] = rnd_.Rand8();
106 b[i] = rnd_.Rand8();
107 }
108 for (int a_stride = 8; a_stride <= 64; a_stride += 8) {
109 for (int b_stride = 8; b_stride <= 64; b_stride += 8) {
110 int min_ref, max_ref, min, max;
111 reference_minmax(a, a_stride, b, b_stride, &min_ref, &max_ref);
112 API_REGISTER_STATE_CHECK(mm_func_(a, a_stride, b, b_stride, &min, &max));
113 EXPECT_EQ(max_ref, max)
114 << "when a_stride = " << a_stride << " and b_stride = " << b_stride;
115 EXPECT_EQ(min_ref, min)
116 << "when a_stride = " << a_stride << " and b_stride = " << b_stride;
117 }
118 }
119 }
120
121 #if CONFIG_AV1_HIGHBITDEPTH
122
123 using HBDMinMaxTest = MinMaxTest;
124
highbd_reference_minmax(const uint8_t * a,int a_stride,const uint8_t * b,int b_stride,int * min_ret,int * max_ret)125 void highbd_reference_minmax(const uint8_t *a, int a_stride, const uint8_t *b,
126 int b_stride, int *min_ret, int *max_ret) {
127 int min = 65535;
128 int max = 0;
129 const uint16_t *a_ptr = CONVERT_TO_SHORTPTR(a);
130 const uint16_t *b_ptr = CONVERT_TO_SHORTPTR(b);
131 for (int i = 0; i < 8; i++) {
132 for (int j = 0; j < 8; j++) {
133 const int diff = abs(a_ptr[i * a_stride + j] - b_ptr[i * b_stride + j]);
134 if (min > diff) min = diff;
135 if (max < diff) max = diff;
136 }
137 }
138
139 *min_ret = min;
140 *max_ret = max;
141 }
142
TEST_P(HBDMinMaxTest,MinValue)143 TEST_P(HBDMinMaxTest, MinValue) {
144 uint8_t *a = CONVERT_TO_BYTEPTR(
145 reinterpret_cast<uint16_t *>(aom_malloc(64 * sizeof(uint16_t))));
146 uint8_t *b = CONVERT_TO_BYTEPTR(
147 reinterpret_cast<uint16_t *>(aom_malloc(64 * sizeof(uint16_t))));
148 for (int i = 0; i < 64; i++) {
149 aom_memset16(CONVERT_TO_SHORTPTR(a), 0, 64);
150 aom_memset16(CONVERT_TO_SHORTPTR(b), 65535, 64);
151 CONVERT_TO_SHORTPTR(b)[i] = i; // Set a minimum difference of i.
152
153 int min, max;
154 API_REGISTER_STATE_CHECK(mm_func_(a, 8, b, 8, &min, &max));
155 EXPECT_EQ(65535, max);
156 EXPECT_EQ(i, min);
157 }
158 aom_free(CONVERT_TO_SHORTPTR(a));
159 aom_free(CONVERT_TO_SHORTPTR(b));
160 }
161
TEST_P(HBDMinMaxTest,MaxValue)162 TEST_P(HBDMinMaxTest, MaxValue) {
163 uint8_t *a = CONVERT_TO_BYTEPTR(
164 reinterpret_cast<uint16_t *>(aom_malloc(64 * sizeof(uint16_t))));
165 uint8_t *b = CONVERT_TO_BYTEPTR(
166 reinterpret_cast<uint16_t *>(aom_malloc(64 * sizeof(uint16_t))));
167 for (int i = 0; i < 64; i++) {
168 aom_memset16(CONVERT_TO_SHORTPTR(a), 0, 64);
169 aom_memset16(CONVERT_TO_SHORTPTR(b), 0, 64);
170 CONVERT_TO_SHORTPTR(b)[i] = i; // Set a minimum difference of i.
171
172 int min, max;
173 API_REGISTER_STATE_CHECK(mm_func_(a, 8, b, 8, &min, &max));
174 EXPECT_EQ(i, max);
175 EXPECT_EQ(0, min);
176 }
177 aom_free(CONVERT_TO_SHORTPTR(a));
178 aom_free(CONVERT_TO_SHORTPTR(b));
179 }
180
TEST_P(HBDMinMaxTest,CompareReference)181 TEST_P(HBDMinMaxTest, CompareReference) {
182 uint8_t *a = CONVERT_TO_BYTEPTR(
183 reinterpret_cast<uint16_t *>(aom_malloc(64 * sizeof(uint16_t))));
184 uint8_t *b = CONVERT_TO_BYTEPTR(
185 reinterpret_cast<uint16_t *>(aom_malloc(64 * sizeof(uint16_t))));
186 for (int j = 0; j < 64; j++) {
187 CONVERT_TO_SHORTPTR(a)[j] = rnd_.Rand16();
188 CONVERT_TO_SHORTPTR(b)[j] = rnd_.Rand16();
189 }
190
191 int min_ref, max_ref, min, max;
192 highbd_reference_minmax(a, 8, b, 8, &min_ref, &max_ref);
193 API_REGISTER_STATE_CHECK(mm_func_(a, 8, b, 8, &min, &max));
194 aom_free(CONVERT_TO_SHORTPTR(a));
195 aom_free(CONVERT_TO_SHORTPTR(b));
196 EXPECT_EQ(max_ref, max);
197 EXPECT_EQ(min_ref, min);
198 }
199
TEST_P(HBDMinMaxTest,CompareReferenceAndVaryStride)200 TEST_P(HBDMinMaxTest, CompareReferenceAndVaryStride) {
201 uint8_t *a = CONVERT_TO_BYTEPTR(
202 reinterpret_cast<uint16_t *>(aom_malloc((8 * 64) * sizeof(uint16_t))));
203 uint8_t *b = CONVERT_TO_BYTEPTR(
204 reinterpret_cast<uint16_t *>(aom_malloc((8 * 64) * sizeof(uint16_t))));
205 for (int i = 0; i < 8 * 64; i++) {
206 CONVERT_TO_SHORTPTR(a)[i] = rnd_.Rand16();
207 CONVERT_TO_SHORTPTR(b)[i] = rnd_.Rand16();
208 }
209 for (int a_stride = 8; a_stride <= 64; a_stride += 8) {
210 for (int b_stride = 8; b_stride <= 64; b_stride += 8) {
211 int min_ref, max_ref, min, max;
212 highbd_reference_minmax(a, a_stride, b, b_stride, &min_ref, &max_ref);
213 API_REGISTER_STATE_CHECK(mm_func_(a, a_stride, b, b_stride, &min, &max));
214 EXPECT_EQ(max_ref, max)
215 << "when a_stride = " << a_stride << " and b_stride = " << b_stride;
216 EXPECT_EQ(min_ref, min)
217 << "when a_stride = " << a_stride << " and b_stride = " << b_stride;
218 }
219 }
220 aom_free(CONVERT_TO_SHORTPTR(a));
221 aom_free(CONVERT_TO_SHORTPTR(b));
222 }
223 #endif // CONFIG_AV1_HIGHBITDEPTH
224
225 INSTANTIATE_TEST_SUITE_P(C, MinMaxTest, ::testing::Values(&aom_minmax_8x8_c));
226 #if CONFIG_AV1_HIGHBITDEPTH
227 INSTANTIATE_TEST_SUITE_P(C, HBDMinMaxTest,
228 ::testing::Values(&aom_highbd_minmax_8x8_c));
229 #if HAVE_NEON
230 INSTANTIATE_TEST_SUITE_P(NEON, HBDMinMaxTest,
231 ::testing::Values(&aom_highbd_minmax_8x8_neon));
232 #endif
233 #endif
234
235 #if HAVE_SSE2
236 INSTANTIATE_TEST_SUITE_P(SSE2, MinMaxTest,
237 ::testing::Values(&aom_minmax_8x8_sse2));
238 #endif
239
240 #if HAVE_NEON
241 INSTANTIATE_TEST_SUITE_P(NEON, MinMaxTest,
242 ::testing::Values(&aom_minmax_8x8_neon));
243 #endif
244 } // namespace
245