]> git.sesse.net Git - mlt/blob - src/modules/xine/cpu_accel.c
Merge ../mlt++
[mlt] / src / modules / xine / cpu_accel.c
1 /*
2  * cpu_accel.c
3  * Copyright (C) 1999-2001 Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
4  *
5  * This file is part of mpeg2dec, a free MPEG-2 video stream decoder.
6  *
7  * mpeg2dec is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * mpeg2dec 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
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 //#include "config.h"
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <inttypes.h>
27 #include <signal.h>
28 #include <setjmp.h>
29 #include <dlfcn.h>
30
31 #define LOG_MODULE "cpu_accel"
32 #define LOG_VERBOSE
33 /*
34 #define LOG
35 */
36
37 #include "xineutils.h"
38
39 #if defined(ARCH_X86) || defined(ARCH_X86_64)
40 #if defined __x86_64__
41 static uint32_t arch_accel (void)
42 {
43   uint32_t caps;
44   /* No need to test for this on AMD64, we know what the 
45      platform has.  */
46   caps = MM_ACCEL_X86_MMX | MM_ACCEL_X86_SSE | MM_ACCEL_X86_MMXEXT | MM_ACCEL_X86_SSE2;
47
48   return caps;
49 }
50 #else
51 static uint32_t arch_accel (void)
52 {
53 #ifndef _MSC_VER
54
55   uint32_t eax, ebx, ecx, edx;
56   int AMD;
57   uint32_t caps;
58
59 #ifndef PIC
60 #define cpuid(op,eax,ebx,ecx,edx)       \
61     __asm__ ("cpuid"                        \
62          : "=a" (eax),                  \
63            "=b" (ebx),                  \
64            "=c" (ecx),                  \
65            "=d" (edx)                   \
66          : "a" (op)                     \
67          : "cc")
68 #else   /* PIC version : save ebx */
69 #define cpuid(op,eax,ebx,ecx,edx)       \
70     __asm__ ("pushl %%ebx\n\t"              \
71          "cpuid\n\t"                    \
72          "movl %%ebx,%1\n\t"            \
73          "popl %%ebx"                   \
74          : "=a" (eax),                  \
75            "=r" (ebx),                  \
76            "=c" (ecx),                  \
77            "=d" (edx)                   \
78          : "a" (op)                     \
79          : "cc")
80 #endif
81
82   __asm__ ("pushfl\n\t"
83        "pushfl\n\t"
84        "popl %0\n\t"
85        "movl %0,%1\n\t"
86        "xorl $0x200000,%0\n\t"
87        "pushl %0\n\t"
88        "popfl\n\t"
89        "pushfl\n\t"
90        "popl %0\n\t"
91        "popfl"
92        : "=r" (eax),
93        "=r" (ebx)
94        :
95        : "cc");
96
97   if (eax == ebx)             /* no cpuid */
98     return 0;
99
100   cpuid (0x00000000, eax, ebx, ecx, edx);
101   if (!eax)                   /* vendor string only */
102     return 0;
103
104   AMD = (ebx == 0x68747541) && (ecx == 0x444d4163) && (edx == 0x69746e65);
105
106   cpuid (0x00000001, eax, ebx, ecx, edx);
107   if (! (edx & 0x00800000))   /* no MMX */
108     return 0;
109
110   caps = MM_ACCEL_X86_MMX;
111   if (edx & 0x02000000)       /* SSE - identical to AMD MMX extensions */
112     caps |= MM_ACCEL_X86_SSE | MM_ACCEL_X86_MMXEXT;
113
114   if (edx & 0x04000000)       /* SSE2 */
115     caps |= MM_ACCEL_X86_SSE2;  
116     
117   cpuid (0x80000000, eax, ebx, ecx, edx);
118   if (eax < 0x80000001)       /* no extended capabilities */
119     return caps;
120
121   cpuid (0x80000001, eax, ebx, ecx, edx);
122
123   if (edx & 0x80000000)
124     caps |= MM_ACCEL_X86_3DNOW;
125
126   if (AMD && (edx & 0x00400000))      /* AMD MMX extensions */
127     caps |= MM_ACCEL_X86_MMXEXT;
128
129   return caps;
130 #else /* _MSC_VER */
131   return 0;
132 #endif
133 }
134 #endif /* x86_64 */
135
136 static jmp_buf sigill_return;
137
138 static void sigill_handler (int n) {
139   longjmp(sigill_return, 1);
140 }
141 #endif /* ARCH_X86 */
142
143 #if defined (ARCH_PPC) && defined (ENABLE_ALTIVEC)
144 static sigjmp_buf jmpbuf;
145 static volatile sig_atomic_t canjump = 0;
146
147 static void sigill_handler (int sig)
148 {
149     if (!canjump) {
150         signal (sig, SIG_DFL);
151         raise (sig);
152     }
153
154     canjump = 0;
155     siglongjmp (jmpbuf, 1);
156 }
157
158 static uint32_t arch_accel (void)
159 {
160     signal (SIGILL, sigill_handler);
161     if (sigsetjmp (jmpbuf, 1)) {
162         signal (SIGILL, SIG_DFL);
163         return 0;
164     }
165
166     canjump = 1;
167
168     __asm__ volatile ("mtspr 256, %0\n\t"
169                   "vand %%v0, %%v0, %%v0"
170                   :
171                   : "r" (-1));
172
173     signal (SIGILL, SIG_DFL);
174     return MM_ACCEL_PPC_ALTIVEC;
175 }
176 #endif /* ARCH_PPC */
177
178 uint32_t xine_mm_accel (void)
179 {
180   static int initialized = 0;
181   static uint32_t accel;
182
183   if (!initialized) {
184 #if defined (ARCH_X86) || (defined (ARCH_PPC) && defined (ENABLE_ALTIVEC))
185     accel = arch_accel ();
186 #elif defined (HAVE_MLIB)
187 #ifdef MLIB_LAZYLOAD
188     void *hndl;
189
190     if ((hndl = dlopen("libmlib.so.2", RTLD_LAZY | RTLD_GLOBAL | RTLD_NODELETE)) == NULL) {
191       accel = 0;
192     }
193     else {
194       dlclose(hndl);
195       accel = MM_ACCEL_MLIB;
196     }
197 #else
198     accel = MM_ACCEL_MLIB;
199 #endif
200 #else
201     accel = 0;
202 #endif
203
204 #if defined(ARCH_X86) || defined(ARCH_X86_64)
205 #ifndef _MSC_VER
206     /* test OS support for SSE */
207     if( accel & MM_ACCEL_X86_SSE ) {
208       void (*old_sigill_handler)(int);
209
210       old_sigill_handler = signal (SIGILL, sigill_handler); 
211
212       if (setjmp(sigill_return)) {
213         lprintf ("OS doesn't support SSE instructions.\n");
214         accel &= ~(MM_ACCEL_X86_SSE|MM_ACCEL_X86_SSE2);
215       } else {
216         __asm__ volatile ("xorps %xmm0, %xmm0");
217       }
218
219       signal (SIGILL, old_sigill_handler);
220     }
221 #endif /* _MSC_VER */
222 #endif /* ARCH_X86 || ARCH_X86_64 */
223     
224     if(getenv("XINE_NO_ACCEL")) {
225       accel = 0;
226     }
227
228     initialized = 1;
229   }
230
231   return accel;
232 }