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