1 /*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
20 */
21 #ifdef TEST_MAIN
22 #include "SDL_config.h"
23 #else
24 #include "../SDL_internal.h"
25 #endif
26
27 #if defined(__WIN32__)
28 #include "../core/windows/SDL_windows.h"
29 #endif
30
31 /* CPU feature detection for SDL */
32
33 #include "SDL_cpuinfo.h"
34
35 #ifdef HAVE_SYSCONF
36 #include <unistd.h>
37 #endif
38 #ifdef HAVE_SYSCTLBYNAME
39 #include <sys/types.h>
40 #include <sys/sysctl.h>
41 #endif
42 #if defined(__MACOSX__) && (defined(__ppc__) || defined(__ppc64__))
43 #include <sys/sysctl.h> /* For AltiVec check */
44 #elif defined(__OpenBSD__) && defined(__powerpc__)
45 #include <sys/param.h>
46 #include <sys/sysctl.h> /* For AltiVec check */
47 #include <machine/cpu.h>
48 #elif SDL_ALTIVEC_BLITTERS && HAVE_SETJMP
49 #include <signal.h>
50 #include <setjmp.h>
51 #endif
52
53 #define CPU_HAS_RDTSC 0x00000001
54 #define CPU_HAS_ALTIVEC 0x00000002
55 #define CPU_HAS_MMX 0x00000004
56 #define CPU_HAS_3DNOW 0x00000008
57 #define CPU_HAS_SSE 0x00000010
58 #define CPU_HAS_SSE2 0x00000020
59 #define CPU_HAS_SSE3 0x00000040
60 #define CPU_HAS_SSE41 0x00000100
61 #define CPU_HAS_SSE42 0x00000200
62 #define CPU_HAS_AVX 0x00000400
63 #define CPU_HAS_AVX2 0x00000800
64
65 #if SDL_ALTIVEC_BLITTERS && HAVE_SETJMP && !__MACOSX__ && !__OpenBSD__
66 /* This is the brute force way of detecting instruction sets...
67 the idea is borrowed from the libmpeg2 library - thanks!
68 */
69 static jmp_buf jmpbuf;
70 static void
illegal_instruction(int sig)71 illegal_instruction(int sig)
72 {
73 longjmp(jmpbuf, 1);
74 }
75 #endif /* HAVE_SETJMP */
76
77 static int
CPU_haveCPUID(void)78 CPU_haveCPUID(void)
79 {
80 int has_CPUID = 0;
81 /* *INDENT-OFF* */
82 #ifndef SDL_CPUINFO_DISABLED
83 #if defined(__GNUC__) && defined(i386)
84 __asm__ (
85 " pushfl # Get original EFLAGS \n"
86 " popl %%eax \n"
87 " movl %%eax,%%ecx \n"
88 " xorl $0x200000,%%eax # Flip ID bit in EFLAGS \n"
89 " pushl %%eax # Save new EFLAGS value on stack \n"
90 " popfl # Replace current EFLAGS value \n"
91 " pushfl # Get new EFLAGS \n"
92 " popl %%eax # Store new EFLAGS in EAX \n"
93 " xorl %%ecx,%%eax # Can not toggle ID bit, \n"
94 " jz 1f # Processor=80486 \n"
95 " movl $1,%0 # We have CPUID support \n"
96 "1: \n"
97 : "=m" (has_CPUID)
98 :
99 : "%eax", "%ecx"
100 );
101 #elif defined(__GNUC__) && defined(__x86_64__)
102 /* Technically, if this is being compiled under __x86_64__ then it has
103 CPUid by definition. But it's nice to be able to prove it. :) */
104 __asm__ (
105 " pushfq # Get original EFLAGS \n"
106 " popq %%rax \n"
107 " movq %%rax,%%rcx \n"
108 " xorl $0x200000,%%eax # Flip ID bit in EFLAGS \n"
109 " pushq %%rax # Save new EFLAGS value on stack \n"
110 " popfq # Replace current EFLAGS value \n"
111 " pushfq # Get new EFLAGS \n"
112 " popq %%rax # Store new EFLAGS in EAX \n"
113 " xorl %%ecx,%%eax # Can not toggle ID bit, \n"
114 " jz 1f # Processor=80486 \n"
115 " movl $1,%0 # We have CPUID support \n"
116 "1: \n"
117 : "=m" (has_CPUID)
118 :
119 : "%rax", "%rcx"
120 );
121 #elif (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
122 __asm {
123 pushfd ; Get original EFLAGS
124 pop eax
125 mov ecx, eax
126 xor eax, 200000h ; Flip ID bit in EFLAGS
127 push eax ; Save new EFLAGS value on stack
128 popfd ; Replace current EFLAGS value
129 pushfd ; Get new EFLAGS
130 pop eax ; Store new EFLAGS in EAX
131 xor eax, ecx ; Can not toggle ID bit,
132 jz done ; Processor=80486
133 mov has_CPUID,1 ; We have CPUID support
134 done:
135 }
136 #elif defined(_MSC_VER) && defined(_M_X64)
137 has_CPUID = 1;
138 #elif defined(__sun) && defined(__i386)
139 __asm (
140 " pushfl \n"
141 " popl %eax \n"
142 " movl %eax,%ecx \n"
143 " xorl $0x200000,%eax \n"
144 " pushl %eax \n"
145 " popfl \n"
146 " pushfl \n"
147 " popl %eax \n"
148 " xorl %ecx,%eax \n"
149 " jz 1f \n"
150 " movl $1,-8(%ebp) \n"
151 "1: \n"
152 );
153 #elif defined(__sun) && defined(__amd64)
154 __asm (
155 " pushfq \n"
156 " popq %rax \n"
157 " movq %rax,%rcx \n"
158 " xorl $0x200000,%eax \n"
159 " pushq %rax \n"
160 " popfq \n"
161 " pushfq \n"
162 " popq %rax \n"
163 " xorl %ecx,%eax \n"
164 " jz 1f \n"
165 " movl $1,-8(%rbp) \n"
166 "1: \n"
167 );
168 #endif
169 #endif
170 /* *INDENT-ON* */
171 return has_CPUID;
172 }
173
174 #if defined(__GNUC__) && defined(i386)
175 #define cpuid(func, a, b, c, d) \
176 __asm__ __volatile__ ( \
177 " pushl %%ebx \n" \
178 " xorl %%ecx,%%ecx \n" \
179 " cpuid \n" \
180 " movl %%ebx, %%esi \n" \
181 " popl %%ebx \n" : \
182 "=a" (a), "=S" (b), "=c" (c), "=d" (d) : "a" (func))
183 #elif defined(__GNUC__) && defined(__x86_64__)
184 #define cpuid(func, a, b, c, d) \
185 __asm__ __volatile__ ( \
186 " pushq %%rbx \n" \
187 " xorq %%rcx,%%rcx \n" \
188 " cpuid \n" \
189 " movq %%rbx, %%rsi \n" \
190 " popq %%rbx \n" : \
191 "=a" (a), "=S" (b), "=c" (c), "=d" (d) : "a" (func))
192 #elif (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
193 #define cpuid(func, a, b, c, d) \
194 __asm { \
195 __asm mov eax, func \
196 __asm xor ecx, ecx \
197 __asm cpuid \
198 __asm mov a, eax \
199 __asm mov b, ebx \
200 __asm mov c, ecx \
201 __asm mov d, edx \
202 }
203 #elif defined(_MSC_VER) && defined(_M_X64)
204 #define cpuid(func, a, b, c, d) \
205 { \
206 int CPUInfo[4]; \
207 __cpuid(CPUInfo, func); \
208 a = CPUInfo[0]; \
209 b = CPUInfo[1]; \
210 c = CPUInfo[2]; \
211 d = CPUInfo[3]; \
212 }
213 #else
214 #define cpuid(func, a, b, c, d) \
215 a = b = c = d = 0
216 #endif
217
218 static int
CPU_getCPUIDFeatures(void)219 CPU_getCPUIDFeatures(void)
220 {
221 int features = 0;
222 int a, b, c, d;
223
224 cpuid(0, a, b, c, d);
225 if (a >= 1) {
226 cpuid(1, a, b, c, d);
227 features = d;
228 }
229 return features;
230 }
231
232 static SDL_bool
CPU_OSSavesYMM(void)233 CPU_OSSavesYMM(void)
234 {
235 int a, b, c, d;
236
237 /* Check to make sure we can call xgetbv */
238 cpuid(0, a, b, c, d);
239 if (a < 1) {
240 return SDL_FALSE;
241 }
242 cpuid(1, a, b, c, d);
243 if (!(c & 0x08000000)) {
244 return SDL_FALSE;
245 }
246
247 /* Call xgetbv to see if YMM register state is saved */
248 a = 0;
249 #if defined(__GNUC__) && (defined(i386) || defined(__x86_64__))
250 asm(".byte 0x0f, 0x01, 0xd0" : "=a" (a) : "c" (0) : "%edx");
251 #elif defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64)) && (_MSC_FULL_VER >= 160040219) /* VS2010 SP1 */
252 a = (int)_xgetbv(0);
253 #elif (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
254 __asm
255 {
256 xor ecx, ecx
257 _asm _emit 0x0f _asm _emit 0x01 _asm _emit 0xd0
258 mov a, eax
259 }
260 #endif
261 return ((a & 6) == 6) ? SDL_TRUE : SDL_FALSE;
262 }
263
264 static int
CPU_haveRDTSC(void)265 CPU_haveRDTSC(void)
266 {
267 if (CPU_haveCPUID()) {
268 return (CPU_getCPUIDFeatures() & 0x00000010);
269 }
270 return 0;
271 }
272
273 static int
CPU_haveAltiVec(void)274 CPU_haveAltiVec(void)
275 {
276 volatile int altivec = 0;
277 #ifndef SDL_CPUINFO_DISABLED
278 #if (defined(__MACOSX__) && (defined(__ppc__) || defined(__ppc64__))) || (defined(__OpenBSD__) && defined(__powerpc__))
279 #ifdef __OpenBSD__
280 int selectors[2] = { CTL_MACHDEP, CPU_ALTIVEC };
281 #else
282 int selectors[2] = { CTL_HW, HW_VECTORUNIT };
283 #endif
284 int hasVectorUnit = 0;
285 size_t length = sizeof(hasVectorUnit);
286 int error = sysctl(selectors, 2, &hasVectorUnit, &length, NULL, 0);
287 if (0 == error)
288 altivec = (hasVectorUnit != 0);
289 #elif SDL_ALTIVEC_BLITTERS && HAVE_SETJMP
290 void (*handler) (int sig);
291 handler = signal(SIGILL, illegal_instruction);
292 if (setjmp(jmpbuf) == 0) {
293 asm volatile ("mtspr 256, %0\n\t" "vand %%v0, %%v0, %%v0"::"r" (-1));
294 altivec = 1;
295 }
296 signal(SIGILL, handler);
297 #endif
298 #endif
299 return altivec;
300 }
301
302 static int
CPU_haveMMX(void)303 CPU_haveMMX(void)
304 {
305 if (CPU_haveCPUID()) {
306 return (CPU_getCPUIDFeatures() & 0x00800000);
307 }
308 return 0;
309 }
310
311 static int
CPU_have3DNow(void)312 CPU_have3DNow(void)
313 {
314 if (CPU_haveCPUID()) {
315 int a, b, c, d;
316
317 cpuid(0x80000000, a, b, c, d);
318 if (a >= 0x80000001) {
319 cpuid(0x80000001, a, b, c, d);
320 return (d & 0x80000000);
321 }
322 }
323 return 0;
324 }
325
326 static int
CPU_haveSSE(void)327 CPU_haveSSE(void)
328 {
329 if (CPU_haveCPUID()) {
330 return (CPU_getCPUIDFeatures() & 0x02000000);
331 }
332 return 0;
333 }
334
335 static int
CPU_haveSSE2(void)336 CPU_haveSSE2(void)
337 {
338 if (CPU_haveCPUID()) {
339 return (CPU_getCPUIDFeatures() & 0x04000000);
340 }
341 return 0;
342 }
343
344 static int
CPU_haveSSE3(void)345 CPU_haveSSE3(void)
346 {
347 if (CPU_haveCPUID()) {
348 int a, b, c, d;
349
350 cpuid(0, a, b, c, d);
351 if (a >= 1) {
352 cpuid(1, a, b, c, d);
353 return (c & 0x00000001);
354 }
355 }
356 return 0;
357 }
358
359 static int
CPU_haveSSE41(void)360 CPU_haveSSE41(void)
361 {
362 if (CPU_haveCPUID()) {
363 int a, b, c, d;
364
365 cpuid(0, a, b, c, d);
366 if (a >= 1) {
367 cpuid(1, a, b, c, d);
368 return (c & 0x00080000);
369 }
370 }
371 return 0;
372 }
373
374 static int
CPU_haveSSE42(void)375 CPU_haveSSE42(void)
376 {
377 if (CPU_haveCPUID()) {
378 int a, b, c, d;
379
380 cpuid(0, a, b, c, d);
381 if (a >= 1) {
382 cpuid(1, a, b, c, d);
383 return (c & 0x00100000);
384 }
385 }
386 return 0;
387 }
388
389 static int
CPU_haveAVX(void)390 CPU_haveAVX(void)
391 {
392 if (CPU_haveCPUID() && CPU_OSSavesYMM()) {
393 int a, b, c, d;
394
395 cpuid(0, a, b, c, d);
396 if (a >= 1) {
397 cpuid(1, a, b, c, d);
398 return (c & 0x10000000);
399 }
400 }
401 return 0;
402 }
403
404 static int
CPU_haveAVX2(void)405 CPU_haveAVX2(void)
406 {
407 if (CPU_haveCPUID() && CPU_OSSavesYMM()) {
408 int a, b, c, d;
409
410 cpuid(0, a, b, c, d);
411 if (a >= 7) {
412 cpuid(7, a, b, c, d);
413 return (b & 0x00000020);
414 }
415 }
416 return 0;
417 }
418
419 static int SDL_CPUCount = 0;
420
421 int
SDL_GetCPUCount(void)422 SDL_GetCPUCount(void)
423 {
424 if (!SDL_CPUCount) {
425 #ifndef SDL_CPUINFO_DISABLED
426 #if defined(HAVE_SYSCONF) && defined(_SC_NPROCESSORS_ONLN)
427 if (SDL_CPUCount <= 0) {
428 SDL_CPUCount = (int)sysconf(_SC_NPROCESSORS_ONLN);
429 }
430 #endif
431 #ifdef HAVE_SYSCTLBYNAME
432 if (SDL_CPUCount <= 0) {
433 size_t size = sizeof(SDL_CPUCount);
434 sysctlbyname("hw.ncpu", &SDL_CPUCount, &size, NULL, 0);
435 }
436 #endif
437 #ifdef __WIN32__
438 if (SDL_CPUCount <= 0) {
439 SYSTEM_INFO info;
440 GetSystemInfo(&info);
441 SDL_CPUCount = info.dwNumberOfProcessors;
442 }
443 #endif
444 #endif
445 /* There has to be at least 1, right? :) */
446 if (SDL_CPUCount <= 0) {
447 SDL_CPUCount = 1;
448 }
449 }
450 return SDL_CPUCount;
451 }
452
453 /* Oh, such a sweet sweet trick, just not very useful. :) */
454 static const char *
SDL_GetCPUType(void)455 SDL_GetCPUType(void)
456 {
457 static char SDL_CPUType[13];
458
459 if (!SDL_CPUType[0]) {
460 int i = 0;
461
462 if (CPU_haveCPUID()) {
463 int a, b, c, d;
464 cpuid(0x00000000, a, b, c, d);
465 (void) a;
466 SDL_CPUType[i++] = (char)(b & 0xff); b >>= 8;
467 SDL_CPUType[i++] = (char)(b & 0xff); b >>= 8;
468 SDL_CPUType[i++] = (char)(b & 0xff); b >>= 8;
469 SDL_CPUType[i++] = (char)(b & 0xff);
470
471 SDL_CPUType[i++] = (char)(d & 0xff); d >>= 8;
472 SDL_CPUType[i++] = (char)(d & 0xff); d >>= 8;
473 SDL_CPUType[i++] = (char)(d & 0xff); d >>= 8;
474 SDL_CPUType[i++] = (char)(d & 0xff);
475
476 SDL_CPUType[i++] = (char)(c & 0xff); c >>= 8;
477 SDL_CPUType[i++] = (char)(c & 0xff); c >>= 8;
478 SDL_CPUType[i++] = (char)(c & 0xff); c >>= 8;
479 SDL_CPUType[i++] = (char)(c & 0xff);
480 }
481 if (!SDL_CPUType[0]) {
482 SDL_strlcpy(SDL_CPUType, "Unknown", sizeof(SDL_CPUType));
483 }
484 }
485 return SDL_CPUType;
486 }
487
488
489 #ifdef TEST_MAIN /* !!! FIXME: only used for test at the moment. */
490 static const char *
SDL_GetCPUName(void)491 SDL_GetCPUName(void)
492 {
493 static char SDL_CPUName[48];
494
495 if (!SDL_CPUName[0]) {
496 int i = 0;
497 int a, b, c, d;
498
499 if (CPU_haveCPUID()) {
500 cpuid(0x80000000, a, b, c, d);
501 if (a >= 0x80000004) {
502 cpuid(0x80000002, a, b, c, d);
503 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
504 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
505 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
506 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
507 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
508 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
509 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
510 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
511 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
512 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
513 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
514 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
515 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
516 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
517 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
518 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
519 cpuid(0x80000003, a, b, c, d);
520 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
521 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
522 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
523 SDL_CPUName[i++] = (char)(a & 0xff); a >>= 8;
524 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
525 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
526 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
527 SDL_CPUName[i++] = (char)(b & 0xff); b >>= 8;
528 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
529 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
530 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
531 SDL_CPUName[i++] = (char)(c & 0xff); c >>= 8;
532 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
533 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
534 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
535 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
536 cpuid(0x80000004, a, b, c, d);
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)(a & 0xff); a >>= 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)(b & 0xff); b >>= 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)(c & 0xff); c >>= 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 SDL_CPUName[i++] = (char)(d & 0xff); d >>= 8;
553 }
554 }
555 if (!SDL_CPUName[0]) {
556 SDL_strlcpy(SDL_CPUName, "Unknown", sizeof(SDL_CPUName));
557 }
558 }
559 return SDL_CPUName;
560 }
561 #endif
562
563 int
SDL_GetCPUCacheLineSize(void)564 SDL_GetCPUCacheLineSize(void)
565 {
566 const char *cpuType = SDL_GetCPUType();
567 int a, b, c, d;
568 (void) a; (void) b; (void) c; (void) d;
569 if (SDL_strcmp(cpuType, "GenuineIntel") == 0) {
570 cpuid(0x00000001, a, b, c, d);
571 return (((b >> 8) & 0xff) * 8);
572 } else if (SDL_strcmp(cpuType, "AuthenticAMD") == 0) {
573 cpuid(0x80000005, a, b, c, d);
574 return (c & 0xff);
575 } else {
576 /* Just make a guess here... */
577 return SDL_CACHELINE_SIZE;
578 }
579 }
580
581 static Uint32 SDL_CPUFeatures = 0xFFFFFFFF;
582
583 static Uint32
SDL_GetCPUFeatures(void)584 SDL_GetCPUFeatures(void)
585 {
586 if (SDL_CPUFeatures == 0xFFFFFFFF) {
587 SDL_CPUFeatures = 0;
588 if (CPU_haveRDTSC()) {
589 SDL_CPUFeatures |= CPU_HAS_RDTSC;
590 }
591 if (CPU_haveAltiVec()) {
592 SDL_CPUFeatures |= CPU_HAS_ALTIVEC;
593 }
594 if (CPU_haveMMX()) {
595 SDL_CPUFeatures |= CPU_HAS_MMX;
596 }
597 if (CPU_have3DNow()) {
598 SDL_CPUFeatures |= CPU_HAS_3DNOW;
599 }
600 if (CPU_haveSSE()) {
601 SDL_CPUFeatures |= CPU_HAS_SSE;
602 }
603 if (CPU_haveSSE2()) {
604 SDL_CPUFeatures |= CPU_HAS_SSE2;
605 }
606 if (CPU_haveSSE3()) {
607 SDL_CPUFeatures |= CPU_HAS_SSE3;
608 }
609 if (CPU_haveSSE41()) {
610 SDL_CPUFeatures |= CPU_HAS_SSE41;
611 }
612 if (CPU_haveSSE42()) {
613 SDL_CPUFeatures |= CPU_HAS_SSE42;
614 }
615 if (CPU_haveAVX()) {
616 SDL_CPUFeatures |= CPU_HAS_AVX;
617 }
618 if (CPU_haveAVX2()) {
619 SDL_CPUFeatures |= CPU_HAS_AVX2;
620 }
621 }
622 return SDL_CPUFeatures;
623 }
624
625 SDL_bool
SDL_HasRDTSC(void)626 SDL_HasRDTSC(void)
627 {
628 if (SDL_GetCPUFeatures() & CPU_HAS_RDTSC) {
629 return SDL_TRUE;
630 }
631 return SDL_FALSE;
632 }
633
634 SDL_bool
SDL_HasAltiVec(void)635 SDL_HasAltiVec(void)
636 {
637 if (SDL_GetCPUFeatures() & CPU_HAS_ALTIVEC) {
638 return SDL_TRUE;
639 }
640 return SDL_FALSE;
641 }
642
643 SDL_bool
SDL_HasMMX(void)644 SDL_HasMMX(void)
645 {
646 if (SDL_GetCPUFeatures() & CPU_HAS_MMX) {
647 return SDL_TRUE;
648 }
649 return SDL_FALSE;
650 }
651
652 SDL_bool
SDL_Has3DNow(void)653 SDL_Has3DNow(void)
654 {
655 if (SDL_GetCPUFeatures() & CPU_HAS_3DNOW) {
656 return SDL_TRUE;
657 }
658 return SDL_FALSE;
659 }
660
661 SDL_bool
SDL_HasSSE(void)662 SDL_HasSSE(void)
663 {
664 if (SDL_GetCPUFeatures() & CPU_HAS_SSE) {
665 return SDL_TRUE;
666 }
667 return SDL_FALSE;
668 }
669
670 SDL_bool
SDL_HasSSE2(void)671 SDL_HasSSE2(void)
672 {
673 if (SDL_GetCPUFeatures() & CPU_HAS_SSE2) {
674 return SDL_TRUE;
675 }
676 return SDL_FALSE;
677 }
678
679 SDL_bool
SDL_HasSSE3(void)680 SDL_HasSSE3(void)
681 {
682 if (SDL_GetCPUFeatures() & CPU_HAS_SSE3) {
683 return SDL_TRUE;
684 }
685 return SDL_FALSE;
686 }
687
688 SDL_bool
SDL_HasSSE41(void)689 SDL_HasSSE41(void)
690 {
691 if (SDL_GetCPUFeatures() & CPU_HAS_SSE41) {
692 return SDL_TRUE;
693 }
694 return SDL_FALSE;
695 }
696
697 SDL_bool
SDL_HasSSE42(void)698 SDL_HasSSE42(void)
699 {
700 if (SDL_GetCPUFeatures() & CPU_HAS_SSE42) {
701 return SDL_TRUE;
702 }
703 return SDL_FALSE;
704 }
705
706 SDL_bool
SDL_HasAVX(void)707 SDL_HasAVX(void)
708 {
709 if (SDL_GetCPUFeatures() & CPU_HAS_AVX) {
710 return SDL_TRUE;
711 }
712 return SDL_FALSE;
713 }
714
715 SDL_bool
SDL_HasAVX2(void)716 SDL_HasAVX2(void)
717 {
718 if (SDL_GetCPUFeatures() & CPU_HAS_AVX2) {
719 return SDL_TRUE;
720 }
721 return SDL_FALSE;
722 }
723
724 static int SDL_SystemRAM = 0;
725
726 int
SDL_GetSystemRAM(void)727 SDL_GetSystemRAM(void)
728 {
729 if (!SDL_SystemRAM) {
730 #ifndef SDL_CPUINFO_DISABLED
731 #if defined(HAVE_SYSCONF) && defined(_SC_PHYS_PAGES) && defined(_SC_PAGESIZE)
732 if (SDL_SystemRAM <= 0) {
733 SDL_SystemRAM = (int)((Sint64)sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGESIZE) / (1024*1024));
734 }
735 #endif
736 #ifdef HAVE_SYSCTLBYNAME
737 if (SDL_SystemRAM <= 0) {
738 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__DragonFly__)
739 #ifdef HW_REALMEM
740 int mib[2] = {CTL_HW, HW_REALMEM};
741 #else
742 /* might only report up to 2 GiB */
743 int mib[2] = {CTL_HW, HW_PHYSMEM};
744 #endif /* HW_REALMEM */
745 #else
746 int mib[2] = {CTL_HW, HW_MEMSIZE};
747 #endif /* __FreeBSD__ || __FreeBSD_kernel__ */
748 Uint64 memsize = 0;
749 size_t len = sizeof(memsize);
750
751 if (sysctl(mib, 2, &memsize, &len, NULL, 0) == 0) {
752 SDL_SystemRAM = (int)(memsize / (1024*1024));
753 }
754 }
755 #endif
756 #ifdef __WIN32__
757 if (SDL_SystemRAM <= 0) {
758 MEMORYSTATUSEX stat;
759 stat.dwLength = sizeof(stat);
760 if (GlobalMemoryStatusEx(&stat)) {
761 SDL_SystemRAM = (int)(stat.ullTotalPhys / (1024 * 1024));
762 }
763 }
764 #endif
765 #endif
766 }
767 return SDL_SystemRAM;
768 }
769
770
771 #ifdef TEST_MAIN
772
773 #include <stdio.h>
774
775 int
main()776 main()
777 {
778 printf("CPU count: %d\n", SDL_GetCPUCount());
779 printf("CPU type: %s\n", SDL_GetCPUType());
780 printf("CPU name: %s\n", SDL_GetCPUName());
781 printf("CacheLine size: %d\n", SDL_GetCPUCacheLineSize());
782 printf("RDTSC: %d\n", SDL_HasRDTSC());
783 printf("Altivec: %d\n", SDL_HasAltiVec());
784 printf("MMX: %d\n", SDL_HasMMX());
785 printf("3DNow: %d\n", SDL_Has3DNow());
786 printf("SSE: %d\n", SDL_HasSSE());
787 printf("SSE2: %d\n", SDL_HasSSE2());
788 printf("SSE3: %d\n", SDL_HasSSE3());
789 printf("SSE4.1: %d\n", SDL_HasSSE41());
790 printf("SSE4.2: %d\n", SDL_HasSSE42());
791 printf("AVX: %d\n", SDL_HasAVX());
792 printf("AVX2: %d\n", SDL_HasAVX2());
793 printf("RAM: %d MB\n", SDL_GetSystemRAM());
794 return 0;
795 }
796
797 #endif /* TEST_MAIN */
798
799 /* vi: set ts=4 sw=4 expandtab: */
800