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