| | |
| | | /* |
| | | Simple DirectMedia Layer |
| | | Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> |
| | | Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org> |
| | | |
| | | This software is provided 'as-is', without any express or implied |
| | | warranty. In no event will the authors be held liable for any damages |
| | |
| | | #include "SDL_config.h" |
| | | #else |
| | | #include "../SDL_internal.h" |
| | | #include "SDL_simd.h" |
| | | #endif |
| | | |
| | | #if defined(__WIN32__) |
| | | #if defined(__WIN32__) || defined(__WINRT__) |
| | | #include "../core/windows/SDL_windows.h" |
| | | #endif |
| | | #if defined(__OS2__) |
| | |
| | | #ifndef AT_HWCAP |
| | | #define AT_HWCAP 16 |
| | | #endif |
| | | #ifndef AT_PLATFORM |
| | | #define AT_PLATFORM 15 |
| | | #endif |
| | | /* Prevent compilation error when including elf.h would also try to define AT_* as an enum */ |
| | | #ifndef AT_NULL |
| | | #define AT_NULL 0 |
| | | #endif |
| | | #ifndef HWCAP_NEON |
| | | #define HWCAP_NEON (1 << 12) |
| | | #endif |
| | |
| | | #else |
| | | #include <fcntl.h> |
| | | #endif |
| | | #endif |
| | | |
| | | #if defined(__ANDROID__) && defined(__ARM_ARCH) && !defined(HAVE_GETAUXVAL) |
| | | #if __ARM_ARCH < 8 |
| | | #include <cpu-features.h> |
| | | #endif |
| | | #endif |
| | | |
| | | #ifdef __RISCOS__ |
| | | #include <kernel.h> |
| | | #include <swis.h> |
| | | #endif |
| | | |
| | | #define CPU_HAS_RDTSC (1 << 0) |
| | |
| | | #define CPU_HAS_AVX2 (1 << 10) |
| | | #define CPU_HAS_NEON (1 << 11) |
| | | #define CPU_HAS_AVX512F (1 << 12) |
| | | #define CPU_HAS_ARM_SIMD (1 << 13) |
| | | |
| | | #if SDL_ALTIVEC_BLITTERS && HAVE_SETJMP && !__MACOSX__ && !__OpenBSD__ |
| | | /* This is the brute force way of detecting instruction sets... |
| | |
| | | return altivec; |
| | | } |
| | | |
| | | #if (defined(__LINUX__) || defined(__ANDROID__)) && defined(__ARM_ARCH) && !defined(HAVE_GETAUXVAL) |
| | | #if defined(__ARM_ARCH) && (__ARM_ARCH >= 6) |
| | | static int |
| | | CPU_haveARMSIMD(void) |
| | | { |
| | | return 1; |
| | | } |
| | | |
| | | #elif !defined(__arm__) |
| | | static int |
| | | CPU_haveARMSIMD(void) |
| | | { |
| | | return 0; |
| | | } |
| | | |
| | | #elif defined(__LINUX__) |
| | | #include <unistd.h> |
| | | #include <sys/types.h> |
| | | #include <sys/stat.h> |
| | | #include <fcntl.h> |
| | | #include <elf.h> |
| | | |
| | | static int |
| | | CPU_haveARMSIMD(void) |
| | | { |
| | | int arm_simd = 0; |
| | | int fd; |
| | | |
| | | fd = open("/proc/self/auxv", O_RDONLY); |
| | | if (fd >= 0) |
| | | { |
| | | Elf32_auxv_t aux; |
| | | while (read(fd, &aux, sizeof aux) == sizeof aux) |
| | | { |
| | | if (aux.a_type == AT_PLATFORM) |
| | | { |
| | | const char *plat = (const char *) aux.a_un.a_val; |
| | | if (plat) { |
| | | arm_simd = strncmp(plat, "v6l", 3) == 0 || |
| | | strncmp(plat, "v7l", 3) == 0; |
| | | } |
| | | } |
| | | } |
| | | close(fd); |
| | | } |
| | | return arm_simd; |
| | | } |
| | | |
| | | #elif defined(__RISCOS__) |
| | | |
| | | static int |
| | | CPU_haveARMSIMD(void) |
| | | { |
| | | _kernel_swi_regs regs; |
| | | regs.r[0] = 0; |
| | | if (_kernel_swi(OS_PlatformFeatures, ®s, ®s) != NULL) |
| | | return 0; |
| | | |
| | | if (!(regs.r[0] & (1<<31))) |
| | | return 0; |
| | | |
| | | regs.r[0] = 34; |
| | | regs.r[1] = 29; |
| | | if (_kernel_swi(OS_PlatformFeatures, ®s, ®s) != NULL) |
| | | return 0; |
| | | |
| | | return regs.r[0]; |
| | | } |
| | | |
| | | #else |
| | | static int |
| | | CPU_haveARMSIMD(void) |
| | | { |
| | | #warning SDL_HasARMSIMD is not implemented for this ARM platform. Write me. |
| | | return 0; |
| | | } |
| | | #endif |
| | | |
| | | #if defined(__LINUX__) && defined(__ARM_ARCH) && !defined(HAVE_GETAUXVAL) |
| | | static int |
| | | readProcAuxvForNeon(void) |
| | | { |
| | |
| | | } |
| | | #endif |
| | | |
| | | |
| | | static int |
| | | CPU_haveNEON(void) |
| | | { |
| | | /* The way you detect NEON is a privileged instruction on ARM, so you have |
| | | query the OS kernel in a platform-specific way. :/ */ |
| | | #if defined(SDL_CPUINFO_DISABLED) || !defined(__ARM_ARCH) |
| | | return 0; /* disabled or not an ARM CPU at all. */ |
| | | #elif __ARM_ARCH >= 8 |
| | | #if defined(SDL_CPUINFO_DISABLED) |
| | | return 0; /* disabled */ |
| | | #elif (defined(__WINDOWS__) || defined(__WINRT__)) && (defined(_M_ARM) || defined(_M_ARM64)) |
| | | /* Visual Studio, for ARM, doesn't define __ARM_ARCH. Handle this first. */ |
| | | /* Seems to have been removed */ |
| | | # if !defined(PF_ARM_NEON_INSTRUCTIONS_AVAILABLE) |
| | | # define PF_ARM_NEON_INSTRUCTIONS_AVAILABLE 19 |
| | | # endif |
| | | /* All WinRT ARM devices are required to support NEON, but just in case. */ |
| | | return IsProcessorFeaturePresent(PF_ARM_NEON_INSTRUCTIONS_AVAILABLE) != 0; |
| | | #elif defined(__ARM_ARCH) && (__ARM_ARCH >= 8) |
| | | return 1; /* ARMv8 always has non-optional NEON support. */ |
| | | #elif defined(__APPLE__) && (__ARM_ARCH >= 7) |
| | | #elif defined(__APPLE__) && defined(__ARM_ARCH) && (__ARM_ARCH >= 7) |
| | | /* (note that sysctlbyname("hw.optional.neon") doesn't work!) */ |
| | | return 1; /* all Apple ARMv7 chips and later have NEON. */ |
| | | #elif defined(__APPLE__) |
| | | return 0; /* assume anything else from Apple doesn't have NEON. */ |
| | | #elif !defined(__arm__) |
| | | return 0; /* not an ARM CPU at all. */ |
| | | #elif defined(__QNXNTO__) |
| | | return SYSPAGE_ENTRY(cpuinfo)->flags & ARM_CPU_FLAG_NEON; |
| | | #elif (defined(__LINUX__) || defined(__ANDROID__)) && defined(HAVE_GETAUXVAL) |
| | | return ((getauxval(AT_HWCAP) & HWCAP_NEON) == HWCAP_NEON); |
| | | #elif (defined(__LINUX__) || defined(__ANDROID__)) |
| | | return readProcAuxvForNeon(); /* Android offers a static library for this, but it just parses /proc/self/auxv */ |
| | | #elif (defined(__WINDOWS__) || defined(__WINRT__)) && defined(_M_ARM) |
| | | /* All WinRT ARM devices are required to support NEON, but just in case. */ |
| | | return IsProcessorFeaturePresent(PF_ARM_NEON_INSTRUCTIONS_AVAILABLE) != 0; |
| | | #elif defined(__LINUX__) |
| | | return readProcAuxvForNeon(); |
| | | #elif defined(__ANDROID__) |
| | | /* Use NDK cpufeatures to read either /proc/self/auxv or /proc/cpuinfo */ |
| | | { |
| | | AndroidCpuFamily cpu_family = android_getCpuFamily(); |
| | | if (cpu_family == ANDROID_CPU_FAMILY_ARM) { |
| | | uint64_t cpu_features = android_getCpuFeatures(); |
| | | if ((cpu_features & ANDROID_CPU_ARM_FEATURE_NEON) != 0) { |
| | | return 1; |
| | | } |
| | | } |
| | | return 0; |
| | | } |
| | | #elif defined(__RISCOS__) |
| | | /* Use the VFPSupport_Features SWI to access the MVFR registers */ |
| | | { |
| | | _kernel_swi_regs regs; |
| | | regs.r[0] = 0; |
| | | if (_kernel_swi(VFPSupport_Features, ®s, ®s) == NULL) { |
| | | if ((regs.r[2] & 0xFFF000) == 0x111000) { |
| | | return 1; |
| | | } |
| | | } |
| | | return 0; |
| | | } |
| | | #else |
| | | #warning SDL_HasNEON is not implemented for this ARM platform. Write me. |
| | | return 0; |
| | |
| | | if (SDL_strcmp(cpuType, "GenuineIntel") == 0) { |
| | | cpuid(0x00000001, a, b, c, d); |
| | | return (((b >> 8) & 0xff) * 8); |
| | | } else if (SDL_strcmp(cpuType, "AuthenticAMD") == 0) { |
| | | } else if (SDL_strcmp(cpuType, "AuthenticAMD") == 0 || SDL_strcmp(cpuType, "HygonGenuine") == 0) { |
| | | cpuid(0x80000005, a, b, c, d); |
| | | return (c & 0xff); |
| | | } else { |
| | |
| | | if (SDL_CPUFeatures == 0xFFFFFFFF) { |
| | | CPU_calcCPUIDFeatures(); |
| | | SDL_CPUFeatures = 0; |
| | | SDL_SIMDAlignment = 4; /* a good safe base value */ |
| | | SDL_SIMDAlignment = sizeof(void *); /* a good safe base value */ |
| | | if (CPU_haveRDTSC()) { |
| | | SDL_CPUFeatures |= CPU_HAS_RDTSC; |
| | | } |
| | |
| | | if (CPU_haveAVX512F()) { |
| | | SDL_CPUFeatures |= CPU_HAS_AVX512F; |
| | | SDL_SIMDAlignment = SDL_max(SDL_SIMDAlignment, 64); |
| | | } |
| | | if (CPU_haveARMSIMD()) { |
| | | SDL_CPUFeatures |= CPU_HAS_ARM_SIMD; |
| | | SDL_SIMDAlignment = SDL_max(SDL_SIMDAlignment, 16); |
| | | } |
| | | if (CPU_haveNEON()) { |
| | | SDL_CPUFeatures |= CPU_HAS_NEON; |
| | |
| | | } |
| | | |
| | | SDL_bool |
| | | SDL_HasARMSIMD(void) |
| | | { |
| | | return CPU_FEATURE_AVAILABLE(CPU_HAS_ARM_SIMD); |
| | | } |
| | | |
| | | SDL_bool |
| | | SDL_HasNEON(void) |
| | | { |
| | | return CPU_FEATURE_AVAILABLE(CPU_HAS_NEON); |
| | |
| | | Uint32 sysram = 0; |
| | | DosQuerySysInfo(QSV_TOTPHYSMEM, QSV_TOTPHYSMEM, &sysram, 4); |
| | | SDL_SystemRAM = (int) (sysram / 0x100000U); |
| | | } |
| | | #endif |
| | | #ifdef __RISCOS__ |
| | | if (SDL_SystemRAM <= 0) { |
| | | _kernel_swi_regs regs; |
| | | regs.r[0] = 0x108; |
| | | if (_kernel_swi(OS_Memory, ®s, ®s) == NULL) { |
| | | SDL_SystemRAM = (int)(regs.r[1] * regs.r[2] / (1024 * 1024)); |
| | | } |
| | | } |
| | | #endif |
| | | #endif |
| | |
| | | printf("AVX: %d\n", SDL_HasAVX()); |
| | | printf("AVX2: %d\n", SDL_HasAVX2()); |
| | | printf("AVX-512F: %d\n", SDL_HasAVX512F()); |
| | | printf("ARM SIMD: %d\n", SDL_HasARMSIMD()); |
| | | printf("NEON: %d\n", SDL_HasNEON()); |
| | | printf("RAM: %d MB\n", SDL_GetSystemRAM()); |
| | | return 0; |