]> git.sesse.net Git - ffmpeg/blob - tests/checkasm/hevc_mc.c
checkasm: hevc: Iterate over features first, then over bitdepths
[ffmpeg] / 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 }