From 35430a73f251f6bb7554d7e2cc5af26dee5a46d5 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Thu, 17 Nov 2016 01:15:16 -0500 Subject: [PATCH] cpuinfo: first attempt at SDL_HasNEON() implementation. --- CMakeLists.txt | 2 +- configure.in | 2 +- include/SDL_config.h.cmake | 2 ++ include/SDL_config.h.in | 1 + include/SDL_cpuinfo.h | 5 +++ src/cpuinfo/SDL_cpuinfo.c | 54 +++++++++++++++++++++++++++++++ src/dynapi/SDL_dynapi_overrides.h | 1 + src/dynapi/SDL_dynapi_procs.h | 1 + test/testplatform.c | 1 + 9 files changed, 67 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 54a23f0c7..2945e4906 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 748ec0332..801d2f198 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 12692f531..dd49bdc98 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 6b96b4f7b..90a304a7e 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 d0ba47bf7..1a5524bd9 100644 --- a/include/SDL_cpuinfo.h +++ b/include/SDL_cpuinfo.h @@ -144,6 +144,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. */ diff --git a/src/cpuinfo/SDL_cpuinfo.c b/src/cpuinfo/SDL_cpuinfo.c index f2b7f7e14..9462875ad 100644 --- a/src/cpuinfo/SDL_cpuinfo.c +++ b/src/cpuinfo/SDL_cpuinfo.c @@ -50,6 +50,15 @@ #include #endif +#if defined(__ANDROID__) +#include +#endif + +#if defined(__LINUX__) && HAVE_GETAUXVAL +#include +#include +#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... @@ -288,6 +298,40 @@ CPU_haveAltiVec(void) return altivec; } +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) { @@ -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 d0d9e18d7..3b02257f4 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 28afcf979..b225d2afd 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 bbd5b8ae0..33b94fde0 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);