src/cpuinfo/SDL_cpuinfo.c
author Ryan C. Gordon <icculus@icculus.org>
Tue, 29 Dec 2015 02:32:47 -0500
changeset 9987 d64783aac765
parent 9619 b94b6d0bff0f
child 9998 f67cf37e9cd4
permissions -rw-r--r--
NetBSD: fixed issues with cpuinfo and pthread_setname_np (thanks, Thomas!).

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