SDL  2.0
SDL_cpuinfo.c
Go to the documentation of this file.
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 #if (defined(__LINUX__) || defined(__ANDROID__)) && defined(__ARM_ARCH)
54 /*#include <asm/hwcap.h>*/
55 #ifndef AT_HWCAP
56 #define AT_HWCAP 16
57 #endif
58 #ifndef HWCAP_NEON
59 #define HWCAP_NEON (1 << 12)
60 #endif
61 #if defined HAVE_GETAUXVAL
62 #include <sys/auxv.h>
63 #else
64 #include <fcntl.h>
65 #endif
66 #endif
67 
68 #define CPU_HAS_RDTSC 0x00000001
69 #define CPU_HAS_ALTIVEC 0x00000002
70 #define CPU_HAS_MMX 0x00000004
71 #define CPU_HAS_3DNOW 0x00000008
72 #define CPU_HAS_SSE 0x00000010
73 #define CPU_HAS_SSE2 0x00000020
74 #define CPU_HAS_SSE3 0x00000040
75 #define CPU_HAS_SSE41 0x00000100
76 #define CPU_HAS_SSE42 0x00000200
77 #define CPU_HAS_AVX 0x00000400
78 #define CPU_HAS_AVX2 0x00000800
79 #define CPU_HAS_NEON 0x00001000
80 #define CPU_HAS_ARM_SIMD 0x00002000
81 
82 #if SDL_ALTIVEC_BLITTERS && HAVE_SETJMP && !__MACOSX__ && !__OpenBSD__
83 /* This is the brute force way of detecting instruction sets...
84  the idea is borrowed from the libmpeg2 library - thanks!
85  */
86 static jmp_buf jmpbuf;
87 static void
88 illegal_instruction(int sig)
89 {
90  longjmp(jmpbuf, 1);
91 }
92 #endif /* HAVE_SETJMP */
93 
94 static int
96 {
97  int has_CPUID = 0;
98 /* *INDENT-OFF* */
99 #ifndef SDL_CPUINFO_DISABLED
100 #if defined(__GNUC__) && defined(i386)
101  __asm__ (
102 " pushfl # Get original EFLAGS \n"
103 " popl %%eax \n"
104 " movl %%eax,%%ecx \n"
105 " xorl $0x200000,%%eax # Flip ID bit in EFLAGS \n"
106 " pushl %%eax # Save new EFLAGS value on stack \n"
107 " popfl # Replace current EFLAGS value \n"
108 " pushfl # Get new EFLAGS \n"
109 " popl %%eax # Store new EFLAGS in EAX \n"
110 " xorl %%ecx,%%eax # Can not toggle ID bit, \n"
111 " jz 1f # Processor=80486 \n"
112 " movl $1,%0 # We have CPUID support \n"
113 "1: \n"
114  : "=m" (has_CPUID)
115  :
116  : "%eax", "%ecx"
117  );
118 #elif defined(__GNUC__) && defined(__x86_64__)
119 /* Technically, if this is being compiled under __x86_64__ then it has
120  CPUid by definition. But it's nice to be able to prove it. :) */
121  __asm__ (
122 " pushfq # Get original EFLAGS \n"
123 " popq %%rax \n"
124 " movq %%rax,%%rcx \n"
125 " xorl $0x200000,%%eax # Flip ID bit in EFLAGS \n"
126 " pushq %%rax # Save new EFLAGS value on stack \n"
127 " popfq # Replace current EFLAGS value \n"
128 " pushfq # Get new EFLAGS \n"
129 " popq %%rax # Store new EFLAGS in EAX \n"
130 " xorl %%ecx,%%eax # Can not toggle ID bit, \n"
131 " jz 1f # Processor=80486 \n"
132 " movl $1,%0 # We have CPUID support \n"
133 "1: \n"
134  : "=m" (has_CPUID)
135  :
136  : "%rax", "%rcx"
137  );
138 #elif (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
139  __asm {
140  pushfd ; Get original EFLAGS
141  pop eax
142  mov ecx, eax
143  xor eax, 200000h ; Flip ID bit in EFLAGS
144  push eax ; Save new EFLAGS value on stack
145  popfd ; Replace current EFLAGS value
146  pushfd ; Get new EFLAGS
147  pop eax ; Store new EFLAGS in EAX
148  xor eax, ecx ; Can not toggle ID bit,
149  jz done ; Processor=80486
150  mov has_CPUID,1 ; We have CPUID support
151 done:
152  }
153 #elif defined(_MSC_VER) && defined(_M_X64)
154  has_CPUID = 1;
155 #elif defined(__sun) && defined(__i386)
156  __asm (
157 " pushfl \n"
158 " popl %eax \n"
159 " movl %eax,%ecx \n"
160 " xorl $0x200000,%eax \n"
161 " pushl %eax \n"
162 " popfl \n"
163 " pushfl \n"
164 " popl %eax \n"
165 " xorl %ecx,%eax \n"
166 " jz 1f \n"
167 " movl $1,-8(%ebp) \n"
168 "1: \n"
169  );
170 #elif defined(__sun) && defined(__amd64)
171  __asm (
172 " pushfq \n"
173 " popq %rax \n"
174 " movq %rax,%rcx \n"
175 " xorl $0x200000,%eax \n"
176 " pushq %rax \n"
177 " popfq \n"
178 " pushfq \n"
179 " popq %rax \n"
180 " xorl %ecx,%eax \n"
181 " jz 1f \n"
182 " movl $1,-8(%rbp) \n"
183 "1: \n"
184  );
185 #endif
186 #endif
187 /* *INDENT-ON* */
188  return has_CPUID;
189 }
190 
191 #if defined(__GNUC__) && defined(i386)
192 #define cpuid(func, a, b, c, d) \
193  __asm__ __volatile__ ( \
194 " pushl %%ebx \n" \
195 " xorl %%ecx,%%ecx \n" \
196 " cpuid \n" \
197 " movl %%ebx, %%esi \n" \
198 " popl %%ebx \n" : \
199  "=a" (a), "=S" (b), "=c" (c), "=d" (d) : "a" (func))
200 #elif defined(__GNUC__) && defined(__x86_64__)
201 #define cpuid(func, a, b, c, d) \
202  __asm__ __volatile__ ( \
203 " pushq %%rbx \n" \
204 " xorq %%rcx,%%rcx \n" \
205 " cpuid \n" \
206 " movq %%rbx, %%rsi \n" \
207 " popq %%rbx \n" : \
208  "=a" (a), "=S" (b), "=c" (c), "=d" (d) : "a" (func))
209 #elif (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
210 #define cpuid(func, a, b, c, d) \
211  __asm { \
212  __asm mov eax, func \
213  __asm xor ecx, ecx \
214  __asm cpuid \
215  __asm mov a, eax \
216  __asm mov b, ebx \
217  __asm mov c, ecx \
218  __asm mov d, edx \
219 }
220 #elif defined(_MSC_VER) && defined(_M_X64)
221 #define cpuid(func, a, b, c, d) \
222 { \
223  int CPUInfo[4]; \
224  __cpuid(CPUInfo, func); \
225  a = CPUInfo[0]; \
226  b = CPUInfo[1]; \
227  c = CPUInfo[2]; \
228  d = CPUInfo[3]; \
229 }
230 #else
231 #define cpuid(func, a, b, c, d) \
232  a = b = c = d = 0
233 #endif
234 
235 static int
237 {
238  int features = 0;
239  int a, b, c, d;
240 
241  cpuid(0, a, b, c, d);
242  if (a >= 1) {
243  cpuid(1, a, b, c, d);
244  features = d;
245  }
246  return features;
247 }
248 
249 static SDL_bool
251 {
252  int a, b, c, d;
253 
254  /* Check to make sure we can call xgetbv */
255  cpuid(0, a, b, c, d);
256  if (a < 1) {
257  return SDL_FALSE;
258  }
259  cpuid(1, a, b, c, d);
260  if (!(c & 0x08000000)) {
261  return SDL_FALSE;
262  }
263 
264  /* Call xgetbv to see if YMM register state is saved */
265  a = 0;
266 #if defined(__GNUC__) && (defined(i386) || defined(__x86_64__))
267  asm(".byte 0x0f, 0x01, 0xd0" : "=a" (a) : "c" (0) : "%edx");
268 #elif defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64)) && (_MSC_FULL_VER >= 160040219) /* VS2010 SP1 */
269  a = (int)_xgetbv(0);
270 #elif (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
271  __asm
272  {
273  xor ecx, ecx
274  _asm _emit 0x0f _asm _emit 0x01 _asm _emit 0xd0
275  mov a, eax
276  }
277 #endif
278  return ((a & 6) == 6) ? SDL_TRUE : SDL_FALSE;
279 }
280 
281 static int
283 {
284  if (CPU_haveCPUID()) {
285  return (CPU_getCPUIDFeatures() & 0x00000010);
286  }
287  return 0;
288 }
289 
290 static int
292 {
293  volatile int altivec = 0;
294 #ifndef SDL_CPUINFO_DISABLED
295 #if (defined(__MACOSX__) && (defined(__ppc__) || defined(__ppc64__))) || (defined(__OpenBSD__) && defined(__powerpc__))
296 #ifdef __OpenBSD__
297  int selectors[2] = { CTL_MACHDEP, CPU_ALTIVEC };
298 #else
299  int selectors[2] = { CTL_HW, HW_VECTORUNIT };
300 #endif
301  int hasVectorUnit = 0;
302  size_t length = sizeof(hasVectorUnit);
303  int error = sysctl(selectors, 2, &hasVectorUnit, &length, NULL, 0);
304  if (0 == error)
305  altivec = (hasVectorUnit != 0);
306 #elif SDL_ALTIVEC_BLITTERS && HAVE_SETJMP
307  void (*handler) (int sig);
308  handler = signal(SIGILL, illegal_instruction);
309  if (setjmp(jmpbuf) == 0) {
310  asm volatile ("mtspr 256, %0\n\t" "vand %%v0, %%v0, %%v0"::"r" (-1));
311  altivec = 1;
312  }
313  signal(SIGILL, handler);
314 #endif
315 #endif
316  return altivec;
317 }
318 
319 #ifdef __linux__
320 
321 #include <unistd.h>
322 #include <sys/types.h>
323 #include <sys/stat.h>
324 #include <fcntl.h>
325 #include <elf.h>
326 
327 static SDL_bool
328 CPU_haveARMSIMD(void)
329 {
330  int arm_simd = 0;
331  int fd;
332 
333  fd = open("/proc/self/auxv", O_RDONLY);
334  if (fd >= 0)
335  {
336  Elf32_auxv_t aux;
337  while (read(fd, &aux, sizeof aux) == sizeof aux)
338  {
339  if (aux.a_type == AT_PLATFORM)
340  {
341  const char *plat = (const char *) aux.a_un.a_val;
342  arm_simd = strncmp(plat, "v6l", 3) == 0 ||
343  strncmp(plat, "v7l", 3) == 0;
344  }
345  }
346  close(fd);
347  }
348  return arm_simd;
349 }
350 
351 #else
352 
353 static SDL_bool
355 {
356 #warning SDL_HasARMSIMD is not implemented for this ARM platform. Write me.
357  return 0;
358 }
359 
360 #endif
361 
362 #if (defined(__LINUX__) || defined(__ANDROID__)) && defined(__ARM_ARCH) && !defined(HAVE_GETAUXVAL)
363 static int
364 readProcAuxvForNeon(void)
365 {
366  int neon = 0;
367  int kv[2];
368  const int fd = open("/proc/self/auxv", O_RDONLY);
369  if (fd != -1) {
370  while (read(fd, kv, sizeof (kv)) == sizeof (kv)) {
371  if (kv[0] == AT_HWCAP) {
372  neon = ((kv[1] & HWCAP_NEON) == HWCAP_NEON);
373  break;
374  }
375  }
376  close(fd);
377  }
378  return neon;
379 }
380 #endif
381 
382 
383 static int
385 {
386 /* The way you detect NEON is a privileged instruction on ARM, so you have
387  query the OS kernel in a platform-specific way. :/ */
388 #if defined(SDL_CPUINFO_DISABLED)
389  return 0; /* disabled */
390 #elif (defined(__WINDOWS__) || defined(__WINRT__)) && (defined(_M_ARM) || defined(_M_ARM64))
391 /* Visual Studio, for ARM, doesn't define __ARM_ARCH. Handle this first. */
392 /* Seems to have been removed */
393 # if !defined(PF_ARM_NEON_INSTRUCTIONS_AVAILABLE)
394 # define PF_ARM_NEON_INSTRUCTIONS_AVAILABLE 19
395 # endif
396 /* All WinRT ARM devices are required to support NEON, but just in case. */
397  return IsProcessorFeaturePresent(PF_ARM_NEON_INSTRUCTIONS_AVAILABLE) != 0;
398 #elif !defined(__ARM_ARCH)
399  return 0; /* not an ARM CPU at all. */
400 #elif __ARM_ARCH >= 8
401  return 1; /* ARMv8 always has non-optional NEON support. */
402 #elif defined(__APPLE__) && (__ARM_ARCH >= 7)
403  /* (note that sysctlbyname("hw.optional.neon") doesn't work!) */
404  return 1; /* all Apple ARMv7 chips and later have NEON. */
405 #elif defined(__APPLE__)
406  return 0; /* assume anything else from Apple doesn't have NEON. */
407 #elif defined(__QNXNTO__)
408  return SYSPAGE_ENTRY(cpuinfo)->flags & ARM_CPU_FLAG_NEON;
409 #elif (defined(__LINUX__) || defined(__ANDROID__)) && defined(HAVE_GETAUXVAL)
410  return ((getauxval(AT_HWCAP) & HWCAP_NEON) == HWCAP_NEON);
411 #elif defined(__LINUX__)
412  return readProcAuxvForNeon();
413 #elif defined(__ANDROID__)
414  /* Use NDK cpufeatures to read either /proc/self/auxv or /proc/cpuinfo */
415  {
416  AndroidCpuFamily cpu_family = android_getCpuFamily();
417  if (cpu_family == ANDROID_CPU_FAMILY_ARM) {
418  uint64_t cpu_features = android_getCpuFeatures();
419  if ((cpu_features & ANDROID_CPU_ARM_FEATURE_NEON) != 0) {
420  return 1;
421  }
422  }
423  return 0;
424  }
425 #else
426 #warning SDL_HasNEON is not implemented for this ARM platform. Write me.
427  return 0;
428 #endif
429 }
430 
431 static int
433 {
434  if (CPU_haveCPUID()) {
435  return (CPU_getCPUIDFeatures() & 0x00800000);
436  }
437  return 0;
438 }
439 
440 static int
442 {
443  if (CPU_haveCPUID()) {
444  int a, b, c, d;
445 
446  cpuid(0x80000000, a, b, c, d);
447  if (a >= 0x80000001) {
448  cpuid(0x80000001, a, b, c, d);
449  return (d & 0x80000000);
450  }
451  }
452  return 0;
453 }
454 
455 static int
457 {
458  if (CPU_haveCPUID()) {
459  return (CPU_getCPUIDFeatures() & 0x02000000);
460  }
461  return 0;
462 }
463 
464 static int
466 {
467  if (CPU_haveCPUID()) {
468  return (CPU_getCPUIDFeatures() & 0x04000000);
469  }
470  return 0;
471 }
472 
473 static int
475 {
476  if (CPU_haveCPUID()) {
477  int a, b, c, d;
478 
479  cpuid(0, a, b, c, d);
480  if (a >= 1) {
481  cpuid(1, a, b, c, d);
482  return (c & 0x00000001);
483  }
484  }
485  return 0;
486 }
487 
488 static int
490 {
491  if (CPU_haveCPUID()) {
492  int a, b, c, d;
493 
494  cpuid(0, a, b, c, d);
495  if (a >= 1) {
496  cpuid(1, a, b, c, d);
497  return (c & 0x00080000);
498  }
499  }
500  return 0;
501 }
502 
503 static int
505 {
506  if (CPU_haveCPUID()) {
507  int a, b, c, d;
508 
509  cpuid(0, a, b, c, d);
510  if (a >= 1) {
511  cpuid(1, a, b, c, d);
512  return (c & 0x00100000);
513  }
514  }
515  return 0;
516 }
517 
518 static int
520 {
521  if (CPU_haveCPUID() && CPU_OSSavesYMM()) {
522  int a, b, c, d;
523 
524  cpuid(0, a, b, c, d);
525  if (a >= 1) {
526  cpuid(1, a, b, c, d);
527  return (c & 0x10000000);
528  }
529  }
530  return 0;
531 }
532 
533 static int
535 {
536  if (CPU_haveCPUID() && CPU_OSSavesYMM()) {
537  int a, b, c, d;
538 
539  cpuid(0, a, b, c, d);
540  if (a >= 7) {
541  cpuid(7, a, b, c, d);
542  return (b & 0x00000020);
543  }
544  }
545  return 0;
546 }
547 
548 static int SDL_CPUCount = 0;
549 
550 int
552 {
553  if (!SDL_CPUCount) {
554 #ifndef SDL_CPUINFO_DISABLED
555 #if defined(HAVE_SYSCONF) && defined(_SC_NPROCESSORS_ONLN)
556  if (SDL_CPUCount <= 0) {
557  SDL_CPUCount = (int)sysconf(_SC_NPROCESSORS_ONLN);
558  }
559 #endif
560 #ifdef HAVE_SYSCTLBYNAME
561  if (SDL_CPUCount <= 0) {
562  size_t size = sizeof(SDL_CPUCount);
563  sysctlbyname("hw.ncpu", &SDL_CPUCount, &size, NULL, 0);
564  }
565 #endif
566 #ifdef __WIN32__
567  if (SDL_CPUCount <= 0) {
568  SYSTEM_INFO info;
569  GetSystemInfo(&info);
570  SDL_CPUCount = info.dwNumberOfProcessors;
571  }
572 #endif
573 #endif
574  /* There has to be at least 1, right? :) */
575  if (SDL_CPUCount <= 0) {
576  SDL_CPUCount = 1;
577  }
578  }
579  return SDL_CPUCount;
580 }
581 
582 /* Oh, such a sweet sweet trick, just not very useful. :) */
583 static const char *
585 {
586  static char SDL_CPUType[13];
587 
588  if (!SDL_CPUType[0]) {
589  int i = 0;
590 
591  if (CPU_haveCPUID()) {
592  int a, b, c, d;
593  cpuid(0x00000000, a, b, c, d);
594  (void) a;
595  SDL_CPUType[i++] = (char)(b & 0xff); b >>= 8;
596  SDL_CPUType[i++] = (char)(b & 0xff); b >>= 8;
597  SDL_CPUType[i++] = (char)(b & 0xff); b >>= 8;
598  SDL_CPUType[i++] = (char)(b & 0xff);
599 
600  SDL_CPUType[i++] = (char)(d & 0xff); d >>= 8;
601  SDL_CPUType[i++] = (char)(d & 0xff); d >>= 8;
602  SDL_CPUType[i++] = (char)(d & 0xff); d >>= 8;
603  SDL_CPUType[i++] = (char)(d & 0xff);
604 
605  SDL_CPUType[i++] = (char)(c & 0xff); c >>= 8;
606  SDL_CPUType[i++] = (char)(c & 0xff); c >>= 8;
607  SDL_CPUType[i++] = (char)(c & 0xff); c >>= 8;
608  SDL_CPUType[i++] = (char)(c & 0xff);
609  }
610  if (!SDL_CPUType[0]) {
611  SDL_strlcpy(SDL_CPUType, "Unknown", sizeof(SDL_CPUType));
612  }
613  }
614  return SDL_CPUType;
615 }
616 
617 
618 #ifdef TEST_MAIN /* !!! FIXME: only used for test at the moment. */
619 static const char *
620 SDL_GetCPUName(void)
621 {
622  static char SDL_CPUName[48];
623 
624  if (!SDL_CPUName[0]) {
625  int i = 0;
626  int a, b, c, d;
627 
628  if (CPU_haveCPUID()) {
629  cpuid(0x80000000, a, b, c, d);
630  if (a >= 0x80000004) {
631  cpuid(0x80000002, a, b, c, d);
632  SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
633  SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
634  SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
635  SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
636  SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
637  SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
638  SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
639  SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
640  SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
641  SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
642  SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
643  SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
644  SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
645  SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
646  SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
647  SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
648  cpuid(0x80000003, a, b, c, d);
649  SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
650  SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
651  SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
652  SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
653  SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
654  SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
655  SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
656  SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
657  SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
658  SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
659  SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
660  SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
661  SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
662  SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
663  SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
664  SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
665  cpuid(0x80000004, a, b, c, d);
666  SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
667  SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
668  SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
669  SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
670  SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
671  SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
672  SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
673  SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
674  SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
675  SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
676  SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
677  SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
678  SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
679  SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
680  SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
681  SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
682  }
683  }
684  if (!SDL_CPUName[0]) {
685  SDL_strlcpy(SDL_CPUName, "Unknown", sizeof(SDL_CPUName));
686  }
687  }
688  return SDL_CPUName;
689 }
690 #endif
691 
692 int
694 {
695  const char *cpuType = SDL_GetCPUType();
696  int a, b, c, d;
697  (void) a; (void) b; (void) c; (void) d;
698  if (SDL_strcmp(cpuType, "GenuineIntel") == 0) {
699  cpuid(0x00000001, a, b, c, d);
700  return (((b >> 8) & 0xff) * 8);
701  } else if (SDL_strcmp(cpuType, "AuthenticAMD") == 0) {
702  cpuid(0x80000005, a, b, c, d);
703  return (c & 0xff);
704  } else {
705  /* Just make a guess here... */
706  return SDL_CACHELINE_SIZE;
707  }
708 }
709 
710 static Uint32 SDL_CPUFeatures = 0xFFFFFFFF;
711 
712 static Uint32
714 {
715  if (SDL_CPUFeatures == 0xFFFFFFFF) {
716  SDL_CPUFeatures = 0;
717  if (CPU_haveRDTSC()) {
719  }
720  if (CPU_haveAltiVec()) {
722  }
723  if (CPU_haveMMX()) {
725  }
726  if (CPU_have3DNow()) {
728  }
729  if (CPU_haveSSE()) {
731  }
732  if (CPU_haveSSE2()) {
734  }
735  if (CPU_haveSSE3()) {
737  }
738  if (CPU_haveSSE41()) {
740  }
741  if (CPU_haveSSE42()) {
743  }
744  if (CPU_haveAVX()) {
746  }
747  if (CPU_haveAVX2()) {
749  }
750  if (CPU_haveARMSIMD()) {
752  }
753  if (CPU_haveNEON()) {
755  }
756  }
757  return SDL_CPUFeatures;
758 }
759 
760 SDL_bool
762 {
764  return SDL_TRUE;
765  }
766  return SDL_FALSE;
767 }
768 
769 SDL_bool
771 {
773  return SDL_TRUE;
774  }
775  return SDL_FALSE;
776 }
777 
778 SDL_bool
780 {
782  return SDL_TRUE;
783  }
784  return SDL_FALSE;
785 }
786 
787 SDL_bool
789 {
791  return SDL_TRUE;
792  }
793  return SDL_FALSE;
794 }
795 
796 SDL_bool
798 {
800  return SDL_TRUE;
801  }
802  return SDL_FALSE;
803 }
804 
805 SDL_bool
807 {
809  return SDL_TRUE;
810  }
811  return SDL_FALSE;
812 }
813 
814 SDL_bool
816 {
818  return SDL_TRUE;
819  }
820  return SDL_FALSE;
821 }
822 
823 SDL_bool
825 {
827  return SDL_TRUE;
828  }
829  return SDL_FALSE;
830 }
831 
832 SDL_bool
834 {
836  return SDL_TRUE;
837  }
838  return SDL_FALSE;
839 }
840 
841 SDL_bool
843 {
845  return SDL_TRUE;
846  }
847  return SDL_FALSE;
848 }
849 
850 SDL_bool
852 {
854  return SDL_TRUE;
855  }
856  return SDL_FALSE;
857 }
858 
859 SDL_bool
861 {
863  return SDL_TRUE;
864  }
865  return SDL_FALSE;
866 }
867 
868 SDL_bool
870 {
872  return SDL_TRUE;
873  }
874  return SDL_FALSE;
875 }
876 
877 static int SDL_SystemRAM = 0;
878 
879 int
881 {
882  if (!SDL_SystemRAM) {
883 #ifndef SDL_CPUINFO_DISABLED
884 #if defined(HAVE_SYSCONF) && defined(_SC_PHYS_PAGES) && defined(_SC_PAGESIZE)
885  if (SDL_SystemRAM <= 0) {
886  SDL_SystemRAM = (int)((Sint64)sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGESIZE) / (1024*1024));
887  }
888 #endif
889 #ifdef HAVE_SYSCTLBYNAME
890  if (SDL_SystemRAM <= 0) {
891 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__)
892 #ifdef HW_REALMEM
893  int mib[2] = {CTL_HW, HW_REALMEM};
894 #else
895  /* might only report up to 2 GiB */
896  int mib[2] = {CTL_HW, HW_PHYSMEM};
897 #endif /* HW_REALMEM */
898 #else
899  int mib[2] = {CTL_HW, HW_MEMSIZE};
900 #endif /* __FreeBSD__ || __FreeBSD_kernel__ */
901  Uint64 memsize = 0;
902  size_t len = sizeof(memsize);
903 
904  if (sysctl(mib, 2, &memsize, &len, NULL, 0) == 0) {
905  SDL_SystemRAM = (int)(memsize / (1024*1024));
906  }
907  }
908 #endif
909 #ifdef __WIN32__
910  if (SDL_SystemRAM <= 0) {
911  MEMORYSTATUSEX stat;
912  stat.dwLength = sizeof(stat);
913  if (GlobalMemoryStatusEx(&stat)) {
914  SDL_SystemRAM = (int)(stat.ullTotalPhys / (1024 * 1024));
915  }
916  }
917 #endif
918 #endif
919  }
920  return SDL_SystemRAM;
921 }
922 
923 
924 #ifdef TEST_MAIN
925 
926 #include <stdio.h>
927 
928 int
929 main()
930 {
931  printf("CPU count: %d\n", SDL_GetCPUCount());
932  printf("CPU type: %s\n", SDL_GetCPUType());
933  printf("CPU name: %s\n", SDL_GetCPUName());
934  printf("CacheLine size: %d\n", SDL_GetCPUCacheLineSize());
935  printf("RDTSC: %d\n", SDL_HasRDTSC());
936  printf("Altivec: %d\n", SDL_HasAltiVec());
937  printf("MMX: %d\n", SDL_HasMMX());
938  printf("3DNow: %d\n", SDL_Has3DNow());
939  printf("SSE: %d\n", SDL_HasSSE());
940  printf("SSE2: %d\n", SDL_HasSSE2());
941  printf("SSE3: %d\n", SDL_HasSSE3());
942  printf("SSE4.1: %d\n", SDL_HasSSE41());
943  printf("SSE4.2: %d\n", SDL_HasSSE42());
944  printf("AVX: %d\n", SDL_HasAVX());
945  printf("AVX2: %d\n", SDL_HasAVX2());
946  printf("ARM SIMD: %d\n", SDL_HasARMSIMD());
947  printf("NEON: %d\n", SDL_HasNEON());
948  printf("RAM: %d MB\n", SDL_GetSystemRAM());
949  return 0;
950 }
951 
952 #endif /* TEST_MAIN */
953 
954 /* vi: set ts=4 sw=4 expandtab: */
#define CPU_HAS_SSE41
Definition: SDL_cpuinfo.c:75
#define SDL_strlcpy
#define CPU_HAS_RDTSC
Definition: SDL_cpuinfo.c:68
#define CPU_HAS_SSE3
Definition: SDL_cpuinfo.c:74
static int CPU_haveSSE42(void)
Definition: SDL_cpuinfo.c:504
SDL_bool SDL_HasSSE41(void)
Definition: SDL_cpuinfo.c:824
int SDL_GetCPUCount(void)
Definition: SDL_cpuinfo.c:551
static int CPU_haveAVX(void)
Definition: SDL_cpuinfo.c:519
static const char * SDL_GetCPUType(void)
Definition: SDL_cpuinfo.c:584
static int CPU_haveRDTSC(void)
Definition: SDL_cpuinfo.c:282
#define CPU_HAS_SSE2
Definition: SDL_cpuinfo.c:73
unsigned long long uint64_t
static SDL_bool CPU_OSSavesYMM(void)
Definition: SDL_cpuinfo.c:250
SDL_bool SDL_HasSSE(void)
Definition: SDL_cpuinfo.c:797
SDL_bool SDL_HasSSE3(void)
Definition: SDL_cpuinfo.c:815
static SDL_bool CPU_haveARMSIMD(void)
Definition: SDL_cpuinfo.c:354
static int CPU_have3DNow(void)
Definition: SDL_cpuinfo.c:441
uint32_t Uint32
An unsigned 32-bit integer type.
Definition: SDL_stdinc.h:159
SDL_bool SDL_HasAltiVec(void)
Definition: SDL_cpuinfo.c:770
#define CPU_HAS_ALTIVEC
Definition: SDL_cpuinfo.c:69
static int SDL_SystemRAM
Definition: SDL_cpuinfo.c:877
static int CPU_haveCPUID(void)
Definition: SDL_cpuinfo.c:95
uint64_t Uint64
An unsigned 64-bit integer type.
Definition: SDL_stdinc.h:168
SDL_bool SDL_HasSSE42(void)
Definition: SDL_cpuinfo.c:833
GLenum GLsizei len
SDL_bool SDL_HasARMSIMD(void)
Definition: SDL_cpuinfo.c:860
SDL_bool SDL_HasMMX(void)
Definition: SDL_cpuinfo.c:779
SDL_bool SDL_HasAVX2(void)
Definition: SDL_cpuinfo.c:851
static int CPU_haveAltiVec(void)
Definition: SDL_cpuinfo.c:291
#define CPU_HAS_AVX
Definition: SDL_cpuinfo.c:77
set set set set set set set set set set set set set set set set set set set set *set set set macro pixldst op &r &cond WK op &r &cond WK op &r &cond WK else op &m &cond &ia op &r &cond WK else op &m &cond &ia elseif elseif else error unsupported base if elseif elseif else error unsupported unaligned pixldst unaligned endm macro pixst base base else pixldst base endif endm macro PF base if bpp PF set rept prefetch_distance PF set OFFSET endr endif endm macro preload_leading_step2 base if bpp ifc DST PF PF else if bpp lsl PF PF lsl PF PF lsl PF PF PF else PF mov
static int CPU_haveSSE3(void)
Definition: SDL_cpuinfo.c:474
#define CPU_HAS_NEON
Definition: SDL_cpuinfo.c:79
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
GLsizei const GLfloat * value
#define pop
Definition: SDL_qsort.c:192
#define CPU_HAS_ARM_SIMD
Definition: SDL_cpuinfo.c:80
int done
Definition: checkkeys.c:28
SDL_bool SDL_HasNEON(void)
Definition: SDL_cpuinfo.c:869
#define SDL_CACHELINE_SIZE
Definition: SDL_cpuinfo.h:77
const GLubyte * c
#define cpuid(func, a, b, c, d)
Definition: SDL_cpuinfo.c:231
SDL_bool SDL_HasAVX(void)
Definition: SDL_cpuinfo.c:842
static Uint32 SDL_CPUFeatures
Definition: SDL_cpuinfo.c:710
static int CPU_haveSSE(void)
Definition: SDL_cpuinfo.c:456
static Uint32 SDL_GetCPUFeatures(void)
Definition: SDL_cpuinfo.c:713
#define CPU_HAS_SSE
Definition: SDL_cpuinfo.c:72
static int CPU_haveAVX2(void)
Definition: SDL_cpuinfo.c:534
GLsizeiptr size
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 CPU_HAS_AVX2
Definition: SDL_cpuinfo.c:78
#define NULL
Definition: begin_code.h:143
SDL_bool
Definition: SDL_stdinc.h:130
static int CPU_haveNEON(void)
Definition: SDL_cpuinfo.c:384
SDL_bool SDL_HasRDTSC(void)
Definition: SDL_cpuinfo.c:761
#define CPU_HAS_MMX
Definition: SDL_cpuinfo.c:70
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
static int CPU_getCPUIDFeatures(void)
Definition: SDL_cpuinfo.c:236
int SDL_GetSystemRAM(void)
Definition: SDL_cpuinfo.c:880
static int SDL_CPUCount
Definition: SDL_cpuinfo.c:548
#define main
Definition: SDL_main.h:104
#define CPU_HAS_SSE42
Definition: SDL_cpuinfo.c:76
#define SDL_strcmp
int64_t Sint64
A signed 64-bit integer type.
Definition: SDL_stdinc.h:164
GLuint GLsizei GLsizei * length
GLboolean GLboolean GLboolean GLboolean a
SDL_bool SDL_HasSSE2(void)
Definition: SDL_cpuinfo.c:806
GLuint in
#define CPU_HAS_3DNOW
Definition: SDL_cpuinfo.c:71
static int CPU_haveSSE41(void)
Definition: SDL_cpuinfo.c:489
static int CPU_haveMMX(void)
Definition: SDL_cpuinfo.c:432
GLboolean GLboolean GLboolean b
static int CPU_haveSSE2(void)
Definition: SDL_cpuinfo.c:465
SDL_bool SDL_Has3DNow(void)
Definition: SDL_cpuinfo.c:788
GLfloat GLfloat GLfloat GLfloat h
int SDL_GetCPUCacheLineSize(void)
Definition: SDL_cpuinfo.c:693