SDL: gpu: Check shader format support in PrepareDriver

From 510126ee6375d49a0d620848dba295e04bb04ba5 Mon Sep 17 00:00:00 2001
From: Ethan Lee <[EMAIL REDACTED]>
Date: Mon, 19 May 2025 08:56:29 -0400
Subject: [PATCH] gpu: Check shader format support in PrepareDriver

---
 src/gpu/SDL_gpu.c               | 28 ----------------------------
 src/gpu/SDL_sysgpu.h            |  1 -
 src/gpu/d3d12/SDL_gpu_d3d12.c   | 29 ++++++++++++++++++++++++++++-
 src/gpu/metal/SDL_gpu_metal.m   |  6 +++++-
 src/gpu/vulkan/SDL_gpu_vulkan.c |  5 ++++-
 5 files changed, 37 insertions(+), 32 deletions(-)

diff --git a/src/gpu/SDL_gpu.c b/src/gpu/SDL_gpu.c
index 9154c4d77011e..6a6b161cd0716 100644
--- a/src/gpu/SDL_gpu.c
+++ b/src/gpu/SDL_gpu.c
@@ -517,7 +517,6 @@ void SDL_GPU_BlitCommon(
 static const SDL_GPUBootstrap * SDL_GPUSelectBackend(SDL_PropertiesID props)
 {
     Uint32 i;
-    SDL_GPUShaderFormat format_flags = 0;
     const char *gpudriver;
     SDL_VideoDevice *_this = SDL_GetVideoDevice();
 
@@ -526,25 +525,6 @@ static const SDL_GPUBootstrap * SDL_GPUSelectBackend(SDL_PropertiesID props)
         return NULL;
     }
 
-    if (SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_PRIVATE_BOOLEAN, false)) {
-        format_flags |= SDL_GPU_SHADERFORMAT_PRIVATE;
-    }
-    if (SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_SPIRV_BOOLEAN, false)) {
-        format_flags |= SDL_GPU_SHADERFORMAT_SPIRV;
-    }
-    if (SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_DXBC_BOOLEAN, false)) {
-        format_flags |= SDL_GPU_SHADERFORMAT_DXBC;
-    }
-    if (SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_DXIL_BOOLEAN, false)) {
-        format_flags |= SDL_GPU_SHADERFORMAT_DXIL;
-    }
-    if (SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_MSL_BOOLEAN, false)) {
-        format_flags |= SDL_GPU_SHADERFORMAT_MSL;
-    }
-    if (SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_METALLIB_BOOLEAN, 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);
@@ -554,10 +534,6 @@ static const SDL_GPUBootstrap * SDL_GPUSelectBackend(SDL_PropertiesID props)
     if (gpudriver != NULL) {
         for (i = 0; backends[i]; i += 1) {
             if (SDL_strcasecmp(gpudriver, backends[i]->name) == 0) {
-                if (!(backends[i]->shader_formats & format_flags)) {
-                    SDL_SetError("Required shader format for backend %s not provided!", gpudriver);
-                    return NULL;
-                }
                 if (backends[i]->PrepareDriver(_this, props)) {
                     return backends[i];
                 }
@@ -569,10 +545,6 @@ static const SDL_GPUBootstrap * SDL_GPUSelectBackend(SDL_PropertiesID props)
     }
 
     for (i = 0; backends[i]; i += 1) {
-        if ((backends[i]->shader_formats & format_flags) == 0) {
-            // Don't select a backend which doesn't support the app's shaders.
-            continue;
-        }
         if (backends[i]->PrepareDriver(_this, props)) {
             return backends[i];
         }
diff --git a/src/gpu/SDL_sysgpu.h b/src/gpu/SDL_sysgpu.h
index d4f532fde6462..ee7fd10f2f75c 100644
--- a/src/gpu/SDL_sysgpu.h
+++ b/src/gpu/SDL_sysgpu.h
@@ -1141,7 +1141,6 @@ struct SDL_GPUDevice
 typedef struct SDL_GPUBootstrap
 {
     const char *name;
-    const SDL_GPUShaderFormat shader_formats;
     bool (*PrepareDriver)(SDL_VideoDevice *_this, SDL_PropertiesID props);
     SDL_GPUDevice *(*CreateDevice)(bool debug_mode, bool prefer_low_power, SDL_PropertiesID props);
 } SDL_GPUBootstrap;
diff --git a/src/gpu/d3d12/SDL_gpu_d3d12.c b/src/gpu/d3d12/SDL_gpu_d3d12.c
index 6ccb2de179c35..ca170089d9170 100644
--- a/src/gpu/d3d12/SDL_gpu_d3d12.c
+++ b/src/gpu/d3d12/SDL_gpu_d3d12.c
@@ -8333,6 +8333,17 @@ static bool D3D12_PrepareDriver(SDL_VideoDevice *_this, SDL_PropertiesID props)
     IDXGIFactory6 *factory6;
     IDXGIAdapter1 *adapter;
 
+    // Early check to see if the app has _any_ D3D12 formats, if not we don't
+    // have to fuss with loading D3D in the first place.
+    bool has_dxbc = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_DXBC_BOOLEAN, false);
+    bool has_dxil = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_DXIL_BOOLEAN, false);
+    bool supports_dxil = false;
+    // TODO SM7: bool has_spirv = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_SPIRV_BOOLEAN, false);
+    // TODO SM7: bool supports_spirv = false;
+    if (!has_dxbc && !has_dxil) {
+        return false;
+    }
+
     // Can we load D3D12?
 
     d3d12Dll = SDL_LoadObject(D3D12_DLL);
@@ -8427,6 +8438,18 @@ static bool D3D12_PrepareDriver(SDL_VideoDevice *_this, SDL_PropertiesID props)
         (void **)&device);
 
     if (SUCCEEDED(res)) {
+        D3D12_FEATURE_DATA_SHADER_MODEL shaderModel;
+        shaderModel.HighestShaderModel = D3D_SHADER_MODEL_6_0;
+
+        res = ID3D12Device_CheckFeatureSupport(
+            device,
+            D3D12_FEATURE_SHADER_MODEL,
+            &shaderModel,
+            sizeof(shaderModel));
+        if (SUCCEEDED(res) && shaderModel.HighestShaderModel >= D3D_SHADER_MODEL_6_0) {
+            supports_dxil = true;
+        }
+
         ID3D12Device_Release(device);
     }
     IDXGIAdapter1_Release(adapter);
@@ -8435,6 +8458,11 @@ static bool D3D12_PrepareDriver(SDL_VideoDevice *_this, SDL_PropertiesID props)
     SDL_UnloadObject(d3d12Dll);
     SDL_UnloadObject(dxgiDll);
 
+    if (!supports_dxil && !has_dxbc) {
+        SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "D3D12: DXIL is not supported and DXBC is not being provided");
+        return false;
+    }
+
     if (FAILED(res)) {
         SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "D3D12: Could not create D3D12Device with feature level " D3D_FEATURE_LEVEL_CHOICE_STR);
         return false;
@@ -9207,7 +9235,6 @@ static SDL_GPUDevice *D3D12_CreateDevice(bool debugMode, bool preferLowPower, SD
 
 SDL_GPUBootstrap D3D12Driver = {
     "direct3d12",
-    SDL_GPU_SHADERFORMAT_DXIL | SDL_GPU_SHADERFORMAT_DXBC,
     D3D12_PrepareDriver,
     D3D12_CreateDevice
 };
diff --git a/src/gpu/metal/SDL_gpu_metal.m b/src/gpu/metal/SDL_gpu_metal.m
index 0d43a07f648ff..cd1d90acd262b 100644
--- a/src/gpu/metal/SDL_gpu_metal.m
+++ b/src/gpu/metal/SDL_gpu_metal.m
@@ -4309,6 +4309,11 @@ static bool METAL_SupportsTextureFormat(
 
 static bool METAL_PrepareDriver(SDL_VideoDevice *this, SDL_PropertiesID props)
 {
+    if (!SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_MSL_BOOLEAN, false) &&
+        !SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_METALLIB_BOOLEAN, false)) {
+        return false;
+    }
+
     if (@available(macOS 10.14, iOS 13.0, tvOS 13.0, *)) {
         return (this->Metal_CreateView != NULL);
     }
@@ -4619,7 +4624,6 @@ static void METAL_INTERNAL_DestroyBlitResources(
 
 SDL_GPUBootstrap MetalDriver = {
     "metal",
-    SDL_GPU_SHADERFORMAT_MSL | SDL_GPU_SHADERFORMAT_METALLIB,
     METAL_PrepareDriver,
     METAL_CreateDevice
 };
diff --git a/src/gpu/vulkan/SDL_gpu_vulkan.c b/src/gpu/vulkan/SDL_gpu_vulkan.c
index de0be4bdbe6e4..9ed7ecad16170 100644
--- a/src/gpu/vulkan/SDL_gpu_vulkan.c
+++ b/src/gpu/vulkan/SDL_gpu_vulkan.c
@@ -11605,6 +11605,10 @@ static bool VULKAN_PrepareDriver(SDL_VideoDevice *_this, SDL_PropertiesID props)
     VulkanRenderer *renderer;
     bool result = false;
 
+    if (!SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_SPIRV_BOOLEAN, false)) {
+        return false;
+    }
+
     if (_this->Vulkan_CreateSurface == NULL) {
         return false;
     }
@@ -11987,7 +11991,6 @@ static SDL_GPUDevice *VULKAN_CreateDevice(bool debugMode, bool preferLowPower, S
 
 SDL_GPUBootstrap VulkanDriver = {
     "vulkan",
-    SDL_GPU_SHADERFORMAT_SPIRV,
     VULKAN_PrepareDriver,
     VULKAN_CreateDevice
 };