diff --git a/include/SDL3/SDL_gpu.h b/include/SDL3/SDL_gpu.h index 0f7a239f5e..b905873667 100644 --- a/include/SDL3/SDL_gpu.h +++ b/include/SDL3/SDL_gpu.h @@ -1675,6 +1675,36 @@ typedef struct SDL_GPUStorageTextureWriteOnlyBinding /* Device */ +/** + * Checks for GPU runtime support. + * + * \param format_flags a bitflag indicating which shader formats the app is + * able to provide. + * \param name the preferred GPU driver, or NULL to let SDL pick the optimal + * driver. + * \returns SDL_TRUE if supported, SDL_FALSE otherwise. + * + * \since This function is available since SDL 3.0.0. + * + * \sa SDL_CreateGPUDevice + */ +extern SDL_DECLSPEC SDL_bool SDLCALL SDL_QueryGPUSupport( + SDL_GPUShaderFormat format_flags, + const char *name); + +/** + * Checks for GPU runtime support. + * + * \param props the properties to use. + * \returns SDL_TRUE if supported, SDL_FALSE otherwise. + * + * \since This function is available since SDL 3.0.0. + * + * \sa SDL_CreateGPUDeviceWithProperties + */ +extern SDL_DECLSPEC SDL_bool SDLCALL SDL_QueryGPUSupportWithProperties( + SDL_PropertiesID props); + /** * Creates a GPU context. * @@ -1690,6 +1720,7 @@ typedef struct SDL_GPUStorageTextureWriteOnlyBinding * \sa SDL_GetGPUShaderFormats * \sa SDL_GetGPUDeviceDriver * \sa SDL_DestroyGPUDevice + * \sa SDL_QueryGPUSupport */ extern SDL_DECLSPEC SDL_GPUDevice *SDLCALL SDL_CreateGPUDevice( SDL_GPUShaderFormat format_flags, @@ -1736,6 +1767,7 @@ extern SDL_DECLSPEC SDL_GPUDevice *SDLCALL SDL_CreateGPUDevice( * \sa SDL_GetGPUShaderFormats * \sa SDL_GetGPUDeviceDriver * \sa SDL_DestroyGPUDevice + * \sa SDL_QueryGPUSupportWithProperties */ extern SDL_DECLSPEC SDL_GPUDevice *SDLCALL SDL_CreateGPUDeviceWithProperties( SDL_PropertiesID props); diff --git a/src/dynapi/SDL_dynapi.sym b/src/dynapi/SDL_dynapi.sym index 89e3992add..1b5f1a40a3 100644 --- a/src/dynapi/SDL_dynapi.sym +++ b/src/dynapi/SDL_dynapi.sym @@ -669,6 +669,8 @@ SDL3_0.0.0 { SDL_PushGPUVertexUniformData; SDL_PutAudioStreamData; SDL_QueryGPUFence; + SDL_QueryGPUSupport; + SDL_QueryGPUSupportWithProperties; SDL_Quit; SDL_QuitSubSystem; SDL_RaiseWindow; diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h index 9bd82e2026..8bad28dbde 100644 --- a/src/dynapi/SDL_dynapi_overrides.h +++ b/src/dynapi/SDL_dynapi_overrides.h @@ -694,6 +694,8 @@ #define SDL_PushGPUVertexUniformData SDL_PushGPUVertexUniformData_REAL #define SDL_PutAudioStreamData SDL_PutAudioStreamData_REAL #define SDL_QueryGPUFence SDL_QueryGPUFence_REAL +#define SDL_QueryGPUSupport SDL_QueryGPUSupport_REAL +#define SDL_QueryGPUSupportWithProperties SDL_QueryGPUSupportWithProperties_REAL #define SDL_Quit SDL_Quit_REAL #define SDL_QuitSubSystem SDL_QuitSubSystem_REAL #define SDL_RaiseWindow SDL_RaiseWindow_REAL diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h index 0ad90cfb85..250089ab4c 100644 --- a/src/dynapi/SDL_dynapi_procs.h +++ b/src/dynapi/SDL_dynapi_procs.h @@ -705,6 +705,8 @@ SDL_DYNAPI_PROC(void,SDL_PushGPUFragmentUniformData,(SDL_GPUCommandBuffer *a, Ui SDL_DYNAPI_PROC(void,SDL_PushGPUVertexUniformData,(SDL_GPUCommandBuffer *a, Uint32 b, const void *c, Uint32 d),(a,b,c,d),) SDL_DYNAPI_PROC(SDL_bool,SDL_PutAudioStreamData,(SDL_AudioStream *a, const void *b, int c),(a,b,c),return) SDL_DYNAPI_PROC(SDL_bool,SDL_QueryGPUFence,(SDL_GPUDevice *a, SDL_GPUFence *b),(a,b),return) +SDL_DYNAPI_PROC(SDL_bool,SDL_QueryGPUSupport,(SDL_GPUShaderFormat a, const char *b),(a,b),return) +SDL_DYNAPI_PROC(SDL_bool,SDL_QueryGPUSupportWithProperties,(SDL_PropertiesID a),(a),return) SDL_DYNAPI_PROC(void,SDL_Quit,(void),(),) SDL_DYNAPI_PROC(void,SDL_QuitSubSystem,(SDL_InitFlags a),(a),) SDL_DYNAPI_PROC(SDL_bool,SDL_RaiseWindow,(SDL_Window *a),(a),return) diff --git a/src/gpu/SDL_gpu.c b/src/gpu/SDL_gpu.c index 7a40303449..fef2c98222 100644 --- a/src/gpu/SDL_gpu.c +++ b/src/gpu/SDL_gpu.c @@ -371,12 +371,41 @@ void SDL_GPU_BlitCommon( // Driver Functions #ifndef SDL_GPU_DISABLED -static const SDL_GPUBootstrap * SDL_GPUSelectBackend( - SDL_VideoDevice *_this, - const char *gpudriver, - SDL_GPUShaderFormat format_flags) +static const SDL_GPUBootstrap * SDL_GPUSelectBackend(SDL_PropertiesID props) { Uint32 i; + SDL_GPUShaderFormat format_flags = 0; + const char *gpudriver; + SDL_VideoDevice *_this = SDL_GetVideoDevice(); + + if (_this == NULL) { + SDL_SetError("Video subsystem not initialized"); + return NULL; + } + + if (SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_PRIVATE_BOOL, false)) { + format_flags |= SDL_GPU_SHADERFORMAT_PRIVATE; + } + if (SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_SPIRV_BOOL, false)) { + format_flags |= SDL_GPU_SHADERFORMAT_SPIRV; + } + if (SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_DXBC_BOOL, false)) { + format_flags |= SDL_GPU_SHADERFORMAT_DXBC; + } + if (SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_DXIL_BOOL, false)) { + format_flags |= SDL_GPU_SHADERFORMAT_DXIL; + } + if (SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_MSL_BOOL, false)) { + format_flags |= SDL_GPU_SHADERFORMAT_MSL; + } + if (SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_METALLIB_BOOL, false)) { + format_flags |= SDL_GPU_SHADERFORMAT_METALLIB; + } + + gpudriver = SDL_GetHint(SDL_HINT_GPU_DRIVER); + if (gpudriver == NULL) { + gpudriver = SDL_GetStringProperty(props, SDL_PROP_GPU_DEVICE_CREATE_NAME_STRING, NULL); + } // Environment/Properties override... if (gpudriver != NULL) { @@ -411,14 +440,12 @@ static const SDL_GPUBootstrap * SDL_GPUSelectBackend( } #endif // SDL_GPU_DISABLED -SDL_GPUDevice *SDL_CreateGPUDevice( +static void SDL_GPU_FillProperties( + SDL_PropertiesID props, SDL_GPUShaderFormat format_flags, SDL_bool debug_mode, const char *name) { -#ifndef SDL_GPU_DISABLED - SDL_GPUDevice *result; - SDL_PropertiesID props = SDL_CreateProperties(); if (format_flags & SDL_GPU_SHADERFORMAT_PRIVATE) { SDL_SetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_PRIVATE_BOOL, true); } @@ -439,6 +466,44 @@ SDL_GPUDevice *SDL_CreateGPUDevice( } SDL_SetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_DEBUGMODE_BOOL, debug_mode); SDL_SetStringProperty(props, SDL_PROP_GPU_DEVICE_CREATE_NAME_STRING, name); +} + +SDL_bool SDL_QueryGPUSupport( + SDL_GPUShaderFormat format_flags, + const char *name) +{ +#ifndef SDL_GPU_DISABLED + bool result; + SDL_PropertiesID props = SDL_CreateProperties(); + SDL_GPU_FillProperties(props, format_flags, SDL_FALSE, name); + result = SDL_QueryGPUSupportWithProperties(props); + SDL_DestroyProperties(props); + return result; +#else + SDL_SetError("SDL not built with GPU support"); + return SDL_FALSE; +#endif +} + +SDL_bool SDL_QueryGPUSupportWithProperties(SDL_PropertiesID props) +{ +#ifndef SDL_GPU_DISABLED + return (SDL_GPUSelectBackend(props) != NULL); +#else + SDL_SetError("SDL not built with GPU support"); + return SDL_FALSE; +#endif +} + +SDL_GPUDevice *SDL_CreateGPUDevice( + SDL_GPUShaderFormat format_flags, + SDL_bool debug_mode, + const char *name) +{ +#ifndef SDL_GPU_DISABLED + SDL_GPUDevice *result; + SDL_PropertiesID props = SDL_CreateProperties(); + SDL_GPU_FillProperties(props, format_flags, debug_mode, name); result = SDL_CreateGPUDeviceWithProperties(props); SDL_DestroyProperties(props); return result; @@ -451,49 +516,16 @@ SDL_GPUDevice *SDL_CreateGPUDevice( SDL_GPUDevice *SDL_CreateGPUDeviceWithProperties(SDL_PropertiesID props) { #ifndef SDL_GPU_DISABLED - SDL_GPUShaderFormat format_flags = 0; bool debug_mode; bool preferLowPower; - - const char *gpudriver; SDL_GPUDevice *result = NULL; const SDL_GPUBootstrap *selectedBackend; - SDL_VideoDevice *_this = SDL_GetVideoDevice(); - if (_this == NULL) { - SDL_SetError("Video subsystem not initialized"); - return NULL; - } - - if (SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_PRIVATE_BOOL, false)) { - format_flags |= SDL_GPU_SHADERFORMAT_PRIVATE; - } - if (SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_SPIRV_BOOL, false)) { - format_flags |= SDL_GPU_SHADERFORMAT_SPIRV; - } - if (SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_DXBC_BOOL, false)) { - format_flags |= SDL_GPU_SHADERFORMAT_DXBC; - } - if (SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_DXIL_BOOL, false)) { - format_flags |= SDL_GPU_SHADERFORMAT_DXIL; - } - if (SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_MSL_BOOL, false)) { - format_flags |= SDL_GPU_SHADERFORMAT_MSL; - } - if (SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_METALLIB_BOOL, false)) { - format_flags |= SDL_GPU_SHADERFORMAT_METALLIB; - } - - debug_mode = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_DEBUGMODE_BOOL, true); - preferLowPower = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_PREFERLOWPOWER_BOOL, false); - - gpudriver = SDL_GetHint(SDL_HINT_GPU_DRIVER); - if (gpudriver == NULL) { - gpudriver = SDL_GetStringProperty(props, SDL_PROP_GPU_DEVICE_CREATE_NAME_STRING, NULL); - } - - selectedBackend = SDL_GPUSelectBackend(_this, gpudriver, format_flags); + selectedBackend = SDL_GPUSelectBackend(props); if (selectedBackend != NULL) { + debug_mode = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_DEBUGMODE_BOOL, true); + preferLowPower = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_PREFERLOWPOWER_BOOL, false); + result = selectedBackend->CreateDevice(debug_mode, preferLowPower, props); if (result != NULL) { result->backend = selectedBackend->name;