common_x86.c revision 4a49301e
1/* 2 * Mesa 3-D graphics library 3 * Version: 6.5.1 4 * 5 * Copyright (C) 1999-2006 Brian Paul All Rights Reserved. 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a 8 * copy of this software and associated documentation files (the "Software"), 9 * to deal in the Software without restriction, including without limitation 10 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 * and/or sell copies of the Software, and to permit persons to whom the 12 * Software is furnished to do so, subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice shall be included 15 * in all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 */ 24 25/** 26 * \file common_x86.c 27 * 28 * Check CPU capabilities & initialize optimized funtions for this particular 29 * processor. 30 * 31 * Changed by Andre Werthmann for using the new SSE functions. 32 * 33 * \author Holger Waechtler <holger@akaflieg.extern.tu-berlin.de> 34 * \author Andre Werthmann <wertmann@cs.uni-potsdam.de> 35 */ 36 37/* XXX these includes should probably go into imports.h or glheader.h */ 38#if defined(USE_SSE_ASM) && defined(__linux__) 39#include <linux/version.h> 40#endif 41#if defined(USE_SSE_ASM) && defined(__FreeBSD__) 42#include <sys/types.h> 43#include <sys/sysctl.h> 44#endif 45#if defined(USE_SSE_ASM) && defined(__OpenBSD__) 46#include <sys/param.h> 47#include <sys/sysctl.h> 48#include <machine/cpu.h> 49#endif 50 51#include "main/imports.h" 52#include "common_x86_asm.h" 53 54 55/** Bitmask of X86_FEATURE_x bits */ 56int _mesa_x86_cpu_features = 0x0; 57 58 59 60/* No reason for this to be public. 61 */ 62extern GLuint _ASMAPI _mesa_x86_has_cpuid(void); 63extern void _ASMAPI _mesa_x86_cpuid(GLuint op, GLuint *reg_eax, GLuint *reg_ebx, GLuint *reg_ecx, GLuint *reg_edx); 64extern GLuint _ASMAPI _mesa_x86_cpuid_eax(GLuint op); 65extern GLuint _ASMAPI _mesa_x86_cpuid_ebx(GLuint op); 66extern GLuint _ASMAPI _mesa_x86_cpuid_ecx(GLuint op); 67extern GLuint _ASMAPI _mesa_x86_cpuid_edx(GLuint op); 68 69 70#if defined(USE_SSE_ASM) 71/* 72 * We must verify that the Streaming SIMD Extensions are truly supported 73 * on this processor before we go ahead and hook out the optimized code. 74 * 75 * However, I have been told by Alan Cox that all 2.4 (and later) Linux 76 * kernels provide full SSE support on all processors that expose SSE via 77 * the CPUID mechanism. 78 */ 79 80/* These are assembly functions: */ 81extern void _mesa_test_os_sse_support( void ); 82extern void _mesa_test_os_sse_exception_support( void ); 83 84 85#if defined(WIN32) 86#ifndef STATUS_FLOAT_MULTIPLE_TRAPS 87# define STATUS_FLOAT_MULTIPLE_TRAPS (0xC00002B5L) 88#endif 89static LONG WINAPI ExceptionFilter(LPEXCEPTION_POINTERS exp) 90{ 91 PEXCEPTION_RECORD rec = exp->ExceptionRecord; 92 PCONTEXT ctx = exp->ContextRecord; 93 94 if ( rec->ExceptionCode == EXCEPTION_ILLEGAL_INSTRUCTION ) { 95 _mesa_debug(NULL, "EXCEPTION_ILLEGAL_INSTRUCTION\n" ); 96 _mesa_x86_cpu_features &= ~(X86_FEATURE_XMM); 97 } else if ( rec->ExceptionCode == STATUS_FLOAT_MULTIPLE_TRAPS ) { 98 _mesa_debug(NULL, "STATUS_FLOAT_MULTIPLE_TRAPS\n"); 99 /* Windows seems to clear the exception flag itself, we just have to increment Eip */ 100 } else { 101 _mesa_debug(NULL, "UNEXPECTED EXCEPTION (0x%08x), terminating!\n" ); 102 return EXCEPTION_EXECUTE_HANDLER; 103 } 104 105 if ( (ctx->ContextFlags & CONTEXT_CONTROL) != CONTEXT_CONTROL ) { 106 _mesa_debug(NULL, "Context does not contain control registers, terminating!\n"); 107 return EXCEPTION_EXECUTE_HANDLER; 108 } 109 ctx->Eip += 3; 110 111 return EXCEPTION_CONTINUE_EXECUTION; 112} 113#endif /* WIN32 */ 114 115 116/** 117 * Check if SSE is supported. 118 * If not, turn off the X86_FEATURE_XMM flag in _mesa_x86_cpu_features. 119 */ 120void _mesa_check_os_sse_support( void ) 121{ 122#if defined(__FreeBSD__) 123 { 124 int ret, enabled; 125 unsigned int len; 126 len = sizeof(enabled); 127 ret = sysctlbyname("hw.instruction_sse", &enabled, &len, NULL, 0); 128 if (ret || !enabled) 129 _mesa_x86_cpu_features &= ~(X86_FEATURE_XMM); 130 } 131#elif defined (__NetBSD__) 132 { 133 int ret, enabled; 134 size_t len = sizeof(enabled); 135 ret = sysctlbyname("machdep.sse", &enabled, &len, (void *)NULL, 0); 136 if (ret || !enabled) 137 _mesa_x86_cpu_features &= ~(X86_FEATURE_XMM); 138 } 139#elif defined(__OpenBSD__) 140 { 141 int mib[2]; 142 int ret, enabled; 143 size_t len = sizeof(enabled); 144 145 mib[0] = CTL_MACHDEP; 146 mib[1] = CPU_SSE; 147 148 ret = sysctl(mib, 2, &enabled, &len, NULL, 0); 149 if (ret || !enabled) 150 _mesa_x86_cpu_features &= ~(X86_FEATURE_XMM); 151 } 152#elif defined(WIN32) 153 LPTOP_LEVEL_EXCEPTION_FILTER oldFilter; 154 155 /* Install our ExceptionFilter */ 156 oldFilter = SetUnhandledExceptionFilter( ExceptionFilter ); 157 158 if ( cpu_has_xmm ) { 159 _mesa_debug(NULL, "Testing OS support for SSE...\n"); 160 161 _mesa_test_os_sse_support(); 162 163 if ( cpu_has_xmm ) { 164 _mesa_debug(NULL, "Yes.\n"); 165 } else { 166 _mesa_debug(NULL, "No!\n"); 167 } 168 } 169 170 if ( cpu_has_xmm ) { 171 _mesa_debug(NULL, "Testing OS support for SSE unmasked exceptions...\n"); 172 173 _mesa_test_os_sse_exception_support(); 174 175 if ( cpu_has_xmm ) { 176 _mesa_debug(NULL, "Yes.\n"); 177 } else { 178 _mesa_debug(NULL, "No!\n"); 179 } 180 } 181 182 /* Restore previous exception filter */ 183 SetUnhandledExceptionFilter( oldFilter ); 184 185 if ( cpu_has_xmm ) { 186 _mesa_debug(NULL, "Tests of OS support for SSE passed.\n"); 187 } else { 188 _mesa_debug(NULL, "Tests of OS support for SSE failed!\n"); 189 } 190#else 191 /* Do nothing on other platforms for now. 192 */ 193 _mesa_debug(NULL, "Not testing OS support for SSE, leaving enabled.\n"); 194#endif /* __FreeBSD__ */ 195} 196 197#endif /* USE_SSE_ASM */ 198 199 200/** 201 * Initialize the _mesa_x86_cpu_features bitfield. 202 * This is a no-op if called more than once. 203 */ 204void 205_mesa_get_x86_features(void) 206{ 207 static int called = 0; 208 209 if (called) 210 return; 211 212 called = 1; 213 214#ifdef USE_X86_ASM 215 _mesa_x86_cpu_features = 0x0; 216 217 if (_mesa_getenv( "MESA_NO_ASM")) { 218 return; 219 } 220 221 if (!_mesa_x86_has_cpuid()) { 222 _mesa_debug(NULL, "CPUID not detected\n"); 223 } 224 else { 225 GLuint cpu_features; 226 GLuint cpu_ext_features; 227 GLuint cpu_ext_info; 228 char cpu_vendor[13]; 229 GLuint result; 230 231 /* get vendor name */ 232 _mesa_x86_cpuid(0, &result, (GLuint *)(cpu_vendor + 0), (GLuint *)(cpu_vendor + 8), (GLuint *)(cpu_vendor + 4)); 233 cpu_vendor[12] = '\0'; 234 235 _mesa_debug(NULL, "CPU vendor: %s\n", cpu_vendor); 236 237 /* get cpu features */ 238 cpu_features = _mesa_x86_cpuid_edx(1); 239 240 if (cpu_features & X86_CPU_FPU) 241 _mesa_x86_cpu_features |= X86_FEATURE_FPU; 242 if (cpu_features & X86_CPU_CMOV) 243 _mesa_x86_cpu_features |= X86_FEATURE_CMOV; 244 245#ifdef USE_MMX_ASM 246 if (cpu_features & X86_CPU_MMX) 247 _mesa_x86_cpu_features |= X86_FEATURE_MMX; 248#endif 249 250#ifdef USE_SSE_ASM 251 if (cpu_features & X86_CPU_XMM) 252 _mesa_x86_cpu_features |= X86_FEATURE_XMM; 253 if (cpu_features & X86_CPU_XMM2) 254 _mesa_x86_cpu_features |= X86_FEATURE_XMM2; 255#endif 256 257 /* query extended cpu features */ 258 if ((cpu_ext_info = _mesa_x86_cpuid_eax(0x80000000)) > 0x80000000) { 259 if (cpu_ext_info >= 0x80000001) { 260 261 cpu_ext_features = _mesa_x86_cpuid_edx(0x80000001); 262 263 if (cpu_features & X86_CPU_MMX) { 264 265#ifdef USE_3DNOW_ASM 266 if (cpu_ext_features & X86_CPUEXT_3DNOW) 267 _mesa_x86_cpu_features |= X86_FEATURE_3DNOW; 268 if (cpu_ext_features & X86_CPUEXT_3DNOW_EXT) 269 _mesa_x86_cpu_features |= X86_FEATURE_3DNOWEXT; 270#endif 271 272#ifdef USE_MMX_ASM 273 if (cpu_ext_features & X86_CPUEXT_MMX_EXT) 274 _mesa_x86_cpu_features |= X86_FEATURE_MMXEXT; 275#endif 276 } 277 } 278 279 /* query cpu name */ 280 if (cpu_ext_info >= 0x80000002) { 281 GLuint ofs; 282 char cpu_name[49]; 283 for (ofs = 0; ofs < 3; ofs++) 284 _mesa_x86_cpuid(0x80000002+ofs, (GLuint *)(cpu_name + (16*ofs)+0), (GLuint *)(cpu_name + (16*ofs)+4), (GLuint *)(cpu_name + (16*ofs)+8), (GLuint *)(cpu_name + (16*ofs)+12)); 285 cpu_name[48] = '\0'; /* the name should be NULL terminated, but just to be sure */ 286 287 _mesa_debug(NULL, "CPU name: %s\n", cpu_name); 288 } 289 } 290 291 } 292#endif /* USE_X86_ASM */ 293} 294