385c33eec7c50c7bffaaced31f04f2c57ea967fd
[libav.git] / tests / checkasm / hevc_mc.c
1 /*
2 * Copyright (c) 2015 Anton Khirnov
3 *
4 * This file is part of Libav.
5 *
6 * Libav is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * Libav is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with Libav; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21 #include <string.h>
22
23 #include "checkasm.h"
24
25 #include "libavcodec/avcodec.h"
26 #include "libavcodec/hevcdsp.h"
27
28 #include "libavutil/common.h"
29 #include "libavutil/intreadwrite.h"
30
31 // max PU size + interpolation stencil
32 #define BUF_SIZE (FFALIGN(64 + 7, 16) * (64 + 7) * 2)
33
34 #define PIXEL_SIZE(depth) ((depth + 7) / 8)
35
36 #define randomize_buffers(buf, size, depth) \
37 do { \
38 uint32_t mask = pixel_mask[depth - 8]; \
39 int i; \
40 for (i = 0; i < size; i += 4) { \
41 uint32_t r = rnd() & mask; \
42 AV_WN32A(buf + i, r); \
43 } \
44 } while (0)
45
46 static const uint32_t pixel_mask[3] = { 0xffffffff, 0x01ff01ff, 0x03ff03ff };
47
48 static const int pred_heights[][7] = {
49 [2] = { 8, 4, 2, 0 },
50 [4] = { 16, 8, 4, 2, 0 },
51 [6] = { 8, 0 },
52 [8] = { 32, 16, 8, 4, 2, 0 },
53 [12] = { 16, 0 },
54 [16] = { 64, 32, 16, 12, 8, 4, 0 },
55 [24] = { 32, 0 },
56 [32] = { 64, 32, 24, 16, 8, 0 },
57 [48] = { 64, 0 },
58 [64] = { 64, 48, 32, 16, 0 },
59 };
60
61 static const int pred_widths[] = { 4, 8, 12, 16, 24, 32, 48, 64 };
62
63 static const char *interp_names[2][2] = { { "pixels", "h" }, { "v", "hv" } };
64
65 #define UNWEIGHTED_PRED(dst0, dst1, src0, width, bit_depth) \
66 do { \
67 int i; \
68 for (i = 0; i < FF_ARRAY_ELEMS(pred_heights[i]); i++) { \
69 int height = pred_heights[width][i]; \
70 if (!height) \
71 break; \
72 call_ref(dst0, dststride, src0, srcstride, height); \
73 call_new(dst1, dststride, src0, srcstride, height); \
74 if (memcmp(dst0, dst1, dststride * height)) \
75 fail(); \
76 bench_new(dst1, dststride, src0, srcstride, height); \
77 } \
78 } while (0)
79
80 #define UNWEIGHTED_PRED_AVG(dst0, dst1, src0, src1, width, bit_depth) \
81 do { \
82 int i; \
83 for (i = 0; i < FF_ARRAY_ELEMS(pred_heights[i]); i++) { \
84 int height = pred_heights[width][i]; \
85 if (!height) \
86 break; \
87 call_ref(dst0, dststride, src0, src1, srcstride, height); \
88 call_new(dst1, dststride, src0, src1, srcstride, height); \
89 if (memcmp(dst0, dst1, dststride * height)) \
90 fail(); \
91 bench_new(dst1, dststride, src0, src1, srcstride, height); \
92 } \
93 } while (0)
94
95 static void check_unweighted_pred(HEVCDSPContext *h, uint8_t *dst0, uint8_t *dst1,
96 int16_t *src0, int16_t *src1, int bit_depth)
97 {
98 int i;
99
100 randomize_buffers(src0, BUF_SIZE, 8);
101 randomize_buffers(src1, BUF_SIZE, 8);
102
103 memset(dst0, 0, BUF_SIZE * sizeof(*dst0));
104 memset(dst1, 0, BUF_SIZE * sizeof(*dst1));
105
106 for (i = 0; i < FF_ARRAY_ELEMS(pred_widths); i++) {
107 const int width = pred_widths[i];
108 const int srcstride = FFALIGN(width, 16) * sizeof(*src0);
109 const int dststride = FFALIGN(width, 16) * PIXEL_SIZE(bit_depth);
110
111 {
112 declare_func(void, uint8_t *dst, ptrdiff_t dststride, int16_t *src, ptrdiff_t srcstride, int height);
113 if (check_func(h->put_unweighted_pred[i], "put_unweighted_pred_%d_%d", width, bit_depth))
114 UNWEIGHTED_PRED(dst0, dst1, src0, width, bit_depth);
115 if (check_func(h->put_unweighted_pred_chroma[i], "put_unweighted_pred_%d_%d", width / 2, bit_depth))
116 UNWEIGHTED_PRED(dst0, dst1, src0, width, bit_depth);
117 }
118 {
119 declare_func(void, uint8_t *dst, ptrdiff_t dststride,
120 int16_t *src0, int16_t *src1, ptrdiff_t srcstride, int height);
121 if (check_func(h->put_unweighted_pred_avg[i], "put_unweighted_pred_avg_%d_%d", width, bit_depth))
122 UNWEIGHTED_PRED_AVG(dst0, dst1, src0, src1, width, bit_depth);
123 if (check_func(h->put_unweighted_pred_avg_chroma[i], "put_unweighted_pred_avg_%d_%d", width / 2, bit_depth))
124 UNWEIGHTED_PRED_AVG(dst0, dst1, src0, src1, width, bit_depth);
125 }
126 }
127 }
128
129 #define WEIGHTED_PRED(dst0, dst1, src0, width, bit_depth) \
130 do { \
131 int i; \
132 for (i = 0; i < FF_ARRAY_ELEMS(pred_heights[i]); i++) { \
133 int height = pred_heights[width][i]; \
134 if (!height) \
135 break; \
136 call_ref(denom, weight0, offset0, dst0, dststride, src0, srcstride, height); \
137 call_new(denom, weight0, offset0, dst1, dststride, src0, srcstride, height); \
138 if (memcmp(dst0, dst1, dststride * height)) \
139 fail(); \
140 bench_new(denom, weight0, offset0, dst1, dststride, src0, srcstride, height); \
141 } \
142 } while (0)
143
144 #define WEIGHTED_PRED_AVG(dst0, dst1, src0, src1, width, bit_depth) \
145 do { \
146 int i; \
147 for (i = 0; i < FF_ARRAY_ELEMS(pred_heights[i]); i++) { \
148 int height = pred_heights[width][i]; \
149 if (!height) \
150 break; \
151 call_ref(denom, weight0, weight1, offset0, offset1, dst0, dststride, src0, src1, srcstride, height); \
152 call_new(denom, weight0, weight1, offset0, offset1, dst1, dststride, src0, src1, srcstride, height); \
153 if (memcmp(dst0, dst1, dststride * height)) \
154 fail(); \
155 bench_new(denom, weight0, weight1, offset0, offset1, dst1, dststride, src0, src1, srcstride, height); \
156 } \
157 } while (0)
158
159 static void check_weighted_pred(HEVCDSPContext *h, uint8_t *dst0, uint8_t *dst1,
160 int16_t *src0, int16_t *src1, int bit_depth)
161 {
162 uint8_t denom;
163 int16_t weight0, weight1, offset0, offset1;
164 int i;
165
166 randomize_buffers(src0, BUF_SIZE, 8);
167 randomize_buffers(src1, BUF_SIZE, 8);
168
169 denom = rnd() & 7;
170 weight0 = denom + ((rnd() & 255) - 128);
171 weight1 = denom + ((rnd() & 255) - 128);
172 offset0 = (rnd() & 255) - 128;
173 offset1 = (rnd() & 255) - 128;
174
175 memset(dst0, 0, BUF_SIZE * sizeof(*dst0));
176 memset(dst1, 0, BUF_SIZE * sizeof(*dst1));
177
178 for (i = 0; i < FF_ARRAY_ELEMS(pred_widths); i++) {
179 const int width = pred_widths[i];
180 const int srcstride = FFALIGN(width, 16) * sizeof(*src0);
181 const int dststride = FFALIGN(width, 16) * PIXEL_SIZE(bit_depth);
182
183 {
184 declare_func(void, uint8_t denom, int16_t weight, int16_t offset,
185 uint8_t *dst, ptrdiff_t dststride, int16_t *src, ptrdiff_t srcstride, int height);
186 if (check_func(h->weighted_pred[i], "weighted_pred_%d_%d", width, bit_depth))
187 WEIGHTED_PRED(dst0, dst1, src0, width, bit_depth);
188 if (check_func(h->weighted_pred_chroma[i], "weighted_pred_%d_%d", width / 2, bit_depth))
189 WEIGHTED_PRED(dst0, dst1, src0, width, bit_depth);
190 }
191 {
192 declare_func(void, uint8_t denom, int16_t weight0, int16_t weight1, int16_t offset0, int16_t offset1,
193 uint8_t *dst, ptrdiff_t dststride, int16_t *src0, int16_t *src1, ptrdiff_t srcstride, int height);
194 if (check_func(h->weighted_pred_avg[i], "weighted_pred_avg_%d_%d", width, bit_depth))
195 WEIGHTED_PRED_AVG(dst0, dst1, src0, src1, width, bit_depth);
196 if (check_func(h->weighted_pred_avg_chroma[i], "weighted_pred_avg_%d_%d", width / 2, bit_depth))
197 WEIGHTED_PRED_AVG(dst0, dst1, src0, src1, width, bit_depth);
198 }
199 }
200 }
201
202 static void check_epel(HEVCDSPContext *h, int16_t *dst0, int16_t *dst1,
203 uint8_t *src, int16_t *mcbuffer, int bit_depth)
204 {
205 int i, j, k, l, mx, my;
206
207 declare_func(void, int16_t *dst, ptrdiff_t dststride, uint8_t *src, ptrdiff_t srcstride,
208 int height, int mx, int my, int16_t *mcbuffer);
209
210 randomize_buffers(src, BUF_SIZE, bit_depth);
211
212 memset(dst0, 0, BUF_SIZE * sizeof(*dst0));
213 memset(dst1, 0, BUF_SIZE * sizeof(*dst1));
214
215 for (i = 0; i < 2; i++) {
216 for (j = 0; j < 2; j++) {
217 for (k = 0; k < FF_ARRAY_ELEMS(h->put_hevc_epel[i][j]); k++) {
218 int width = pred_widths[k] / 2;
219 int dststride = FFALIGN(width, 16) * sizeof(*dst0);
220 int srcstride = FFALIGN(width + 3, 8) * PIXEL_SIZE(bit_depth);
221
222 if (!check_func(h->put_hevc_epel[i][j][k], "epel_%s_%d_%d", interp_names[i][j], width, bit_depth))
223 continue;
224
225 for (l = 0; l < FF_ARRAY_ELEMS(pred_heights[0]); l++) {
226 int height = pred_heights[width][l];
227
228 if (!height)
229 continue;
230
231 for (my = i; my < (i ? 8 : 1); my++)
232 for (mx = j; mx < (j ? 8 : 1); mx++) {
233 call_ref(dst0, dststride, src + srcstride + PIXEL_SIZE(bit_depth), srcstride, height, mx, my, mcbuffer);
234 call_new(dst1, dststride, src + srcstride + PIXEL_SIZE(bit_depth), srcstride, height, mx, my, mcbuffer);
235
236 if (memcmp(dst0, dst1, dststride * height * sizeof(*dst0)))
237 fail();
238
239 bench_new(dst1, dststride, src + srcstride + PIXEL_SIZE(bit_depth), srcstride, height, mx, my, mcbuffer);
240 }
241 }
242 }
243 }
244 }
245 }
246
247 static void check_qpel(HEVCDSPContext *h, int16_t *dst0, int16_t *dst1,
248 uint8_t *src, int16_t *mcbuffer, int bit_depth)
249 {
250 int i, j, k, l, mx, my;
251
252 declare_func(void, int16_t *dst, ptrdiff_t dststride, uint8_t *src, ptrdiff_t srcstride,
253 int height, int mx, int my, int16_t *mcbuffer);
254
255 randomize_buffers(src, BUF_SIZE, bit_depth);
256
257 memset(dst0, 0, BUF_SIZE * sizeof(*dst0));
258 memset(dst1, 0, BUF_SIZE * sizeof(*dst1));
259
260 for (i = 0; i < 2; i++) {
261 for (j = 0; j < 2; j++) {
262 for (k = 0; k < FF_ARRAY_ELEMS(h->put_hevc_qpel[i][j]); k++) {
263 int width = pred_widths[k];
264 int dststride = FFALIGN(width, 16) * sizeof(*dst0);
265 int srcstride = FFALIGN(width + 7, 8) * PIXEL_SIZE(bit_depth);
266
267 if (!check_func(h->put_hevc_qpel[i][j][k], "qpel_%s_%d_%d", interp_names[i][j], width, bit_depth))
268 continue;
269
270 for (l = 0; l < FF_ARRAY_ELEMS(pred_heights[0]); l++) {
271 int height = pred_heights[width][l];
272
273 if (!height)
274 continue;
275
276 for (my = i; my < (i ? 2 : 1); my++)
277 for (mx = j; mx < (j ? 2 : 1); mx++) {
278 call_ref(dst0, dststride, src + 3 * srcstride + 3 * PIXEL_SIZE(bit_depth), srcstride, height, mx, my, mcbuffer);
279 call_new(dst1, dststride, src + 3 * srcstride + 3 * PIXEL_SIZE(bit_depth), srcstride, height, mx, my, mcbuffer);
280
281 if (memcmp(dst0, dst1, dststride * height * sizeof(*dst0)))
282 fail();
283
284 bench_new(dst1, dststride, src + 3 * srcstride + 3 * PIXEL_SIZE(bit_depth), srcstride, height, mx, my, mcbuffer);
285 }
286 }
287 }
288 }
289 }
290 }
291
292 void checkasm_check_hevc_mc(void)
293 {
294 DECLARE_ALIGNED(16, uint8_t, buf8_0)[BUF_SIZE];
295 DECLARE_ALIGNED(16, uint8_t, buf8_1)[BUF_SIZE];
296
297 DECLARE_ALIGNED(16, int16_t, buf16_0)[BUF_SIZE];
298 DECLARE_ALIGNED(16, int16_t, buf16_1)[BUF_SIZE];
299
300 DECLARE_ALIGNED(16, int16_t, mcbuffer)[BUF_SIZE];
301
302 HEVCDSPContext h;
303 int bit_depth;
304
305 for (bit_depth = 8; bit_depth <= 10; bit_depth++) {
306 ff_hevc_dsp_init(&h, bit_depth);
307 check_qpel(&h, buf16_0, buf16_1, buf8_0, mcbuffer, bit_depth);
308 }
309 report("qpel");
310
311 for (bit_depth = 8; bit_depth <= 10; bit_depth++) {
312 ff_hevc_dsp_init(&h, bit_depth);
313 check_epel(&h, buf16_0, buf16_1, buf8_0, mcbuffer, bit_depth);
314 }
315 report("epel");
316
317 for (bit_depth = 8; bit_depth <= 10; bit_depth++) {
318 ff_hevc_dsp_init(&h, bit_depth);
319 check_unweighted_pred(&h, buf8_0, buf8_1, buf16_0, buf16_1, bit_depth);
320 }
321 report("unweighted_pred");
322
323 for (bit_depth = 8; bit_depth <= 10; bit_depth++) {
324 ff_hevc_dsp_init(&h, bit_depth);
325 check_weighted_pred(&h, buf8_0, buf8_1, buf16_0, buf16_1, bit_depth);
326 }
327 report("weighted_pred");
328 }