configure: update FFmpeg revision (bc63a76).
[vaapi:mplayer.git] / cpudetect.c
1 /*
2  * This file is part of MPlayer.
3  *
4  * MPlayer is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * MPlayer is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with MPlayer; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17  */
18
19 #include "libavutil/x86/asm.h"
20 #include "config.h"
21 #include "cpudetect.h"
22 #include "mp_msg.h"
23
24 CpuCaps gCpuCaps;
25
26 #include <stdlib.h>
27
28 #if ARCH_X86
29
30 #include <stdio.h>
31 #include <string.h>
32
33 #if defined (__NetBSD__) || defined(__OpenBSD__)
34 #include <sys/param.h>
35 #include <sys/sysctl.h>
36 #include <machine/cpu.h>
37 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) || defined(__APPLE__)
38 #include <sys/types.h>
39 #include <sys/sysctl.h>
40 #elif defined(__linux__)
41 #include <signal.h>
42 #elif defined(__MINGW32__) || defined(__CYGWIN__)
43 #include <windows.h>
44 #elif defined(__OS2__)
45 #define INCL_DOS
46 #include <os2.h>
47 #elif defined(__AMIGAOS4__)
48 #include <proto/exec.h>
49 #endif
50
51 /* Thanks to the FreeBSD project for some of this cpuid code, and
52  * help understanding how to use it.  Thanks to the Mesa
53  * team for SSE support detection and more cpu detect code.
54  */
55
56 #if CONFIG_RUNTIME_CPUDETECT
57 /* I believe this code works.  However, it has only been used on a PII and PIII */
58
59 #if defined(__linux__) && defined(_POSIX_SOURCE) && !ARCH_X86_64
60 static void sigill_handler_sse( int signal, struct sigcontext sc )
61 {
62    mp_msg(MSGT_CPUDETECT,MSGL_V, "SIGILL, " );
63
64    /* Both the "xorps %%xmm0,%%xmm0" and "divps %xmm0,%%xmm1"
65     * instructions are 3 bytes long.  We must increment the instruction
66     * pointer manually to avoid repeated execution of the offending
67     * instruction.
68     *
69     * If the SIGILL is caused by a divide-by-zero when unmasked
70     * exceptions aren't supported, the SIMD FPU status and control
71     * word will be restored at the end of the test, so we don't need
72     * to worry about doing it here.  Besides, we may not be able to...
73     */
74    sc.eip += 3;
75
76    gCpuCaps.hasSSE=0;
77 }
78 #endif /* __linux__ && _POSIX_SOURCE */
79
80 #if (defined(__MINGW32__) || defined(__CYGWIN__)) && !ARCH_X86_64
81 LONG CALLBACK win32_sig_handler_sse(EXCEPTION_POINTERS* ep)
82 {
83     if(ep->ExceptionRecord->ExceptionCode==EXCEPTION_ILLEGAL_INSTRUCTION){
84         mp_msg(MSGT_CPUDETECT,MSGL_V, "SIGILL, " );
85         ep->ContextRecord->Eip +=3;
86         gCpuCaps.hasSSE=0;
87         return EXCEPTION_CONTINUE_EXECUTION;
88     }
89     return EXCEPTION_CONTINUE_SEARCH;
90 }
91 #endif /* defined(__MINGW32__) || defined(__CYGWIN__) */
92
93 #ifdef __OS2__
94 ULONG _System os2_sig_handler_sse(PEXCEPTIONREPORTRECORD       p1,
95                                   PEXCEPTIONREGISTRATIONRECORD p2,
96                                   PCONTEXTRECORD               p3,
97                                   PVOID                        p4)
98 {
99     if(p1->ExceptionNum == XCPT_ILLEGAL_INSTRUCTION){
100         mp_msg(MSGT_CPUDETECT, MSGL_V, "SIGILL, ");
101
102         p3->ctx_RegEip += 3;
103         gCpuCaps.hasSSE = 0;
104
105         return XCPT_CONTINUE_EXECUTION;
106     }
107     return XCPT_CONTINUE_SEARCH;
108 }
109 #endif
110
111 /* If we're running on a processor that can do SSE, let's see if we
112  * are allowed to or not.  This will catch 2.4.0 or later kernels that
113  * haven't been configured for a Pentium III but are running on one,
114  * and RedHat patched 2.2 kernels that have broken exception handling
115  * support for user space apps that do SSE.
116  */
117
118 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
119 #define SSE_SYSCTL_NAME "hw.instruction_sse"
120 #elif defined(__APPLE__)
121 #define SSE_SYSCTL_NAME "hw.optional.sse"
122 #endif
123
124 static void check_os_katmai_support( void )
125 {
126 #if ARCH_X86_64
127     gCpuCaps.hasSSE=1;
128     gCpuCaps.hasSSE2=1;
129 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) || defined(__APPLE__)
130     int has_sse=0, ret;
131     size_t len=sizeof(has_sse);
132
133     ret = sysctlbyname(SSE_SYSCTL_NAME, &has_sse, &len, NULL, 0);
134     if (ret || !has_sse)
135         gCpuCaps.hasSSE=0;
136
137 #elif defined(__NetBSD__) || defined (__OpenBSD__)
138 #if __NetBSD_Version__ >= 105250000 || (defined __OpenBSD__)
139     int has_sse, has_sse2, ret, mib[2];
140     size_t varlen;
141
142     mib[0] = CTL_MACHDEP;
143     mib[1] = CPU_SSE;
144     varlen = sizeof(has_sse);
145
146     mp_msg(MSGT_CPUDETECT,MSGL_V, "Testing OS support for SSE... " );
147     ret = sysctl(mib, 2, &has_sse, &varlen, NULL, 0);
148     gCpuCaps.hasSSE = ret >= 0 && has_sse;
149     mp_msg(MSGT_CPUDETECT,MSGL_V, gCpuCaps.hasSSE ? "yes.\n" : "no!\n" );
150
151     mib[1] = CPU_SSE2;
152     varlen = sizeof(has_sse2);
153     mp_msg(MSGT_CPUDETECT,MSGL_V, "Testing OS support for SSE2... " );
154     ret = sysctl(mib, 2, &has_sse2, &varlen, NULL, 0);
155     gCpuCaps.hasSSE2 = ret >= 0 && has_sse2;
156     mp_msg(MSGT_CPUDETECT,MSGL_V, gCpuCaps.hasSSE2 ? "yes.\n" : "no!\n" );
157 #else
158     gCpuCaps.hasSSE = 0;
159     mp_msg(MSGT_CPUDETECT,MSGL_WARN, "No OS support for SSE, disabling to be safe.\n" );
160 #endif
161 #elif defined(__MINGW32__) || defined(__CYGWIN__)
162     LPTOP_LEVEL_EXCEPTION_FILTER exc_fil;
163     if ( gCpuCaps.hasSSE ) {
164         mp_msg(MSGT_CPUDETECT,MSGL_V, "Testing OS support for SSE... " );
165         exc_fil = SetUnhandledExceptionFilter(win32_sig_handler_sse);
166         __asm__ volatile ("xorps %xmm0, %xmm0");
167         SetUnhandledExceptionFilter(exc_fil);
168         mp_msg(MSGT_CPUDETECT,MSGL_V, gCpuCaps.hasSSE ? "yes.\n" : "no!\n" );
169     }
170 #elif defined(__OS2__)
171     EXCEPTIONREGISTRATIONRECORD RegRec = { 0, &os2_sig_handler_sse };
172     if ( gCpuCaps.hasSSE ) {
173         mp_msg(MSGT_CPUDETECT,MSGL_V, "Testing OS support for SSE... " );
174         DosSetExceptionHandler( &RegRec );
175         __asm__ volatile ("xorps %xmm0, %xmm0");
176         DosUnsetExceptionHandler( &RegRec );
177         mp_msg(MSGT_CPUDETECT,MSGL_V, gCpuCaps.hasSSE ? "yes.\n" : "no!\n" );
178     }
179 #elif defined(__linux__)
180 #if defined(_POSIX_SOURCE)
181     struct sigaction saved_sigill;
182
183     /* Save the original signal handlers.
184      */
185     sigaction( SIGILL, NULL, &saved_sigill );
186
187     signal( SIGILL, (void (*)(int))sigill_handler_sse );
188
189     /* Emulate test for OSFXSR in CR4.  The OS will set this bit if it
190      * supports the extended FPU save and restore required for SSE.  If
191      * we execute an SSE instruction on a PIII and get a SIGILL, the OS
192      * doesn't support Streaming SIMD Exceptions, even if the processor
193      * does.
194      */
195     if ( gCpuCaps.hasSSE ) {
196         mp_msg(MSGT_CPUDETECT,MSGL_V, "Testing OS support for SSE... " );
197
198 //      __asm__ volatile ("xorps %%xmm0, %%xmm0");
199         __asm__ volatile ("xorps %xmm0, %xmm0");
200
201         mp_msg(MSGT_CPUDETECT,MSGL_V, gCpuCaps.hasSSE ? "yes.\n" : "no!\n" );
202     }
203
204     /* Restore the original signal handlers.
205      */
206     sigaction( SIGILL, &saved_sigill, NULL );
207
208     /* If we've gotten to here and the XMM CPUID bit is still set, we're
209      * safe to go ahead and hook out the SSE code throughout Mesa.
210      */
211     mp_msg(MSGT_CPUDETECT,MSGL_V, "Tests of OS support for SSE %s\n", gCpuCaps.hasSSE ? "passed." : "failed!" );
212 #else
213     /* We can't use POSIX signal handling to test the availability of
214      * SSE, so we disable it by default.
215      */
216     mp_msg(MSGT_CPUDETECT,MSGL_WARN, "Cannot test OS support for SSE, disabling to be safe.\n" );
217     gCpuCaps.hasSSE=0;
218 #endif /* _POSIX_SOURCE */
219 #else
220     /* Do nothing on other platforms for now.
221      */
222     mp_msg(MSGT_CPUDETECT,MSGL_WARN, "Cannot test OS support for SSE, leaving disabled.\n" );
223     gCpuCaps.hasSSE=0;
224 #endif /* __linux__ */
225 }
226 #endif
227
228
229 // return TRUE if cpuid supported
230 static int has_cpuid(void)
231 {
232 // code from libavcodec:
233 #if ARCH_X86_64
234    return 1;
235 #else
236    long a, c;
237    __asm__ volatile (
238        /* See if CPUID instruction is supported ... */
239        /* ... Get copies of EFLAGS into eax and ecx */
240        "pushfl\n\t"
241        "pop %0\n\t"
242        "mov %0, %1\n\t"
243
244        /* ... Toggle the ID bit in one copy and store */
245        /*     to the EFLAGS reg */
246        "xor $0x200000, %0\n\t"
247        "push %0\n\t"
248        "popfl\n\t"
249
250        /* ... Get the (hopefully modified) EFLAGS */
251        "pushfl\n\t"
252        "pop %0\n\t"
253        : "=a" (a), "=c" (c)
254        :
255        : "cc"
256        );
257
258    return a != c;
259 #endif
260 }
261
262 void
263 do_cpuid(unsigned int ax, unsigned int *p)
264 {
265 // code from libavcodec:
266     __asm__ volatile
267         ("mov %%"REG_b", %%"REG_S"\n\t"
268          "cpuid\n\t"
269          "xchg %%"REG_b", %%"REG_S
270          : "=a" (p[0]), "=S" (p[1]),
271            "=c" (p[2]), "=d" (p[3])
272          : "0" (ax));
273 }
274
275 void GetCpuCaps( CpuCaps *caps)
276 {
277     unsigned int regs[4];
278     unsigned int regs2[4];
279
280     memset(caps, 0, sizeof(*caps));
281     caps->isX86=1;
282     caps->cl_size=32; /* default */
283     if (!has_cpuid()) {
284         mp_msg(MSGT_CPUDETECT,MSGL_WARN,"CPUID not supported!??? (maybe an old 486?)\n");
285         return;
286     }
287     do_cpuid(0x00000000, regs); // get _max_ cpuid level and vendor name
288     mp_msg(MSGT_CPUDETECT,MSGL_V,"CPU vendor name: %.4s%.4s%.4s  max cpuid level: %d\n",
289             (char*) (regs+1),(char*) (regs+3),(char*) (regs+2), regs[0]);
290     if (regs[0]>=0x00000001)
291     {
292         char *tmpstr, *ptmpstr;
293         unsigned cl_size;
294
295         do_cpuid(0x00000001, regs2);
296
297         caps->cpuType=(regs2[0] >> 8)&0xf;
298         caps->cpuModel=(regs2[0] >> 4)&0xf;
299
300 // see AMD64 Architecture Programmer's Manual, Volume 3: General-purpose and
301 // System Instructions, Table 3-2: Effective family computation, page 120.
302         if(caps->cpuType==0xf){
303             // use extended family (P4, IA64, K8)
304             caps->cpuType=0xf+((regs2[0]>>20)&255);
305         }
306         if(caps->cpuType==0xf || caps->cpuType==6)
307             caps->cpuModel |= ((regs2[0]>>16)&0xf) << 4;
308
309         caps->cpuStepping=regs2[0] & 0xf;
310
311         // general feature flags:
312         caps->hasTSC  = (regs2[3] & (1 << 8  )) >>  8; // 0x0000010
313         caps->hasMMX  = (regs2[3] & (1 << 23 )) >> 23; // 0x0800000
314         caps->hasSSE  = (regs2[3] & (1 << 25 )) >> 25; // 0x2000000
315         caps->hasSSE2 = (regs2[3] & (1 << 26 )) >> 26; // 0x4000000
316         caps->hasSSE3 = (regs2[2] & 1);        // 0x0000001
317         caps->hasSSSE3 = (regs2[2] & (1 << 9 )) >>  9; // 0x0000200
318         caps->hasSSE4 = (regs2[2] & (1 << 19 )) >> 19; // 0x0080000
319         caps->hasSSE42 = (regs2[2] & (1 << 20)) >> 20; // 0x0100000
320         caps->hasAVX  = (regs2[2] & (1 << 28 )) >> 28; // 0x10000000
321         caps->hasMMX2 = caps->hasSSE; // SSE cpus supports mmxext too
322         cl_size = ((regs2[1] >> 8) & 0xFF)*8;
323         if(cl_size) caps->cl_size = cl_size;
324
325         ptmpstr=tmpstr=GetCpuFriendlyName(regs, regs2);
326         while(*ptmpstr == ' ')    // strip leading spaces
327             ptmpstr++;
328         mp_msg(MSGT_CPUDETECT,MSGL_V,"CPU: %s ", ptmpstr);
329         free(tmpstr);
330         mp_msg(MSGT_CPUDETECT,MSGL_V,"(Family: %d, Model: %d, Stepping: %d)\n",
331                caps->cpuType, caps->cpuModel, caps->cpuStepping);
332
333     }
334     do_cpuid(0x80000000, regs);
335     if (regs[0]>=0x80000001) {
336         mp_msg(MSGT_CPUDETECT,MSGL_V,"extended cpuid-level: %d\n",regs[0]&0x7FFFFFFF);
337         do_cpuid(0x80000001, regs2);
338         caps->hasMMX  |= (regs2[3] & (1 << 23 )) >> 23; // 0x0800000
339         caps->hasMMX2 |= (regs2[3] & (1 << 22 )) >> 22; // 0x400000
340         caps->has3DNow    = (regs2[3] & (1 << 31 )) >> 31; //0x80000000
341         caps->has3DNowExt = (regs2[3] & (1 << 30 )) >> 30;
342         caps->hasSSE4a = (regs2[2] & (1 << 6 )) >>  6; // 0x0000040
343     }
344     if(regs[0]>=0x80000006)
345     {
346         do_cpuid(0x80000006, regs2);
347         mp_msg(MSGT_CPUDETECT,MSGL_V,"extended cache-info: %d\n",regs2[2]&0x7FFFFFFF);
348         caps->cl_size  = regs2[2] & 0xFF;
349     }
350     mp_msg(MSGT_CPUDETECT,MSGL_V,"Detected cache-line size is %u bytes\n",caps->cl_size);
351 #if 0
352     mp_msg(MSGT_CPUDETECT,MSGL_INFO,"cpudetect: MMX=%d MMX2=%d SSE=%d SSE2=%d 3DNow=%d 3DNowExt=%d\n",
353            gCpuCaps.hasMMX,
354            gCpuCaps.hasMMX2,
355            gCpuCaps.hasSSE,
356            gCpuCaps.hasSSE2,
357            gCpuCaps.has3DNow,
358            gCpuCaps.has3DNowExt);
359 #endif
360
361 #if CONFIG_RUNTIME_CPUDETECT
362         /* FIXME: Does SSE2 need more OS support, too? */
363         if (caps->hasSSE)
364             check_os_katmai_support();
365         if (!caps->hasSSE)
366             caps->hasSSE2 = 0;
367 //          caps->has3DNow=1;
368 //          caps->hasMMX2 = 0;
369 //          caps->hasMMX = 0;
370
371 #else
372 #if !HAVE_MMX
373         if(caps->hasMMX) mp_msg(MSGT_CPUDETECT,MSGL_WARN,"MMX supported but disabled\n");
374         caps->hasMMX=0;
375 #endif
376 #if !HAVE_MMX2
377         if(caps->hasMMX2) mp_msg(MSGT_CPUDETECT,MSGL_WARN,"MMX2 supported but disabled\n");
378         caps->hasMMX2=0;
379 #endif
380 #if !HAVE_SSE
381         if(caps->hasSSE) mp_msg(MSGT_CPUDETECT,MSGL_WARN,"SSE supported but disabled\n");
382         caps->hasSSE=0;
383 #endif
384 #if !HAVE_SSE2
385         if(caps->hasSSE2) mp_msg(MSGT_CPUDETECT,MSGL_WARN,"SSE2 supported but disabled\n");
386         caps->hasSSE2=0;
387 #endif
388 #if !HAVE_AMD3DNOW
389         if(caps->has3DNow) mp_msg(MSGT_CPUDETECT,MSGL_WARN,"3DNow supported but disabled\n");
390         caps->has3DNow=0;
391 #endif
392 #if !HAVE_AMD3DNOWEXT
393         if(caps->has3DNowExt) mp_msg(MSGT_CPUDETECT,MSGL_WARN,"3DNowExt supported but disabled\n");
394         caps->has3DNowExt=0;
395 #endif
396 #endif  // CONFIG_RUNTIME_CPUDETECT
397 }
398
399 char *GetCpuFriendlyName(unsigned int regs[], unsigned int regs2[]){
400     char vendor[13];
401     char *retname;
402     int i;
403
404     if (NULL==(retname=malloc(256))) {
405         mp_msg(MSGT_CPUDETECT,MSGL_FATAL,"Error: GetCpuFriendlyName() not enough memory\n");
406         exit(1);
407     }
408     retname[0] = '\0';
409
410     sprintf(vendor,"%.4s%.4s%.4s",(char*)(regs+1),(char*)(regs+3),(char*)(regs+2));
411
412     do_cpuid(0x80000000,regs);
413     if (regs[0] >= 0x80000004)
414     {
415         // CPU has built-in namestring
416         for (i = 0x80000002; i <= 0x80000004; i++)
417         {
418             do_cpuid(i, regs);
419             strncat(retname, (char*)regs, 16);
420         }
421     }
422     return retname;
423 }
424
425 #else /* ARCH_X86 */
426
427 #ifdef __APPLE__
428 #include <sys/sysctl.h>
429 #elif defined(__AMIGAOS4__)
430 /* nothing */
431 #else
432 #include <signal.h>
433 #include <setjmp.h>
434
435 static sigjmp_buf jmpbuf;
436 static volatile sig_atomic_t canjump = 0;
437
438 static void sigill_handler (int sig)
439 {
440     if (!canjump) {
441         signal (sig, SIG_DFL);
442         raise (sig);
443     }
444
445     canjump = 0;
446     siglongjmp (jmpbuf, 1);
447 }
448 #endif /* __APPLE__ */
449
450 void GetCpuCaps( CpuCaps *caps)
451 {
452     caps->cpuType=0;
453     caps->cpuModel=0;
454     caps->cpuStepping=0;
455     caps->hasMMX=0;
456     caps->hasMMX2=0;
457     caps->has3DNow=0;
458     caps->has3DNowExt=0;
459     caps->hasSSE=0;
460     caps->hasSSE2=0;
461     caps->hasSSE3=0;
462     caps->hasSSSE3=0;
463     caps->hasSSE4=0;
464     caps->hasSSE42=0;
465     caps->hasSSE4a=0;
466     caps->hasAVX=0;
467     caps->isX86=0;
468     caps->hasAltiVec = 0;
469 #if HAVE_ALTIVEC
470 #ifdef __APPLE__
471 /*
472   rip-off from ffmpeg altivec detection code.
473   this code also appears on Apple's AltiVec pages.
474  */
475     {
476         int sels[2] = {CTL_HW, HW_VECTORUNIT};
477         int has_vu = 0;
478         size_t len = sizeof(has_vu);
479         int err;
480
481         err = sysctl(sels, 2, &has_vu, &len, NULL, 0);
482
483         if (err == 0)
484             if (has_vu != 0)
485                 caps->hasAltiVec = 1;
486     }
487 #elif defined(__AMIGAOS4__)
488     ULONG result = 0;
489
490     GetCPUInfoTags(GCIT_VectorUnit, &result, TAG_DONE);
491     if (result == VECTORTYPE_ALTIVEC)
492         caps->hasAltiVec = 1;
493 #else
494 /* no Darwin, do it the brute-force way */
495 /* this is borrowed from the libmpeg2 library */
496     {
497         signal (SIGILL, sigill_handler);
498         if (sigsetjmp (jmpbuf, 1)) {
499             signal (SIGILL, SIG_DFL);
500         } else {
501             canjump = 1;
502
503         __asm__ volatile ("mtspr 256, %0\n\t"
504                           "vand %%v0, %%v0, %%v0"
505                           :
506                           : "r" (-1));
507
508         signal (SIGILL, SIG_DFL);
509         caps->hasAltiVec = 1;
510         }
511     }
512 #endif /* __APPLE__ */
513     mp_msg(MSGT_CPUDETECT,MSGL_V,"AltiVec %sfound\n", (caps->hasAltiVec ? "" : "not "));
514 #endif /* HAVE_ALTIVEC */
515
516     if (ARCH_IA64)
517         mp_msg(MSGT_CPUDETECT,MSGL_V,"CPU: Intel Itanium\n");
518
519     if (ARCH_SPARC)
520         mp_msg(MSGT_CPUDETECT,MSGL_V,"CPU: Sun Sparc\n");
521
522     if (ARCH_ARM)
523         mp_msg(MSGT_CPUDETECT,MSGL_V,"CPU: ARM\n");
524
525     if (ARCH_PPC)
526         mp_msg(MSGT_CPUDETECT,MSGL_V,"CPU: PowerPC\n");
527
528     if (ARCH_ALPHA)
529         mp_msg(MSGT_CPUDETECT,MSGL_V,"CPU: Digital Alpha\n");
530
531     if (ARCH_MIPS)
532         mp_msg(MSGT_CPUDETECT,MSGL_V,"CPU: MIPS\n");
533
534     if (ARCH_PA_RISC)
535         mp_msg(MSGT_CPUDETECT,MSGL_V,"CPU: Hewlett-Packard PA-RISC\n");
536
537     if (ARCH_S390)
538         mp_msg(MSGT_CPUDETECT,MSGL_V,"CPU: IBM S/390\n");
539
540     if (ARCH_S390X)
541         mp_msg(MSGT_CPUDETECT,MSGL_V,"CPU: IBM S/390X\n");
542
543     if (ARCH_VAX)
544         mp_msg(MSGT_CPUDETECT,MSGL_V, "CPU: Digital VAX\n" );
545
546     if (ARCH_XTENSA)
547         mp_msg(MSGT_CPUDETECT,MSGL_V, "CPU: Tensilica Xtensa\n" );
548 }
549 #endif /* !ARCH_X86 */