SDL 2.0
SDL_cpuinfo.c
Go to the documentation of this file.
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2019 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__) || defined(__WINRT__)
28#include "../core/windows/SDL_windows.h"
29#endif
30#if defined(__OS2__)
31#define INCL_DOS
32#include <os2.h>
33#ifndef QSV_NUMPROCESSORS
34#define QSV_NUMPROCESSORS 26
35#endif
36#endif
37
38/* CPU feature detection for SDL */
39
40#include "SDL_cpuinfo.h"
41#include "SDL_assert.h"
42
43#ifdef HAVE_SYSCONF
44#include <unistd.h>
45#endif
46#ifdef HAVE_SYSCTLBYNAME
47#include <sys/types.h>
48#include <sys/sysctl.h>
49#endif
50#if defined(__MACOSX__) && (defined(__ppc__) || defined(__ppc64__))
51#include <sys/sysctl.h> /* For AltiVec check */
52#elif defined(__OpenBSD__) && defined(__powerpc__)
53#include <sys/param.h>
54#include <sys/sysctl.h> /* For AltiVec check */
55#include <machine/cpu.h>
56#elif SDL_ALTIVEC_BLITTERS && HAVE_SETJMP
57#include <signal.h>
58#include <setjmp.h>
59#endif
60
61#if defined(__QNXNTO__)
62#include <sys/syspage.h>
63#endif
64
65#if (defined(__LINUX__) || defined(__ANDROID__)) && defined(__ARM_ARCH)
66/*#include <asm/hwcap.h>*/
67#ifndef AT_HWCAP
68#define AT_HWCAP 16
69#endif
70#ifndef HWCAP_NEON
71#define HWCAP_NEON (1 << 12)
72#endif
73#if defined HAVE_GETAUXVAL
74#include <sys/auxv.h>
75#else
76#include <fcntl.h>
77#endif
78#endif
79
80#if defined(__ANDROID__) && defined(__ARM_ARCH) && !defined(HAVE_GETAUXVAL)
81#if __ARM_ARCH < 8
82#include <cpu-features.h>
83#endif
84#endif
85
86#define CPU_HAS_RDTSC (1 << 0)
87#define CPU_HAS_ALTIVEC (1 << 1)
88#define CPU_HAS_MMX (1 << 2)
89#define CPU_HAS_3DNOW (1 << 3)
90#define CPU_HAS_SSE (1 << 4)
91#define CPU_HAS_SSE2 (1 << 5)
92#define CPU_HAS_SSE3 (1 << 6)
93#define CPU_HAS_SSE41 (1 << 7)
94#define CPU_HAS_SSE42 (1 << 8)
95#define CPU_HAS_AVX (1 << 9)
96#define CPU_HAS_AVX2 (1 << 10)
97#define CPU_HAS_NEON (1 << 11)
98#define CPU_HAS_AVX512F (1 << 12)
99
100#if SDL_ALTIVEC_BLITTERS && HAVE_SETJMP && !__MACOSX__ && !__OpenBSD__
101/* This is the brute force way of detecting instruction sets...
102 the idea is borrowed from the libmpeg2 library - thanks!
103 */
104static jmp_buf jmpbuf;
105static void
106illegal_instruction(int sig)
107{
108 longjmp(jmpbuf, 1);
109}
110#endif /* HAVE_SETJMP */
111
112static int
114{
115 int has_CPUID = 0;
116
117/* *INDENT-OFF* */
118#ifndef SDL_CPUINFO_DISABLED
119#if defined(__GNUC__) && defined(i386)
120 __asm__ (
121" pushfl # Get original EFLAGS \n"
122" popl %%eax \n"
123" movl %%eax,%%ecx \n"
124" xorl $0x200000,%%eax # Flip ID bit in EFLAGS \n"
125" pushl %%eax # Save new EFLAGS value on stack \n"
126" popfl # Replace current EFLAGS value \n"
127" pushfl # Get new EFLAGS \n"
128" popl %%eax # Store new EFLAGS in EAX \n"
129" xorl %%ecx,%%eax # Can not toggle ID bit, \n"
130" jz 1f # Processor=80486 \n"
131" movl $1,%0 # We have CPUID support \n"
132"1: \n"
133 : "=m" (has_CPUID)
134 :
135 : "%eax", "%ecx"
136 );
137#elif defined(__GNUC__) && defined(__x86_64__)
138/* Technically, if this is being compiled under __x86_64__ then it has
139 CPUid by definition. But it's nice to be able to prove it. :) */
140 __asm__ (
141" pushfq # Get original EFLAGS \n"
142" popq %%rax \n"
143" movq %%rax,%%rcx \n"
144" xorl $0x200000,%%eax # Flip ID bit in EFLAGS \n"
145" pushq %%rax # Save new EFLAGS value on stack \n"
146" popfq # Replace current EFLAGS value \n"
147" pushfq # Get new EFLAGS \n"
148" popq %%rax # Store new EFLAGS in EAX \n"
149" xorl %%ecx,%%eax # Can not toggle ID bit, \n"
150" jz 1f # Processor=80486 \n"
151" movl $1,%0 # We have CPUID support \n"
152"1: \n"
153 : "=m" (has_CPUID)
154 :
155 : "%rax", "%rcx"
156 );
157#elif (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
158 __asm {
159 pushfd ; Get original EFLAGS
160 pop eax
161 mov ecx, eax
162 xor eax, 200000h ; Flip ID bit in EFLAGS
163 push eax ; Save new EFLAGS value on stack
164 popfd ; Replace current EFLAGS value
165 pushfd ; Get new EFLAGS
166 pop eax ; Store new EFLAGS in EAX
167 xor eax, ecx ; Can not toggle ID bit,
168 jz done ; Processor=80486
169 mov has_CPUID,1 ; We have CPUID support
170done:
171 }
172#elif defined(_MSC_VER) && defined(_M_X64)
173 has_CPUID = 1;
174#elif defined(__sun) && defined(__i386)
175 __asm (
176" pushfl \n"
177" popl %eax \n"
178" movl %eax,%ecx \n"
179" xorl $0x200000,%eax \n"
180" pushl %eax \n"
181" popfl \n"
182" pushfl \n"
183" popl %eax \n"
184" xorl %ecx,%eax \n"
185" jz 1f \n"
186" movl $1,-8(%ebp) \n"
187"1: \n"
188 );
189#elif defined(__sun) && defined(__amd64)
190 __asm (
191" pushfq \n"
192" popq %rax \n"
193" movq %rax,%rcx \n"
194" xorl $0x200000,%eax \n"
195" pushq %rax \n"
196" popfq \n"
197" pushfq \n"
198" popq %rax \n"
199" xorl %ecx,%eax \n"
200" jz 1f \n"
201" movl $1,-8(%rbp) \n"
202"1: \n"
203 );
204#endif
205#endif
206/* *INDENT-ON* */
207 return has_CPUID;
208}
209
210#if defined(__GNUC__) && defined(i386)
211#define cpuid(func, a, b, c, d) \
212 __asm__ __volatile__ ( \
213" pushl %%ebx \n" \
214" xorl %%ecx,%%ecx \n" \
215" cpuid \n" \
216" movl %%ebx, %%esi \n" \
217" popl %%ebx \n" : \
218 "=a" (a), "=S" (b), "=c" (c), "=d" (d) : "a" (func))
219#elif defined(__GNUC__) && defined(__x86_64__)
220#define cpuid(func, a, b, c, d) \
221 __asm__ __volatile__ ( \
222" pushq %%rbx \n" \
223" xorq %%rcx,%%rcx \n" \
224" cpuid \n" \
225" movq %%rbx, %%rsi \n" \
226" popq %%rbx \n" : \
227 "=a" (a), "=S" (b), "=c" (c), "=d" (d) : "a" (func))
228#elif (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
229#define cpuid(func, a, b, c, d) \
230 __asm { \
231 __asm mov eax, func \
232 __asm xor ecx, ecx \
233 __asm cpuid \
234 __asm mov a, eax \
235 __asm mov b, ebx \
236 __asm mov c, ecx \
237 __asm mov d, edx \
238}
239#elif defined(_MSC_VER) && defined(_M_X64)
240#define cpuid(func, a, b, c, d) \
241{ \
242 int CPUInfo[4]; \
243 __cpuid(CPUInfo, func); \
244 a = CPUInfo[0]; \
245 b = CPUInfo[1]; \
246 c = CPUInfo[2]; \
247 d = CPUInfo[3]; \
248}
249#else
250#define cpuid(func, a, b, c, d) \
251 do { a = b = c = d = 0; (void) a; (void) b; (void) c; (void) d; } while (0)
252#endif
253
254static int CPU_CPUIDFeatures[4];
255static int CPU_CPUIDMaxFunction = 0;
258
259static void
261{
262 static SDL_bool checked = SDL_FALSE;
263 if (!checked) {
264 checked = SDL_TRUE;
265 if (CPU_haveCPUID()) {
266 int a, b, c, d;
267 cpuid(0, a, b, c, d);
269 if (CPU_CPUIDMaxFunction >= 1) {
270 cpuid(1, a, b, c, d);
271 CPU_CPUIDFeatures[0] = a;
272 CPU_CPUIDFeatures[1] = b;
273 CPU_CPUIDFeatures[2] = c;
274 CPU_CPUIDFeatures[3] = d;
275
276 /* Check to make sure we can call xgetbv */
277 if (c & 0x08000000) {
278 /* Call xgetbv to see if YMM (etc) register state is saved */
279#if defined(__GNUC__) && (defined(i386) || defined(__x86_64__))
280 __asm__(".byte 0x0f, 0x01, 0xd0" : "=a" (a) : "c" (0) : "%edx");
281#elif defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64)) && (_MSC_FULL_VER >= 160040219) /* VS2010 SP1 */
282 a = (int)_xgetbv(0);
283#elif (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
284 __asm
285 {
286 xor ecx, ecx
287 _asm _emit 0x0f _asm _emit 0x01 _asm _emit 0xd0
288 mov a, eax
289 }
290#endif
291 CPU_OSSavesYMM = ((a & 6) == 6) ? SDL_TRUE : SDL_FALSE;
292 CPU_OSSavesZMM = (CPU_OSSavesYMM && ((a & 0xe0) == 0xe0)) ? SDL_TRUE : SDL_FALSE;
293 }
294 }
295 }
296 }
297}
298
299static int
301{
302 volatile int altivec = 0;
303#ifndef SDL_CPUINFO_DISABLED
304#if (defined(__MACOSX__) && (defined(__ppc__) || defined(__ppc64__))) || (defined(__OpenBSD__) && defined(__powerpc__))
305#ifdef __OpenBSD__
306 int selectors[2] = { CTL_MACHDEP, CPU_ALTIVEC };
307#else
308 int selectors[2] = { CTL_HW, HW_VECTORUNIT };
309#endif
310 int hasVectorUnit = 0;
311 size_t length = sizeof(hasVectorUnit);
312 int error = sysctl(selectors, 2, &hasVectorUnit, &length, NULL, 0);
313 if (0 == error)
314 altivec = (hasVectorUnit != 0);
315#elif SDL_ALTIVEC_BLITTERS && HAVE_SETJMP
316 void (*handler) (int sig);
317 handler = signal(SIGILL, illegal_instruction);
318 if (setjmp(jmpbuf) == 0) {
319 asm volatile ("mtspr 256, %0\n\t" "vand %%v0, %%v0, %%v0"::"r" (-1));
320 altivec = 1;
321 }
322 signal(SIGILL, handler);
323#endif
324#endif
325 return altivec;
326}
327
328#if defined(__LINUX__) && defined(__ARM_ARCH) && !defined(HAVE_GETAUXVAL)
329static int
330readProcAuxvForNeon(void)
331{
332 int neon = 0;
333 int kv[2];
334 const int fd = open("/proc/self/auxv", O_RDONLY);
335 if (fd != -1) {
336 while (read(fd, kv, sizeof (kv)) == sizeof (kv)) {
337 if (kv[0] == AT_HWCAP) {
338 neon = ((kv[1] & HWCAP_NEON) == HWCAP_NEON);
339 break;
340 }
341 }
342 close(fd);
343 }
344 return neon;
345}
346#endif
347
348
349static int
351{
352/* The way you detect NEON is a privileged instruction on ARM, so you have
353 query the OS kernel in a platform-specific way. :/ */
354#if defined(SDL_CPUINFO_DISABLED)
355 return 0; /* disabled */
356#elif (defined(__WINDOWS__) || defined(__WINRT__)) && (defined(_M_ARM) || defined(_M_ARM64))
357/* Visual Studio, for ARM, doesn't define __ARM_ARCH. Handle this first. */
358/* Seems to have been removed */
359# if !defined(PF_ARM_NEON_INSTRUCTIONS_AVAILABLE)
360# define PF_ARM_NEON_INSTRUCTIONS_AVAILABLE 19
361# endif
362/* All WinRT ARM devices are required to support NEON, but just in case. */
363 return IsProcessorFeaturePresent(PF_ARM_NEON_INSTRUCTIONS_AVAILABLE) != 0;
364#elif !defined(__ARM_ARCH)
365 return 0; /* not an ARM CPU at all. */
366#elif __ARM_ARCH >= 8
367 return 1; /* ARMv8 always has non-optional NEON support. */
368#elif defined(__APPLE__) && (__ARM_ARCH >= 7)
369 /* (note that sysctlbyname("hw.optional.neon") doesn't work!) */
370 return 1; /* all Apple ARMv7 chips and later have NEON. */
371#elif defined(__APPLE__)
372 return 0; /* assume anything else from Apple doesn't have NEON. */
373#elif defined(__QNXNTO__)
374 return SYSPAGE_ENTRY(cpuinfo)->flags & ARM_CPU_FLAG_NEON;
375#elif (defined(__LINUX__) || defined(__ANDROID__)) && defined(HAVE_GETAUXVAL)
376 return ((getauxval(AT_HWCAP) & HWCAP_NEON) == HWCAP_NEON);
377#elif defined(__LINUX__)
378 return readProcAuxvForNeon();
379#elif defined(__ANDROID__)
380 /* Use NDK cpufeatures to read either /proc/self/auxv or /proc/cpuinfo */
381 {
382 AndroidCpuFamily cpu_family = android_getCpuFamily();
383 if (cpu_family == ANDROID_CPU_FAMILY_ARM) {
384 uint64_t cpu_features = android_getCpuFeatures();
385 if ((cpu_features & ANDROID_CPU_ARM_FEATURE_NEON) != 0) {
386 return 1;
387 }
388 }
389 return 0;
390 }
391#else
392#warning SDL_HasNEON is not implemented for this ARM platform. Write me.
393 return 0;
394#endif
395}
396
397static int
399{
400 if (CPU_CPUIDMaxFunction > 0) { /* that is, do we have CPUID at all? */
401 int a, b, c, d;
402 cpuid(0x80000000, a, b, c, d);
403 if (a >= 0x80000001) {
404 cpuid(0x80000001, a, b, c, d);
405 return (d & 0x80000000);
406 }
407 }
408 return 0;
409}
410
411#define CPU_haveRDTSC() (CPU_CPUIDFeatures[3] & 0x00000010)
412#define CPU_haveMMX() (CPU_CPUIDFeatures[3] & 0x00800000)
413#define CPU_haveSSE() (CPU_CPUIDFeatures[3] & 0x02000000)
414#define CPU_haveSSE2() (CPU_CPUIDFeatures[3] & 0x04000000)
415#define CPU_haveSSE3() (CPU_CPUIDFeatures[2] & 0x00000001)
416#define CPU_haveSSE41() (CPU_CPUIDFeatures[2] & 0x00080000)
417#define CPU_haveSSE42() (CPU_CPUIDFeatures[2] & 0x00100000)
418#define CPU_haveAVX() (CPU_OSSavesYMM && (CPU_CPUIDFeatures[2] & 0x10000000))
419
420static int
422{
423 if (CPU_OSSavesYMM && (CPU_CPUIDMaxFunction >= 7)) {
424 int a, b, c, d;
425 (void) a; (void) b; (void) c; (void) d; /* compiler warnings... */
426 cpuid(7, a, b, c, d);
427 return (b & 0x00000020);
428 }
429 return 0;
430}
431
432static int
434{
435 if (CPU_OSSavesZMM && (CPU_CPUIDMaxFunction >= 7)) {
436 int a, b, c, d;
437 (void) a; (void) b; (void) c; (void) d; /* compiler warnings... */
438 cpuid(7, a, b, c, d);
439 return (b & 0x00010000);
440 }
441 return 0;
442}
443
444static int SDL_CPUCount = 0;
445
446int
448{
449 if (!SDL_CPUCount) {
450#ifndef SDL_CPUINFO_DISABLED
451#if defined(HAVE_SYSCONF) && defined(_SC_NPROCESSORS_ONLN)
452 if (SDL_CPUCount <= 0) {
453 SDL_CPUCount = (int)sysconf(_SC_NPROCESSORS_ONLN);
454 }
455#endif
456#ifdef HAVE_SYSCTLBYNAME
457 if (SDL_CPUCount <= 0) {
458 size_t size = sizeof(SDL_CPUCount);
459 sysctlbyname("hw.ncpu", &SDL_CPUCount, &size, NULL, 0);
460 }
461#endif
462#ifdef __WIN32__
463 if (SDL_CPUCount <= 0) {
464 SYSTEM_INFO info;
465 GetSystemInfo(&info);
466 SDL_CPUCount = info.dwNumberOfProcessors;
467 }
468#endif
469#ifdef __OS2__
470 if (SDL_CPUCount <= 0) {
471 DosQuerySysInfo(QSV_NUMPROCESSORS, QSV_NUMPROCESSORS,
472 &SDL_CPUCount, sizeof(SDL_CPUCount) );
473 }
474#endif
475#endif
476 /* There has to be at least 1, right? :) */
477 if (SDL_CPUCount <= 0) {
478 SDL_CPUCount = 1;
479 }
480 }
481 return SDL_CPUCount;
482}
483
484/* Oh, such a sweet sweet trick, just not very useful. :) */
485static const char *
487{
488 static char SDL_CPUType[13];
489
490 if (!SDL_CPUType[0]) {
491 int i = 0;
492
494 if (CPU_CPUIDMaxFunction > 0) { /* do we have CPUID at all? */
495 int a, b, c, d;
496 cpuid(0x00000000, a, b, c, d);
497 (void) a;
498 SDL_CPUType[i++] = (char)(b & 0xff); b >>= 8;
499 SDL_CPUType[i++] = (char)(b & 0xff); b >>= 8;
500 SDL_CPUType[i++] = (char)(b & 0xff); b >>= 8;
501 SDL_CPUType[i++] = (char)(b & 0xff);
502
503 SDL_CPUType[i++] = (char)(d & 0xff); d >>= 8;
504 SDL_CPUType[i++] = (char)(d & 0xff); d >>= 8;
505 SDL_CPUType[i++] = (char)(d & 0xff); d >>= 8;
506 SDL_CPUType[i++] = (char)(d & 0xff);
507
508 SDL_CPUType[i++] = (char)(c & 0xff); c >>= 8;
509 SDL_CPUType[i++] = (char)(c & 0xff); c >>= 8;
510 SDL_CPUType[i++] = (char)(c & 0xff); c >>= 8;
511 SDL_CPUType[i++] = (char)(c & 0xff);
512 }
513 if (!SDL_CPUType[0]) {
514 SDL_strlcpy(SDL_CPUType, "Unknown", sizeof(SDL_CPUType));
515 }
516 }
517 return SDL_CPUType;
518}
519
520
521#ifdef TEST_MAIN /* !!! FIXME: only used for test at the moment. */
522static const char *
523SDL_GetCPUName(void)
524{
525 static char SDL_CPUName[48];
526
527 if (!SDL_CPUName[0]) {
528 int i = 0;
529 int a, b, c, d;
530
532 if (CPU_CPUIDMaxFunction > 0) { /* do we have CPUID at all? */
533 cpuid(0x80000000, a, b, c, d);
534 if (a >= 0x80000004) {
535 cpuid(0x80000002, a, b, c, d);
536 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
537 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
538 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
539 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
540 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
541 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
542 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
543 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
544 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
545 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
546 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
547 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
548 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
549 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
550 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
551 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
552 cpuid(0x80000003, a, b, c, d);
553 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
554 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
555 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
556 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
557 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
558 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
559 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
560 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
561 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
562 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
563 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
564 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
565 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
566 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
567 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
568 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
569 cpuid(0x80000004, a, b, c, d);
570 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
571 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
572 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
573 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
574 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
575 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
576 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
577 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
578 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
579 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
580 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
581 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
582 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
583 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
584 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
585 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
586 }
587 }
588 if (!SDL_CPUName[0]) {
589 SDL_strlcpy(SDL_CPUName, "Unknown", sizeof(SDL_CPUName));
590 }
591 }
592 return SDL_CPUName;
593}
594#endif
595
596int
598{
599 const char *cpuType = SDL_GetCPUType();
600 int a, b, c, d;
601 (void) a; (void) b; (void) c; (void) d;
602 if (SDL_strcmp(cpuType, "GenuineIntel") == 0) {
603 cpuid(0x00000001, a, b, c, d);
604 return (((b >> 8) & 0xff) * 8);
605 } else if (SDL_strcmp(cpuType, "AuthenticAMD") == 0) {
606 cpuid(0x80000005, a, b, c, d);
607 return (c & 0xff);
608 } else {
609 /* Just make a guess here... */
610 return SDL_CACHELINE_SIZE;
611 }
612}
613
614static Uint32 SDL_CPUFeatures = 0xFFFFFFFF;
615static Uint32 SDL_SIMDAlignment = 0xFFFFFFFF;
616
617static Uint32
619{
620 if (SDL_CPUFeatures == 0xFFFFFFFF) {
622 SDL_CPUFeatures = 0;
623 SDL_SIMDAlignment = 4; /* a good safe base value */
624 if (CPU_haveRDTSC()) {
626 }
627 if (CPU_haveAltiVec()) {
630 }
631 if (CPU_haveMMX()) {
634 }
635 if (CPU_have3DNow()) {
638 }
639 if (CPU_haveSSE()) {
642 }
643 if (CPU_haveSSE2()) {
646 }
647 if (CPU_haveSSE3()) {
650 }
651 if (CPU_haveSSE41()) {
654 }
655 if (CPU_haveSSE42()) {
658 }
659 if (CPU_haveAVX()) {
662 }
663 if (CPU_haveAVX2()) {
666 }
667 if (CPU_haveAVX512F()) {
670 }
671 if (CPU_haveNEON()) {
674 }
675 }
676 return SDL_CPUFeatures;
677}
678
679#define CPU_FEATURE_AVAILABLE(f) ((SDL_GetCPUFeatures() & f) ? SDL_TRUE : SDL_FALSE)
680
682{
684}
685
688{
690}
691
694{
696}
697
700{
702}
703
706{
708}
709
712{
714}
715
718{
720}
721
724{
726}
727
730{
732}
733
736{
738}
739
742{
744}
745
748{
750}
751
754{
756}
757
758static int SDL_SystemRAM = 0;
759
760int
762{
763 if (!SDL_SystemRAM) {
764#ifndef SDL_CPUINFO_DISABLED
765#if defined(HAVE_SYSCONF) && defined(_SC_PHYS_PAGES) && defined(_SC_PAGESIZE)
766 if (SDL_SystemRAM <= 0) {
767 SDL_SystemRAM = (int)((Sint64)sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGESIZE) / (1024*1024));
768 }
769#endif
770#ifdef HAVE_SYSCTLBYNAME
771 if (SDL_SystemRAM <= 0) {
772#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__)
773#ifdef HW_REALMEM
774 int mib[2] = {CTL_HW, HW_REALMEM};
775#else
776 /* might only report up to 2 GiB */
777 int mib[2] = {CTL_HW, HW_PHYSMEM};
778#endif /* HW_REALMEM */
779#else
780 int mib[2] = {CTL_HW, HW_MEMSIZE};
781#endif /* __FreeBSD__ || __FreeBSD_kernel__ */
782 Uint64 memsize = 0;
783 size_t len = sizeof(memsize);
784
785 if (sysctl(mib, 2, &memsize, &len, NULL, 0) == 0) {
786 SDL_SystemRAM = (int)(memsize / (1024*1024));
787 }
788 }
789#endif
790#ifdef __WIN32__
791 if (SDL_SystemRAM <= 0) {
792 MEMORYSTATUSEX stat;
793 stat.dwLength = sizeof(stat);
794 if (GlobalMemoryStatusEx(&stat)) {
795 SDL_SystemRAM = (int)(stat.ullTotalPhys / (1024 * 1024));
796 }
797 }
798#endif
799#ifdef __OS2__
800 if (SDL_SystemRAM <= 0) {
801 Uint32 sysram = 0;
802 DosQuerySysInfo(QSV_TOTPHYSMEM, QSV_TOTPHYSMEM, &sysram, 4);
803 SDL_SystemRAM = (int) (sysram / 0x100000U);
804 }
805#endif
806#endif
807 }
808 return SDL_SystemRAM;
809}
810
811
812size_t
814{
815 if (SDL_SIMDAlignment == 0xFFFFFFFF) {
816 SDL_GetCPUFeatures(); /* make sure this has been calculated */
817 }
819 return SDL_SIMDAlignment;
820}
821
822void *
823SDL_SIMDAlloc(const size_t len)
824{
825 const size_t alignment = SDL_SIMDGetAlignment();
826 const size_t padding = alignment - (len % alignment);
827 const size_t padded = (padding != alignment) ? (len + padding) : len;
828 Uint8 *retval = NULL;
829 Uint8 *ptr = (Uint8 *) SDL_malloc(padded + alignment + sizeof (void *));
830 if (ptr) {
831 /* store the actual malloc pointer right before our aligned pointer. */
832 retval = ptr + sizeof (void *);
833 retval += alignment - (((size_t) retval) % alignment);
834 *(((void **) retval) - 1) = ptr;
835 }
836 return retval;
837}
838
839void
840SDL_SIMDFree(void *ptr)
841{
842 if (ptr) {
843 void **realptr = (void **) ptr;
844 realptr--;
845 SDL_free(*(((void **) ptr) - 1));
846 }
847}
848
849
850#ifdef TEST_MAIN
851
852#include <stdio.h>
853
854int
855main()
856{
857 printf("CPU count: %d\n", SDL_GetCPUCount());
858 printf("CPU type: %s\n", SDL_GetCPUType());
859 printf("CPU name: %s\n", SDL_GetCPUName());
860 printf("CacheLine size: %d\n", SDL_GetCPUCacheLineSize());
861 printf("RDTSC: %d\n", SDL_HasRDTSC());
862 printf("Altivec: %d\n", SDL_HasAltiVec());
863 printf("MMX: %d\n", SDL_HasMMX());
864 printf("3DNow: %d\n", SDL_Has3DNow());
865 printf("SSE: %d\n", SDL_HasSSE());
866 printf("SSE2: %d\n", SDL_HasSSE2());
867 printf("SSE3: %d\n", SDL_HasSSE3());
868 printf("SSE4.1: %d\n", SDL_HasSSE41());
869 printf("SSE4.2: %d\n", SDL_HasSSE42());
870 printf("AVX: %d\n", SDL_HasAVX());
871 printf("AVX2: %d\n", SDL_HasAVX2());
872 printf("AVX-512F: %d\n", SDL_HasAVX512F());
873 printf("NEON: %d\n", SDL_HasNEON());
874 printf("RAM: %d MB\n", SDL_GetSystemRAM());
875 return 0;
876}
877
878#endif /* TEST_MAIN */
879
880/* vi: set ts=4 sw=4 expandtab: */
#define SDL_assert(condition)
Definition: SDL_assert.h:169
unsigned int size_t
unsigned long long uint64_t
SDL_bool SDL_HasSSE2(void)
Definition: SDL_cpuinfo.c:711
SDL_bool SDL_HasSSE42(void)
Definition: SDL_cpuinfo.c:729
static SDL_bool CPU_OSSavesYMM
Definition: SDL_cpuinfo.c:256
static int CPU_haveAVX512F(void)
Definition: SDL_cpuinfo.c:433
#define CPU_haveSSE3()
Definition: SDL_cpuinfo.c:415
SDL_bool SDL_HasNEON(void)
Definition: SDL_cpuinfo.c:753
#define cpuid(func, a, b, c, d)
Definition: SDL_cpuinfo.c:250
#define CPU_HAS_SSE42
Definition: SDL_cpuinfo.c:94
static Uint32 SDL_SIMDAlignment
Definition: SDL_cpuinfo.c:615
#define CPU_haveSSE41()
Definition: SDL_cpuinfo.c:416
static SDL_bool CPU_OSSavesZMM
Definition: SDL_cpuinfo.c:257
SDL_bool SDL_HasSSE3(void)
Definition: SDL_cpuinfo.c:717
SDL_bool SDL_HasAVX2(void)
Definition: SDL_cpuinfo.c:741
SDL_bool SDL_HasSSE41(void)
Definition: SDL_cpuinfo.c:723
#define CPU_HAS_SSE3
Definition: SDL_cpuinfo.c:92
#define CPU_FEATURE_AVAILABLE(f)
Definition: SDL_cpuinfo.c:679
SDL_bool SDL_HasMMX(void)
Definition: SDL_cpuinfo.c:693
SDL_bool SDL_HasAltiVec(void)
Definition: SDL_cpuinfo.c:687
#define CPU_HAS_MMX
Definition: SDL_cpuinfo.c:88
void * SDL_SIMDAlloc(const size_t len)
Allocate memory in a SIMD-friendly way.
Definition: SDL_cpuinfo.c:823
#define CPU_haveSSE42()
Definition: SDL_cpuinfo.c:417
void SDL_SIMDFree(void *ptr)
Deallocate memory obtained from SDL_SIMDAlloc.
Definition: SDL_cpuinfo.c:840
#define CPU_HAS_SSE2
Definition: SDL_cpuinfo.c:91
#define CPU_haveSSE()
Definition: SDL_cpuinfo.c:413
static Uint32 SDL_CPUFeatures
Definition: SDL_cpuinfo.c:614
#define CPU_HAS_SSE
Definition: SDL_cpuinfo.c:90
size_t SDL_SIMDGetAlignment(void)
Report the alignment this system needs for SIMD allocations.
Definition: SDL_cpuinfo.c:813
int SDL_GetSystemRAM(void)
Definition: SDL_cpuinfo.c:761
static int CPU_CPUIDMaxFunction
Definition: SDL_cpuinfo.c:255
#define CPU_HAS_SSE41
Definition: SDL_cpuinfo.c:93
static int CPU_haveCPUID(void)
Definition: SDL_cpuinfo.c:113
static const char * SDL_GetCPUType(void)
Definition: SDL_cpuinfo.c:486
SDL_bool SDL_HasAVX512F(void)
Definition: SDL_cpuinfo.c:747
int SDL_GetCPUCount(void)
Definition: SDL_cpuinfo.c:447
static int CPU_have3DNow(void)
Definition: SDL_cpuinfo.c:398
#define CPU_haveAVX()
Definition: SDL_cpuinfo.c:418
SDL_bool SDL_HasAVX(void)
Definition: SDL_cpuinfo.c:735
static int CPU_haveAVX2(void)
Definition: SDL_cpuinfo.c:421
#define CPU_HAS_AVX2
Definition: SDL_cpuinfo.c:96
#define CPU_HAS_ALTIVEC
Definition: SDL_cpuinfo.c:87
#define CPU_HAS_RDTSC
Definition: SDL_cpuinfo.c:86
static void CPU_calcCPUIDFeatures(void)
Definition: SDL_cpuinfo.c:260
#define CPU_HAS_NEON
Definition: SDL_cpuinfo.c:97
int SDL_GetCPUCacheLineSize(void)
Definition: SDL_cpuinfo.c:597
#define CPU_haveMMX()
Definition: SDL_cpuinfo.c:412
#define CPU_haveSSE2()
Definition: SDL_cpuinfo.c:414
SDL_bool SDL_HasRDTSC(void)
Definition: SDL_cpuinfo.c:681
#define CPU_haveRDTSC()
Definition: SDL_cpuinfo.c:411
#define CPU_HAS_AVX
Definition: SDL_cpuinfo.c:95
static int SDL_CPUCount
Definition: SDL_cpuinfo.c:444
SDL_bool SDL_HasSSE(void)
Definition: SDL_cpuinfo.c:705
static int CPU_haveAltiVec(void)
Definition: SDL_cpuinfo.c:300
static Uint32 SDL_GetCPUFeatures(void)
Definition: SDL_cpuinfo.c:618
#define CPU_HAS_AVX512F
Definition: SDL_cpuinfo.c:98
static int CPU_CPUIDFeatures[4]
Definition: SDL_cpuinfo.c:254
SDL_bool SDL_Has3DNow(void)
Definition: SDL_cpuinfo.c:699
static int CPU_haveNEON(void)
Definition: SDL_cpuinfo.c:350
static int SDL_SystemRAM
Definition: SDL_cpuinfo.c:758
#define CPU_HAS_3DNOW
Definition: SDL_cpuinfo.c:89
#define SDL_CACHELINE_SIZE
Definition: SDL_cpuinfo.h:114
#define SDL_malloc
#define SDL_strlcpy
#define SDL_free
#define SDL_strcmp
SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char const char SDL_SCANF_FORMAT_STRING const char return SDL_ThreadFunction const char void return Uint32 return Uint32 void
SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char const char SDL_SCANF_FORMAT_STRING const char return SDL_ThreadFunction const char void return Uint32 return Uint32 SDL_AssertionHandler void SDL_SpinLock SDL_atomic_t int int return SDL_atomic_t return void void void return void return int return SDL_AudioSpec SDL_AudioSpec return int int return return int SDL_RWops int SDL_AudioSpec Uint8 ** d
#define main
Definition: SDL_main.h:109
GLboolean GLboolean GLboolean b
GLenum GLsizei len
GLboolean GLboolean GLboolean GLboolean a
const GLubyte * c
GLuint in
GLsizeiptr size
GLuint GLsizei GLsizei * length
GLsizei const GLfloat * value
GLfloat GLfloat GLfloat GLfloat h
#define pop
Definition: SDL_qsort.c:192
SDL_bool
Definition: SDL_stdinc.h:162
@ SDL_TRUE
Definition: SDL_stdinc.h:164
@ SDL_FALSE
Definition: SDL_stdinc.h:163
uint32_t Uint32
Definition: SDL_stdinc.h:203
uint64_t Uint64
Definition: SDL_stdinc.h:216
#define SDL_max(x, y)
Definition: SDL_stdinc.h:407
uint8_t Uint8
Definition: SDL_stdinc.h:179
int64_t Sint64
Definition: SDL_stdinc.h:210
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:50
#define NULL
Definition: begin_code.h:167
int done
Definition: checkkeys.c:28
GLuint64 GLenum GLint fd
Definition: gl2ext.h:1508
SDL_bool retval