Initialize MEMORYSTATUSEX size before GlobalMemoryStatusEx() (thanks, Justin!).
Fixes Bugzilla #2177.
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
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.
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:
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.
21 #include "SDL_config.h"
23 #if defined(__WIN32__)
24 #include "../core/windows/SDL_windows.h"
27 /* CPU feature detection for SDL */
29 #include "SDL_cpuinfo.h"
34 #ifdef HAVE_SYSCTLBYNAME
35 #include <sys/types.h>
36 #include <sys/sysctl.h>
38 #if defined(__MACOSX__) && (defined(__ppc__) || defined(__ppc64__))
39 #include <sys/sysctl.h> /* For AltiVec check */
40 #elif defined(__OpenBSD__) && defined(__powerpc__)
41 #include <sys/param.h>
42 #include <sys/sysctl.h> /* For AltiVec check */
43 #include <machine/cpu.h>
44 #elif SDL_ALTIVEC_BLITTERS && HAVE_SETJMP
49 #define CPU_HAS_RDTSC 0x00000001
50 #define CPU_HAS_ALTIVEC 0x00000002
51 #define CPU_HAS_MMX 0x00000004
52 #define CPU_HAS_3DNOW 0x00000008
53 #define CPU_HAS_SSE 0x00000010
54 #define CPU_HAS_SSE2 0x00000020
55 #define CPU_HAS_SSE3 0x00000040
56 #define CPU_HAS_SSE41 0x00000100
57 #define CPU_HAS_SSE42 0x00000200
59 #if SDL_ALTIVEC_BLITTERS && HAVE_SETJMP && !__MACOSX__ && !__OpenBSD__
60 /* This is the brute force way of detecting instruction sets...
61 the idea is borrowed from the libmpeg2 library - thanks!
63 static jmp_buf jmpbuf;
65 illegal_instruction(int sig)
69 #endif /* HAVE_SETJMP */
76 #if defined(__GNUC__) && defined(i386)
78 " pushfl # Get original EFLAGS \n"
80 " movl %%eax,%%ecx \n"
81 " xorl $0x200000,%%eax # Flip ID bit in EFLAGS \n"
82 " pushl %%eax # Save new EFLAGS value on stack \n"
83 " popfl # Replace current EFLAGS value \n"
84 " pushfl # Get new EFLAGS \n"
85 " popl %%eax # Store new EFLAGS in EAX \n"
86 " xorl %%ecx,%%eax # Can not toggle ID bit, \n"
87 " jz 1f # Processor=80486 \n"
88 " movl $1,%0 # We have CPUID support \n"
94 #elif defined(__GNUC__) && defined(__x86_64__)
95 /* Technically, if this is being compiled under __x86_64__ then it has
96 CPUid by definition. But it's nice to be able to prove it. :) */
98 " pushfq # Get original EFLAGS \n"
100 " movq %%rax,%%rcx \n"
101 " xorl $0x200000,%%eax # Flip ID bit in EFLAGS \n"
102 " pushq %%rax # Save new EFLAGS value on stack \n"
103 " popfq # Replace current EFLAGS value \n"
104 " pushfq # Get new EFLAGS \n"
105 " popq %%rax # Store new EFLAGS in EAX \n"
106 " xorl %%ecx,%%eax # Can not toggle ID bit, \n"
107 " jz 1f # Processor=80486 \n"
108 " movl $1,%0 # We have CPUID support \n"
114 #elif (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
116 pushfd ; Get original EFLAGS
119 xor eax, 200000h ; Flip ID bit in EFLAGS
120 push eax ; Save new EFLAGS value on stack
121 popfd ; Replace current EFLAGS value
122 pushfd ; Get new EFLAGS
123 pop eax ; Store new EFLAGS in EAX
124 xor eax, ecx ; Can not toggle ID bit,
125 jz done ; Processor=80486
126 mov has_CPUID,1 ; We have CPUID support
129 #elif defined(__sun) && defined(__i386)
134 " xorl $0x200000,%eax \n"
141 " movl $1,-8(%ebp) \n"
144 #elif defined(__sun) && defined(__amd64)
149 " xorl $0x200000,%eax \n"
156 " movl $1,-8(%rbp) \n"
164 #if defined(__GNUC__) && defined(i386)
165 #define cpuid(func, a, b, c, d) \
166 __asm__ __volatile__ ( \
169 " movl %%ebx, %%esi \n" \
171 "=a" (a), "=S" (b), "=c" (c), "=d" (d) : "a" (func))
172 #elif defined(__GNUC__) && defined(__x86_64__)
173 #define cpuid(func, a, b, c, d) \
174 __asm__ __volatile__ ( \
177 " movq %%rbx, %%rsi \n" \
179 "=a" (a), "=S" (b), "=c" (c), "=d" (d) : "a" (func))
180 #elif (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
181 #define cpuid(func, a, b, c, d) \
183 __asm mov eax, func \
191 #define cpuid(func, a, b, c, d) \
195 static SDL_INLINE int
196 CPU_getCPUIDFeatures(void)
201 cpuid(0, a, b, c, d);
203 cpuid(1, a, b, c, d);
209 static SDL_INLINE int
212 if (CPU_haveCPUID()) {
213 return (CPU_getCPUIDFeatures() & 0x00000010);
218 static SDL_INLINE int
219 CPU_haveAltiVec(void)
221 volatile int altivec = 0;
222 #if (defined(__MACOSX__) && (defined(__ppc__) || defined(__ppc64__))) || (defined(__OpenBSD__) && defined(__powerpc__))
224 int selectors[2] = { CTL_MACHDEP, CPU_ALTIVEC };
226 int selectors[2] = { CTL_HW, HW_VECTORUNIT };
228 int hasVectorUnit = 0;
229 size_t length = sizeof(hasVectorUnit);
230 int error = sysctl(selectors, 2, &hasVectorUnit, &length, NULL, 0);
232 altivec = (hasVectorUnit != 0);
233 #elif SDL_ALTIVEC_BLITTERS && HAVE_SETJMP
234 void (*handler) (int sig);
235 handler = signal(SIGILL, illegal_instruction);
236 if (setjmp(jmpbuf) == 0) {
237 asm volatile ("mtspr 256, %0\n\t" "vand %%v0, %%v0, %%v0"::"r" (-1));
240 signal(SIGILL, handler);
245 static SDL_INLINE int
248 if (CPU_haveCPUID()) {
249 return (CPU_getCPUIDFeatures() & 0x00800000);
254 static SDL_INLINE int
257 if (CPU_haveCPUID()) {
260 cpuid(0x80000000, a, b, c, d);
261 if (a >= 0x80000001) {
262 cpuid(0x80000001, a, b, c, d);
263 return (d & 0x80000000);
269 static SDL_INLINE int
272 if (CPU_haveCPUID()) {
273 return (CPU_getCPUIDFeatures() & 0x02000000);
278 static SDL_INLINE int
281 if (CPU_haveCPUID()) {
282 return (CPU_getCPUIDFeatures() & 0x04000000);
287 static SDL_INLINE int
290 if (CPU_haveCPUID()) {
293 cpuid(0, a, b, c, d);
295 cpuid(1, a, b, c, d);
296 return (c & 0x00000001);
302 static SDL_INLINE int
305 if (CPU_haveCPUID()) {
308 cpuid(1, a, b, c, d);
310 cpuid(1, a, b, c, d);
311 return (c & 0x00080000);
317 static SDL_INLINE int
320 if (CPU_haveCPUID()) {
323 cpuid(1, a, b, c, d);
325 cpuid(1, a, b, c, d);
326 return (c & 0x00100000);
332 static int SDL_CPUCount = 0;
335 SDL_GetCPUCount(void)
338 #if defined(HAVE_SYSCONF) && defined(_SC_NPROCESSORS_ONLN)
339 if (SDL_CPUCount <= 0) {
340 SDL_CPUCount = (int)sysconf(_SC_NPROCESSORS_ONLN);
343 #ifdef HAVE_SYSCTLBYNAME
344 if (SDL_CPUCount <= 0) {
345 size_t size = sizeof(SDL_CPUCount);
346 sysctlbyname("hw.ncpu", &SDL_CPUCount, &size, NULL, 0);
350 if (SDL_CPUCount <= 0) {
352 GetSystemInfo(&info);
353 SDL_CPUCount = info.dwNumberOfProcessors;
356 /* There has to be at least 1, right? :) */
357 if (SDL_CPUCount <= 0) {
364 /* Oh, such a sweet sweet trick, just not very useful. :) */
368 static char SDL_CPUType[13];
370 if (!SDL_CPUType[0]) {
374 if (CPU_haveCPUID()) {
375 cpuid(0x00000000, a, b, c, d);
376 SDL_CPUType[i++] = (char)(b & 0xff); b >>= 8;
377 SDL_CPUType[i++] = (char)(b & 0xff); b >>= 8;
378 SDL_CPUType[i++] = (char)(b & 0xff); b >>= 8;
379 SDL_CPUType[i++] = (char)(b & 0xff); b >>= 8;
380 SDL_CPUType[i++] = (char)(d & 0xff); d >>= 8;
381 SDL_CPUType[i++] = (char)(d & 0xff); d >>= 8;
382 SDL_CPUType[i++] = (char)(d & 0xff); d >>= 8;
383 SDL_CPUType[i++] = (char)(d & 0xff); d >>= 8;
384 SDL_CPUType[i++] = (char)(c & 0xff); c >>= 8;
385 SDL_CPUType[i++] = (char)(c & 0xff); c >>= 8;
386 SDL_CPUType[i++] = (char)(c & 0xff); c >>= 8;
387 SDL_CPUType[i++] = (char)(c & 0xff); c >>= 8;
389 if (!SDL_CPUType[0]) {
390 SDL_strlcpy(SDL_CPUType, "Unknown", sizeof(SDL_CPUType));
397 #ifdef TEST_MAIN /* !!! FIXME: only used for test at the moment. */
401 static char SDL_CPUName[48];
403 if (!SDL_CPUName[0]) {
407 if (CPU_haveCPUID()) {
408 cpuid(0x80000000, a, b, c, d);
409 if (a >= 0x80000004) {
410 cpuid(0x80000002, a, b, c, d);
411 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
412 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
413 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
414 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
415 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
416 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
417 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
418 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
419 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
420 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
421 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
422 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
423 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
424 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
425 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
426 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
427 cpuid(0x80000003, a, b, c, d);
428 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
429 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
430 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
431 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
432 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
433 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
434 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
435 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
436 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
437 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
438 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
439 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
440 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
441 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
442 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
443 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
444 cpuid(0x80000004, a, b, c, d);
445 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
446 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
447 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
448 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
449 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
450 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
451 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
452 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
453 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
454 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
455 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
456 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
457 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
458 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
459 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
460 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
463 if (!SDL_CPUName[0]) {
464 SDL_strlcpy(SDL_CPUName, "Unknown", sizeof(SDL_CPUName));
472 SDL_GetCPUCacheLineSize(void)
474 const char *cpuType = SDL_GetCPUType();
476 if (SDL_strcmp(cpuType, "GenuineIntel") == 0) {
479 cpuid(0x00000001, a, b, c, d);
480 return (((b >> 8) & 0xff) * 8);
481 } else if (SDL_strcmp(cpuType, "AuthenticAMD") == 0) {
484 cpuid(0x80000005, a, b, c, d);
487 /* Just make a guess here... */
488 return SDL_CACHELINE_SIZE;
492 static Uint32 SDL_CPUFeatures = 0xFFFFFFFF;
495 SDL_GetCPUFeatures(void)
497 if (SDL_CPUFeatures == 0xFFFFFFFF) {
499 if (CPU_haveRDTSC()) {
500 SDL_CPUFeatures |= CPU_HAS_RDTSC;
502 if (CPU_haveAltiVec()) {
503 SDL_CPUFeatures |= CPU_HAS_ALTIVEC;
506 SDL_CPUFeatures |= CPU_HAS_MMX;
508 if (CPU_have3DNow()) {
509 SDL_CPUFeatures |= CPU_HAS_3DNOW;
512 SDL_CPUFeatures |= CPU_HAS_SSE;
514 if (CPU_haveSSE2()) {
515 SDL_CPUFeatures |= CPU_HAS_SSE2;
517 if (CPU_haveSSE3()) {
518 SDL_CPUFeatures |= CPU_HAS_SSE3;
520 if (CPU_haveSSE41()) {
521 SDL_CPUFeatures |= CPU_HAS_SSE41;
523 if (CPU_haveSSE42()) {
524 SDL_CPUFeatures |= CPU_HAS_SSE42;
527 return SDL_CPUFeatures;
533 if (SDL_GetCPUFeatures() & CPU_HAS_RDTSC) {
542 if (SDL_GetCPUFeatures() & CPU_HAS_ALTIVEC) {
551 if (SDL_GetCPUFeatures() & CPU_HAS_MMX) {
560 if (SDL_GetCPUFeatures() & CPU_HAS_3DNOW) {
569 if (SDL_GetCPUFeatures() & CPU_HAS_SSE) {
578 if (SDL_GetCPUFeatures() & CPU_HAS_SSE2) {
587 if (SDL_GetCPUFeatures() & CPU_HAS_SSE3) {
596 if (SDL_GetCPUFeatures() & CPU_HAS_SSE41) {
605 if (SDL_GetCPUFeatures() & CPU_HAS_SSE42) {
611 static int SDL_SystemRAM = 0;
614 SDL_GetSystemRAM(void)
616 if (!SDL_SystemRAM) {
617 #if defined(HAVE_SYSCONF) && defined(_SC_PHYS_PAGES) && defined(_SC_PAGESIZE)
618 if (SDL_SystemRAM <= 0) {
619 SDL_SystemRAM = (int)((Sint64)sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGESIZE) / (1024*1024));
622 #ifdef HAVE_SYSCTLBYNAME
623 if (SDL_SystemRAM <= 0) {
626 int mib[2] = {CTL_HW, HW_REALMEM};
628 /* might only report up to 2 GiB */
629 int mib[2] = {CTL_HW, HW_PHYSMEM};
630 #endif /* HW_REALMEM */
632 int mib[2] = {CTL_HW, HW_MEMSIZE};
633 #endif /* __FreeBSD__ */
635 size_t len = sizeof(memsize);
637 if (sysctl(mib, 2, &memsize, &len, NULL, 0) == 0) {
638 SDL_SystemRAM = (int)(memsize / (1024*1024));
643 if (SDL_SystemRAM <= 0) {
645 stat.dwLength = sizeof(stat);
646 if (GlobalMemoryStatusEx(&stat)) {
647 SDL_SystemRAM = (int)(stat.ullTotalPhys / (1024 * 1024));
652 return SDL_SystemRAM;
663 printf("CPU count: %d\n", SDL_GetCPUCount());
664 printf("CPU type: %s\n", SDL_GetCPUType());
665 printf("CPU name: %s\n", SDL_GetCPUName());
666 printf("CacheLine size: %d\n", SDL_GetCPUCacheLineSize());
667 printf("RDTSC: %d\n", SDL_HasRDTSC());
668 printf("Altivec: %d\n", SDL_HasAltiVec());
669 printf("MMX: %d\n", SDL_HasMMX());
670 printf("3DNow: %d\n", SDL_Has3DNow());
671 printf("SSE: %d\n", SDL_HasSSE());
672 printf("SSE2: %d\n", SDL_HasSSE2());
673 printf("SSE3: %d\n", SDL_HasSSE3());
674 printf("SSE4.1: %d\n", SDL_HasSSE41());
675 printf("SSE4.2: %d\n", SDL_HasSSE42());
676 printf("RAM: %d MB\n", SDL_GetSystemRAM());
680 #endif /* TEST_MAIN */
682 /* vi: set ts=4 sw=4 expandtab: */