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