src/cpuinfo/SDL_cpuinfo.c
author David Ludwig <dludwig@pobox.com>
Sun, 10 Aug 2014 22:21:21 -0400
changeset 9047 101109110bf7
parent 9005 ef3ef3c8da98
child 9278 8900afb78a19
permissions -rw-r--r--
WinRT build fix for ARM platforms

The _xgetbv intrinsic was being used in ARM builds of SDL/WinRT, which was
leading to linker errors. This commit limits _xgetbv use to the platforms on
which it is available, x86 and x64.
     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) && (defined(_M_IX86) || defined(_M_X64)) && (_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, eax
   257     }
   258 #endif
   259     return ((a & 6) == 6) ? SDL_TRUE : SDL_FALSE;
   260 }
   261 
   262 static int
   263 CPU_haveRDTSC(void)
   264 {
   265     if (CPU_haveCPUID()) {
   266         return (CPU_getCPUIDFeatures() & 0x00000010);
   267     }
   268     return 0;
   269 }
   270 
   271 static int
   272 CPU_haveAltiVec(void)
   273 {
   274     volatile int altivec = 0;
   275 #if (defined(__MACOSX__) && (defined(__ppc__) || defined(__ppc64__))) || (defined(__OpenBSD__) && defined(__powerpc__))
   276 #ifdef __OpenBSD__
   277     int selectors[2] = { CTL_MACHDEP, CPU_ALTIVEC };
   278 #else
   279     int selectors[2] = { CTL_HW, HW_VECTORUNIT };
   280 #endif
   281     int hasVectorUnit = 0;
   282     size_t length = sizeof(hasVectorUnit);
   283     int error = sysctl(selectors, 2, &hasVectorUnit, &length, NULL, 0);
   284     if (0 == error)
   285         altivec = (hasVectorUnit != 0);
   286 #elif SDL_ALTIVEC_BLITTERS && HAVE_SETJMP
   287     void (*handler) (int sig);
   288     handler = signal(SIGILL, illegal_instruction);
   289     if (setjmp(jmpbuf) == 0) {
   290         asm volatile ("mtspr 256, %0\n\t" "vand %%v0, %%v0, %%v0"::"r" (-1));
   291         altivec = 1;
   292     }
   293     signal(SIGILL, handler);
   294 #endif
   295     return altivec;
   296 }
   297 
   298 static int
   299 CPU_haveMMX(void)
   300 {
   301     if (CPU_haveCPUID()) {
   302         return (CPU_getCPUIDFeatures() & 0x00800000);
   303     }
   304     return 0;
   305 }
   306 
   307 static int
   308 CPU_have3DNow(void)
   309 {
   310     if (CPU_haveCPUID()) {
   311         int a, b, c, d;
   312 
   313         cpuid(0x80000000, a, b, c, d);
   314         if (a >= 0x80000001) {
   315             cpuid(0x80000001, a, b, c, d);
   316             return (d & 0x80000000);
   317         }
   318     }
   319     return 0;
   320 }
   321 
   322 static int
   323 CPU_haveSSE(void)
   324 {
   325     if (CPU_haveCPUID()) {
   326         return (CPU_getCPUIDFeatures() & 0x02000000);
   327     }
   328     return 0;
   329 }
   330 
   331 static int
   332 CPU_haveSSE2(void)
   333 {
   334     if (CPU_haveCPUID()) {
   335         return (CPU_getCPUIDFeatures() & 0x04000000);
   336     }
   337     return 0;
   338 }
   339 
   340 static int
   341 CPU_haveSSE3(void)
   342 {
   343     if (CPU_haveCPUID()) {
   344         int a, b, c, d;
   345 
   346         cpuid(0, a, b, c, d);
   347         if (a >= 1) {
   348             cpuid(1, a, b, c, d);
   349             return (c & 0x00000001);
   350         }
   351     }
   352     return 0;
   353 }
   354 
   355 static int
   356 CPU_haveSSE41(void)
   357 {
   358     if (CPU_haveCPUID()) {
   359         int a, b, c, d;
   360 
   361         cpuid(0, a, b, c, d);
   362         if (a >= 1) {
   363             cpuid(1, a, b, c, d);
   364             return (c & 0x00080000);
   365         }
   366     }
   367     return 0;
   368 }
   369 
   370 static int
   371 CPU_haveSSE42(void)
   372 {
   373     if (CPU_haveCPUID()) {
   374         int a, b, c, d;
   375 
   376         cpuid(0, a, b, c, d);
   377         if (a >= 1) {
   378             cpuid(1, a, b, c, d);
   379             return (c & 0x00100000);
   380         }
   381     }
   382     return 0;
   383 }
   384 
   385 static int
   386 CPU_haveAVX(void)
   387 {
   388     if (CPU_haveCPUID() && CPU_OSSavesYMM()) {
   389         int a, b, c, d;
   390 
   391         cpuid(0, a, b, c, d);
   392         if (a >= 1) {
   393             cpuid(1, a, b, c, d);
   394             return (c & 0x10000000);
   395         }
   396     }
   397     return 0;
   398 }
   399 
   400 static int
   401 CPU_haveAVX2(void)
   402 {
   403     if (CPU_haveCPUID() && CPU_OSSavesYMM()) {
   404         int a, b, c, d;
   405 
   406         cpuid(0, a, b, c, d);
   407         if (a >= 7) {
   408             cpuid(7, a, b, c, d);
   409             return (b & 0x00000020);
   410         }
   411     }
   412     return 0;
   413 }
   414 
   415 static int SDL_CPUCount = 0;
   416 
   417 int
   418 SDL_GetCPUCount(void)
   419 {
   420     if (!SDL_CPUCount) {
   421 #if defined(HAVE_SYSCONF) && defined(_SC_NPROCESSORS_ONLN)
   422         if (SDL_CPUCount <= 0) {
   423             SDL_CPUCount = (int)sysconf(_SC_NPROCESSORS_ONLN);
   424         }
   425 #endif
   426 #ifdef HAVE_SYSCTLBYNAME
   427         if (SDL_CPUCount <= 0) {
   428             size_t size = sizeof(SDL_CPUCount);
   429             sysctlbyname("hw.ncpu", &SDL_CPUCount, &size, NULL, 0);
   430         }
   431 #endif
   432 #ifdef __WIN32__
   433         if (SDL_CPUCount <= 0) {
   434             SYSTEM_INFO info;
   435             GetSystemInfo(&info);
   436             SDL_CPUCount = info.dwNumberOfProcessors;
   437         }
   438 #endif
   439         /* There has to be at least 1, right? :) */
   440         if (SDL_CPUCount <= 0) {
   441             SDL_CPUCount = 1;
   442         }
   443     }
   444     return SDL_CPUCount;
   445 }
   446 
   447 /* Oh, such a sweet sweet trick, just not very useful. :) */
   448 static const char *
   449 SDL_GetCPUType(void)
   450 {
   451     static char SDL_CPUType[13];
   452 
   453     if (!SDL_CPUType[0]) {
   454         int i = 0;
   455         int a, b, c, d;
   456 
   457         if (CPU_haveCPUID()) {
   458             cpuid(0x00000000, a, b, c, d);
   459             SDL_CPUType[i++] = (char)(b & 0xff); b >>= 8;
   460             SDL_CPUType[i++] = (char)(b & 0xff); b >>= 8;
   461             SDL_CPUType[i++] = (char)(b & 0xff); b >>= 8;
   462             SDL_CPUType[i++] = (char)(b & 0xff);
   463 
   464             SDL_CPUType[i++] = (char)(d & 0xff); d >>= 8;
   465             SDL_CPUType[i++] = (char)(d & 0xff); d >>= 8;
   466             SDL_CPUType[i++] = (char)(d & 0xff); d >>= 8;
   467             SDL_CPUType[i++] = (char)(d & 0xff);
   468 
   469             SDL_CPUType[i++] = (char)(c & 0xff); c >>= 8;
   470             SDL_CPUType[i++] = (char)(c & 0xff); c >>= 8;
   471             SDL_CPUType[i++] = (char)(c & 0xff); c >>= 8;
   472             SDL_CPUType[i++] = (char)(c & 0xff);
   473         }
   474         if (!SDL_CPUType[0]) {
   475             SDL_strlcpy(SDL_CPUType, "Unknown", sizeof(SDL_CPUType));
   476         }
   477     }
   478     return SDL_CPUType;
   479 }
   480 
   481 
   482 #ifdef TEST_MAIN  /* !!! FIXME: only used for test at the moment. */
   483 static const char *
   484 SDL_GetCPUName(void)
   485 {
   486     static char SDL_CPUName[48];
   487 
   488     if (!SDL_CPUName[0]) {
   489         int i = 0;
   490         int a, b, c, d;
   491 
   492         if (CPU_haveCPUID()) {
   493             cpuid(0x80000000, a, b, c, d);
   494             if (a >= 0x80000004) {
   495                 cpuid(0x80000002, a, b, c, d);
   496                 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
   497                 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
   498                 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
   499                 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
   500                 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
   501                 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
   502                 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
   503                 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
   504                 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
   505                 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
   506                 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
   507                 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
   508                 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
   509                 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
   510                 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
   511                 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
   512                 cpuid(0x80000003, a, b, c, d);
   513                 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
   514                 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
   515                 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
   516                 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
   517                 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
   518                 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
   519                 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
   520                 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
   521                 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
   522                 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
   523                 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
   524                 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
   525                 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
   526                 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
   527                 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
   528                 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
   529                 cpuid(0x80000004, a, b, c, d);
   530                 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
   531                 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
   532                 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
   533                 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
   534                 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
   535                 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
   536                 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
   537                 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
   538                 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
   539                 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
   540                 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
   541                 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
   542                 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
   543                 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
   544                 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
   545                 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
   546             }
   547         }
   548         if (!SDL_CPUName[0]) {
   549             SDL_strlcpy(SDL_CPUName, "Unknown", sizeof(SDL_CPUName));
   550         }
   551     }
   552     return SDL_CPUName;
   553 }
   554 #endif
   555 
   556 int
   557 SDL_GetCPUCacheLineSize(void)
   558 {
   559     const char *cpuType = SDL_GetCPUType();
   560 
   561     if (SDL_strcmp(cpuType, "GenuineIntel") == 0) {
   562         int a, b, c, d;
   563 
   564         cpuid(0x00000001, a, b, c, d);
   565         return (((b >> 8) & 0xff) * 8);
   566     } else if (SDL_strcmp(cpuType, "AuthenticAMD") == 0) {
   567         int a, b, c, d;
   568 
   569         cpuid(0x80000005, a, b, c, d);
   570         return (c & 0xff);
   571     } else {
   572         /* Just make a guess here... */
   573         return SDL_CACHELINE_SIZE;
   574     }
   575 }
   576 
   577 static Uint32 SDL_CPUFeatures = 0xFFFFFFFF;
   578 
   579 static Uint32
   580 SDL_GetCPUFeatures(void)
   581 {
   582     if (SDL_CPUFeatures == 0xFFFFFFFF) {
   583         SDL_CPUFeatures = 0;
   584         if (CPU_haveRDTSC()) {
   585             SDL_CPUFeatures |= CPU_HAS_RDTSC;
   586         }
   587         if (CPU_haveAltiVec()) {
   588             SDL_CPUFeatures |= CPU_HAS_ALTIVEC;
   589         }
   590         if (CPU_haveMMX()) {
   591             SDL_CPUFeatures |= CPU_HAS_MMX;
   592         }
   593         if (CPU_have3DNow()) {
   594             SDL_CPUFeatures |= CPU_HAS_3DNOW;
   595         }
   596         if (CPU_haveSSE()) {
   597             SDL_CPUFeatures |= CPU_HAS_SSE;
   598         }
   599         if (CPU_haveSSE2()) {
   600             SDL_CPUFeatures |= CPU_HAS_SSE2;
   601         }
   602         if (CPU_haveSSE3()) {
   603             SDL_CPUFeatures |= CPU_HAS_SSE3;
   604         }
   605         if (CPU_haveSSE41()) {
   606             SDL_CPUFeatures |= CPU_HAS_SSE41;
   607         }
   608         if (CPU_haveSSE42()) {
   609             SDL_CPUFeatures |= CPU_HAS_SSE42;
   610         }
   611         if (CPU_haveAVX()) {
   612             SDL_CPUFeatures |= CPU_HAS_AVX;
   613         }
   614         if (CPU_haveAVX2()) {
   615             SDL_CPUFeatures |= CPU_HAS_AVX2;
   616         }
   617     }
   618     return SDL_CPUFeatures;
   619 }
   620 
   621 SDL_bool
   622 SDL_HasRDTSC(void)
   623 {
   624     if (SDL_GetCPUFeatures() & CPU_HAS_RDTSC) {
   625         return SDL_TRUE;
   626     }
   627     return SDL_FALSE;
   628 }
   629 
   630 SDL_bool
   631 SDL_HasAltiVec(void)
   632 {
   633     if (SDL_GetCPUFeatures() & CPU_HAS_ALTIVEC) {
   634         return SDL_TRUE;
   635     }
   636     return SDL_FALSE;
   637 }
   638 
   639 SDL_bool
   640 SDL_HasMMX(void)
   641 {
   642     if (SDL_GetCPUFeatures() & CPU_HAS_MMX) {
   643         return SDL_TRUE;
   644     }
   645     return SDL_FALSE;
   646 }
   647 
   648 SDL_bool
   649 SDL_Has3DNow(void)
   650 {
   651     if (SDL_GetCPUFeatures() & CPU_HAS_3DNOW) {
   652         return SDL_TRUE;
   653     }
   654     return SDL_FALSE;
   655 }
   656 
   657 SDL_bool
   658 SDL_HasSSE(void)
   659 {
   660     if (SDL_GetCPUFeatures() & CPU_HAS_SSE) {
   661         return SDL_TRUE;
   662     }
   663     return SDL_FALSE;
   664 }
   665 
   666 SDL_bool
   667 SDL_HasSSE2(void)
   668 {
   669     if (SDL_GetCPUFeatures() & CPU_HAS_SSE2) {
   670         return SDL_TRUE;
   671     }
   672     return SDL_FALSE;
   673 }
   674 
   675 SDL_bool
   676 SDL_HasSSE3(void)
   677 {
   678     if (SDL_GetCPUFeatures() & CPU_HAS_SSE3) {
   679         return SDL_TRUE;
   680     }
   681     return SDL_FALSE;
   682 }
   683 
   684 SDL_bool
   685 SDL_HasSSE41(void)
   686 {
   687     if (SDL_GetCPUFeatures() & CPU_HAS_SSE41) {
   688         return SDL_TRUE;
   689     }
   690     return SDL_FALSE;
   691 }
   692 
   693 SDL_bool
   694 SDL_HasSSE42(void)
   695 {
   696     if (SDL_GetCPUFeatures() & CPU_HAS_SSE42) {
   697         return SDL_TRUE;
   698     }
   699     return SDL_FALSE;
   700 }
   701 
   702 SDL_bool
   703 SDL_HasAVX(void)
   704 {
   705     if (SDL_GetCPUFeatures() & CPU_HAS_AVX) {
   706         return SDL_TRUE;
   707     }
   708     return SDL_FALSE;
   709 }
   710 
   711 SDL_bool
   712 SDL_HasAVX2(void)
   713 {
   714     if (SDL_GetCPUFeatures() & CPU_HAS_AVX2) {
   715         return SDL_TRUE;
   716     }
   717     return SDL_FALSE;
   718 }
   719 
   720 static int SDL_SystemRAM = 0;
   721 
   722 int
   723 SDL_GetSystemRAM(void)
   724 {
   725     if (!SDL_SystemRAM) {
   726 #if defined(HAVE_SYSCONF) && defined(_SC_PHYS_PAGES) && defined(_SC_PAGESIZE)
   727         if (SDL_SystemRAM <= 0) {
   728             SDL_SystemRAM = (int)((Sint64)sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGESIZE) / (1024*1024));
   729         }
   730 #endif
   731 #ifdef HAVE_SYSCTLBYNAME
   732         if (SDL_SystemRAM <= 0) {
   733 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
   734 #ifdef HW_REALMEM
   735             int mib[2] = {CTL_HW, HW_REALMEM};
   736 #else
   737             /* might only report up to 2 GiB */
   738             int mib[2] = {CTL_HW, HW_PHYSMEM};
   739 #endif /* HW_REALMEM */
   740 #else
   741             int mib[2] = {CTL_HW, HW_MEMSIZE};
   742 #endif /* __FreeBSD__ || __FreeBSD_kernel__ */
   743             Uint64 memsize = 0;
   744             size_t len = sizeof(memsize);
   745             
   746             if (sysctl(mib, 2, &memsize, &len, NULL, 0) == 0) {
   747                 SDL_SystemRAM = (int)(memsize / (1024*1024));
   748             }
   749         }
   750 #endif
   751 #ifdef __WIN32__
   752         if (SDL_SystemRAM <= 0) {
   753             MEMORYSTATUSEX stat;
   754             stat.dwLength = sizeof(stat);
   755             if (GlobalMemoryStatusEx(&stat)) {
   756                 SDL_SystemRAM = (int)(stat.ullTotalPhys / (1024 * 1024));
   757             }
   758         }
   759 #endif
   760     }
   761     return SDL_SystemRAM;
   762 }
   763 
   764 
   765 #ifdef TEST_MAIN
   766 
   767 #include <stdio.h>
   768 
   769 int
   770 main()
   771 {
   772     printf("CPU count: %d\n", SDL_GetCPUCount());
   773     printf("CPU type: %s\n", SDL_GetCPUType());
   774     printf("CPU name: %s\n", SDL_GetCPUName());
   775     printf("CacheLine size: %d\n", SDL_GetCPUCacheLineSize());
   776     printf("RDTSC: %d\n", SDL_HasRDTSC());
   777     printf("Altivec: %d\n", SDL_HasAltiVec());
   778     printf("MMX: %d\n", SDL_HasMMX());
   779     printf("3DNow: %d\n", SDL_Has3DNow());
   780     printf("SSE: %d\n", SDL_HasSSE());
   781     printf("SSE2: %d\n", SDL_HasSSE2());
   782     printf("SSE3: %d\n", SDL_HasSSE3());
   783     printf("SSE4.1: %d\n", SDL_HasSSE41());
   784     printf("SSE4.2: %d\n", SDL_HasSSE42());
   785     printf("AVX: %d\n", SDL_HasAVX());
   786     printf("AVX2: %d\n", SDL_HasAVX2());
   787     printf("RAM: %d MB\n", SDL_GetSystemRAM());
   788     return 0;
   789 }
   790 
   791 #endif /* TEST_MAIN */
   792 
   793 /* vi: set ts=4 sw=4 expandtab: */