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