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 #endif
26 
27 #if defined(__WIN32__)
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 
42 #ifdef HAVE_SYSCONF
43 #include <unistd.h>
44 #endif
45 #ifdef HAVE_SYSCTLBYNAME
46 #include <sys/types.h>
47 #include <sys/sysctl.h>
48 #endif
49 #if defined(__MACOSX__) && (defined(__ppc__) || defined(__ppc64__))
50 #include <sys/sysctl.h> /* For AltiVec check */
51 #elif defined(__OpenBSD__) && defined(__powerpc__)
52 #include <sys/param.h>
53 #include <sys/sysctl.h> /* For AltiVec check */
54 #include <machine/cpu.h>
55 #elif SDL_ALTIVEC_BLITTERS && HAVE_SETJMP
56 #include <signal.h>
57 #include <setjmp.h>
58 #endif
59 
60 #if defined(__QNXNTO__)
61 #include <sys/syspage.h>
62 #endif
63 
64 #if (defined(__LINUX__) || defined(__ANDROID__)) && defined(__ARM_ARCH)
65 /*#include <asm/hwcap.h>*/
66 #ifndef AT_HWCAP
67 #define AT_HWCAP 16
68 #endif
69 #ifndef HWCAP_NEON
70 #define HWCAP_NEON (1 << 12)
71 #endif
72 #if defined HAVE_GETAUXVAL
73 #include <sys/auxv.h>
74 #else
75 #include <fcntl.h>
76 #endif
77 #endif
78 
79 #define CPU_HAS_RDTSC 0x00000001
80 #define CPU_HAS_ALTIVEC 0x00000002
81 #define CPU_HAS_MMX 0x00000004
82 #define CPU_HAS_3DNOW 0x00000008
83 #define CPU_HAS_SSE 0x00000010
84 #define CPU_HAS_SSE2 0x00000020
85 #define CPU_HAS_SSE3 0x00000040
86 #define CPU_HAS_SSE41 0x00000100
87 #define CPU_HAS_SSE42 0x00000200
88 #define CPU_HAS_AVX 0x00000400
89 #define CPU_HAS_AVX2 0x00000800
90 #define CPU_HAS_NEON 0x00001000
91 
92 #if SDL_ALTIVEC_BLITTERS && HAVE_SETJMP && !__MACOSX__ && !__OpenBSD__
93 /* This is the brute force way of detecting instruction sets...
94  the idea is borrowed from the libmpeg2 library - thanks!
95  */
96 static jmp_buf jmpbuf;
97 static void
98 illegal_instruction(int sig)
99 {
100  longjmp(jmpbuf, 1);
101 }
102 #endif /* HAVE_SETJMP */
103 
104 static int
106 {
107  int has_CPUID = 0;
108 
109 /* *INDENT-OFF* */
110 #ifndef SDL_CPUINFO_DISABLED
111 #if defined(__GNUC__) && defined(i386)
112  __asm__ (
113 " pushfl # Get original EFLAGS \n"
114 " popl %%eax \n"
115 " movl %%eax,%%ecx \n"
116 " xorl $0x200000,%%eax # Flip ID bit in EFLAGS \n"
117 " pushl %%eax # Save new EFLAGS value on stack \n"
118 " popfl # Replace current EFLAGS value \n"
119 " pushfl # Get new EFLAGS \n"
120 " popl %%eax # Store new EFLAGS in EAX \n"
121 " xorl %%ecx,%%eax # Can not toggle ID bit, \n"
122 " jz 1f # Processor=80486 \n"
123 " movl $1,%0 # We have CPUID support \n"
124 "1: \n"
125  : "=m" (has_CPUID)
126  :
127  : "%eax", "%ecx"
128  );
129 #elif defined(__GNUC__) && defined(__x86_64__)
130 /* Technically, if this is being compiled under __x86_64__ then it has
131  CPUid by definition. But it's nice to be able to prove it. :) */
132  __asm__ (
133 " pushfq # Get original EFLAGS \n"
134 " popq %%rax \n"
135 " movq %%rax,%%rcx \n"
136 " xorl $0x200000,%%eax # Flip ID bit in EFLAGS \n"
137 " pushq %%rax # Save new EFLAGS value on stack \n"
138 " popfq # Replace current EFLAGS value \n"
139 " pushfq # Get new EFLAGS \n"
140 " popq %%rax # Store new EFLAGS in EAX \n"
141 " xorl %%ecx,%%eax # Can not toggle ID bit, \n"
142 " jz 1f # Processor=80486 \n"
143 " movl $1,%0 # We have CPUID support \n"
144 "1: \n"
145  : "=m" (has_CPUID)
146  :
147  : "%rax", "%rcx"
148  );
149 #elif (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
150  __asm {
151  pushfd ; Get original EFLAGS
152  pop eax
153  mov ecx, eax
154  xor eax, 200000h ; Flip ID bit in EFLAGS
155  push eax ; Save new EFLAGS value on stack
156  popfd ; Replace current EFLAGS value
157  pushfd ; Get new EFLAGS
158  pop eax ; Store new EFLAGS in EAX
159  xor eax, ecx ; Can not toggle ID bit,
160  jz done ; Processor=80486
161  mov has_CPUID,1 ; We have CPUID support
162 done:
163  }
164 #elif defined(_MSC_VER) && defined(_M_X64)
165  has_CPUID = 1;
166 #elif defined(__sun) && defined(__i386)
167  __asm (
168 " pushfl \n"
169 " popl %eax \n"
170 " movl %eax,%ecx \n"
171 " xorl $0x200000,%eax \n"
172 " pushl %eax \n"
173 " popfl \n"
174 " pushfl \n"
175 " popl %eax \n"
176 " xorl %ecx,%eax \n"
177 " jz 1f \n"
178 " movl $1,-8(%ebp) \n"
179 "1: \n"
180  );
181 #elif defined(__sun) && defined(__amd64)
182  __asm (
183 " pushfq \n"
184 " popq %rax \n"
185 " movq %rax,%rcx \n"
186 " xorl $0x200000,%eax \n"
187 " pushq %rax \n"
188 " popfq \n"
189 " pushfq \n"
190 " popq %rax \n"
191 " xorl %ecx,%eax \n"
192 " jz 1f \n"
193 " movl $1,-8(%rbp) \n"
194 "1: \n"
195  );
196 #endif
197 #endif
198 /* *INDENT-ON* */
199  return has_CPUID;
200 }
201 
202 #if defined(__GNUC__) && defined(i386)
203 #define cpuid(func, a, b, c, d) \
204  __asm__ __volatile__ ( \
205 " pushl %%ebx \n" \
206 " xorl %%ecx,%%ecx \n" \
207 " cpuid \n" \
208 " movl %%ebx, %%esi \n" \
209 " popl %%ebx \n" : \
210  "=a" (a), "=S" (b), "=c" (c), "=d" (d) : "a" (func))
211 #elif defined(__GNUC__) && defined(__x86_64__)
212 #define cpuid(func, a, b, c, d) \
213  __asm__ __volatile__ ( \
214 " pushq %%rbx \n" \
215 " xorq %%rcx,%%rcx \n" \
216 " cpuid \n" \
217 " movq %%rbx, %%rsi \n" \
218 " popq %%rbx \n" : \
219  "=a" (a), "=S" (b), "=c" (c), "=d" (d) : "a" (func))
220 #elif (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
221 #define cpuid(func, a, b, c, d) \
222  __asm { \
223  __asm mov eax, func \
224  __asm xor ecx, ecx \
225  __asm cpuid \
226  __asm mov a, eax \
227  __asm mov b, ebx \
228  __asm mov c, ecx \
229  __asm mov d, edx \
230 }
231 #elif defined(_MSC_VER) && defined(_M_X64)
232 #define cpuid(func, a, b, c, d) \
233 { \
234  int CPUInfo[4]; \
235  __cpuid(CPUInfo, func); \
236  a = CPUInfo[0]; \
237  b = CPUInfo[1]; \
238  c = CPUInfo[2]; \
239  d = CPUInfo[3]; \
240 }
241 #else
242 #define cpuid(func, a, b, c, d) \
243  do { a = b = c = d = 0; (void) a; (void) b; (void) c; (void) d; } while (0)
244 #endif
245 
246 static int CPU_CPUIDFeatures[4];
247 static int CPU_CPUIDMaxFunction = 0;
249 
250 static void
252 {
253  static SDL_bool checked = SDL_FALSE;
254  if (!checked) {
255  checked = SDL_TRUE;
256  if (CPU_haveCPUID()) {
257  int a, b, c, d;
258  cpuid(0, a, b, c, d);
260  if (CPU_CPUIDMaxFunction >= 1) {
261  cpuid(1, a, b, c, d);
262  CPU_CPUIDFeatures[0] = a;
263  CPU_CPUIDFeatures[1] = b;
264  CPU_CPUIDFeatures[2] = c;
265  CPU_CPUIDFeatures[3] = d;
266 
267  /* Check to make sure we can call xgetbv */
268  if (c & 0x08000000) {
269  /* Call xgetbv to see if YMM register state is saved */
270 #if defined(__GNUC__) && (defined(i386) || defined(__x86_64__))
271  __asm__(".byte 0x0f, 0x01, 0xd0" : "=a" (a) : "c" (0) : "%edx");
272 #elif defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64)) && (_MSC_FULL_VER >= 160040219) /* VS2010 SP1 */
273  a = (int)_xgetbv(0);
274 #elif (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
275  __asm
276  {
277  xor ecx, ecx
278  _asm _emit 0x0f _asm _emit 0x01 _asm _emit 0xd0
279  mov a, eax
280  }
281 #endif
282  CPU_OSSavesYMM = ((a & 6) == 6) ? SDL_TRUE : SDL_FALSE;
283  }
284  }
285  }
286  }
287 }
288 
289 static int
291 {
292  volatile int altivec = 0;
293 #ifndef SDL_CPUINFO_DISABLED
294 #if (defined(__MACOSX__) && (defined(__ppc__) || defined(__ppc64__))) || (defined(__OpenBSD__) && defined(__powerpc__))
295 #ifdef __OpenBSD__
296  int selectors[2] = { CTL_MACHDEP, CPU_ALTIVEC };
297 #else
298  int selectors[2] = { CTL_HW, HW_VECTORUNIT };
299 #endif
300  int hasVectorUnit = 0;
301  size_t length = sizeof(hasVectorUnit);
302  int error = sysctl(selectors, 2, &hasVectorUnit, &length, NULL, 0);
303  if (0 == error)
304  altivec = (hasVectorUnit != 0);
305 #elif SDL_ALTIVEC_BLITTERS && HAVE_SETJMP
306  void (*handler) (int sig);
307  handler = signal(SIGILL, illegal_instruction);
308  if (setjmp(jmpbuf) == 0) {
309  asm volatile ("mtspr 256, %0\n\t" "vand %%v0, %%v0, %%v0"::"r" (-1));
310  altivec = 1;
311  }
312  signal(SIGILL, handler);
313 #endif
314 #endif
315  return altivec;
316 }
317 
318 #if (defined(__LINUX__) || defined(__ANDROID__)) && defined(__ARM_ARCH) && !defined(HAVE_GETAUXVAL)
319 static int
320 readProcAuxvForNeon(void)
321 {
322  int neon = 0;
323  int kv[2];
324  const int fd = open("/proc/self/auxv", O_RDONLY);
325  if (fd != -1) {
326  while (read(fd, kv, sizeof (kv)) == sizeof (kv)) {
327  if (kv[0] == AT_HWCAP) {
328  neon = ((kv[1] & HWCAP_NEON) == HWCAP_NEON);
329  break;
330  }
331  }
332  close(fd);
333  }
334  return neon;
335 }
336 #endif
337 
338 
339 static int
341 {
342 /* The way you detect NEON is a privileged instruction on ARM, so you have
343  query the OS kernel in a platform-specific way. :/ */
344 #if defined(SDL_CPUINFO_DISABLED) || !defined(__ARM_ARCH)
345  return 0; /* disabled or not an ARM CPU at all. */
346 #elif __ARM_ARCH >= 8
347  return 1; /* ARMv8 always has non-optional NEON support. */
348 #elif defined(__APPLE__) && (__ARM_ARCH >= 7)
349  /* (note that sysctlbyname("hw.optional.neon") doesn't work!) */
350  return 1; /* all Apple ARMv7 chips and later have NEON. */
351 #elif defined(__APPLE__)
352  return 0; /* assume anything else from Apple doesn't have NEON. */
353 #elif defined(__QNXNTO__)
354  return SYSPAGE_ENTRY(cpuinfo)->flags & ARM_CPU_FLAG_NEON;
355 #elif (defined(__LINUX__) || defined(__ANDROID__)) && defined(HAVE_GETAUXVAL)
356  return ((getauxval(AT_HWCAP) & HWCAP_NEON) == HWCAP_NEON);
357 #elif (defined(__LINUX__) || defined(__ANDROID__))
358  return readProcAuxvForNeon(); /* Android offers a static library for this, but it just parses /proc/self/auxv */
359 #elif (defined(__WINDOWS__) || defined(__WINRT__)) && defined(_M_ARM)
360  /* All WinRT ARM devices are required to support NEON, but just in case. */
361  return IsProcessorFeaturePresent(PF_ARM_NEON_INSTRUCTIONS_AVAILABLE) != 0;
362 #else
363 #warning SDL_HasNEON is not implemented for this ARM platform. Write me.
364  return 0;
365 #endif
366 }
367 
368 static int
370 {
371  if (CPU_CPUIDMaxFunction > 0) { /* that is, do we have CPUID at all? */
372  int a, b, c, d;
373  cpuid(0x80000000, a, b, c, d);
374  if (a >= 0x80000001) {
375  cpuid(0x80000001, a, b, c, d);
376  return (d & 0x80000000);
377  }
378  }
379  return 0;
380 }
381 
382 #define CPU_haveRDTSC() (CPU_CPUIDFeatures[3] & 0x00000010)
383 #define CPU_haveMMX() (CPU_CPUIDFeatures[3] & 0x00800000)
384 #define CPU_haveSSE() (CPU_CPUIDFeatures[3] & 0x02000000)
385 #define CPU_haveSSE2() (CPU_CPUIDFeatures[3] & 0x04000000)
386 #define CPU_haveSSE3() (CPU_CPUIDFeatures[2] & 0x00000001)
387 #define CPU_haveSSE41() (CPU_CPUIDFeatures[2] & 0x00080000)
388 #define CPU_haveSSE42() (CPU_CPUIDFeatures[2] & 0x00100000)
389 #define CPU_haveAVX() (CPU_OSSavesYMM && (CPU_CPUIDFeatures[2] & 0x10000000))
390 
391 static int
393 {
394  if (CPU_OSSavesYMM && (CPU_CPUIDMaxFunction >= 7)) {
395  int a, b, c, d;
396  (void) a; (void) b; (void) c; (void) d; /* compiler warnings... */
397  cpuid(7, a, b, c, d);
398  return (b & 0x00000020);
399  }
400  return 0;
401 }
402 
403 static int SDL_CPUCount = 0;
404 
405 int
407 {
408  if (!SDL_CPUCount) {
409 #ifndef SDL_CPUINFO_DISABLED
410 #if defined(HAVE_SYSCONF) && defined(_SC_NPROCESSORS_ONLN)
411  if (SDL_CPUCount <= 0) {
412  SDL_CPUCount = (int)sysconf(_SC_NPROCESSORS_ONLN);
413  }
414 #endif
415 #ifdef HAVE_SYSCTLBYNAME
416  if (SDL_CPUCount <= 0) {
417  size_t size = sizeof(SDL_CPUCount);
418  sysctlbyname("hw.ncpu", &SDL_CPUCount, &size, NULL, 0);
419  }
420 #endif
421 #ifdef __WIN32__
422  if (SDL_CPUCount <= 0) {
423  SYSTEM_INFO info;
424  GetSystemInfo(&info);
425  SDL_CPUCount = info.dwNumberOfProcessors;
426  }
427 #endif
428 #ifdef __OS2__
429  if (SDL_CPUCount <= 0) {
430  DosQuerySysInfo(QSV_NUMPROCESSORS, QSV_NUMPROCESSORS,
431  &SDL_CPUCount, sizeof(SDL_CPUCount) );
432  }
433 #endif
434 #endif
435  /* There has to be at least 1, right? :) */
436  if (SDL_CPUCount <= 0) {
437  SDL_CPUCount = 1;
438  }
439  }
440  return SDL_CPUCount;
441 }
442 
443 /* Oh, such a sweet sweet trick, just not very useful. :) */
444 static const char *
446 {
447  static char SDL_CPUType[13];
448 
449  if (!SDL_CPUType[0]) {
450  int i = 0;
451 
453  if (CPU_CPUIDMaxFunction > 0) { /* do we have CPUID at all? */
454  int a, b, c, d;
455  cpuid(0x00000000, a, b, c, d);
456  (void) a;
457  SDL_CPUType[i++] = (char)(b & 0xff); b >>= 8;
458  SDL_CPUType[i++] = (char)(b & 0xff); b >>= 8;
459  SDL_CPUType[i++] = (char)(b & 0xff); b >>= 8;
460  SDL_CPUType[i++] = (char)(b & 0xff);
461 
462  SDL_CPUType[i++] = (char)(d & 0xff); d >>= 8;
463  SDL_CPUType[i++] = (char)(d & 0xff); d >>= 8;
464  SDL_CPUType[i++] = (char)(d & 0xff); d >>= 8;
465  SDL_CPUType[i++] = (char)(d & 0xff);
466 
467  SDL_CPUType[i++] = (char)(c & 0xff); c >>= 8;
468  SDL_CPUType[i++] = (char)(c & 0xff); c >>= 8;
469  SDL_CPUType[i++] = (char)(c & 0xff); c >>= 8;
470  SDL_CPUType[i++] = (char)(c & 0xff);
471  }
472  if (!SDL_CPUType[0]) {
473  SDL_strlcpy(SDL_CPUType, "Unknown", sizeof(SDL_CPUType));
474  }
475  }
476  return SDL_CPUType;
477 }
478 
479 
480 #ifdef TEST_MAIN /* !!! FIXME: only used for test at the moment. */
481 static const char *
482 SDL_GetCPUName(void)
483 {
484  static char SDL_CPUName[48];
485 
486  if (!SDL_CPUName[0]) {
487  int i = 0;
488  int a, b, c, d;
489 
491  if (CPU_CPUIDMaxFunction > 0) { /* do we have CPUID at all? */
492  cpuid(0x80000000, a, b, c, d);
493  if (a >= 0x80000004) {
494  cpuid(0x80000002, a, b, c, d);
495  SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
496  SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
497  SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
498  SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
499  SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
500  SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
501  SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
502  SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
503  SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
504  SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
505  SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
506  SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
507  SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
508  SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
509  SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
510  SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
511  cpuid(0x80000003, 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(0x80000004, 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  }
546  }
547  if (!SDL_CPUName[0]) {
548  SDL_strlcpy(SDL_CPUName, "Unknown", sizeof(SDL_CPUName));
549  }
550  }
551  return SDL_CPUName;
552 }
553 #endif
554 
555 int
557 {
558  const char *cpuType = SDL_GetCPUType();
559  int a, b, c, d;
560  (void) a; (void) b; (void) c; (void) d;
561  if (SDL_strcmp(cpuType, "GenuineIntel") == 0) {
562  cpuid(0x00000001, a, b, c, d);
563  return (((b >> 8) & 0xff) * 8);
564  } else if (SDL_strcmp(cpuType, "AuthenticAMD") == 0) {
565  cpuid(0x80000005, a, b, c, d);
566  return (c & 0xff);
567  } else {
568  /* Just make a guess here... */
569  return SDL_CACHELINE_SIZE;
570  }
571 }
572 
573 static Uint32 SDL_CPUFeatures = 0xFFFFFFFF;
574 
575 static Uint32
577 {
578  if (SDL_CPUFeatures == 0xFFFFFFFF) {
580  SDL_CPUFeatures = 0;
581  if (CPU_haveRDTSC()) {
583  }
584  if (CPU_haveAltiVec()) {
586  }
587  if (CPU_haveMMX()) {
589  }
590  if (CPU_have3DNow()) {
592  }
593  if (CPU_haveSSE()) {
595  }
596  if (CPU_haveSSE2()) {
598  }
599  if (CPU_haveSSE3()) {
601  }
602  if (CPU_haveSSE41()) {
604  }
605  if (CPU_haveSSE42()) {
607  }
608  if (CPU_haveAVX()) {
610  }
611  if (CPU_haveAVX2()) {
613  }
614  if (CPU_haveNEON()) {
616  }
617  }
618  return SDL_CPUFeatures;
619 }
620 
621 #define CPU_FEATURE_AVAILABLE(f) ((SDL_GetCPUFeatures() & f) ? SDL_TRUE : SDL_FALSE)
622 
624 {
626 }
627 
628 SDL_bool
630 {
632 }
633 
634 SDL_bool
636 {
638 }
639 
640 SDL_bool
642 {
644 }
645 
646 SDL_bool
648 {
650 }
651 
652 SDL_bool
654 {
656 }
657 
658 SDL_bool
660 {
662 }
663 
664 SDL_bool
666 {
668 }
669 
670 SDL_bool
672 {
674 }
675 
676 SDL_bool
678 {
680 }
681 
682 SDL_bool
684 {
686 }
687 
688 SDL_bool
690 {
692 }
693 
694 static int SDL_SystemRAM = 0;
695 
696 int
698 {
699  if (!SDL_SystemRAM) {
700 #ifndef SDL_CPUINFO_DISABLED
701 #if defined(HAVE_SYSCONF) && defined(_SC_PHYS_PAGES) && defined(_SC_PAGESIZE)
702  if (SDL_SystemRAM <= 0) {
703  SDL_SystemRAM = (int)((Sint64)sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGESIZE) / (1024*1024));
704  }
705 #endif
706 #ifdef HAVE_SYSCTLBYNAME
707  if (SDL_SystemRAM <= 0) {
708 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__)
709 #ifdef HW_REALMEM
710  int mib[2] = {CTL_HW, HW_REALMEM};
711 #else
712  /* might only report up to 2 GiB */
713  int mib[2] = {CTL_HW, HW_PHYSMEM};
714 #endif /* HW_REALMEM */
715 #else
716  int mib[2] = {CTL_HW, HW_MEMSIZE};
717 #endif /* __FreeBSD__ || __FreeBSD_kernel__ */
718  Uint64 memsize = 0;
719  size_t len = sizeof(memsize);
720 
721  if (sysctl(mib, 2, &memsize, &len, NULL, 0) == 0) {
722  SDL_SystemRAM = (int)(memsize / (1024*1024));
723  }
724  }
725 #endif
726 #ifdef __WIN32__
727  if (SDL_SystemRAM <= 0) {
728  MEMORYSTATUSEX stat;
729  stat.dwLength = sizeof(stat);
730  if (GlobalMemoryStatusEx(&stat)) {
731  SDL_SystemRAM = (int)(stat.ullTotalPhys / (1024 * 1024));
732  }
733  }
734 #endif
735 #ifdef __OS2__
736  if (SDL_SystemRAM <= 0) {
737  Uint32 sysram = 0;
738  DosQuerySysInfo(QSV_TOTPHYSMEM, QSV_TOTPHYSMEM, &sysram, 4);
739  SDL_SystemRAM = (int) (sysram / 0x100000U);
740  }
741 #endif
742 #endif
743  }
744  return SDL_SystemRAM;
745 }
746 
747 
748 #ifdef TEST_MAIN
749 
750 #include <stdio.h>
751 
752 int
753 main()
754 {
755  printf("CPU count: %d\n", SDL_GetCPUCount());
756  printf("CPU type: %s\n", SDL_GetCPUType());
757  printf("CPU name: %s\n", SDL_GetCPUName());
758  printf("CacheLine size: %d\n", SDL_GetCPUCacheLineSize());
759  printf("RDTSC: %d\n", SDL_HasRDTSC());
760  printf("Altivec: %d\n", SDL_HasAltiVec());
761  printf("MMX: %d\n", SDL_HasMMX());
762  printf("3DNow: %d\n", SDL_Has3DNow());
763  printf("SSE: %d\n", SDL_HasSSE());
764  printf("SSE2: %d\n", SDL_HasSSE2());
765  printf("SSE3: %d\n", SDL_HasSSE3());
766  printf("SSE4.1: %d\n", SDL_HasSSE41());
767  printf("SSE4.2: %d\n", SDL_HasSSE42());
768  printf("AVX: %d\n", SDL_HasAVX());
769  printf("AVX2: %d\n", SDL_HasAVX2());
770  printf("NEON: %d\n", SDL_HasNEON());
771  printf("RAM: %d MB\n", SDL_GetSystemRAM());
772  return 0;
773 }
774 
775 #endif /* TEST_MAIN */
776 
777 /* vi: set ts=4 sw=4 expandtab: */
#define CPU_haveSSE2()
Definition: SDL_cpuinfo.c:385
#define CPU_haveAVX()
Definition: SDL_cpuinfo.c:389
#define CPU_HAS_SSE41
Definition: SDL_cpuinfo.c:86
#define SDL_strlcpy
#define CPU_HAS_RDTSC
Definition: SDL_cpuinfo.c:79
static SDL_bool CPU_OSSavesYMM
Definition: SDL_cpuinfo.c:248
#define CPU_HAS_SSE3
Definition: SDL_cpuinfo.c:85
SDL_bool SDL_HasSSE41(void)
Definition: SDL_cpuinfo.c:665
static void CPU_calcCPUIDFeatures(void)
Definition: SDL_cpuinfo.c:251
int SDL_GetCPUCount(void)
Definition: SDL_cpuinfo.c:406
static const char * SDL_GetCPUType(void)
Definition: SDL_cpuinfo.c:445
GLfloat GLfloat GLfloat GLfloat h
#define CPU_HAS_SSE2
Definition: SDL_cpuinfo.c:84
SDL_bool SDL_HasSSE(void)
Definition: SDL_cpuinfo.c:647
SDL_bool SDL_HasSSE3(void)
Definition: SDL_cpuinfo.c:659
static int CPU_CPUIDMaxFunction
Definition: SDL_cpuinfo.c:247
static int CPU_have3DNow(void)
Definition: SDL_cpuinfo.c:369
uint32_t Uint32
Definition: SDL_stdinc.h:181
#define CPU_haveRDTSC()
Definition: SDL_cpuinfo.c:382
SDL_bool SDL_HasAltiVec(void)
Definition: SDL_cpuinfo.c:629
#define CPU_HAS_ALTIVEC
Definition: SDL_cpuinfo.c:80
static int SDL_SystemRAM
Definition: SDL_cpuinfo.c:694
static int CPU_haveCPUID(void)
Definition: SDL_cpuinfo.c:105
#define CPU_haveMMX()
Definition: SDL_cpuinfo.c:383
uint64_t Uint64
Definition: SDL_stdinc.h:194
SDL_bool SDL_HasSSE42(void)
Definition: SDL_cpuinfo.c:671
GLenum GLsizei len
SDL_bool SDL_HasMMX(void)
Definition: SDL_cpuinfo.c:635
SDL_bool SDL_HasAVX2(void)
Definition: SDL_cpuinfo.c:683
static int CPU_haveAltiVec(void)
Definition: SDL_cpuinfo.c:290
#define CPU_HAS_AVX
Definition: SDL_cpuinfo.c:88
#define CPU_FEATURE_AVAILABLE(f)
Definition: SDL_cpuinfo.c:621
#define CPU_haveSSE42()
Definition: SDL_cpuinfo.c:388
#define CPU_HAS_NEON
Definition: SDL_cpuinfo.c:90
#define CPU_haveSSE3()
Definition: SDL_cpuinfo.c:386
SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char const char SDL_SCANF_FORMAT_STRING const char return SDL_ThreadFunction const char void return Uint32 return Uint32 SDL_AssertionHandler void SDL_SpinLock SDL_atomic_t int int return SDL_atomic_t return void void void return void return int return SDL_AudioSpec SDL_AudioSpec return int int return return int SDL_RWops int SDL_AudioSpec Uint8 ** d
#define pop
Definition: SDL_qsort.c:192
int done
Definition: checkkeys.c:28
SDL_bool SDL_HasNEON(void)
Definition: SDL_cpuinfo.c:689
#define SDL_CACHELINE_SIZE
Definition: SDL_cpuinfo.h:92
const GLubyte * c
GLsizei const GLfloat * value
#define cpuid(func, a, b, c, d)
Definition: SDL_cpuinfo.c:242
SDL_bool SDL_HasAVX(void)
Definition: SDL_cpuinfo.c:677
static Uint32 SDL_CPUFeatures
Definition: SDL_cpuinfo.c:573
static Uint32 SDL_GetCPUFeatures(void)
Definition: SDL_cpuinfo.c:576
#define CPU_HAS_SSE
Definition: SDL_cpuinfo.c:83
static int CPU_haveAVX2(void)
Definition: SDL_cpuinfo.c:392
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:89
#define NULL
Definition: begin_code.h:164
SDL_bool
Definition: SDL_stdinc.h:139
static int CPU_haveNEON(void)
Definition: SDL_cpuinfo.c:340
#define CPU_haveSSE()
Definition: SDL_cpuinfo.c:384
SDL_bool SDL_HasRDTSC(void)
Definition: SDL_cpuinfo.c:623
#define CPU_HAS_MMX
Definition: SDL_cpuinfo.c:81
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
int SDL_GetSystemRAM(void)
Definition: SDL_cpuinfo.c:697
#define CPU_haveSSE41()
Definition: SDL_cpuinfo.c:387
static int SDL_CPUCount
Definition: SDL_cpuinfo.c:403
#define main
Definition: SDL_main.h:111
#define CPU_HAS_SSE42
Definition: SDL_cpuinfo.c:87
#define SDL_strcmp
int64_t Sint64
Definition: SDL_stdinc.h:188
static int CPU_CPUIDFeatures[4]
Definition: SDL_cpuinfo.c:246
GLuint GLsizei GLsizei * length
GLboolean GLboolean GLboolean GLboolean a
SDL_bool SDL_HasSSE2(void)
Definition: SDL_cpuinfo.c:653
GLuint in
#define CPU_HAS_3DNOW
Definition: SDL_cpuinfo.c:82
GLboolean GLboolean GLboolean b
SDL_bool SDL_Has3DNow(void)
Definition: SDL_cpuinfo.c:641
GLuint64 GLenum GLint fd
Definition: gl2ext.h:1508
int SDL_GetCPUCacheLineSize(void)
Definition: SDL_cpuinfo.c:556