vk: enable portability enumeration on Apple platforms#2324
vk: enable portability enumeration on Apple platforms#2324JoeMatt wants to merge 2 commits intoflyinghead:masterfrom
Conversation
MoltenVK is a portability driver. Since Vulkan loader 1.3.216 the loader no longer enumerates portability ICDs unless the application sets VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR and enables the VK_KHR_portability_enumeration instance extension. Without this, vkCreateInstance returns VK_ERROR_INCOMPATIBLE_DRIVER on macOS / iOS where MoltenVK is the only available ICD, and Flycast fails to start the Vulkan renderer entirely. The opt-in is gated on __APPLE__ / VK_USE_PLATFORM_METAL_EXT so that non-portability platforms are unaffected, and on the extension macro being defined so older Vulkan headers continue to build. The matching VK_KHR_portability_subset device extension is already enabled on device creation under VK_ENABLE_BETA_EXTENSIONS. Made-with: Cursor
There was a problem hiding this comment.
Pull request overview
Enables Vulkan portability enumeration on Apple/Metal builds so the Vulkan loader can enumerate MoltenVK (portability) ICDs and avoid VK_ERROR_INCOMPATIBLE_DRIVER during instance creation.
Changes:
- Adds
VK_KHR_portability_enumerationto the instance extension list on Apple/Metal builds (when available in headers). - Sets
vk::InstanceCreateFlagBits::eEnumeratePortabilityKHRon instance creation for those builds.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // MoltenVK is a portability driver. Vulkan loaders >= 1.3.216 | ||
| // will not enumerate portability ICDs unless the application | ||
| // opts in via VK_KHR_portability_enumeration. Without this | ||
| // instance creation fails with VK_ERROR_INCOMPATIBLE_DRIVER | ||
| // on macOS / iOS where MoltenVK is the only available ICD. | ||
| vext.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME); | ||
| instanceFlags |= vk::InstanceCreateFlagBits::eEnumeratePortabilityKHR; |
There was a problem hiding this comment.
Enabling VK_KHR_portability_enumeration unconditionally (based only on compile-time macros) can regress on systems where the app is built with newer headers but runs against an older Vulkan loader that doesn’t advertise this instance extension: vkCreateInstance would fail with VK_ERROR_EXTENSION_NOT_PRESENT even though the old loader would otherwise work without the opt-in. Consider querying available instance extensions via vkEnumerateInstanceExtensionProperties (after VULKAN_HPP_DEFAULT_DISPATCHER.init) and only appending the extension + setting eEnumeratePortabilityKHR when it’s actually reported, and also avoid adding it if it’s already present in vext to prevent duplicate extension names.
There was a problem hiding this comment.
Good point — applied in 530bd90. Now queries vk::enumerateInstanceExtensionProperties() and only opts in (both pushing the extension and setting eEnumeratePortabilityKHR) when the loader actually advertises VK_KHR_portability_enumeration. So a binary built against newer headers but running against a pre-1.3.216 loader stays on the old code path instead of flipping to VK_ERROR_EXTENSION_NOT_PRESENT. Also added an std::any_of check against the host-provided vext to avoid duplicate names in case the surface backend (SDL etc.) ever starts requesting it itself.
Address Copilot review feedback. Compile-time gating alone is not enough: a binary built with newer Vulkan headers can run against an older loader that does not advertise VK_KHR_portability_enumeration, in which case unconditionally requesting it would flip the failure mode from "no MoltenVK ICD enumerated" to VK_ERROR_EXTENSION_NOT_PRESENT on otherwise-working setups. Query vk::enumerateInstanceExtensionProperties() and only push the extension + set eEnumeratePortabilityKHR when the loader reports it. Also skip re-pushing if the host (SDL etc.) already requested it, so we don't end up with duplicate names in vext. Made-with: Cursor
|
Please target the |
Summary
MoltenVK is a portability driver. Starting with Vulkan loader 1.3.216 the loader no longer enumerates portability ICDs unless the application explicitly opts in via:
VK_KHR_portability_enumerationinstance extensionVK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHRflag onVkInstanceCreateInfoWithout this,
vkCreateInstancereturnsVK_ERROR_INCOMPATIBLE_DRIVERon macOS / iOS where MoltenVK is the only available ICD, and Flycast falls back / fails to start the Vulkan renderer at all on a fresh install with the current SDK.The matching
VK_KHR_portability_subsetdevice extension is already enabled on device creation (underVK_ENABLE_BETA_EXTENSIONS), so this PR only fills in the missing instance side.Scope
defined(__APPLE__) || defined(VK_USE_PLATFORM_METAL_EXT), so non-portability platforms are not affected.defined(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME)so older Vulkan headers continue to compile.Test plan
VK_ERROR_INCOMPATIBLE_DRIVER).vextdoes not gain the portability extension andinstanceFlagsstays{}.Made with Cursor