src/cpuinfo/SDL_cpuinfo.c
author Sam Lantinga <slouken@libsdl.org>
Fri, 11 Jul 2014 22:02:50 -0700
changeset 9003 446ed0fe0fc3
parent 8642 3506de54b829
child 9004 51bc44d49052
permissions -rw-r--r--
Fixed bug in AVX detection and added AVX2 detection
     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 #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 /* *INDENT-OFF* */
    82 #if defined(__GNUC__) && defined(i386)
    83     __asm__ (
    84 "        pushfl                      # Get original EFLAGS             \n"
    85 "        popl    %%eax                                                 \n"
    86 "        movl    %%eax,%%ecx                                           \n"
    87 "        xorl    $0x200000,%%eax     # Flip ID bit in EFLAGS           \n"
    88 "        pushl   %%eax               # Save new EFLAGS value on stack  \n"
    89 "        popfl                       # Replace current EFLAGS value    \n"
    90 "        pushfl                      # Get new EFLAGS                  \n"
    91 "        popl    %%eax               # Store new EFLAGS in EAX         \n"
    92 "        xorl    %%ecx,%%eax         # Can not toggle ID bit,          \n"
    93 "        jz      1f                  # Processor=80486                 \n"
    94 "        movl    $1,%0               # We have CPUID support           \n"
    95 "1:                                                                    \n"
    96     : "=m" (has_CPUID)
    97     :
    98     : "%eax", "%ecx"
    99     );
   100 #elif defined(__GNUC__) && defined(__x86_64__)
   101 /* Technically, if this is being compiled under __x86_64__ then it has 
   102    CPUid by definition.  But it's nice to be able to prove it.  :)      */
   103     __asm__ (
   104 "        pushfq                      # Get original EFLAGS             \n"
   105 "        popq    %%rax                                                 \n"
   106 "        movq    %%rax,%%rcx                                           \n"
   107 "        xorl    $0x200000,%%eax     # Flip ID bit in EFLAGS           \n"
   108 "        pushq   %%rax               # Save new EFLAGS value on stack  \n"
   109 "        popfq                       # Replace current EFLAGS value    \n"
   110 "        pushfq                      # Get new EFLAGS                  \n"
   111 "        popq    %%rax               # Store new EFLAGS in EAX         \n"
   112 "        xorl    %%ecx,%%eax         # Can not toggle ID bit,          \n"
   113 "        jz      1f                  # Processor=80486                 \n"
   114 "        movl    $1,%0               # We have CPUID support           \n"
   115 "1:                                                                    \n"
   116     : "=m" (has_CPUID)
   117     :
   118     : "%rax", "%rcx"
   119     );
   120 #elif (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
   121     __asm {
   122         pushfd                      ; Get original EFLAGS
   123         pop     eax
   124         mov     ecx, eax
   125         xor     eax, 200000h        ; Flip ID bit in EFLAGS
   126         push    eax                 ; Save new EFLAGS value on stack
   127         popfd                       ; Replace current EFLAGS value
   128         pushfd                      ; Get new EFLAGS
   129         pop     eax                 ; Store new EFLAGS in EAX
   130         xor     eax, ecx            ; Can not toggle ID bit,
   131         jz      done                ; Processor=80486
   132         mov     has_CPUID,1         ; We have CPUID support
   133 done:
   134     }
   135 #elif defined(_MSC_VER) && defined(_M_X64)
   136     has_CPUID = 1;
   137 #elif defined(__sun) && defined(__i386)
   138     __asm (
   139 "       pushfl                 \n"
   140 "       popl    %eax           \n"
   141 "       movl    %eax,%ecx      \n"
   142 "       xorl    $0x200000,%eax \n"
   143 "       pushl   %eax           \n"
   144 "       popfl                  \n"
   145 "       pushfl                 \n"
   146 "       popl    %eax           \n"
   147 "       xorl    %ecx,%eax      \n"
   148 "       jz      1f             \n"
   149 "       movl    $1,-8(%ebp)    \n"
   150 "1:                            \n"
   151     );
   152 #elif defined(__sun) && defined(__amd64)
   153     __asm (
   154 "       pushfq                 \n"
   155 "       popq    %rax           \n"
   156 "       movq    %rax,%rcx      \n"
   157 "       xorl    $0x200000,%eax \n"
   158 "       pushq   %rax           \n"
   159 "       popfq                  \n"
   160 "       pushfq                 \n"
   161 "       popq    %rax           \n"
   162 "       xorl    %ecx,%eax      \n"
   163 "       jz      1f             \n"
   164 "       movl    $1,-8(%rbp)    \n"
   165 "1:                            \n"
   166     );
   167 #endif
   168 /* *INDENT-ON* */
   169     return has_CPUID;
   170 }
   171 
   172 #if defined(__GNUC__) && defined(i386)
   173 #define cpuid(func, a, b, c, d) \
   174     __asm__ __volatile__ ( \
   175 "        pushl %%ebx        \n" \
   176 "        xorl %%ecx,%%ecx   \n" \
   177 "        cpuid              \n" \
   178 "        movl %%ebx, %%esi  \n" \
   179 "        popl %%ebx         \n" : \
   180             "=a" (a), "=S" (b), "=c" (c), "=d" (d) : "a" (func))
   181 #elif defined(__GNUC__) && defined(__x86_64__)
   182 #define cpuid(func, a, b, c, d) \
   183     __asm__ __volatile__ ( \
   184 "        pushq %%rbx        \n" \
   185 "        xorq %%rcx,%%rcx   \n" \
   186 "        cpuid              \n" \
   187 "        movq %%rbx, %%rsi  \n" \
   188 "        popq %%rbx         \n" : \
   189             "=a" (a), "=S" (b), "=c" (c), "=d" (d) : "a" (func))
   190 #elif (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
   191 #define cpuid(func, a, b, c, d) \
   192     __asm { \
   193         __asm mov eax, func \
   194         __asm xor ecx, ecx \
   195         __asm cpuid \
   196         __asm mov a, eax \
   197         __asm mov b, ebx \
   198         __asm mov c, ecx \
   199         __asm mov d, edx \
   200 }
   201 #elif defined(_MSC_VER) && defined(_M_X64)
   202 #define cpuid(func, a, b, c, d) \
   203 { \
   204     int CPUInfo[4]; \
   205     __cpuid(CPUInfo, func); \
   206     a = CPUInfo[0]; \
   207     b = CPUInfo[1]; \
   208     c = CPUInfo[2]; \
   209     d = CPUInfo[3]; \
   210 }
   211 #else
   212 #define cpuid(func, a, b, c, d) \
   213     a = b = c = d = 0
   214 #endif
   215 
   216 static int
   217 CPU_getCPUIDFeatures(void)
   218 {
   219     int features = 0;
   220     int a, b, c, d;
   221 
   222     cpuid(0, a, b, c, d);
   223     if (a >= 1) {
   224         cpuid(1, a, b, c, d);
   225         features = d;
   226     }
   227     return features;
   228 }
   229 
   230 static SDL_bool
   231 CPU_OSSavesYMM(void)
   232 {
   233     int a, b, c, d;
   234 
   235     /* Check to make sure we can call xgetbv */
   236     cpuid(0, a, b, c, d);
   237     if (a < 1) {
   238         return SDL_FALSE;
   239     }
   240     cpuid(1, a, b, c, d);
   241     if (!(c & 0x08000000)) {
   242         return SDL_FALSE;
   243     }
   244 
   245     /* Call xgetbv to see if YMM register state is saved */
   246     a = 0;
   247 #if defined(__GNUC__) && (defined(i386) || defined(__x86_64__))
   248     asm(".byte 0x0f, 0x01, 0xd0" : "=a" (a) : "c" (0) : "%edx");
   249 #elif defined(_MSC_VER) && (_MSC_FULL_VER >= 160040219) /* VS2010 SP1 */
   250     a = (int)_xgetbv(0);
   251 #elif (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
   252     __asm
   253     {
   254         xor ecx, ecx
   255         _asm _emit 0x0f _asm _emit 0x01 _asm _emit 0xd0
   256         mov a, xcr0
   257     }
   258 #else
   259 #error Need xgetbv implementation!
   260 #endif
   261     return ((a & 6) == 6) ? SDL_TRUE : SDL_FALSE;
   262 }
   263 
   264 static int
   265 CPU_haveRDTSC(void)
   266 {
   267     if (CPU_haveCPUID()) {
   268         return (CPU_getCPUIDFeatures() & 0x00000010);
   269     }
   270     return 0;
   271 }
   272 
   273 static int
   274 CPU_haveAltiVec(void)
   275 {
   276     volatile int altivec = 0;
   277 #if (defined(__MACOSX__) && (defined(__ppc__) || defined(__ppc64__))) || (defined(__OpenBSD__) && defined(__powerpc__))
   278 #ifdef __OpenBSD__
   279     int selectors[2] = { CTL_MACHDEP, CPU_ALTIVEC };
   280 #else
   281     int selectors[2] = { CTL_HW, HW_VECTORUNIT };
   282 #endif
   283     int hasVectorUnit = 0;
   284     size_t length = sizeof(hasVectorUnit);
   285     int error = sysctl(selectors, 2, &hasVectorUnit, &length, NULL, 0);
   286     if (0 == error)
   287         altivec = (hasVectorUnit != 0);
   288 #elif SDL_ALTIVEC_BLITTERS && HAVE_SETJMP
   289     void (*handler) (int sig);
   290     handler = signal(SIGILL, illegal_instruction);
   291     if (setjmp(jmpbuf) == 0) {
   292         asm volatile ("mtspr 256, %0\n\t" "vand %%v0, %%v0, %%v0"::"r" (-1));
   293         altivec = 1;
   294     }
   295     signal(SIGILL, handler);
   296 #endif
   297     return altivec;
   298 }
   299 
   300 static int
   301 CPU_haveMMX(void)
   302 {
   303     if (CPU_haveCPUID()) {
   304         return (CPU_getCPUIDFeatures() & 0x00800000);
   305     }
   306     return 0;
   307 }
   308 
   309 static int
   310 CPU_have3DNow(void)
   311 {
   312     if (CPU_haveCPUID()) {
   313         int a, b, c, d;
   314 
   315         cpuid(0x80000000, a, b, c, d);
   316         if (a >= 0x80000001) {
   317             cpuid(0x80000001, a, b, c, d);
   318             return (d & 0x80000000);
   319         }
   320     }
   321     return 0;
   322 }
   323 
   324 static int
   325 CPU_haveSSE(void)
   326 {
   327     if (CPU_haveCPUID()) {
   328         return (CPU_getCPUIDFeatures() & 0x02000000);
   329     }
   330     return 0;
   331 }
   332 
   333 static int
   334 CPU_haveSSE2(void)
   335 {
   336     if (CPU_haveCPUID()) {
   337         return (CPU_getCPUIDFeatures() & 0x04000000);
   338     }
   339     return 0;
   340 }
   341 
   342 static int
   343 CPU_haveSSE3(void)
   344 {
   345     if (CPU_haveCPUID()) {
   346         int a, b, c, d;
   347 
   348         cpuid(0, a, b, c, d);
   349         if (a >= 1) {
   350             cpuid(1, a, b, c, d);
   351             return (c & 0x00000001);
   352         }
   353     }
   354     return 0;
   355 }
   356 
   357 static int
   358 CPU_haveSSE41(void)
   359 {
   360     if (CPU_haveCPUID()) {
   361         int a, b, c, d;
   362 
   363         cpuid(0, a, b, c, d);
   364         if (a >= 1) {
   365             cpuid(1, a, b, c, d);
   366             return (c & 0x00080000);
   367         }
   368     }
   369     return 0;
   370 }
   371 
   372 static int
   373 CPU_haveSSE42(void)
   374 {
   375     if (CPU_haveCPUID()) {
   376         int a, b, c, d;
   377 
   378         cpuid(0, a, b, c, d);
   379         if (a >= 1) {
   380             cpuid(1, a, b, c, d);
   381             return (c & 0x00100000);
   382         }
   383     }
   384     return 0;
   385 }
   386 
   387 static int
   388 CPU_haveAVX(void)
   389 {
   390     if (CPU_haveCPUID() && CPU_OSSavesYMM()) {
   391         int a, b, c, d;
   392 
   393         cpuid(0, a, b, c, d);
   394         if (a >= 1) {
   395             cpuid(1, a, b, c, d);
   396             return (c & 0x10000000);
   397         }
   398     }
   399     return 0;
   400 }
   401 
   402 static int
   403 CPU_haveAVX2(void)
   404 {
   405     if (CPU_haveCPUID() && CPU_OSSavesYMM()) {
   406         int a, b, c, d;
   407 
   408         cpuid(0, a, b, c, d);
   409         if (a >= 7) {
   410             cpuid(7, a, b, c, d);
   411             return (b & 0x00000020);
   412         }
   413     }
   414     return 0;
   415 }
   416 
   417 static int SDL_CPUCount = 0;
   418 
   419 int
   420 SDL_GetCPUCount(void)
   421 {
   422     if (!SDL_CPUCount) {
   423 #if defined(HAVE_SYSCONF) && defined(_SC_NPROCESSORS_ONLN)
   424         if (SDL_CPUCount <= 0) {
   425             SDL_CPUCount = (int)sysconf(_SC_NPROCESSORS_ONLN);
   426         }
   427 #endif
   428 #ifdef HAVE_SYSCTLBYNAME
   429         if (SDL_CPUCount <= 0) {
   430             size_t size = sizeof(SDL_CPUCount);
   431             sysctlbyname("hw.ncpu", &SDL_CPUCount, &size, NULL, 0);
   432         }
   433 #endif
   434 #ifdef __WIN32__
   435         if (SDL_CPUCount <= 0) {
   436             SYSTEM_INFO info;
   437             GetSystemInfo(&info);
   438             SDL_CPUCount = info.dwNumberOfProcessors;
   439         }
   440 #endif
   441         /* There has to be at least 1, right? :) */
   442         if (SDL_CPUCount <= 0) {
   443             SDL_CPUCount = 1;
   444         }
   445     }
   446     return SDL_CPUCount;
   447 }
   448 
   449 /* Oh, such a sweet sweet trick, just not very useful. :) */
   450 static const char *
   451 SDL_GetCPUType(void)
   452 {
   453     static char SDL_CPUType[13];
   454 
   455     if (!SDL_CPUType[0]) {
   456         int i = 0;
   457         int a, b, c, d;
   458 
   459         if (CPU_haveCPUID()) {
   460             cpuid(0x00000000, a, b, c, d);
   461             SDL_CPUType[i++] = (char)(b & 0xff); b >>= 8;
   462             SDL_CPUType[i++] = (char)(b & 0xff); b >>= 8;
   463             SDL_CPUType[i++] = (char)(b & 0xff); b >>= 8;
   464             SDL_CPUType[i++] = (char)(b & 0xff);
   465 
   466             SDL_CPUType[i++] = (char)(d & 0xff); d >>= 8;
   467             SDL_CPUType[i++] = (char)(d & 0xff); d >>= 8;
   468             SDL_CPUType[i++] = (char)(d & 0xff); d >>= 8;
   469             SDL_CPUType[i++] = (char)(d & 0xff);
   470 
   471             SDL_CPUType[i++] = (char)(c & 0xff); c >>= 8;
   472             SDL_CPUType[i++] = (char)(c & 0xff); c >>= 8;
   473             SDL_CPUType[i++] = (char)(c & 0xff); c >>= 8;
   474             SDL_CPUType[i++] = (char)(c & 0xff);
   475         }
   476         if (!SDL_CPUType[0]) {
   477             SDL_strlcpy(SDL_CPUType, "Unknown", sizeof(SDL_CPUType));
   478         }
   479     }
   480     return SDL_CPUType;
   481 }
   482 
   483 
   484 #ifdef TEST_MAIN  /* !!! FIXME: only used for test at the moment. */
   485 static const char *
   486 SDL_GetCPUName(void)
   487 {
   488     static char SDL_CPUName[48];
   489 
   490     if (!SDL_CPUName[0]) {
   491         int i = 0;
   492         int a, b, c, d;
   493 
   494         if (CPU_haveCPUID()) {
   495             cpuid(0x80000000, a, b, c, d);
   496             if (a >= 0x80000004) {
   497                 cpuid(0x80000002, a, b, c, d);
   498                 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
   499                 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
   500                 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
   501                 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
   502                 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
   503                 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
   504                 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
   505                 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
   506                 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
   507                 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
   508                 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
   509                 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
   510                 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
   511                 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
   512                 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
   513                 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
   514                 cpuid(0x80000003, a, b, c, d);
   515                 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
   516                 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
   517                 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
   518                 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
   519                 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
   520                 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
   521                 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
   522                 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
   523                 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
   524                 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
   525                 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
   526                 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
   527                 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
   528                 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
   529                 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
   530                 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
   531                 cpuid(0x80000004, a, b, c, d);
   532                 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
   533                 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
   534                 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
   535                 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
   536                 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
   537                 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
   538                 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
   539                 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
   540                 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
   541                 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
   542                 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
   543                 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
   544                 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
   545                 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
   546                 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
   547                 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
   548             }
   549         }
   550         if (!SDL_CPUName[0]) {
   551             SDL_strlcpy(SDL_CPUName, "Unknown", sizeof(SDL_CPUName));
   552         }
   553     }
   554     return SDL_CPUName;
   555 }
   556 #endif
   557 
   558 int
   559 SDL_GetCPUCacheLineSize(void)
   560 {
   561     const char *cpuType = SDL_GetCPUType();
   562 
   563     if (SDL_strcmp(cpuType, "GenuineIntel") == 0) {
   564         int a, b, c, d;
   565 
   566         cpuid(0x00000001, a, b, c, d);
   567         return (((b >> 8) & 0xff) * 8);
   568     } else if (SDL_strcmp(cpuType, "AuthenticAMD") == 0) {
   569         int a, b, c, d;
   570 
   571         cpuid(0x80000005, a, b, c, d);
   572         return (c & 0xff);
   573     } else {
   574         /* Just make a guess here... */
   575         return SDL_CACHELINE_SIZE;
   576     }
   577 }
   578 
   579 static Uint32 SDL_CPUFeatures = 0xFFFFFFFF;
   580 
   581 static Uint32
   582 SDL_GetCPUFeatures(void)
   583 {
   584     if (SDL_CPUFeatures == 0xFFFFFFFF) {
   585         SDL_CPUFeatures = 0;
   586         if (CPU_haveRDTSC()) {
   587             SDL_CPUFeatures |= CPU_HAS_RDTSC;
   588         }
   589         if (CPU_haveAltiVec()) {
   590             SDL_CPUFeatures |= CPU_HAS_ALTIVEC;
   591         }
   592         if (CPU_haveMMX()) {
   593             SDL_CPUFeatures |= CPU_HAS_MMX;
   594         }
   595         if (CPU_have3DNow()) {
   596             SDL_CPUFeatures |= CPU_HAS_3DNOW;
   597         }
   598         if (CPU_haveSSE()) {
   599             SDL_CPUFeatures |= CPU_HAS_SSE;
   600         }
   601         if (CPU_haveSSE2()) {
   602             SDL_CPUFeatures |= CPU_HAS_SSE2;
   603         }
   604         if (CPU_haveSSE3()) {
   605             SDL_CPUFeatures |= CPU_HAS_SSE3;
   606         }
   607         if (CPU_haveSSE41()) {
   608             SDL_CPUFeatures |= CPU_HAS_SSE41;
   609         }
   610         if (CPU_haveSSE42()) {
   611             SDL_CPUFeatures |= CPU_HAS_SSE42;
   612         }
   613         if (CPU_haveAVX()) {
   614             SDL_CPUFeatures |= CPU_HAS_AVX;
   615         }
   616         if (CPU_haveAVX2()) {
   617             SDL_CPUFeatures |= CPU_HAS_AVX2;
   618         }
   619     }
   620     return SDL_CPUFeatures;
   621 }
   622 
   623 SDL_bool
   624 SDL_HasRDTSC(void)
   625 {
   626     if (SDL_GetCPUFeatures() & CPU_HAS_RDTSC) {
   627         return SDL_TRUE;
   628     }
   629     return SDL_FALSE;
   630 }
   631 
   632 SDL_bool
   633 SDL_HasAltiVec(void)
   634 {
   635     if (SDL_GetCPUFeatures() & CPU_HAS_ALTIVEC) {
   636         return SDL_TRUE;
   637     }
   638     return SDL_FALSE;
   639 }
   640 
   641 SDL_bool
   642 SDL_HasMMX(void)
   643 {
   644     if (SDL_GetCPUFeatures() & CPU_HAS_MMX) {
   645         return SDL_TRUE;
   646     }
   647     return SDL_FALSE;
   648 }
   649 
   650 SDL_bool
   651 SDL_Has3DNow(void)
   652 {
   653     if (SDL_GetCPUFeatures() & CPU_HAS_3DNOW) {
   654         return SDL_TRUE;
   655     }
   656     return SDL_FALSE;
   657 }
   658 
   659 SDL_bool
   660 SDL_HasSSE(void)
   661 {
   662     if (SDL_GetCPUFeatures() & CPU_HAS_SSE) {
   663         return SDL_TRUE;
   664     }
   665     return SDL_FALSE;
   666 }
   667 
   668 SDL_bool
   669 SDL_HasSSE2(void)
   670 {
   671     if (SDL_GetCPUFeatures() & CPU_HAS_SSE2) {
   672         return SDL_TRUE;
   673     }
   674     return SDL_FALSE;
   675 }
   676 
   677 SDL_bool
   678 SDL_HasSSE3(void)
   679 {
   680     if (SDL_GetCPUFeatures() & CPU_HAS_SSE3) {
   681         return SDL_TRUE;
   682     }
   683     return SDL_FALSE;
   684 }
   685 
   686 SDL_bool
   687 SDL_HasSSE41(void)
   688 {
   689     if (SDL_GetCPUFeatures() & CPU_HAS_SSE41) {
   690         return SDL_TRUE;
   691     }
   692     return SDL_FALSE;
   693 }
   694 
   695 SDL_bool
   696 SDL_HasSSE42(void)
   697 {
   698     if (SDL_GetCPUFeatures() & CPU_HAS_SSE42) {
   699         return SDL_TRUE;
   700     }
   701     return SDL_FALSE;
   702 }
   703 
   704 SDL_bool
   705 SDL_HasAVX(void)
   706 {
   707     if (SDL_GetCPUFeatures() & CPU_HAS_AVX) {
   708         return SDL_TRUE;
   709     }
   710     return SDL_FALSE;
   711 }
   712 
   713 SDL_bool
   714 SDL_HasAVX2(void)
   715 {
   716     if (SDL_GetCPUFeatures() & CPU_HAS_AVX2) {
   717         return SDL_TRUE;
   718     }
   719     return SDL_FALSE;
   720 }
   721 
   722 static int SDL_SystemRAM = 0;
   723 
   724 int
   725 SDL_GetSystemRAM(void)
   726 {
   727     if (!SDL_SystemRAM) {
   728 #if defined(HAVE_SYSCONF) && defined(_SC_PHYS_PAGES) && defined(_SC_PAGESIZE)
   729         if (SDL_SystemRAM <= 0) {
   730             SDL_SystemRAM = (int)((Sint64)sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGESIZE) / (1024*1024));
   731         }
   732 #endif
   733 #ifdef HAVE_SYSCTLBYNAME
   734         if (SDL_SystemRAM <= 0) {
   735 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
   736 #ifdef HW_REALMEM
   737             int mib[2] = {CTL_HW, HW_REALMEM};
   738 #else
   739             /* might only report up to 2 GiB */
   740             int mib[2] = {CTL_HW, HW_PHYSMEM};
   741 #endif /* HW_REALMEM */
   742 #else
   743             int mib[2] = {CTL_HW, HW_MEMSIZE};
   744 #endif /* __FreeBSD__ || __FreeBSD_kernel__ */
   745             Uint64 memsize = 0;
   746             size_t len = sizeof(memsize);
   747             
   748             if (sysctl(mib, 2, &memsize, &len, NULL, 0) == 0) {
   749                 SDL_SystemRAM = (int)(memsize / (1024*1024));
   750             }
   751         }
   752 #endif
   753 #ifdef __WIN32__
   754         if (SDL_SystemRAM <= 0) {
   755             MEMORYSTATUSEX stat;
   756             stat.dwLength = sizeof(stat);
   757             if (GlobalMemoryStatusEx(&stat)) {
   758                 SDL_SystemRAM = (int)(stat.ullTotalPhys / (1024 * 1024));
   759             }
   760         }
   761 #endif
   762     }
   763     return SDL_SystemRAM;
   764 }
   765 
   766 
   767 #ifdef TEST_MAIN
   768 
   769 #include <stdio.h>
   770 
   771 int
   772 main()
   773 {
   774     printf("CPU count: %d\n", SDL_GetCPUCount());
   775     printf("CPU type: %s\n", SDL_GetCPUType());
   776     printf("CPU name: %s\n", SDL_GetCPUName());
   777     printf("CacheLine size: %d\n", SDL_GetCPUCacheLineSize());
   778     printf("RDTSC: %d\n", SDL_HasRDTSC());
   779     printf("Altivec: %d\n", SDL_HasAltiVec());
   780     printf("MMX: %d\n", SDL_HasMMX());
   781     printf("3DNow: %d\n", SDL_Has3DNow());
   782     printf("SSE: %d\n", SDL_HasSSE());
   783     printf("SSE2: %d\n", SDL_HasSSE2());
   784     printf("SSE3: %d\n", SDL_HasSSE3());
   785     printf("SSE4.1: %d\n", SDL_HasSSE41());
   786     printf("SSE4.2: %d\n", SDL_HasSSE42());
   787     printf("AVX: %d\n", SDL_HasAVX());
   788     printf("AVX2: %d\n", SDL_HasAVX2());
   789     printf("RAM: %d MB\n", SDL_GetSystemRAM());
   790     return 0;
   791 }
   792 
   793 #endif /* TEST_MAIN */
   794 
   795 /* vi: set ts=4 sw=4 expandtab: */