X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fmisc%2Fcpu.c;h=f223bf859c0b133811a48ee61f5062c8f6e19604;hb=8210d67fc5e51e0951dbad9b833b89a351bdb1f6;hp=39e9331390933cd958743f2c11fd4218b7eb675a;hpb=2fa6c9ce280b037c058eed166bfc51e7c70c5d14;p=vlc diff --git a/src/misc/cpu.c b/src/misc/cpu.c index 39e9331390..f223bf859c 100644 --- a/src/misc/cpu.c +++ b/src/misc/cpu.c @@ -1,8 +1,8 @@ /***************************************************************************** * cpu.c: CPU detection code ***************************************************************************** - * Copyright (C) 1998-2002 VideoLAN - * $Id: cpu.c,v 1.5 2002/08/19 11:13:45 sam Exp $ + * Copyright (C) 1998-2004 the VideoLAN team + * $Id$ * * Authors: Samuel Hocevar * Christophe Massiot @@ -20,145 +20,123 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************/ /***************************************************************************** * Preamble *****************************************************************************/ -#include /* SIGHUP, SIGINT, SIGKILL */ -#include /* longjmp, setjmp */ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif -#include +#include -#ifdef SYS_DARWIN -# include /* AltiVec detection */ -# include /* some day the header files||compiler * - will define it for us */ -# include +#include +#ifndef WIN32 +#include +#include #endif -#include "vlc_cpu.h" - -/***************************************************************************** - * Local prototypes - *****************************************************************************/ -static void SigHandler ( int ); -static u32 Capabilities ( vlc_object_t * ); +#include "libvlc.h" -/***************************************************************************** - * Global variables - they're needed for signal handling - *****************************************************************************/ -static jmp_buf env; -static int i_illegal; -#if defined( __i386__ ) -static char *psz_capability; +#if defined(__APPLE__) && (defined(__ppc__) || defined(__ppc64__)) +#include #endif -/***************************************************************************** - * CPUCapabilities: get the CPU capabilities - ***************************************************************************** - * This function is a wrapper around Capabilities(). - *****************************************************************************/ -u32 __CPUCapabilities( vlc_object_t *p_this ) +#if defined( __i386__ ) || defined( __x86_64__ ) \ + || defined( __ppc__ ) || defined( __ppc64__ ) +static bool check_OS_capability( const char *psz_capability, pid_t pid ) { - u32 i_capabilities; +#ifndef WIN32 + int status; - vlc_mutex_lock( p_this->p_vlc->p_global_lock ); - i_capabilities = Capabilities( p_this ); - vlc_mutex_unlock( p_this->p_vlc->p_global_lock ); - - return i_capabilities; + if( pid == -1 ) + return false; /* fail safe :-/ */ + + while( waitpid( pid, &status, 0 ) == -1 ); + + if( WIFEXITED( status ) && WEXITSTATUS( status ) == 0 ) + return true; + + fprintf( stderr, "warning: your CPU has %s instructions, but not your " + "operating system.\n", psz_capability ); + fprintf( stderr, " some optimizations will be disabled unless " + "you upgrade your OS\n" ); + return false; +#else +# warning FIXME! +# define fork() (errno = ENOSYS, -1) + (void)pid; + (void)psz_capability; + return true; +#endif } +#endif /***************************************************************************** - * Capabilities: list the processors MMX support and other capabilities + * CPUCapabilities: get the CPU capabilities ***************************************************************************** * This function is called to list extensions the CPU may have. *****************************************************************************/ -static u32 Capabilities( vlc_object_t *p_this ) +uint32_t CPUCapabilities( void ) { - volatile u32 i_capabilities = CPU_CAPABILITY_NONE; - -#if defined( SYS_DARWIN ) - struct host_basic_info hi; - kern_return_t ret; - host_name_port_t host; + uint32_t i_capabilities = CPU_CAPABILITY_NONE; - int i_size; - char *psz_name, *psz_subname; - - i_capabilities |= CPU_CAPABILITY_FPU; - - /* Should 'never' fail? */ - host = mach_host_self(); - - i_size = sizeof( hi ) / sizeof( int ); - ret = host_info( host, HOST_BASIC_INFO, ( host_info_t )&hi, &i_size ); - - if( ret != KERN_SUCCESS ) - { - fprintf( stderr, "error: couldn't get CPU information\n" ); - return i_capabilities; - } - - slot_name( hi.cpu_type, hi.cpu_subtype, &psz_name, &psz_subname ); - /* FIXME: need better way to detect newer proccessors. - * could do strncmp(a,b,5), but that's real ugly */ - if( !strcmp(psz_name, "ppc7400") || !strcmp(psz_name, "ppc7450") ) - { - i_capabilities |= CPU_CAPABILITY_ALTIVEC; - } - - return i_capabilities; - -#elif defined( __i386__ ) - volatile unsigned int i_eax, i_ebx, i_ecx, i_edx; - volatile vlc_bool_t b_amd; +#if defined( __i386__ ) || defined( __x86_64__ ) + unsigned int i_eax, i_ebx, i_ecx, i_edx; + bool b_amd; /* Needed for x86 CPU capabilities detection */ -# define cpuid( a ) \ - asm volatile ( "pushl %%ebx\n\t" \ - "cpuid\n\t" \ - "movl %%ebx,%1\n\t" \ - "popl %%ebx\n\t" \ - : "=a" ( i_eax ), \ - "=r" ( i_ebx ), \ - "=c" ( i_ecx ), \ - "=d" ( i_edx ) \ - : "a" ( a ) \ - : "cc" ); - -# if defined( CAN_COMPILE_SSE ) || defined ( CAN_COMPILE_3DNOW ) - sighandler_t pf_sigill = signal( SIGILL, SigHandler ); +# if defined( __x86_64__ ) +# define cpuid( reg ) \ + asm volatile ( "cpuid\n\t" \ + "movl %%ebx,%1\n\t" \ + : "=a" ( i_eax ), \ + "=b" ( i_ebx ), \ + "=c" ( i_ecx ), \ + "=d" ( i_edx ) \ + : "a" ( reg ) \ + : "cc" ); +# else +# define cpuid( reg ) \ + asm volatile ( "push %%ebx\n\t" \ + "cpuid\n\t" \ + "movl %%ebx,%1\n\t" \ + "pop %%ebx\n\t" \ + : "=a" ( i_eax ), \ + "=r" ( i_ebx ), \ + "=c" ( i_ecx ), \ + "=d" ( i_edx ) \ + : "a" ( reg ) \ + : "cc" ); # endif i_capabilities |= CPU_CAPABILITY_FPU; - /* test for a 486 CPU */ - asm volatile ( "pushl %%ebx\n\t" - "pushfl\n\t" - "popl %%eax\n\t" +# if defined( __i386__ ) + /* check if cpuid instruction is supported */ + asm volatile ( "push %%ebx\n\t" + "pushf\n\t" + "pop %%eax\n\t" "movl %%eax, %%ebx\n\t" "xorl $0x200000, %%eax\n\t" - "pushl %%eax\n\t" - "popfl\n\t" - "pushfl\n\t" - "popl %%eax\n\t" + "push %%eax\n\t" + "popf\n\t" + "pushf\n\t" + "pop %%eax\n\t" "movl %%ebx,%1\n\t" - "popl %%ebx\n\t" + "pop %%ebx\n\t" : "=a" ( i_eax ), "=r" ( i_ebx ) : : "cc" ); if( i_eax == i_ebx ) - { -# if defined( CAN_COMPILE_SSE ) || defined ( CAN_COMPILE_3DNOW ) - signal( SIGILL, pf_sigill ); + goto out; +# else + /* x86_64 supports cpuid instruction, so we dont need to check it */ # endif - return i_capabilities; - } i_capabilities |= CPU_CAPABILITY_486; @@ -166,12 +144,7 @@ static u32 Capabilities( vlc_object_t *p_this ) cpuid( 0x00000000 ); if( !i_eax ) - { -# if defined( CAN_COMPILE_SSE ) || defined ( CAN_COMPILE_3DNOW ) - signal( SIGILL, pf_sigill ); -# endif - return i_capabilities; - } + goto out; /* FIXME: this isn't correct, since some 486s have cpuid */ i_capabilities |= CPU_CAPABILITY_586; @@ -184,12 +157,7 @@ static u32 Capabilities( vlc_object_t *p_this ) cpuid( 0x00000001 ); if( ! (i_edx & 0x00800000) ) - { -# if defined( CAN_COMPILE_SSE ) || defined ( CAN_COMPILE_3DNOW ) - signal( SIGILL, pf_sigill ); -# endif - return i_capabilities; - } + goto out; i_capabilities |= CPU_CAPABILITY_MMX; @@ -199,19 +167,31 @@ static u32 Capabilities( vlc_object_t *p_this ) # ifdef CAN_COMPILE_SSE /* We test if OS supports the SSE instructions */ - psz_capability = "SSE"; - i_illegal = 0; - - if( setjmp( env ) == 0 ) + pid_t pid = fork(); + if( pid == 0 ) { /* Test a SSE instruction */ __asm__ __volatile__ ( "xorps %%xmm0,%%xmm0\n" : : ); + exit(0); } + if( check_OS_capability( "SSE", pid ) ) + i_capabilities |= CPU_CAPABILITY_SSE; +# endif + } - if( i_illegal == 0 ) + if( i_edx & 0x04000000 ) + { +# if defined(CAN_COMPILE_SSE) + /* We test if OS supports the SSE2 instructions */ + pid_t pid = fork(); + if( pid == 0 ) { - i_capabilities |= CPU_CAPABILITY_SSE; + /* Test a SSE2 instruction */ + __asm__ __volatile__ ( "movupd %%xmm0, %%xmm0\n" : : ); + exit(0); } + if( check_OS_capability( "SSE2", pid ) ) + i_capabilities |= CPU_CAPABILITY_SSE2; # endif } @@ -219,12 +199,7 @@ static u32 Capabilities( vlc_object_t *p_this ) cpuid( 0x80000000 ); if( i_eax < 0x80000001 ) - { -# if defined( CAN_COMPILE_SSE ) || defined ( CAN_COMPILE_3DNOW ) - signal( SIGILL, pf_sigill ); -# endif - return i_capabilities; - } + goto out; /* list these additional capabilities */ cpuid( 0x80000001 ); @@ -232,19 +207,15 @@ static u32 Capabilities( vlc_object_t *p_this ) # ifdef CAN_COMPILE_3DNOW if( i_edx & 0x80000000 ) { - psz_capability = "3D Now!"; - i_illegal = 0; - - if( setjmp( env ) == 0 ) + pid_t pid = fork(); + if( pid == 0 ) { /* Test a 3D Now! instruction */ __asm__ __volatile__ ( "pfadd %%mm0,%%mm0\n" "femms\n" : : ); + exit(0); } - - if( i_illegal == 0 ) - { + if( check_OS_capability( "3D Now!", pid ) ) i_capabilities |= CPU_CAPABILITY_3DNOW; - } } # endif @@ -252,76 +223,86 @@ static u32 Capabilities( vlc_object_t *p_this ) { i_capabilities |= CPU_CAPABILITY_MMXEXT; } +out: -# if defined( CAN_COMPILE_SSE ) || defined ( CAN_COMPILE_3DNOW ) - signal( SIGILL, pf_sigill ); +#elif defined( __arm__ ) +# if defined( __ARM_EABI__ ) && !defined( __SOFTFP__ ) + i_capabilities |= CPU_CAPABILITY_FPU; # endif - return i_capabilities; -#elif defined( __powerpc__ ) - -# ifdef CAN_COMPILE_ALTIVEC - sighandler_t pf_sigill = signal( SIGILL, SigHandler ); +#elif defined( __powerpc__ ) || defined( __ppc__ ) || defined( __ppc64__ ) i_capabilities |= CPU_CAPABILITY_FPU; - i_illegal = 0; +# if defined(__APPLE__) + int selectors[2] = { CTL_HW, HW_VECTORUNIT }; + int i_has_altivec = 0; + size_t i_length = sizeof( i_has_altivec ); + int i_error = sysctl( selectors, 2, &i_has_altivec, &i_length, NULL, 0); + + if( i_error == 0 && i_has_altivec != 0 ) + i_capabilities |= CPU_CAPABILITY_ALTIVEC; - if( setjmp( env ) == 0 ) +# elif defined( CAN_COMPILE_ALTIVEC ) + pid_t pid = fork(); + if( pid == 0 ) { asm volatile ("mtspr 256, %0\n\t" "vand %%v0, %%v0, %%v0" : : "r" (-1)); + exit(0); } - if( i_illegal == 0 ) - { + if( check_OS_capability( "Altivec", pid ) ) i_capabilities |= CPU_CAPABILITY_ALTIVEC; - } - signal( SIGILL, pf_sigill ); # endif - return i_capabilities; - #elif defined( __sparc__ ) - i_capabilities |= CPU_CAPABILITY_FPU; - return i_capabilities; -#else - /* default behaviour */ - return i_capabilities; +#elif defined( _MSC_VER ) && !defined( UNDER_CE ) + i_capabilities |= CPU_CAPABILITY_FPU; #endif + return i_capabilities; } +uint32_t cpu_flags = 0; + + /***************************************************************************** - * SigHandler: system signal handler - ***************************************************************************** - * This function is called when an illegal instruction signal is received by - * the program. We use this function to test OS and CPU capabilities - *****************************************************************************/ -static void SigHandler( int i_signal ) + * vlc_CPU: get pre-computed CPU capability flags + ****************************************************************************/ +unsigned vlc_CPU (void) { - /* Acknowledge the signal received */ - i_illegal = 1; + return cpu_flags; +} -#ifdef HAVE_SIGRELSE - sigrelse( i_signal ); -#endif +static vlc_memcpy_t pf_vlc_memcpy = memcpy; +static vlc_memset_t pf_vlc_memset = memset; -#if defined( __i386__ ) - fprintf( stderr, "warning: your CPU has %s instructions, but not your " - "operating system.\n", psz_capability ); - fprintf( stderr, " some optimizations will be disabled unless " - "you upgrade your OS\n" ); -# if defined( SYS_LINUX ) - fprintf( stderr, " (for instance Linux kernel 2.4.x or later)\n" ); -# endif -#endif +void vlc_fastmem_register (vlc_memcpy_t cpy, vlc_memset_t set) +{ + if (cpy) + pf_vlc_memcpy = cpy; + if (set) + pf_vlc_memset = set; +} - longjmp( env, 1 ); +/** + * vlc_memcpy: fast CPU-dependent memcpy + */ +void *vlc_memcpy (void *tgt, const void *src, size_t n) +{ + return pf_vlc_memcpy (tgt, src, n); } +/** + * vlc_memset: fast CPU-dependent memset + */ +void *vlc_memset (void *tgt, int c, size_t n) +{ + return pf_vlc_memset (tgt, c, n); +}