]> git.sesse.net Git - ffmpeg/blob - libavcodec/dct-test.c
Define mm_flags/support to be 0 on architectures where they don't exist.
[ffmpeg] / 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 FFmpeg.
6  *
7  * FFmpeg 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  * FFmpeg 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 FFmpeg; 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 dct-test.c
24  * DCT test. (c) 2001 Fabrice Bellard.
25  * Started from sample code by Juan J. Sierralta P.
26  */
27
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <sys/time.h>
32 #include <unistd.h>
33 #include <math.h>
34
35 #include "libavutil/common.h"
36 #include "dsputil.h"
37
38 #include "simple_idct.h"
39 #include "faandct.h"
40 #include "faanidct.h"
41 #include "i386/idct_xvid.h"
42
43 #undef printf
44 #undef random
45
46 void *fast_memcpy(void *a, const void *b, size_t c){return memcpy(a,b,c);};
47
48 /* reference fdct/idct */
49 extern void fdct(DCTELEM *block);
50 extern void idct(DCTELEM *block);
51 extern void init_fdct();
52
53 extern void ff_mmx_idct(DCTELEM *data);
54 extern void ff_mmxext_idct(DCTELEM *data);
55
56 extern void odivx_idct_c (short *block);
57
58 // BFIN
59 extern void ff_bfin_idct (DCTELEM *block)  ;
60 extern void ff_bfin_fdct (DCTELEM *block) ;
61
62 // ALTIVEC
63 extern void fdct_altivec (DCTELEM *block);
64 //extern void idct_altivec (DCTELEM *block);?? no routine
65
66
67 struct algo {
68   const char *name;
69   enum { FDCT, IDCT } is_idct;
70   void (* func) (DCTELEM *block);
71   void (* ref)  (DCTELEM *block);
72   enum formattag { NO_PERM,MMX_PERM, MMX_SIMPLE_PERM, SCALE_PERM, SSE2_PERM } format;
73   int  mm_support;
74 };
75
76 #ifndef FAAN_POSTSCALE
77 #define FAAN_SCALE SCALE_PERM
78 #else
79 #define FAAN_SCALE NO_PERM
80 #endif
81
82 struct algo algos[] = {
83   {"REF-DBL",         0, fdct,               fdct, NO_PERM},
84   {"FAAN",            0, ff_faandct,         fdct, FAAN_SCALE},
85   {"FAANI",           1, ff_faanidct,        idct, NO_PERM},
86   {"IJG-AAN-INT",     0, fdct_ifast,         fdct, SCALE_PERM},
87   {"IJG-LLM-INT",     0, ff_jpeg_fdct_islow, fdct, NO_PERM},
88   {"REF-DBL",         1, idct,               idct, NO_PERM},
89   {"INT",             1, j_rev_dct,          idct, MMX_PERM},
90   {"SIMPLE-C",        1, ff_simple_idct,     idct, NO_PERM},
91
92 #ifdef HAVE_MMX
93   {"MMX",             0, ff_fdct_mmx,        fdct, NO_PERM, MM_MMX},
94 #ifdef HAVE_MMX2
95   {"MMX2",            0, ff_fdct_mmx2,       fdct, NO_PERM, MM_MMXEXT},
96 #endif
97
98 #ifdef CONFIG_GPL
99   {"LIBMPEG2-MMX",    1, ff_mmx_idct,        idct, MMX_PERM, MM_MMX},
100   {"LIBMPEG2-MMXEXT", 1, ff_mmxext_idct,     idct, MMX_PERM, MM_MMXEXT},
101 #endif
102   {"SIMPLE-MMX",      1, ff_simple_idct_mmx, idct, MMX_SIMPLE_PERM, MM_MMX},
103   {"XVID-MMX",        1, ff_idct_xvid_mmx,   idct, NO_PERM, MM_MMX},
104   {"XVID-MMX2",       1, ff_idct_xvid_mmx2,  idct, NO_PERM, MM_MMXEXT},
105   {"XVID-SSE2",       1, ff_idct_xvid_sse2,  idct, SSE2_PERM, MM_SSE2},
106 #endif
107
108 #ifdef HAVE_ALTIVEC
109   {"altivecfdct",     0, fdct_altivec,       fdct, NO_PERM, MM_ALTIVEC},
110 #endif
111
112 #ifdef ARCH_BFIN
113   {"BFINfdct",        0, ff_bfin_fdct,       fdct, NO_PERM},
114   {"BFINidct",        1, ff_bfin_idct,       idct, NO_PERM},
115 #endif
116
117   { 0 }
118 };
119
120 #define AANSCALE_BITS 12
121 static const unsigned short aanscales[64] = {
122     /* precomputed values scaled up by 14 bits */
123     16384, 22725, 21407, 19266, 16384, 12873,  8867,  4520,
124     22725, 31521, 29692, 26722, 22725, 17855, 12299,  6270,
125     21407, 29692, 27969, 25172, 21407, 16819, 11585,  5906,
126     19266, 26722, 25172, 22654, 19266, 15137, 10426,  5315,
127     16384, 22725, 21407, 19266, 16384, 12873,  8867,  4520,
128     12873, 17855, 16819, 15137, 12873, 10114,  6967,  3552,
129     8867, 12299, 11585, 10426,  8867,  6967,  4799,  2446,
130     4520,  6270,  5906,  5315,  4520,  3552,  2446,  1247
131 };
132
133 uint8_t cropTbl[256 + 2 * MAX_NEG_CROP];
134
135 int64_t gettime(void)
136 {
137     struct timeval tv;
138     gettimeofday(&tv,NULL);
139     return (int64_t)tv.tv_sec * 1000000 + tv.tv_usec;
140 }
141
142 #define NB_ITS 20000
143 #define NB_ITS_SPEED 50000
144
145 static short idct_mmx_perm[64];
146
147 static short idct_simple_mmx_perm[64]={
148         0x00, 0x08, 0x04, 0x09, 0x01, 0x0C, 0x05, 0x0D,
149         0x10, 0x18, 0x14, 0x19, 0x11, 0x1C, 0x15, 0x1D,
150         0x20, 0x28, 0x24, 0x29, 0x21, 0x2C, 0x25, 0x2D,
151         0x12, 0x1A, 0x16, 0x1B, 0x13, 0x1E, 0x17, 0x1F,
152         0x02, 0x0A, 0x06, 0x0B, 0x03, 0x0E, 0x07, 0x0F,
153         0x30, 0x38, 0x34, 0x39, 0x31, 0x3C, 0x35, 0x3D,
154         0x22, 0x2A, 0x26, 0x2B, 0x23, 0x2E, 0x27, 0x2F,
155         0x32, 0x3A, 0x36, 0x3B, 0x33, 0x3E, 0x37, 0x3F,
156 };
157
158 static const uint8_t idct_sse2_row_perm[8] = {0, 4, 1, 5, 2, 6, 3, 7};
159
160 void idct_mmx_init(void)
161 {
162     int i;
163
164     /* the mmx/mmxext idct uses a reordered input, so we patch scan tables */
165     for (i = 0; i < 64; i++) {
166         idct_mmx_perm[i] = (i & 0x38) | ((i & 6) >> 1) | ((i & 1) << 2);
167 //        idct_simple_mmx_perm[i] = simple_block_permute_op(i);
168     }
169 }
170
171 static DCTELEM block[64] __attribute__ ((aligned (16)));
172 static DCTELEM block1[64] __attribute__ ((aligned (8)));
173 static DCTELEM block_org[64] __attribute__ ((aligned (8)));
174
175 void dct_error(const char *name, int is_idct,
176                void (*fdct_func)(DCTELEM *block),
177                void (*fdct_ref)(DCTELEM *block), int form, int test)
178 {
179     int it, i, scale;
180     int err_inf, v;
181     int64_t err2, ti, ti1, it1;
182     int64_t sysErr[64], sysErrMax=0;
183     int maxout=0;
184     int blockSumErrMax=0, blockSumErr;
185
186     srandom(0);
187
188     err_inf = 0;
189     err2 = 0;
190     for(i=0; i<64; i++) sysErr[i]=0;
191     for(it=0;it<NB_ITS;it++) {
192         for(i=0;i<64;i++)
193             block1[i] = 0;
194         switch(test){
195         case 0:
196             for(i=0;i<64;i++)
197                 block1[i] = (random() % 512) -256;
198             if (is_idct){
199                 fdct(block1);
200
201                 for(i=0;i<64;i++)
202                     block1[i]>>=3;
203             }
204         break;
205         case 1:{
206             int num= (random()%10)+1;
207             for(i=0;i<num;i++)
208                 block1[random()%64] = (random() % 512) -256;
209         }break;
210         case 2:
211             block1[0]= (random()%4096)-2048;
212             block1[63]= (block1[0]&1)^1;
213         break;
214         }
215
216 #if 0 // simulate mismatch control
217 { int sum=0;
218         for(i=0;i<64;i++)
219            sum+=block1[i];
220
221         if((sum&1)==0) block1[63]^=1;
222 }
223 #endif
224
225         for(i=0; i<64; i++)
226             block_org[i]= block1[i];
227
228         if (form == MMX_PERM) {
229             for(i=0;i<64;i++)
230                 block[idct_mmx_perm[i]] = block1[i];
231             } else if (form == MMX_SIMPLE_PERM) {
232             for(i=0;i<64;i++)
233                 block[idct_simple_mmx_perm[i]] = block1[i];
234
235         } else if (form == SSE2_PERM) {
236             for(i=0; i<64; i++)
237                 block[(i&0x38) | idct_sse2_row_perm[i&7]] = block1[i];
238         } else {
239             for(i=0; i<64; i++)
240                 block[i]= block1[i];
241         }
242 #if 0 // simulate mismatch control for tested IDCT but not the ref
243 { int sum=0;
244         for(i=0;i<64;i++)
245            sum+=block[i];
246
247         if((sum&1)==0) block[63]^=1;
248 }
249 #endif
250
251         fdct_func(block);
252         emms_c(); /* for ff_mmx_idct */
253
254         if (form == SCALE_PERM) {
255             for(i=0; i<64; i++) {
256                 scale = 8*(1 << (AANSCALE_BITS + 11)) / aanscales[i];
257                 block[i] = (block[i] * scale /*+ (1<<(AANSCALE_BITS-1))*/) >> AANSCALE_BITS;
258             }
259         }
260
261         fdct_ref(block1);
262
263         blockSumErr=0;
264         for(i=0;i<64;i++) {
265             v = abs(block[i] - block1[i]);
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) maxout=abs(block[i]);
272         }
273         if(blockSumErrMax < blockSumErr) blockSumErrMax= blockSumErr;
274 #if 0 // print different matrix pairs
275         if(blockSumErr){
276             printf("\n");
277             for(i=0; i<64; i++){
278                 if((i&7)==0) printf("\n");
279                 printf("%4d ", block_org[i]);
280             }
281             for(i=0; i<64; i++){
282                 if((i&7)==0) printf("\n");
283                 printf("%4d ", block[i] - block1[i]);
284             }
285         }
286 #endif
287     }
288     for(i=0; i<64; i++) sysErrMax= FFMAX(sysErrMax, FFABS(sysErr[i]));
289
290 #if 1 // dump systematic errors
291     for(i=0; i<64; i++){
292         if(i%8==0) printf("\n");
293         printf("%5d ", (int)sysErr[i]);
294     }
295     printf("\n");
296 #endif
297
298     printf("%s %s: err_inf=%d err2=%0.8f syserr=%0.8f maxout=%d blockSumErr=%d\n",
299            is_idct ? "IDCT" : "DCT",
300            name, err_inf, (double)err2 / NB_ITS / 64.0, (double)sysErrMax / NB_ITS, maxout, blockSumErrMax);
301 #if 1 //Speed test
302     /* speed test */
303     for(i=0;i<64;i++)
304         block1[i] = 0;
305     switch(test){
306     case 0:
307         for(i=0;i<64;i++)
308             block1[i] = (random() % 512) -256;
309         if (is_idct){
310             fdct(block1);
311
312             for(i=0;i<64;i++)
313                 block1[i]>>=3;
314         }
315     break;
316     case 1:{
317     case 2:
318         block1[0] = (random() % 512) -256;
319         block1[1] = (random() % 512) -256;
320         block1[2] = (random() % 512) -256;
321         block1[3] = (random() % 512) -256;
322     }break;
323     }
324
325     if (form == MMX_PERM) {
326         for(i=0;i<64;i++)
327             block[idct_mmx_perm[i]] = block1[i];
328     } else if(form == MMX_SIMPLE_PERM) {
329         for(i=0;i<64;i++)
330             block[idct_simple_mmx_perm[i]] = block1[i];
331     } else {
332         for(i=0; i<64; i++)
333             block[i]= block1[i];
334     }
335
336     ti = gettime();
337     it1 = 0;
338     do {
339         for(it=0;it<NB_ITS_SPEED;it++) {
340             for(i=0; i<64; i++)
341                 block[i]= block1[i];
342 //            memcpy(block, block1, sizeof(DCTELEM) * 64);
343 // do not memcpy especially not fastmemcpy because it does movntq !!!
344             fdct_func(block);
345         }
346         it1 += NB_ITS_SPEED;
347         ti1 = gettime() - ti;
348     } while (ti1 < 1000000);
349     emms_c();
350
351     printf("%s %s: %0.1f kdct/s\n",
352            is_idct ? "IDCT" : "DCT",
353            name, (double)it1 * 1000.0 / (double)ti1);
354 #endif
355 }
356
357 static uint8_t img_dest[64] __attribute__ ((aligned (8)));
358 static uint8_t img_dest1[64] __attribute__ ((aligned (8)));
359
360 void idct248_ref(uint8_t *dest, int linesize, int16_t *block)
361 {
362     static int init;
363     static double c8[8][8];
364     static double c4[4][4];
365     double block1[64], block2[64], block3[64];
366     double s, sum, v;
367     int i, j, k;
368
369     if (!init) {
370         init = 1;
371
372         for(i=0;i<8;i++) {
373             sum = 0;
374             for(j=0;j<8;j++) {
375                 s = (i==0) ? sqrt(1.0/8.0) : sqrt(1.0/4.0);
376                 c8[i][j] = s * cos(M_PI * i * (j + 0.5) / 8.0);
377                 sum += c8[i][j] * c8[i][j];
378             }
379         }
380
381         for(i=0;i<4;i++) {
382             sum = 0;
383             for(j=0;j<4;j++) {
384                 s = (i==0) ? sqrt(1.0/4.0) : sqrt(1.0/2.0);
385                 c4[i][j] = s * cos(M_PI * i * (j + 0.5) / 4.0);
386                 sum += c4[i][j] * c4[i][j];
387             }
388         }
389     }
390
391     /* butterfly */
392     s = 0.5 * sqrt(2.0);
393     for(i=0;i<4;i++) {
394         for(j=0;j<8;j++) {
395             block1[8*(2*i)+j] = (block[8*(2*i)+j] + block[8*(2*i+1)+j]) * s;
396             block1[8*(2*i+1)+j] = (block[8*(2*i)+j] - block[8*(2*i+1)+j]) * s;
397         }
398     }
399
400     /* idct8 on lines */
401     for(i=0;i<8;i++) {
402         for(j=0;j<8;j++) {
403             sum = 0;
404             for(k=0;k<8;k++)
405                 sum += c8[k][j] * block1[8*i+k];
406             block2[8*i+j] = sum;
407         }
408     }
409
410     /* idct4 */
411     for(i=0;i<8;i++) {
412         for(j=0;j<4;j++) {
413             /* top */
414             sum = 0;
415             for(k=0;k<4;k++)
416                 sum += c4[k][j] * block2[8*(2*k)+i];
417             block3[8*(2*j)+i] = sum;
418
419             /* bottom */
420             sum = 0;
421             for(k=0;k<4;k++)
422                 sum += c4[k][j] * block2[8*(2*k+1)+i];
423             block3[8*(2*j+1)+i] = sum;
424         }
425     }
426
427     /* clamp and store the result */
428     for(i=0;i<8;i++) {
429         for(j=0;j<8;j++) {
430             v = block3[8*i+j];
431             if (v < 0)
432                 v = 0;
433             else if (v > 255)
434                 v = 255;
435             dest[i * linesize + j] = (int)rint(v);
436         }
437     }
438 }
439
440 void idct248_error(const char *name,
441                     void (*idct248_put)(uint8_t *dest, int line_size, int16_t *block))
442 {
443     int it, i, it1, ti, ti1, err_max, v;
444
445     srandom(0);
446
447     /* just one test to see if code is correct (precision is less
448        important here) */
449     err_max = 0;
450     for(it=0;it<NB_ITS;it++) {
451
452         /* XXX: use forward transform to generate values */
453         for(i=0;i<64;i++)
454             block1[i] = (random() % 256) - 128;
455         block1[0] += 1024;
456
457         for(i=0; i<64; i++)
458             block[i]= block1[i];
459         idct248_ref(img_dest1, 8, block);
460
461         for(i=0; i<64; i++)
462             block[i]= block1[i];
463         idct248_put(img_dest, 8, block);
464
465         for(i=0;i<64;i++) {
466             v = abs((int)img_dest[i] - (int)img_dest1[i]);
467             if (v == 255)
468                 printf("%d %d\n", img_dest[i], img_dest1[i]);
469             if (v > err_max)
470                 err_max = v;
471         }
472 #if 0
473         printf("ref=\n");
474         for(i=0;i<8;i++) {
475             int j;
476             for(j=0;j<8;j++) {
477                 printf(" %3d", img_dest1[i*8+j]);
478             }
479             printf("\n");
480         }
481
482         printf("out=\n");
483         for(i=0;i<8;i++) {
484             int j;
485             for(j=0;j<8;j++) {
486                 printf(" %3d", img_dest[i*8+j]);
487             }
488             printf("\n");
489         }
490 #endif
491     }
492     printf("%s %s: err_inf=%d\n",
493            1 ? "IDCT248" : "DCT248",
494            name, err_max);
495
496     ti = gettime();
497     it1 = 0;
498     do {
499         for(it=0;it<NB_ITS_SPEED;it++) {
500             for(i=0; i<64; i++)
501                 block[i]= block1[i];
502 //            memcpy(block, block1, sizeof(DCTELEM) * 64);
503 // do not memcpy especially not fastmemcpy because it does movntq !!!
504             idct248_put(img_dest, 8, block);
505         }
506         it1 += NB_ITS_SPEED;
507         ti1 = gettime() - ti;
508     } while (ti1 < 1000000);
509     emms_c();
510
511     printf("%s %s: %0.1f kdct/s\n",
512            1 ? "IDCT248" : "DCT248",
513            name, (double)it1 * 1000.0 / (double)ti1);
514 }
515
516 void help(void)
517 {
518     printf("dct-test [-i] [<test-number>]\n"
519            "test-number 0 -> test with random matrixes\n"
520            "            1 -> test with random sparse matrixes\n"
521            "            2 -> do 3. test from mpeg4 std\n"
522            "-i          test IDCT implementations\n"
523            "-4          test IDCT248 implementations\n");
524 }
525
526 int main(int argc, char **argv)
527 {
528     int test_idct = 0, test_248_dct = 0;
529     int c,i;
530     int test=1;
531
532     init_fdct();
533     idct_mmx_init();
534
535 #ifndef mm_flags
536     mm_flags = mm_support();
537 #endif
538
539     for(i=0;i<256;i++) cropTbl[i + MAX_NEG_CROP] = i;
540     for(i=0;i<MAX_NEG_CROP;i++) {
541         cropTbl[i] = 0;
542         cropTbl[i + MAX_NEG_CROP + 256] = 255;
543     }
544
545     for(;;) {
546         c = getopt(argc, argv, "ih4");
547         if (c == -1)
548             break;
549         switch(c) {
550         case 'i':
551             test_idct = 1;
552             break;
553         case '4':
554             test_248_dct = 1;
555             break;
556         default :
557         case 'h':
558             help();
559             return 0;
560         }
561     }
562
563     if(optind <argc) test= atoi(argv[optind]);
564
565     printf("ffmpeg DCT/IDCT test\n");
566
567     if (test_248_dct) {
568         idct248_error("SIMPLE-C", ff_simple_idct248_put);
569     } else {
570       for (i=0;algos[i].name;i++)
571         if (algos[i].is_idct == test_idct && !(~mm_flags & algos[i].mm_support)) {
572           dct_error (algos[i].name, algos[i].is_idct, algos[i].func, algos[i].ref, algos[i].format, test);
573         }
574     }
575     return 0;
576 }