src/cpuinfo/SDL_cpuinfo.c
author Ryan C. Gordon <icculus@icculus.org>
Thu, 17 Nov 2016 01:34:18 -0500
changeset 10622 972f7f6dd9b9
parent 10621 3b74422e881d
child 10623 3b93b7acc1b4
permissions -rw-r--r--
cpuinfo: disable NEON detection on Android for now.

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