src/cpuinfo/SDL_cpuinfo.c
author Sam Lantinga <slouken@libsdl.org>
Sat, 22 Feb 2014 19:10:45 -0800
changeset 8241 b6d5a589ce3f
parent 8240 334257cd613d
child 8642 3506de54b829
permissions -rw-r--r--
Fixed bug 2404 - CPU detection not working with MSVC on x64

Tiemo Jung

All CPU detection functions SDL_Has* will return false, even if it is supported by the CPU, if SDL is compiled with MSVC and the target is x64.

The reason for this is that 'CPU_haveCPUID' will return 0 and macro 'cpuid' in SDL_cpuinfo.c is the fallback implementation, which sets all params to zero.

It is safe to assume that cpuid is supported on a CPU that runs windows x64, so CPU_haveCPUID can just return 1, and the empty macro can be replaced with a small wrap around the __cpuid intrinsic.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 #ifdef TEST_MAIN
    22 #include "SDL_config.h"
    23 #else
    24 #include "../SDL_internal.h"
    25 #endif
    26 
    27 #if defined(__WIN32__)
    28 #include "../core/windows/SDL_windows.h"
    29 #endif
    30 
    31 /* CPU feature detection for SDL */
    32 
    33 #include "SDL_cpuinfo.h"
    34 
    35 #ifdef HAVE_SYSCONF
    36 #include <unistd.h>
    37 #endif
    38 #ifdef HAVE_SYSCTLBYNAME
    39 #include <sys/types.h>
    40 #include <sys/sysctl.h>
    41 #endif
    42 #if defined(__MACOSX__) && (defined(__ppc__) || defined(__ppc64__))
    43 #include <sys/sysctl.h>         /* For AltiVec check */
    44 #elif defined(__OpenBSD__) && defined(__powerpc__)
    45 #include <sys/param.h>
    46 #include <sys/sysctl.h> /* For AltiVec check */
    47 #include <machine/cpu.h>
    48 #elif SDL_ALTIVEC_BLITTERS && HAVE_SETJMP
    49 #include <signal.h>
    50 #include <setjmp.h>
    51 #endif
    52 
    53 #define CPU_HAS_RDTSC   0x00000001
    54 #define CPU_HAS_ALTIVEC 0x00000002
    55 #define CPU_HAS_MMX     0x00000004
    56 #define CPU_HAS_3DNOW   0x00000008
    57 #define CPU_HAS_SSE     0x00000010
    58 #define CPU_HAS_SSE2    0x00000020
    59 #define CPU_HAS_SSE3    0x00000040
    60 #define CPU_HAS_SSE41   0x00000100
    61 #define CPU_HAS_SSE42   0x00000200
    62 #define CPU_HAS_AVX     0x00000400
    63 
    64 #if SDL_ALTIVEC_BLITTERS && HAVE_SETJMP && !__MACOSX__ && !__OpenBSD__
    65 /* This is the brute force way of detecting instruction sets...
    66    the idea is borrowed from the libmpeg2 library - thanks!
    67  */
    68 static jmp_buf jmpbuf;
    69 static void
    70 illegal_instruction(int sig)
    71 {
    72     longjmp(jmpbuf, 1);
    73 }
    74 #endif /* HAVE_SETJMP */
    75 
    76 static SDL_INLINE int
    77 CPU_haveCPUID(void)
    78 {
    79     int has_CPUID = 0;
    80 /* *INDENT-OFF* */
    81 #if defined(__GNUC__) && defined(i386)
    82     __asm__ (
    83 "        pushfl                      # Get original EFLAGS             \n"
    84 "        popl    %%eax                                                 \n"
    85 "        movl    %%eax,%%ecx                                           \n"
    86 "        xorl    $0x200000,%%eax     # Flip ID bit in EFLAGS           \n"
    87 "        pushl   %%eax               # Save new EFLAGS value on stack  \n"
    88 "        popfl                       # Replace current EFLAGS value    \n"
    89 "        pushfl                      # Get new EFLAGS                  \n"
    90 "        popl    %%eax               # Store new EFLAGS in EAX         \n"
    91 "        xorl    %%ecx,%%eax         # Can not toggle ID bit,          \n"
    92 "        jz      1f                  # Processor=80486                 \n"
    93 "        movl    $1,%0               # We have CPUID support           \n"
    94 "1:                                                                    \n"
    95     : "=m" (has_CPUID)
    96     :
    97     : "%eax", "%ecx"
    98     );
    99 #elif defined(__GNUC__) && defined(__x86_64__)
   100 /* Technically, if this is being compiled under __x86_64__ then it has 
   101    CPUid by definition.  But it's nice to be able to prove it.  :)      */
   102     __asm__ (
   103 "        pushfq                      # Get original EFLAGS             \n"
   104 "        popq    %%rax                                                 \n"
   105 "        movq    %%rax,%%rcx                                           \n"
   106 "        xorl    $0x200000,%%eax     # Flip ID bit in EFLAGS           \n"
   107 "        pushq   %%rax               # Save new EFLAGS value on stack  \n"
   108 "        popfq                       # Replace current EFLAGS value    \n"
   109 "        pushfq                      # Get new EFLAGS                  \n"
   110 "        popq    %%rax               # Store new EFLAGS in EAX         \n"
   111 "        xorl    %%ecx,%%eax         # Can not toggle ID bit,          \n"
   112 "        jz      1f                  # Processor=80486                 \n"
   113 "        movl    $1,%0               # We have CPUID support           \n"
   114 "1:                                                                    \n"
   115     : "=m" (has_CPUID)
   116     :
   117     : "%rax", "%rcx"
   118     );
   119 #elif (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
   120     __asm {
   121         pushfd                      ; Get original EFLAGS
   122         pop     eax
   123         mov     ecx, eax
   124         xor     eax, 200000h        ; Flip ID bit in EFLAGS
   125         push    eax                 ; Save new EFLAGS value on stack
   126         popfd                       ; Replace current EFLAGS value
   127         pushfd                      ; Get new EFLAGS
   128         pop     eax                 ; Store new EFLAGS in EAX
   129         xor     eax, ecx            ; Can not toggle ID bit,
   130         jz      done                ; Processor=80486
   131         mov     has_CPUID,1         ; We have CPUID support
   132 done:
   133     }
   134 #elif defined(_MSC_VER) && defined(_M_X64)
   135     has_CPUID = 1;
   136 #elif defined(__sun) && defined(__i386)
   137     __asm (
   138 "       pushfl                 \n"
   139 "       popl    %eax           \n"
   140 "       movl    %eax,%ecx      \n"
   141 "       xorl    $0x200000,%eax \n"
   142 "       pushl   %eax           \n"
   143 "       popfl                  \n"
   144 "       pushfl                 \n"
   145 "       popl    %eax           \n"
   146 "       xorl    %ecx,%eax      \n"
   147 "       jz      1f             \n"
   148 "       movl    $1,-8(%ebp)    \n"
   149 "1:                            \n"
   150     );
   151 #elif defined(__sun) && defined(__amd64)
   152     __asm (
   153 "       pushfq                 \n"
   154 "       popq    %rax           \n"
   155 "       movq    %rax,%rcx      \n"
   156 "       xorl    $0x200000,%eax \n"
   157 "       pushq   %rax           \n"
   158 "       popfq                  \n"
   159 "       pushfq                 \n"
   160 "       popq    %rax           \n"
   161 "       xorl    %ecx,%eax      \n"
   162 "       jz      1f             \n"
   163 "       movl    $1,-8(%rbp)    \n"
   164 "1:                            \n"
   165     );
   166 #endif
   167 /* *INDENT-ON* */
   168     return has_CPUID;
   169 }
   170 
   171 #if defined(__GNUC__) && defined(i386)
   172 #define cpuid(func, a, b, c, d) \
   173     __asm__ __volatile__ ( \
   174 "        pushl %%ebx        \n" \
   175 "        cpuid              \n" \
   176 "        movl %%ebx, %%esi  \n" \
   177 "        popl %%ebx         \n" : \
   178             "=a" (a), "=S" (b), "=c" (c), "=d" (d) : "a" (func))
   179 #elif defined(__GNUC__) && defined(__x86_64__)
   180 #define cpuid(func, a, b, c, d) \
   181     __asm__ __volatile__ ( \
   182 "        pushq %%rbx        \n" \
   183 "        cpuid              \n" \
   184 "        movq %%rbx, %%rsi  \n" \
   185 "        popq %%rbx         \n" : \
   186             "=a" (a), "=S" (b), "=c" (c), "=d" (d) : "a" (func))
   187 #elif (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
   188 #define cpuid(func, a, b, c, d) \
   189     __asm { \
   190         __asm mov eax, func \
   191         __asm cpuid \
   192         __asm mov a, eax \
   193         __asm mov b, ebx \
   194         __asm mov c, ecx \
   195         __asm mov d, edx \
   196 }
   197 #elif defined(_MSC_VER) && defined(_M_X64)
   198 #define cpuid(func, a, b, c, d) \
   199 { \
   200     int CPUInfo[4]; \
   201     __cpuid(CPUInfo, func); \
   202     a = CPUInfo[0]; \
   203     b = CPUInfo[1]; \
   204     c = CPUInfo[2]; \
   205     d = CPUInfo[3]; \
   206 }
   207 #else
   208 #define cpuid(func, a, b, c, d) \
   209     a = b = c = d = 0
   210 #endif
   211 
   212 static SDL_INLINE int
   213 CPU_getCPUIDFeatures(void)
   214 {
   215     int features = 0;
   216     int a, b, c, d;
   217 
   218     cpuid(0, a, b, c, d);
   219     if (a >= 1) {
   220         cpuid(1, a, b, c, d);
   221         features = d;
   222     }
   223     return features;
   224 }
   225 
   226 static SDL_INLINE int
   227 CPU_haveRDTSC(void)
   228 {
   229     if (CPU_haveCPUID()) {
   230         return (CPU_getCPUIDFeatures() & 0x00000010);
   231     }
   232     return 0;
   233 }
   234 
   235 static SDL_INLINE int
   236 CPU_haveAltiVec(void)
   237 {
   238     volatile int altivec = 0;
   239 #if (defined(__MACOSX__) && (defined(__ppc__) || defined(__ppc64__))) || (defined(__OpenBSD__) && defined(__powerpc__))
   240 #ifdef __OpenBSD__
   241     int selectors[2] = { CTL_MACHDEP, CPU_ALTIVEC };
   242 #else
   243     int selectors[2] = { CTL_HW, HW_VECTORUNIT };
   244 #endif
   245     int hasVectorUnit = 0;
   246     size_t length = sizeof(hasVectorUnit);
   247     int error = sysctl(selectors, 2, &hasVectorUnit, &length, NULL, 0);
   248     if (0 == error)
   249         altivec = (hasVectorUnit != 0);
   250 #elif SDL_ALTIVEC_BLITTERS && HAVE_SETJMP
   251     void (*handler) (int sig);
   252     handler = signal(SIGILL, illegal_instruction);
   253     if (setjmp(jmpbuf) == 0) {
   254         asm volatile ("mtspr 256, %0\n\t" "vand %%v0, %%v0, %%v0"::"r" (-1));
   255         altivec = 1;
   256     }
   257     signal(SIGILL, handler);
   258 #endif
   259     return altivec;
   260 }
   261 
   262 static SDL_INLINE int
   263 CPU_haveMMX(void)
   264 {
   265     if (CPU_haveCPUID()) {
   266         return (CPU_getCPUIDFeatures() & 0x00800000);
   267     }
   268     return 0;
   269 }
   270 
   271 static SDL_INLINE int
   272 CPU_have3DNow(void)
   273 {
   274     if (CPU_haveCPUID()) {
   275         int a, b, c, d;
   276 
   277         cpuid(0x80000000, a, b, c, d);
   278         if (a >= 0x80000001) {
   279             cpuid(0x80000001, a, b, c, d);
   280             return (d & 0x80000000);
   281         }
   282     }
   283     return 0;
   284 }
   285 
   286 static SDL_INLINE int
   287 CPU_haveSSE(void)
   288 {
   289     if (CPU_haveCPUID()) {
   290         return (CPU_getCPUIDFeatures() & 0x02000000);
   291     }
   292     return 0;
   293 }
   294 
   295 static SDL_INLINE int
   296 CPU_haveSSE2(void)
   297 {
   298     if (CPU_haveCPUID()) {
   299         return (CPU_getCPUIDFeatures() & 0x04000000);
   300     }
   301     return 0;
   302 }
   303 
   304 static SDL_INLINE int
   305 CPU_haveSSE3(void)
   306 {
   307     if (CPU_haveCPUID()) {
   308         int a, b, c, d;
   309 
   310         cpuid(0, a, b, c, d);
   311         if (a >= 1) {
   312             cpuid(1, a, b, c, d);
   313             return (c & 0x00000001);
   314         }
   315     }
   316     return 0;
   317 }
   318 
   319 static SDL_INLINE int
   320 CPU_haveSSE41(void)
   321 {
   322     if (CPU_haveCPUID()) {
   323         int a, b, c, d;
   324 
   325         cpuid(1, a, b, c, d);
   326         if (a >= 1) {
   327             cpuid(1, a, b, c, d);
   328             return (c & 0x00080000);
   329         }
   330     }
   331     return 0;
   332 }
   333 
   334 static SDL_INLINE int
   335 CPU_haveSSE42(void)
   336 {
   337     if (CPU_haveCPUID()) {
   338         int a, b, c, d;
   339 
   340         cpuid(1, a, b, c, d);
   341         if (a >= 1) {
   342             cpuid(1, a, b, c, d);
   343             return (c & 0x00100000);
   344         }
   345     }
   346     return 0;
   347 }
   348 
   349 static SDL_INLINE int
   350 CPU_haveAVX(void)
   351 {
   352     if (CPU_haveCPUID()) {
   353         int a, b, c, d;
   354 
   355         cpuid(1, a, b, c, d);
   356         if (a >= 1) {
   357             cpuid(1, a, b, c, d);
   358             return (c & 0x10000000);
   359         }
   360     }
   361     return 0;
   362 }
   363 
   364 static int SDL_CPUCount = 0;
   365 
   366 int
   367 SDL_GetCPUCount(void)
   368 {
   369     if (!SDL_CPUCount) {
   370 #if defined(HAVE_SYSCONF) && defined(_SC_NPROCESSORS_ONLN)
   371         if (SDL_CPUCount <= 0) {
   372             SDL_CPUCount = (int)sysconf(_SC_NPROCESSORS_ONLN);
   373         }
   374 #endif
   375 #ifdef HAVE_SYSCTLBYNAME
   376         if (SDL_CPUCount <= 0) {
   377             size_t size = sizeof(SDL_CPUCount);
   378             sysctlbyname("hw.ncpu", &SDL_CPUCount, &size, NULL, 0);
   379         }
   380 #endif
   381 #ifdef __WIN32__
   382         if (SDL_CPUCount <= 0) {
   383             SYSTEM_INFO info;
   384             GetSystemInfo(&info);
   385             SDL_CPUCount = info.dwNumberOfProcessors;
   386         }
   387 #endif
   388         /* There has to be at least 1, right? :) */
   389         if (SDL_CPUCount <= 0) {
   390             SDL_CPUCount = 1;
   391         }
   392     }
   393     return SDL_CPUCount;
   394 }
   395 
   396 /* Oh, such a sweet sweet trick, just not very useful. :) */
   397 static const char *
   398 SDL_GetCPUType(void)
   399 {
   400     static char SDL_CPUType[13];
   401 
   402     if (!SDL_CPUType[0]) {
   403         int i = 0;
   404         int a, b, c, d;
   405 
   406         if (CPU_haveCPUID()) {
   407             cpuid(0x00000000, a, b, c, d);
   408             SDL_CPUType[i++] = (char)(b & 0xff); b >>= 8;
   409             SDL_CPUType[i++] = (char)(b & 0xff); b >>= 8;
   410             SDL_CPUType[i++] = (char)(b & 0xff); b >>= 8;
   411             SDL_CPUType[i++] = (char)(b & 0xff); b >>= 8;
   412             SDL_CPUType[i++] = (char)(d & 0xff); d >>= 8;
   413             SDL_CPUType[i++] = (char)(d & 0xff); d >>= 8;
   414             SDL_CPUType[i++] = (char)(d & 0xff); d >>= 8;
   415             SDL_CPUType[i++] = (char)(d & 0xff); d >>= 8;
   416             SDL_CPUType[i++] = (char)(c & 0xff); c >>= 8;
   417             SDL_CPUType[i++] = (char)(c & 0xff); c >>= 8;
   418             SDL_CPUType[i++] = (char)(c & 0xff); c >>= 8;
   419             SDL_CPUType[i++] = (char)(c & 0xff); c >>= 8;
   420         }
   421         if (!SDL_CPUType[0]) {
   422             SDL_strlcpy(SDL_CPUType, "Unknown", sizeof(SDL_CPUType));
   423         }
   424     }
   425     return SDL_CPUType;
   426 }
   427 
   428 
   429 #ifdef TEST_MAIN  /* !!! FIXME: only used for test at the moment. */
   430 static const char *
   431 SDL_GetCPUName(void)
   432 {
   433     static char SDL_CPUName[48];
   434 
   435     if (!SDL_CPUName[0]) {
   436         int i = 0;
   437         int a, b, c, d;
   438 
   439         if (CPU_haveCPUID()) {
   440             cpuid(0x80000000, a, b, c, d);
   441             if (a >= 0x80000004) {
   442                 cpuid(0x80000002, a, b, c, d);
   443                 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
   444                 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
   445                 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
   446                 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
   447                 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
   448                 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
   449                 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
   450                 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
   451                 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
   452                 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
   453                 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
   454                 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
   455                 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
   456                 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
   457                 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
   458                 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
   459                 cpuid(0x80000003, a, b, c, d);
   460                 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
   461                 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
   462                 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
   463                 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
   464                 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
   465                 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
   466                 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
   467                 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
   468                 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
   469                 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
   470                 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
   471                 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
   472                 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
   473                 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
   474                 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
   475                 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
   476                 cpuid(0x80000004, a, b, c, d);
   477                 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
   478                 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
   479                 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
   480                 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
   481                 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
   482                 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
   483                 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
   484                 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
   485                 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
   486                 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
   487                 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
   488                 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
   489                 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
   490                 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
   491                 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
   492                 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
   493             }
   494         }
   495         if (!SDL_CPUName[0]) {
   496             SDL_strlcpy(SDL_CPUName, "Unknown", sizeof(SDL_CPUName));
   497         }
   498     }
   499     return SDL_CPUName;
   500 }
   501 #endif
   502 
   503 int
   504 SDL_GetCPUCacheLineSize(void)
   505 {
   506     const char *cpuType = SDL_GetCPUType();
   507 
   508     if (SDL_strcmp(cpuType, "GenuineIntel") == 0) {
   509         int a, b, c, d;
   510 
   511         cpuid(0x00000001, a, b, c, d);
   512         return (((b >> 8) & 0xff) * 8);
   513     } else if (SDL_strcmp(cpuType, "AuthenticAMD") == 0) {
   514         int a, b, c, d;
   515 
   516         cpuid(0x80000005, a, b, c, d);
   517         return (c & 0xff);
   518     } else {
   519         /* Just make a guess here... */
   520         return SDL_CACHELINE_SIZE;
   521     }
   522 }
   523 
   524 static Uint32 SDL_CPUFeatures = 0xFFFFFFFF;
   525 
   526 static Uint32
   527 SDL_GetCPUFeatures(void)
   528 {
   529     if (SDL_CPUFeatures == 0xFFFFFFFF) {
   530         SDL_CPUFeatures = 0;
   531         if (CPU_haveRDTSC()) {
   532             SDL_CPUFeatures |= CPU_HAS_RDTSC;
   533         }
   534         if (CPU_haveAltiVec()) {
   535             SDL_CPUFeatures |= CPU_HAS_ALTIVEC;
   536         }
   537         if (CPU_haveMMX()) {
   538             SDL_CPUFeatures |= CPU_HAS_MMX;
   539         }
   540         if (CPU_have3DNow()) {
   541             SDL_CPUFeatures |= CPU_HAS_3DNOW;
   542         }
   543         if (CPU_haveSSE()) {
   544             SDL_CPUFeatures |= CPU_HAS_SSE;
   545         }
   546         if (CPU_haveSSE2()) {
   547             SDL_CPUFeatures |= CPU_HAS_SSE2;
   548         }
   549         if (CPU_haveSSE3()) {
   550             SDL_CPUFeatures |= CPU_HAS_SSE3;
   551         }
   552         if (CPU_haveSSE41()) {
   553             SDL_CPUFeatures |= CPU_HAS_SSE41;
   554         }
   555         if (CPU_haveSSE42()) {
   556             SDL_CPUFeatures |= CPU_HAS_SSE42;
   557         }
   558         if (CPU_haveAVX()) {
   559             SDL_CPUFeatures |= CPU_HAS_AVX;
   560         }
   561     }
   562     return SDL_CPUFeatures;
   563 }
   564 
   565 SDL_bool
   566 SDL_HasRDTSC(void)
   567 {
   568     if (SDL_GetCPUFeatures() & CPU_HAS_RDTSC) {
   569         return SDL_TRUE;
   570     }
   571     return SDL_FALSE;
   572 }
   573 
   574 SDL_bool
   575 SDL_HasAltiVec(void)
   576 {
   577     if (SDL_GetCPUFeatures() & CPU_HAS_ALTIVEC) {
   578         return SDL_TRUE;
   579     }
   580     return SDL_FALSE;
   581 }
   582 
   583 SDL_bool
   584 SDL_HasMMX(void)
   585 {
   586     if (SDL_GetCPUFeatures() & CPU_HAS_MMX) {
   587         return SDL_TRUE;
   588     }
   589     return SDL_FALSE;
   590 }
   591 
   592 SDL_bool
   593 SDL_Has3DNow(void)
   594 {
   595     if (SDL_GetCPUFeatures() & CPU_HAS_3DNOW) {
   596         return SDL_TRUE;
   597     }
   598     return SDL_FALSE;
   599 }
   600 
   601 SDL_bool
   602 SDL_HasSSE(void)
   603 {
   604     if (SDL_GetCPUFeatures() & CPU_HAS_SSE) {
   605         return SDL_TRUE;
   606     }
   607     return SDL_FALSE;
   608 }
   609 
   610 SDL_bool
   611 SDL_HasSSE2(void)
   612 {
   613     if (SDL_GetCPUFeatures() & CPU_HAS_SSE2) {
   614         return SDL_TRUE;
   615     }
   616     return SDL_FALSE;
   617 }
   618 
   619 SDL_bool
   620 SDL_HasSSE3(void)
   621 {
   622     if (SDL_GetCPUFeatures() & CPU_HAS_SSE3) {
   623         return SDL_TRUE;
   624     }
   625     return SDL_FALSE;
   626 }
   627 
   628 SDL_bool
   629 SDL_HasSSE41(void)
   630 {
   631     if (SDL_GetCPUFeatures() & CPU_HAS_SSE41) {
   632         return SDL_TRUE;
   633     }
   634     return SDL_FALSE;
   635 }
   636 
   637 SDL_bool
   638 SDL_HasSSE42(void)
   639 {
   640     if (SDL_GetCPUFeatures() & CPU_HAS_SSE42) {
   641         return SDL_TRUE;
   642     }
   643     return SDL_FALSE;
   644 }
   645 
   646 SDL_bool
   647 SDL_HasAVX(void)
   648 {
   649     if (SDL_GetCPUFeatures() & CPU_HAS_AVX) {
   650         return SDL_TRUE;
   651     }
   652     return SDL_FALSE;
   653 }
   654 
   655 static int SDL_SystemRAM = 0;
   656 
   657 int
   658 SDL_GetSystemRAM(void)
   659 {
   660     if (!SDL_SystemRAM) {
   661 #if defined(HAVE_SYSCONF) && defined(_SC_PHYS_PAGES) && defined(_SC_PAGESIZE)
   662         if (SDL_SystemRAM <= 0) {
   663             SDL_SystemRAM = (int)((Sint64)sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGESIZE) / (1024*1024));
   664         }
   665 #endif
   666 #ifdef HAVE_SYSCTLBYNAME
   667         if (SDL_SystemRAM <= 0) {
   668 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
   669 #ifdef HW_REALMEM
   670             int mib[2] = {CTL_HW, HW_REALMEM};
   671 #else
   672             /* might only report up to 2 GiB */
   673             int mib[2] = {CTL_HW, HW_PHYSMEM};
   674 #endif /* HW_REALMEM */
   675 #else
   676             int mib[2] = {CTL_HW, HW_MEMSIZE};
   677 #endif /* __FreeBSD__ || __FreeBSD_kernel__ */
   678             Uint64 memsize = 0;
   679             size_t len = sizeof(memsize);
   680             
   681             if (sysctl(mib, 2, &memsize, &len, NULL, 0) == 0) {
   682                 SDL_SystemRAM = (int)(memsize / (1024*1024));
   683             }
   684         }
   685 #endif
   686 #ifdef __WIN32__
   687         if (SDL_SystemRAM <= 0) {
   688             MEMORYSTATUSEX stat;
   689             stat.dwLength = sizeof(stat);
   690             if (GlobalMemoryStatusEx(&stat)) {
   691                 SDL_SystemRAM = (int)(stat.ullTotalPhys / (1024 * 1024));
   692             }
   693         }
   694 #endif
   695     }
   696     return SDL_SystemRAM;
   697 }
   698 
   699 
   700 #ifdef TEST_MAIN
   701 
   702 #include <stdio.h>
   703 
   704 int
   705 main()
   706 {
   707     printf("CPU count: %d\n", SDL_GetCPUCount());
   708     printf("CPU type: %s\n", SDL_GetCPUType());
   709     printf("CPU name: %s\n", SDL_GetCPUName());
   710     printf("CacheLine size: %d\n", SDL_GetCPUCacheLineSize());
   711     printf("RDTSC: %d\n", SDL_HasRDTSC());
   712     printf("Altivec: %d\n", SDL_HasAltiVec());
   713     printf("MMX: %d\n", SDL_HasMMX());
   714     printf("3DNow: %d\n", SDL_Has3DNow());
   715     printf("SSE: %d\n", SDL_HasSSE());
   716     printf("SSE2: %d\n", SDL_HasSSE2());
   717     printf("SSE3: %d\n", SDL_HasSSE3());
   718     printf("SSE4.1: %d\n", SDL_HasSSE41());
   719     printf("SSE4.2: %d\n", SDL_HasSSE42());
   720     printf("AVX: %d\n", SDL_HasAVX());
   721     printf("RAM: %d MB\n", SDL_GetSystemRAM());
   722     return 0;
   723 }
   724 
   725 #endif /* TEST_MAIN */
   726 
   727 /* vi: set ts=4 sw=4 expandtab: */