Update ChangeLog and remove svn log from the make install target.
[melted] / 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 }