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