1 /*
2   Simple DirectMedia Layer
3   Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
4 
5   This software is provided 'as-is', without any express or implied
6   warranty.  In no event will the authors be held liable for any damages
7   arising from the use of this software.
8 
9   Permission is granted to anyone to use this software for any purpose,
10   including commercial applications, and to alter it and redistribute it
11   freely, subject to the following restrictions:
12 
13   1. The origin of this software must not be misrepresented; you must not
14      claim that you wrote the original software. If you use this software
15      in a product, an acknowledgment in the product documentation would be
16      appreciated but is not required.
17   2. Altered source versions must be plainly marked as such, and must not be
18      misrepresented as being the original software.
19   3. This notice may not be removed or altered from any source distribution.
20 */
21 #ifdef TEST_MAIN
22 #include "SDL_config.h"
23 #else
24 #include "../SDL_internal.h"
25 #endif
26 
27 #if defined(__WIN32__)
28 #include "../core/windows/SDL_windows.h"
29 #endif
30 
31 /* CPU feature detection for SDL */
32 
33 #include "SDL_cpuinfo.h"
34 
35 #ifdef HAVE_SYSCONF
36 #include <unistd.h>
37 #endif
38 #ifdef HAVE_SYSCTLBYNAME
39 #include <sys/types.h>
40 #include <sys/sysctl.h>
41 #endif
42 #if defined(__MACOSX__) && (defined(__ppc__) || defined(__ppc64__))
43 #include <sys/sysctl.h>         /* For AltiVec check */
44 #elif defined(__OpenBSD__) && defined(__powerpc__)
45 #include <sys/param.h>
46 #include <sys/sysctl.h> /* For AltiVec check */
47 #include <machine/cpu.h>
48 #elif SDL_ALTIVEC_BLITTERS && HAVE_SETJMP
49 #include <signal.h>
50 #include <setjmp.h>
51 #endif
52 
53 #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
illegal_instruction(int sig)71 illegal_instruction(int sig)
72 {
73     longjmp(jmpbuf, 1);
74 }
75 #endif /* HAVE_SETJMP */
76 
77 static int
CPU_haveCPUID(void)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
CPU_getCPUIDFeatures(void)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
CPU_OSSavesYMM(void)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
CPU_haveRDTSC(void)265 CPU_haveRDTSC(void)
266 {
267     if (CPU_haveCPUID()) {
268         return (CPU_getCPUIDFeatures() & 0x00000010);
269     }
270     return 0;
271 }
272 
273 static int
CPU_haveAltiVec(void)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
CPU_haveMMX(void)303 CPU_haveMMX(void)
304 {
305     if (CPU_haveCPUID()) {
306         return (CPU_getCPUIDFeatures() & 0x00800000);
307     }
308     return 0;
309 }
310 
311 static int
CPU_have3DNow(void)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
CPU_haveSSE(void)327 CPU_haveSSE(void)
328 {
329     if (CPU_haveCPUID()) {
330         return (CPU_getCPUIDFeatures() & 0x02000000);
331     }
332     return 0;
333 }
334 
335 static int
CPU_haveSSE2(void)336 CPU_haveSSE2(void)
337 {
338     if (CPU_haveCPUID()) {
339         return (CPU_getCPUIDFeatures() & 0x04000000);
340     }
341     return 0;
342 }
343 
344 static int
CPU_haveSSE3(void)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
CPU_haveSSE41(void)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
CPU_haveSSE42(void)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
CPU_haveAVX(void)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
CPU_haveAVX2(void)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
SDL_GetCPUCount(void)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 *
SDL_GetCPUType(void)455 SDL_GetCPUType(void)
456 {
457     static char SDL_CPUType[13];
458 
459     if (!SDL_CPUType[0]) {
460         int i = 0;
461 
462         if (CPU_haveCPUID()) {
463             int a, b, c, d;
464             cpuid(0x00000000, a, b, c, d);
465             (void) a;
466             SDL_CPUType[i++] = (char)(b & 0xff); b >>= 8;
467             SDL_CPUType[i++] = (char)(b & 0xff); b >>= 8;
468             SDL_CPUType[i++] = (char)(b & 0xff); b >>= 8;
469             SDL_CPUType[i++] = (char)(b & 0xff);
470 
471             SDL_CPUType[i++] = (char)(d & 0xff); d >>= 8;
472             SDL_CPUType[i++] = (char)(d & 0xff); d >>= 8;
473             SDL_CPUType[i++] = (char)(d & 0xff); d >>= 8;
474             SDL_CPUType[i++] = (char)(d & 0xff);
475 
476             SDL_CPUType[i++] = (char)(c & 0xff); c >>= 8;
477             SDL_CPUType[i++] = (char)(c & 0xff); c >>= 8;
478             SDL_CPUType[i++] = (char)(c & 0xff); c >>= 8;
479             SDL_CPUType[i++] = (char)(c & 0xff);
480         }
481         if (!SDL_CPUType[0]) {
482             SDL_strlcpy(SDL_CPUType, "Unknown", sizeof(SDL_CPUType));
483         }
484     }
485     return SDL_CPUType;
486 }
487 
488 
489 #ifdef TEST_MAIN  /* !!! FIXME: only used for test at the moment. */
490 static const char *
SDL_GetCPUName(void)491 SDL_GetCPUName(void)
492 {
493     static char SDL_CPUName[48];
494 
495     if (!SDL_CPUName[0]) {
496         int i = 0;
497         int a, b, c, d;
498 
499         if (CPU_haveCPUID()) {
500             cpuid(0x80000000, a, b, c, d);
501             if (a >= 0x80000004) {
502                 cpuid(0x80000002, a, b, c, d);
503                 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
504                 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
505                 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
506                 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
507                 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
508                 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
509                 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
510                 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
511                 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
512                 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
513                 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
514                 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
515                 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
516                 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
517                 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
518                 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
519                 cpuid(0x80000003, a, b, c, d);
520                 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
521                 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
522                 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
523                 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
524                 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
525                 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
526                 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
527                 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
528                 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
529                 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
530                 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
531                 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
532                 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
533                 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
534                 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
535                 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
536                 cpuid(0x80000004, a, b, c, d);
537                 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
538                 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
539                 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
540                 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
541                 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
542                 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
543                 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
544                 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
545                 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
546                 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
547                 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
548                 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
549                 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
550                 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
551                 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
552                 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
553             }
554         }
555         if (!SDL_CPUName[0]) {
556             SDL_strlcpy(SDL_CPUName, "Unknown", sizeof(SDL_CPUName));
557         }
558     }
559     return SDL_CPUName;
560 }
561 #endif
562 
563 int
SDL_GetCPUCacheLineSize(void)564 SDL_GetCPUCacheLineSize(void)
565 {
566     const char *cpuType = SDL_GetCPUType();
567     int a, b, c, d;
568     (void) a; (void) b; (void) c; (void) d;
569     if (SDL_strcmp(cpuType, "GenuineIntel") == 0) {
570         cpuid(0x00000001, a, b, c, d);
571         return (((b >> 8) & 0xff) * 8);
572     } else if (SDL_strcmp(cpuType, "AuthenticAMD") == 0) {
573         cpuid(0x80000005, a, b, c, d);
574         return (c & 0xff);
575     } else {
576         /* Just make a guess here... */
577         return SDL_CACHELINE_SIZE;
578     }
579 }
580 
581 static Uint32 SDL_CPUFeatures = 0xFFFFFFFF;
582 
583 static Uint32
SDL_GetCPUFeatures(void)584 SDL_GetCPUFeatures(void)
585 {
586     if (SDL_CPUFeatures == 0xFFFFFFFF) {
587         SDL_CPUFeatures = 0;
588         if (CPU_haveRDTSC()) {
589             SDL_CPUFeatures |= CPU_HAS_RDTSC;
590         }
591         if (CPU_haveAltiVec()) {
592             SDL_CPUFeatures |= CPU_HAS_ALTIVEC;
593         }
594         if (CPU_haveMMX()) {
595             SDL_CPUFeatures |= CPU_HAS_MMX;
596         }
597         if (CPU_have3DNow()) {
598             SDL_CPUFeatures |= CPU_HAS_3DNOW;
599         }
600         if (CPU_haveSSE()) {
601             SDL_CPUFeatures |= CPU_HAS_SSE;
602         }
603         if (CPU_haveSSE2()) {
604             SDL_CPUFeatures |= CPU_HAS_SSE2;
605         }
606         if (CPU_haveSSE3()) {
607             SDL_CPUFeatures |= CPU_HAS_SSE3;
608         }
609         if (CPU_haveSSE41()) {
610             SDL_CPUFeatures |= CPU_HAS_SSE41;
611         }
612         if (CPU_haveSSE42()) {
613             SDL_CPUFeatures |= CPU_HAS_SSE42;
614         }
615         if (CPU_haveAVX()) {
616             SDL_CPUFeatures |= CPU_HAS_AVX;
617         }
618         if (CPU_haveAVX2()) {
619             SDL_CPUFeatures |= CPU_HAS_AVX2;
620         }
621     }
622     return SDL_CPUFeatures;
623 }
624 
625 SDL_bool
SDL_HasRDTSC(void)626 SDL_HasRDTSC(void)
627 {
628     if (SDL_GetCPUFeatures() & CPU_HAS_RDTSC) {
629         return SDL_TRUE;
630     }
631     return SDL_FALSE;
632 }
633 
634 SDL_bool
SDL_HasAltiVec(void)635 SDL_HasAltiVec(void)
636 {
637     if (SDL_GetCPUFeatures() & CPU_HAS_ALTIVEC) {
638         return SDL_TRUE;
639     }
640     return SDL_FALSE;
641 }
642 
643 SDL_bool
SDL_HasMMX(void)644 SDL_HasMMX(void)
645 {
646     if (SDL_GetCPUFeatures() & CPU_HAS_MMX) {
647         return SDL_TRUE;
648     }
649     return SDL_FALSE;
650 }
651 
652 SDL_bool
SDL_Has3DNow(void)653 SDL_Has3DNow(void)
654 {
655     if (SDL_GetCPUFeatures() & CPU_HAS_3DNOW) {
656         return SDL_TRUE;
657     }
658     return SDL_FALSE;
659 }
660 
661 SDL_bool
SDL_HasSSE(void)662 SDL_HasSSE(void)
663 {
664     if (SDL_GetCPUFeatures() & CPU_HAS_SSE) {
665         return SDL_TRUE;
666     }
667     return SDL_FALSE;
668 }
669 
670 SDL_bool
SDL_HasSSE2(void)671 SDL_HasSSE2(void)
672 {
673     if (SDL_GetCPUFeatures() & CPU_HAS_SSE2) {
674         return SDL_TRUE;
675     }
676     return SDL_FALSE;
677 }
678 
679 SDL_bool
SDL_HasSSE3(void)680 SDL_HasSSE3(void)
681 {
682     if (SDL_GetCPUFeatures() & CPU_HAS_SSE3) {
683         return SDL_TRUE;
684     }
685     return SDL_FALSE;
686 }
687 
688 SDL_bool
SDL_HasSSE41(void)689 SDL_HasSSE41(void)
690 {
691     if (SDL_GetCPUFeatures() & CPU_HAS_SSE41) {
692         return SDL_TRUE;
693     }
694     return SDL_FALSE;
695 }
696 
697 SDL_bool
SDL_HasSSE42(void)698 SDL_HasSSE42(void)
699 {
700     if (SDL_GetCPUFeatures() & CPU_HAS_SSE42) {
701         return SDL_TRUE;
702     }
703     return SDL_FALSE;
704 }
705 
706 SDL_bool
SDL_HasAVX(void)707 SDL_HasAVX(void)
708 {
709     if (SDL_GetCPUFeatures() & CPU_HAS_AVX) {
710         return SDL_TRUE;
711     }
712     return SDL_FALSE;
713 }
714 
715 SDL_bool
SDL_HasAVX2(void)716 SDL_HasAVX2(void)
717 {
718     if (SDL_GetCPUFeatures() & CPU_HAS_AVX2) {
719         return SDL_TRUE;
720     }
721     return SDL_FALSE;
722 }
723 
724 static int SDL_SystemRAM = 0;
725 
726 int
SDL_GetSystemRAM(void)727 SDL_GetSystemRAM(void)
728 {
729     if (!SDL_SystemRAM) {
730 #ifndef SDL_CPUINFO_DISABLED
731 #if defined(HAVE_SYSCONF) && defined(_SC_PHYS_PAGES) && defined(_SC_PAGESIZE)
732         if (SDL_SystemRAM <= 0) {
733             SDL_SystemRAM = (int)((Sint64)sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGESIZE) / (1024*1024));
734         }
735 #endif
736 #ifdef HAVE_SYSCTLBYNAME
737         if (SDL_SystemRAM <= 0) {
738 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__DragonFly__)
739 #ifdef HW_REALMEM
740             int mib[2] = {CTL_HW, HW_REALMEM};
741 #else
742             /* might only report up to 2 GiB */
743             int mib[2] = {CTL_HW, HW_PHYSMEM};
744 #endif /* HW_REALMEM */
745 #else
746             int mib[2] = {CTL_HW, HW_MEMSIZE};
747 #endif /* __FreeBSD__ || __FreeBSD_kernel__ */
748             Uint64 memsize = 0;
749             size_t len = sizeof(memsize);
750 
751             if (sysctl(mib, 2, &memsize, &len, NULL, 0) == 0) {
752                 SDL_SystemRAM = (int)(memsize / (1024*1024));
753             }
754         }
755 #endif
756 #ifdef __WIN32__
757         if (SDL_SystemRAM <= 0) {
758             MEMORYSTATUSEX stat;
759             stat.dwLength = sizeof(stat);
760             if (GlobalMemoryStatusEx(&stat)) {
761                 SDL_SystemRAM = (int)(stat.ullTotalPhys / (1024 * 1024));
762             }
763         }
764 #endif
765 #endif
766     }
767     return SDL_SystemRAM;
768 }
769 
770 
771 #ifdef TEST_MAIN
772 
773 #include <stdio.h>
774 
775 int
main()776 main()
777 {
778     printf("CPU count: %d\n", SDL_GetCPUCount());
779     printf("CPU type: %s\n", SDL_GetCPUType());
780     printf("CPU name: %s\n", SDL_GetCPUName());
781     printf("CacheLine size: %d\n", SDL_GetCPUCacheLineSize());
782     printf("RDTSC: %d\n", SDL_HasRDTSC());
783     printf("Altivec: %d\n", SDL_HasAltiVec());
784     printf("MMX: %d\n", SDL_HasMMX());
785     printf("3DNow: %d\n", SDL_Has3DNow());
786     printf("SSE: %d\n", SDL_HasSSE());
787     printf("SSE2: %d\n", SDL_HasSSE2());
788     printf("SSE3: %d\n", SDL_HasSSE3());
789     printf("SSE4.1: %d\n", SDL_HasSSE41());
790     printf("SSE4.2: %d\n", SDL_HasSSE42());
791     printf("AVX: %d\n", SDL_HasAVX());
792     printf("AVX2: %d\n", SDL_HasAVX2());
793     printf("RAM: %d MB\n", SDL_GetSystemRAM());
794     return 0;
795 }
796 
797 #endif /* TEST_MAIN */
798 
799 /* vi: set ts=4 sw=4 expandtab: */
800