dct-test: Remove possibility of returning a restricted exit code
[ffmpeg.git] / libavcodec / dct-test.c
1 /*
2  * (c) 2001 Fabrice Bellard
3  *     2007 Marc Hoffman <marc.hoffman@analog.com>
4  *
5  * This file is part of Libav.
6  *
7  * Libav is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * Libav is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with Libav; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21
22 /**
23  * @file
24  * DCT test (c) 2001 Fabrice Bellard
25  * Started from sample code by Juan J. Sierralta P.
26  */
27
28 #include "config.h"
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <string.h>
32 #if HAVE_UNISTD_H
33 #include <unistd.h>
34 #endif
35 #include <math.h>
36
37 #include "libavutil/cpu.h"
38 #include "libavutil/common.h"
39 #include "libavutil/lfg.h"
40 #include "libavutil/time.h"
41
42 #include "dct.h"
43 #include "simple_idct.h"
44 #include "aandcttab.h"
45 #include "faandct.h"
46 #include "faanidct.h"
47 #include "x86/idct_xvid.h"
48 #include "dctref.h"
49
50 #undef printf
51
52 // BFIN
53 void ff_bfin_idct(int16_t *block);
54 void ff_bfin_fdct(int16_t *block);
55
56 // ALTIVEC
57 void ff_fdct_altivec(int16_t *block);
58
59 // ARM
60 void ff_j_rev_dct_arm(int16_t *data);
61 void ff_simple_idct_arm(int16_t *data);
62 void ff_simple_idct_armv5te(int16_t *data);
63 void ff_simple_idct_armv6(int16_t *data);
64 void ff_simple_idct_neon(int16_t *data);
65
66 void ff_simple_idct_axp(int16_t *data);
67
68 struct algo {
69     const char *name;
70     void (*func)(int16_t *block);
71     enum formattag { NO_PERM, MMX_PERM, MMX_SIMPLE_PERM, SCALE_PERM,
72                      SSE2_PERM, PARTTRANS_PERM } format;
73     int mm_support;
74     int nonspec;
75 };
76
77 static int cpu_flags;
78
79 static const struct algo fdct_tab[] = {
80     { "REF-DBL",        ff_ref_fdct,           NO_PERM    },
81     { "FAAN",           ff_faandct,            NO_PERM    },
82     { "IJG-AAN-INT",    ff_fdct_ifast,         SCALE_PERM },
83     { "IJG-LLM-INT",    ff_jpeg_fdct_islow_8,  NO_PERM    },
84
85 #if HAVE_MMX_INLINE
86     { "MMX",            ff_fdct_mmx,           NO_PERM,   AV_CPU_FLAG_MMX     },
87 #endif
88 #if HAVE_MMXEXT_INLINE
89     { "MMXEXT",         ff_fdct_mmxext,        NO_PERM,   AV_CPU_FLAG_MMXEXT  },
90 #endif
91 #if HAVE_SSE2_INLINE
92     { "SSE2",           ff_fdct_sse2,          NO_PERM,   AV_CPU_FLAG_SSE2    },
93 #endif
94
95 #if HAVE_ALTIVEC
96     { "altivecfdct",    ff_fdct_altivec,       NO_PERM,   AV_CPU_FLAG_ALTIVEC },
97 #endif
98
99 #if ARCH_BFIN
100     { "BFINfdct",       ff_bfin_fdct,          NO_PERM  },
101 #endif
102
103     { 0 }
104 };
105
106 static const struct algo idct_tab[] = {
107     { "FAANI",          ff_faanidct,           NO_PERM  },
108     { "REF-DBL",        ff_ref_idct,           NO_PERM  },
109     { "INT",            ff_j_rev_dct,          MMX_PERM },
110     { "SIMPLE-C",       ff_simple_idct_8,      NO_PERM  },
111
112 #if HAVE_MMX_INLINE
113     { "SIMPLE-MMX",     ff_simple_idct_mmx,  MMX_SIMPLE_PERM, AV_CPU_FLAG_MMX },
114     { "XVID-MMX",       ff_idct_xvid_mmx,      NO_PERM,   AV_CPU_FLAG_MMX,  1 },
115 #endif
116 #if HAVE_MMXEXT_INLINE
117     { "XVID-MMXEXT",    ff_idct_xvid_mmxext,   NO_PERM,   AV_CPU_FLAG_MMXEXT, 1 },
118 #endif
119 #if HAVE_SSE2_INLINE
120     { "XVID-SSE2",      ff_idct_xvid_sse2,     SSE2_PERM, AV_CPU_FLAG_SSE2, 1 },
121 #endif
122
123 #if ARCH_BFIN
124     { "BFINidct",       ff_bfin_idct,          NO_PERM  },
125 #endif
126
127 #if ARCH_ARM
128     { "SIMPLE-ARM",     ff_simple_idct_arm,    NO_PERM  },
129     { "INT-ARM",        ff_j_rev_dct_arm,      MMX_PERM },
130 #endif
131 #if HAVE_ARMV5TE
132     { "SIMPLE-ARMV5TE", ff_simple_idct_armv5te,NO_PERM,   AV_CPU_FLAG_ARMV5TE },
133 #endif
134 #if HAVE_ARMV6
135     { "SIMPLE-ARMV6",   ff_simple_idct_armv6,  MMX_PERM,  AV_CPU_FLAG_ARMV6   },
136 #endif
137 #if HAVE_NEON
138     { "SIMPLE-NEON",    ff_simple_idct_neon, PARTTRANS_PERM, AV_CPU_FLAG_NEON },
139 #endif
140
141 #if ARCH_ALPHA
142     { "SIMPLE-ALPHA",   ff_simple_idct_axp,    NO_PERM },
143 #endif
144
145     { 0 }
146 };
147
148 #define AANSCALE_BITS 12
149
150 #define NB_ITS 20000
151 #define NB_ITS_SPEED 50000
152
153 static short idct_mmx_perm[64];
154
155 static short idct_simple_mmx_perm[64] = {
156     0x00, 0x08, 0x04, 0x09, 0x01, 0x0C, 0x05, 0x0D,
157     0x10, 0x18, 0x14, 0x19, 0x11, 0x1C, 0x15, 0x1D,
158     0x20, 0x28, 0x24, 0x29, 0x21, 0x2C, 0x25, 0x2D,
159     0x12, 0x1A, 0x16, 0x1B, 0x13, 0x1E, 0x17, 0x1F,
160     0x02, 0x0A, 0x06, 0x0B, 0x03, 0x0E, 0x07, 0x0F,
161     0x30, 0x38, 0x34, 0x39, 0x31, 0x3C, 0x35, 0x3D,
162     0x22, 0x2A, 0x26, 0x2B, 0x23, 0x2E, 0x27, 0x2F,
163     0x32, 0x3A, 0x36, 0x3B, 0x33, 0x3E, 0x37, 0x3F,
164 };
165
166 static const uint8_t idct_sse2_row_perm[8] = { 0, 4, 1, 5, 2, 6, 3, 7 };
167
168 static void idct_mmx_init(void)
169 {
170     int i;
171
172     /* the mmx/mmxext idct uses a reordered input, so we patch scan tables */
173     for (i = 0; i < 64; i++) {
174         idct_mmx_perm[i] = (i & 0x38) | ((i & 6) >> 1) | ((i & 1) << 2);
175     }
176 }
177
178 DECLARE_ALIGNED(16, static int16_t, block)[64];
179 DECLARE_ALIGNED(8,  static int16_t, block1)[64];
180
181 static void init_block(int16_t block[64], int test, int is_idct, AVLFG *prng)
182 {
183     int i, j;
184
185     memset(block, 0, 64 * sizeof(*block));
186
187     switch (test) {
188     case 0:
189         for (i = 0; i < 64; i++)
190             block[i] = (av_lfg_get(prng) % 512) - 256;
191         if (is_idct) {
192             ff_ref_fdct(block);
193             for (i = 0; i < 64; i++)
194                 block[i] >>= 3;
195         }
196         break;
197     case 1:
198         j = av_lfg_get(prng) % 10 + 1;
199         for (i = 0; i < j; i++)
200             block[av_lfg_get(prng) % 64] = av_lfg_get(prng) % 512 - 256;
201         break;
202     case 2:
203         block[ 0] = av_lfg_get(prng) % 4096 - 2048;
204         block[63] = (block[0] & 1) ^ 1;
205         break;
206     }
207 }
208
209 static void permute(int16_t dst[64], const int16_t src[64], int perm)
210 {
211     int i;
212
213     if (perm == MMX_PERM) {
214         for (i = 0; i < 64; i++)
215             dst[idct_mmx_perm[i]] = src[i];
216     } else if (perm == MMX_SIMPLE_PERM) {
217         for (i = 0; i < 64; i++)
218             dst[idct_simple_mmx_perm[i]] = src[i];
219     } else if (perm == SSE2_PERM) {
220         for (i = 0; i < 64; i++)
221             dst[(i & 0x38) | idct_sse2_row_perm[i & 7]] = src[i];
222     } else if (perm == PARTTRANS_PERM) {
223         for (i = 0; i < 64; i++)
224             dst[(i & 0x24) | ((i & 3) << 3) | ((i >> 3) & 3)] = src[i];
225     } else {
226         for (i = 0; i < 64; i++)
227             dst[i] = src[i];
228     }
229 }
230
231 static int dct_error(const struct algo *dct, int test, int is_idct, int speed)
232 {
233     void (*ref)(int16_t *block) = is_idct ? ff_ref_idct : ff_ref_fdct;
234     int it, i, scale;
235     int err_inf, v;
236     int64_t err2, ti, ti1, it1, err_sum = 0;
237     int64_t sysErr[64], sysErrMax = 0;
238     int maxout = 0;
239     int blockSumErrMax = 0, blockSumErr;
240     AVLFG prng;
241     double omse, ome;
242     int spec_err;
243
244     av_lfg_init(&prng, 1);
245
246     err_inf = 0;
247     err2 = 0;
248     for (i = 0; i < 64; i++)
249         sysErr[i] = 0;
250     for (it = 0; it < NB_ITS; it++) {
251         init_block(block1, test, is_idct, &prng);
252         permute(block, block1, dct->format);
253
254         dct->func(block);
255         emms_c();
256
257         if (dct->format == SCALE_PERM) {
258             for (i = 0; i < 64; i++) {
259                 scale = 8 * (1 << (AANSCALE_BITS + 11)) / ff_aanscales[i];
260                 block[i] = (block[i] * scale) >> AANSCALE_BITS;
261             }
262         }
263
264         ref(block1);
265
266         blockSumErr = 0;
267         for (i = 0; i < 64; i++) {
268             int err = block[i] - block1[i];
269             err_sum += err;
270             v = abs(err);
271             if (v > err_inf)
272                 err_inf = v;
273             err2 += v * v;
274             sysErr[i] += block[i] - block1[i];
275             blockSumErr += v;
276             if (abs(block[i]) > maxout)
277                 maxout = abs(block[i]);
278         }
279         if (blockSumErrMax < blockSumErr)
280             blockSumErrMax = blockSumErr;
281     }
282     for (i = 0; i < 64; i++)
283         sysErrMax = FFMAX(sysErrMax, FFABS(sysErr[i]));
284
285     for (i = 0; i < 64; i++) {
286         if (i % 8 == 0)
287             printf("\n");
288         printf("%7d ", (int) sysErr[i]);
289     }
290     printf("\n");
291
292     omse = (double) err2 / NB_ITS / 64;
293     ome  = (double) err_sum / NB_ITS / 64;
294
295     spec_err = is_idct && (err_inf > 1 || omse > 0.02 || fabs(ome) > 0.0015);
296
297     printf("%s %s: ppe=%d omse=%0.8f ome=%0.8f syserr=%0.8f maxout=%d blockSumErr=%d\n",
298            is_idct ? "IDCT" : "DCT", dct->name, err_inf,
299            omse, ome, (double) sysErrMax / NB_ITS,
300            maxout, blockSumErrMax);
301
302     if (spec_err && !dct->nonspec)
303         return 1;
304
305     if (!speed)
306         return 0;
307
308     /* speed test */
309     init_block(block, test, is_idct, &prng);
310     permute(block1, block, dct->format);
311
312     ti = av_gettime();
313     it1 = 0;
314     do {
315         for (it = 0; it < NB_ITS_SPEED; it++) {
316             memcpy(block, block1, sizeof(block));
317             dct->func(block);
318         }
319         it1 += NB_ITS_SPEED;
320         ti1 = av_gettime() - ti;
321     } while (ti1 < 1000000);
322     emms_c();
323
324     printf("%s %s: %0.1f kdct/s\n", is_idct ? "IDCT" : "DCT", dct->name,
325            (double) it1 * 1000.0 / (double) ti1);
326
327     return 0;
328 }
329
330 DECLARE_ALIGNED(8, static uint8_t, img_dest)[64];
331 DECLARE_ALIGNED(8, static uint8_t, img_dest1)[64];
332
333 static void idct248_ref(uint8_t *dest, int linesize, int16_t *block)
334 {
335     static int init;
336     static double c8[8][8];
337     static double c4[4][4];
338     double block1[64], block2[64], block3[64];
339     double s, sum, v;
340     int i, j, k;
341
342     if (!init) {
343         init = 1;
344
345         for (i = 0; i < 8; i++) {
346             sum = 0;
347             for (j = 0; j < 8; j++) {
348                 s = (i == 0) ? sqrt(1.0 / 8.0) : sqrt(1.0 / 4.0);
349                 c8[i][j] = s * cos(M_PI * i * (j + 0.5) / 8.0);
350                 sum += c8[i][j] * c8[i][j];
351             }
352         }
353
354         for (i = 0; i < 4; i++) {
355             sum = 0;
356             for (j = 0; j < 4; j++) {
357                 s = (i == 0) ? sqrt(1.0 / 4.0) : sqrt(1.0 / 2.0);
358                 c4[i][j] = s * cos(M_PI * i * (j + 0.5) / 4.0);
359                 sum += c4[i][j] * c4[i][j];
360             }
361         }
362     }
363
364     /* butterfly */
365     s = 0.5 * sqrt(2.0);
366     for (i = 0; i < 4; i++) {
367         for (j = 0; j < 8; j++) {
368             block1[8 * (2 * i) + j] =
369                 (block[8 * (2 * i) + j] + block[8 * (2 * i + 1) + j]) * s;
370             block1[8 * (2 * i + 1) + j] =
371                 (block[8 * (2 * i) + j] - block[8 * (2 * i + 1) + j]) * s;
372         }
373     }
374
375     /* idct8 on lines */
376     for (i = 0; i < 8; i++) {
377         for (j = 0; j < 8; j++) {
378             sum = 0;
379             for (k = 0; k < 8; k++)
380                 sum += c8[k][j] * block1[8 * i + k];
381             block2[8 * i + j] = sum;
382         }
383     }
384
385     /* idct4 */
386     for (i = 0; i < 8; i++) {
387         for (j = 0; j < 4; j++) {
388             /* top */
389             sum = 0;
390             for (k = 0; k < 4; k++)
391                 sum += c4[k][j] * block2[8 * (2 * k) + i];
392             block3[8 * (2 * j) + i] = sum;
393
394             /* bottom */
395             sum = 0;
396             for (k = 0; k < 4; k++)
397                 sum += c4[k][j] * block2[8 * (2 * k + 1) + i];
398             block3[8 * (2 * j + 1) + i] = sum;
399         }
400     }
401
402     /* clamp and store the result */
403     for (i = 0; i < 8; i++) {
404         for (j = 0; j < 8; j++) {
405             v = block3[8 * i + j];
406             if      (v < 0)   v = 0;
407             else if (v > 255) v = 255;
408             dest[i * linesize + j] = (int) rint(v);
409         }
410     }
411 }
412
413 static void idct248_error(const char *name,
414                           void (*idct248_put)(uint8_t *dest, int line_size,
415                                               int16_t *block),
416                           int speed)
417 {
418     int it, i, it1, ti, ti1, err_max, v;
419     AVLFG prng;
420
421     av_lfg_init(&prng, 1);
422
423     /* just one test to see if code is correct (precision is less
424        important here) */
425     err_max = 0;
426     for (it = 0; it < NB_ITS; it++) {
427         /* XXX: use forward transform to generate values */
428         for (i = 0; i < 64; i++)
429             block1[i] = av_lfg_get(&prng) % 256 - 128;
430         block1[0] += 1024;
431
432         for (i = 0; i < 64; i++)
433             block[i] = block1[i];
434         idct248_ref(img_dest1, 8, block);
435
436         for (i = 0; i < 64; i++)
437             block[i] = block1[i];
438         idct248_put(img_dest, 8, block);
439
440         for (i = 0; i < 64; i++) {
441             v = abs((int) img_dest[i] - (int) img_dest1[i]);
442             if (v == 255)
443                 printf("%d %d\n", img_dest[i], img_dest1[i]);
444             if (v > err_max)
445                 err_max = v;
446         }
447     }
448     printf("%s %s: err_inf=%d\n", 1 ? "IDCT248" : "DCT248", name, err_max);
449
450     if (!speed)
451         return;
452
453     ti = av_gettime();
454     it1 = 0;
455     do {
456         for (it = 0; it < NB_ITS_SPEED; it++) {
457             for (i = 0; i < 64; i++)
458                 block[i] = block1[i];
459             idct248_put(img_dest, 8, block);
460         }
461         it1 += NB_ITS_SPEED;
462         ti1 = av_gettime() - ti;
463     } while (ti1 < 1000000);
464     emms_c();
465
466     printf("%s %s: %0.1f kdct/s\n", 1 ? "IDCT248" : "DCT248", name,
467            (double) it1 * 1000.0 / (double) ti1);
468 }
469
470 static void help(void)
471 {
472     printf("dct-test [-i] [<test-number>]\n"
473            "test-number 0 -> test with random matrixes\n"
474            "            1 -> test with random sparse matrixes\n"
475            "            2 -> do 3. test from mpeg4 std\n"
476            "-i          test IDCT implementations\n"
477            "-4          test IDCT248 implementations\n"
478            "-t          speed test\n");
479 }
480
481 #if !HAVE_GETOPT
482 #include "compat/getopt.c"
483 #endif
484
485 int main(int argc, char **argv)
486 {
487     int test_idct = 0, test_248_dct = 0;
488     int c, i;
489     int test = 1;
490     int speed = 0;
491     int err = 0;
492
493     cpu_flags = av_get_cpu_flags();
494
495     ff_ref_dct_init();
496     idct_mmx_init();
497
498     for (;;) {
499         c = getopt(argc, argv, "ih4t");
500         if (c == -1)
501             break;
502         switch (c) {
503         case 'i':
504             test_idct = 1;
505             break;
506         case '4':
507             test_248_dct = 1;
508             break;
509         case 't':
510             speed = 1;
511             break;
512         default:
513         case 'h':
514             help();
515             return 0;
516         }
517     }
518
519     if (optind < argc)
520         test = atoi(argv[optind]);
521
522     printf("Libav DCT/IDCT test\n");
523
524     if (test_248_dct) {
525         idct248_error("SIMPLE-C", ff_simple_idct248_put, speed);
526     } else {
527         const struct algo *algos = test_idct ? idct_tab : fdct_tab;
528         for (i = 0; algos[i].name; i++)
529             if (!(~cpu_flags & algos[i].mm_support)) {
530                 err |= dct_error(&algos[i], test, test_idct, speed);
531             }
532     }
533
534     if (err)
535         printf("Error: %d.\n", err);
536
537     return !!err;
538 }