From 910d31e56a1827d487aaf35080a14972e203d927 Mon Sep 17 00:00:00 2001
From: Ethan Lee <[EMAIL REDACTED]>
Date: Fri, 20 Feb 2026 10:31:53 -0500
Subject: [PATCH] vulkan: Only enable KHR_portability_enumeration when
available
---
src/gpu/vulkan/SDL_gpu_vulkan.c | 22 ++++++++----
test/testvulkan.c | 60 ++++++++++++++++++++++++++++++---
2 files changed, 71 insertions(+), 11 deletions(-)
diff --git a/src/gpu/vulkan/SDL_gpu_vulkan.c b/src/gpu/vulkan/SDL_gpu_vulkan.c
index 721545d4305cb..ea75c15864766 100644
--- a/src/gpu/vulkan/SDL_gpu_vulkan.c
+++ b/src/gpu/vulkan/SDL_gpu_vulkan.c
@@ -1123,6 +1123,7 @@ struct VulkanRenderer
bool supportsDebugUtils;
bool supportsColorspace;
bool supportsPhysicalDeviceProperties2;
+ bool supportsPortabilityEnumeration;
bool supportsFillModeNonSolid;
bool supportsMultiDrawIndirect;
@@ -11104,6 +11105,7 @@ static Uint8 VULKAN_INTERNAL_CheckInstanceExtensions(
bool *supportsDebugUtils,
bool *supportsColorspace,
bool *supportsPhysicalDeviceProperties2,
+ bool *supportsPortabilityEnumeration,
int *firstUnsupportedExtensionIndex)
{
Uint32 extensionCount, i;
@@ -11150,6 +11152,12 @@ static Uint8 VULKAN_INTERNAL_CheckInstanceExtensions(
availableExtensions,
extensionCount);
+ // Only needed for MoltenVK!
+ *supportsPortabilityEnumeration = SupportsInstanceExtension(
+ VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME,
+ availableExtensions,
+ extensionCount);
+
SDL_free(availableExtensions);
return allExtensionsSupported;
}
@@ -11775,13 +11783,6 @@ static Uint8 VULKAN_INTERNAL_CreateInstance(VulkanRenderer *renderer, VulkanFeat
nextInstanceExtensionNamePtr += extraInstanceExtensionCount;
}
-
-#ifdef SDL_PLATFORM_APPLE
- *nextInstanceExtensionNamePtr++ = VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME;
- instanceExtensionCount++;
- createFlags |= VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR;
-#endif
-
int firstUnsupportedExtensionIndex = 0;
if (!VULKAN_INTERNAL_CheckInstanceExtensions(
instanceExtensionNames,
@@ -11789,6 +11790,7 @@ static Uint8 VULKAN_INTERNAL_CreateInstance(VulkanRenderer *renderer, VulkanFeat
&renderer->supportsDebugUtils,
&renderer->supportsColorspace,
&renderer->supportsPhysicalDeviceProperties2,
+ &renderer->supportsPortabilityEnumeration,
&firstUnsupportedExtensionIndex)) {
if (renderer->debugMode) {
SDL_LogError(SDL_LOG_CATEGORY_GPU,
@@ -11824,6 +11826,12 @@ static Uint8 VULKAN_INTERNAL_CreateInstance(VulkanRenderer *renderer, VulkanFeat
instanceExtensionCount++;
}
+ if (renderer->supportsPortabilityEnumeration) {
+ *nextInstanceExtensionNamePtr++ = VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME;
+ instanceExtensionCount++;
+ createFlags |= VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR;
+ }
+
createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
createInfo.pNext = NULL;
createInfo.flags = createFlags;
diff --git a/test/testvulkan.c b/test/testvulkan.c
index 14f896eae755e..840dd096c8c18 100644
--- a/test/testvulkan.c
+++ b/test/testvulkan.c
@@ -218,22 +218,74 @@ static void loadGlobalFunctions(void)
#undef VULKAN_INSTANCE_FUNCTION
}
+static bool checkVulkanPortability(void)
+{
+ Uint32 extensionCount, i;
+ VkExtensionProperties *availableExtensions;
+ bool supported = false;
+
+ vkEnumerateInstanceExtensionProperties(
+ NULL,
+ &extensionCount,
+ NULL);
+ availableExtensions = SDL_malloc(
+ extensionCount * sizeof(VkExtensionProperties));
+ vkEnumerateInstanceExtensionProperties(
+ NULL,
+ &extensionCount,
+ availableExtensions);
+
+ for (i = 0; i < extensionCount; i += 1) {
+ if (SDL_strcmp(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME, availableExtensions[i].extensionName) == 0) {
+ supported = true;
+ break;
+ }
+ }
+
+ SDL_free(availableExtensions);
+ return supported;
+}
+
static void createInstance(void)
{
VkApplicationInfo appInfo = { 0 };
VkInstanceCreateInfo instanceCreateInfo = { 0 };
+ bool supportsPortabilityEnumeration;
+ const char **instanceExtensions;
VkResult result;
appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
appInfo.apiVersion = VK_API_VERSION_1_0;
instanceCreateInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
instanceCreateInfo.pApplicationInfo = &appInfo;
-#ifdef __APPLE__
- instanceCreateInfo.flags = VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR;
-#endif
- instanceCreateInfo.ppEnabledExtensionNames = SDL_Vulkan_GetInstanceExtensions(&instanceCreateInfo.enabledExtensionCount);
+ supportsPortabilityEnumeration = checkVulkanPortability();
+ if (supportsPortabilityEnumeration) {
+ // Allocate our own extension array so that we can add the KHR_portability extensions for MoltenVK
+ Uint32 count_instance_extensions;
+ const char * const *instance_extensions = SDL_Vulkan_GetInstanceExtensions(&count_instance_extensions);
+
+ int count_extensions = count_instance_extensions + 1;
+ instanceExtensions = SDL_malloc(count_extensions * sizeof(const char *));
+ instanceExtensions[0] = VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME;
+ SDL_memcpy(&instanceExtensions[1], instance_extensions, count_instance_extensions * sizeof(const char*));
+
+ instanceCreateInfo.enabledExtensionCount = count_extensions;
+ instanceCreateInfo.ppEnabledExtensionNames = instanceExtensions;
+ instanceCreateInfo.flags = VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR;
+ } else {
+ // No need to allocate anything, just use SDL's array directly
+ instanceExtensions = NULL;
+ instanceCreateInfo.ppEnabledExtensionNames =
+ SDL_Vulkan_GetInstanceExtensions(&instanceCreateInfo.enabledExtensionCount);
+ }
+
result = vkCreateInstance(&instanceCreateInfo, NULL, &vulkanContext->instance);
+
+ if (instanceExtensions != NULL) {
+ SDL_free(instanceExtensions);
+ }
+
if (result != VK_SUCCESS) {
vulkanContext->instance = VK_NULL_HANDLE;
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,