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  */
104 static jmp_buf jmpbuf;
105 static void
106 illegal_instruction(int sig)
107 {
108  longjmp(jmpbuf, 1);
109 }
110 #endif /* HAVE_SETJMP */
111 
112 static 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
170 done:
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 
254 static int CPU_CPUIDFeatures[4];
255 static int CPU_CPUIDMaxFunction = 0;
258 
259 static 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 
299 static 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)
329 static int
330 readProcAuxvForNeon(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 
349 static 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 
397 static 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 
420 static 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 
432 static 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 
444 static int SDL_CPUCount = 0;
445 
446 int
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. :) */
485 static 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. */
522 static const char *
523 SDL_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 
596 int
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 
614 static Uint32 SDL_CPUFeatures = 0xFFFFFFFF;
615 static Uint32 SDL_SIMDAlignment = 0xFFFFFFFF;
616 
617 static 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 
686 SDL_bool
688 {
690 }
691 
692 SDL_bool
694 {
696 }
697 
698 SDL_bool
700 {
702 }
703 
704 SDL_bool
706 {
708 }
709 
710 SDL_bool
712 {
714 }
715 
716 SDL_bool
718 {
720 }
721 
722 SDL_bool
724 {
726 }
727 
728 SDL_bool
730 {
732 }
733 
734 SDL_bool
736 {
738 }
739 
740 SDL_bool
742 {
744 }
745 
746 SDL_bool
748 {
750 }
751 
752 SDL_bool
754 {
756 }
757 
758 static int SDL_SystemRAM = 0;
759 
760 int
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 
812 size_t
814 {
815  if (SDL_SIMDAlignment == 0xFFFFFFFF) {
816  SDL_GetCPUFeatures(); /* make sure this has been calculated */
817  }
819  return SDL_SIMDAlignment;
820 }
821 
822 void *
823 SDL_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 
839 void
840 SDL_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 
854 int
855 main()
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: */
CPU_haveMMX
#define CPU_haveMMX()
Definition: SDL_cpuinfo.c:412
SDL_HasSSE42
SDL_bool SDL_HasSSE42(void)
Definition: SDL_cpuinfo.c:729
SDL_CACHELINE_SIZE
#define SDL_CACHELINE_SIZE
Definition: SDL_cpuinfo.h:114
CPU_OSSavesZMM
static SDL_bool CPU_OSSavesZMM
Definition: SDL_cpuinfo.c:257
CPU_haveAltiVec
static int CPU_haveAltiVec(void)
Definition: SDL_cpuinfo.c:300
SDL_GetCPUType
static const char * SDL_GetCPUType(void)
Definition: SDL_cpuinfo.c:486
SDL_strlcpy
#define SDL_strlcpy
Definition: SDL_dynapi_overrides.h:394
SDL_HasAVX
SDL_bool SDL_HasAVX(void)
Definition: SDL_cpuinfo.c:735
SDL_CPUFeatures
static Uint32 SDL_CPUFeatures
Definition: SDL_cpuinfo.c:614
SDL_GetCPUFeatures
static Uint32 SDL_GetCPUFeatures(void)
Definition: SDL_cpuinfo.c:618
CPU_HAS_SSE
#define CPU_HAS_SSE
Definition: SDL_cpuinfo.c:90
NULL
#define NULL
Definition: begin_code.h:167
b
GLboolean GLboolean GLboolean b
Definition: SDL_opengl_glext.h:1109
CPU_haveAVX
#define CPU_haveAVX()
Definition: SDL_cpuinfo.c:418
CPU_HAS_SSE41
#define CPU_HAS_SSE41
Definition: SDL_cpuinfo.c:93
CPU_HAS_AVX2
#define CPU_HAS_AVX2
Definition: SDL_cpuinfo.c:96
CPU_HAS_ALTIVEC
#define CPU_HAS_ALTIVEC
Definition: SDL_cpuinfo.c:87
SDL_SystemRAM
static int SDL_SystemRAM
Definition: SDL_cpuinfo.c:758
CPU_haveCPUID
static int CPU_haveCPUID(void)
Definition: SDL_cpuinfo.c:113
SDL_HasSSE2
SDL_bool SDL_HasSSE2(void)
Definition: SDL_cpuinfo.c:711
CPU_HAS_3DNOW
#define CPU_HAS_3DNOW
Definition: SDL_cpuinfo.c:89
CPU_FEATURE_AVAILABLE
#define CPU_FEATURE_AVAILABLE(f)
Definition: SDL_cpuinfo.c:679
a
GLboolean GLboolean GLboolean GLboolean a
Definition: SDL_opengl_glext.h:1109
h
GLfloat GLfloat GLfloat GLfloat h
Definition: SDL_opengl_glext.h:1946
length
GLuint GLsizei GLsizei * length
Definition: SDL_opengl_glext.h:669
main
#define main
Definition: SDL_main.h:109
c
const GLubyte * c
Definition: SDL_opengl_glext.h:11093
CPU_HAS_NEON
#define CPU_HAS_NEON
Definition: SDL_cpuinfo.c:97
CPU_HAS_SSE42
#define CPU_HAS_SSE42
Definition: SDL_cpuinfo.c:94
SDL_SIMDAlignment
static Uint32 SDL_SIMDAlignment
Definition: SDL_cpuinfo.c:615
CPU_haveSSE
#define CPU_haveSSE()
Definition: SDL_cpuinfo.c:413
len
GLenum GLsizei len
Definition: SDL_opengl_glext.h:2926
Uint8
uint8_t Uint8
Definition: SDL_stdinc.h:179
done
int done
Definition: checkkeys.c:28
retval
SDL_bool retval
Definition: testgamecontroller.c:65
SDL_GetCPUCount
int SDL_GetCPUCount(void)
Definition: SDL_cpuinfo.c:447
SDL_GetCPUCacheLineSize
int SDL_GetCPUCacheLineSize(void)
Definition: SDL_cpuinfo.c:597
SDL_free
#define SDL_free
Definition: SDL_dynapi_overrides.h:377
SDL_max
#define SDL_max(x, y)
Definition: SDL_stdinc.h:407
in
GLuint in
Definition: SDL_opengl_glext.h:7940
SDL_cpuinfo.h
SDL_FALSE
Definition: SDL_stdinc.h:163
CPU_HAS_SSE2
#define CPU_HAS_SSE2
Definition: SDL_cpuinfo.c:91
CPU_haveSSE41
#define CPU_haveSSE41()
Definition: SDL_cpuinfo.c:416
SDL_GetSystemRAM
int SDL_GetSystemRAM(void)
Definition: SDL_cpuinfo.c:761
CPU_HAS_RDTSC
#define CPU_HAS_RDTSC
Definition: SDL_cpuinfo.c:86
CPU_HAS_AVX512F
#define CPU_HAS_AVX512F
Definition: SDL_cpuinfo.c:98
SDL_assert.h
CPU_haveNEON
static int CPU_haveNEON(void)
Definition: SDL_cpuinfo.c:350
SDL_SIMDGetAlignment
size_t SDL_SIMDGetAlignment(void)
Report the alignment this system needs for SIMD allocations.
Definition: SDL_cpuinfo.c:813
SDL_HasSSE3
SDL_bool SDL_HasSSE3(void)
Definition: SDL_cpuinfo.c:717
SDL_HasRDTSC
SDL_bool SDL_HasRDTSC(void)
Definition: SDL_cpuinfo.c:681
pop
#define pop
Definition: SDL_qsort.c:192
CPU_HAS_MMX
#define CPU_HAS_MMX
Definition: SDL_cpuinfo.c:88
SDL_SIMDAlloc
void * SDL_SIMDAlloc(const size_t len)
Allocate memory in a SIMD-friendly way.
Definition: SDL_cpuinfo.c:823
SDL_assert
#define SDL_assert(condition)
Definition: SDL_assert.h:169
SDL_Has3DNow
SDL_bool SDL_Has3DNow(void)
Definition: SDL_cpuinfo.c:699
CPU_calcCPUIDFeatures
static void CPU_calcCPUIDFeatures(void)
Definition: SDL_cpuinfo.c:260
size
GLsizeiptr size
Definition: SDL_opengl_glext.h:537
SDL_bool
SDL_bool
Definition: SDL_stdinc.h:161
CPU_haveSSE2
#define CPU_haveSSE2()
Definition: SDL_cpuinfo.c:414
SDL_HasAVX512F
SDL_bool SDL_HasAVX512F(void)
Definition: SDL_cpuinfo.c:747
value
GLsizei const GLfloat * value
Definition: SDL_opengl_glext.h:698
CPU_CPUIDFeatures
static int CPU_CPUIDFeatures[4]
Definition: SDL_cpuinfo.c:254
Uint64
uint64_t Uint64
Definition: SDL_stdinc.h:216
CPU_haveSSE42
#define CPU_haveSSE42()
Definition: SDL_cpuinfo.c:417
SDL_TRUE
Definition: SDL_stdinc.h:164
CPU_OSSavesYMM
static SDL_bool CPU_OSSavesYMM
Definition: SDL_cpuinfo.c:256
CPU_HAS_SSE3
#define CPU_HAS_SSE3
Definition: SDL_cpuinfo.c:92
CPU_have3DNow
static int CPU_have3DNow(void)
Definition: SDL_cpuinfo.c:398
SDL_HasSSE41
SDL_bool SDL_HasSSE41(void)
Definition: SDL_cpuinfo.c:723
SDL_HasAltiVec
SDL_bool SDL_HasAltiVec(void)
Definition: SDL_cpuinfo.c:687
Uint32
uint32_t Uint32
Definition: SDL_stdinc.h:203
SDL_HasMMX
SDL_bool SDL_HasMMX(void)
Definition: SDL_cpuinfo.c:693
SDL_HasNEON
SDL_bool SDL_HasNEON(void)
Definition: SDL_cpuinfo.c:753
SDL_HasAVX2
SDL_bool SDL_HasAVX2(void)
Definition: SDL_cpuinfo.c:741
cpuid
#define cpuid(func, a, b, c, d)
Definition: SDL_cpuinfo.c:250
CPU_haveAVX512F
static int CPU_haveAVX512F(void)
Definition: SDL_cpuinfo.c:433
CPU_HAS_AVX
#define CPU_HAS_AVX
Definition: SDL_cpuinfo.c:95
SDL_malloc
#define SDL_malloc
Definition: SDL_dynapi_overrides.h:374
SDL_strcmp
#define SDL_strcmp
Definition: SDL_dynapi_overrides.h:417
fd
GLuint64 GLenum GLint fd
Definition: gl2ext.h:1508
void
const SDL_PRINTF_FORMAT_STRING char int const SDL_PRINTF_FORMAT_STRING char int const SDL_PRINTF_FORMAT_STRING char int const SDL_PRINTF_FORMAT_STRING char const char const SDL_SCANF_FORMAT_STRING char return SDL_ThreadFunction const char void return Uint32 return Uint32 void
Definition: SDL_dynapi_procs.h:89
SDL_config.h
SDL_HasSSE
SDL_bool SDL_HasSSE(void)
Definition: SDL_cpuinfo.c:705
SDL_SIMDFree
void SDL_SIMDFree(void *ptr)
Deallocate memory obtained from SDL_SIMDAlloc.
Definition: SDL_cpuinfo.c:840
size_t
unsigned int size_t
Definition: SDL_config_windows.h:68
CPU_haveAVX2
static int CPU_haveAVX2(void)
Definition: SDL_cpuinfo.c:421
uint64_t
unsigned long long uint64_t
Definition: SDL_config_windows.h:65
i
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
CPU_CPUIDMaxFunction
static int CPU_CPUIDMaxFunction
Definition: SDL_cpuinfo.c:255
Sint64
int64_t Sint64
Definition: SDL_stdinc.h:210
CPU_haveSSE3
#define CPU_haveSSE3()
Definition: SDL_cpuinfo.c:415
d
const SDL_PRINTF_FORMAT_STRING char int const SDL_PRINTF_FORMAT_STRING char int const SDL_PRINTF_FORMAT_STRING char int const SDL_PRINTF_FORMAT_STRING char const char const SDL_SCANF_FORMAT_STRING 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
Definition: SDL_dynapi_procs.h:117
SDL_CPUCount
static int SDL_CPUCount
Definition: SDL_cpuinfo.c:444
CPU_haveRDTSC
#define CPU_haveRDTSC()
Definition: SDL_cpuinfo.c:411