Subversion Repositories Kolibri OS

Rev

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

  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. #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. }
  339.