diff --git a/include/SDL3/SDL_hints.h b/include/SDL3/SDL_hints.h index 30a04c4da4..51505fe651 100644 --- a/include/SDL3/SDL_hints.h +++ b/include/SDL3/SDL_hints.h @@ -4381,6 +4381,27 @@ extern "C" { */ #define SDL_HINT_PEN_TOUCH_EVENTS "SDL_PEN_TOUCH_EVENTS" +/** + * A variable controlling whether SDL backend information is logged. + * + * The variable can be set to the following values: + * + * - "0": Subsystem information will not be logged. (default) + * - "1": Subsystem information will be logged. + * + * This is generally meant to be used as an environment variable to let + * end-users report what subsystems were chosen on their system, to aid + * in debugging. Logged information is sent through SDL_Log(), which + * means by default they appear on stdout on most platforms or maybe + * OutputDebugString() on Windows, and can be funneled by the app with + * SDL_SetLogOutputFunction(), etc. + * + * This hint can be set anytime, but the specific logs are generated + * during subsystem init. + * + * \since This hint is available since SDL 3.4.0. + */ +#define SDL_HINT_LOG_BACKENDS "SDL_LOG_BACKENDS" /** * An enumeration of hint priorities. diff --git a/src/SDL_utils.c b/src/SDL_utils.c index f2090747a8..ec2c435a92 100644 --- a/src/SDL_utils.c +++ b/src/SDL_utils.c @@ -552,3 +552,12 @@ char *SDL_CreateDeviceName(Uint16 vendor, Uint16 product, const char *vendor_nam return name; } + +void SDL_LogBackend(const char *subsystem, const char *backend) +{ + if (SDL_GetHintBoolean(SDL_HINT_LOG_BACKENDS, false)) { + SDL_Log("SDL_BACKEND: %s -> '%s'", subsystem, backend); + } +} + + diff --git a/src/SDL_utils_c.h b/src/SDL_utils_c.h index 5e0e8f519e..2929e7f1f1 100644 --- a/src/SDL_utils_c.h +++ b/src/SDL_utils_c.h @@ -75,4 +75,7 @@ extern const char *SDL_GetPersistentString(const char *string); extern char *SDL_CreateDeviceName(Uint16 vendor, Uint16 product, const char *vendor_name, const char *product_name, const char *default_name); +// Log what backend a subsystem chose, if a hint was set to do so. Useful for debugging. +extern void SDL_LogBackend(const char *subsystem, const char *backend); + #endif // SDL_utils_h_ diff --git a/src/audio/SDL_audio.c b/src/audio/SDL_audio.c index 7dc247b193..a450bbee84 100644 --- a/src/audio/SDL_audio.c +++ b/src/audio/SDL_audio.c @@ -1006,7 +1006,9 @@ bool SDL_InitAudio(const char *driver_name) } } - if (!initialized) { + if (initialized) { + SDL_LogBackend("audio", current_audio.name); + } else { // specific drivers will set the error message if they fail, but otherwise we do it here. if (!tried_to_init) { if (driver_name) { diff --git a/src/camera/SDL_camera.c b/src/camera/SDL_camera.c index 9f71cea0f3..7385426afc 100644 --- a/src/camera/SDL_camera.c +++ b/src/camera/SDL_camera.c @@ -1524,7 +1524,9 @@ bool SDL_CameraInit(const char *driver_name) } } - if (!initialized) { + if (initialized) { + SDL_LogBackend("camera", camera_driver.name); + } else { // specific drivers will set the error message if they fail, but otherwise we do it here. if (!tried_to_init) { if (driver_name) { diff --git a/src/gpu/SDL_gpu.c b/src/gpu/SDL_gpu.c index ebf0b333e9..3e0002f058 100644 --- a/src/gpu/SDL_gpu.c +++ b/src/gpu/SDL_gpu.c @@ -711,6 +711,7 @@ SDL_GPUDevice *SDL_CreateGPUDeviceWithProperties(SDL_PropertiesID props) selectedBackend = SDL_GPUSelectBackend(props); if (selectedBackend != NULL) { + SDL_LogBackend("gpu", selectedBackend->name); debug_mode = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_DEBUGMODE_BOOLEAN, true); preferLowPower = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_PREFERLOWPOWER_BOOLEAN, false); diff --git a/src/io/io_uring/SDL_asyncio_liburing.c b/src/io/io_uring/SDL_asyncio_liburing.c index 07e8c2415c..8b4738f9ca 100644 --- a/src/io/io_uring/SDL_asyncio_liburing.c +++ b/src/io/io_uring/SDL_asyncio_liburing.c @@ -512,10 +512,12 @@ static void MaybeInitializeLibUring(void) { if (SDL_ShouldInit(&liburing_init)) { if (LoadLibUring()) { + SDL_LogBackend("asyncio", "liburing"); CreateAsyncIOQueue = SDL_SYS_CreateAsyncIOQueue_liburing; QuitAsyncIO = SDL_SYS_QuitAsyncIO_liburing; AsyncIOFromFile = SDL_SYS_AsyncIOFromFile_liburing; } else { // can't use liburing? Use the "generic" threadpool implementation instead. + SDL_LogBackend("asyncio", "generic"); CreateAsyncIOQueue = SDL_SYS_CreateAsyncIOQueue_Generic; QuitAsyncIO = SDL_SYS_QuitAsyncIO_Generic; AsyncIOFromFile = SDL_SYS_AsyncIOFromFile_Generic; diff --git a/src/io/windows/SDL_asyncio_windows_ioring.c b/src/io/windows/SDL_asyncio_windows_ioring.c index 497456cfa4..fd65921015 100644 --- a/src/io/windows/SDL_asyncio_windows_ioring.c +++ b/src/io/windows/SDL_asyncio_windows_ioring.c @@ -511,10 +511,12 @@ static void MaybeInitializeWinIoRing(void) { if (SDL_ShouldInit(&ioring_init)) { if (LoadWinIoRing()) { + SDL_LogBackend("asyncio", "ioring"); CreateAsyncIOQueue = SDL_SYS_CreateAsyncIOQueue_ioring; QuitAsyncIO = SDL_SYS_QuitAsyncIO_ioring; AsyncIOFromFile = SDL_SYS_AsyncIOFromFile_ioring; } else { // can't use ioring? Use the "generic" threadpool implementation instead. + SDL_LogBackend("asyncio", "generic"); CreateAsyncIOQueue = SDL_SYS_CreateAsyncIOQueue_Generic; QuitAsyncIO = SDL_SYS_QuitAsyncIO_Generic; AsyncIOFromFile = SDL_SYS_AsyncIOFromFile_Generic; diff --git a/src/power/SDL_power.c b/src/power/SDL_power.c index 5dde3b145d..3d91c9a931 100644 --- a/src/power/SDL_power.c +++ b/src/power/SDL_power.c @@ -84,7 +84,7 @@ static SDL_GetPowerInfo_Impl implementations[] = { SDL_PowerState SDL_GetPowerInfo(int *seconds, int *percent) { #ifndef SDL_POWER_DISABLED - const int total = sizeof(implementations) / sizeof(implementations[0]); + const int total = SDL_arraysize(implementations); SDL_PowerState result = SDL_POWERSTATE_UNKNOWN; int i; #endif diff --git a/src/render/SDL_render.c b/src/render/SDL_render.c index 60265b81c3..3fa627b13f 100644 --- a/src/render/SDL_render.c +++ b/src/render/SDL_render.c @@ -1063,7 +1063,9 @@ SDL_Renderer *SDL_CreateRendererWithProperties(SDL_PropertiesID props) } } - if (!rc) { + if (rc) { + SDL_LogBackend("render", renderer->name); + } else { if (driver_name) { SDL_SetError("%s not available", driver_name); } else { diff --git a/src/storage/SDL_storage.c b/src/storage/SDL_storage.c index 7c395b36a8..dd3343b0e2 100644 --- a/src/storage/SDL_storage.c +++ b/src/storage/SDL_storage.c @@ -118,7 +118,9 @@ SDL_Storage *SDL_OpenTitleStorage(const char *override, SDL_PropertiesID props) } } } - if (!storage) { + if (storage) { + SDL_LogBackend("title_storage", titlebootstrap[i]->name); + } else { if (driver_name) { SDL_SetError("%s not available", driver_name); } else { @@ -160,7 +162,9 @@ SDL_Storage *SDL_OpenUserStorage(const char *org, const char *app, SDL_Propertie } } } - if (!storage) { + if (storage) { + SDL_LogBackend("user_storage", userbootstrap[i]->name); + } else { if (driver_name) { SDL_SetError("%s not available", driver_name); } else { diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c index e54a685396..1b29fc42d3 100644 --- a/src/video/SDL_video.c +++ b/src/video/SDL_video.c @@ -679,7 +679,9 @@ bool SDL_VideoInit(const char *driver_name) } } } - if (!video) { + if (video) { + SDL_LogBackend("video", bootstrap[i]->name); + } else { if (driver_name) { SDL_SetError("%s not available", driver_name); goto pre_driver_error;