SDL_cpuinfo.c 40 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282
  1. /*
  2. Simple DirectMedia Layer
  3. Copyright (C) 1997-2025 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. #include "SDL_internal.h"
  19. #include "SDL_cpuinfo_c.h"
  20. #if defined(SDL_PLATFORM_WINDOWS)
  21. #include "../core/windows/SDL_windows.h"
  22. #endif
  23. // CPU feature detection for SDL
  24. #if defined(HAVE_SYSCONF) || defined(HAVE_GETPAGESIZE)
  25. #include <unistd.h>
  26. #endif
  27. #ifdef HAVE_SYSCTLBYNAME
  28. #include <sys/types.h>
  29. #include <sys/sysctl.h>
  30. #endif
  31. #if defined(SDL_PLATFORM_MACOS) && (defined(__ppc__) || defined(__ppc64__))
  32. #include <sys/sysctl.h> // For AltiVec check
  33. #elif defined(SDL_PLATFORM_OPENBSD) && defined(__powerpc__) && !defined(HAVE_ELF_AUX_INFO)
  34. #include <sys/types.h>
  35. #include <sys/sysctl.h> // For AltiVec check
  36. #include <machine/cpu.h>
  37. #elif defined(SDL_PLATFORM_FREEBSD) && defined(__powerpc__) && defined(HAVE_ELF_AUX_INFO)
  38. #include <machine/cpu.h>
  39. #elif defined(SDL_ALTIVEC_BLITTERS) && defined(HAVE_SETJMP)
  40. #include <signal.h>
  41. #include <setjmp.h>
  42. #endif
  43. #if (defined(SDL_PLATFORM_LINUX) || defined(SDL_PLATFORM_ANDROID)) && defined(__arm__)
  44. #include <unistd.h>
  45. #include <sys/types.h>
  46. #include <sys/stat.h>
  47. #include <fcntl.h>
  48. #include <elf.h>
  49. // #include <asm/hwcap.h>
  50. #ifndef AT_HWCAP
  51. #define AT_HWCAP 16
  52. #endif
  53. #ifndef AT_PLATFORM
  54. #define AT_PLATFORM 15
  55. #endif
  56. #ifndef HWCAP_NEON
  57. #define HWCAP_NEON (1 << 12)
  58. #endif
  59. #endif
  60. #if defined (SDL_PLATFORM_FREEBSD)
  61. #include <sys/param.h>
  62. #endif
  63. #if defined(SDL_PLATFORM_ANDROID) && defined(__arm__) && !defined(HAVE_GETAUXVAL)
  64. #include <cpu-features.h>
  65. #endif
  66. #if defined(HAVE_GETAUXVAL) || defined(HAVE_ELF_AUX_INFO)
  67. #include <sys/auxv.h>
  68. #endif
  69. #ifdef SDL_PLATFORM_RISCOS
  70. #include <kernel.h>
  71. #include <swis.h>
  72. #endif
  73. #ifdef SDL_PLATFORM_3DS
  74. #include <3ds.h>
  75. #endif
  76. #ifdef SDL_PLATFORM_PS2
  77. #include <kernel.h>
  78. #endif
  79. #ifdef SDL_PLATFORM_HAIKU
  80. #include <kernel/OS.h>
  81. #endif
  82. #define CPU_HAS_ALTIVEC (1 << 0)
  83. #define CPU_HAS_MMX (1 << 1)
  84. #define CPU_HAS_SSE (1 << 2)
  85. #define CPU_HAS_SSE2 (1 << 3)
  86. #define CPU_HAS_SSE3 (1 << 4)
  87. #define CPU_HAS_SSE41 (1 << 5)
  88. #define CPU_HAS_SSE42 (1 << 6)
  89. #define CPU_HAS_AVX (1 << 7)
  90. #define CPU_HAS_AVX2 (1 << 8)
  91. #define CPU_HAS_NEON (1 << 9)
  92. #define CPU_HAS_AVX512F (1 << 10)
  93. #define CPU_HAS_ARM_SIMD (1 << 11)
  94. #define CPU_HAS_LSX (1 << 12)
  95. #define CPU_HAS_LASX (1 << 13)
  96. #define CPU_CFG2 0x2
  97. #define CPU_CFG2_LSX (1 << 6)
  98. #define CPU_CFG2_LASX (1 << 7)
  99. #if !defined(SDL_CPUINFO_DISABLED) && \
  100. !((defined(SDL_PLATFORM_MACOS) && (defined(__ppc__) || defined(__ppc64__))) || (defined(SDL_PLATFORM_OPENBSD) && defined(__powerpc__))) && \
  101. !(defined(SDL_PLATFORM_FREEBSD) && defined(__powerpc__)) && \
  102. !(defined(SDL_PLATFORM_LINUX) && defined(__powerpc__) && defined(HAVE_GETAUXVAL)) && \
  103. defined(SDL_ALTIVEC_BLITTERS) && defined(HAVE_SETJMP)
  104. /* This is the brute force way of detecting instruction sets...
  105. the idea is borrowed from the libmpeg2 library - thanks!
  106. */
  107. static jmp_buf jmpbuf;
  108. static void illegal_instruction(int sig)
  109. {
  110. longjmp(jmpbuf, 1);
  111. }
  112. #endif // HAVE_SETJMP
  113. static int CPU_haveCPUID(void)
  114. {
  115. int has_CPUID = 0;
  116. /* *INDENT-OFF* */ // clang-format off
  117. #ifndef SDL_PLATFORM_EMSCRIPTEN
  118. #if (defined(__GNUC__) || defined(__llvm__)) && defined(__i386__)
  119. __asm__ (
  120. " pushfl # Get original EFLAGS \n"
  121. " popl %%eax \n"
  122. " movl %%eax,%%ecx \n"
  123. " xorl $0x200000,%%eax # Flip ID bit in EFLAGS \n"
  124. " pushl %%eax # Save new EFLAGS value on stack \n"
  125. " popfl # Replace current EFLAGS value \n"
  126. " pushfl # Get new EFLAGS \n"
  127. " popl %%eax # Store new EFLAGS in EAX \n"
  128. " xorl %%ecx,%%eax # Can not toggle ID bit, \n"
  129. " jz 1f # Processor=80486 \n"
  130. " movl $1,%0 # We have CPUID support \n"
  131. "1: \n"
  132. : "=m" (has_CPUID)
  133. :
  134. : "%eax", "%ecx"
  135. );
  136. #elif (defined(__GNUC__) || defined(__llvm__)) && defined(__x86_64__)
  137. /* Technically, if this is being compiled under __x86_64__ then it has
  138. CPUid by definition. But it's nice to be able to prove it. :) */
  139. __asm__ (
  140. " pushfq # Get original EFLAGS \n"
  141. " popq %%rax \n"
  142. " movq %%rax,%%rcx \n"
  143. " xorl $0x200000,%%eax # Flip ID bit in EFLAGS \n"
  144. " pushq %%rax # Save new EFLAGS value on stack \n"
  145. " popfq # Replace current EFLAGS value \n"
  146. " pushfq # Get new EFLAGS \n"
  147. " popq %%rax # Store new EFLAGS in EAX \n"
  148. " xorl %%ecx,%%eax # Can not toggle ID bit, \n"
  149. " jz 1f # Processor=80486 \n"
  150. " movl $1,%0 # We have CPUID support \n"
  151. "1: \n"
  152. : "=m" (has_CPUID)
  153. :
  154. : "%rax", "%rcx"
  155. );
  156. #elif defined(_MSC_VER) && defined(_M_IX86)
  157. __asm {
  158. pushfd ; Get original EFLAGS
  159. pop eax
  160. mov ecx, eax
  161. xor eax, 200000h ; Flip ID bit in EFLAGS
  162. push eax ; Save new EFLAGS value on stack
  163. popfd ; Replace current EFLAGS value
  164. pushfd ; Get new EFLAGS
  165. pop eax ; Store new EFLAGS in EAX
  166. xor eax, ecx ; Can not toggle ID bit,
  167. jz done ; Processor=80486
  168. mov has_CPUID,1 ; We have CPUID support
  169. done:
  170. }
  171. #elif defined(_MSC_VER) && defined(_M_X64)
  172. has_CPUID = 1;
  173. #elif defined(__sun) && defined(__i386)
  174. __asm (
  175. " pushfl \n"
  176. " popl %eax \n"
  177. " movl %eax,%ecx \n"
  178. " xorl $0x200000,%eax \n"
  179. " pushl %eax \n"
  180. " popfl \n"
  181. " pushfl \n"
  182. " popl %eax \n"
  183. " xorl %ecx,%eax \n"
  184. " jz 1f \n"
  185. " movl $1,-8(%ebp) \n"
  186. "1: \n"
  187. );
  188. #elif defined(__sun) && defined(__amd64)
  189. __asm (
  190. " pushfq \n"
  191. " popq %rax \n"
  192. " movq %rax,%rcx \n"
  193. " xorl $0x200000,%eax \n"
  194. " pushq %rax \n"
  195. " popfq \n"
  196. " pushfq \n"
  197. " popq %rax \n"
  198. " xorl %ecx,%eax \n"
  199. " jz 1f \n"
  200. " movl $1,-8(%rbp) \n"
  201. "1: \n"
  202. );
  203. #endif
  204. #endif // !SDL_PLATFORM_EMSCRIPTEN
  205. /* *INDENT-ON* */ // clang-format on
  206. return has_CPUID;
  207. }
  208. #if (defined(__GNUC__) || defined(__llvm__)) && defined(__i386__)
  209. #define cpuid(func, a, b, c, d) \
  210. __asm__ __volatile__( \
  211. " pushl %%ebx \n" \
  212. " xorl %%ecx,%%ecx \n" \
  213. " cpuid \n" \
  214. " movl %%ebx, %%esi \n" \
  215. " popl %%ebx \n" \
  216. : "=a"(a), "=S"(b), "=c"(c), "=d"(d) \
  217. : "a"(func))
  218. #elif (defined(__GNUC__) || defined(__llvm__)) && defined(__x86_64__)
  219. #define cpuid(func, a, b, c, d) \
  220. __asm__ __volatile__( \
  221. " pushq %%rbx \n" \
  222. " xorq %%rcx,%%rcx \n" \
  223. " cpuid \n" \
  224. " movq %%rbx, %%rsi \n" \
  225. " popq %%rbx \n" \
  226. : "=a"(a), "=S"(b), "=c"(c), "=d"(d) \
  227. : "a"(func))
  228. #elif defined(_MSC_VER) && defined(_M_IX86)
  229. #define cpuid(func, a, b, c, d) \
  230. __asm { \
  231. __asm mov eax, func \
  232. __asm xor ecx, ecx \
  233. __asm cpuid \
  234. __asm mov a, eax \
  235. __asm mov b, ebx \
  236. __asm mov c, ecx \
  237. __asm mov d, edx \
  238. }
  239. #elif (defined(_MSC_VER) && defined(_M_X64))
  240. // Use __cpuidex instead of __cpuid because ICL does not clear ecx register
  241. #define cpuid(func, a, b, c, d) \
  242. { \
  243. int CPUInfo[4]; \
  244. __cpuidex(CPUInfo, func, 0); \
  245. a = CPUInfo[0]; \
  246. b = CPUInfo[1]; \
  247. c = CPUInfo[2]; \
  248. d = CPUInfo[3]; \
  249. }
  250. #else
  251. #define cpuid(func, a, b, c, d) \
  252. do { \
  253. a = b = c = d = 0; \
  254. (void)a; \
  255. (void)b; \
  256. (void)c; \
  257. (void)d; \
  258. } while (0)
  259. #endif
  260. static int CPU_CPUIDFeatures[4];
  261. static int CPU_CPUIDMaxFunction = 0;
  262. static bool CPU_OSSavesYMM = false;
  263. static bool CPU_OSSavesZMM = false;
  264. static void CPU_calcCPUIDFeatures(void)
  265. {
  266. static bool checked = false;
  267. if (!checked) {
  268. checked = true;
  269. if (CPU_haveCPUID()) {
  270. int a, b, c, d;
  271. cpuid(0, a, b, c, d);
  272. CPU_CPUIDMaxFunction = a;
  273. if (CPU_CPUIDMaxFunction >= 1) {
  274. cpuid(1, a, b, c, d);
  275. CPU_CPUIDFeatures[0] = a;
  276. CPU_CPUIDFeatures[1] = b;
  277. CPU_CPUIDFeatures[2] = c;
  278. CPU_CPUIDFeatures[3] = d;
  279. // Check to make sure we can call xgetbv
  280. if (c & 0x08000000) {
  281. // Call xgetbv to see if YMM (etc) register state is saved
  282. #if (defined(__GNUC__) || defined(__llvm__)) && (defined(__i386__) || defined(__x86_64__))
  283. __asm__(".byte 0x0f, 0x01, 0xd0"
  284. : "=a"(a)
  285. : "c"(0)
  286. : "%edx");
  287. #elif defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64)) && (_MSC_FULL_VER >= 160040219) // VS2010 SP1
  288. a = (int)_xgetbv(0);
  289. #elif defined(_MSC_VER) && defined(_M_IX86)
  290. __asm
  291. {
  292. xor ecx, ecx
  293. _asm _emit 0x0f _asm _emit 0x01 _asm _emit 0xd0
  294. mov a, eax
  295. }
  296. #endif
  297. CPU_OSSavesYMM = ((a & 6) == 6) ? true : false;
  298. CPU_OSSavesZMM = (CPU_OSSavesYMM && ((a & 0xe0) == 0xe0)) ? true : false;
  299. }
  300. }
  301. }
  302. }
  303. }
  304. static int CPU_haveAltiVec(void)
  305. {
  306. volatile int altivec = 0;
  307. #ifndef SDL_CPUINFO_DISABLED
  308. #if (defined(SDL_PLATFORM_FREEBSD) || defined(SDL_PLATFORM_OPENBSD)) && defined(__powerpc__) && defined(HAVE_ELF_AUX_INFO)
  309. unsigned long cpufeatures = 0;
  310. elf_aux_info(AT_HWCAP, &cpufeatures, sizeof(cpufeatures));
  311. altivec = cpufeatures & PPC_FEATURE_HAS_ALTIVEC;
  312. return altivec;
  313. #elif (defined(SDL_PLATFORM_MACOS) && (defined(__ppc__) || defined(__ppc64__))) || (defined(SDL_PLATFORM_OPENBSD) && defined(__powerpc__))
  314. #ifdef SDL_PLATFORM_OPENBSD
  315. int selectors[2] = { CTL_MACHDEP, CPU_ALTIVEC };
  316. #else
  317. int selectors[2] = { CTL_HW, HW_VECTORUNIT };
  318. #endif
  319. int hasVectorUnit = 0;
  320. size_t length = sizeof(hasVectorUnit);
  321. int error = sysctl(selectors, 2, &hasVectorUnit, &length, NULL, 0);
  322. if (0 == error) {
  323. altivec = (hasVectorUnit != 0);
  324. }
  325. #elif defined(SDL_PLATFORM_LINUX) && defined(__powerpc__) && defined(HAVE_GETAUXVAL)
  326. altivec = getauxval(AT_HWCAP) & PPC_FEATURE_HAS_ALTIVEC;
  327. #elif defined(SDL_ALTIVEC_BLITTERS) && defined(HAVE_SETJMP)
  328. void (*handler)(int sig);
  329. handler = signal(SIGILL, illegal_instruction);
  330. if (setjmp(jmpbuf) == 0) {
  331. asm volatile("mtspr 256, %0\n\t"
  332. "vand %%v0, %%v0, %%v0" ::"r"(-1));
  333. altivec = 1;
  334. }
  335. signal(SIGILL, handler);
  336. #endif
  337. #endif
  338. return altivec;
  339. }
  340. #if (defined(__ARM_ARCH) && (__ARM_ARCH >= 6)) || defined(__aarch64__)
  341. static int CPU_haveARMSIMD(void)
  342. {
  343. return 1;
  344. }
  345. #elif !defined(__arm__)
  346. static int CPU_haveARMSIMD(void)
  347. {
  348. return 0;
  349. }
  350. #elif defined(SDL_PLATFORM_LINUX)
  351. static int CPU_haveARMSIMD(void)
  352. {
  353. int arm_simd = 0;
  354. int fd;
  355. fd = open("/proc/self/auxv", O_RDONLY | O_CLOEXEC);
  356. if (fd >= 0) {
  357. Elf32_auxv_t aux;
  358. while (read(fd, &aux, sizeof(aux)) == sizeof(aux)) {
  359. if (aux.a_type == AT_PLATFORM) {
  360. const char *plat = (const char *)aux.a_un.a_val;
  361. if (plat) {
  362. arm_simd = SDL_strncmp(plat, "v6l", 3) == 0 ||
  363. SDL_strncmp(plat, "v7l", 3) == 0;
  364. }
  365. }
  366. }
  367. close(fd);
  368. }
  369. return arm_simd;
  370. }
  371. #elif defined(SDL_PLATFORM_RISCOS)
  372. static int CPU_haveARMSIMD(void)
  373. {
  374. _kernel_swi_regs regs;
  375. regs.r[0] = 0;
  376. if (_kernel_swi(OS_PlatformFeatures, &regs, &regs) != NULL) {
  377. return 0;
  378. }
  379. if (!(regs.r[0] & (1 << 31))) {
  380. return 0;
  381. }
  382. regs.r[0] = 34;
  383. regs.r[1] = 29;
  384. if (_kernel_swi(OS_PlatformFeatures, &regs, &regs) != NULL) {
  385. return 0;
  386. }
  387. return regs.r[0];
  388. }
  389. #elif defined(SDL_PLATFORM_NGAGE)
  390. static int CPU_haveARMSIMD(void)
  391. {
  392. // The RM920T is based on the ARMv4T architecture and doesn't have SIMD.
  393. return 0;
  394. }
  395. #else
  396. static int CPU_haveARMSIMD(void)
  397. {
  398. #warning SDL_HasARMSIMD is not implemented for this ARM platform. Write me.
  399. return 0;
  400. }
  401. #endif
  402. #if defined(SDL_PLATFORM_LINUX) && defined(__arm__) && !defined(HAVE_GETAUXVAL)
  403. static int readProcAuxvForNeon(void)
  404. {
  405. int neon = 0;
  406. int fd;
  407. fd = open("/proc/self/auxv", O_RDONLY | O_CLOEXEC);
  408. if (fd >= 0) {
  409. Elf32_auxv_t aux;
  410. while (read(fd, &aux, sizeof(aux)) == sizeof(aux)) {
  411. if (aux.a_type == AT_HWCAP) {
  412. neon = (aux.a_un.a_val & HWCAP_NEON) == HWCAP_NEON;
  413. break;
  414. }
  415. }
  416. close(fd);
  417. }
  418. return neon;
  419. }
  420. #endif
  421. static int CPU_haveNEON(void)
  422. {
  423. /* The way you detect NEON is a privileged instruction on ARM, so you have
  424. query the OS kernel in a platform-specific way. :/ */
  425. #if defined(SDL_PLATFORM_WINDOWS) && (defined(_M_ARM) || defined(_M_ARM64))
  426. // Visual Studio, for ARM, doesn't define __ARM_ARCH. Handle this first.
  427. // Seems to have been removed
  428. #ifndef PF_ARM_NEON_INSTRUCTIONS_AVAILABLE
  429. #define PF_ARM_NEON_INSTRUCTIONS_AVAILABLE 19
  430. #endif
  431. // All WinRT ARM devices are required to support NEON, but just in case.
  432. return IsProcessorFeaturePresent(PF_ARM_NEON_INSTRUCTIONS_AVAILABLE) != 0;
  433. #elif (defined(__ARM_ARCH) && (__ARM_ARCH >= 8)) || defined(__aarch64__)
  434. return 1; // ARMv8 always has non-optional NEON support.
  435. #elif defined(SDL_PLATFORM_VITA)
  436. return 1;
  437. #elif defined(SDL_PLATFORM_3DS)
  438. return 0;
  439. #elif defined(SDL_PLATFORM_NGAGE)
  440. return 0; // The ARM920T is based on the ARMv4T architecture and doesn't have NEON.
  441. #elif defined(SDL_PLATFORM_APPLE) && defined(__ARM_ARCH) && (__ARM_ARCH >= 7)
  442. // (note that sysctlbyname("hw.optional.neon") doesn't work!)
  443. return 1; // all Apple ARMv7 chips and later have NEON.
  444. #elif defined(SDL_PLATFORM_APPLE)
  445. return 0; // assume anything else from Apple doesn't have NEON.
  446. #elif !defined(__arm__)
  447. return 0; // not an ARM CPU at all.
  448. #elif defined(HAVE_ELF_AUX_INFO)
  449. unsigned long hasneon = 0;
  450. if (elf_aux_info(AT_HWCAP, (void *)&hasneon, (int)sizeof(hasneon)) != 0) {
  451. return 0;
  452. }
  453. return (hasneon & HWCAP_NEON) == HWCAP_NEON;
  454. #elif (defined(SDL_PLATFORM_LINUX) || defined(SDL_PLATFORM_ANDROID)) && defined(HAVE_GETAUXVAL)
  455. return (getauxval(AT_HWCAP) & HWCAP_NEON) == HWCAP_NEON;
  456. #elif defined(SDL_PLATFORM_LINUX)
  457. return readProcAuxvForNeon();
  458. #elif defined(SDL_PLATFORM_ANDROID)
  459. // Use NDK cpufeatures to read either /proc/self/auxv or /proc/cpuinfo
  460. {
  461. AndroidCpuFamily cpu_family = android_getCpuFamily();
  462. if (cpu_family == ANDROID_CPU_FAMILY_ARM) {
  463. uint64_t cpu_features = android_getCpuFeatures();
  464. if (cpu_features & ANDROID_CPU_ARM_FEATURE_NEON) {
  465. return 1;
  466. }
  467. }
  468. return 0;
  469. }
  470. #elif defined(SDL_PLATFORM_RISCOS)
  471. // Use the VFPSupport_Features SWI to access the MVFR registers
  472. {
  473. _kernel_swi_regs regs;
  474. regs.r[0] = 0;
  475. if (_kernel_swi(VFPSupport_Features, &regs, &regs) == NULL) {
  476. if ((regs.r[2] & 0xFFF000) == 0x111000) {
  477. return 1;
  478. }
  479. }
  480. return 0;
  481. }
  482. #elif defined(SDL_PLATFORM_OPENBSD)
  483. return 1; // OpenBSD only supports ARMv7 CPUs that have NEON.
  484. #elif defined(SDL_PLATFORM_EMSCRIPTEN)
  485. return 0;
  486. #else
  487. #warning SDL_HasNEON is not implemented for this ARM platform. Write me.
  488. return 0;
  489. #endif
  490. }
  491. static int CPU_readCPUCFG(void)
  492. {
  493. uint32_t cfg2 = 0;
  494. #if defined __loongarch__
  495. __asm__ volatile(
  496. "cpucfg %0, %1 \n\t"
  497. : "+&r"(cfg2)
  498. : "r"(CPU_CFG2));
  499. #endif
  500. return cfg2;
  501. }
  502. #define CPU_haveLSX() (CPU_readCPUCFG() & CPU_CFG2_LSX)
  503. #define CPU_haveLASX() (CPU_readCPUCFG() & CPU_CFG2_LASX)
  504. #ifdef __e2k__
  505. #ifdef __MMX__
  506. #define CPU_haveMMX() (1)
  507. #else
  508. #define CPU_haveMMX() (0)
  509. #endif
  510. #ifdef __SSE__
  511. #define CPU_haveSSE() (1)
  512. #else
  513. #define CPU_haveSSE() (0)
  514. #endif
  515. #ifdef __SSE2__
  516. #define CPU_haveSSE2() (1)
  517. #else
  518. #define CPU_haveSSE2() (0)
  519. #endif
  520. #ifdef __SSE3__
  521. #define CPU_haveSSE3() (1)
  522. #else
  523. #define CPU_haveSSE3() (0)
  524. #endif
  525. #ifdef __SSE4_1__
  526. #define CPU_haveSSE41() (1)
  527. #else
  528. #define CPU_haveSSE41() (0)
  529. #endif
  530. #ifdef __SSE4_2__
  531. #define CPU_haveSSE42() (1)
  532. #else
  533. #define CPU_haveSSE42() (0)
  534. #endif
  535. #ifdef __AVX__
  536. #define CPU_haveAVX() (1)
  537. #else
  538. #define CPU_haveAVX() (0)
  539. #endif
  540. #else
  541. #define CPU_haveMMX() (CPU_CPUIDFeatures[3] & 0x00800000)
  542. #define CPU_haveSSE() (CPU_CPUIDFeatures[3] & 0x02000000)
  543. #define CPU_haveSSE2() (CPU_CPUIDFeatures[3] & 0x04000000)
  544. #define CPU_haveSSE3() (CPU_CPUIDFeatures[2] & 0x00000001)
  545. #define CPU_haveSSE41() (CPU_CPUIDFeatures[2] & 0x00080000)
  546. #define CPU_haveSSE42() (CPU_CPUIDFeatures[2] & 0x00100000)
  547. #define CPU_haveAVX() (CPU_OSSavesYMM && (CPU_CPUIDFeatures[2] & 0x10000000))
  548. #endif
  549. #ifdef __e2k__
  550. inline int
  551. CPU_haveAVX2(void)
  552. {
  553. #ifdef __AVX2__
  554. return 1;
  555. #else
  556. return 0;
  557. #endif
  558. }
  559. #else
  560. static int CPU_haveAVX2(void)
  561. {
  562. if (CPU_OSSavesYMM && (CPU_CPUIDMaxFunction >= 7)) {
  563. int a, b, c, d;
  564. (void)a;
  565. (void)b;
  566. (void)c;
  567. (void)d; // compiler warnings...
  568. cpuid(7, a, b, c, d);
  569. return b & 0x00000020;
  570. }
  571. return 0;
  572. }
  573. #endif
  574. #ifdef __e2k__
  575. inline int
  576. CPU_haveAVX512F(void)
  577. {
  578. return 0;
  579. }
  580. #else
  581. static int CPU_haveAVX512F(void)
  582. {
  583. if (CPU_OSSavesZMM && (CPU_CPUIDMaxFunction >= 7)) {
  584. int a, b, c, d;
  585. (void)a;
  586. (void)b;
  587. (void)c;
  588. (void)d; // compiler warnings...
  589. cpuid(7, a, b, c, d);
  590. return b & 0x00010000;
  591. }
  592. return 0;
  593. }
  594. #endif
  595. static int SDL_NumLogicalCPUCores = 0;
  596. int SDL_GetNumLogicalCPUCores(void)
  597. {
  598. if (!SDL_NumLogicalCPUCores) {
  599. #if defined(HAVE_SYSCONF) && defined(_SC_NPROCESSORS_ONLN)
  600. if (SDL_NumLogicalCPUCores <= 0) {
  601. SDL_NumLogicalCPUCores = (int)sysconf(_SC_NPROCESSORS_ONLN);
  602. }
  603. #endif
  604. #ifdef HAVE_SYSCTLBYNAME
  605. if (SDL_NumLogicalCPUCores <= 0) {
  606. size_t size = sizeof(SDL_NumLogicalCPUCores);
  607. sysctlbyname("hw.ncpu", &SDL_NumLogicalCPUCores, &size, NULL, 0);
  608. }
  609. #endif
  610. #if defined(SDL_PLATFORM_WINDOWS)
  611. if (SDL_NumLogicalCPUCores <= 0) {
  612. SYSTEM_INFO info;
  613. GetSystemInfo(&info);
  614. SDL_NumLogicalCPUCores = info.dwNumberOfProcessors;
  615. }
  616. #endif
  617. #ifdef SDL_PLATFORM_3DS
  618. if (SDL_NumLogicalCPUCores <= 0) {
  619. bool isNew3DS = false;
  620. APT_CheckNew3DS(&isNew3DS);
  621. // 1 core is always dedicated to the OS
  622. // Meaning that the New3DS has 3 available core, and the Old3DS only one.
  623. SDL_NumLogicalCPUCores = isNew3DS ? 4 : 2;
  624. }
  625. #endif
  626. // There has to be at least 1, right? :)
  627. if (SDL_NumLogicalCPUCores <= 0) {
  628. SDL_NumLogicalCPUCores = 1;
  629. }
  630. }
  631. return SDL_NumLogicalCPUCores;
  632. }
  633. #ifdef __e2k__
  634. inline const char *
  635. SDL_GetCPUType(void)
  636. {
  637. static char SDL_CPUType[13];
  638. SDL_strlcpy(SDL_CPUType, "E2K MACHINE", sizeof(SDL_CPUType));
  639. return SDL_CPUType;
  640. }
  641. #else
  642. // Oh, such a sweet sweet trick, just not very useful. :)
  643. static const char *SDL_GetCPUType(void)
  644. {
  645. static char SDL_CPUType[13];
  646. if (!SDL_CPUType[0]) {
  647. int i = 0;
  648. CPU_calcCPUIDFeatures();
  649. if (CPU_CPUIDMaxFunction > 0) { // do we have CPUID at all?
  650. int a, b, c, d;
  651. cpuid(0x00000000, a, b, c, d);
  652. (void)a;
  653. SDL_CPUType[i++] = (char)(b & 0xff);
  654. b >>= 8;
  655. SDL_CPUType[i++] = (char)(b & 0xff);
  656. b >>= 8;
  657. SDL_CPUType[i++] = (char)(b & 0xff);
  658. b >>= 8;
  659. SDL_CPUType[i++] = (char)(b & 0xff);
  660. SDL_CPUType[i++] = (char)(d & 0xff);
  661. d >>= 8;
  662. SDL_CPUType[i++] = (char)(d & 0xff);
  663. d >>= 8;
  664. SDL_CPUType[i++] = (char)(d & 0xff);
  665. d >>= 8;
  666. SDL_CPUType[i++] = (char)(d & 0xff);
  667. SDL_CPUType[i++] = (char)(c & 0xff);
  668. c >>= 8;
  669. SDL_CPUType[i++] = (char)(c & 0xff);
  670. c >>= 8;
  671. SDL_CPUType[i++] = (char)(c & 0xff);
  672. c >>= 8;
  673. SDL_CPUType[i++] = (char)(c & 0xff);
  674. }
  675. if (!SDL_CPUType[0]) {
  676. SDL_strlcpy(SDL_CPUType, "Unknown", sizeof(SDL_CPUType));
  677. }
  678. }
  679. return SDL_CPUType;
  680. }
  681. #endif
  682. #if 0
  683. !!! FIXME: Not used at the moment. */
  684. #ifdef __e2k__
  685. inline const char *
  686. SDL_GetCPUName(void)
  687. {
  688. static char SDL_CPUName[48];
  689. SDL_strlcpy(SDL_CPUName, __builtin_cpu_name(), sizeof(SDL_CPUName));
  690. return SDL_CPUName;
  691. }
  692. #else
  693. static const char *SDL_GetCPUName(void)
  694. {
  695. static char SDL_CPUName[48];
  696. if (!SDL_CPUName[0]) {
  697. int i = 0;
  698. int a, b, c, d;
  699. CPU_calcCPUIDFeatures();
  700. if (CPU_CPUIDMaxFunction > 0) { // do we have CPUID at all?
  701. cpuid(0x80000000, a, b, c, d);
  702. if (a >= 0x80000004) {
  703. cpuid(0x80000002, a, b, c, d);
  704. SDL_CPUName[i++] = (char)(a & 0xff);
  705. a >>= 8;
  706. SDL_CPUName[i++] = (char)(a & 0xff);
  707. a >>= 8;
  708. SDL_CPUName[i++] = (char)(a & 0xff);
  709. a >>= 8;
  710. SDL_CPUName[i++] = (char)(a & 0xff);
  711. a >>= 8;
  712. SDL_CPUName[i++] = (char)(b & 0xff);
  713. b >>= 8;
  714. SDL_CPUName[i++] = (char)(b & 0xff);
  715. b >>= 8;
  716. SDL_CPUName[i++] = (char)(b & 0xff);
  717. b >>= 8;
  718. SDL_CPUName[i++] = (char)(b & 0xff);
  719. b >>= 8;
  720. SDL_CPUName[i++] = (char)(c & 0xff);
  721. c >>= 8;
  722. SDL_CPUName[i++] = (char)(c & 0xff);
  723. c >>= 8;
  724. SDL_CPUName[i++] = (char)(c & 0xff);
  725. c >>= 8;
  726. SDL_CPUName[i++] = (char)(c & 0xff);
  727. c >>= 8;
  728. SDL_CPUName[i++] = (char)(d & 0xff);
  729. d >>= 8;
  730. SDL_CPUName[i++] = (char)(d & 0xff);
  731. d >>= 8;
  732. SDL_CPUName[i++] = (char)(d & 0xff);
  733. d >>= 8;
  734. SDL_CPUName[i++] = (char)(d & 0xff);
  735. d >>= 8;
  736. cpuid(0x80000003, a, b, c, d);
  737. SDL_CPUName[i++] = (char)(a & 0xff);
  738. a >>= 8;
  739. SDL_CPUName[i++] = (char)(a & 0xff);
  740. a >>= 8;
  741. SDL_CPUName[i++] = (char)(a & 0xff);
  742. a >>= 8;
  743. SDL_CPUName[i++] = (char)(a & 0xff);
  744. a >>= 8;
  745. SDL_CPUName[i++] = (char)(b & 0xff);
  746. b >>= 8;
  747. SDL_CPUName[i++] = (char)(b & 0xff);
  748. b >>= 8;
  749. SDL_CPUName[i++] = (char)(b & 0xff);
  750. b >>= 8;
  751. SDL_CPUName[i++] = (char)(b & 0xff);
  752. b >>= 8;
  753. SDL_CPUName[i++] = (char)(c & 0xff);
  754. c >>= 8;
  755. SDL_CPUName[i++] = (char)(c & 0xff);
  756. c >>= 8;
  757. SDL_CPUName[i++] = (char)(c & 0xff);
  758. c >>= 8;
  759. SDL_CPUName[i++] = (char)(c & 0xff);
  760. c >>= 8;
  761. SDL_CPUName[i++] = (char)(d & 0xff);
  762. d >>= 8;
  763. SDL_CPUName[i++] = (char)(d & 0xff);
  764. d >>= 8;
  765. SDL_CPUName[i++] = (char)(d & 0xff);
  766. d >>= 8;
  767. SDL_CPUName[i++] = (char)(d & 0xff);
  768. d >>= 8;
  769. cpuid(0x80000004, a, b, c, d);
  770. SDL_CPUName[i++] = (char)(a & 0xff);
  771. a >>= 8;
  772. SDL_CPUName[i++] = (char)(a & 0xff);
  773. a >>= 8;
  774. SDL_CPUName[i++] = (char)(a & 0xff);
  775. a >>= 8;
  776. SDL_CPUName[i++] = (char)(a & 0xff);
  777. a >>= 8;
  778. SDL_CPUName[i++] = (char)(b & 0xff);
  779. b >>= 8;
  780. SDL_CPUName[i++] = (char)(b & 0xff);
  781. b >>= 8;
  782. SDL_CPUName[i++] = (char)(b & 0xff);
  783. b >>= 8;
  784. SDL_CPUName[i++] = (char)(b & 0xff);
  785. b >>= 8;
  786. SDL_CPUName[i++] = (char)(c & 0xff);
  787. c >>= 8;
  788. SDL_CPUName[i++] = (char)(c & 0xff);
  789. c >>= 8;
  790. SDL_CPUName[i++] = (char)(c & 0xff);
  791. c >>= 8;
  792. SDL_CPUName[i++] = (char)(c & 0xff);
  793. c >>= 8;
  794. SDL_CPUName[i++] = (char)(d & 0xff);
  795. d >>= 8;
  796. SDL_CPUName[i++] = (char)(d & 0xff);
  797. d >>= 8;
  798. SDL_CPUName[i++] = (char)(d & 0xff);
  799. d >>= 8;
  800. SDL_CPUName[i++] = (char)(d & 0xff);
  801. d >>= 8;
  802. }
  803. }
  804. if (!SDL_CPUName[0]) {
  805. SDL_strlcpy(SDL_CPUName, "Unknown", sizeof(SDL_CPUName));
  806. }
  807. }
  808. return SDL_CPUName;
  809. }
  810. #endif
  811. #endif
  812. int SDL_GetCPUCacheLineSize(void)
  813. {
  814. const char *cpuType = SDL_GetCPUType();
  815. int cacheline_size = SDL_CACHELINE_SIZE; // initial guess
  816. int a, b, c, d;
  817. (void)a;
  818. (void)b;
  819. (void)c;
  820. (void)d;
  821. if (SDL_strcmp(cpuType, "GenuineIntel") == 0 || SDL_strcmp(cpuType, "CentaurHauls") == 0 || SDL_strcmp(cpuType, " Shanghai ") == 0) {
  822. cpuid(0x00000001, a, b, c, d);
  823. cacheline_size = ((b >> 8) & 0xff) * 8;
  824. } else if (SDL_strcmp(cpuType, "AuthenticAMD") == 0 || SDL_strcmp(cpuType, "HygonGenuine") == 0) {
  825. cpuid(0x80000005, a, b, c, d);
  826. cacheline_size = c & 0xff;
  827. } else {
  828. #if defined(HAVE_SYSCONF) && defined(_SC_LEVEL1_DCACHE_LINESIZE)
  829. if ((cacheline_size = (int)sysconf(_SC_LEVEL1_DCACHE_LINESIZE)) > 0) {
  830. return cacheline_size;
  831. } else {
  832. cacheline_size = SDL_CACHELINE_SIZE;
  833. }
  834. #endif
  835. #if defined(SDL_PLATFORM_LINUX)
  836. {
  837. FILE *f = fopen("/sys/devices/system/cpu/cpu0/cache/index0/coherency_line_size", "r");
  838. if (f) {
  839. int size;
  840. if (fscanf(f, "%d", &size) == 1) {
  841. cacheline_size = size;
  842. }
  843. fclose(f);
  844. }
  845. }
  846. #elif defined(__FREEBSD__) && defined(CACHE_LINE_SIZE)
  847. cacheline_size = CACHE_LINE_SIZE;
  848. #endif
  849. }
  850. return cacheline_size;
  851. }
  852. #define SDL_CPUFEATURES_RESET_VALUE 0xFFFFFFFF
  853. static Uint32 SDL_CPUFeatures = SDL_CPUFEATURES_RESET_VALUE;
  854. static Uint32 SDL_SIMDAlignment = 0xFFFFFFFF;
  855. static bool ref_string_equals(const char *ref, const char *test, const char *end_test) {
  856. size_t len_test = end_test - test;
  857. return SDL_strncmp(ref, test, len_test) == 0 && ref[len_test] == '\0' && (test[len_test] == '\0' || test[len_test] == ',');
  858. }
  859. static Uint32 SDLCALL SDL_CPUFeatureMaskFromHint(void)
  860. {
  861. Uint32 result_mask = SDL_CPUFEATURES_RESET_VALUE;
  862. const char *hint = SDL_GetHint(SDL_HINT_CPU_FEATURE_MASK);
  863. if (hint) {
  864. for (const char *spot = hint, *next; *spot; spot = next) {
  865. const char *end = SDL_strchr(spot, ',');
  866. Uint32 spot_mask;
  867. bool add_spot_mask = true;
  868. if (end) {
  869. next = end + 1;
  870. } else {
  871. size_t len = SDL_strlen(spot);
  872. end = spot + len;
  873. next = end;
  874. }
  875. if (spot[0] == '+') {
  876. add_spot_mask = true;
  877. spot += 1;
  878. } else if (spot[0] == '-') {
  879. add_spot_mask = false;
  880. spot += 1;
  881. }
  882. if (ref_string_equals("all", spot, end)) {
  883. spot_mask = SDL_CPUFEATURES_RESET_VALUE;
  884. } else if (ref_string_equals("altivec", spot, end)) {
  885. spot_mask= CPU_HAS_ALTIVEC;
  886. } else if (ref_string_equals("mmx", spot, end)) {
  887. spot_mask = CPU_HAS_MMX;
  888. } else if (ref_string_equals("sse", spot, end)) {
  889. spot_mask = CPU_HAS_SSE;
  890. } else if (ref_string_equals("sse2", spot, end)) {
  891. spot_mask = CPU_HAS_SSE2;
  892. } else if (ref_string_equals("sse3", spot, end)) {
  893. spot_mask = CPU_HAS_SSE3;
  894. } else if (ref_string_equals("sse41", spot, end)) {
  895. spot_mask = CPU_HAS_SSE41;
  896. } else if (ref_string_equals("sse42", spot, end)) {
  897. spot_mask = CPU_HAS_SSE42;
  898. } else if (ref_string_equals("avx", spot, end)) {
  899. spot_mask = CPU_HAS_AVX;
  900. } else if (ref_string_equals("avx2", spot, end)) {
  901. spot_mask = CPU_HAS_AVX2;
  902. } else if (ref_string_equals("avx512f", spot, end)) {
  903. spot_mask = CPU_HAS_AVX512F;
  904. } else if (ref_string_equals("arm-simd", spot, end)) {
  905. spot_mask = CPU_HAS_ARM_SIMD;
  906. } else if (ref_string_equals("neon", spot, end)) {
  907. spot_mask = CPU_HAS_NEON;
  908. } else if (ref_string_equals("lsx", spot, end)) {
  909. spot_mask = CPU_HAS_LSX;
  910. } else if (ref_string_equals("lasx", spot, end)) {
  911. spot_mask = CPU_HAS_LASX;
  912. } else {
  913. // Ignore unknown/incorrect cpu feature(s)
  914. continue;
  915. }
  916. if (add_spot_mask) {
  917. result_mask |= spot_mask;
  918. } else {
  919. result_mask &= ~spot_mask;
  920. }
  921. }
  922. }
  923. return result_mask;
  924. }
  925. static Uint32 SDL_GetCPUFeatures(void)
  926. {
  927. if (SDL_CPUFeatures == SDL_CPUFEATURES_RESET_VALUE) {
  928. CPU_calcCPUIDFeatures();
  929. SDL_CPUFeatures = 0;
  930. SDL_SIMDAlignment = sizeof(void *); // a good safe base value
  931. if (CPU_haveAltiVec()) {
  932. SDL_CPUFeatures |= CPU_HAS_ALTIVEC;
  933. SDL_SIMDAlignment = SDL_max(SDL_SIMDAlignment, 16);
  934. }
  935. if (CPU_haveMMX()) {
  936. SDL_CPUFeatures |= CPU_HAS_MMX;
  937. SDL_SIMDAlignment = SDL_max(SDL_SIMDAlignment, 8);
  938. }
  939. if (CPU_haveSSE()) {
  940. SDL_CPUFeatures |= CPU_HAS_SSE;
  941. SDL_SIMDAlignment = SDL_max(SDL_SIMDAlignment, 16);
  942. }
  943. if (CPU_haveSSE2()) {
  944. SDL_CPUFeatures |= CPU_HAS_SSE2;
  945. SDL_SIMDAlignment = SDL_max(SDL_SIMDAlignment, 16);
  946. }
  947. if (CPU_haveSSE3()) {
  948. SDL_CPUFeatures |= CPU_HAS_SSE3;
  949. SDL_SIMDAlignment = SDL_max(SDL_SIMDAlignment, 16);
  950. }
  951. if (CPU_haveSSE41()) {
  952. SDL_CPUFeatures |= CPU_HAS_SSE41;
  953. SDL_SIMDAlignment = SDL_max(SDL_SIMDAlignment, 16);
  954. }
  955. if (CPU_haveSSE42()) {
  956. SDL_CPUFeatures |= CPU_HAS_SSE42;
  957. SDL_SIMDAlignment = SDL_max(SDL_SIMDAlignment, 16);
  958. }
  959. if (CPU_haveAVX()) {
  960. SDL_CPUFeatures |= CPU_HAS_AVX;
  961. SDL_SIMDAlignment = SDL_max(SDL_SIMDAlignment, 32);
  962. }
  963. if (CPU_haveAVX2()) {
  964. SDL_CPUFeatures |= CPU_HAS_AVX2;
  965. SDL_SIMDAlignment = SDL_max(SDL_SIMDAlignment, 32);
  966. }
  967. if (CPU_haveAVX512F()) {
  968. SDL_CPUFeatures |= CPU_HAS_AVX512F;
  969. SDL_SIMDAlignment = SDL_max(SDL_SIMDAlignment, 64);
  970. }
  971. if (CPU_haveARMSIMD()) {
  972. SDL_CPUFeatures |= CPU_HAS_ARM_SIMD;
  973. SDL_SIMDAlignment = SDL_max(SDL_SIMDAlignment, 16);
  974. }
  975. if (CPU_haveNEON()) {
  976. SDL_CPUFeatures |= CPU_HAS_NEON;
  977. SDL_SIMDAlignment = SDL_max(SDL_SIMDAlignment, 16);
  978. }
  979. if (CPU_haveLSX()) {
  980. SDL_CPUFeatures |= CPU_HAS_LSX;
  981. SDL_SIMDAlignment = SDL_max(SDL_SIMDAlignment, 16);
  982. }
  983. if (CPU_haveLASX()) {
  984. SDL_CPUFeatures |= CPU_HAS_LASX;
  985. SDL_SIMDAlignment = SDL_max(SDL_SIMDAlignment, 32);
  986. }
  987. SDL_CPUFeatures &= SDL_CPUFeatureMaskFromHint();
  988. }
  989. return SDL_CPUFeatures;
  990. }
  991. void SDL_QuitCPUInfo(void) {
  992. SDL_CPUFeatures = SDL_CPUFEATURES_RESET_VALUE;
  993. }
  994. #define CPU_FEATURE_AVAILABLE(f) ((SDL_GetCPUFeatures() & (f)) ? true : false)
  995. bool SDL_HasAltiVec(void)
  996. {
  997. return CPU_FEATURE_AVAILABLE(CPU_HAS_ALTIVEC);
  998. }
  999. bool SDL_HasMMX(void)
  1000. {
  1001. return CPU_FEATURE_AVAILABLE(CPU_HAS_MMX);
  1002. }
  1003. bool SDL_HasSSE(void)
  1004. {
  1005. return CPU_FEATURE_AVAILABLE(CPU_HAS_SSE);
  1006. }
  1007. bool SDL_HasSSE2(void)
  1008. {
  1009. return CPU_FEATURE_AVAILABLE(CPU_HAS_SSE2);
  1010. }
  1011. bool SDL_HasSSE3(void)
  1012. {
  1013. return CPU_FEATURE_AVAILABLE(CPU_HAS_SSE3);
  1014. }
  1015. bool SDL_HasSSE41(void)
  1016. {
  1017. return CPU_FEATURE_AVAILABLE(CPU_HAS_SSE41);
  1018. }
  1019. bool SDL_HasSSE42(void)
  1020. {
  1021. return CPU_FEATURE_AVAILABLE(CPU_HAS_SSE42);
  1022. }
  1023. bool SDL_HasAVX(void)
  1024. {
  1025. return CPU_FEATURE_AVAILABLE(CPU_HAS_AVX);
  1026. }
  1027. bool SDL_HasAVX2(void)
  1028. {
  1029. return CPU_FEATURE_AVAILABLE(CPU_HAS_AVX2);
  1030. }
  1031. bool SDL_HasAVX512F(void)
  1032. {
  1033. return CPU_FEATURE_AVAILABLE(CPU_HAS_AVX512F);
  1034. }
  1035. bool SDL_HasARMSIMD(void)
  1036. {
  1037. return CPU_FEATURE_AVAILABLE(CPU_HAS_ARM_SIMD);
  1038. }
  1039. bool SDL_HasNEON(void)
  1040. {
  1041. return CPU_FEATURE_AVAILABLE(CPU_HAS_NEON);
  1042. }
  1043. bool SDL_HasLSX(void)
  1044. {
  1045. return CPU_FEATURE_AVAILABLE(CPU_HAS_LSX);
  1046. }
  1047. bool SDL_HasLASX(void)
  1048. {
  1049. return CPU_FEATURE_AVAILABLE(CPU_HAS_LASX);
  1050. }
  1051. static int SDL_SystemRAM = 0;
  1052. int SDL_GetSystemRAM(void)
  1053. {
  1054. if (!SDL_SystemRAM) {
  1055. #if defined(HAVE_SYSCONF) && defined(_SC_PHYS_PAGES) && defined(_SC_PAGESIZE)
  1056. if (SDL_SystemRAM <= 0) {
  1057. SDL_SystemRAM = (int)((Sint64)sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGESIZE) / (1024 * 1024));
  1058. }
  1059. #endif
  1060. #ifdef HAVE_SYSCTLBYNAME
  1061. if (SDL_SystemRAM <= 0) {
  1062. #ifdef HW_PHYSMEM64
  1063. // (64-bit): NetBSD since 2003, OpenBSD
  1064. int mib[2] = { CTL_HW, HW_PHYSMEM64 };
  1065. #elif defined(HW_REALMEM)
  1066. // (64-bit): FreeBSD since 2005, DragonFly
  1067. int mib[2] = { CTL_HW, HW_REALMEM };
  1068. #elif defined(HW_MEMSIZE)
  1069. // (64-bit): Darwin
  1070. int mib[2] = { CTL_HW, HW_MEMSIZE };
  1071. #else
  1072. // (32-bit): very old BSD, might only report up to 2 GiB
  1073. int mib[2] = { CTL_HW, HW_PHYSMEM };
  1074. #endif // HW_PHYSMEM64
  1075. Uint64 memsize = 0;
  1076. size_t len = sizeof(memsize);
  1077. if (sysctl(mib, 2, &memsize, &len, NULL, 0) == 0) {
  1078. SDL_SystemRAM = (int)(memsize / (1024 * 1024));
  1079. }
  1080. }
  1081. #endif
  1082. #if defined(SDL_PLATFORM_WINDOWS)
  1083. if (SDL_SystemRAM <= 0) {
  1084. MEMORYSTATUSEX stat;
  1085. stat.dwLength = sizeof(stat);
  1086. if (GlobalMemoryStatusEx(&stat)) {
  1087. SDL_SystemRAM = (int)(stat.ullTotalPhys / (1024 * 1024));
  1088. }
  1089. }
  1090. #endif
  1091. #ifdef SDL_PLATFORM_RISCOS
  1092. if (SDL_SystemRAM <= 0) {
  1093. _kernel_swi_regs regs;
  1094. regs.r[0] = 0x108;
  1095. if (_kernel_swi(OS_Memory, &regs, &regs) == NULL) {
  1096. SDL_SystemRAM = (int)(regs.r[1] * regs.r[2] / (1024 * 1024));
  1097. }
  1098. }
  1099. #endif
  1100. #ifdef SDL_PLATFORM_3DS
  1101. if (SDL_SystemRAM <= 0) {
  1102. // The New3DS has 255MiB, the Old3DS 127MiB
  1103. SDL_SystemRAM = (int)(osGetMemRegionSize(MEMREGION_ALL) / (1024 * 1024));
  1104. }
  1105. #endif
  1106. #ifdef SDL_PLATFORM_VITA
  1107. if (SDL_SystemRAM <= 0) {
  1108. /* Vita has 512MiB on SoC, that's split into 256MiB(+109MiB in extended memory mode) for app
  1109. +26MiB of physically continuous memory, +112MiB of CDRAM(VRAM) + system reserved memory. */
  1110. SDL_SystemRAM = 536870912;
  1111. }
  1112. #endif
  1113. #ifdef SDL_PLATFORM_PS2
  1114. if (SDL_SystemRAM <= 0) {
  1115. // PlayStation 2 has 32MiB however there are some special models with 64 and 128
  1116. SDL_SystemRAM = GetMemorySize();
  1117. }
  1118. #endif
  1119. #ifdef SDL_PLATFORM_HAIKU
  1120. if (SDL_SystemRAM <= 0) {
  1121. system_info info;
  1122. if (get_system_info(&info) == B_OK) {
  1123. /* To have an accurate amount, we also take in account the inaccessible pages (aka ignored)
  1124. which is a bit handier compared to the legacy system's api (i.e. used_pages).*/
  1125. SDL_SystemRAM = (int)SDL_round((info.max_pages + info.ignored_pages > 0 ? info.ignored_pages : 0) * B_PAGE_SIZE / 1048576.0);
  1126. }
  1127. }
  1128. #endif
  1129. }
  1130. return SDL_SystemRAM;
  1131. }
  1132. static int SDL_SystemPageSize = -1;
  1133. int SDL_GetSystemPageSize(void)
  1134. {
  1135. if (SDL_SystemPageSize == -1) {
  1136. #ifdef SDL_PLATFORM_SYSTEM_PAGE_SIZE_PRIVATE // consoles will define this in a platform-specific internal header.
  1137. SDL_SystemPageSize = SDL_PLATFORM_SYSTEM_PAGE_SIZE_PRIVATE;
  1138. #endif
  1139. #ifdef SDL_PLATFORM_3DS
  1140. SDL_SystemPageSize = 4096; // It's an ARM11 CPU; I assume this is 4K.
  1141. #endif
  1142. #ifdef SDL_PLATFORM_VITA
  1143. SDL_SystemPageSize = 4096; // It's an ARMv7 CPU; I assume this is 4K.
  1144. #endif
  1145. #ifdef SDL_PLATFORM_PS2
  1146. SDL_SystemPageSize = 4096; // It's a MIPS R5900 CPU; I assume this is 4K.
  1147. #endif
  1148. #if defined(HAVE_SYSCONF) && (defined(_SC_PAGESIZE) || defined(_SC_PAGE_SIZE))
  1149. if (SDL_SystemPageSize <= 0) {
  1150. #if defined(_SC_PAGE_SIZE)
  1151. SDL_SystemPageSize = sysconf(_SC_PAGE_SIZE);
  1152. #else
  1153. SDL_SystemPageSize = sysconf(_SC_PAGESIZE);
  1154. #endif
  1155. }
  1156. #endif
  1157. #if defined(HAVE_SYSCTLBYNAME) && defined(HW_PAGESIZE)
  1158. if (SDL_SystemPageSize <= 0) {
  1159. // NetBSD, OpenBSD, FreeBSD, Darwin...everything agrees to use HW_PAGESIZE.
  1160. int mib[2] = { CTL_HW, HW_PAGESIZE };
  1161. int pagesize = 0;
  1162. size_t len = sizeof(pagesize);
  1163. if (sysctl(mib, 2, &pagesize, &len, NULL, 0) == 0) {
  1164. SDL_SystemPageSize = pagesize;
  1165. }
  1166. }
  1167. #endif
  1168. #ifdef HAVE_GETPAGESIZE
  1169. if (SDL_SystemPageSize <= 0) {
  1170. SDL_SystemPageSize = getpagesize();
  1171. }
  1172. #endif
  1173. #if defined(SDL_PLATFORM_WINDOWS)
  1174. if (SDL_SystemPageSize <= 0) {
  1175. SYSTEM_INFO sysinfo;
  1176. GetSystemInfo(&sysinfo);
  1177. SDL_SystemPageSize = (int) sysinfo.dwPageSize;
  1178. }
  1179. #endif
  1180. if (SDL_SystemPageSize < 0) { // in case we got a weird result somewhere, or no better information, force it to 0.
  1181. SDL_SystemPageSize = 0; // unknown page size, sorry.
  1182. }
  1183. }
  1184. return SDL_SystemPageSize;
  1185. }
  1186. size_t SDL_GetSIMDAlignment(void)
  1187. {
  1188. if (SDL_SIMDAlignment == 0xFFFFFFFF) {
  1189. SDL_GetCPUFeatures(); // make sure this has been calculated
  1190. }
  1191. SDL_assert(SDL_SIMDAlignment != 0);
  1192. return SDL_SIMDAlignment;
  1193. }