]> git.sesse.net Git - ffmpeg/blob - libavcodec/dct-test.c
add libmpeg2 permutation to dct-test
[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, LIBMPEG2_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 if (form == LIBMPEG2_PERM) {
239             for(i=0; i<64; i++)
240                 block[(i&0x38) | ((i&6) >> 1) | ((i&1) << 2)] = block1[i];
241         } else {
242             for(i=0; i<64; i++)
243                 block[i]= block1[i];
244         }
245 #if 0 // simulate mismatch control for tested IDCT but not the ref
246 { int sum=0;
247         for(i=0;i<64;i++)
248            sum+=block[i];
249
250         if((sum&1)==0) block[63]^=1;
251 }
252 #endif
253
254         fdct_func(block);
255         emms_c(); /* for ff_mmx_idct */
256
257         if (form == SCALE_PERM) {
258             for(i=0; i<64; i++) {
259                 scale = 8*(1 << (AANSCALE_BITS + 11)) / aanscales[i];
260                 block[i] = (block[i] * scale /*+ (1<<(AANSCALE_BITS-1))*/) >> AANSCALE_BITS;
261             }
262         }
263
264         fdct_ref(block1);
265
266         blockSumErr=0;
267         for(i=0;i<64;i++) {
268             v = abs(block[i] - block1[i]);
269             if (v > err_inf)
270                 err_inf = v;
271             err2 += v * v;
272             sysErr[i] += block[i] - block1[i];
273             blockSumErr += v;
274             if( abs(block[i])>maxout) maxout=abs(block[i]);
275         }
276         if(blockSumErrMax < blockSumErr) blockSumErrMax= blockSumErr;
277 #if 0 // print different matrix pairs
278         if(blockSumErr){
279             printf("\n");
280             for(i=0; i<64; i++){
281                 if((i&7)==0) printf("\n");
282                 printf("%4d ", block_org[i]);
283             }
284             for(i=0; i<64; i++){
285                 if((i&7)==0) printf("\n");
286                 printf("%4d ", block[i] - block1[i]);
287             }
288         }
289 #endif
290     }
291     for(i=0; i<64; i++) sysErrMax= FFMAX(sysErrMax, FFABS(sysErr[i]));
292
293 #if 1 // dump systematic errors
294     for(i=0; i<64; i++){
295         if(i%8==0) printf("\n");
296         printf("%5d ", (int)sysErr[i]);
297     }
298     printf("\n");
299 #endif
300
301     printf("%s %s: err_inf=%d err2=%0.8f syserr=%0.8f maxout=%d blockSumErr=%d\n",
302            is_idct ? "IDCT" : "DCT",
303            name, err_inf, (double)err2 / NB_ITS / 64.0, (double)sysErrMax / NB_ITS, maxout, blockSumErrMax);
304 #if 1 //Speed test
305     /* speed test */
306     for(i=0;i<64;i++)
307         block1[i] = 0;
308     switch(test){
309     case 0:
310         for(i=0;i<64;i++)
311             block1[i] = (random() % 512) -256;
312         if (is_idct){
313             fdct(block1);
314
315             for(i=0;i<64;i++)
316                 block1[i]>>=3;
317         }
318     break;
319     case 1:{
320     case 2:
321         block1[0] = (random() % 512) -256;
322         block1[1] = (random() % 512) -256;
323         block1[2] = (random() % 512) -256;
324         block1[3] = (random() % 512) -256;
325     }break;
326     }
327
328     if (form == MMX_PERM) {
329         for(i=0;i<64;i++)
330             block[idct_mmx_perm[i]] = block1[i];
331     } else if(form == MMX_SIMPLE_PERM) {
332         for(i=0;i<64;i++)
333             block[idct_simple_mmx_perm[i]] = block1[i];
334     } else {
335         for(i=0; i<64; i++)
336             block[i]= block1[i];
337     }
338
339     ti = gettime();
340     it1 = 0;
341     do {
342         for(it=0;it<NB_ITS_SPEED;it++) {
343             for(i=0; i<64; i++)
344                 block[i]= block1[i];
345 //            memcpy(block, block1, sizeof(DCTELEM) * 64);
346 // do not memcpy especially not fastmemcpy because it does movntq !!!
347             fdct_func(block);
348         }
349         it1 += NB_ITS_SPEED;
350         ti1 = gettime() - ti;
351     } while (ti1 < 1000000);
352     emms_c();
353
354     printf("%s %s: %0.1f kdct/s\n",
355            is_idct ? "IDCT" : "DCT",
356            name, (double)it1 * 1000.0 / (double)ti1);
357 #endif
358 }
359
360 static uint8_t img_dest[64] __attribute__ ((aligned (8)));
361 static uint8_t img_dest1[64] __attribute__ ((aligned (8)));
362
363 void idct248_ref(uint8_t *dest, int linesize, int16_t *block)
364 {
365     static int init;
366     static double c8[8][8];
367     static double c4[4][4];
368     double block1[64], block2[64], block3[64];
369     double s, sum, v;
370     int i, j, k;
371
372     if (!init) {
373         init = 1;
374
375         for(i=0;i<8;i++) {
376             sum = 0;
377             for(j=0;j<8;j++) {
378                 s = (i==0) ? sqrt(1.0/8.0) : sqrt(1.0/4.0);
379                 c8[i][j] = s * cos(M_PI * i * (j + 0.5) / 8.0);
380                 sum += c8[i][j] * c8[i][j];
381             }
382         }
383
384         for(i=0;i<4;i++) {
385             sum = 0;
386             for(j=0;j<4;j++) {
387                 s = (i==0) ? sqrt(1.0/4.0) : sqrt(1.0/2.0);
388                 c4[i][j] = s * cos(M_PI * i * (j + 0.5) / 4.0);
389                 sum += c4[i][j] * c4[i][j];
390             }
391         }
392     }
393
394     /* butterfly */
395     s = 0.5 * sqrt(2.0);
396     for(i=0;i<4;i++) {
397         for(j=0;j<8;j++) {
398             block1[8*(2*i)+j] = (block[8*(2*i)+j] + block[8*(2*i+1)+j]) * s;
399             block1[8*(2*i+1)+j] = (block[8*(2*i)+j] - block[8*(2*i+1)+j]) * s;
400         }
401     }
402
403     /* idct8 on lines */
404     for(i=0;i<8;i++) {
405         for(j=0;j<8;j++) {
406             sum = 0;
407             for(k=0;k<8;k++)
408                 sum += c8[k][j] * block1[8*i+k];
409             block2[8*i+j] = sum;
410         }
411     }
412
413     /* idct4 */
414     for(i=0;i<8;i++) {
415         for(j=0;j<4;j++) {
416             /* top */
417             sum = 0;
418             for(k=0;k<4;k++)
419                 sum += c4[k][j] * block2[8*(2*k)+i];
420             block3[8*(2*j)+i] = sum;
421
422             /* bottom */
423             sum = 0;
424             for(k=0;k<4;k++)
425                 sum += c4[k][j] * block2[8*(2*k+1)+i];
426             block3[8*(2*j+1)+i] = sum;
427         }
428     }
429
430     /* clamp and store the result */
431     for(i=0;i<8;i++) {
432         for(j=0;j<8;j++) {
433             v = block3[8*i+j];
434             if (v < 0)
435                 v = 0;
436             else if (v > 255)
437                 v = 255;
438             dest[i * linesize + j] = (int)rint(v);
439         }
440     }
441 }
442
443 void idct248_error(const char *name,
444                     void (*idct248_put)(uint8_t *dest, int line_size, int16_t *block))
445 {
446     int it, i, it1, ti, ti1, err_max, v;
447
448     srandom(0);
449
450     /* just one test to see if code is correct (precision is less
451        important here) */
452     err_max = 0;
453     for(it=0;it<NB_ITS;it++) {
454
455         /* XXX: use forward transform to generate values */
456         for(i=0;i<64;i++)
457             block1[i] = (random() % 256) - 128;
458         block1[0] += 1024;
459
460         for(i=0; i<64; i++)
461             block[i]= block1[i];
462         idct248_ref(img_dest1, 8, block);
463
464         for(i=0; i<64; i++)
465             block[i]= block1[i];
466         idct248_put(img_dest, 8, block);
467
468         for(i=0;i<64;i++) {
469             v = abs((int)img_dest[i] - (int)img_dest1[i]);
470             if (v == 255)
471                 printf("%d %d\n", img_dest[i], img_dest1[i]);
472             if (v > err_max)
473                 err_max = v;
474         }
475 #if 0
476         printf("ref=\n");
477         for(i=0;i<8;i++) {
478             int j;
479             for(j=0;j<8;j++) {
480                 printf(" %3d", img_dest1[i*8+j]);
481             }
482             printf("\n");
483         }
484
485         printf("out=\n");
486         for(i=0;i<8;i++) {
487             int j;
488             for(j=0;j<8;j++) {
489                 printf(" %3d", img_dest[i*8+j]);
490             }
491             printf("\n");
492         }
493 #endif
494     }
495     printf("%s %s: err_inf=%d\n",
496            1 ? "IDCT248" : "DCT248",
497            name, err_max);
498
499     ti = gettime();
500     it1 = 0;
501     do {
502         for(it=0;it<NB_ITS_SPEED;it++) {
503             for(i=0; i<64; i++)
504                 block[i]= block1[i];
505 //            memcpy(block, block1, sizeof(DCTELEM) * 64);
506 // do not memcpy especially not fastmemcpy because it does movntq !!!
507             idct248_put(img_dest, 8, block);
508         }
509         it1 += NB_ITS_SPEED;
510         ti1 = gettime() - ti;
511     } while (ti1 < 1000000);
512     emms_c();
513
514     printf("%s %s: %0.1f kdct/s\n",
515            1 ? "IDCT248" : "DCT248",
516            name, (double)it1 * 1000.0 / (double)ti1);
517 }
518
519 void help(void)
520 {
521     printf("dct-test [-i] [<test-number>]\n"
522            "test-number 0 -> test with random matrixes\n"
523            "            1 -> test with random sparse matrixes\n"
524            "            2 -> do 3. test from mpeg4 std\n"
525            "-i          test IDCT implementations\n"
526            "-4          test IDCT248 implementations\n");
527 }
528
529 int main(int argc, char **argv)
530 {
531     int test_idct = 0, test_248_dct = 0;
532     int c,i;
533     int test=1;
534     int cpu_flags = mm_support();
535
536     init_fdct();
537     idct_mmx_init();
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 && !(~cpu_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 }