src/cpuinfo/SDL_cpuinfo.c
author Sam Lantinga <slouken@libsdl.org>
Sun, 02 Feb 2014 00:33:31 -0800
changeset 8148 56ba41ac64fe
parent 8093 b43765095a6f
child 8149 681eb46b8ac4
permissions -rw-r--r--
Fixed bug 2376 - no SDL_HasAVX

Haneef Mubarak

AVX is the successor to SSE* and is fairly widely available. As such, it really ought to be detectable.

This functionality ought to be trivial to implement, and not having it means being forced to write an ugly workaround to check for AVX (so that normal SSE can be used if AVX is not available).

Here is an example on detecting AVX from SO (it actually shows ways to cehck for all of teh fancy instructions):

http://stackoverflow.com/questions/6121792/how-to-check-if-a-cpu-supports-the-sse3-instruction-set
slouken@739
     1
/*
slouken@5535
     2
  Simple DirectMedia Layer
slouken@6885
     3
  Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
slouken@739
     4
slouken@5535
     5
  This software is provided 'as-is', without any express or implied
slouken@5535
     6
  warranty.  In no event will the authors be held liable for any damages
slouken@5535
     7
  arising from the use of this software.
slouken@739
     8
slouken@5535
     9
  Permission is granted to anyone to use this software for any purpose,
slouken@5535
    10
  including commercial applications, and to alter it and redistribute it
slouken@5535
    11
  freely, subject to the following restrictions:
slouken@739
    12
slouken@5535
    13
  1. The origin of this software must not be misrepresented; you must not
slouken@5535
    14
     claim that you wrote the original software. If you use this software
slouken@5535
    15
     in a product, an acknowledgment in the product documentation would be
slouken@5535
    16
     appreciated but is not required.
slouken@5535
    17
  2. Altered source versions must be plainly marked as such, and must not be
slouken@5535
    18
     misrepresented as being the original software.
slouken@5535
    19
  3. This notice may not be removed or altered from any source distribution.
slouken@739
    20
*/
slouken@8148
    21
#ifdef TEST_MAIN
slouken@8148
    22
#include "SDL_config.h"
slouken@8148
    23
#else
icculus@8093
    24
#include "../SDL_internal.h"
slouken@8148
    25
#endif
slouken@739
    26
slouken@7828
    27
#if defined(__WIN32__)
slouken@7828
    28
#include "../core/windows/SDL_windows.h"
slouken@7828
    29
#endif
slouken@7828
    30
slouken@739
    31
/* CPU feature detection for SDL */
slouken@739
    32
slouken@1361
    33
#include "SDL_cpuinfo.h"
slouken@1361
    34
slouken@3586
    35
#ifdef HAVE_SYSCONF
slouken@3586
    36
#include <unistd.h>
slouken@3586
    37
#endif
slouken@3579
    38
#ifdef HAVE_SYSCTLBYNAME
slouken@3579
    39
#include <sys/types.h>
slouken@3579
    40
#include <sys/sysctl.h>
slouken@3579
    41
#endif
slouken@5389
    42
#if defined(__MACOSX__) && (defined(__ppc__) || defined(__ppc64__))
slouken@5389
    43
#include <sys/sysctl.h>         /* For AltiVec check */
slouken@6363
    44
#elif defined(__OpenBSD__) && defined(__powerpc__)
slouken@6363
    45
#include <sys/param.h>
slouken@6363
    46
#include <sys/sysctl.h> /* For AltiVec check */
slouken@6363
    47
#include <machine/cpu.h>
slouken@5389
    48
#elif SDL_ALTIVEC_BLITTERS && HAVE_SETJMP
slouken@5389
    49
#include <signal.h>
slouken@5389
    50
#include <setjmp.h>
slouken@5389
    51
#endif
slouken@793
    52
slouken@3579
    53
#define CPU_HAS_RDTSC   0x00000001
slouken@5389
    54
#define CPU_HAS_ALTIVEC 0x00000002
slouken@5389
    55
#define CPU_HAS_MMX     0x00000004
slouken@5389
    56
#define CPU_HAS_3DNOW   0x00000008
slouken@5259
    57
#define CPU_HAS_SSE     0x00000010
slouken@5259
    58
#define CPU_HAS_SSE2    0x00000020
slouken@5259
    59
#define CPU_HAS_SSE3    0x00000040
slouken@5389
    60
#define CPU_HAS_SSE41   0x00000100
slouken@5389
    61
#define CPU_HAS_SSE42   0x00000200
slouken@8148
    62
#define CPU_HAS_AVX     0x00000400
slouken@739
    63
slouken@6363
    64
#if SDL_ALTIVEC_BLITTERS && HAVE_SETJMP && !__MACOSX__ && !__OpenBSD__
slouken@5389
    65
/* This is the brute force way of detecting instruction sets...
slouken@5389
    66
   the idea is borrowed from the libmpeg2 library - thanks!
slouken@5389
    67
 */
slouken@5389
    68
static jmp_buf jmpbuf;
slouken@5389
    69
static void
slouken@5389
    70
illegal_instruction(int sig)
slouken@5389
    71
{
slouken@5389
    72
    longjmp(jmpbuf, 1);
slouken@5389
    73
}
slouken@5389
    74
#endif /* HAVE_SETJMP */
slouken@793
    75
slouken@7860
    76
static SDL_INLINE int
slouken@1895
    77
CPU_haveCPUID(void)
slouken@745
    78
{
slouken@1895
    79
    int has_CPUID = 0;
slouken@1895
    80
/* *INDENT-OFF* */
slouken@745
    81
#if defined(__GNUC__) && defined(i386)
slouken@3579
    82
    __asm__ (
slouken@745
    83
"        pushfl                      # Get original EFLAGS             \n"
slouken@745
    84
"        popl    %%eax                                                 \n"
slouken@745
    85
"        movl    %%eax,%%ecx                                           \n"
slouken@745
    86
"        xorl    $0x200000,%%eax     # Flip ID bit in EFLAGS           \n"
slouken@745
    87
"        pushl   %%eax               # Save new EFLAGS value on stack  \n"
slouken@745
    88
"        popfl                       # Replace current EFLAGS value    \n"
slouken@745
    89
"        pushfl                      # Get new EFLAGS                  \n"
slouken@745
    90
"        popl    %%eax               # Store new EFLAGS in EAX         \n"
slouken@745
    91
"        xorl    %%ecx,%%eax         # Can not toggle ID bit,          \n"
slouken@745
    92
"        jz      1f                  # Processor=80486                 \n"
slouken@745
    93
"        movl    $1,%0               # We have CPUID support           \n"
slouken@745
    94
"1:                                                                    \n"
slouken@3579
    95
    : "=m" (has_CPUID)
slouken@3579
    96
    :
slouken@3579
    97
    : "%eax", "%ecx"
slouken@3579
    98
    );
slouken@881
    99
#elif defined(__GNUC__) && defined(__x86_64__)
slouken@881
   100
/* Technically, if this is being compiled under __x86_64__ then it has 
slouken@881
   101
CPUid by definition.  But it's nice to be able to prove it.  :)      */
slouken@3579
   102
    __asm__ (
slouken@881
   103
"        pushfq                      # Get original EFLAGS             \n"
slouken@881
   104
"        popq    %%rax                                                 \n"
slouken@881
   105
"        movq    %%rax,%%rcx                                           \n"
slouken@881
   106
"        xorl    $0x200000,%%eax     # Flip ID bit in EFLAGS           \n"
slouken@881
   107
"        pushq   %%rax               # Save new EFLAGS value on stack  \n"
slouken@881
   108
"        popfq                       # Replace current EFLAGS value    \n"
slouken@881
   109
"        pushfq                      # Get new EFLAGS                  \n"
slouken@881
   110
"        popq    %%rax               # Store new EFLAGS in EAX         \n"
slouken@881
   111
"        xorl    %%ecx,%%eax         # Can not toggle ID bit,          \n"
slouken@881
   112
"        jz      1f                  # Processor=80486                 \n"
slouken@881
   113
"        movl    $1,%0               # We have CPUID support           \n"
slouken@881
   114
"1:                                                                    \n"
slouken@3579
   115
    : "=m" (has_CPUID)
slouken@3579
   116
    :
slouken@3579
   117
    : "%rax", "%rcx"
slouken@3579
   118
    );
slouken@1442
   119
#elif (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
slouken@3579
   120
    __asm {
slouken@745
   121
        pushfd                      ; Get original EFLAGS
slouken@745
   122
        pop     eax
slouken@745
   123
        mov     ecx, eax
slouken@745
   124
        xor     eax, 200000h        ; Flip ID bit in EFLAGS
slouken@745
   125
        push    eax                 ; Save new EFLAGS value on stack
slouken@745
   126
        popfd                       ; Replace current EFLAGS value
slouken@745
   127
        pushfd                      ; Get new EFLAGS
slouken@745
   128
        pop     eax                 ; Store new EFLAGS in EAX
slouken@745
   129
        xor     eax, ecx            ; Can not toggle ID bit,
slouken@745
   130
        jz      done                ; Processor=80486
slouken@745
   131
        mov     has_CPUID,1         ; We have CPUID support
slouken@745
   132
done:
slouken@3579
   133
    }
slouken@1864
   134
#elif defined(__sun) && defined(__i386)
slouken@3579
   135
    __asm (
icculus@1229
   136
"       pushfl                 \n"
slouken@3584
   137
"       popl    %eax           \n"
slouken@3584
   138
"       movl    %eax,%ecx      \n"
slouken@3584
   139
"       xorl    $0x200000,%eax \n"
slouken@3584
   140
"       pushl   %eax           \n"
slouken@3584
   141
"       popfl                  \n"
slouken@3584
   142
"       pushfl                 \n"
slouken@3584
   143
"       popl    %eax           \n"
slouken@3584
   144
"       xorl    %ecx,%eax      \n"
slouken@3584
   145
"       jz      1f             \n"
slouken@3584
   146
"       movl    $1,-8(%ebp)    \n"
icculus@1229
   147
"1:                            \n"
slouken@3579
   148
    );
icculus@1229
   149
#elif defined(__sun) && defined(__amd64)
slouken@3579
   150
    __asm (
icculus@1229
   151
"       pushfq                 \n"
icculus@1229
   152
"       popq    %rax           \n"
icculus@1229
   153
"       movq    %rax,%rcx      \n"
icculus@1229
   154
"       xorl    $0x200000,%eax \n"
icculus@1229
   155
"       pushq   %rax           \n"
icculus@1229
   156
"       popfq                  \n"
icculus@1229
   157
"       pushfq                 \n"
icculus@1229
   158
"       popq    %rax           \n"
icculus@1229
   159
"       xorl    %ecx,%eax      \n"
icculus@1229
   160
"       jz      1f             \n"
icculus@1229
   161
"       movl    $1,-8(%rbp)    \n"
icculus@1229
   162
"1:                            \n"
slouken@3579
   163
    );
slouken@745
   164
#endif
slouken@1895
   165
/* *INDENT-ON* */
slouken@1895
   166
    return has_CPUID;
slouken@745
   167
}
slouken@745
   168
slouken@3587
   169
#if defined(__GNUC__) && defined(i386)
slouken@3580
   170
#define cpuid(func, a, b, c, d) \
slouken@3584
   171
    __asm__ __volatile__ ( \
slouken@3584
   172
"        pushl %%ebx        \n" \
slouken@3584
   173
"        cpuid              \n" \
slouken@3584
   174
"        movl %%ebx, %%esi  \n" \
slouken@3584
   175
"        popl %%ebx         \n" : \
slouken@3584
   176
            "=a" (a), "=S" (b), "=c" (c), "=d" (d) : "a" (func))
slouken@3587
   177
#elif defined(__GNUC__) && defined(__x86_64__)
slouken@3587
   178
#define cpuid(func, a, b, c, d) \
slouken@3587
   179
    __asm__ __volatile__ ( \
slouken@3587
   180
"        pushq %%rbx        \n" \
slouken@3587
   181
"        cpuid              \n" \
slouken@3587
   182
"        movq %%rbx, %%rsi  \n" \
slouken@3587
   183
"        popq %%rbx         \n" : \
slouken@3587
   184
            "=a" (a), "=S" (b), "=c" (c), "=d" (d) : "a" (func))
slouken@3579
   185
#elif (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
slouken@3580
   186
#define cpuid(func, a, b, c, d) \
slouken@3580
   187
    __asm { \
slouken@3580
   188
        __asm mov eax, func \
slouken@3580
   189
        __asm cpuid \
slouken@3580
   190
        __asm mov a, eax \
slouken@3580
   191
        __asm mov b, ebx \
slouken@3580
   192
        __asm mov c, ecx \
slouken@3580
   193
        __asm mov d, edx \
slouken@3579
   194
    }
slouken@3579
   195
#else
slouken@3580
   196
#define cpuid(func, a, b, c, d) \
slouken@3580
   197
    a = b = c = d = 0
slouken@3579
   198
#endif
slouken@3579
   199
slouken@7860
   200
static SDL_INLINE int
slouken@1895
   201
CPU_getCPUIDFeatures(void)
slouken@745
   202
{
slouken@1895
   203
    int features = 0;
slouken@3580
   204
    int a, b, c, d;
slouken@3579
   205
slouken@3580
   206
    cpuid(0, a, b, c, d);
slouken@3580
   207
    if (a >= 1) {
slouken@3580
   208
        cpuid(1, a, b, c, d);
slouken@3580
   209
        features = d;
slouken@3579
   210
    }
slouken@1895
   211
    return features;
slouken@745
   212
}
slouken@745
   213
slouken@7860
   214
static SDL_INLINE int
slouken@1895
   215
CPU_haveRDTSC(void)
slouken@745
   216
{
slouken@1895
   217
    if (CPU_haveCPUID()) {
slouken@1895
   218
        return (CPU_getCPUIDFeatures() & 0x00000010);
slouken@1895
   219
    }
slouken@1895
   220
    return 0;
slouken@745
   221
}
slouken@745
   222
slouken@7860
   223
static SDL_INLINE int
slouken@5389
   224
CPU_haveAltiVec(void)
slouken@5389
   225
{
slouken@5389
   226
    volatile int altivec = 0;
slouken@6363
   227
#if (defined(__MACOSX__) && (defined(__ppc__) || defined(__ppc64__))) || (defined(__OpenBSD__) && defined(__powerpc__))
slouken@6363
   228
#ifdef __OpenBSD__
slouken@6363
   229
    int selectors[2] = { CTL_MACHDEP, CPU_ALTIVEC };
slouken@6363
   230
#else
slouken@5389
   231
    int selectors[2] = { CTL_HW, HW_VECTORUNIT };
slouken@6363
   232
#endif
slouken@5389
   233
    int hasVectorUnit = 0;
slouken@5389
   234
    size_t length = sizeof(hasVectorUnit);
slouken@5389
   235
    int error = sysctl(selectors, 2, &hasVectorUnit, &length, NULL, 0);
slouken@5389
   236
    if (0 == error)
slouken@5389
   237
        altivec = (hasVectorUnit != 0);
slouken@5389
   238
#elif SDL_ALTIVEC_BLITTERS && HAVE_SETJMP
slouken@5389
   239
    void (*handler) (int sig);
slouken@5389
   240
    handler = signal(SIGILL, illegal_instruction);
slouken@5389
   241
    if (setjmp(jmpbuf) == 0) {
slouken@5389
   242
        asm volatile ("mtspr 256, %0\n\t" "vand %%v0, %%v0, %%v0"::"r" (-1));
slouken@5389
   243
        altivec = 1;
slouken@5389
   244
    }
slouken@5389
   245
    signal(SIGILL, handler);
slouken@5389
   246
#endif
slouken@5389
   247
    return altivec;
slouken@5389
   248
}
slouken@5389
   249
slouken@7860
   250
static SDL_INLINE int
slouken@1895
   251
CPU_haveMMX(void)
slouken@745
   252
{
slouken@1895
   253
    if (CPU_haveCPUID()) {
slouken@1895
   254
        return (CPU_getCPUIDFeatures() & 0x00800000);
slouken@1895
   255
    }
slouken@1895
   256
    return 0;
slouken@745
   257
}
slouken@745
   258
slouken@7860
   259
static SDL_INLINE int
slouken@5389
   260
CPU_have3DNow(void)
slouken@5389
   261
{
slouken@5389
   262
    if (CPU_haveCPUID()) {
slouken@5389
   263
        int a, b, c, d;
slouken@5389
   264
slouken@5389
   265
        cpuid(0x80000000, a, b, c, d);
slouken@5389
   266
        if (a >= 0x80000001) {
slouken@5389
   267
            cpuid(0x80000001, a, b, c, d);
slouken@5389
   268
            return (d & 0x80000000);
slouken@5389
   269
        }
slouken@5389
   270
    }
slouken@5389
   271
    return 0;
slouken@5389
   272
}
slouken@5389
   273
slouken@7860
   274
static SDL_INLINE int
slouken@1895
   275
CPU_haveSSE(void)
slouken@745
   276
{
slouken@1895
   277
    if (CPU_haveCPUID()) {
slouken@1895
   278
        return (CPU_getCPUIDFeatures() & 0x02000000);
slouken@1895
   279
    }
slouken@1895
   280
    return 0;
slouken@745
   281
}
slouken@739
   282
slouken@7860
   283
static SDL_INLINE int
slouken@1895
   284
CPU_haveSSE2(void)
slouken@785
   285
{
slouken@1895
   286
    if (CPU_haveCPUID()) {
slouken@1895
   287
        return (CPU_getCPUIDFeatures() & 0x04000000);
slouken@1895
   288
    }
slouken@1895
   289
    return 0;
slouken@785
   290
}
slouken@785
   291
slouken@7860
   292
static SDL_INLINE int
slouken@5259
   293
CPU_haveSSE3(void)
slouken@778
   294
{
slouken@5259
   295
    if (CPU_haveCPUID()) {
slouken@5259
   296
        int a, b, c, d;
slouken@5259
   297
slouken@5259
   298
        cpuid(0, a, b, c, d);
slouken@5259
   299
        if (a >= 1) {
slouken@5259
   300
            cpuid(1, a, b, c, d);
slouken@5259
   301
            return (c & 0x00000001);
slouken@5259
   302
        }
slouken@1895
   303
    }
slouken@5259
   304
    return 0;
slouken@5259
   305
}
slouken@5259
   306
slouken@7860
   307
static SDL_INLINE int
slouken@5263
   308
CPU_haveSSE41(void)
slouken@5259
   309
{
slouken@5259
   310
    if (CPU_haveCPUID()) {
slouken@5259
   311
        int a, b, c, d;
slouken@5259
   312
slouken@5263
   313
        cpuid(1, a, b, c, d);
slouken@5259
   314
        if (a >= 1) {
slouken@5259
   315
            cpuid(1, a, b, c, d);
slouken@5263
   316
            return (c & 0x00080000);
slouken@5263
   317
        }
slouken@5263
   318
    }
slouken@5263
   319
    return 0;
slouken@5263
   320
}
slouken@5263
   321
slouken@7860
   322
static SDL_INLINE int
slouken@5263
   323
CPU_haveSSE42(void)
slouken@5263
   324
{
slouken@5263
   325
    if (CPU_haveCPUID()) {
slouken@5263
   326
        int a, b, c, d;
slouken@5263
   327
slouken@5263
   328
        cpuid(1, a, b, c, d);
slouken@5263
   329
        if (a >= 1) {
slouken@5263
   330
            cpuid(1, a, b, c, d);
slouken@5263
   331
            return (c & 0x00100000);
slouken@5259
   332
        }
slouken@5259
   333
    }
slouken@5259
   334
    return 0;
slouken@778
   335
}
slouken@778
   336
slouken@8148
   337
static SDL_INLINE int
slouken@8148
   338
CPU_haveAVX(void)
slouken@8148
   339
{
slouken@8148
   340
    if (CPU_haveCPUID()) {
slouken@8148
   341
        int a, b, c, d;
slouken@8148
   342
slouken@8148
   343
        cpuid(1, a, b, c, d);
slouken@8148
   344
        if (a >= 1) {
slouken@8148
   345
            cpuid(1, a, b, c, d);
slouken@8148
   346
            return (c & 0x10000000);
slouken@8148
   347
        }
slouken@8148
   348
    }
slouken@8148
   349
    return 0;
slouken@8148
   350
}
slouken@8148
   351
slouken@3579
   352
static int SDL_CPUCount = 0;
slouken@3579
   353
slouken@3579
   354
int
slouken@5120
   355
SDL_GetCPUCount(void)
slouken@3579
   356
{
slouken@3579
   357
    if (!SDL_CPUCount) {
slouken@3606
   358
#if defined(HAVE_SYSCONF) && defined(_SC_NPROCESSORS_ONLN)
slouken@3586
   359
        if (SDL_CPUCount <= 0) {
slouken@3586
   360
            SDL_CPUCount = (int)sysconf(_SC_NPROCESSORS_ONLN);
slouken@3586
   361
        }
slouken@3586
   362
#endif
slouken@3579
   363
#ifdef HAVE_SYSCTLBYNAME
slouken@3586
   364
        if (SDL_CPUCount <= 0) {
slouken@3580
   365
            size_t size = sizeof(SDL_CPUCount);
slouken@3580
   366
            sysctlbyname("hw.ncpu", &SDL_CPUCount, &size, NULL, 0);
slouken@3580
   367
        }
slouken@3580
   368
#endif
slouken@5086
   369
#ifdef __WIN32__
slouken@3586
   370
        if (SDL_CPUCount <= 0) {
slouken@3580
   371
            SYSTEM_INFO info;
slouken@3580
   372
            GetSystemInfo(&info);
slouken@3580
   373
            SDL_CPUCount = info.dwNumberOfProcessors;
slouken@3580
   374
        }
slouken@3579
   375
#endif
slouken@3579
   376
        /* There has to be at least 1, right? :) */
slouken@3586
   377
        if (SDL_CPUCount <= 0) {
slouken@3579
   378
            SDL_CPUCount = 1;
slouken@3579
   379
        }
slouken@3579
   380
    }
slouken@3579
   381
    return SDL_CPUCount;
slouken@3579
   382
}
slouken@3579
   383
slouken@3579
   384
/* Oh, such a sweet sweet trick, just not very useful. :) */
slouken@4472
   385
static const char *
slouken@5120
   386
SDL_GetCPUType(void)
slouken@3579
   387
{
slouken@5115
   388
    static char SDL_CPUType[13];
slouken@3579
   389
slouken@3579
   390
    if (!SDL_CPUType[0]) {
slouken@3579
   391
        int i = 0;
slouken@3580
   392
        int a, b, c, d;
slouken@3579
   393
slouken@3579
   394
        if (CPU_haveCPUID()) {
slouken@5115
   395
            cpuid(0x00000000, a, b, c, d);
slouken@5115
   396
            SDL_CPUType[i++] = (char)(b & 0xff); b >>= 8;
slouken@5115
   397
            SDL_CPUType[i++] = (char)(b & 0xff); b >>= 8;
slouken@5115
   398
            SDL_CPUType[i++] = (char)(b & 0xff); b >>= 8;
slouken@5115
   399
            SDL_CPUType[i++] = (char)(b & 0xff); b >>= 8;
slouken@5115
   400
            SDL_CPUType[i++] = (char)(d & 0xff); d >>= 8;
slouken@5115
   401
            SDL_CPUType[i++] = (char)(d & 0xff); d >>= 8;
slouken@5115
   402
            SDL_CPUType[i++] = (char)(d & 0xff); d >>= 8;
slouken@5115
   403
            SDL_CPUType[i++] = (char)(d & 0xff); d >>= 8;
slouken@5115
   404
            SDL_CPUType[i++] = (char)(c & 0xff); c >>= 8;
slouken@5115
   405
            SDL_CPUType[i++] = (char)(c & 0xff); c >>= 8;
slouken@5115
   406
            SDL_CPUType[i++] = (char)(c & 0xff); c >>= 8;
slouken@5115
   407
            SDL_CPUType[i++] = (char)(c & 0xff); c >>= 8;
slouken@5115
   408
        }
slouken@5115
   409
        if (!SDL_CPUType[0]) {
slouken@5115
   410
            SDL_strlcpy(SDL_CPUType, "Unknown", sizeof(SDL_CPUType));
slouken@5115
   411
        }
slouken@5115
   412
    }
slouken@5115
   413
    return SDL_CPUType;
slouken@5115
   414
}
slouken@5115
   415
icculus@5981
   416
icculus@5981
   417
#ifdef TEST_MAIN  /* !!! FIXME: only used for test at the moment. */
slouken@5115
   418
static const char *
slouken@5120
   419
SDL_GetCPUName(void)
slouken@5115
   420
{
slouken@5115
   421
    static char SDL_CPUName[48];
slouken@5115
   422
slouken@5115
   423
    if (!SDL_CPUName[0]) {
slouken@5115
   424
        int i = 0;
slouken@5115
   425
        int a, b, c, d;
slouken@5115
   426
slouken@5115
   427
        if (CPU_haveCPUID()) {
slouken@3580
   428
            cpuid(0x80000000, a, b, c, d);
slouken@3580
   429
            if (a >= 0x80000004) {
slouken@3580
   430
                cpuid(0x80000002, a, b, c, d);
slouken@5115
   431
                SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
slouken@5115
   432
                SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
slouken@5115
   433
                SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
slouken@5115
   434
                SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
slouken@5115
   435
                SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
slouken@5115
   436
                SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
slouken@5115
   437
                SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
slouken@5115
   438
                SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
slouken@5115
   439
                SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
slouken@5115
   440
                SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
slouken@5115
   441
                SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
slouken@5115
   442
                SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
slouken@5115
   443
                SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
slouken@5115
   444
                SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
slouken@5115
   445
                SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
slouken@5115
   446
                SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
slouken@3580
   447
                cpuid(0x80000003, a, b, c, d);
slouken@5115
   448
                SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
slouken@5115
   449
                SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
slouken@5115
   450
                SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
slouken@5115
   451
                SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
slouken@5115
   452
                SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
slouken@5115
   453
                SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
slouken@5115
   454
                SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
slouken@5115
   455
                SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
slouken@5115
   456
                SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
slouken@5115
   457
                SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
slouken@5115
   458
                SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
slouken@5115
   459
                SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
slouken@5115
   460
                SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
slouken@5115
   461
                SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
slouken@5115
   462
                SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
slouken@5115
   463
                SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
slouken@3580
   464
                cpuid(0x80000004, a, b, c, d);
slouken@5115
   465
                SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
slouken@5115
   466
                SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
slouken@5115
   467
                SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
slouken@5115
   468
                SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
slouken@5115
   469
                SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
slouken@5115
   470
                SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
slouken@5115
   471
                SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
slouken@5115
   472
                SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
slouken@5115
   473
                SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
slouken@5115
   474
                SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
slouken@5115
   475
                SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
slouken@5115
   476
                SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
slouken@5115
   477
                SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
slouken@5115
   478
                SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
slouken@5115
   479
                SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
slouken@5115
   480
                SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
slouken@3579
   481
            }
slouken@3579
   482
        }
slouken@5115
   483
        if (!SDL_CPUName[0]) {
slouken@5115
   484
            SDL_strlcpy(SDL_CPUName, "Unknown", sizeof(SDL_CPUName));
slouken@3579
   485
        }
slouken@3579
   486
    }
slouken@5115
   487
    return SDL_CPUName;
slouken@5115
   488
}
icculus@5981
   489
#endif
slouken@5115
   490
slouken@5120
   491
int
slouken@5120
   492
SDL_GetCPUCacheLineSize(void)
slouken@5115
   493
{
slouken@5115
   494
    const char *cpuType = SDL_GetCPUType();
slouken@5115
   495
slouken@5115
   496
    if (SDL_strcmp(cpuType, "GenuineIntel") == 0) {
slouken@5115
   497
        int a, b, c, d;
slouken@5115
   498
slouken@5115
   499
        cpuid(0x00000001, a, b, c, d);
slouken@5115
   500
        return (((b >> 8) & 0xff) * 8);
slouken@5115
   501
    } else if (SDL_strcmp(cpuType, "AuthenticAMD") == 0) {
slouken@5115
   502
        int a, b, c, d;
slouken@5115
   503
slouken@5115
   504
        cpuid(0x80000005, a, b, c, d);
slouken@5115
   505
        return (c & 0xff);
slouken@5115
   506
    } else {
slouken@5115
   507
        /* Just make a guess here... */
slouken@5115
   508
        return SDL_CACHELINE_SIZE;
slouken@5115
   509
    }
slouken@3579
   510
}
slouken@3579
   511
slouken@739
   512
static Uint32 SDL_CPUFeatures = 0xFFFFFFFF;
slouken@739
   513
slouken@1895
   514
static Uint32
slouken@1895
   515
SDL_GetCPUFeatures(void)
slouken@739
   516
{
slouken@1895
   517
    if (SDL_CPUFeatures == 0xFFFFFFFF) {
slouken@1895
   518
        SDL_CPUFeatures = 0;
slouken@1895
   519
        if (CPU_haveRDTSC()) {
slouken@1895
   520
            SDL_CPUFeatures |= CPU_HAS_RDTSC;
slouken@1895
   521
        }
slouken@5389
   522
        if (CPU_haveAltiVec()) {
slouken@5389
   523
            SDL_CPUFeatures |= CPU_HAS_ALTIVEC;
slouken@5389
   524
        }
slouken@1895
   525
        if (CPU_haveMMX()) {
slouken@1895
   526
            SDL_CPUFeatures |= CPU_HAS_MMX;
slouken@1895
   527
        }
slouken@5389
   528
        if (CPU_have3DNow()) {
slouken@5389
   529
            SDL_CPUFeatures |= CPU_HAS_3DNOW;
slouken@5389
   530
        }
slouken@1895
   531
        if (CPU_haveSSE()) {
slouken@1895
   532
            SDL_CPUFeatures |= CPU_HAS_SSE;
slouken@1895
   533
        }
slouken@1895
   534
        if (CPU_haveSSE2()) {
slouken@1895
   535
            SDL_CPUFeatures |= CPU_HAS_SSE2;
slouken@1895
   536
        }
slouken@5259
   537
        if (CPU_haveSSE3()) {
slouken@5259
   538
            SDL_CPUFeatures |= CPU_HAS_SSE3;
slouken@5259
   539
        }
slouken@5263
   540
        if (CPU_haveSSE41()) {
slouken@5263
   541
            SDL_CPUFeatures |= CPU_HAS_SSE41;
slouken@5263
   542
        }
slouken@5263
   543
        if (CPU_haveSSE42()) {
slouken@5263
   544
            SDL_CPUFeatures |= CPU_HAS_SSE42;
slouken@1895
   545
        }
slouken@8148
   546
        if (CPU_haveAVX()) {
slouken@8148
   547
            SDL_CPUFeatures |= CPU_HAS_AVX;
slouken@8148
   548
        }
slouken@1895
   549
    }
slouken@1895
   550
    return SDL_CPUFeatures;
slouken@739
   551
}
slouken@739
   552
slouken@1895
   553
SDL_bool
slouken@1895
   554
SDL_HasRDTSC(void)
slouken@745
   555
{
slouken@1895
   556
    if (SDL_GetCPUFeatures() & CPU_HAS_RDTSC) {
slouken@1895
   557
        return SDL_TRUE;
slouken@1895
   558
    }
slouken@1895
   559
    return SDL_FALSE;
slouken@745
   560
}
slouken@745
   561
slouken@1895
   562
SDL_bool
slouken@5389
   563
SDL_HasAltiVec(void)
slouken@5389
   564
{
slouken@5389
   565
    if (SDL_GetCPUFeatures() & CPU_HAS_ALTIVEC) {
slouken@5389
   566
        return SDL_TRUE;
slouken@5389
   567
    }
slouken@5389
   568
    return SDL_FALSE;
slouken@5389
   569
}
slouken@5389
   570
slouken@5389
   571
SDL_bool
slouken@1895
   572
SDL_HasMMX(void)
slouken@739
   573
{
slouken@1895
   574
    if (SDL_GetCPUFeatures() & CPU_HAS_MMX) {
slouken@1895
   575
        return SDL_TRUE;
slouken@1895
   576
    }
slouken@1895
   577
    return SDL_FALSE;
slouken@739
   578
}
slouken@739
   579
slouken@1895
   580
SDL_bool
slouken@5389
   581
SDL_Has3DNow(void)
slouken@5389
   582
{
slouken@5389
   583
    if (SDL_GetCPUFeatures() & CPU_HAS_3DNOW) {
slouken@5389
   584
        return SDL_TRUE;
slouken@5389
   585
    }
slouken@5389
   586
    return SDL_FALSE;
slouken@5389
   587
}
slouken@5389
   588
slouken@5389
   589
SDL_bool
slouken@1895
   590
SDL_HasSSE(void)
slouken@739
   591
{
slouken@1895
   592
    if (SDL_GetCPUFeatures() & CPU_HAS_SSE) {
slouken@1895
   593
        return SDL_TRUE;
slouken@1895
   594
    }
slouken@1895
   595
    return SDL_FALSE;
slouken@739
   596
}
slouken@739
   597
slouken@1895
   598
SDL_bool
slouken@1895
   599
SDL_HasSSE2(void)
slouken@804
   600
{
slouken@1895
   601
    if (SDL_GetCPUFeatures() & CPU_HAS_SSE2) {
slouken@1895
   602
        return SDL_TRUE;
slouken@1895
   603
    }
slouken@1895
   604
    return SDL_FALSE;
slouken@804
   605
}
slouken@804
   606
slouken@1895
   607
SDL_bool
slouken@5259
   608
SDL_HasSSE3(void)
slouken@778
   609
{
slouken@5259
   610
    if (SDL_GetCPUFeatures() & CPU_HAS_SSE3) {
slouken@5259
   611
        return SDL_TRUE;
slouken@5259
   612
    }
slouken@5259
   613
    return SDL_FALSE;
slouken@5259
   614
}
slouken@5259
   615
slouken@5259
   616
SDL_bool
slouken@5263
   617
SDL_HasSSE41(void)
slouken@5259
   618
{
slouken@5263
   619
    if (SDL_GetCPUFeatures() & CPU_HAS_SSE41) {
slouken@5263
   620
        return SDL_TRUE;
slouken@5263
   621
    }
slouken@5263
   622
    return SDL_FALSE;
slouken@5263
   623
}
slouken@5263
   624
slouken@5263
   625
SDL_bool
slouken@5263
   626
SDL_HasSSE42(void)
slouken@5263
   627
{
slouken@5263
   628
    if (SDL_GetCPUFeatures() & CPU_HAS_SSE42) {
slouken@1895
   629
        return SDL_TRUE;
slouken@1895
   630
    }
slouken@1895
   631
    return SDL_FALSE;
slouken@778
   632
}
slouken@778
   633
slouken@8148
   634
SDL_bool
slouken@8148
   635
SDL_HasAVX(void)
slouken@8148
   636
{
slouken@8148
   637
    if (SDL_GetCPUFeatures() & CPU_HAS_AVX) {
slouken@8148
   638
        return SDL_TRUE;
slouken@8148
   639
    }
slouken@8148
   640
    return SDL_FALSE;
slouken@8148
   641
}
slouken@8148
   642
slouken@7821
   643
static int SDL_SystemRAM = 0;
slouken@7821
   644
slouken@7821
   645
int
slouken@7821
   646
SDL_GetSystemRAM(void)
slouken@7821
   647
{
slouken@7821
   648
    if (!SDL_SystemRAM) {
slouken@7821
   649
#if defined(HAVE_SYSCONF) && defined(_SC_PHYS_PAGES) && defined(_SC_PAGESIZE)
slouken@7821
   650
        if (SDL_SystemRAM <= 0) {
slouken@7821
   651
            SDL_SystemRAM = (int)((Sint64)sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGESIZE) / (1024*1024));
slouken@7821
   652
        }
slouken@7821
   653
#endif
slouken@7821
   654
#ifdef HAVE_SYSCTLBYNAME
slouken@7821
   655
        if (SDL_SystemRAM <= 0) {
slouken@7826
   656
#ifdef __FreeBSD__
slouken@7826
   657
#ifdef HW_REALMEM
slouken@7826
   658
            int mib[2] = {CTL_HW, HW_REALMEM};
slouken@7826
   659
#else
slouken@7826
   660
            /* might only report up to 2 GiB */
slouken@7826
   661
            int mib[2] = {CTL_HW, HW_PHYSMEM};
slouken@7826
   662
#endif /* HW_REALMEM */
slouken@7826
   663
#else
slouken@7821
   664
            int mib[2] = {CTL_HW, HW_MEMSIZE};
slouken@7826
   665
#endif /* __FreeBSD__ */
slouken@7823
   666
            Uint64 memsize = 0;
slouken@7821
   667
            size_t len = sizeof(memsize);
slouken@7821
   668
            
slouken@7821
   669
            if (sysctl(mib, 2, &memsize, &len, NULL, 0) == 0) {
slouken@7821
   670
                SDL_SystemRAM = (int)(memsize / (1024*1024));
slouken@7821
   671
            }
slouken@7821
   672
        }
slouken@7821
   673
#endif
slouken@7821
   674
#ifdef __WIN32__
slouken@7821
   675
        if (SDL_SystemRAM <= 0) {
slouken@7821
   676
            MEMORYSTATUSEX stat;
icculus@7889
   677
            stat.dwLength = sizeof(stat);
slouken@7821
   678
            if (GlobalMemoryStatusEx(&stat)) {
slouken@7821
   679
                SDL_SystemRAM = (int)(stat.ullTotalPhys / (1024 * 1024));
slouken@7821
   680
            }
slouken@7821
   681
        }
slouken@7821
   682
#endif
slouken@7821
   683
    }
slouken@7821
   684
    return SDL_SystemRAM;
slouken@7821
   685
}
slouken@7821
   686
slouken@7821
   687
slouken@739
   688
#ifdef TEST_MAIN
slouken@739
   689
slouken@739
   690
#include <stdio.h>
slouken@739
   691
slouken@1895
   692
int
slouken@1895
   693
main()
slouken@739
   694
{
slouken@3579
   695
    printf("CPU count: %d\n", SDL_GetCPUCount());
slouken@5115
   696
    printf("CPU type: %s\n", SDL_GetCPUType());
slouken@5115
   697
    printf("CPU name: %s\n", SDL_GetCPUName());
slouken@5115
   698
    printf("CacheLine size: %d\n", SDL_GetCPUCacheLineSize());
slouken@1895
   699
    printf("RDTSC: %d\n", SDL_HasRDTSC());
slouken@5389
   700
    printf("Altivec: %d\n", SDL_HasAltiVec());
slouken@1895
   701
    printf("MMX: %d\n", SDL_HasMMX());
slouken@5389
   702
    printf("3DNow: %d\n", SDL_Has3DNow());
slouken@1895
   703
    printf("SSE: %d\n", SDL_HasSSE());
slouken@1895
   704
    printf("SSE2: %d\n", SDL_HasSSE2());
slouken@5259
   705
    printf("SSE3: %d\n", SDL_HasSSE3());
slouken@5263
   706
    printf("SSE4.1: %d\n", SDL_HasSSE41());
slouken@5263
   707
    printf("SSE4.2: %d\n", SDL_HasSSE42());
slouken@8148
   708
    printf("AVX: %d\n", SDL_HasAVX());
slouken@7821
   709
    printf("RAM: %d MB\n", SDL_GetSystemRAM());
slouken@1895
   710
    return 0;
slouken@739
   711
}
slouken@739
   712
slouken@739
   713
#endif /* TEST_MAIN */
slouken@1895
   714
slouken@1895
   715
/* vi: set ts=4 sw=4 expandtab: */