cpuinfo: first attempt at SDL_HasNEON() implementation.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 54a23f0..2945e49 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -615,7 +615,7 @@ if(LIBC)
_uitoa _ultoa strtol strtoul _i64toa _ui64toa strtoll strtoull
atoi atof strcmp strncmp _stricmp strcasecmp _strnicmp strncasecmp
vsscanf vsnprintf fseeko fseeko64 sigaction setjmp
- nanosleep sysconf sysctlbyname
+ nanosleep sysconf sysctlbyname getauxval
)
string(TOUPPER ${_FN} _UPPER)
set(_HAVEVAR "HAVE_${_UPPER}")
diff --git a/configure.in b/configure.in
index 748ec03..801d2f1 100644
--- a/configure.in
+++ b/configure.in
@@ -268,7 +268,7 @@ if test x$enable_libc = xyes; then
AC_DEFINE(HAVE_MPROTECT, 1, [ ])
]),
)
- AC_CHECK_FUNCS(malloc calloc realloc free getenv setenv putenv unsetenv qsort abs bcopy memset memcpy memmove strlen strlcpy strlcat strdup _strrev _strupr _strlwr strchr strrchr strstr itoa _ltoa _uitoa _ultoa strtol strtoul _i64toa _ui64toa strtoll strtoull atoi atof strcmp strncmp _stricmp strcasecmp _strnicmp strncasecmp vsscanf vsnprintf fseeko fseeko64 sigaction setjmp nanosleep sysconf sysctlbyname)
+ AC_CHECK_FUNCS(malloc calloc realloc free getenv setenv putenv unsetenv qsort abs bcopy memset memcpy memmove strlen strlcpy strlcat strdup _strrev _strupr _strlwr strchr strrchr strstr itoa _ltoa _uitoa _ultoa strtol strtoul _i64toa _ui64toa strtoll strtoull atoi atof strcmp strncmp _stricmp strcasecmp _strnicmp strncasecmp vsscanf vsnprintf fseeko fseeko64 sigaction setjmp nanosleep sysconf sysctlbyname getauxval)
AC_CHECK_LIB(m, pow, [LIBS="$LIBS -lm"; EXTRA_LDFLAGS="$EXTRA_LDFLAGS -lm"])
AC_CHECK_FUNCS(atan atan2 acos asin ceil copysign cos cosf fabs floor log pow scalbn sin sinf sqrt sqrtf tan tanf)
diff --git a/include/SDL_config.h.cmake b/include/SDL_config.h.cmake
index 12692f5..dd49bdc 100644
--- a/include/SDL_config.h.cmake
+++ b/include/SDL_config.h.cmake
@@ -171,6 +171,8 @@
#cmakedefine HAVE_PTHREAD_SETNAME_NP 1
#cmakedefine HAVE_PTHREAD_SET_NAME_NP 1
#cmakedefine HAVE_SEM_TIMEDWAIT 1
+#cmakedefine HAVE_GETAUXVAL 1
+
#elif __WIN32__
#cmakedefine HAVE_STDARG_H 1
#cmakedefine HAVE_STDDEF_H 1
diff --git a/include/SDL_config.h.in b/include/SDL_config.h.in
index 6b96b4f..90a304a 100644
--- a/include/SDL_config.h.in
+++ b/include/SDL_config.h.in
@@ -173,6 +173,7 @@
#undef HAVE_PTHREAD_SETNAME_NP
#undef HAVE_PTHREAD_SET_NAME_NP
#undef HAVE_SEM_TIMEDWAIT
+#undef HAVE_GETAUXVAL
#else
#define HAVE_STDARG_H 1
diff --git a/include/SDL_cpuinfo.h b/include/SDL_cpuinfo.h
index d0ba47b..1a5524b 100644
--- a/include/SDL_cpuinfo.h
+++ b/include/SDL_cpuinfo.h
@@ -145,6 +145,11 @@ extern DECLSPEC SDL_bool SDLCALL SDL_HasAVX(void);
extern DECLSPEC SDL_bool SDLCALL SDL_HasAVX2(void);
/**
+ * This function returns true if the CPU has NEON (ARM SIMD) features.
+ */
+extern DECLSPEC SDL_bool SDLCALL SDL_HasNEON(void);
+
+/**
* This function returns the amount of RAM configured in the system, in MB.
*/
extern DECLSPEC int SDLCALL SDL_GetSystemRAM(void);
diff --git a/src/cpuinfo/SDL_cpuinfo.c b/src/cpuinfo/SDL_cpuinfo.c
index f2b7f7e..9462875 100644
--- a/src/cpuinfo/SDL_cpuinfo.c
+++ b/src/cpuinfo/SDL_cpuinfo.c
@@ -50,6 +50,15 @@
#include <setjmp.h>
#endif
+#if defined(__ANDROID__)
+#include <cpu-features.h>
+#endif
+
+#if defined(__LINUX__) && HAVE_GETAUXVAL
+#include <sys/auxv.h>
+#include <asm/hwcap.h>
+#endif
+
#define CPU_HAS_RDTSC 0x00000001
#define CPU_HAS_ALTIVEC 0x00000002
#define CPU_HAS_MMX 0x00000004
@@ -61,6 +70,7 @@
#define CPU_HAS_SSE42 0x00000200
#define CPU_HAS_AVX 0x00000400
#define CPU_HAS_AVX2 0x00000800
+#define CPU_HAS_NEON 0x00001000
#if SDL_ALTIVEC_BLITTERS && HAVE_SETJMP && !__MACOSX__ && !__OpenBSD__
/* This is the brute force way of detecting instruction sets...
@@ -289,6 +299,40 @@ CPU_haveAltiVec(void)
}
static int
+CPU_haveNEON(void)
+{
+ int neon = 0;
+
+/* 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)
+ /* all hardware that runs iOS 5 and later support NEON, but check anyhow */
+ size_t length = sizeof (neon);
+ const int error = sysctlbyname("hw.optional.neon", &neon, &length, NULL, 0);
+ if (!error)
+ neon = (neon != 0);
+#elif defined(__ANDROID__)
+ if ( (android_getCpuFamily() == ANDROID_CPU_FAMILY_ARM) &&
+ ((android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON) != 0) ) {
+ neon = 1;
+ }
+#elif defined(__LINUX__) && HAVE_GETAUXVAL && defined(__arm__)
+ if (getauxval(AT_HWCAP) & HWCAP_NEON) {
+ neon = 1;
+ }
+#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;
+ }
+#endif
+#endif
+
+ return neon;
+}
+
+static int
CPU_have3DNow(void)
{
if (CPU_CPUIDMaxFunction > 0) { /* that is, do we have CPUID at all? */
@@ -527,6 +571,9 @@ SDL_GetCPUFeatures(void)
if (CPU_haveAVX2()) {
SDL_CPUFeatures |= CPU_HAS_AVX2;
}
+ if (CPU_haveNEON()) {
+ SDL_CPUFeatures |= CPU_HAS_NEON;
+ }
}
return SDL_CPUFeatures;
}
@@ -598,6 +645,12 @@ SDL_HasAVX2(void)
return CPU_FEATURE_AVAILABLE(CPU_HAS_AVX2);
}
+SDL_bool
+SDL_HasNEON(void)
+{
+ return CPU_FEATURE_AVAILABLE(CPU_HAS_NEON);
+}
+
static int SDL_SystemRAM = 0;
int
@@ -667,6 +720,7 @@ main()
printf("SSE4.2: %d\n", SDL_HasSSE42());
printf("AVX: %d\n", SDL_HasAVX());
printf("AVX2: %d\n", SDL_HasAVX2());
+ printf("NEON: %d\n", SDL_HasNEON());
printf("RAM: %d MB\n", SDL_GetSystemRAM());
return 0;
}
diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h
index d0d9e18..3b02257 100644
--- a/src/dynapi/SDL_dynapi_overrides.h
+++ b/src/dynapi/SDL_dynapi_overrides.h
@@ -621,3 +621,4 @@
#define SDL_GameControllerGetVendor SDL_GameControllerGetVendor_REAL
#define SDL_GameControllerGetProduct SDL_GameControllerGetProduct_REAL
#define SDL_GameControllerGetProductVersion SDL_GameControllerGetProductVersion_REAL
+#define SDL_HasNEON SDL_HasNEON_REAL
diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h
index 28afcf9..b225d2a 100644
--- a/src/dynapi/SDL_dynapi_procs.h
+++ b/src/dynapi/SDL_dynapi_procs.h
@@ -653,3 +653,4 @@ SDL_DYNAPI_PROC(Uint16,SDL_JoystickGetProductVersion,(SDL_Joystick *a),(a),retur
SDL_DYNAPI_PROC(Uint16,SDL_GameControllerGetVendor,(SDL_GameController *a),(a),return)
SDL_DYNAPI_PROC(Uint16,SDL_GameControllerGetProduct,(SDL_GameController *a),(a),return)
SDL_DYNAPI_PROC(Uint16,SDL_GameControllerGetProductVersion,(SDL_GameController *a),(a),return)
+SDL_DYNAPI_PROC(SDL_bool,SDL_HasNEON,(void),(),return)
diff --git a/test/testplatform.c b/test/testplatform.c
index bbd5b8a..33b94fd 100644
--- a/test/testplatform.c
+++ b/test/testplatform.c
@@ -360,6 +360,7 @@ TestCPUInfo(SDL_bool verbose)
SDL_Log("SSE4.2 %s\n", SDL_HasSSE42()? "detected" : "not detected");
SDL_Log("AVX %s\n", SDL_HasAVX()? "detected" : "not detected");
SDL_Log("AVX2 %s\n", SDL_HasAVX2()? "detected" : "not detected");
+ SDL_Log("NEON %s\n", SDL_HasNEON()? "detected" : "not detected");
SDL_Log("System RAM %d MB\n", SDL_GetSystemRAM());
}
return (0);