Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1901 serge 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 
34
 * \author Andre Werthmann 
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 
40
#endif
41
#if defined(USE_SSE_ASM) && defined(__FreeBSD__)
42
#include 
43
#include 
44
#endif
45
#if defined(USE_SSE_ASM) && defined(__OpenBSD__)
46
#include 
47
#include 
48
#include 
49
#endif
50
 
51
#include "main/imports.h"
52
#include "common_x86_asm.h"
53
 
54
#undef WIN32
55
#undef _WIN32
56
 
57
/** Bitmask of X86_FEATURE_x bits */
58
int _mesa_x86_cpu_features = 0x0;
59
 
60
static int detection_debug = GL_FALSE;
61
 
62
/* No reason for this to be public.
63
 */
64
extern GLuint	_ASMAPI _mesa_x86_has_cpuid(void);
65
extern void	_ASMAPI _mesa_x86_cpuid(GLuint op, GLuint *reg_eax, GLuint *reg_ebx, GLuint *reg_ecx, GLuint *reg_edx);
66
extern GLuint	_ASMAPI _mesa_x86_cpuid_eax(GLuint op);
67
extern GLuint	_ASMAPI _mesa_x86_cpuid_ebx(GLuint op);
68
extern GLuint	_ASMAPI _mesa_x86_cpuid_ecx(GLuint op);
69
extern GLuint	_ASMAPI _mesa_x86_cpuid_edx(GLuint op);
70
 
71
 
72
#if defined(USE_SSE_ASM)
73
/*
74
 * We must verify that the Streaming SIMD Extensions are truly supported
75
 * on this processor before we go ahead and hook out the optimized code.
76
 *
77
 * However, I have been told by Alan Cox that all 2.4 (and later) Linux
78
 * kernels provide full SSE support on all processors that expose SSE via
79
 * the CPUID mechanism.
80
 */
81
 
82
/* These are assembly functions: */
83
extern void _mesa_test_os_sse_support( void );
84
extern void _mesa_test_os_sse_exception_support( void );
85
 
86
 
87
#if defined(WIN32)
88
#ifndef STATUS_FLOAT_MULTIPLE_TRAPS
89
# define STATUS_FLOAT_MULTIPLE_TRAPS (0xC00002B5L)
90
#endif
91
static LONG WINAPI ExceptionFilter(LPEXCEPTION_POINTERS exp)
92
{
93
   PEXCEPTION_RECORD rec = exp->ExceptionRecord;
94
   PCONTEXT ctx = exp->ContextRecord;
95
 
96
   if ( rec->ExceptionCode == EXCEPTION_ILLEGAL_INSTRUCTION ) {
97
      _mesa_debug(NULL, "EXCEPTION_ILLEGAL_INSTRUCTION\n" );
98
      _mesa_x86_cpu_features &= ~(X86_FEATURE_XMM);
99
   } else if ( rec->ExceptionCode == STATUS_FLOAT_MULTIPLE_TRAPS ) {
100
      _mesa_debug(NULL, "STATUS_FLOAT_MULTIPLE_TRAPS\n");
101
      /* Windows seems to clear the exception flag itself, we just have to increment Eip */
102
   } else {
103
      _mesa_debug(NULL, "UNEXPECTED EXCEPTION (0x%08x), terminating!\n" );
104
      return EXCEPTION_EXECUTE_HANDLER;
105
   }
106
 
107
   if ( (ctx->ContextFlags & CONTEXT_CONTROL) != CONTEXT_CONTROL ) {
108
      _mesa_debug(NULL, "Context does not contain control registers, terminating!\n");
109
      return EXCEPTION_EXECUTE_HANDLER;
110
   }
111
   ctx->Eip += 3;
112
 
113
   return EXCEPTION_CONTINUE_EXECUTION;
114
}
115
#endif /* WIN32 */
116
 
117
 
118
/**
119
 * Check if SSE is supported.
120
 * If not, turn off the X86_FEATURE_XMM flag in _mesa_x86_cpu_features.
121
 */
122
void _mesa_check_os_sse_support( void )
123
{
124
#if defined(__FreeBSD__)
125
   {
126
      int ret, enabled;
127
      unsigned int len;
128
      len = sizeof(enabled);
129
      ret = sysctlbyname("hw.instruction_sse", &enabled, &len, NULL, 0);
130
      if (ret || !enabled)
131
         _mesa_x86_cpu_features &= ~(X86_FEATURE_XMM);
132
   }
133
#elif defined (__NetBSD__)
134
   {
135
      int ret, enabled;
136
      size_t len = sizeof(enabled);
137
      ret = sysctlbyname("machdep.sse", &enabled, &len, (void *)NULL, 0);
138
      if (ret || !enabled)
139
         _mesa_x86_cpu_features &= ~(X86_FEATURE_XMM);
140
   }
141
#elif defined(__OpenBSD__)
142
   {
143
      int mib[2];
144
      int ret, enabled;
145
      size_t len = sizeof(enabled);
146
 
147
      mib[0] = CTL_MACHDEP;
148
      mib[1] = CPU_SSE;
149
 
150
      ret = sysctl(mib, 2, &enabled, &len, NULL, 0);
151
      if (ret || !enabled)
152
         _mesa_x86_cpu_features &= ~(X86_FEATURE_XMM);
153
   }
154
#elif defined(WIN32)
155
   LPTOP_LEVEL_EXCEPTION_FILTER oldFilter;
156
 
157
   /* Install our ExceptionFilter */
158
   oldFilter = SetUnhandledExceptionFilter( ExceptionFilter );
159
 
160
   if ( cpu_has_xmm ) {
161
      _mesa_debug(NULL, "Testing OS support for SSE...\n");
162
 
163
      _mesa_test_os_sse_support();
164
 
165
      if ( cpu_has_xmm ) {
166
	 _mesa_debug(NULL, "Yes.\n");
167
      } else {
168
	 _mesa_debug(NULL, "No!\n");
169
      }
170
   }
171
 
172
   if ( cpu_has_xmm ) {
173
      _mesa_debug(NULL, "Testing OS support for SSE unmasked exceptions...\n");
174
 
175
      _mesa_test_os_sse_exception_support();
176
 
177
      if ( cpu_has_xmm ) {
178
	 _mesa_debug(NULL, "Yes.\n");
179
      } else {
180
	 _mesa_debug(NULL, "No!\n");
181
      }
182
   }
183
 
184
   /* Restore previous exception filter */
185
   SetUnhandledExceptionFilter( oldFilter );
186
 
187
   if ( cpu_has_xmm ) {
188
      _mesa_debug(NULL, "Tests of OS support for SSE passed.\n");
189
   } else {
190
      _mesa_debug(NULL, "Tests of OS support for SSE failed!\n");
191
   }
192
#else
193
   /* Do nothing on other platforms for now.
194
    */
195
   if (detection_debug)
196
      _mesa_debug(NULL, "Not testing OS support for SSE, leaving enabled.\n");
197
#endif /* __FreeBSD__ */
198
}
199
 
200
#endif /* USE_SSE_ASM */
201
 
202
 
203
/**
204
 * Initialize the _mesa_x86_cpu_features bitfield.
205
 * This is a no-op if called more than once.
206
 */
207
void
208
_mesa_get_x86_features(void)
209
{
210
   static int called = 0;
211
 
212
   if (called)
213
      return;
214
 
215
   called = 1;
216
 
217
#ifdef USE_X86_ASM
218
   _mesa_x86_cpu_features = 0x0;
219
 
220
   if (_mesa_getenv( "MESA_NO_ASM")) {
221
      return;
222
   }
223
 
224
   if (!_mesa_x86_has_cpuid()) {
225
       _mesa_debug(NULL, "CPUID not detected\n");
226
   }
227
   else {
228
       GLuint cpu_features;
229
       GLuint cpu_ext_features;
230
       GLuint cpu_ext_info;
231
       char cpu_vendor[13];
232
       GLuint result;
233
 
234
       /* get vendor name */
235
       _mesa_x86_cpuid(0, &result, (GLuint *)(cpu_vendor + 0), (GLuint *)(cpu_vendor + 8), (GLuint *)(cpu_vendor + 4));
236
       cpu_vendor[12] = '\0';
237
 
238
       if (detection_debug)
239
	  _mesa_debug(NULL, "CPU vendor: %s\n", cpu_vendor);
240
 
241
       /* get cpu features */
242
       cpu_features = _mesa_x86_cpuid_edx(1);
243
 
244
       if (cpu_features & X86_CPU_FPU)
245
	   _mesa_x86_cpu_features |= X86_FEATURE_FPU;
246
       if (cpu_features & X86_CPU_CMOV)
247
	   _mesa_x86_cpu_features |= X86_FEATURE_CMOV;
248
 
249
#ifdef USE_MMX_ASM
250
       if (cpu_features & X86_CPU_MMX)
251
	   _mesa_x86_cpu_features |= X86_FEATURE_MMX;
252
#endif
253
 
254
#ifdef USE_SSE_ASM
255
       if (cpu_features & X86_CPU_XMM)
256
	   _mesa_x86_cpu_features |= X86_FEATURE_XMM;
257
       if (cpu_features & X86_CPU_XMM2)
258
	   _mesa_x86_cpu_features |= X86_FEATURE_XMM2;
259
#endif
260
 
261
       /* query extended cpu features */
262
       if ((cpu_ext_info = _mesa_x86_cpuid_eax(0x80000000)) > 0x80000000) {
263
	   if (cpu_ext_info >= 0x80000001) {
264
 
265
	       cpu_ext_features = _mesa_x86_cpuid_edx(0x80000001);
266
 
267
	       if (cpu_features & X86_CPU_MMX) {
268
 
269
#ifdef USE_3DNOW_ASM
270
		   if (cpu_ext_features & X86_CPUEXT_3DNOW)
271
		       _mesa_x86_cpu_features |= X86_FEATURE_3DNOW;
272
		   if (cpu_ext_features & X86_CPUEXT_3DNOW_EXT)
273
		       _mesa_x86_cpu_features |= X86_FEATURE_3DNOWEXT;
274
#endif
275
 
276
#ifdef USE_MMX_ASM
277
		   if (cpu_ext_features & X86_CPUEXT_MMX_EXT)
278
		       _mesa_x86_cpu_features |= X86_FEATURE_MMXEXT;
279
#endif
280
	       }
281
	   }
282
 
283
	   /* query cpu name */
284
	   if (cpu_ext_info >= 0x80000002) {
285
	       GLuint ofs;
286
	       char cpu_name[49];
287
	       for (ofs = 0; ofs < 3; ofs++)
288
		   _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));
289
	       cpu_name[48] = '\0'; /* the name should be NULL terminated, but just to be sure */
290
 
291
	       if (detection_debug)
292
		  _mesa_debug(NULL, "CPU name: %s\n", cpu_name);
293
	   }
294
       }
295
 
296
   }
297
 
298
#ifdef USE_MMX_ASM
299
   if ( cpu_has_mmx ) {
300
      if ( _mesa_getenv( "MESA_NO_MMX" ) == 0 ) {
301
	 if (detection_debug)
302
	    _mesa_debug(NULL, "MMX cpu detected.\n");
303
      } else {
304
         _mesa_x86_cpu_features &= ~(X86_FEATURE_MMX);
305
      }
306
   }
307
#endif
308
 
309
#ifdef USE_3DNOW_ASM
310
   if ( cpu_has_3dnow ) {
311
      if ( _mesa_getenv( "MESA_NO_3DNOW" ) == 0 ) {
312
	 if (detection_debug)
313
	    _mesa_debug(NULL, "3DNow! cpu detected.\n");
314
      } else {
315
         _mesa_x86_cpu_features &= ~(X86_FEATURE_3DNOW);
316
      }
317
   }
318
#endif
319
 
320
#ifdef USE_SSE_ASM
321
   if ( cpu_has_xmm ) {
322
      if ( _mesa_getenv( "MESA_NO_SSE" ) == 0 ) {
323
	 if (detection_debug)
324
	    _mesa_debug(NULL, "SSE cpu detected.\n");
325
         if ( _mesa_getenv( "MESA_FORCE_SSE" ) == 0 ) {
326
            _mesa_check_os_sse_support();
327
         }
328
      } else {
329
         _mesa_debug(NULL, "SSE cpu detected, but switched off by user.\n");
330
         _mesa_x86_cpu_features &= ~(X86_FEATURE_XMM);
331
      }
332
   }
333
#endif
334
 
335
#endif /* USE_X86_ASM */
336
 
337
   (void) detection_debug;
338
}