src/cpuinfo/SDL_cpuinfo.c
author Ryan C. Gordon <icculus@icculus.org>
Wed, 16 Nov 2016 22:49:04 -0500
changeset 10619 8786a8d1088e
parent 9998 f67cf37e9cd4
child 10620 c37e02dd1a9b
permissions -rw-r--r--
cpuinfo: Removed code duplication, cached CPUID details.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2016 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 #define CPU_HAS_AVX2    0x00000800
    64 
    65 #if SDL_ALTIVEC_BLITTERS && HAVE_SETJMP && !__MACOSX__ && !__OpenBSD__
    66 /* This is the brute force way of detecting instruction sets...
    67    the idea is borrowed from the libmpeg2 library - thanks!
    68  */
    69 static jmp_buf jmpbuf;
    70 static void
    71 illegal_instruction(int sig)
    72 {
    73     longjmp(jmpbuf, 1);
    74 }
    75 #endif /* HAVE_SETJMP */
    76 
    77 static int
    78 CPU_haveCPUID(void)
    79 {
    80     int has_CPUID = 0;
    81 
    82 /* *INDENT-OFF* */
    83 #ifndef SDL_CPUINFO_DISABLED
    84 #if defined(__GNUC__) && defined(i386)
    85     __asm__ (
    86 "        pushfl                      # Get original EFLAGS             \n"
    87 "        popl    %%eax                                                 \n"
    88 "        movl    %%eax,%%ecx                                           \n"
    89 "        xorl    $0x200000,%%eax     # Flip ID bit in EFLAGS           \n"
    90 "        pushl   %%eax               # Save new EFLAGS value on stack  \n"
    91 "        popfl                       # Replace current EFLAGS value    \n"
    92 "        pushfl                      # Get new EFLAGS                  \n"
    93 "        popl    %%eax               # Store new EFLAGS in EAX         \n"
    94 "        xorl    %%ecx,%%eax         # Can not toggle ID bit,          \n"
    95 "        jz      1f                  # Processor=80486                 \n"
    96 "        movl    $1,%0               # We have CPUID support           \n"
    97 "1:                                                                    \n"
    98     : "=m" (has_CPUID)
    99     :
   100     : "%eax", "%ecx"
   101     );
   102 #elif defined(__GNUC__) && defined(__x86_64__)
   103 /* Technically, if this is being compiled under __x86_64__ then it has 
   104    CPUid by definition.  But it's nice to be able to prove it.  :)      */
   105     __asm__ (
   106 "        pushfq                      # Get original EFLAGS             \n"
   107 "        popq    %%rax                                                 \n"
   108 "        movq    %%rax,%%rcx                                           \n"
   109 "        xorl    $0x200000,%%eax     # Flip ID bit in EFLAGS           \n"
   110 "        pushq   %%rax               # Save new EFLAGS value on stack  \n"
   111 "        popfq                       # Replace current EFLAGS value    \n"
   112 "        pushfq                      # Get new EFLAGS                  \n"
   113 "        popq    %%rax               # Store new EFLAGS in EAX         \n"
   114 "        xorl    %%ecx,%%eax         # Can not toggle ID bit,          \n"
   115 "        jz      1f                  # Processor=80486                 \n"
   116 "        movl    $1,%0               # We have CPUID support           \n"
   117 "1:                                                                    \n"
   118     : "=m" (has_CPUID)
   119     :
   120     : "%rax", "%rcx"
   121     );
   122 #elif (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
   123     __asm {
   124         pushfd                      ; Get original EFLAGS
   125         pop     eax
   126         mov     ecx, eax
   127         xor     eax, 200000h        ; Flip ID bit in EFLAGS
   128         push    eax                 ; Save new EFLAGS value on stack
   129         popfd                       ; Replace current EFLAGS value
   130         pushfd                      ; Get new EFLAGS
   131         pop     eax                 ; Store new EFLAGS in EAX
   132         xor     eax, ecx            ; Can not toggle ID bit,
   133         jz      done                ; Processor=80486
   134         mov     has_CPUID,1         ; We have CPUID support
   135 done:
   136     }
   137 #elif defined(_MSC_VER) && defined(_M_X64)
   138     has_CPUID = 1;
   139 #elif defined(__sun) && defined(__i386)
   140     __asm (
   141 "       pushfl                 \n"
   142 "       popl    %eax           \n"
   143 "       movl    %eax,%ecx      \n"
   144 "       xorl    $0x200000,%eax \n"
   145 "       pushl   %eax           \n"
   146 "       popfl                  \n"
   147 "       pushfl                 \n"
   148 "       popl    %eax           \n"
   149 "       xorl    %ecx,%eax      \n"
   150 "       jz      1f             \n"
   151 "       movl    $1,-8(%ebp)    \n"
   152 "1:                            \n"
   153     );
   154 #elif defined(__sun) && defined(__amd64)
   155     __asm (
   156 "       pushfq                 \n"
   157 "       popq    %rax           \n"
   158 "       movq    %rax,%rcx      \n"
   159 "       xorl    $0x200000,%eax \n"
   160 "       pushq   %rax           \n"
   161 "       popfq                  \n"
   162 "       pushfq                 \n"
   163 "       popq    %rax           \n"
   164 "       xorl    %ecx,%eax      \n"
   165 "       jz      1f             \n"
   166 "       movl    $1,-8(%rbp)    \n"
   167 "1:                            \n"
   168     );
   169 #endif
   170 #endif
   171 /* *INDENT-ON* */
   172     return has_CPUID;
   173 }
   174 
   175 #if defined(__GNUC__) && defined(i386)
   176 #define cpuid(func, a, b, c, d) \
   177     __asm__ __volatile__ ( \
   178 "        pushl %%ebx        \n" \
   179 "        xorl %%ecx,%%ecx   \n" \
   180 "        cpuid              \n" \
   181 "        movl %%ebx, %%esi  \n" \
   182 "        popl %%ebx         \n" : \
   183             "=a" (a), "=S" (b), "=c" (c), "=d" (d) : "a" (func))
   184 #elif defined(__GNUC__) && defined(__x86_64__)
   185 #define cpuid(func, a, b, c, d) \
   186     __asm__ __volatile__ ( \
   187 "        pushq %%rbx        \n" \
   188 "        xorq %%rcx,%%rcx   \n" \
   189 "        cpuid              \n" \
   190 "        movq %%rbx, %%rsi  \n" \
   191 "        popq %%rbx         \n" : \
   192             "=a" (a), "=S" (b), "=c" (c), "=d" (d) : "a" (func))
   193 #elif (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
   194 #define cpuid(func, a, b, c, d) \
   195     __asm { \
   196         __asm mov eax, func \
   197         __asm xor ecx, ecx \
   198         __asm cpuid \
   199         __asm mov a, eax \
   200         __asm mov b, ebx \
   201         __asm mov c, ecx \
   202         __asm mov d, edx \
   203 }
   204 #elif defined(_MSC_VER) && defined(_M_X64)
   205 #define cpuid(func, a, b, c, d) \
   206 { \
   207     int CPUInfo[4]; \
   208     __cpuid(CPUInfo, func); \
   209     a = CPUInfo[0]; \
   210     b = CPUInfo[1]; \
   211     c = CPUInfo[2]; \
   212     d = CPUInfo[3]; \
   213 }
   214 #else
   215 #define cpuid(func, a, b, c, d) \
   216     a = b = c = d = 0
   217 #endif
   218 
   219 static int CPU_CPUIDFeatures[4];
   220 static int CPU_CPUIDMaxFunction = 0;
   221 static SDL_bool CPU_OSSavesYMM = SDL_FALSE;
   222 
   223 static void
   224 CPU_calcCPUIDFeatures(void)
   225 {
   226     static SDL_bool checked = SDL_FALSE;
   227     if (!checked) {
   228         checked = SDL_TRUE;
   229         if (CPU_haveCPUID()) {
   230             int a, b, c, d;
   231             cpuid(0, a, b, c, d);
   232             CPU_CPUIDMaxFunction = a;
   233             if (CPU_CPUIDMaxFunction >= 1) {
   234                 cpuid(1, a, b, c, d);
   235                 CPU_CPUIDFeatures[0] = a;
   236                 CPU_CPUIDFeatures[1] = b;
   237                 CPU_CPUIDFeatures[2] = c;
   238                 CPU_CPUIDFeatures[3] = d;
   239 
   240                 /* Check to make sure we can call xgetbv */
   241                 if (c & 0x08000000) {
   242                     /* Call xgetbv to see if YMM register state is saved */
   243 #if defined(__GNUC__) && (defined(i386) || defined(__x86_64__))
   244                     asm(".byte 0x0f, 0x01, 0xd0" : "=a" (a) : "c" (0) : "%edx");
   245 #elif defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64)) && (_MSC_FULL_VER >= 160040219) /* VS2010 SP1 */
   246                     a = (int)_xgetbv(0);
   247 #elif (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
   248                     __asm
   249                     {
   250                         xor ecx, ecx
   251                         _asm _emit 0x0f _asm _emit 0x01 _asm _emit 0xd0
   252                         mov a, eax
   253                     }
   254 #endif
   255                     CPU_OSSavesYMM = ((a & 6) == 6) ? SDL_TRUE : SDL_FALSE;
   256                 }
   257             }
   258         }
   259     }
   260 }
   261 
   262 static int
   263 CPU_haveAltiVec(void)
   264 {
   265     volatile int altivec = 0;
   266 #ifndef SDL_CPUINFO_DISABLED
   267 #if (defined(__MACOSX__) && (defined(__ppc__) || defined(__ppc64__))) || (defined(__OpenBSD__) && defined(__powerpc__))
   268 #ifdef __OpenBSD__
   269     int selectors[2] = { CTL_MACHDEP, CPU_ALTIVEC };
   270 #else
   271     int selectors[2] = { CTL_HW, HW_VECTORUNIT };
   272 #endif
   273     int hasVectorUnit = 0;
   274     size_t length = sizeof(hasVectorUnit);
   275     int error = sysctl(selectors, 2, &hasVectorUnit, &length, NULL, 0);
   276     if (0 == error)
   277         altivec = (hasVectorUnit != 0);
   278 #elif SDL_ALTIVEC_BLITTERS && HAVE_SETJMP
   279     void (*handler) (int sig);
   280     handler = signal(SIGILL, illegal_instruction);
   281     if (setjmp(jmpbuf) == 0) {
   282         asm volatile ("mtspr 256, %0\n\t" "vand %%v0, %%v0, %%v0"::"r" (-1));
   283         altivec = 1;
   284     }
   285     signal(SIGILL, handler);
   286 #endif
   287 #endif
   288     return altivec;
   289 }
   290 
   291 static int
   292 CPU_have3DNow(void)
   293 {
   294     if (CPU_CPUIDMaxFunction > 0) {  /* that is, do we have CPUID at all? */
   295         int a, b, c, d;
   296         cpuid(0x80000000, a, b, c, d);
   297         if (a >= 0x80000001) {
   298             cpuid(0x80000001, a, b, c, d);
   299             return (d & 0x80000000);
   300         }
   301     }
   302     return 0;
   303 }
   304 
   305 #define CPU_haveRDTSC() (CPU_CPUIDFeatures[3] & 0x00000010)
   306 #define CPU_haveMMX() (CPU_CPUIDFeatures[3] & 0x00800000)
   307 #define CPU_haveSSE() (CPU_CPUIDFeatures[3] & 0x02000000)
   308 #define CPU_haveSSE2() (CPU_CPUIDFeatures[3] & 0x04000000)
   309 #define CPU_haveSSE3() (CPU_CPUIDFeatures[2] & 0x00000001)
   310 #define CPU_haveSSE41() (CPU_CPUIDFeatures[2] & 0x00080000)
   311 #define CPU_haveSSE42() (CPU_CPUIDFeatures[2] & 0x00100000)
   312 #define CPU_haveAVX() (CPU_OSSavesYMM && (CPU_CPUIDFeatures[2] & 0x10000000))
   313 
   314 static int
   315 CPU_haveAVX2(void)
   316 {
   317     if (CPU_OSSavesYMM && (CPU_CPUIDMaxFunction >= 7)) {
   318         int a, b, c, d;
   319         cpuid(7, a, b, c, d);
   320         return (b & 0x00000020);
   321     }
   322     return 0;
   323 }
   324 
   325 static int SDL_CPUCount = 0;
   326 
   327 int
   328 SDL_GetCPUCount(void)
   329 {
   330     if (!SDL_CPUCount) {
   331 #ifndef SDL_CPUINFO_DISABLED
   332 #if defined(HAVE_SYSCONF) && defined(_SC_NPROCESSORS_ONLN)
   333         if (SDL_CPUCount <= 0) {
   334             SDL_CPUCount = (int)sysconf(_SC_NPROCESSORS_ONLN);
   335         }
   336 #endif
   337 #ifdef HAVE_SYSCTLBYNAME
   338         if (SDL_CPUCount <= 0) {
   339             size_t size = sizeof(SDL_CPUCount);
   340             sysctlbyname("hw.ncpu", &SDL_CPUCount, &size, NULL, 0);
   341         }
   342 #endif
   343 #ifdef __WIN32__
   344         if (SDL_CPUCount <= 0) {
   345             SYSTEM_INFO info;
   346             GetSystemInfo(&info);
   347             SDL_CPUCount = info.dwNumberOfProcessors;
   348         }
   349 #endif
   350 #endif
   351         /* There has to be at least 1, right? :) */
   352         if (SDL_CPUCount <= 0) {
   353             SDL_CPUCount = 1;
   354         }
   355     }
   356     return SDL_CPUCount;
   357 }
   358 
   359 /* Oh, such a sweet sweet trick, just not very useful. :) */
   360 static const char *
   361 SDL_GetCPUType(void)
   362 {
   363     static char SDL_CPUType[13];
   364 
   365     if (!SDL_CPUType[0]) {
   366         int i = 0;
   367 
   368         CPU_calcCPUIDFeatures();
   369         if (CPU_CPUIDMaxFunction > 0) {  /* do we have CPUID at all? */
   370             int a, b, c, d;
   371             cpuid(0x00000000, a, b, c, d);
   372             (void) a;
   373             SDL_CPUType[i++] = (char)(b & 0xff); b >>= 8;
   374             SDL_CPUType[i++] = (char)(b & 0xff); b >>= 8;
   375             SDL_CPUType[i++] = (char)(b & 0xff); b >>= 8;
   376             SDL_CPUType[i++] = (char)(b & 0xff);
   377 
   378             SDL_CPUType[i++] = (char)(d & 0xff); d >>= 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);
   382 
   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);
   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         CPU_calcCPUIDFeatures();
   407         if (CPU_CPUIDMaxFunction > 0) {  /* do we have CPUID at all? */
   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     int a, b, c, d;
   476     (void) a; (void) b; (void) c; (void) d;
   477     if (SDL_strcmp(cpuType, "GenuineIntel") == 0) {
   478         cpuid(0x00000001, a, b, c, d);
   479         return (((b >> 8) & 0xff) * 8);
   480     } else if (SDL_strcmp(cpuType, "AuthenticAMD") == 0) {
   481         cpuid(0x80000005, a, b, c, d);
   482         return (c & 0xff);
   483     } else {
   484         /* Just make a guess here... */
   485         return SDL_CACHELINE_SIZE;
   486     }
   487 }
   488 
   489 static Uint32 SDL_CPUFeatures = 0xFFFFFFFF;
   490 
   491 static Uint32
   492 SDL_GetCPUFeatures(void)
   493 {
   494     if (SDL_CPUFeatures == 0xFFFFFFFF) {
   495         CPU_calcCPUIDFeatures();
   496         SDL_CPUFeatures = 0;
   497         if (CPU_haveRDTSC()) {
   498             SDL_CPUFeatures |= CPU_HAS_RDTSC;
   499         }
   500         if (CPU_haveAltiVec()) {
   501             SDL_CPUFeatures |= CPU_HAS_ALTIVEC;
   502         }
   503         if (CPU_haveMMX()) {
   504             SDL_CPUFeatures |= CPU_HAS_MMX;
   505         }
   506         if (CPU_have3DNow()) {
   507             SDL_CPUFeatures |= CPU_HAS_3DNOW;
   508         }
   509         if (CPU_haveSSE()) {
   510             SDL_CPUFeatures |= CPU_HAS_SSE;
   511         }
   512         if (CPU_haveSSE2()) {
   513             SDL_CPUFeatures |= CPU_HAS_SSE2;
   514         }
   515         if (CPU_haveSSE3()) {
   516             SDL_CPUFeatures |= CPU_HAS_SSE3;
   517         }
   518         if (CPU_haveSSE41()) {
   519             SDL_CPUFeatures |= CPU_HAS_SSE41;
   520         }
   521         if (CPU_haveSSE42()) {
   522             SDL_CPUFeatures |= CPU_HAS_SSE42;
   523         }
   524         if (CPU_haveAVX()) {
   525             SDL_CPUFeatures |= CPU_HAS_AVX;
   526         }
   527         if (CPU_haveAVX2()) {
   528             SDL_CPUFeatures |= CPU_HAS_AVX2;
   529         }
   530     }
   531     return SDL_CPUFeatures;
   532 }
   533 
   534 #define CPU_FEATURE_AVAILABLE(f) ((SDL_GetCPUFeatures() & f) ? SDL_TRUE : SDL_FALSE)
   535 
   536 SDL_bool SDL_HasRDTSC(void)
   537 {
   538     return CPU_FEATURE_AVAILABLE(CPU_HAS_RDTSC);
   539 }
   540 
   541 SDL_bool
   542 SDL_HasAltiVec(void)
   543 {
   544     return CPU_FEATURE_AVAILABLE(CPU_HAS_ALTIVEC);
   545 }
   546 
   547 SDL_bool
   548 SDL_HasMMX(void)
   549 {
   550     return CPU_FEATURE_AVAILABLE(CPU_HAS_MMX);
   551 }
   552 
   553 SDL_bool
   554 SDL_Has3DNow(void)
   555 {
   556     return CPU_FEATURE_AVAILABLE(CPU_HAS_3DNOW);
   557 }
   558 
   559 SDL_bool
   560 SDL_HasSSE(void)
   561 {
   562     return CPU_FEATURE_AVAILABLE(CPU_HAS_SSE);
   563 }
   564 
   565 SDL_bool
   566 SDL_HasSSE2(void)
   567 {
   568     return CPU_FEATURE_AVAILABLE(CPU_HAS_SSE2);
   569 }
   570 
   571 SDL_bool
   572 SDL_HasSSE3(void)
   573 {
   574     return CPU_FEATURE_AVAILABLE(CPU_HAS_SSE3);
   575 }
   576 
   577 SDL_bool
   578 SDL_HasSSE41(void)
   579 {
   580     return CPU_FEATURE_AVAILABLE(CPU_HAS_SSE41);
   581 }
   582 
   583 SDL_bool
   584 SDL_HasSSE42(void)
   585 {
   586     return CPU_FEATURE_AVAILABLE(CPU_HAS_SSE42);
   587 }
   588 
   589 SDL_bool
   590 SDL_HasAVX(void)
   591 {
   592     return CPU_FEATURE_AVAILABLE(CPU_HAS_AVX);
   593 }
   594 
   595 SDL_bool
   596 SDL_HasAVX2(void)
   597 {
   598     return CPU_FEATURE_AVAILABLE(CPU_HAS_AVX2);
   599 }
   600 
   601 static int SDL_SystemRAM = 0;
   602 
   603 int
   604 SDL_GetSystemRAM(void)
   605 {
   606     if (!SDL_SystemRAM) {
   607 #ifndef SDL_CPUINFO_DISABLED
   608 #if defined(HAVE_SYSCONF) && defined(_SC_PHYS_PAGES) && defined(_SC_PAGESIZE)
   609         if (SDL_SystemRAM <= 0) {
   610             SDL_SystemRAM = (int)((Sint64)sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGESIZE) / (1024*1024));
   611         }
   612 #endif
   613 #ifdef HAVE_SYSCTLBYNAME
   614         if (SDL_SystemRAM <= 0) {
   615 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__)
   616 #ifdef HW_REALMEM
   617             int mib[2] = {CTL_HW, HW_REALMEM};
   618 #else
   619             /* might only report up to 2 GiB */
   620             int mib[2] = {CTL_HW, HW_PHYSMEM};
   621 #endif /* HW_REALMEM */
   622 #else
   623             int mib[2] = {CTL_HW, HW_MEMSIZE};
   624 #endif /* __FreeBSD__ || __FreeBSD_kernel__ */
   625             Uint64 memsize = 0;
   626             size_t len = sizeof(memsize);
   627             
   628             if (sysctl(mib, 2, &memsize, &len, NULL, 0) == 0) {
   629                 SDL_SystemRAM = (int)(memsize / (1024*1024));
   630             }
   631         }
   632 #endif
   633 #ifdef __WIN32__
   634         if (SDL_SystemRAM <= 0) {
   635             MEMORYSTATUSEX stat;
   636             stat.dwLength = sizeof(stat);
   637             if (GlobalMemoryStatusEx(&stat)) {
   638                 SDL_SystemRAM = (int)(stat.ullTotalPhys / (1024 * 1024));
   639             }
   640         }
   641 #endif
   642 #endif
   643     }
   644     return SDL_SystemRAM;
   645 }
   646 
   647 
   648 #ifdef TEST_MAIN
   649 
   650 #include <stdio.h>
   651 
   652 int
   653 main()
   654 {
   655     printf("CPU count: %d\n", SDL_GetCPUCount());
   656     printf("CPU type: %s\n", SDL_GetCPUType());
   657     printf("CPU name: %s\n", SDL_GetCPUName());
   658     printf("CacheLine size: %d\n", SDL_GetCPUCacheLineSize());
   659     printf("RDTSC: %d\n", SDL_HasRDTSC());
   660     printf("Altivec: %d\n", SDL_HasAltiVec());
   661     printf("MMX: %d\n", SDL_HasMMX());
   662     printf("3DNow: %d\n", SDL_Has3DNow());
   663     printf("SSE: %d\n", SDL_HasSSE());
   664     printf("SSE2: %d\n", SDL_HasSSE2());
   665     printf("SSE3: %d\n", SDL_HasSSE3());
   666     printf("SSE4.1: %d\n", SDL_HasSSE41());
   667     printf("SSE4.2: %d\n", SDL_HasSSE42());
   668     printf("AVX: %d\n", SDL_HasAVX());
   669     printf("AVX2: %d\n", SDL_HasAVX2());
   670     printf("RAM: %d MB\n", SDL_GetSystemRAM());
   671     return 0;
   672 }
   673 
   674 #endif /* TEST_MAIN */
   675 
   676 /* vi: set ts=4 sw=4 expandtab: */