src/cpuinfo/SDL_cpuinfo.c
author Ryan C. Gordon <icculus@icculus.org>
Thu, 18 Dec 2014 00:19:52 -0500
changeset 9278 8900afb78a19
parent 9047 101109110bf7
child 9300 0293f45e4814
permissions -rw-r--r--
Initial merge of Emscripten port!

With this commit, you can compile SDL2 with Emscripten
( http://emscripten.org/ ), and make your SDL-based C/C++ program
into a web app.

This port was due to the efforts of several people, including: Charlie Birks,
Sathyanarayanan Gunasekaran, Jukka Jylänki, Alon Zakai, Edward Rudd,
Bruce Mitchener, and Martin Gerhardy. (Thanks, everyone!)
     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 #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         int a, b, c, d;
   462 
   463         if (CPU_haveCPUID()) {
   464             cpuid(0x00000000, a, b, c, d);
   465             SDL_CPUType[i++] = (char)(b & 0xff); b >>= 8;
   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);
   469 
   470             SDL_CPUType[i++] = (char)(d & 0xff); d >>= 8;
   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);
   474 
   475             SDL_CPUType[i++] = (char)(c & 0xff); c >>= 8;
   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);
   479         }
   480         if (!SDL_CPUType[0]) {
   481             SDL_strlcpy(SDL_CPUType, "Unknown", sizeof(SDL_CPUType));
   482         }
   483     }
   484     return SDL_CPUType;
   485 }
   486 
   487 
   488 #ifdef TEST_MAIN  /* !!! FIXME: only used for test at the moment. */
   489 static const char *
   490 SDL_GetCPUName(void)
   491 {
   492     static char SDL_CPUName[48];
   493 
   494     if (!SDL_CPUName[0]) {
   495         int i = 0;
   496         int a, b, c, d;
   497 
   498         if (CPU_haveCPUID()) {
   499             cpuid(0x80000000, a, b, c, d);
   500             if (a >= 0x80000004) {
   501                 cpuid(0x80000002, a, b, c, d);
   502                 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
   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)(b & 0xff); b >>= 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)(c & 0xff); c >>= 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)(d & 0xff); d >>= 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                 cpuid(0x80000003, a, b, c, d);
   519                 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
   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)(b & 0xff); b >>= 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)(c & 0xff); c >>= 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)(d & 0xff); d >>= 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                 cpuid(0x80000004, a, b, c, d);
   536                 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
   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)(b & 0xff); b >>= 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)(c & 0xff); c >>= 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)(d & 0xff); d >>= 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             }
   553         }
   554         if (!SDL_CPUName[0]) {
   555             SDL_strlcpy(SDL_CPUName, "Unknown", sizeof(SDL_CPUName));
   556         }
   557     }
   558     return SDL_CPUName;
   559 }
   560 #endif
   561 
   562 int
   563 SDL_GetCPUCacheLineSize(void)
   564 {
   565     const char *cpuType = SDL_GetCPUType();
   566 
   567     if (SDL_strcmp(cpuType, "GenuineIntel") == 0) {
   568         int a, b, c, d;
   569 
   570         cpuid(0x00000001, a, b, c, d);
   571         return (((b >> 8) & 0xff) * 8);
   572     } else if (SDL_strcmp(cpuType, "AuthenticAMD") == 0) {
   573         int a, b, c, d;
   574 
   575         cpuid(0x80000005, a, b, c, d);
   576         return (c & 0xff);
   577     } else {
   578         /* Just make a guess here... */
   579         return SDL_CACHELINE_SIZE;
   580     }
   581 }
   582 
   583 static Uint32 SDL_CPUFeatures = 0xFFFFFFFF;
   584 
   585 static Uint32
   586 SDL_GetCPUFeatures(void)
   587 {
   588     if (SDL_CPUFeatures == 0xFFFFFFFF) {
   589         SDL_CPUFeatures = 0;
   590         if (CPU_haveRDTSC()) {
   591             SDL_CPUFeatures |= CPU_HAS_RDTSC;
   592         }
   593         if (CPU_haveAltiVec()) {
   594             SDL_CPUFeatures |= CPU_HAS_ALTIVEC;
   595         }
   596         if (CPU_haveMMX()) {
   597             SDL_CPUFeatures |= CPU_HAS_MMX;
   598         }
   599         if (CPU_have3DNow()) {
   600             SDL_CPUFeatures |= CPU_HAS_3DNOW;
   601         }
   602         if (CPU_haveSSE()) {
   603             SDL_CPUFeatures |= CPU_HAS_SSE;
   604         }
   605         if (CPU_haveSSE2()) {
   606             SDL_CPUFeatures |= CPU_HAS_SSE2;
   607         }
   608         if (CPU_haveSSE3()) {
   609             SDL_CPUFeatures |= CPU_HAS_SSE3;
   610         }
   611         if (CPU_haveSSE41()) {
   612             SDL_CPUFeatures |= CPU_HAS_SSE41;
   613         }
   614         if (CPU_haveSSE42()) {
   615             SDL_CPUFeatures |= CPU_HAS_SSE42;
   616         }
   617         if (CPU_haveAVX()) {
   618             SDL_CPUFeatures |= CPU_HAS_AVX;
   619         }
   620         if (CPU_haveAVX2()) {
   621             SDL_CPUFeatures |= CPU_HAS_AVX2;
   622         }
   623     }
   624     return SDL_CPUFeatures;
   625 }
   626 
   627 SDL_bool
   628 SDL_HasRDTSC(void)
   629 {
   630     if (SDL_GetCPUFeatures() & CPU_HAS_RDTSC) {
   631         return SDL_TRUE;
   632     }
   633     return SDL_FALSE;
   634 }
   635 
   636 SDL_bool
   637 SDL_HasAltiVec(void)
   638 {
   639     if (SDL_GetCPUFeatures() & CPU_HAS_ALTIVEC) {
   640         return SDL_TRUE;
   641     }
   642     return SDL_FALSE;
   643 }
   644 
   645 SDL_bool
   646 SDL_HasMMX(void)
   647 {
   648     if (SDL_GetCPUFeatures() & CPU_HAS_MMX) {
   649         return SDL_TRUE;
   650     }
   651     return SDL_FALSE;
   652 }
   653 
   654 SDL_bool
   655 SDL_Has3DNow(void)
   656 {
   657     if (SDL_GetCPUFeatures() & CPU_HAS_3DNOW) {
   658         return SDL_TRUE;
   659     }
   660     return SDL_FALSE;
   661 }
   662 
   663 SDL_bool
   664 SDL_HasSSE(void)
   665 {
   666     if (SDL_GetCPUFeatures() & CPU_HAS_SSE) {
   667         return SDL_TRUE;
   668     }
   669     return SDL_FALSE;
   670 }
   671 
   672 SDL_bool
   673 SDL_HasSSE2(void)
   674 {
   675     if (SDL_GetCPUFeatures() & CPU_HAS_SSE2) {
   676         return SDL_TRUE;
   677     }
   678     return SDL_FALSE;
   679 }
   680 
   681 SDL_bool
   682 SDL_HasSSE3(void)
   683 {
   684     if (SDL_GetCPUFeatures() & CPU_HAS_SSE3) {
   685         return SDL_TRUE;
   686     }
   687     return SDL_FALSE;
   688 }
   689 
   690 SDL_bool
   691 SDL_HasSSE41(void)
   692 {
   693     if (SDL_GetCPUFeatures() & CPU_HAS_SSE41) {
   694         return SDL_TRUE;
   695     }
   696     return SDL_FALSE;
   697 }
   698 
   699 SDL_bool
   700 SDL_HasSSE42(void)
   701 {
   702     if (SDL_GetCPUFeatures() & CPU_HAS_SSE42) {
   703         return SDL_TRUE;
   704     }
   705     return SDL_FALSE;
   706 }
   707 
   708 SDL_bool
   709 SDL_HasAVX(void)
   710 {
   711     if (SDL_GetCPUFeatures() & CPU_HAS_AVX) {
   712         return SDL_TRUE;
   713     }
   714     return SDL_FALSE;
   715 }
   716 
   717 SDL_bool
   718 SDL_HasAVX2(void)
   719 {
   720     if (SDL_GetCPUFeatures() & CPU_HAS_AVX2) {
   721         return SDL_TRUE;
   722     }
   723     return SDL_FALSE;
   724 }
   725 
   726 static int SDL_SystemRAM = 0;
   727 
   728 int
   729 SDL_GetSystemRAM(void)
   730 {
   731     if (!SDL_SystemRAM) {
   732 #ifndef SDL_CPUINFO_DISABLED
   733 #if defined(HAVE_SYSCONF) && defined(_SC_PHYS_PAGES) && defined(_SC_PAGESIZE)
   734         if (SDL_SystemRAM <= 0) {
   735             SDL_SystemRAM = (int)((Sint64)sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGESIZE) / (1024*1024));
   736         }
   737 #endif
   738 #ifdef HAVE_SYSCTLBYNAME
   739         if (SDL_SystemRAM <= 0) {
   740 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
   741 #ifdef HW_REALMEM
   742             int mib[2] = {CTL_HW, HW_REALMEM};
   743 #else
   744             /* might only report up to 2 GiB */
   745             int mib[2] = {CTL_HW, HW_PHYSMEM};
   746 #endif /* HW_REALMEM */
   747 #else
   748             int mib[2] = {CTL_HW, HW_MEMSIZE};
   749 #endif /* __FreeBSD__ || __FreeBSD_kernel__ */
   750             Uint64 memsize = 0;
   751             size_t len = sizeof(memsize);
   752             
   753             if (sysctl(mib, 2, &memsize, &len, NULL, 0) == 0) {
   754                 SDL_SystemRAM = (int)(memsize / (1024*1024));
   755             }
   756         }
   757 #endif
   758 #ifdef __WIN32__
   759         if (SDL_SystemRAM <= 0) {
   760             MEMORYSTATUSEX stat;
   761             stat.dwLength = sizeof(stat);
   762             if (GlobalMemoryStatusEx(&stat)) {
   763                 SDL_SystemRAM = (int)(stat.ullTotalPhys / (1024 * 1024));
   764             }
   765         }
   766 #endif
   767 #endif
   768     }
   769     return SDL_SystemRAM;
   770 }
   771 
   772 
   773 #ifdef TEST_MAIN
   774 
   775 #include <stdio.h>
   776 
   777 int
   778 main()
   779 {
   780     printf("CPU count: %d\n", SDL_GetCPUCount());
   781     printf("CPU type: %s\n", SDL_GetCPUType());
   782     printf("CPU name: %s\n", SDL_GetCPUName());
   783     printf("CacheLine size: %d\n", SDL_GetCPUCacheLineSize());
   784     printf("RDTSC: %d\n", SDL_HasRDTSC());
   785     printf("Altivec: %d\n", SDL_HasAltiVec());
   786     printf("MMX: %d\n", SDL_HasMMX());
   787     printf("3DNow: %d\n", SDL_Has3DNow());
   788     printf("SSE: %d\n", SDL_HasSSE());
   789     printf("SSE2: %d\n", SDL_HasSSE2());
   790     printf("SSE3: %d\n", SDL_HasSSE3());
   791     printf("SSE4.1: %d\n", SDL_HasSSE41());
   792     printf("SSE4.2: %d\n", SDL_HasSSE42());
   793     printf("AVX: %d\n", SDL_HasAVX());
   794     printf("AVX2: %d\n", SDL_HasAVX2());
   795     printf("RAM: %d MB\n", SDL_GetSystemRAM());
   796     return 0;
   797 }
   798 
   799 #endif /* TEST_MAIN */
   800 
   801 /* vi: set ts=4 sw=4 expandtab: */