cpu: privatize vlc_CPU_init()
[vlc.git] / src / misc / cpu.c
blob8451facaa23bb5ce64ed0e840c07610280c4221b
1 /*****************************************************************************
2 * cpu.c: CPU detection code
3 *****************************************************************************
4 * Copyright (C) 1998-2004 VLC authors and VideoLAN
5 * $Id$
7 * Authors: Samuel Hocevar <sam@zoy.org>
8 * Christophe Massiot <massiot@via.ecp.fr>
9 * Eugenio Jarosiewicz <ej0@cise.ufl.eduEujenio>
11 * This program is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU Lesser General Public License as published by
13 * the Free Software Foundation; either version 2.1 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public License
22 * along with this program; if not, write to the Free Software Foundation,
23 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24 *****************************************************************************/
26 /*****************************************************************************
27 * Preamble
28 *****************************************************************************/
29 #ifdef HAVE_CONFIG_H
30 # include "config.h"
31 #endif
33 #include <vlc_common.h>
34 #include <vlc_cpu.h>
35 #include <vlc_memstream.h>
36 #include "libvlc.h"
38 #include <assert.h>
40 #ifndef __linux__
41 #include <sys/types.h>
42 #ifndef _WIN32
43 #include <unistd.h>
44 #include <sys/wait.h>
45 #include <signal.h>
46 #else
47 #include <errno.h>
48 #endif
50 #ifdef __APPLE__
51 #include <sys/sysctl.h>
52 #endif
53 #ifdef __ANDROID__
54 #include <cpu-features.h>
55 #endif
57 #if defined(__OpenBSD__) && defined(__powerpc__)
58 #include <sys/param.h>
59 #include <sys/sysctl.h>
60 #include <machine/cpu.h>
61 #endif
63 static uint32_t cpu_flags;
65 #if defined (__i386__) || defined (__x86_64__) || defined (__powerpc__) \
66 || defined (__ppc__) || defined (__ppc64__) || defined (__powerpc64__)
67 # if defined (HAVE_FORK)
68 static bool vlc_CPU_check (const char *name, void (*func) (void))
70 pid_t pid = fork();
72 switch (pid)
74 case 0:
75 signal (SIGILL, SIG_DFL);
76 func ();
77 _exit (0);
78 case -1:
79 return false;
82 int status;
83 while( waitpid( pid, &status, 0 ) == -1 );
85 if( WIFEXITED( status ) && WEXITSTATUS( status ) == 0 )
86 return true;
88 fprintf (stderr, "Warning: your CPU has %s instructions, but not your "
89 "operating system.\n", name);
90 fprintf( stderr, " some optimizations will be disabled unless "
91 "you upgrade your OS\n" );
92 return false;
95 #if defined (CAN_COMPILE_SSE) && !defined (__SSE__)
96 VLC_SSE static void SSE_test (void)
98 asm volatile ("xorps %%xmm0,%%xmm0\n" : : : "xmm0", "xmm1");
100 #endif
101 #if defined (CAN_COMPILE_3DNOW)
102 VLC_MMX static void ThreeD_Now_test (void)
104 asm volatile ("pfadd %%mm0,%%mm0\n" "femms\n" : : : "mm0");
106 #endif
108 #if defined (CAN_COMPILE_ALTIVEC)
109 static void Altivec_test (void)
111 asm volatile ("mtspr 256, %0\n" "vand %%v0, %%v0, %%v0\n" : : "r" (-1));
113 #endif
115 #else /* _WIN32 || __OS2__ */
116 # define vlc_CPU_check(name, func) (1)
117 #endif
118 #endif
121 * Determines the CPU capabilities and stores them in cpu_flags.
122 * The result can be retrieved with vlc_CPU().
124 void vlc_CPU_init (void)
126 uint32_t i_capabilities = 0;
128 #if defined( __i386__ ) || defined( __x86_64__ )
129 unsigned int i_eax, i_ebx, i_ecx, i_edx;
130 bool b_amd;
132 /* Needed for x86 CPU capabilities detection */
133 # if defined (__i386__) && defined (__PIC__)
134 # define cpuid(reg) \
135 asm volatile ("xchgl %%ebx,%1\n\t" \
136 "cpuid\n\t" \
137 "xchgl %%ebx,%1\n\t" \
138 : "=a" (i_eax), "=r" (i_ebx), "=c" (i_ecx), "=d" (i_edx) \
139 : "a" (reg) \
140 : "cc");
141 # else
142 # define cpuid(reg) \
143 asm volatile ("cpuid\n\t" \
144 : "=a" (i_eax), "=b" (i_ebx), "=c" (i_ecx), "=d" (i_edx) \
145 : "a" (reg) \
146 : "cc");
147 # endif
148 /* Check if the OS really supports the requested instructions */
149 # if defined (__i386__) && !defined (__i486__) && !defined (__i586__) \
150 && !defined (__i686__) && !defined (__pentium4__) \
151 && !defined (__k6__) && !defined (__athlon__) && !defined (__k8__)
152 /* check if cpuid instruction is supported */
153 asm volatile ( "push %%ebx\n\t"
154 "pushf\n\t"
155 "pop %%eax\n\t"
156 "movl %%eax, %%ebx\n\t"
157 "xorl $0x200000, %%eax\n\t"
158 "push %%eax\n\t"
159 "popf\n\t"
160 "pushf\n\t"
161 "pop %%eax\n\t"
162 "movl %%ebx,%1\n\t"
163 "pop %%ebx\n\t"
164 : "=a" ( i_eax ),
165 "=r" ( i_ebx )
167 : "cc" );
169 if( i_eax == i_ebx )
170 goto out;
171 # endif
173 /* the CPU supports the CPUID instruction - get its level */
174 cpuid( 0x00000000 );
176 # if defined (__i386__) && !defined (__i586__) \
177 && !defined (__i686__) && !defined (__pentium4__) \
178 && !defined (__k6__) && !defined (__athlon__) && !defined (__k8__)
179 if( !i_eax )
180 goto out;
181 #endif
183 /* borrowed from mpeg2dec */
184 b_amd = ( i_ebx == 0x68747541 ) && ( i_ecx == 0x444d4163 )
185 && ( i_edx == 0x69746e65 );
187 /* test for the MMX flag */
188 cpuid( 0x00000001 );
189 # if !defined (__MMX__)
190 if( ! (i_edx & 0x00800000) )
191 goto out;
192 # endif
193 i_capabilities |= VLC_CPU_MMX;
195 if( i_edx & 0x02000000 )
196 i_capabilities |= VLC_CPU_MMXEXT;
197 # if defined (CAN_COMPILE_SSE) && !defined (__SSE__)
198 if (( i_edx & 0x02000000 ) && vlc_CPU_check ("SSE", SSE_test))
199 # endif
201 /*if( i_edx & 0x02000000 )*/
202 i_capabilities |= VLC_CPU_SSE;
203 if (i_edx & 0x04000000)
204 i_capabilities |= VLC_CPU_SSE2;
205 if (i_ecx & 0x00000001)
206 i_capabilities |= VLC_CPU_SSE3;
207 if (i_ecx & 0x00000200)
208 i_capabilities |= VLC_CPU_SSSE3;
209 if (i_ecx & 0x00080000)
210 i_capabilities |= VLC_CPU_SSE4_1;
211 if (i_ecx & 0x00100000)
212 i_capabilities |= VLC_CPU_SSE4_2;
215 /* test for additional capabilities */
216 cpuid( 0x80000000 );
218 if( i_eax < 0x80000001 )
219 goto out;
221 /* list these additional capabilities */
222 cpuid( 0x80000001 );
224 # if defined (CAN_COMPILE_3DNOW) && !defined (__3dNOW__)
225 if ((i_edx & 0x80000000) && vlc_CPU_check ("3D Now!", ThreeD_Now_test))
226 # endif
227 i_capabilities |= VLC_CPU_3dNOW;
229 if( b_amd && ( i_edx & 0x00400000 ) )
230 i_capabilities |= VLC_CPU_MMXEXT;
231 out:
233 #elif defined( __powerpc__ ) || defined( __ppc__ ) || defined( __powerpc64__ ) \
234 || defined( __ppc64__ )
236 # if defined(__APPLE__) || defined(__OpenBSD__)
237 # if defined(__OpenBSD__)
238 int selectors[2] = { CTL_MACHDEP, CPU_ALTIVEC };
239 # else
240 int selectors[2] = { CTL_HW, HW_VECTORUNIT };
241 # endif
242 int i_has_altivec = 0;
243 size_t i_length = sizeof( i_has_altivec );
244 int i_error = sysctl( selectors, 2, &i_has_altivec, &i_length, NULL, 0);
246 if( i_error == 0 && i_has_altivec != 0 )
247 i_capabilities |= VLC_CPU_ALTIVEC;
249 # elif defined( CAN_COMPILE_ALTIVEC )
250 if (vlc_CPU_check ("Altivec", Altivec_test))
251 i_capabilities |= VLC_CPU_ALTIVEC;
253 # endif
255 #elif defined ( __arm__)
256 # ifdef __ANDROID__
257 if (android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON)
258 i_capabilities |= VLC_CPU_ARM_NEON;
259 # endif
261 #endif
263 cpu_flags = i_capabilities;
267 * Retrieves pre-computed CPU capability flags
269 unsigned vlc_CPU (void)
271 static vlc_once_t once = VLC_STATIC_ONCE;
272 vlc_once(&once, vlc_CPU_init);
273 return cpu_flags;
275 #endif
277 void vlc_CPU_dump (vlc_object_t *obj)
279 struct vlc_memstream stream;
281 vlc_memstream_open(&stream);
283 #if defined (__i386__) || defined (__x86_64__)
284 if (vlc_CPU_MMX())
285 vlc_memstream_puts(&stream, "MMX ");
286 if (vlc_CPU_MMXEXT())
287 vlc_memstream_puts(&stream, "MMXEXT ");
288 if (vlc_CPU_SSE())
289 vlc_memstream_puts(&stream, "SSE ");
290 if (vlc_CPU_SSE2())
291 vlc_memstream_puts(&stream, "SSE2 ");
292 if (vlc_CPU_SSE3())
293 vlc_memstream_puts(&stream, "SSE3 ");
294 if (vlc_CPU_SSSE3())
295 vlc_memstream_puts(&stream, "SSSE3 ");
296 if (vlc_CPU_SSE4_1())
297 vlc_memstream_puts(&stream, "SSE4.1 ");
298 if (vlc_CPU_SSE4_2())
299 vlc_memstream_puts(&stream, "SSE4.2 ");
300 if (vlc_CPU_SSE4A())
301 vlc_memstream_puts(&stream, "SSE4A ");
302 if (vlc_CPU_AVX())
303 vlc_memstream_puts(&stream, "AVX ");
304 if (vlc_CPU_AVX2())
305 vlc_memstream_puts(&stream, "AVX2 ");
306 if (vlc_CPU_3dNOW())
307 vlc_memstream_puts(&stream, "3DNow! ");
308 if (vlc_CPU_XOP())
309 vlc_memstream_puts(&stream, "XOP ");
310 if (vlc_CPU_FMA4())
311 vlc_memstream_puts(&stream, "FMA4 ");
313 #elif defined (__powerpc__) || defined (__ppc__) || defined (__ppc64__)
314 if (vlc_CPU_ALTIVEC())
315 vlc_memstream_puts(&stream, "AltiVec");
317 #elif defined (__arm__)
318 if (vlc_CPU_ARM_NEON())
319 vlc_memstream_puts(&stream, "ARM_NEON ");
321 #endif
323 #if HAVE_FPU
324 vlc_memstream_puts(&stream, "FPU ");
325 #endif
327 if (vlc_memstream_close(&stream) == 0)
329 msg_Dbg (obj, "CPU has capabilities %s", stream.ptr);
330 free(stream.ptr);