From 0160e9eac64d7fb47f2e95bd6bd61b1dfc785a81 Mon Sep 17 00:00:00 2001
From: Ethan Lee <[EMAIL REDACTED]>
Date: Fri, 13 Sep 2024 13:23:55 -0400
Subject: [PATCH] gpu: Add SDL_QueryGPUSupport
---
include/SDL3/SDL_gpu.h | 32 ++++++++
src/dynapi/SDL_dynapi.sym | 2 +
src/dynapi/SDL_dynapi_overrides.h | 2 +
src/dynapi/SDL_dynapi_procs.h | 2 +
src/gpu/SDL_gpu.c | 122 +++++++++++++++++++-----------
5 files changed, 115 insertions(+), 45 deletions(-)
diff --git a/include/SDL3/SDL_gpu.h b/include/SDL3/SDL_gpu.h
index 0f7a239f5ef9d..b905873667616 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 89e3992addd02..1b5f1a40a3bf5 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 9bd82e2026be8..8bad28dbdee6c 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 0ad90cfb85d16..250089ab4c216 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 7a40303449afe..fef2c982225d9 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;