src/cpuinfo/SDL_cpuinfo.c
author Ryan C. Gordon <icculus@icculus.org>
Sun, 24 Nov 2013 23:56:17 -0500
changeset 8093 b43765095a6f
parent 7889 9ec71e56071c
child 8148 56ba41ac64fe
permissions -rw-r--r--
Make internal SDL sources include SDL_internal.h instead of SDL_config.h

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