Limit CPU features through a hint

main
Anonymous Maarten 2024-02-23 23:22:41 +01:00 committed by Sam Lantinga
parent b5d4206b30
commit 1d0e5286aa
2 changed files with 106 additions and 0 deletions

View File

@ -371,6 +371,37 @@ extern "C" {
*/ */
#define SDL_HINT_CAMERA_DRIVER "SDL_CAMERA_DRIVER" #define SDL_HINT_CAMERA_DRIVER "SDL_CAMERA_DRIVER"
/**
* A variable that limits what CPU features are available.
*
* By default, SDL marks all features the current CPU supports as available.
* This hint allows to limit these to a subset.
*
* When the hint is unset, or empty, SDL will enable all detected CPU
* features.
*
* The variable can be set to a comma separated list containing the following items:
* "all"
* "altivec"
* "sse"
* "sse2"
* "sse3"
* "sse41"
* "sse42"
* "avx"
* "avx2"
* "avx512f"
* "arm-simd"
* "neon"
* "lsx"
* "lasx"
*
* The items can be prefixed by '+'/'-' to add/remove features.
*
* This hint is available since SDL 3.0.0.
*/
#define SDL_HINT_CPU_FEATURE_MASK "SDL_CPU_FEATURE_MASK"
/** /**
* A variable controlling whether DirectInput should be used for controllers * A variable controlling whether DirectInput should be used for controllers
* *

View File

@ -858,6 +858,80 @@ int SDL_GetCPUCacheLineSize(void)
static Uint32 SDL_CPUFeatures = 0xFFFFFFFF; static Uint32 SDL_CPUFeatures = 0xFFFFFFFF;
static Uint32 SDL_SIMDAlignment = 0xFFFFFFFF; static Uint32 SDL_SIMDAlignment = 0xFFFFFFFF;
static SDL_bool ref_string_equals(const char *ref, const char *test, const char *end_test) {
size_t len_test = end_test - test;
return SDL_strncmp(ref, test, len_test) == 0 && ref[len_test] == '\0' && (test[len_test] == '\0' || test[len_test] == ',');
}
static Uint32 SDLCALL SDL_CPUFeatureMaskFromHint(void)
{
Uint32 result_mask = 0xFFFFFFFF;
const char *hint = SDL_GetHint(SDL_HINT_CPU_FEATURE_MASK);
if (hint) {
for (const char *spot = hint, *next; *spot; spot = next) {
const char *end = SDL_strchr(spot, ',');
Uint32 spot_mask;
SDL_bool add_spot_mask = SDL_TRUE;
if (end) {
next = end + 1;
} else {
size_t len = SDL_strlen(spot);
end = spot + len;
next = end;
}
if (spot[0] == '+') {
add_spot_mask = SDL_TRUE;
spot += 1;
} else if (spot[0] == '-') {
add_spot_mask = SDL_FALSE;
spot += 1;
}
if (ref_string_equals("all", spot, end)) {
spot_mask = 0xFFFFFFFF;
} else if (ref_string_equals("altivec", spot, end)) {
spot_mask= CPU_HAS_ALTIVEC;
} else if (ref_string_equals("mmx", spot, end)) {
spot_mask = CPU_HAS_MMX;
} else if (ref_string_equals("sse", spot, end)) {
spot_mask = CPU_HAS_SSE;
} else if (ref_string_equals("sse2", spot, end)) {
spot_mask = CPU_HAS_SSE2;
} else if (ref_string_equals("sse3", spot, end)) {
spot_mask = CPU_HAS_SSE3;
} else if (ref_string_equals("sse41", spot, end)) {
spot_mask = CPU_HAS_SSE41;
} else if (ref_string_equals("sse42", spot, end)) {
spot_mask = CPU_HAS_SSE42;
} else if (ref_string_equals("avx", spot, end)) {
spot_mask = CPU_HAS_AVX;
} else if (ref_string_equals("avx2", spot, end)) {
spot_mask = CPU_HAS_AVX2;
} else if (ref_string_equals("avx512f", spot, end)) {
spot_mask = CPU_HAS_AVX512F;
} else if (ref_string_equals("arm-simd", spot, end)) {
spot_mask = CPU_HAS_ARM_SIMD;
} else if (ref_string_equals("neon", spot, end)) {
spot_mask = CPU_HAS_NEON;
} else if (ref_string_equals("lsx", spot, end)) {
spot_mask = CPU_HAS_LSX;
} else if (ref_string_equals("lasx", spot, end)) {
spot_mask = CPU_HAS_LASX;
} else {
/* Ignore unknown/incorrect cpu feature(s) */
continue;
}
if (add_spot_mask) {
result_mask |= spot_mask;
} else {
result_mask &= ~spot_mask;
}
}
}
return result_mask;
}
static Uint32 SDL_GetCPUFeatures(void) static Uint32 SDL_GetCPUFeatures(void)
{ {
if (SDL_CPUFeatures == 0xFFFFFFFF) { if (SDL_CPUFeatures == 0xFFFFFFFF) {
@ -920,6 +994,7 @@ static Uint32 SDL_GetCPUFeatures(void)
SDL_CPUFeatures |= CPU_HAS_LASX; SDL_CPUFeatures |= CPU_HAS_LASX;
SDL_SIMDAlignment = SDL_max(SDL_SIMDAlignment, 32); SDL_SIMDAlignment = SDL_max(SDL_SIMDAlignment, 32);
} }
SDL_CPUFeatures &= SDL_CPUFeatureMaskFromHint();
} }
return SDL_CPUFeatures; return SDL_CPUFeatures;
} }