From 910d31e56a1827d487aaf35080a14972e203d927 Mon Sep 17 00:00:00 2001 From: Ethan Lee 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 721545d430..ea75c15864 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 14f896eae7..840dd096c8 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,