1 /*
2  *  Copyright (c) 2015 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 <stdlib.h>
12 
13 #include "./vpx_config.h"
14 #include "./vpx_dsp_rtcd.h"
15 
16 #include "vpx/vpx_integer.h"
17 #include "vpx_ports/mem.h"
18 
19 /* 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)20 static INLINE unsigned int sad(const uint8_t *a, int a_stride, const uint8_t *b,
21                                int b_stride, int width, int height) {
22   int y, x;
23   unsigned int sad = 0;
24 
25   for (y = 0; y < height; y++) {
26     for (x = 0; x < width; x++) sad += abs(a[x] - b[x]);
27 
28     a += a_stride;
29     b += b_stride;
30   }
31   return sad;
32 }
33 
34 #define sadMxN(m, n)                                                        \
35   unsigned int vpx_sad##m##x##n##_c(const uint8_t *src, int src_stride,     \
36                                     const uint8_t *ref, int ref_stride) {   \
37     return sad(src, src_stride, ref, ref_stride, m, n);                     \
38   }                                                                         \
39   unsigned int vpx_sad##m##x##n##_avg_c(const uint8_t *src, int src_stride, \
40                                         const uint8_t *ref, int ref_stride, \
41                                         const uint8_t *second_pred) {       \
42     DECLARE_ALIGNED(16, uint8_t, comp_pred[m * n]);                         \
43     vpx_comp_avg_pred_c(comp_pred, second_pred, m, n, ref, ref_stride);     \
44     return sad(src, src_stride, comp_pred, m, m, n);                        \
45   }
46 
47 // depending on call sites, pass **ref_array to avoid & in subsequent call and
48 // de-dup with 4D below.
49 #define sadMxNxK(m, n, k)                                                   \
50   void vpx_sad##m##x##n##x##k##_c(const uint8_t *src, int src_stride,       \
51                                   const uint8_t *ref_array, int ref_stride, \
52                                   uint32_t *sad_array) {                    \
53     int i;                                                                  \
54     for (i = 0; i < k; ++i)                                                 \
55       sad_array[i] =                                                        \
56           vpx_sad##m##x##n##_c(src, src_stride, &ref_array[i], ref_stride); \
57   }
58 
59 // This appears to be equivalent to the above when k == 4 and refs is const
60 #define sadMxNx4D(m, n)                                                    \
61   void vpx_sad##m##x##n##x4d_c(const uint8_t *src, int src_stride,         \
62                                const uint8_t *const ref_array[],           \
63                                int ref_stride, uint32_t *sad_array) {      \
64     int i;                                                                 \
65     for (i = 0; i < 4; ++i)                                                \
66       sad_array[i] =                                                       \
67           vpx_sad##m##x##n##_c(src, src_stride, ref_array[i], ref_stride); \
68   }
69 
70 /* clang-format off */
71 // 64x64
72 sadMxN(64, 64)
73 sadMxNxK(64, 64, 3)
74 sadMxNxK(64, 64, 8)
75 sadMxNx4D(64, 64)
76 
77 // 64x32
78 sadMxN(64, 32)
79 sadMxNx4D(64, 32)
80 
81 // 32x64
82 sadMxN(32, 64)
83 sadMxNx4D(32, 64)
84 
85 // 32x32
86 sadMxN(32, 32)
87 sadMxNxK(32, 32, 3)
88 sadMxNxK(32, 32, 8)
89 sadMxNx4D(32, 32)
90 
91 // 32x16
92 sadMxN(32, 16)
93 sadMxNx4D(32, 16)
94 
95 // 16x32
96 sadMxN(16, 32)
97 sadMxNx4D(16, 32)
98 
99 // 16x16
100 sadMxN(16, 16)
101 sadMxNxK(16, 16, 3)
102 sadMxNxK(16, 16, 8)
103 sadMxNx4D(16, 16)
104 
105 // 16x8
106 sadMxN(16, 8)
107 sadMxNxK(16, 8, 3)
108 sadMxNxK(16, 8, 8)
109 sadMxNx4D(16, 8)
110 
111 // 8x16
112 sadMxN(8, 16)
113 sadMxNxK(8, 16, 3)
114 sadMxNxK(8, 16, 8)
115 sadMxNx4D(8, 16)
116 
117 // 8x8
118 sadMxN(8, 8)
119 sadMxNxK(8, 8, 3)
120 sadMxNxK(8, 8, 8)
121 sadMxNx4D(8, 8)
122 
123 // 8x4
124 sadMxN(8, 4)
125 sadMxNxK(8, 4, 8)
126 sadMxNx4D(8, 4)
127 
128 // 4x8
129 sadMxN(4, 8)
130 sadMxNxK(4, 8, 8)
131 sadMxNx4D(4, 8)
132 
133 // 4x4
134 sadMxN(4, 4)
135 sadMxNxK(4, 4, 3)
136 sadMxNxK(4, 4, 8)
137 sadMxNx4D(4, 4)
138 /* clang-format on */
139 
140 #if CONFIG_VP9_HIGHBITDEPTH
141         static INLINE
highbd_sad(const uint8_t * a8,int a_stride,const uint8_t * b8,int b_stride,int width,int height)142     unsigned int highbd_sad(const uint8_t *a8, int a_stride, const uint8_t *b8,
143                             int b_stride, int width, int height) {
144   int y, x;
145   unsigned int sad = 0;
146   const uint16_t *a = CONVERT_TO_SHORTPTR(a8);
147   const uint16_t *b = CONVERT_TO_SHORTPTR(b8);
148   for (y = 0; y < height; y++) {
149     for (x = 0; x < width; x++) sad += abs(a[x] - b[x]);
150 
151     a += a_stride;
152     b += b_stride;
153   }
154   return sad;
155 }
156 
highbd_sadb(const uint8_t * a8,int a_stride,const uint16_t * b,int b_stride,int width,int height)157 static INLINE unsigned int highbd_sadb(const uint8_t *a8, int a_stride,
158                                        const uint16_t *b, int b_stride,
159                                        int width, int height) {
160   int y, x;
161   unsigned int sad = 0;
162   const uint16_t *a = CONVERT_TO_SHORTPTR(a8);
163   for (y = 0; y < height; y++) {
164     for (x = 0; x < width; x++) sad += abs(a[x] - b[x]);
165 
166     a += a_stride;
167     b += b_stride;
168   }
169   return sad;
170 }
171 
172 #define highbd_sadMxN(m, n)                                                    \
173   unsigned int vpx_highbd_sad##m##x##n##_c(const uint8_t *src, int src_stride, \
174                                            const uint8_t *ref,                 \
175                                            int ref_stride) {                   \
176     return highbd_sad(src, src_stride, ref, ref_stride, m, n);                 \
177   }                                                                            \
178   unsigned int vpx_highbd_sad##m##x##n##_avg_c(                                \
179       const uint8_t *src, int src_stride, const uint8_t *ref, int ref_stride,  \
180       const uint8_t *second_pred) {                                            \
181     DECLARE_ALIGNED(16, uint16_t, comp_pred[m * n]);                           \
182     vpx_highbd_comp_avg_pred_c(comp_pred, second_pred, m, n, ref, ref_stride); \
183     return highbd_sadb(src, src_stride, comp_pred, m, m, n);                   \
184   }
185 
186 #define highbd_sadMxNxK(m, n, k)                                             \
187   void vpx_highbd_sad##m##x##n##x##k##_c(                                    \
188       const uint8_t *src, int src_stride, const uint8_t *ref_array,          \
189       int ref_stride, uint32_t *sad_array) {                                 \
190     int i;                                                                   \
191     for (i = 0; i < k; ++i) {                                                \
192       sad_array[i] = vpx_highbd_sad##m##x##n##_c(src, src_stride,            \
193                                                  &ref_array[i], ref_stride); \
194     }                                                                        \
195   }
196 
197 #define highbd_sadMxNx4D(m, n)                                               \
198   void vpx_highbd_sad##m##x##n##x4d_c(const uint8_t *src, int src_stride,    \
199                                       const uint8_t *const ref_array[],      \
200                                       int ref_stride, uint32_t *sad_array) { \
201     int i;                                                                   \
202     for (i = 0; i < 4; ++i) {                                                \
203       sad_array[i] = vpx_highbd_sad##m##x##n##_c(src, src_stride,            \
204                                                  ref_array[i], ref_stride);  \
205     }                                                                        \
206   }
207 
208 /* clang-format off */
209 // 64x64
210 highbd_sadMxN(64, 64)
211 highbd_sadMxNxK(64, 64, 3)
212 highbd_sadMxNxK(64, 64, 8)
213 highbd_sadMxNx4D(64, 64)
214 
215 // 64x32
216 highbd_sadMxN(64, 32)
217 highbd_sadMxNx4D(64, 32)
218 
219 // 32x64
220 highbd_sadMxN(32, 64)
221 highbd_sadMxNx4D(32, 64)
222 
223 // 32x32
224 highbd_sadMxN(32, 32)
225 highbd_sadMxNxK(32, 32, 3)
226 highbd_sadMxNxK(32, 32, 8)
227 highbd_sadMxNx4D(32, 32)
228 
229 // 32x16
230 highbd_sadMxN(32, 16)
231 highbd_sadMxNx4D(32, 16)
232 
233 // 16x32
234 highbd_sadMxN(16, 32)
235 highbd_sadMxNx4D(16, 32)
236 
237 // 16x16
238 highbd_sadMxN(16, 16)
239 highbd_sadMxNxK(16, 16, 3)
240 highbd_sadMxNxK(16, 16, 8)
241 highbd_sadMxNx4D(16, 16)
242 
243 // 16x8
244 highbd_sadMxN(16, 8)
245 highbd_sadMxNxK(16, 8, 3)
246 highbd_sadMxNxK(16, 8, 8)
247 highbd_sadMxNx4D(16, 8)
248 
249 // 8x16
250 highbd_sadMxN(8, 16)
251 highbd_sadMxNxK(8, 16, 3)
252 highbd_sadMxNxK(8, 16, 8)
253 highbd_sadMxNx4D(8, 16)
254 
255 // 8x8
256 highbd_sadMxN(8, 8)
257 highbd_sadMxNxK(8, 8, 3)
258 highbd_sadMxNxK(8, 8, 8)
259 highbd_sadMxNx4D(8, 8)
260 
261 // 8x4
262 highbd_sadMxN(8, 4)
263 highbd_sadMxNxK(8, 4, 8)
264 highbd_sadMxNx4D(8, 4)
265 
266 // 4x8
267 highbd_sadMxN(4, 8)
268 highbd_sadMxNxK(4, 8, 8)
269 highbd_sadMxNx4D(4, 8)
270 
271 // 4x4
272 highbd_sadMxN(4, 4)
273 highbd_sadMxNxK(4, 4, 3)
274 highbd_sadMxNxK(4, 4, 8)
275 highbd_sadMxNx4D(4, 4)
276 /* clang-format on */
277 
278 #endif  // CONFIG_VP9_HIGHBITDEPTH
279