Commit 74eb78dcbfa717933577548940cc3d42f4abad49

Ryan C. Gordon 2016-11-17T15:57:58

cpuinfo: more work on SDL_HasNEON().

diff --git a/src/cpuinfo/SDL_cpuinfo.c b/src/cpuinfo/SDL_cpuinfo.c
index f98cf76..1253797 100644
--- a/src/cpuinfo/SDL_cpuinfo.c
+++ b/src/cpuinfo/SDL_cpuinfo.c
@@ -50,13 +50,7 @@
 #include <setjmp.h>
 #endif
 
-#if 0  /* !!! FIXME */
-#if defined(__ANDROID__) && defined(__ARM_ARCH)
-#include <cpu-features.h>
-#endif
-#endif
-
-#if defined(__LINUX__) && defined(__ARM_ARCH) && HAVE_GETAUXVAL
+#if defined(__LINUX__) && defined(__ARM_ARCH)
 #include <sys/auxv.h>
 #include <asm/hwcap.h>
 #endif
@@ -300,38 +294,61 @@ CPU_haveAltiVec(void)
     return altivec;
 }
 
+#if (defined(__LINUX__) || defined(__ANDROID__)) && !HAVE_GETAUXVAL
 static int
-CPU_haveNEON(void)
+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
+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. :/ */
-#ifndef SDL_CPUINFO_DISABLED
-#if defined(__APPLE__) && defined(__ARM_ARCH)
+#if defined(SDL_CPUINFO_DISABLED) || !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 */
+    int neon = 0;
     size_t length = sizeof (neon);
     const int error = sysctlbyname("hw.optional.neon", &neon, &length, NULL, 0);
-    if (!error)
-        neon = (neon != 0);
-#elif 0 && defined(__ANDROID__) && defined(__ARM_ARCH)  /* !!! FIXME */
-    if ( (android_getCpuFamily() == ANDROID_CPU_FAMILY_ARM) &&
-         ((android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON) != 0) ) {
-        neon = 1;
-    }
-#elif defined(__LINUX__) && defined(__ARM_ARCH) && HAVE_GETAUXVAL
-    if (getauxval(AT_HWCAP) & HWCAP_NEON) {
-        neon = 1;
-    }
+    return (!error) && (neon != 0);
+/* Android offers a static library for this but all it does is parse /proc/cpuinfo */
+#elif (defined(__LINUX__) || defined(__ANDROID__)) && HAVE_GETAUXVAL
+    return ((getauxval(AT_HWCAP) & HWCAP_NEON) == HWCAP_NEON)
+#elif (defined(__LINUX__) || defined(__ANDROID__))
+    return readProcAuxvForNeon();
 #elif (defined(__WINDOWS__) || defined(__WINRT__)) && defined(_M_ARM)
     /* All WinRT ARM devices are required to support NEON, but just in case. */
     if (IsProcessorFeaturePresent(PF_ARM_NEON_INSTRUCTIONS_AVAILABLE)) {
         neon = 1;
     }
+#else
+#warning SDL_HasNEON is not implemented for this ARM platform. Write me.
 #endif
 #endif
-
-    return neon;
 }
 
 static int