From b5624e14ffdc88d00e0da2408091e3376c08419b Mon Sep 17 00:00:00 2001
From: Ethan Lee <[EMAIL REDACTED]>
Date: Fri, 7 Nov 2025 14:22:45 -0500
Subject: [PATCH] gpu: Add
SDL_PROP_GPU_DEVICE_CREATE_VULKAN_REQUIRE_HARDWARE_ACCELERATION property
---
include/SDL3/SDL_gpu.h | 9 +++++++++
src/gpu/vulkan/SDL_gpu_vulkan.c | 14 ++++++++++++++
2 files changed, 23 insertions(+)
diff --git a/include/SDL3/SDL_gpu.h b/include/SDL3/SDL_gpu.h
index 18ee000869629..d3d97b96a747d 100644
--- a/include/SDL3/SDL_gpu.h
+++ b/include/SDL3/SDL_gpu.h
@@ -2307,6 +2307,14 @@ extern SDL_DECLSPEC SDL_GPUDevice * SDLCALL SDL_CreateGPUDevice(
* either supports Tier 2 Resource Binding or does not support D3D12 in any
* capacity. Defaults to false.
*
+ * With the Vulkan renderer:
+ * - `SDL_PROP_GPU_DEVICE_CREATE_VULKAN_REQUIRE_HARDWARE_ACCELERATION`: By
+ * default, Vulkan device enumeration includes drivers of all types, including
+ * software renderers (for example, the Lavapipe Mesa driver). This can be
+ * useful if your application _requires_ SDL_GPU, but if you can provide your
+ * own fallback renderer (for example, an OpenGL renderer) this property can
+ * be set to true. Defaults to false.
+ *
* \param props the properties to use.
* \returns a GPU context on success or NULL on failure; call SDL_GetError()
* for more information.
@@ -2337,6 +2345,7 @@ extern SDL_DECLSPEC SDL_GPUDevice * SDLCALL SDL_CreateGPUDeviceWithProperties(
#define SDL_PROP_GPU_DEVICE_CREATE_SHADERS_METALLIB_BOOLEAN "SDL.gpu.device.create.shaders.metallib"
#define SDL_PROP_GPU_DEVICE_CREATE_D3D12_ALLOW_FEWER_RESOURCE_SLOTS_BOOLEAN "SDL.gpu.device.create.d3d12.allowtier1resourcebinding"
#define SDL_PROP_GPU_DEVICE_CREATE_D3D12_SEMANTIC_NAME_STRING "SDL.gpu.device.create.d3d12.semantic"
+#define SDL_PROP_GPU_DEVICE_CREATE_VULKAN_REQUIRE_HARDWARE_ACCELERATION "SDL.gpu.device.create.vulkan.requirehardwareacceleration"
/**
* Destroys a GPU context previously returned by SDL_CreateGPUDevice.
diff --git a/src/gpu/vulkan/SDL_gpu_vulkan.c b/src/gpu/vulkan/SDL_gpu_vulkan.c
index 6dfb9c4624000..3db3e258593ac 100644
--- a/src/gpu/vulkan/SDL_gpu_vulkan.c
+++ b/src/gpu/vulkan/SDL_gpu_vulkan.c
@@ -1096,6 +1096,7 @@ struct VulkanRenderer
bool debugMode;
bool preferLowPower;
+ bool requireHardwareAcceleration;
SDL_PropertiesID props;
Uint32 allowedFramesInFlight;
@@ -11343,6 +11344,15 @@ static bool VULKAN_INTERNAL_GetDeviceRank(
deviceType = physicalDeviceProperties.deviceType;
}
+ if (renderer->requireHardwareAcceleration) {
+ if (deviceType != VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU &&
+ deviceType != VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU &&
+ deviceType != VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU) {
+ // In addition to CPU, "Other" drivers (including layered drivers) don't count as hardware-accelerated
+ return 0;
+ }
+ }
+
/* Apply a large bias on the devicePriority so that we always respect the order in the priority arrays.
* We also rank by e.g. VRAM which should have less influence than the device type.
*/
@@ -11818,6 +11828,8 @@ static bool VULKAN_PrepareDriver(SDL_VideoDevice *_this, SDL_PropertiesID props)
renderer->desiredDeviceFeatures.sampleRateShading = VK_TRUE;
renderer->desiredDeviceFeatures.imageCubeArray = VK_TRUE;
+ renderer->requireHardwareAcceleration = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_VULKAN_REQUIRE_HARDWARE_ACCELERATION, false);
+
result = VULKAN_INTERNAL_PrepareVulkan(renderer);
if (result) {
renderer->vkDestroyInstance(renderer->instance, NULL);
@@ -11867,6 +11879,8 @@ static SDL_GPUDevice *VULKAN_CreateDevice(bool debugMode, bool preferLowPower, S
renderer->desiredDeviceFeatures.sampleRateShading = VK_TRUE;
renderer->desiredDeviceFeatures.imageCubeArray = VK_TRUE;
+ renderer->requireHardwareAcceleration = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_VULKAN_REQUIRE_HARDWARE_ACCELERATION, false);
+
if (!VULKAN_INTERNAL_PrepareVulkan(renderer)) {
SET_STRING_ERROR("Failed to initialize Vulkan!");
SDL_free(renderer);