1 /*
2 * Copyright (c) 2016, Alliance for Open Media. All rights reserved.
3 *
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.
10 */
11
12 #include <stdlib.h>
13
14 #include "config/aom_config.h"
15 #include "config/aom_dsp_rtcd.h"
16
17 #include "aom/aom_integer.h"
18 #include "aom_ports/mem.h"
19 #include "aom_dsp/blend.h"
20
21 /* Sum the difference between every corresponding element of the buffers. */
sad(const uint8_t * a,int a_stride,const uint8_t * b,int b_stride,int width,int height)22 static inline unsigned int sad(const uint8_t *a, int a_stride, const uint8_t *b,
23 int b_stride, int width, int height) {
24 int y, x;
25 unsigned int sad = 0;
26
27 for (y = 0; y < height; y++) {
28 for (x = 0; x < width; x++) {
29 sad += abs(a[x] - b[x]);
30 }
31
32 a += a_stride;
33 b += b_stride;
34 }
35 return sad;
36 }
37
38 #define SADMXN(m, n) \
39 unsigned int aom_sad##m##x##n##_c(const uint8_t *src, int src_stride, \
40 const uint8_t *ref, int ref_stride) { \
41 return sad(src, src_stride, ref, ref_stride, m, n); \
42 }
43
44 #define SADMXN_AVG(m, n) \
45 unsigned int aom_sad##m##x##n##_avg_c(const uint8_t *src, int src_stride, \
46 const uint8_t *ref, int ref_stride, \
47 const uint8_t *second_pred) { \
48 uint8_t comp_pred[m * n]; \
49 aom_comp_avg_pred(comp_pred, second_pred, m, n, ref, ref_stride); \
50 return sad(src, src_stride, comp_pred, m, m, n); \
51 }
52
53 #define SADMXN_SKIP(m, n) \
54 unsigned int aom_sad_skip_##m##x##n##_c(const uint8_t *src, int src_stride, \
55 const uint8_t *ref, \
56 int ref_stride) { \
57 return 2 * sad(src, 2 * src_stride, ref, 2 * ref_stride, (m), (n / 2)); \
58 }
59
60 #define SADMXN_NO_SKIP(m, n) \
61 SADMXN(m, n) \
62 SADMXN_AVG(m, n)
63
64 #define SADMXN_NO_AVG(m, n) \
65 SADMXN(m, n) \
66 SADMXN_SKIP(m, n)
67
68 #define SADMXN_ALL(m, n) \
69 SADMXN(m, n) \
70 SADMXN_AVG(m, n) \
71 SADMXN_SKIP(m, n)
72
73 // Calculate sad against 4 reference locations and store each in sad_array
74 #define SAD_MXNX4D_NO_SKIP(m, n) \
75 void aom_sad##m##x##n##x4d_c(const uint8_t *src, int src_stride, \
76 const uint8_t *const ref_array[4], \
77 int ref_stride, uint32_t sad_array[4]) { \
78 int i; \
79 for (i = 0; i < 4; ++i) { \
80 sad_array[i] = \
81 aom_sad##m##x##n##_c(src, src_stride, ref_array[i], ref_stride); \
82 } \
83 }
84
85 #define SAD_MXNX4D(m, n) \
86 SAD_MXNX4D_NO_SKIP(m, n) \
87 void aom_sad_skip_##m##x##n##x4d_c(const uint8_t *src, int src_stride, \
88 const uint8_t *const ref_array[4], \
89 int ref_stride, uint32_t sad_array[4]) { \
90 int i; \
91 for (i = 0; i < 4; ++i) { \
92 sad_array[i] = 2 * sad(src, 2 * src_stride, ref_array[i], \
93 2 * ref_stride, (m), (n / 2)); \
94 } \
95 }
96 // Call SIMD version of aom_sad_mxnx4d if the 3d version is unavailable.
97 #define SAD_MXNX3D(m, n) \
98 void aom_sad##m##x##n##x3d_c(const uint8_t *src, int src_stride, \
99 const uint8_t *const ref_array[4], \
100 int ref_stride, uint32_t sad_array[4]) { \
101 aom_sad##m##x##n##x4d(src, src_stride, ref_array, ref_stride, sad_array); \
102 }
103
104 // 128x128
105 SADMXN_ALL(128, 128)
106 SAD_MXNX4D(128, 128)
107 SAD_MXNX3D(128, 128)
108
109 // 128x64
110 SADMXN_ALL(128, 64)
111 SAD_MXNX4D(128, 64)
112 SAD_MXNX3D(128, 64)
113
114 // 64x128
115 SADMXN_ALL(64, 128)
116 SAD_MXNX4D(64, 128)
117 SAD_MXNX3D(64, 128)
118
119 // 64x64
120 SADMXN_ALL(64, 64)
121 SAD_MXNX4D(64, 64)
122 SAD_MXNX3D(64, 64)
123
124 // 64x32
125 SADMXN_ALL(64, 32)
126 SAD_MXNX4D(64, 32)
127 SAD_MXNX3D(64, 32)
128
129 // 32x64
130 SADMXN_ALL(32, 64)
131 SAD_MXNX4D(32, 64)
132 SAD_MXNX3D(32, 64)
133
134 // 32x32
135 SADMXN_ALL(32, 32)
136 SAD_MXNX4D(32, 32)
137 SAD_MXNX3D(32, 32)
138
139 // 32x16
140 SADMXN_ALL(32, 16)
141 SAD_MXNX4D(32, 16)
142 SAD_MXNX3D(32, 16)
143
144 // 16x32
145 SADMXN_ALL(16, 32)
146 SAD_MXNX4D(16, 32)
147 SAD_MXNX3D(16, 32)
148
149 // 16x16
150 SADMXN_ALL(16, 16)
151 SAD_MXNX4D(16, 16)
152 SAD_MXNX3D(16, 16)
153
154 // 16x8
155 SADMXN_NO_SKIP(16, 8)
156 SAD_MXNX4D_NO_SKIP(16, 8)
157 SAD_MXNX3D(16, 8)
158
159 // 8x16
160 SADMXN_ALL(8, 16)
161 SAD_MXNX4D(8, 16)
162 SAD_MXNX3D(8, 16)
163
164 // 8x8
165 SADMXN_NO_SKIP(8, 8)
166 SAD_MXNX4D_NO_SKIP(8, 8)
167 SAD_MXNX3D(8, 8)
168
169 // 8x4
170 SADMXN(8, 4)
171 SAD_MXNX4D_NO_SKIP(8, 4)
172 SAD_MXNX3D(8, 4)
173
174 // 4x8
175 SADMXN(4, 8)
176 SAD_MXNX4D_NO_SKIP(4, 8)
177 SAD_MXNX3D(4, 8)
178
179 // 4x4
180 SADMXN(4, 4)
181 SAD_MXNX4D_NO_SKIP(4, 4)
182 SAD_MXNX3D(4, 4)
183
184 #if !CONFIG_REALTIME_ONLY
185 SADMXN_NO_AVG(4, 16)
186 SAD_MXNX4D(4, 16)
187 SADMXN(16, 4)
188 SAD_MXNX4D_NO_SKIP(16, 4)
189 SADMXN_ALL(8, 32)
190 SAD_MXNX4D(8, 32)
191 SADMXN_NO_SKIP(32, 8)
192 SAD_MXNX4D_NO_SKIP(32, 8)
193 SADMXN_ALL(16, 64)
194 SAD_MXNX4D(16, 64)
195 SADMXN_ALL(64, 16)
196 SAD_MXNX4D(64, 16)
197 SAD_MXNX3D(4, 16)
198 SAD_MXNX3D(16, 4)
199 SAD_MXNX3D(8, 32)
200 SAD_MXNX3D(32, 8)
201 SAD_MXNX3D(16, 64)
202 SAD_MXNX3D(64, 16)
203 #endif // !CONFIG_REALTIME_ONLY
204
205 #if CONFIG_AV1_HIGHBITDEPTH
highbd_sad(const uint8_t * a8,int a_stride,const uint8_t * b8,int b_stride,int width,int height)206 static inline unsigned int highbd_sad(const uint8_t *a8, int a_stride,
207 const uint8_t *b8, int b_stride,
208 int width, int height) {
209 int y, x;
210 unsigned int sad = 0;
211 const uint16_t *a = CONVERT_TO_SHORTPTR(a8);
212 const uint16_t *b = CONVERT_TO_SHORTPTR(b8);
213 for (y = 0; y < height; y++) {
214 for (x = 0; x < width; x++) {
215 sad += abs(a[x] - b[x]);
216 }
217
218 a += a_stride;
219 b += b_stride;
220 }
221 return sad;
222 }
223
highbd_sadb(const uint8_t * a8,int a_stride,const uint8_t * b8,int b_stride,int width,int height)224 static inline unsigned int highbd_sadb(const uint8_t *a8, int a_stride,
225 const uint8_t *b8, int b_stride,
226 int width, int height) {
227 int y, x;
228 unsigned int sad = 0;
229 const uint16_t *a = CONVERT_TO_SHORTPTR(a8);
230 const uint16_t *b = CONVERT_TO_SHORTPTR(b8);
231 for (y = 0; y < height; y++) {
232 for (x = 0; x < width; x++) {
233 sad += abs(a[x] - b[x]);
234 }
235
236 a += a_stride;
237 b += b_stride;
238 }
239 return sad;
240 }
241
242 #define HIGHBD_SADMXN(m, n) \
243 unsigned int aom_highbd_sad##m##x##n##_c(const uint8_t *src, int src_stride, \
244 const uint8_t *ref, \
245 int ref_stride) { \
246 return highbd_sad(src, src_stride, ref, ref_stride, m, n); \
247 }
248
249 #define HIGHBD_SADMXN_AVG(m, n) \
250 unsigned int aom_highbd_sad##m##x##n##_avg_c( \
251 const uint8_t *src, int src_stride, const uint8_t *ref, int ref_stride, \
252 const uint8_t *second_pred) { \
253 uint16_t comp_pred[m * n]; \
254 uint8_t *const comp_pred8 = CONVERT_TO_BYTEPTR(comp_pred); \
255 aom_highbd_comp_avg_pred(comp_pred8, second_pred, m, n, ref, ref_stride); \
256 return highbd_sadb(src, src_stride, comp_pred8, m, m, n); \
257 }
258
259 #define HIGHBD_SADMXN_SKIP(m, n) \
260 unsigned int aom_highbd_sad_skip_##m##x##n##_c( \
261 const uint8_t *src, int src_stride, const uint8_t *ref, \
262 int ref_stride) { \
263 return 2 * \
264 highbd_sad(src, 2 * src_stride, ref, 2 * ref_stride, (m), (n / 2)); \
265 }
266
267 #define HIGHBD_SADMXN_NO_SKIP(m, n) \
268 HIGHBD_SADMXN(m, n) \
269 HIGHBD_SADMXN_AVG(m, n)
270
271 #define HIGHBD_SADMXN_NO_AVG(m, n) \
272 HIGHBD_SADMXN(m, n) \
273 HIGHBD_SADMXN_SKIP(m, n)
274
275 #define HIGHBD_SADMXN_ALL(m, n) \
276 HIGHBD_SADMXN(m, n) \
277 HIGHBD_SADMXN_AVG(m, n) \
278 HIGHBD_SADMXN_SKIP(m, n)
279
280 #define HIGHBD_SAD_MXNX4D_NO_SKIP(m, n) \
281 void aom_highbd_sad##m##x##n##x4d_c(const uint8_t *src, int src_stride, \
282 const uint8_t *const ref_array[4], \
283 int ref_stride, uint32_t sad_array[4]) { \
284 int i; \
285 for (i = 0; i < 4; ++i) { \
286 sad_array[i] = aom_highbd_sad##m##x##n##_c(src, src_stride, \
287 ref_array[i], ref_stride); \
288 } \
289 }
290
291 #define HIGHBD_SAD_MXNX4D(m, n) \
292 HIGHBD_SAD_MXNX4D_NO_SKIP(m, n) \
293 void aom_highbd_sad_skip_##m##x##n##x4d_c( \
294 const uint8_t *src, int src_stride, const uint8_t *const ref_array[4], \
295 int ref_stride, uint32_t sad_array[4]) { \
296 int i; \
297 for (i = 0; i < 4; ++i) { \
298 sad_array[i] = 2 * highbd_sad(src, 2 * src_stride, ref_array[i], \
299 2 * ref_stride, (m), (n / 2)); \
300 } \
301 }
302 // Call SIMD version of aom_highbd_sad_mxnx4d if the 3d version is unavailable.
303 #define HIGHBD_SAD_MXNX3D(m, n) \
304 void aom_highbd_sad##m##x##n##x3d_c(const uint8_t *src, int src_stride, \
305 const uint8_t *const ref_array[4], \
306 int ref_stride, uint32_t sad_array[4]) { \
307 aom_highbd_sad##m##x##n##x4d(src, src_stride, ref_array, ref_stride, \
308 sad_array); \
309 }
310
311 // 128x128
312 HIGHBD_SADMXN_ALL(128, 128)
313 HIGHBD_SAD_MXNX4D(128, 128)
314 HIGHBD_SAD_MXNX3D(128, 128)
315
316 // 128x64
317 HIGHBD_SADMXN_ALL(128, 64)
318 HIGHBD_SAD_MXNX4D(128, 64)
319 HIGHBD_SAD_MXNX3D(128, 64)
320
321 // 64x128
322 HIGHBD_SADMXN_ALL(64, 128)
323 HIGHBD_SAD_MXNX4D(64, 128)
324 HIGHBD_SAD_MXNX3D(64, 128)
325
326 // 64x64
327 HIGHBD_SADMXN_ALL(64, 64)
328 HIGHBD_SAD_MXNX4D(64, 64)
329 HIGHBD_SAD_MXNX3D(64, 64)
330
331 // 64x32
332 HIGHBD_SADMXN_ALL(64, 32)
333 HIGHBD_SAD_MXNX4D(64, 32)
334 HIGHBD_SAD_MXNX3D(64, 32)
335
336 // 32x64
337 HIGHBD_SADMXN_ALL(32, 64)
338 HIGHBD_SAD_MXNX4D(32, 64)
339 HIGHBD_SAD_MXNX3D(32, 64)
340
341 // 32x32
342 HIGHBD_SADMXN_ALL(32, 32)
343 HIGHBD_SAD_MXNX4D(32, 32)
344 HIGHBD_SAD_MXNX3D(32, 32)
345
346 // 32x16
347 HIGHBD_SADMXN_ALL(32, 16)
348 HIGHBD_SAD_MXNX4D(32, 16)
349 HIGHBD_SAD_MXNX3D(32, 16)
350
351 // 16x32
352 HIGHBD_SADMXN_ALL(16, 32)
353 HIGHBD_SAD_MXNX4D(16, 32)
354 HIGHBD_SAD_MXNX3D(16, 32)
355
356 // 16x16
357 HIGHBD_SADMXN_ALL(16, 16)
358 HIGHBD_SAD_MXNX4D(16, 16)
359 HIGHBD_SAD_MXNX3D(16, 16)
360
361 // 16x8
362 HIGHBD_SADMXN_NO_SKIP(16, 8)
363 HIGHBD_SAD_MXNX4D_NO_SKIP(16, 8)
364 HIGHBD_SAD_MXNX3D(16, 8)
365
366 // 8x16
367 HIGHBD_SADMXN_ALL(8, 16)
368 HIGHBD_SAD_MXNX4D(8, 16)
369 HIGHBD_SAD_MXNX3D(8, 16)
370
371 // 8x8
372 HIGHBD_SADMXN_NO_SKIP(8, 8)
373 HIGHBD_SAD_MXNX4D_NO_SKIP(8, 8)
374 HIGHBD_SAD_MXNX3D(8, 8)
375
376 // 8x4
377 HIGHBD_SADMXN(8, 4)
378 HIGHBD_SAD_MXNX4D_NO_SKIP(8, 4)
379 HIGHBD_SAD_MXNX3D(8, 4)
380
381 // 4x8
382 HIGHBD_SADMXN(4, 8)
383 HIGHBD_SAD_MXNX4D_NO_SKIP(4, 8)
384 HIGHBD_SAD_MXNX3D(4, 8)
385
386 // 4x4
387 HIGHBD_SADMXN(4, 4)
388 HIGHBD_SAD_MXNX4D_NO_SKIP(4, 4)
389 HIGHBD_SAD_MXNX3D(4, 4)
390
391 #if !CONFIG_REALTIME_ONLY
392 HIGHBD_SADMXN_NO_AVG(4, 16)
393 HIGHBD_SAD_MXNX4D(4, 16)
394 HIGHBD_SADMXN(16, 4)
395 HIGHBD_SAD_MXNX4D_NO_SKIP(16, 4)
396 HIGHBD_SADMXN_ALL(8, 32)
397 HIGHBD_SAD_MXNX4D(8, 32)
398 HIGHBD_SADMXN_NO_SKIP(32, 8)
399 HIGHBD_SAD_MXNX4D_NO_SKIP(32, 8)
400 HIGHBD_SADMXN_ALL(16, 64)
401 HIGHBD_SAD_MXNX4D(16, 64)
402 HIGHBD_SADMXN_ALL(64, 16)
403 HIGHBD_SAD_MXNX4D(64, 16)
404
405 HIGHBD_SAD_MXNX3D(4, 16)
406 HIGHBD_SAD_MXNX3D(16, 4)
407 HIGHBD_SAD_MXNX3D(8, 32)
408 HIGHBD_SAD_MXNX3D(32, 8)
409 HIGHBD_SAD_MXNX3D(16, 64)
410 HIGHBD_SAD_MXNX3D(64, 16)
411 #endif // !CONFIG_REALTIME_ONLY
412 #endif // CONFIG_AV1_HIGHBITDEPTH
413