SDL_cpuinfo.c 22 KB

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