cpuinfo: more work on SDL_HasNEON().

This commit is contained in:
Ryan C. Gordon 2016-11-17 15:57:58 -05:00
parent db97c3d3e8
commit 74eb78dcbf

View File

@ -50,13 +50,7 @@
#include <setjmp.h> #include <setjmp.h>
#endif #endif
#if 0 /* !!! FIXME */ #if defined(__LINUX__) && defined(__ARM_ARCH)
#if defined(__ANDROID__) && defined(__ARM_ARCH)
#include <cpu-features.h>
#endif
#endif
#if defined(__LINUX__) && defined(__ARM_ARCH) && HAVE_GETAUXVAL
#include <sys/auxv.h> #include <sys/auxv.h>
#include <asm/hwcap.h> #include <asm/hwcap.h>
#endif #endif
@ -300,38 +294,61 @@ CPU_haveAltiVec(void)
return altivec; return altivec;
} }
#if (defined(__LINUX__) || defined(__ANDROID__)) && !HAVE_GETAUXVAL
static int
readProcAuxvForNeon(void)
{
int neon = 0;
int kv[2];
const int fd = open("/proc/self/auxv", O_RDONLY);
if (fd == -1) {
return 0;
}
while (read(fd, kv, sizeof (kv)) == sizeof (kv)) {
if (kv[0] == AT_HWCAP) {
neon = ((kv[1] & HWCAP_NEON) == HWCAP_NEON);
break;
}
}
close(fd);
return neon;
}
#endif
static int static int
CPU_haveNEON(void) CPU_haveNEON(void)
{ {
int neon = 0;
/* The way you detect NEON is a privileged instruction on ARM, so you have /* The way you detect NEON is a privileged instruction on ARM, so you have
query the OS kernel in a platform-specific way. :/ */ query the OS kernel in a platform-specific way. :/ */
#ifndef SDL_CPUINFO_DISABLED #if defined(SDL_CPUINFO_DISABLED) || !defined(__ARM_ARCH)
#if defined(__APPLE__) && defined(__ARM_ARCH) return 0;
#elif __ARM_ARCH >= 8
return 1; // ARMv8 always has non-optional NEON support.
#elif defined(__APPLE__)
/* all hardware that runs iOS 5 and later support NEON, but check anyhow */ /* all hardware that runs iOS 5 and later support NEON, but check anyhow */
int neon = 0;
size_t length = sizeof (neon); size_t length = sizeof (neon);
const int error = sysctlbyname("hw.optional.neon", &neon, &length, NULL, 0); const int error = sysctlbyname("hw.optional.neon", &neon, &length, NULL, 0);
if (!error) return (!error) && (neon != 0);
neon = (neon != 0); /* Android offers a static library for this but all it does is parse /proc/cpuinfo */
#elif 0 && defined(__ANDROID__) && defined(__ARM_ARCH) /* !!! FIXME */ #elif (defined(__LINUX__) || defined(__ANDROID__)) && HAVE_GETAUXVAL
if ( (android_getCpuFamily() == ANDROID_CPU_FAMILY_ARM) && return ((getauxval(AT_HWCAP) & HWCAP_NEON) == HWCAP_NEON)
((android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON) != 0) ) { #elif (defined(__LINUX__) || defined(__ANDROID__))
neon = 1; return readProcAuxvForNeon();
}
#elif defined(__LINUX__) && defined(__ARM_ARCH) && HAVE_GETAUXVAL
if (getauxval(AT_HWCAP) & HWCAP_NEON) {
neon = 1;
}
#elif (defined(__WINDOWS__) || defined(__WINRT__)) && defined(_M_ARM) #elif (defined(__WINDOWS__) || defined(__WINRT__)) && defined(_M_ARM)
/* All WinRT ARM devices are required to support NEON, but just in case. */ /* All WinRT ARM devices are required to support NEON, but just in case. */
if (IsProcessorFeaturePresent(PF_ARM_NEON_INSTRUCTIONS_AVAILABLE)) { if (IsProcessorFeaturePresent(PF_ARM_NEON_INSTRUCTIONS_AVAILABLE)) {
neon = 1; neon = 1;
} }
#else
#warning SDL_HasNEON is not implemented for this ARM platform. Write me.
#endif #endif
#endif #endif
return neon;
} }
static int static int