SDL GPU: Implemented opt out Vulkan device features (#13016)

This commit is contained in:
Manuel
2025-05-14 03:28:28 +03:00
committed by GitHub
parent 1eeffc5933
commit f85f83ec7c
6 changed files with 71 additions and 36 deletions

View File

@@ -2254,6 +2254,22 @@ extern SDL_DECLSPEC SDL_GPUDevice * SDLCALL SDL_CreateGPUDevice(
* - `SDL_PROP_GPU_DEVICE_CREATE_D3D12_SEMANTIC_NAME_STRING`: the prefix to * - `SDL_PROP_GPU_DEVICE_CREATE_D3D12_SEMANTIC_NAME_STRING`: the prefix to
* use for all vertex semantics, default is "TEXCOORD". * use for all vertex semantics, default is "TEXCOORD".
* *
* With the Vulkan renderer:
*
* - `SDL_PROP_GPU_DEVICE_CREATE_VULKAN_SHADERCLIPDISTANCE_BOOL`: Enable device feature
* shaderClipDistance. If disabled, clip distances are not supported in shader code:
* gl_ClipDistance[] built-ins of GLSL, SV_ClipDistance0/1 semantics of HLSL and
* [[clip_distance]] attribute of Metal. Defaults to true.
* - `SDL_PROP_GPU_DEVICE_CREATE_VULKAN_DEPTHCLAMP_BOOL`: Enable device feature
* depthClamp. If disabled, there is no depth clamp support and enable_depth_clip in
* SDL_GPURasterizerState must always be set to true. Defaults to true.
* - `SDL_PROP_GPU_DEVICE_CREATE_VULKAN_DRAWINDIRECTFIRST_BOOL`: Enable device feature
* drawIndirectFirstInstance. If disabled, the argument first_instance of
* SDL_GPUIndirectDrawCommand must be set to zero. Defaults to true.
* - `SDL_PROP_GPU_DEVICE_CREATE_VULKAN_SAMPLERANISOTROPY_BOOL`: Enable device feature
* samplerAnisotropy. If disabled, enable_anisotropy of SDL_GPUSamplerCreateInfo must
* be set to false. Defaults to true.
*
* \param props the properties to use. * \param props the properties to use.
* \returns a GPU context on success or NULL on failure; call SDL_GetError() * \returns a GPU context on success or NULL on failure; call SDL_GetError()
* for more information. * for more information.
@@ -2268,17 +2284,21 @@ extern SDL_DECLSPEC SDL_GPUDevice * SDLCALL SDL_CreateGPUDevice(
extern SDL_DECLSPEC SDL_GPUDevice * SDLCALL SDL_CreateGPUDeviceWithProperties( extern SDL_DECLSPEC SDL_GPUDevice * SDLCALL SDL_CreateGPUDeviceWithProperties(
SDL_PropertiesID props); SDL_PropertiesID props);
#define SDL_PROP_GPU_DEVICE_CREATE_DEBUGMODE_BOOLEAN "SDL.gpu.device.create.debugmode" #define SDL_PROP_GPU_DEVICE_CREATE_DEBUGMODE_BOOLEAN "SDL.gpu.device.create.debugmode"
#define SDL_PROP_GPU_DEVICE_CREATE_PREFERLOWPOWER_BOOLEAN "SDL.gpu.device.create.preferlowpower" #define SDL_PROP_GPU_DEVICE_CREATE_PREFERLOWPOWER_BOOLEAN "SDL.gpu.device.create.preferlowpower"
#define SDL_PROP_GPU_DEVICE_CREATE_VERBOSE_BOOLEAN "SDL.gpu.device.create.verbose" #define SDL_PROP_GPU_DEVICE_CREATE_VERBOSE_BOOLEAN "SDL.gpu.device.create.verbose"
#define SDL_PROP_GPU_DEVICE_CREATE_NAME_STRING "SDL.gpu.device.create.name" #define SDL_PROP_GPU_DEVICE_CREATE_NAME_STRING "SDL.gpu.device.create.name"
#define SDL_PROP_GPU_DEVICE_CREATE_SHADERS_PRIVATE_BOOLEAN "SDL.gpu.device.create.shaders.private" #define SDL_PROP_GPU_DEVICE_CREATE_SHADERS_PRIVATE_BOOLEAN "SDL.gpu.device.create.shaders.private"
#define SDL_PROP_GPU_DEVICE_CREATE_SHADERS_SPIRV_BOOLEAN "SDL.gpu.device.create.shaders.spirv" #define SDL_PROP_GPU_DEVICE_CREATE_SHADERS_SPIRV_BOOLEAN "SDL.gpu.device.create.shaders.spirv"
#define SDL_PROP_GPU_DEVICE_CREATE_SHADERS_DXBC_BOOLEAN "SDL.gpu.device.create.shaders.dxbc" #define SDL_PROP_GPU_DEVICE_CREATE_SHADERS_DXBC_BOOLEAN "SDL.gpu.device.create.shaders.dxbc"
#define SDL_PROP_GPU_DEVICE_CREATE_SHADERS_DXIL_BOOLEAN "SDL.gpu.device.create.shaders.dxil" #define SDL_PROP_GPU_DEVICE_CREATE_SHADERS_DXIL_BOOLEAN "SDL.gpu.device.create.shaders.dxil"
#define SDL_PROP_GPU_DEVICE_CREATE_SHADERS_MSL_BOOLEAN "SDL.gpu.device.create.shaders.msl" #define SDL_PROP_GPU_DEVICE_CREATE_SHADERS_MSL_BOOLEAN "SDL.gpu.device.create.shaders.msl"
#define SDL_PROP_GPU_DEVICE_CREATE_SHADERS_METALLIB_BOOLEAN "SDL.gpu.device.create.shaders.metallib" #define SDL_PROP_GPU_DEVICE_CREATE_SHADERS_METALLIB_BOOLEAN "SDL.gpu.device.create.shaders.metallib"
#define SDL_PROP_GPU_DEVICE_CREATE_D3D12_SEMANTIC_NAME_STRING "SDL.gpu.device.create.d3d12.semantic" #define SDL_PROP_GPU_DEVICE_CREATE_D3D12_SEMANTIC_NAME_STRING "SDL.gpu.device.create.d3d12.semantic"
#define SDL_PROP_GPU_DEVICE_CREATE_VULKAN_SHADERCLIPDISTANCE_BOOLEAN "SDL.gpu.device.create.vulkan.shaderclipdistance"
#define SDL_PROP_GPU_DEVICE_CREATE_VULKAN_DEPTHCLAMP_BOOLEAN "SDL.gpu.device.create.vulkan.depthclamp"
#define SDL_PROP_GPU_DEVICE_CREATE_VULKAN_DRAWINDIRECTFIRST_BOOLEAN "SDL.gpu.device.create.vulkan.drawindirectfirstinstance"
#define SDL_PROP_GPU_DEVICE_CREATE_VULKAN_SAMPLERANISOTROPY_BOOLEAN "SDL.gpu.device.create.vulkan.sampleranisotropy"
/** /**
* Destroys a GPU context previously returned by SDL_CreateGPUDevice. * Destroys a GPU context previously returned by SDL_CreateGPUDevice.

View File

@@ -450,7 +450,7 @@ static const SDL_GPUBootstrap * SDL_GPUSelectBackend(SDL_PropertiesID props)
SDL_SetError("Required shader format for backend %s not provided!", gpudriver); SDL_SetError("Required shader format for backend %s not provided!", gpudriver);
return NULL; return NULL;
} }
if (backends[i]->PrepareDriver(_this)) { if (backends[i]->PrepareDriver(_this, props)) {
return backends[i]; return backends[i];
} }
} }
@@ -465,7 +465,7 @@ static const SDL_GPUBootstrap * SDL_GPUSelectBackend(SDL_PropertiesID props)
// Don't select a backend which doesn't support the app's shaders. // Don't select a backend which doesn't support the app's shaders.
continue; continue;
} }
if (backends[i]->PrepareDriver(_this)) { if (backends[i]->PrepareDriver(_this, props)) {
return backends[i]; return backends[i];
} }
} }

View File

@@ -1142,7 +1142,7 @@ typedef struct SDL_GPUBootstrap
{ {
const char *name; const char *name;
const SDL_GPUShaderFormat shader_formats; const SDL_GPUShaderFormat shader_formats;
bool (*PrepareDriver)(SDL_VideoDevice *_this); bool (*PrepareDriver)(SDL_VideoDevice *_this, SDL_PropertiesID props);
SDL_GPUDevice *(*CreateDevice)(bool debug_mode, bool prefer_low_power, SDL_PropertiesID props); SDL_GPUDevice *(*CreateDevice)(bool debug_mode, bool prefer_low_power, SDL_PropertiesID props);
} SDL_GPUBootstrap; } SDL_GPUBootstrap;

View File

@@ -8317,7 +8317,7 @@ static void D3D12_INTERNAL_InitBlitResources(
} }
} }
static bool D3D12_PrepareDriver(SDL_VideoDevice *_this) static bool D3D12_PrepareDriver(SDL_VideoDevice *_this, SDL_PropertiesID props)
{ {
#if defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES) #if defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES)
return true; return true;

View File

@@ -4307,7 +4307,7 @@ static bool METAL_SupportsTextureFormat(
// Device Creation // Device Creation
static bool METAL_PrepareDriver(SDL_VideoDevice *this) static bool METAL_PrepareDriver(SDL_VideoDevice *this, SDL_PropertiesID props)
{ {
if (@available(macOS 10.14, iOS 13.0, tvOS 13.0, *)) { if (@available(macOS 10.14, iOS 13.0, tvOS 13.0, *)) {
return (this->Metal_CreateView != NULL); return (this->Metal_CreateView != NULL);

View File

@@ -1088,6 +1088,7 @@ struct VulkanRenderer
VkPhysicalDevice physicalDevice; VkPhysicalDevice physicalDevice;
VkPhysicalDeviceProperties2KHR physicalDeviceProperties; VkPhysicalDeviceProperties2KHR physicalDeviceProperties;
VkPhysicalDeviceDriverPropertiesKHR physicalDeviceDriverProperties; VkPhysicalDeviceDriverPropertiesKHR physicalDeviceDriverProperties;
VkPhysicalDeviceFeatures desiredDeviceFeatures;
VkDevice logicalDevice; VkDevice logicalDevice;
Uint8 integratedMemoryNotification; Uint8 integratedMemoryNotification;
Uint8 outOfDeviceLocalMemoryWarning; Uint8 outOfDeviceLocalMemoryWarning;
@@ -11220,12 +11221,14 @@ static Uint8 VULKAN_INTERNAL_IsDeviceSuitable(
renderer->vkGetPhysicalDeviceFeatures( renderer->vkGetPhysicalDeviceFeatures(
physicalDevice, physicalDevice,
&deviceFeatures); &deviceFeatures);
if (!deviceFeatures.independentBlend ||
!deviceFeatures.imageCubeArray || if ((!deviceFeatures.independentBlend && renderer->desiredDeviceFeatures.independentBlend) ||
!deviceFeatures.depthClamp || (!deviceFeatures.imageCubeArray && renderer->desiredDeviceFeatures.imageCubeArray) ||
!deviceFeatures.shaderClipDistance || (!deviceFeatures.depthClamp && renderer->desiredDeviceFeatures.depthClamp) ||
!deviceFeatures.drawIndirectFirstInstance || (!deviceFeatures.shaderClipDistance && renderer->desiredDeviceFeatures.shaderClipDistance) ||
!deviceFeatures.sampleRateShading) { (!deviceFeatures.drawIndirectFirstInstance && renderer->desiredDeviceFeatures.drawIndirectFirstInstance) ||
(!deviceFeatures.sampleRateShading && renderer->desiredDeviceFeatures.sampleRateShading) ||
(!deviceFeatures.samplerAnisotropy && renderer->desiredDeviceFeatures.samplerAnisotropy)) {
return 0; return 0;
} }
@@ -11441,7 +11444,6 @@ static Uint8 VULKAN_INTERNAL_CreateLogicalDevice(
{ {
VkResult vulkanResult; VkResult vulkanResult;
VkDeviceCreateInfo deviceCreateInfo; VkDeviceCreateInfo deviceCreateInfo;
VkPhysicalDeviceFeatures desiredDeviceFeatures;
VkPhysicalDeviceFeatures haveDeviceFeatures; VkPhysicalDeviceFeatures haveDeviceFeatures;
VkPhysicalDevicePortabilitySubsetFeaturesKHR portabilityFeatures; VkPhysicalDevicePortabilitySubsetFeaturesKHR portabilityFeatures;
const char **deviceExtensions; const char **deviceExtensions;
@@ -11465,22 +11467,13 @@ static Uint8 VULKAN_INTERNAL_CreateLogicalDevice(
// specifying used device features // specifying used device features
SDL_zero(desiredDeviceFeatures);
desiredDeviceFeatures.independentBlend = VK_TRUE;
desiredDeviceFeatures.samplerAnisotropy = VK_TRUE;
desiredDeviceFeatures.imageCubeArray = VK_TRUE;
desiredDeviceFeatures.depthClamp = VK_TRUE;
desiredDeviceFeatures.shaderClipDistance = VK_TRUE;
desiredDeviceFeatures.drawIndirectFirstInstance = VK_TRUE;
desiredDeviceFeatures.sampleRateShading = VK_TRUE;
if (haveDeviceFeatures.fillModeNonSolid) { if (haveDeviceFeatures.fillModeNonSolid) {
desiredDeviceFeatures.fillModeNonSolid = VK_TRUE; renderer->desiredDeviceFeatures.fillModeNonSolid = VK_TRUE;
renderer->supportsFillModeNonSolid = true; renderer->supportsFillModeNonSolid = true;
} }
if (haveDeviceFeatures.multiDrawIndirect) { if (haveDeviceFeatures.multiDrawIndirect) {
desiredDeviceFeatures.multiDrawIndirect = VK_TRUE; renderer->desiredDeviceFeatures.multiDrawIndirect = VK_TRUE;
renderer->supportsMultiDrawIndirect = true; renderer->supportsMultiDrawIndirect = true;
} }
@@ -11521,7 +11514,7 @@ static Uint8 VULKAN_INTERNAL_CreateLogicalDevice(
deviceCreateInfo.enabledExtensionCount); deviceCreateInfo.enabledExtensionCount);
CreateDeviceExtensionArray(&renderer->supports, deviceExtensions); CreateDeviceExtensionArray(&renderer->supports, deviceExtensions);
deviceCreateInfo.ppEnabledExtensionNames = deviceExtensions; deviceCreateInfo.ppEnabledExtensionNames = deviceExtensions;
deviceCreateInfo.pEnabledFeatures = &desiredDeviceFeatures; deviceCreateInfo.pEnabledFeatures = &renderer->desiredDeviceFeatures;
vulkanResult = renderer->vkCreateDevice( vulkanResult = renderer->vkCreateDevice(
renderer->physicalDevice, renderer->physicalDevice,
@@ -11606,7 +11599,7 @@ static bool VULKAN_INTERNAL_PrepareVulkan(
return true; return true;
} }
static bool VULKAN_PrepareDriver(SDL_VideoDevice *_this) static bool VULKAN_PrepareDriver(SDL_VideoDevice *_this, SDL_PropertiesID props)
{ {
// Set up dummy VulkanRenderer // Set up dummy VulkanRenderer
VulkanRenderer *renderer; VulkanRenderer *renderer;
@@ -11622,6 +11615,17 @@ static bool VULKAN_PrepareDriver(SDL_VideoDevice *_this)
renderer = (VulkanRenderer *)SDL_calloc(1, sizeof(*renderer)); renderer = (VulkanRenderer *)SDL_calloc(1, sizeof(*renderer));
if (renderer) { if (renderer) {
// Opt out device features (higher compatibility in exchange for reduced functionality)
renderer->desiredDeviceFeatures.samplerAnisotropy = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_VULKAN_SAMPLERANISOTROPY_BOOLEAN, true) ? VK_TRUE : VK_FALSE;
renderer->desiredDeviceFeatures.depthClamp = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_VULKAN_DEPTHCLAMP_BOOLEAN, true) ? VK_TRUE : VK_FALSE;
renderer->desiredDeviceFeatures.shaderClipDistance = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_VULKAN_SHADERCLIPDISTANCE_BOOLEAN, true) ? VK_TRUE : VK_FALSE;
renderer->desiredDeviceFeatures.drawIndirectFirstInstance = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_VULKAN_DRAWINDIRECTFIRST_BOOLEAN, true) ? VK_TRUE : VK_FALSE;
// These features have near universal support so they are always enabled
renderer->desiredDeviceFeatures.independentBlend = VK_TRUE;
renderer->desiredDeviceFeatures.sampleRateShading = VK_TRUE;
renderer->desiredDeviceFeatures.imageCubeArray = VK_TRUE;
result = VULKAN_INTERNAL_PrepareVulkan(renderer); result = VULKAN_INTERNAL_PrepareVulkan(renderer);
if (result) { if (result) {
renderer->vkDestroyInstance(renderer->instance, NULL); renderer->vkDestroyInstance(renderer->instance, NULL);
@@ -11660,6 +11664,17 @@ static SDL_GPUDevice *VULKAN_CreateDevice(bool debugMode, bool preferLowPower, S
renderer->preferLowPower = preferLowPower; renderer->preferLowPower = preferLowPower;
renderer->allowedFramesInFlight = 2; renderer->allowedFramesInFlight = 2;
// Opt out device features (higher compatibility in exchange for reduced functionality)
renderer->desiredDeviceFeatures.samplerAnisotropy = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_VULKAN_SAMPLERANISOTROPY_BOOLEAN, true) ? VK_TRUE : VK_FALSE;
renderer->desiredDeviceFeatures.depthClamp = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_VULKAN_DEPTHCLAMP_BOOLEAN, true) ? VK_TRUE : VK_FALSE;
renderer->desiredDeviceFeatures.shaderClipDistance = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_VULKAN_SHADERCLIPDISTANCE_BOOLEAN, true) ? VK_TRUE : VK_FALSE;
renderer->desiredDeviceFeatures.drawIndirectFirstInstance = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_VULKAN_DRAWINDIRECTFIRST_BOOLEAN, true) ? VK_TRUE : VK_FALSE;
// These features have near universal support so they are always enabled
renderer->desiredDeviceFeatures.independentBlend = VK_TRUE;
renderer->desiredDeviceFeatures.sampleRateShading = VK_TRUE;
renderer->desiredDeviceFeatures.imageCubeArray = VK_TRUE;
if (!VULKAN_INTERNAL_PrepareVulkan(renderer)) { if (!VULKAN_INTERNAL_PrepareVulkan(renderer)) {
SDL_free(renderer); SDL_free(renderer);
SDL_Vulkan_UnloadLibrary(); SDL_Vulkan_UnloadLibrary();