Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4358 Serge 1
/*
2
 * Mesa 3-D graphics library
3
 *
4
 * Copyright (C) 1999-2006  Brian Paul   All Rights Reserved.
5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining a
7
 * copy of this software and associated documentation files (the "Software"),
8
 * to deal in the Software without restriction, including without limitation
9
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
 * and/or sell copies of the Software, and to permit persons to whom the
11
 * Software is furnished to do so, subject to the following conditions:
12
 *
13
 * The above copyright notice and this permission notice shall be included
14
 * in all copies or substantial portions of the Software.
15
 *
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
 * 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
 
55
/** Bitmask of X86_FEATURE_x bits */
56
int _mesa_x86_cpu_features = 0x0;
57
 
58
static int detection_debug = GL_FALSE;
59
 
60
/* No reason for this to be public.
61
 */
62
extern GLuint	_ASMAPI _mesa_x86_has_cpuid(void);
63
extern void	_ASMAPI _mesa_x86_cpuid(GLuint op, GLuint *reg_eax, GLuint *reg_ebx, GLuint *reg_ecx, GLuint *reg_edx);
64
extern GLuint	_ASMAPI _mesa_x86_cpuid_eax(GLuint op);
65
extern GLuint	_ASMAPI _mesa_x86_cpuid_ebx(GLuint op);
66
extern GLuint	_ASMAPI _mesa_x86_cpuid_ecx(GLuint op);
67
extern 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: */
81
extern void _mesa_test_os_sse_support( void );
82
extern 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
89
static 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
 */
120
void _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
   if (detection_debug)
194
      _mesa_debug(NULL, "Not testing OS support for SSE, leaving enabled.\n");
195
#endif /* __FreeBSD__ */
196
}
197
 
198
#endif /* USE_SSE_ASM */
199
 
200
 
201
/**
202
 * Initialize the _mesa_x86_cpu_features bitfield.
203
 * This is a no-op if called more than once.
204
 */
205
void
206
_mesa_get_x86_features(void)
207
{
208
   static int called = 0;
209
 
210
   if (called)
211
      return;
212
 
213
   called = 1;
214
 
215
#ifdef USE_X86_ASM
216
   _mesa_x86_cpu_features = 0x0;
217
 
218
   if (_mesa_getenv( "MESA_NO_ASM")) {
219
      return;
220
   }
221
 
222
   if (!_mesa_x86_has_cpuid()) {
223
       _mesa_debug(NULL, "CPUID not detected\n");
224
   }
225
   else {
226
       GLuint cpu_features;
227
       GLuint cpu_ext_features;
228
       GLuint cpu_ext_info;
229
       char cpu_vendor[13];
230
       GLuint result;
231
 
232
       /* get vendor name */
233
       _mesa_x86_cpuid(0, &result, (GLuint *)(cpu_vendor + 0), (GLuint *)(cpu_vendor + 8), (GLuint *)(cpu_vendor + 4));
234
       cpu_vendor[12] = '\0';
235
 
236
       if (detection_debug)
237
	  _mesa_debug(NULL, "CPU vendor: %s\n", cpu_vendor);
238
 
239
       /* get cpu features */
240
       cpu_features = _mesa_x86_cpuid_edx(1);
241
 
242
       if (cpu_features & X86_CPU_FPU)
243
	   _mesa_x86_cpu_features |= X86_FEATURE_FPU;
244
       if (cpu_features & X86_CPU_CMOV)
245
	   _mesa_x86_cpu_features |= X86_FEATURE_CMOV;
246
 
247
#ifdef USE_MMX_ASM
248
       if (cpu_features & X86_CPU_MMX)
249
	   _mesa_x86_cpu_features |= X86_FEATURE_MMX;
250
#endif
251
 
252
#ifdef USE_SSE_ASM
253
       if (cpu_features & X86_CPU_XMM)
254
	   _mesa_x86_cpu_features |= X86_FEATURE_XMM;
255
       if (cpu_features & X86_CPU_XMM2)
256
	   _mesa_x86_cpu_features |= X86_FEATURE_XMM2;
257
#endif
258
 
259
       /* query extended cpu features */
260
       if ((cpu_ext_info = _mesa_x86_cpuid_eax(0x80000000)) > 0x80000000) {
261
	   if (cpu_ext_info >= 0x80000001) {
262
 
263
	       cpu_ext_features = _mesa_x86_cpuid_edx(0x80000001);
264
 
265
	       if (cpu_features & X86_CPU_MMX) {
266
 
267
#ifdef USE_3DNOW_ASM
268
		   if (cpu_ext_features & X86_CPUEXT_3DNOW)
269
		       _mesa_x86_cpu_features |= X86_FEATURE_3DNOW;
270
		   if (cpu_ext_features & X86_CPUEXT_3DNOW_EXT)
271
		       _mesa_x86_cpu_features |= X86_FEATURE_3DNOWEXT;
272
#endif
273
 
274
#ifdef USE_MMX_ASM
275
		   if (cpu_ext_features & X86_CPUEXT_MMX_EXT)
276
		       _mesa_x86_cpu_features |= X86_FEATURE_MMXEXT;
277
#endif
278
	       }
279
	   }
280
 
281
	   /* query cpu name */
282
	   if (cpu_ext_info >= 0x80000002) {
283
	       GLuint ofs;
284
	       char cpu_name[49];
285
	       for (ofs = 0; ofs < 3; ofs++)
286
		   _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));
287
	       cpu_name[48] = '\0'; /* the name should be NULL terminated, but just to be sure */
288
 
289
	       if (detection_debug)
290
		  _mesa_debug(NULL, "CPU name: %s\n", cpu_name);
291
	   }
292
       }
293
 
294
   }
295
 
296
#ifdef USE_MMX_ASM
297
   if ( cpu_has_mmx ) {
298
      if ( _mesa_getenv( "MESA_NO_MMX" ) == 0 ) {
299
	 if (detection_debug)
300
	    _mesa_debug(NULL, "MMX cpu detected.\n");
301
      } else {
302
         _mesa_x86_cpu_features &= ~(X86_FEATURE_MMX);
303
      }
304
   }
305
#endif
306
 
307
#ifdef USE_3DNOW_ASM
308
   if ( cpu_has_3dnow ) {
309
      if ( _mesa_getenv( "MESA_NO_3DNOW" ) == 0 ) {
310
	 if (detection_debug)
311
	    _mesa_debug(NULL, "3DNow! cpu detected.\n");
312
      } else {
313
         _mesa_x86_cpu_features &= ~(X86_FEATURE_3DNOW);
314
      }
315
   }
316
#endif
317
 
318
#ifdef USE_SSE_ASM
319
   if ( cpu_has_xmm ) {
320
      if ( _mesa_getenv( "MESA_NO_SSE" ) == 0 ) {
321
	 if (detection_debug)
322
	    _mesa_debug(NULL, "SSE cpu detected.\n");
323
         if ( _mesa_getenv( "MESA_FORCE_SSE" ) == 0 ) {
324
            _mesa_check_os_sse_support();
325
         }
326
      } else {
327
         _mesa_debug(NULL, "SSE cpu detected, but switched off by user.\n");
328
         _mesa_x86_cpu_features &= ~(X86_FEATURE_XMM);
329
      }
330
   }
331
#endif
332
 
333
#endif /* USE_X86_ASM */
334
 
335
   (void) detection_debug;
336
}