From b4fefd4a94c202b8da4dd40c9377406892f9e80f Mon Sep 17 00:00:00 2001 From: SRSaunders <82544213+SRSaunders@users.noreply.github.com> Date: Sat, 1 Nov 2025 13:15:35 -0400 Subject: [PATCH 01/10] Change VKB_ENABLE_PORTABILITY from CMake declaration to option (default ON) --- bldsys/cmake/global_options.cmake | 82 ++++++++++++++++--------------- 1 file changed, 42 insertions(+), 40 deletions(-) diff --git a/bldsys/cmake/global_options.cmake b/bldsys/cmake/global_options.cmake index a25d77110..4e0f3495c 100644 --- a/bldsys/cmake/global_options.cmake +++ b/bldsys/cmake/global_options.cmake @@ -33,51 +33,53 @@ endif() if(APPLE) cmake_minimum_required(VERSION 3.24) - set(VKB_ENABLE_PORTABILITY ON CACHE BOOL "Enable portability enumeration and subset features in the framework. This is required to be set when running on Apple platforms." FORCE) - - find_package(Vulkan QUIET OPTIONAL_COMPONENTS MoltenVK) - if(USE_MoltenVK OR (IOS AND (NOT Vulkan_MoltenVK_FOUND OR ${CMAKE_OSX_SYSROOT} STREQUAL "iphonesimulator"))) - # if using MoltenVK, or MoltenVK for iOS was not found, or using iOS Simulator, look for MoltenVK in the Vulkan SDK and MoltenVK project locations - if(NOT Vulkan_MoltenVK_LIBRARY) - # since both are available in the Vulkan SDK and MoltenVK github project, make sure we look for MoltenVK framework on iOS and dylib on macOS - set(_saved_cmake_find_framework ${CMAKE_FIND_FRAMEWORK}) - if(IOS) - set(CMAKE_FIND_FRAMEWORK ALWAYS) - else() - set(CMAKE_FIND_FRAMEWORK NEVER) + option(VKB_ENABLE_PORTABILITY "Enable portability enumeration and subset features in the framework. This is required for MoltenVK on Apple platforms." ON) + + if(VKB_ENABLE_PORTABILITY) + find_package(Vulkan QUIET OPTIONAL_COMPONENTS MoltenVK) + if(USE_MoltenVK OR (IOS AND (NOT Vulkan_MoltenVK_FOUND OR ${CMAKE_OSX_SYSROOT} STREQUAL "iphonesimulator"))) + # if using MoltenVK, or MoltenVK for iOS was not found, or using iOS Simulator, look for MoltenVK in the Vulkan SDK and MoltenVK project locations + if(NOT Vulkan_MoltenVK_LIBRARY) + # since both are available in the Vulkan SDK and MoltenVK github project, make sure we look for MoltenVK framework on iOS and dylib on macOS + set(_saved_cmake_find_framework ${CMAKE_FIND_FRAMEWORK}) + if(IOS) + set(CMAKE_FIND_FRAMEWORK ALWAYS) + else() + set(CMAKE_FIND_FRAMEWORK NEVER) + endif() + find_library(Vulkan_MoltenVK_LIBRARY NAMES MoltenVK HINTS "$ENV{VULKAN_SDK}/lib" "$ENV{VULKAN_SDK}/dynamic" "$ENV{VULKAN_SDK}/dylib/macOS") + set(CMAKE_FIND_FRAMEWORK ${_saved_cmake_find_framework}) + unset(_saved_cmake_find_framework) endif() - find_library(Vulkan_MoltenVK_LIBRARY NAMES MoltenVK HINTS "$ENV{VULKAN_SDK}/lib" "$ENV{VULKAN_SDK}/dynamic" "$ENV{VULKAN_SDK}/dylib/macOS") - set(CMAKE_FIND_FRAMEWORK ${_saved_cmake_find_framework}) - unset(_saved_cmake_find_framework) - endif() - if(Vulkan_MoltenVK_LIBRARY) - get_filename_component(MoltenVK_LIBRARY_PATH ${Vulkan_MoltenVK_LIBRARY} DIRECTORY) - - # For both iOS and macOS: set up global Vulkan Library defines so that MoltenVK is dynamically loaded versus the Vulkan loader - # on iOS we can control Vulkan library loading priority by selecting which libraries are embedded in the iOS application bundle - if(IOS) - add_compile_definitions(_HPP_VULKAN_LIBRARY="MoltenVK.framework/MoltenVK") - # unset FindVulkan.cmake cache variables so Vulkan loader, Validation Layer, and icd/layer json files are not embedded on iOS - unset(Vulkan_LIBRARY CACHE) - unset(Vulkan_Layer_VALIDATION CACHE) - - # on macOS make sure that MoltenVK_LIBRARY_PATH points to the MoltenVK project installation and not to the Vulkan_LIBRARY location - # otherwise if DYLD_LIBRARY_PATH points to a common search path, Volk may dynamically load libvulkan.dylib versus libMoltenVK.dylib - elseif(NOT Vulkan_LIBRARY MATCHES "${MoltenVK_LIBRARY_PATH}") - add_compile_definitions(_HPP_VULKAN_LIBRARY="libMoltenVK.dylib") - add_compile_definitions(_GLFW_VULKAN_LIBRARY="libMoltenVK.dylib") - set(ENV{DYLD_LIBRARY_PATH} "${MoltenVK_LIBRARY_PATH}:$ENV{DYLD_LIBRARY_PATH}") + if(Vulkan_MoltenVK_LIBRARY) + get_filename_component(MoltenVK_LIBRARY_PATH ${Vulkan_MoltenVK_LIBRARY} DIRECTORY) + + # For both iOS and macOS: set up global Vulkan Library defines so that MoltenVK is dynamically loaded versus the Vulkan loader + # on iOS we can control Vulkan library loading priority by selecting which libraries are embedded in the iOS application bundle + if(IOS) + add_compile_definitions(_HPP_VULKAN_LIBRARY="MoltenVK.framework/MoltenVK") + # unset FindVulkan.cmake cache variables so Vulkan loader, Validation Layer, and icd/layer json files are not embedded on iOS + unset(Vulkan_LIBRARY CACHE) + unset(Vulkan_Layer_VALIDATION CACHE) + + # on macOS make sure that MoltenVK_LIBRARY_PATH points to the MoltenVK project installation and not to the Vulkan_LIBRARY location + # otherwise if DYLD_LIBRARY_PATH points to a common search path, Volk may dynamically load libvulkan.dylib versus libMoltenVK.dylib + elseif(NOT Vulkan_LIBRARY MATCHES "${MoltenVK_LIBRARY_PATH}") + add_compile_definitions(_HPP_VULKAN_LIBRARY="libMoltenVK.dylib") + add_compile_definitions(_GLFW_VULKAN_LIBRARY="libMoltenVK.dylib") + set(ENV{DYLD_LIBRARY_PATH} "${MoltenVK_LIBRARY_PATH}:$ENV{DYLD_LIBRARY_PATH}") + else() + message(FATAL_ERROR "Vulkan library found in MoltenVK search path. Please set VULKAN_SDK to the MoltenVK project install location.") + endif() + message(STATUS "Using MoltenVK: ${Vulkan_MoltenVK_LIBRARY}") else() - message(FATAL_ERROR "Vulkan library found in MoltenVK search path. Please set VULKAN_SDK to the MoltenVK project install location.") + message(FATAL_ERROR "Can't find MoltenVK library. Please install the Vulkan SDK or MoltenVK project and set VULKAN_SDK.") endif() - message(STATUS "Using MoltenVK: ${Vulkan_MoltenVK_LIBRARY}") - else() - message(FATAL_ERROR "Can't find MoltenVK library. Please install the Vulkan SDK or MoltenVK project and set VULKAN_SDK.") + elseif(IOS) + # if not using MoltenVK standalone on iOS, set up global Vulkan Library define for iOS Vulkan loader + add_compile_definitions(_HPP_VULKAN_LIBRARY="vulkan.framework/vulkan") endif() - elseif(IOS) - # if not using MoltenVK on iOS, set up global Vulkan Library define for iOS Vulkan loader - add_compile_definitions(_HPP_VULKAN_LIBRARY="vulkan.framework/vulkan") endif() if(CMAKE_GENERATOR MATCHES "Xcode") From 2c7bf57535d8167063a0100b55cff7b616c958af Mon Sep 17 00:00:00 2001 From: SRSaunders <82544213+SRSaunders@users.noreply.github.com> Date: Sat, 1 Nov 2025 13:25:04 -0400 Subject: [PATCH 02/10] Protect MoltenVK-specific code with VKB_ENABLE_PORTABILITY guards --- framework/core/instance.h | 2 +- .../performance/layout_transitions/layout_transitions.cpp | 6 +++--- samples/performance/pipeline_barriers/pipeline_barriers.cpp | 6 +++--- samples/performance/subpasses/subpasses.cpp | 6 +++--- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/framework/core/instance.h b/framework/core/instance.h index 4f4781f57..ae213566b 100644 --- a/framework/core/instance.h +++ b/framework/core/instance.h @@ -251,7 +251,7 @@ inline bool enable_layer_setting(vk::LayerSettingEXT const &requested_lay // Vulkan does not provide a reflection API for layer settings. Layer settings are described in each layer JSON manifest. bool is_available = std::ranges::any_of( enabled_layers, [&requested_layer_setting](auto const &available_layer) { return strcmp(available_layer, requested_layer_setting.pLayerName) == 0; }); -#if defined(PLATFORM__MACOS) +#if defined(PLATFORM__MACOS) && defined(VKB_ENABLE_PORTABILITY) // On Apple platforms the MoltenVK layer is implicitly enabled and available, and cannot be explicitly added or checked via enabled_layers. is_available = is_available || strcmp(requested_layer_setting.pLayerName, "MoltenVK") == 0; #endif diff --git a/samples/performance/layout_transitions/layout_transitions.cpp b/samples/performance/layout_transitions/layout_transitions.cpp index 7667f4809..a0b8e1280 100644 --- a/samples/performance/layout_transitions/layout_transitions.cpp +++ b/samples/performance/layout_transitions/layout_transitions.cpp @@ -37,7 +37,7 @@ LayoutTransitions::LayoutTransitions() config.insert(0, reinterpret_cast(layout_transition_type), LayoutTransitionType::UNDEFINED); config.insert(1, reinterpret_cast(layout_transition_type), LayoutTransitionType::LAST_LAYOUT); -#if defined(PLATFORM__MACOS) && TARGET_OS_IOS && TARGET_OS_SIMULATOR +#if defined(PLATFORM__MACOS) && TARGET_OS_IOS && TARGET_OS_SIMULATOR && defined(VKB_ENABLE_PORTABILITY) // On iOS Simulator use layer setting to disable MoltenVK's Metal argument buffers - otherwise blank display add_instance_extension(VK_EXT_LAYER_SETTINGS_EXTENSION_NAME, /*optional*/ true); @@ -48,8 +48,8 @@ LayoutTransitions::LayoutTransitions() layerSetting.valueCount = 1; // Make this static so layer setting reference remains valid after leaving constructor scope - static const int32_t useMetalArgumentBuffers = 0; - layerSetting.pValues = &useMetalArgumentBuffers; + static const int32_t disableMetalArgumentBuffers = 0; + layerSetting.pValues = &disableMetalArgumentBuffers; add_layer_setting(layerSetting); #endif diff --git a/samples/performance/pipeline_barriers/pipeline_barriers.cpp b/samples/performance/pipeline_barriers/pipeline_barriers.cpp index 1f8272427..5cbb3d1ad 100644 --- a/samples/performance/pipeline_barriers/pipeline_barriers.cpp +++ b/samples/performance/pipeline_barriers/pipeline_barriers.cpp @@ -39,7 +39,7 @@ PipelineBarriers::PipelineBarriers() config.insert(1, reinterpret_cast(dependency_type), DependencyType::FRAG_TO_VERT); config.insert(2, reinterpret_cast(dependency_type), DependencyType::FRAG_TO_FRAG); -#if defined(PLATFORM__MACOS) && TARGET_OS_IOS && TARGET_OS_SIMULATOR +#if defined(PLATFORM__MACOS) && TARGET_OS_IOS && TARGET_OS_SIMULATOR && defined(VKB_ENABLE_PORTABILITY) // On iOS Simulator use layer setting to disable MoltenVK's Metal argument buffers - otherwise blank display add_instance_extension(VK_EXT_LAYER_SETTINGS_EXTENSION_NAME, /*optional*/ true); @@ -50,8 +50,8 @@ PipelineBarriers::PipelineBarriers() layerSetting.valueCount = 1; // Make this static so layer setting reference remains valid after leaving constructor scope - static const int32_t useMetalArgumentBuffers = 0; - layerSetting.pValues = &useMetalArgumentBuffers; + static const int32_t disableMetalArgumentBuffers = 0; + layerSetting.pValues = &disableMetalArgumentBuffers; add_layer_setting(layerSetting); #endif diff --git a/samples/performance/subpasses/subpasses.cpp b/samples/performance/subpasses/subpasses.cpp index 42a66f78c..7d59e2b73 100644 --- a/samples/performance/subpasses/subpasses.cpp +++ b/samples/performance/subpasses/subpasses.cpp @@ -51,7 +51,7 @@ Subpasses::Subpasses() config.insert(3, configs[Config::TransientAttachments].value, 0); config.insert(3, configs[Config::GBufferSize].value, 1); -#if defined(PLATFORM__MACOS) && TARGET_OS_IOS && TARGET_OS_SIMULATOR +#if defined(PLATFORM__MACOS) && TARGET_OS_IOS && TARGET_OS_SIMULATOR && defined(VKB_ENABLE_PORTABILITY) // On iOS Simulator use layer setting to disable MoltenVK's Metal argument buffers - otherwise blank display add_instance_extension(VK_EXT_LAYER_SETTINGS_EXTENSION_NAME, /*optional*/ true); @@ -62,8 +62,8 @@ Subpasses::Subpasses() layerSetting.valueCount = 1; // Make this static so layer setting reference remains valid after leaving constructor scope - static const int32_t useMetalArgumentBuffers = 0; - layerSetting.pValues = &useMetalArgumentBuffers; + static const int32_t disableMetalArgumentBuffers = 0; + layerSetting.pValues = &disableMetalArgumentBuffers; add_layer_setting(layerSetting); #endif From 0dfbc182415ec3727fa93589de8b8a71ad937a7d Mon Sep 17 00:00:00 2001 From: SRSaunders <82544213+SRSaunders@users.noreply.github.com> Date: Sat, 1 Nov 2025 13:28:02 -0400 Subject: [PATCH 03/10] Remove unneeded Apple-specific #ifdefs from descriptor_indexing sample --- .../descriptor_indexing.cpp | 33 ------------------- 1 file changed, 33 deletions(-) diff --git a/samples/extensions/descriptor_indexing/descriptor_indexing.cpp b/samples/extensions/descriptor_indexing/descriptor_indexing.cpp index 7f853d0e7..178021faf 100644 --- a/samples/extensions/descriptor_indexing/descriptor_indexing.cpp +++ b/samples/extensions/descriptor_indexing/descriptor_indexing.cpp @@ -31,23 +31,6 @@ DescriptorIndexing::DescriptorIndexing() // Works around a validation layer bug with descriptor pool allocation with VARIABLE_COUNT. // See: https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/2350. add_device_extension(VK_KHR_MAINTENANCE1_EXTENSION_NAME); - -#if defined(PLATFORM__MACOS) - // On Apple use layer setting to enable MoltenVK's Metal argument buffers - needed for descriptor indexing/scaling - add_instance_extension(VK_EXT_LAYER_SETTINGS_EXTENSION_NAME, /*optional*/ true); - - VkLayerSettingEXT layerSetting; - layerSetting.pLayerName = "MoltenVK"; - layerSetting.pSettingName = "MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS"; - layerSetting.type = VK_LAYER_SETTING_TYPE_INT32_EXT; - layerSetting.valueCount = 1; - - // Make this static so layer setting reference remains valid after leaving constructor scope - static const int32_t useMetalArgumentBuffers = 1; - layerSetting.pValues = &useMetalArgumentBuffers; - - add_layer_setting(layerSetting); -#endif } DescriptorIndexing::~DescriptorIndexing() @@ -212,14 +195,6 @@ void DescriptorIndexing::create_bindless_descriptors() { uint32_t descriptorCount = descriptor_indexing_properties.maxDescriptorSetUpdateAfterBindSampledImages; -#if defined(PLATFORM__MACOS) - // On Apple Vulkan API <= 1.2.283 variable descriptor counts don't work, use max expected count instead. Fixed in later versions. - if (get_device().get_gpu().get_properties().apiVersion <= VK_MAKE_API_VERSION(0, 1, 2, 283)) - { - descriptorCount = std::max(NumDescriptorsStreaming, NumDescriptorsNonUniform); - } -#endif - VkDescriptorSetLayoutBinding binding = vkb::initializers::descriptor_set_layout_binding(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, VK_SHADER_STAGE_FRAGMENT_BIT, 0, descriptorCount); VkDescriptorSetLayoutCreateInfo set_layout_create_info = vkb::initializers::descriptor_set_layout_create_info(&binding, 1); @@ -262,14 +237,6 @@ void DescriptorIndexing::create_bindless_descriptors() // For the non-uniform indexing part, we allocate few descriptors, and for the streaming case, we allocate a fairly large ring buffer of descriptors we can play around with. uint32_t poolCount = NumDescriptorsStreaming + NumDescriptorsNonUniform; -#if defined(PLATFORM__MACOS) - // On Apple Vulkan API <= 1.2.283 variable descriptor counts don't work, use pool size of max expected count x 2 (for 2 allocations). Fixed in later versions. - if (get_device().get_gpu().get_properties().apiVersion <= VK_MAKE_API_VERSION(0, 1, 2, 283)) - { - poolCount = std::max(NumDescriptorsStreaming, NumDescriptorsNonUniform) * 2; - } -#endif - VkDescriptorPoolSize pool_size = vkb::initializers::descriptor_pool_size(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, poolCount); VkDescriptorPoolCreateInfo pool = vkb::initializers::descriptor_pool_create_info(1, &pool_size, 2); From f85f4c8881a6fd76f7ebaf79efb4d2d9308e0240 Mon Sep 17 00:00:00 2001 From: SRSaunders <82544213+SRSaunders@users.noreply.github.com> Date: Sat, 1 Nov 2025 13:32:26 -0400 Subject: [PATCH 04/10] Update profiles sample to not assume MoltenVK portability driver on Apple --- samples/tooling/profiles/profiles.cpp | 21 -------------------- samples/tooling/profiles/vulkan_profiles.hpp | 19 ------------------ 2 files changed, 40 deletions(-) diff --git a/samples/tooling/profiles/profiles.cpp b/samples/tooling/profiles/profiles.cpp index 040df2096..f804ab62d 100644 --- a/samples/tooling/profiles/profiles.cpp +++ b/samples/tooling/profiles/profiles.cpp @@ -167,27 +167,6 @@ std::unique_ptr Profiles::create_instance() } #endif -#if defined(PLATFORM__MACOS) - // On Apple use layer setting to enable MoltenVK's Metal argument buffers - needed for descriptor indexing/scaling - enabled_extensions.push_back(VK_EXT_LAYER_SETTINGS_EXTENSION_NAME); - - VkLayerSettingEXT layerSetting{}; - layerSetting.pLayerName = "MoltenVK"; - layerSetting.pSettingName = "MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS"; - layerSetting.type = VK_LAYER_SETTING_TYPE_INT32_EXT; - layerSetting.valueCount = 1; - - const int32_t useMetalArgumentBuffers = 1; - layerSetting.pValues = &useMetalArgumentBuffers; - - VkLayerSettingsCreateInfoEXT layerSettingsCreateInfo{}; - layerSettingsCreateInfo.sType = VK_STRUCTURE_TYPE_LAYER_SETTINGS_CREATE_INFO_EXT; - layerSettingsCreateInfo.settingCount = 1; - layerSettingsCreateInfo.pSettings = &layerSetting; - - create_info.pNext = &layerSettingsCreateInfo; -#endif - create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; create_info.ppEnabledExtensionNames = enabled_extensions.data(); create_info.enabledExtensionCount = static_cast(enabled_extensions.size()); diff --git a/samples/tooling/profiles/vulkan_profiles.hpp b/samples/tooling/profiles/vulkan_profiles.hpp index aab81bcfe..499c121a6 100644 --- a/samples/tooling/profiles/vulkan_profiles.hpp +++ b/samples/tooling/profiles/vulkan_profiles.hpp @@ -33648,25 +33648,6 @@ VPAPI_ATTR VkResult vpCreateInstance( } } -#ifdef __APPLE__ - bool has_portability_ext = false; - for (std::size_t ext_index = 0, ext_count = extensions.size(); ext_index < ext_count; ++ext_index) - { - if (strcmp(extensions[ext_index], VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME) == 0) - { - has_portability_ext = true; - break; - } - } - - if (!has_portability_ext) - { - extensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME); - } - - createInfo.flags |= VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR; -#endif - if (!extensions.empty()) { createInfo.enabledExtensionCount = static_cast(extensions.size()); From 82bd79204d4f16f4154883888917f7fdfd914a39 Mon Sep 17 00:00:00 2001 From: SRSaunders <82544213+SRSaunders@users.noreply.github.com> Date: Sat, 1 Nov 2025 13:33:58 -0400 Subject: [PATCH 05/10] Fix [hpp_]hello_triangle samples to check for null objects on error termination --- samples/api/hello_triangle/hello_triangle.cpp | 5 ++++- .../api/hpp_hello_triangle/hpp_hello_triangle.cpp | 15 ++++++++++++--- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/samples/api/hello_triangle/hello_triangle.cpp b/samples/api/hello_triangle/hello_triangle.cpp index 75e1d1839..3e5cde46a 100644 --- a/samples/api/hello_triangle/hello_triangle.cpp +++ b/samples/api/hello_triangle/hello_triangle.cpp @@ -997,7 +997,10 @@ HelloTriangle::~HelloTriangle() { // When destroying the application, we need to make sure the GPU is no longer accessing any resources // This is done by doing a device wait idle, which blocks until the GPU signals - vkDeviceWaitIdle(context.device); + if (context.device != VK_NULL_HANDLE) + { + vkDeviceWaitIdle(context.device); + } for (auto &framebuffer : context.swapchain_framebuffers) { diff --git a/samples/api/hpp_hello_triangle/hpp_hello_triangle.cpp b/samples/api/hpp_hello_triangle/hpp_hello_triangle.cpp index b1727a372..5a8a2fe34 100644 --- a/samples/api/hpp_hello_triangle/hpp_hello_triangle.cpp +++ b/samples/api/hpp_hello_triangle/hpp_hello_triangle.cpp @@ -76,7 +76,10 @@ HPPHelloTriangle::HPPHelloTriangle() HPPHelloTriangle::~HPPHelloTriangle() { // Don't release anything until the GPU is completely idle. - device.waitIdle(); + if (device) + { + device.waitIdle(); + } teardown_framebuffers(); @@ -142,7 +145,10 @@ HPPHelloTriangle::~HPPHelloTriangle() instance.destroyDebugUtilsMessengerEXT(debug_utils_messenger); } - instance.destroy(); + if (instance) + { + instance.destroy(); + } } bool HPPHelloTriangle::prepare(const vkb::ApplicationOptions &options) @@ -915,7 +921,10 @@ void HPPHelloTriangle::select_physical_device_and_surface() void HPPHelloTriangle::teardown_framebuffers() { // Wait until device is idle before teardown. - queue.waitIdle(); + if (queue) + { + queue.waitIdle(); + } for (auto &framebuffer : swapchain_data.framebuffers) { From 86de62a06e056422c1ddf32e9719e6c8744436f6 Mon Sep 17 00:00:00 2001 From: SRSaunders <82544213+SRSaunders@users.noreply.github.com> Date: Mon, 3 Nov 2025 10:31:03 -0500 Subject: [PATCH 06/10] Improve CMake comments+messages for iOS config and build framework --- app/CMakeLists.txt | 11 +++++++++-- bldsys/cmake/global_options.cmake | 10 +++++----- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 1de3d7b7e..996d907b1 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -135,7 +135,7 @@ if(IOS) XCODE_EMBED_FRAMEWORKS_CODE_SIGN_ON_COPY "YES" ) endif () - # No need to search for Vulkan package or MoltenVK library, Vulkan cache variables already defined on Apple platforms by global_options.cmake + # Vulkan cache variables already defined by main project CMakeLists and updated on Apple platforms by global_options.cmake if(Vulkan_LIBRARY AND ${Vulkan_VERSION} VERSION_GREATER_EQUAL 1.3.278) target_sources(${PROJECT_NAME} PRIVATE ${Vulkan_Target_SDK}/iOS/share/vulkan @@ -163,17 +163,24 @@ if(IOS) set(FRAMEWORKS_TO_EMBED) if(Vulkan_MoltenVK_LIBRARY) list(APPEND FRAMEWORKS_TO_EMBED "${Vulkan_MoltenVK_LIBRARY};") + message(STATUS "Embedding Vulkan driver: ${Vulkan_MoltenVK_LIBRARY}") + # add support for potentially other iOS Vulkan drivers here... + #elseif(OTHER_IOS_VULKAN_DRIVER) + #list(APPEND FRAMEWORKS_TO_EMBED "${OTHER_IOS_VULKAN_DRIVER};") + #message(STATUS "Embedding Vulkan driver: ${OTHER_IOS_VULKAN_DRIVER}") else() - message(FATAL_ERROR "Can't find MoltenVK library. Please install the Vulkan SDK or MoltenVK project and set VULKAN_SDK.") + message(FATAL_ERROR "Can't find Vulkan driver for iOS. Please install the Vulkan SDK and run: 'source /iOS/setup-env.sh'") endif() if(Vulkan_LIBRARY) list(APPEND FRAMEWORKS_TO_EMBED "${Vulkan_LIBRARY};") + message(STATUS "Embedding Vulkan loader: ${Vulkan_LIBRARY}") endif() if(Vulkan_Layer_VALIDATION) # trouble is can't turn this on/off if XCode decides to build debug and we're configured for release. Need to revist # note the Vulkan validation layer must be present and enabled even in release mode for the shader_debugprintf sample #if(("${VKB_DEBUG}" STREQUAL "ON") OR ("${VKB_VALIDATION_LAYERS}" STREQUAL "ON")) list(APPEND FRAMEWORKS_TO_EMBED "${Vulkan_Layer_VALIDATION}") + message(STATUS "Embedding Vulkan Validation Layer: ${Vulkan_Layer_VALIDATION}") #endif() endif() set_target_properties(${PROJECT_NAME} PROPERTIES diff --git a/bldsys/cmake/global_options.cmake b/bldsys/cmake/global_options.cmake index 4e0f3495c..99077c0f5 100644 --- a/bldsys/cmake/global_options.cmake +++ b/bldsys/cmake/global_options.cmake @@ -38,7 +38,7 @@ if(APPLE) if(VKB_ENABLE_PORTABILITY) find_package(Vulkan QUIET OPTIONAL_COMPONENTS MoltenVK) if(USE_MoltenVK OR (IOS AND (NOT Vulkan_MoltenVK_FOUND OR ${CMAKE_OSX_SYSROOT} STREQUAL "iphonesimulator"))) - # if using MoltenVK, or MoltenVK for iOS was not found, or using iOS Simulator, look for MoltenVK in the Vulkan SDK and MoltenVK project locations + # if using MoltenVK standalone, or MoltenVK for iOS not found or using iOS Simulator, look for MoltenVK in Vulkan SDK and MoltenVK project paths if(NOT Vulkan_MoltenVK_LIBRARY) # since both are available in the Vulkan SDK and MoltenVK github project, make sure we look for MoltenVK framework on iOS and dylib on macOS set(_saved_cmake_find_framework ${CMAKE_FIND_FRAMEWORK}) @@ -72,13 +72,13 @@ if(APPLE) else() message(FATAL_ERROR "Vulkan library found in MoltenVK search path. Please set VULKAN_SDK to the MoltenVK project install location.") endif() - message(STATUS "Using MoltenVK: ${Vulkan_MoltenVK_LIBRARY}") + message(STATUS "Using MoltenVK standalone: ${Vulkan_MoltenVK_LIBRARY}") else() message(FATAL_ERROR "Can't find MoltenVK library. Please install the Vulkan SDK or MoltenVK project and set VULKAN_SDK.") endif() - elseif(IOS) - # if not using MoltenVK standalone on iOS, set up global Vulkan Library define for iOS Vulkan loader - add_compile_definitions(_HPP_VULKAN_LIBRARY="vulkan.framework/vulkan") + #else() + # if not using MoltenVK standalone, retain find_package() results for MoltenVK, Vulkan loader, and Validation Layer library defines + # no need to override with _HPP_VULKAN_LIBRARY in this case since Vulkan DynamicLoader will find/load Vulkan library on macOS & iOS endif() endif() From f9448e6fb63ea3c7168719d3705d2a0d9f7bdfd7 Mon Sep 17 00:00:00 2001 From: SRSaunders <82544213+SRSaunders@users.noreply.github.com> Date: Mon, 3 Nov 2025 10:52:06 -0500 Subject: [PATCH 07/10] Update copyright header date in vulkan_samples CMakeLists --- app/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 996d907b1..22c817f0c 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2019-2024, Arm Limited and Contributors +# Copyright (c) 2019-2025, Arm Limited and Contributors # # SPDX-License-Identifier: Apache-2.0 # From 5bb74483c310634ef73b3cf43e981b7bb114b4bc Mon Sep 17 00:00:00 2001 From: SRSaunders <82544213+SRSaunders@users.noreply.github.com> Date: Mon, 3 Nov 2025 22:37:55 -0500 Subject: [PATCH 08/10] Update profiles sample: portability subset, update-after-bind pool, clean-up on exit --- samples/tooling/profiles/profiles.cpp | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/samples/tooling/profiles/profiles.cpp b/samples/tooling/profiles/profiles.cpp index f804ab62d..8f3eb927a 100644 --- a/samples/tooling/profiles/profiles.cpp +++ b/samples/tooling/profiles/profiles.cpp @@ -47,13 +47,18 @@ Profiles::~Profiles() // Clean up used Vulkan resources // Note : Inherited destructor cleans up resources stored in base class for (auto &tex : textures) + { + vkDestroyImageView(get_device().get_handle(), tex.image_view, nullptr); + vkDestroyImage(get_device().get_handle(), tex.image, nullptr); vkFreeMemory(get_device().get_handle(), tex.memory, nullptr); + } vkDestroyPipeline(get_device().get_handle(), pipeline, nullptr); vkDestroyPipelineLayout(get_device().get_handle(), pipeline_layout, nullptr); vkDestroyDescriptorSetLayout(get_device().get_handle(), base_descriptor_set_layout, nullptr); vkDestroyDescriptorSetLayout(get_device().get_handle(), sampler_descriptor_set_layout, nullptr); + vkDestroySampler(get_device().get_handle(), sampler, nullptr); } } @@ -92,6 +97,20 @@ std::unique_ptr Profiles::create_device(vkb::core::PhysicalD std::vector enabled_extensions; enabled_extensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME); +#if (defined(VKB_ENABLE_PORTABILITY)) + uint32_t device_extension_count; + VK_CHECK(vkEnumerateDeviceExtensionProperties(gpu.get_handle(), nullptr, &device_extension_count, nullptr)); + std::vector available_device_extensions(device_extension_count); + VK_CHECK(vkEnumerateDeviceExtensionProperties(gpu.get_handle(), nullptr, &device_extension_count, available_device_extensions.data())); + + // VK_KHR_portability_subset must be enabled if present in the implementation (e.g on macOS/iOS with beta extensions enabled) + if (std::ranges::any_of(available_device_extensions, + [](VkExtensionProperties const &extension) { return strcmp(extension.extensionName, VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME) == 0; })) + { + enabled_extensions.push_back(VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME); + } +#endif + VkDeviceCreateInfo create_info{VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO}; create_info.pNext = gpu.get_extension_feature_chain(); create_info.pQueueCreateInfos = &queue_create_info; @@ -443,6 +462,7 @@ void Profiles::setup_descriptor_pool() static_cast(pool_sizes.size()), pool_sizes.data(), 3); + descriptor_pool_create_info.flags = VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT_EXT; VK_CHECK(vkCreateDescriptorPool(get_device().get_handle(), &descriptor_pool_create_info, nullptr, &descriptor_pool)); } @@ -480,6 +500,7 @@ void Profiles::setup_descriptor_set_layout() static_cast(textures.size()))}; descriptor_layout_create_info.bindingCount = static_cast(set_layout_bindings.size()); descriptor_layout_create_info.pBindings = set_layout_bindings.data(); + descriptor_layout_create_info.flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT_EXT; VK_CHECK(vkCreateDescriptorSetLayout(get_device().get_handle(), &descriptor_layout_create_info, nullptr, &base_descriptor_set_layout)); // Set layout for the samplers @@ -492,6 +513,7 @@ void Profiles::setup_descriptor_set_layout() static_cast(textures.size()))}; descriptor_layout_create_info.bindingCount = static_cast(set_layout_bindings.size()); descriptor_layout_create_info.pBindings = set_layout_bindings.data(); + descriptor_layout_create_info.pNext = nullptr; VK_CHECK(vkCreateDescriptorSetLayout(get_device().get_handle(), &descriptor_layout_create_info, nullptr, &sampler_descriptor_set_layout)); // Pipeline layout From f9f90abfc98c46cebf18cfb41577ba4b3ed2be4b Mon Sep 17 00:00:00 2001 From: SRSaunders <82544213+SRSaunders@users.noreply.github.com> Date: Wed, 5 Nov 2025 12:44:24 -0500 Subject: [PATCH 09/10] Always check for Portability at runtime and update comments to not assume MoltenVK --- bldsys/cmake/global_options.cmake | 2 + framework/core/instance.h | 16 +++- framework/vulkan_sample.h | 2 +- samples/api/hello_triangle/hello_triangle.cpp | 2 +- .../hello_triangle_1_3/hello_triangle_1_3.cpp | 2 +- .../hpp_hello_triangle/hpp_hello_triangle.cpp | 2 +- .../hpp_hello_triangle_1_3.cpp | 2 +- .../extensions/portability/portability.cpp | 85 ++++++++++--------- .../shader_debugprintf/shader_debugprintf.cpp | 2 +- .../async_compute/async_compute.cpp | 2 +- .../layout_transitions/layout_transitions.cpp | 4 +- .../multithreading_render_passes.cpp | 2 +- .../pipeline_barriers/pipeline_barriers.cpp | 4 +- samples/performance/subpasses/subpasses.cpp | 4 +- samples/tooling/profiles/profiles.cpp | 15 ++-- 15 files changed, 82 insertions(+), 64 deletions(-) diff --git a/bldsys/cmake/global_options.cmake b/bldsys/cmake/global_options.cmake index 99077c0f5..50122695c 100644 --- a/bldsys/cmake/global_options.cmake +++ b/bldsys/cmake/global_options.cmake @@ -105,6 +105,8 @@ if(APPLE) set(CMAKE_SUPPRESS_REGENERATION ON) endif() endif() +else() + option(VKB_ENABLE_PORTABILITY "Enable portability enumeration and subset features in the framework. This is default off on non-Apple platforms." OFF) endif() set(VKB_WARNINGS_AS_ERRORS ON CACHE BOOL "Enable Warnings as Errors") diff --git a/framework/core/instance.h b/framework/core/instance.h index ae213566b..5d8c89428 100644 --- a/framework/core/instance.h +++ b/framework/core/instance.h @@ -251,9 +251,19 @@ inline bool enable_layer_setting(vk::LayerSettingEXT const &requested_lay // Vulkan does not provide a reflection API for layer settings. Layer settings are described in each layer JSON manifest. bool is_available = std::ranges::any_of( enabled_layers, [&requested_layer_setting](auto const &available_layer) { return strcmp(available_layer, requested_layer_setting.pLayerName) == 0; }); -#if defined(PLATFORM__MACOS) && defined(VKB_ENABLE_PORTABILITY) - // On Apple platforms the MoltenVK layer is implicitly enabled and available, and cannot be explicitly added or checked via enabled_layers. - is_available = is_available || strcmp(requested_layer_setting.pLayerName, "MoltenVK") == 0; + +#if defined(PLATFORM__MACOS) + // On Apple the MoltenVK driver configuration layer is implicitly enabled and available, and cannot be explicitly added or checked via enabled_layers. + if (!is_available && strcmp(requested_layer_setting.pLayerName, "MoltenVK") == 0) + { + // Check for VK_EXT_layer_settings extension in the driver which indicates MoltenVK vs. KosmicKrisp (note: VK_MVK_moltenvk extension is deprecated). + std::vector available_instance_extensions = vk::enumerateInstanceExtensionProperties(); + if (std::ranges::any_of(available_instance_extensions, + [](vk::ExtensionProperties const &extension) { return strcmp(extension.extensionName, VK_EXT_LAYER_SETTINGS_EXTENSION_NAME) == 0; })) + { + is_available = true; + } + } #endif if (!is_available) diff --git a/framework/vulkan_sample.h b/framework/vulkan_sample.h index 6dda756c7..6c1c4d94b 100644 --- a/framework/vulkan_sample.h +++ b/framework/vulkan_sample.h @@ -1115,7 +1115,7 @@ inline bool VulkanSample::prepare(const ApplicationOptions &options } #ifdef VKB_ENABLE_PORTABILITY - // VK_KHR_portability_subset must be enabled if present in the implementation (e.g on macOS/iOS with beta extensions enabled) + // VK_KHR_portability_subset must be enabled if present in the implementation (e.g on macOS/iOS using MoltenVK with beta extensions enabled) add_device_extension(VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME, /*optional=*/true); #endif diff --git a/samples/api/hello_triangle/hello_triangle.cpp b/samples/api/hello_triangle/hello_triangle.cpp index 3e5cde46a..e10954a1c 100644 --- a/samples/api/hello_triangle/hello_triangle.cpp +++ b/samples/api/hello_triangle/hello_triangle.cpp @@ -293,7 +293,7 @@ void HelloTriangle::init_device() } #if (defined(VKB_ENABLE_PORTABILITY)) - // VK_KHR_portability_subset must be enabled if present in the implementation (e.g on macOS/iOS with beta extensions enabled) + // VK_KHR_portability_subset must be enabled if present in the implementation (e.g on macOS/iOS using MoltenVK with beta extensions enabled) if (std::ranges::any_of(device_extensions, [](VkExtensionProperties const &extension) { return strcmp(extension.extensionName, VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME) == 0; })) { diff --git a/samples/api/hello_triangle_1_3/hello_triangle_1_3.cpp b/samples/api/hello_triangle_1_3/hello_triangle_1_3.cpp index 84d37f3d3..f0d23fe11 100644 --- a/samples/api/hello_triangle_1_3/hello_triangle_1_3.cpp +++ b/samples/api/hello_triangle_1_3/hello_triangle_1_3.cpp @@ -309,7 +309,7 @@ void HelloTriangleV13::init_device() } #if (defined(VKB_ENABLE_PORTABILITY)) - // VK_KHR_portability_subset must be enabled if present in the implementation (e.g on macOS/iOS with beta extensions enabled) + // VK_KHR_portability_subset must be enabled if present in the implementation (e.g on macOS/iOS using MoltenVK with beta extensions enabled) if (std::ranges::any_of(device_extensions, [](VkExtensionProperties const &extension) { return strcmp(extension.extensionName, VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME) == 0; })) { diff --git a/samples/api/hpp_hello_triangle/hpp_hello_triangle.cpp b/samples/api/hpp_hello_triangle/hpp_hello_triangle.cpp index 5a8a2fe34..a8ccf3a63 100644 --- a/samples/api/hpp_hello_triangle/hpp_hello_triangle.cpp +++ b/samples/api/hpp_hello_triangle/hpp_hello_triangle.cpp @@ -331,7 +331,7 @@ vk::Device HPPHelloTriangle::create_device(const std::vector &requ std::vector active_device_extensions(required_device_extensions); #if (defined(VKB_ENABLE_PORTABILITY)) - // VK_KHR_portability_subset must be enabled if present in the implementation (e.g on macOS/iOS with beta extensions enabled) + // VK_KHR_portability_subset must be enabled if present in the implementation (e.g on macOS/iOS using MoltenVK with beta extensions enabled) if (std::ranges::any_of(device_extensions, [](vk::ExtensionProperties const &extension) { return strcmp(extension.extensionName, VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME) == 0; })) { diff --git a/samples/api/hpp_hello_triangle_1_3/hpp_hello_triangle_1_3.cpp b/samples/api/hpp_hello_triangle_1_3/hpp_hello_triangle_1_3.cpp index e54a304ce..ce5c5a2c9 100644 --- a/samples/api/hpp_hello_triangle_1_3/hpp_hello_triangle_1_3.cpp +++ b/samples/api/hpp_hello_triangle_1_3/hpp_hello_triangle_1_3.cpp @@ -386,7 +386,7 @@ void HPPHelloTriangleV13::init_device() } #if (defined(VKB_ENABLE_PORTABILITY)) - // VK_KHR_portability_subset must be enabled if present in the implementation (e.g on macOS/iOS with beta extensions enabled) + // VK_KHR_portability_subset must be enabled if present in the implementation (e.g on macOS/iOS using MoltenVK with beta extensions enabled) if (std::ranges::any_of(device_extensions, [](vk::ExtensionProperties const &extension) { return strcmp(extension.extensionName, VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME) == 0; })) { diff --git a/samples/extensions/portability/portability.cpp b/samples/extensions/portability/portability.cpp index a600960e7..9078a3fb0 100644 --- a/samples/extensions/portability/portability.cpp +++ b/samples/extensions/portability/portability.cpp @@ -33,10 +33,12 @@ Portability::Portability() : filter_pass() { title = "Portability"; - // Portability is a Vulkan 1.3 extension - set_api_version(VK_API_VERSION_1_3); - add_instance_extension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); - add_instance_extension(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME, /*optional*/ true); + // These instance extensions are conditionally added by the sample framework when VKB_ENABLE_PORTABILITY is enabled + // add_instance_extension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); + // add_instance_extension(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME, /*optional=*/true); + + // VK_KHR_portability_subset depends on VK_KHR_get_physical_device_properties2 or Vulkan 1.1 (default for project) + // This device extension is conditionally added by the sample framework when VKB_ENABLE_PORTABILITY is enabled } Portability::~Portability() @@ -868,41 +870,48 @@ void Portability::render(float delta_time) void Portability::on_update_ui_overlay(vkb::Drawer &drawer) { #ifdef VKB_ENABLE_PORTABILITY - std::string portability_support_list; - if (portability_features.constantAlphaColorBlendFactors) - portability_support_list += "constantAlphaColorBlendFactors\n"; - if (portability_features.events) - portability_support_list += "events\n"; - if (portability_features.imageView2DOn3DImage) - portability_support_list += "imageView2DOn3dImage\n"; - if (portability_features.imageViewFormatReinterpretation) - portability_support_list += "imageViewFormatReinterpretation\n"; - if (portability_features.imageViewFormatSwizzle) - portability_support_list += "imageViewFormatSwizzle\n"; - if (portability_features.multisampleArrayImage) - portability_support_list += "multisampleArrayImage\n"; - if (portability_features.mutableComparisonSamplers) - portability_support_list += "mutableComparisonSamplers\n"; - if (portability_features.pointPolygons) - portability_support_list += "pointPolygons\n"; - if (portability_features.samplerMipLodBias) - portability_support_list += "samplerMipLodBias\n"; - if (portability_features.separateStencilMaskRef) - portability_support_list += "separateStencilMaskRef\n"; - if (portability_features.shaderSampleRateInterpolationFunctions) - portability_support_list += "shaderSampleRateInterpolationFunctions\n"; - if (portability_features.tessellationIsolines) - portability_support_list += "tessellationIsolines\n"; - if (portability_features.tessellationPointMode) - portability_support_list += "tessellationPointMode\n"; - if (portability_features.triangleFans) - portability_support_list += "triangleFans\n"; - if (portability_features.vertexAttributeAccessBeyondStride) - portability_support_list += "vertexAttributeAccessBeyondStride\n"; - drawer.text("Device Portability feature support list:\n%s", portability_support_list.c_str()); -#else - drawer.text("VKB_ENABLE_PORTABILITY not enabled can't list portability feature set"); + // VK_KHR_portability_subset extension must be available in the implementation to list device portability feature set + if (get_device().get_gpu().is_extension_supported(VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME)) + { + std::string portability_support_list; + if (portability_features.constantAlphaColorBlendFactors) + portability_support_list += "constantAlphaColorBlendFactors\n"; + if (portability_features.events) + portability_support_list += "events\n"; + if (portability_features.imageView2DOn3DImage) + portability_support_list += "imageView2DOn3dImage\n"; + if (portability_features.imageViewFormatReinterpretation) + portability_support_list += "imageViewFormatReinterpretation\n"; + if (portability_features.imageViewFormatSwizzle) + portability_support_list += "imageViewFormatSwizzle\n"; + if (portability_features.multisampleArrayImage) + portability_support_list += "multisampleArrayImage\n"; + if (portability_features.mutableComparisonSamplers) + portability_support_list += "mutableComparisonSamplers\n"; + if (portability_features.pointPolygons) + portability_support_list += "pointPolygons\n"; + if (portability_features.samplerMipLodBias) + portability_support_list += "samplerMipLodBias\n"; + if (portability_features.separateStencilMaskRef) + portability_support_list += "separateStencilMaskRef\n"; + if (portability_features.shaderSampleRateInterpolationFunctions) + portability_support_list += "shaderSampleRateInterpolationFunctions\n"; + if (portability_features.tessellationIsolines) + portability_support_list += "tessellationIsolines\n"; + if (portability_features.tessellationPointMode) + portability_support_list += "tessellationPointMode\n"; + if (portability_features.triangleFans) + portability_support_list += "triangleFans\n"; + if (portability_features.vertexAttributeAccessBeyondStride) + portability_support_list += "vertexAttributeAccessBeyondStride\n"; + drawer.text("Device Portability feature support list:\n%s", portability_support_list.c_str()); + } + else #endif + { + drawer.text("VK_KHR_portability_subset not available can't list portability feature set"); + } + if (drawer.header("Settings")) { if (drawer.checkbox("Bloom", &bloom)) diff --git a/samples/extensions/shader_debugprintf/shader_debugprintf.cpp b/samples/extensions/shader_debugprintf/shader_debugprintf.cpp index 29f2ef96e..f851dcf81 100644 --- a/samples/extensions/shader_debugprintf/shader_debugprintf.cpp +++ b/samples/extensions/shader_debugprintf/shader_debugprintf.cpp @@ -497,7 +497,7 @@ std::unique_ptr ShaderDebugPrintf::create_instance() std::vector available_instance_extensions(available_extension_count); VK_CHECK(vkEnumerateInstanceExtensionProperties(nullptr, &available_extension_count, available_instance_extensions.data())); - // If VK_KHR_portability_enumeration is available in the portability implementation, then we must enable the extension + // If VK_KHR_portability_enumeration is available in the implementation, then we must enable the extension bool portability_enumeration_available = false; if (std::ranges::any_of(available_instance_extensions, [](VkExtensionProperties const &extension) { return strcmp(extension.extensionName, VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME) == 0; })) diff --git a/samples/performance/async_compute/async_compute.cpp b/samples/performance/async_compute/async_compute.cpp index c87597a86..c39d2315f 100644 --- a/samples/performance/async_compute/async_compute.cpp +++ b/samples/performance/async_compute/async_compute.cpp @@ -42,7 +42,7 @@ void AsyncComputeSample::request_gpu_features(vkb::core::PhysicalDeviceC &gpu) { #ifdef VKB_ENABLE_PORTABILITY // Since sampler_info.compareEnable = VK_TRUE, must enable the mutableComparisonSamplers feature of VK_KHR_portability_subset - REQUEST_REQUIRED_FEATURE(gpu, VkPhysicalDevicePortabilitySubsetFeaturesKHR, mutableComparisonSamplers); + REQUEST_OPTIONAL_FEATURE(gpu, VkPhysicalDevicePortabilitySubsetFeaturesKHR, mutableComparisonSamplers); #endif } diff --git a/samples/performance/layout_transitions/layout_transitions.cpp b/samples/performance/layout_transitions/layout_transitions.cpp index a0b8e1280..e050cbf35 100644 --- a/samples/performance/layout_transitions/layout_transitions.cpp +++ b/samples/performance/layout_transitions/layout_transitions.cpp @@ -37,9 +37,9 @@ LayoutTransitions::LayoutTransitions() config.insert(0, reinterpret_cast(layout_transition_type), LayoutTransitionType::UNDEFINED); config.insert(1, reinterpret_cast(layout_transition_type), LayoutTransitionType::LAST_LAYOUT); -#if defined(PLATFORM__MACOS) && TARGET_OS_IOS && TARGET_OS_SIMULATOR && defined(VKB_ENABLE_PORTABILITY) +#if defined(PLATFORM__MACOS) && TARGET_OS_IOS && TARGET_OS_SIMULATOR // On iOS Simulator use layer setting to disable MoltenVK's Metal argument buffers - otherwise blank display - add_instance_extension(VK_EXT_LAYER_SETTINGS_EXTENSION_NAME, /*optional*/ true); + add_instance_extension(VK_EXT_LAYER_SETTINGS_EXTENSION_NAME, /*optional=*/true); VkLayerSettingEXT layerSetting; layerSetting.pLayerName = "MoltenVK"; diff --git a/samples/performance/multithreading_render_passes/multithreading_render_passes.cpp b/samples/performance/multithreading_render_passes/multithreading_render_passes.cpp index ce7704b6f..e8d85f9bf 100644 --- a/samples/performance/multithreading_render_passes/multithreading_render_passes.cpp +++ b/samples/performance/multithreading_render_passes/multithreading_render_passes.cpp @@ -43,7 +43,7 @@ void MultithreadingRenderPasses::request_gpu_features(vkb::core::PhysicalDeviceC { #ifdef VKB_ENABLE_PORTABILITY // Since shadowmap_sampler_create_info.compareEnable = VK_TRUE, must enable the mutableComparisonSamplers feature of VK_KHR_portability_subset - REQUEST_REQUIRED_FEATURE(gpu, VkPhysicalDevicePortabilitySubsetFeaturesKHR, mutableComparisonSamplers); + REQUEST_OPTIONAL_FEATURE(gpu, VkPhysicalDevicePortabilitySubsetFeaturesKHR, mutableComparisonSamplers); #endif } diff --git a/samples/performance/pipeline_barriers/pipeline_barriers.cpp b/samples/performance/pipeline_barriers/pipeline_barriers.cpp index 5cbb3d1ad..717cd36ce 100644 --- a/samples/performance/pipeline_barriers/pipeline_barriers.cpp +++ b/samples/performance/pipeline_barriers/pipeline_barriers.cpp @@ -39,9 +39,9 @@ PipelineBarriers::PipelineBarriers() config.insert(1, reinterpret_cast(dependency_type), DependencyType::FRAG_TO_VERT); config.insert(2, reinterpret_cast(dependency_type), DependencyType::FRAG_TO_FRAG); -#if defined(PLATFORM__MACOS) && TARGET_OS_IOS && TARGET_OS_SIMULATOR && defined(VKB_ENABLE_PORTABILITY) +#if defined(PLATFORM__MACOS) && TARGET_OS_IOS && TARGET_OS_SIMULATOR // On iOS Simulator use layer setting to disable MoltenVK's Metal argument buffers - otherwise blank display - add_instance_extension(VK_EXT_LAYER_SETTINGS_EXTENSION_NAME, /*optional*/ true); + add_instance_extension(VK_EXT_LAYER_SETTINGS_EXTENSION_NAME, /*optional=*/true); VkLayerSettingEXT layerSetting; layerSetting.pLayerName = "MoltenVK"; diff --git a/samples/performance/subpasses/subpasses.cpp b/samples/performance/subpasses/subpasses.cpp index 7d59e2b73..2872f0069 100644 --- a/samples/performance/subpasses/subpasses.cpp +++ b/samples/performance/subpasses/subpasses.cpp @@ -51,9 +51,9 @@ Subpasses::Subpasses() config.insert(3, configs[Config::TransientAttachments].value, 0); config.insert(3, configs[Config::GBufferSize].value, 1); -#if defined(PLATFORM__MACOS) && TARGET_OS_IOS && TARGET_OS_SIMULATOR && defined(VKB_ENABLE_PORTABILITY) +#if defined(PLATFORM__MACOS) && TARGET_OS_IOS && TARGET_OS_SIMULATOR // On iOS Simulator use layer setting to disable MoltenVK's Metal argument buffers - otherwise blank display - add_instance_extension(VK_EXT_LAYER_SETTINGS_EXTENSION_NAME, /*optional*/ true); + add_instance_extension(VK_EXT_LAYER_SETTINGS_EXTENSION_NAME, /*optional=*/true); VkLayerSettingEXT layerSetting; layerSetting.pLayerName = "MoltenVK"; diff --git a/samples/tooling/profiles/profiles.cpp b/samples/tooling/profiles/profiles.cpp index 8f3eb927a..35e4601f7 100644 --- a/samples/tooling/profiles/profiles.cpp +++ b/samples/tooling/profiles/profiles.cpp @@ -98,14 +98,8 @@ std::unique_ptr Profiles::create_device(vkb::core::PhysicalD enabled_extensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME); #if (defined(VKB_ENABLE_PORTABILITY)) - uint32_t device_extension_count; - VK_CHECK(vkEnumerateDeviceExtensionProperties(gpu.get_handle(), nullptr, &device_extension_count, nullptr)); - std::vector available_device_extensions(device_extension_count); - VK_CHECK(vkEnumerateDeviceExtensionProperties(gpu.get_handle(), nullptr, &device_extension_count, available_device_extensions.data())); - - // VK_KHR_portability_subset must be enabled if present in the implementation (e.g on macOS/iOS with beta extensions enabled) - if (std::ranges::any_of(available_device_extensions, - [](VkExtensionProperties const &extension) { return strcmp(extension.extensionName, VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME) == 0; })) + // VK_KHR_portability_subset must be enabled if present in the implementation (e.g on macOS/iOS using MoltenVK with beta extensions enabled) + if (gpu.is_extension_supported(VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME)) { enabled_extensions.push_back(VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME); } @@ -172,12 +166,15 @@ std::unique_ptr Profiles::create_instance() VkInstanceCreateInfo create_info{}; #if (defined(VKB_ENABLE_PORTABILITY)) + enabled_extensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); + + // Enumerate all instance extensions for the loader + driver to determine if VK_KHR_portability_enumeration is available uint32_t instance_extension_count; VK_CHECK(vkEnumerateInstanceExtensionProperties(nullptr, &instance_extension_count, nullptr)); std::vector available_instance_extensions(instance_extension_count); VK_CHECK(vkEnumerateInstanceExtensionProperties(nullptr, &instance_extension_count, available_instance_extensions.data())); - // If VK_KHR_portability_enumeration is available at runtime, enable the extension and flag for instance creation + // If VK_KHR_portability_enumeration is available in the implementation, then we must enable the extension if (std::ranges::any_of(available_instance_extensions, [](VkExtensionProperties const &extension) { return strcmp(extension.extensionName, VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME) == 0; })) { From ff23d709a7a891b74468b1d4994cdc17c08c621d Mon Sep 17 00:00:00 2001 From: SRSaunders <82544213+SRSaunders@users.noreply.github.com> Date: Thu, 6 Nov 2025 12:42:18 -0500 Subject: [PATCH 10/10] Revert VKB_ENABLE_PORTABILITY check in global_options.cmake and add comments for driver optionality --- bldsys/cmake/global_options.cmake | 90 ++++++++++++++++--------------- 1 file changed, 47 insertions(+), 43 deletions(-) diff --git a/bldsys/cmake/global_options.cmake b/bldsys/cmake/global_options.cmake index 50122695c..a47ffbada 100644 --- a/bldsys/cmake/global_options.cmake +++ b/bldsys/cmake/global_options.cmake @@ -33,53 +33,57 @@ endif() if(APPLE) cmake_minimum_required(VERSION 3.24) - option(VKB_ENABLE_PORTABILITY "Enable portability enumeration and subset features in the framework. This is required for MoltenVK on Apple platforms." ON) - - if(VKB_ENABLE_PORTABILITY) - find_package(Vulkan QUIET OPTIONAL_COMPONENTS MoltenVK) - if(USE_MoltenVK OR (IOS AND (NOT Vulkan_MoltenVK_FOUND OR ${CMAKE_OSX_SYSROOT} STREQUAL "iphonesimulator"))) - # if using MoltenVK standalone, or MoltenVK for iOS not found or using iOS Simulator, look for MoltenVK in Vulkan SDK and MoltenVK project paths - if(NOT Vulkan_MoltenVK_LIBRARY) - # since both are available in the Vulkan SDK and MoltenVK github project, make sure we look for MoltenVK framework on iOS and dylib on macOS - set(_saved_cmake_find_framework ${CMAKE_FIND_FRAMEWORK}) - if(IOS) - set(CMAKE_FIND_FRAMEWORK ALWAYS) - else() - set(CMAKE_FIND_FRAMEWORK NEVER) - endif() - find_library(Vulkan_MoltenVK_LIBRARY NAMES MoltenVK HINTS "$ENV{VULKAN_SDK}/lib" "$ENV{VULKAN_SDK}/dynamic" "$ENV{VULKAN_SDK}/dylib/macOS") - set(CMAKE_FIND_FRAMEWORK ${_saved_cmake_find_framework}) - unset(_saved_cmake_find_framework) + option(VKB_ENABLE_PORTABILITY "Enable portability enumeration and subset features in the framework. This is default ON for Apple platforms." ON) + + # the following assumes MoltenVK is used for these cases: a) standalone deployment on macOS (i.e. set USE_MoltenVK=ON), and b) for iOS deployment + # if this assumption changes (e.g. KosmicKrisp adds standalone or iOS support), then this section will require modification to handle optionality + find_package(Vulkan QUIET OPTIONAL_COMPONENTS MoltenVK) + if(USE_MoltenVK OR (IOS AND (NOT Vulkan_MoltenVK_FOUND OR ${CMAKE_OSX_SYSROOT} STREQUAL "iphonesimulator"))) + # if using MoltenVK standalone, or MoltenVK for iOS not found or using iOS Simulator, look for MoltenVK in Vulkan SDK and MoltenVK project paths + if(NOT Vulkan_MoltenVK_LIBRARY) + # since both are available in the Vulkan SDK and MoltenVK github project, make sure we look for MoltenVK framework on iOS and dylib on macOS + set(_saved_cmake_find_framework ${CMAKE_FIND_FRAMEWORK}) + if(IOS) + set(CMAKE_FIND_FRAMEWORK ALWAYS) + else() + set(CMAKE_FIND_FRAMEWORK NEVER) endif() + find_library(Vulkan_MoltenVK_LIBRARY NAMES MoltenVK HINTS "$ENV{VULKAN_SDK}/lib" "$ENV{VULKAN_SDK}/dynamic" "$ENV{VULKAN_SDK}/dylib/macOS") + set(CMAKE_FIND_FRAMEWORK ${_saved_cmake_find_framework}) + unset(_saved_cmake_find_framework) + endif() - if(Vulkan_MoltenVK_LIBRARY) - get_filename_component(MoltenVK_LIBRARY_PATH ${Vulkan_MoltenVK_LIBRARY} DIRECTORY) - - # For both iOS and macOS: set up global Vulkan Library defines so that MoltenVK is dynamically loaded versus the Vulkan loader - # on iOS we can control Vulkan library loading priority by selecting which libraries are embedded in the iOS application bundle - if(IOS) - add_compile_definitions(_HPP_VULKAN_LIBRARY="MoltenVK.framework/MoltenVK") - # unset FindVulkan.cmake cache variables so Vulkan loader, Validation Layer, and icd/layer json files are not embedded on iOS - unset(Vulkan_LIBRARY CACHE) - unset(Vulkan_Layer_VALIDATION CACHE) - - # on macOS make sure that MoltenVK_LIBRARY_PATH points to the MoltenVK project installation and not to the Vulkan_LIBRARY location - # otherwise if DYLD_LIBRARY_PATH points to a common search path, Volk may dynamically load libvulkan.dylib versus libMoltenVK.dylib - elseif(NOT Vulkan_LIBRARY MATCHES "${MoltenVK_LIBRARY_PATH}") - add_compile_definitions(_HPP_VULKAN_LIBRARY="libMoltenVK.dylib") - add_compile_definitions(_GLFW_VULKAN_LIBRARY="libMoltenVK.dylib") - set(ENV{DYLD_LIBRARY_PATH} "${MoltenVK_LIBRARY_PATH}:$ENV{DYLD_LIBRARY_PATH}") - else() - message(FATAL_ERROR "Vulkan library found in MoltenVK search path. Please set VULKAN_SDK to the MoltenVK project install location.") - endif() - message(STATUS "Using MoltenVK standalone: ${Vulkan_MoltenVK_LIBRARY}") + if(Vulkan_MoltenVK_LIBRARY) + get_filename_component(MoltenVK_LIBRARY_PATH ${Vulkan_MoltenVK_LIBRARY} DIRECTORY) + + # For both iOS and macOS: set up global Vulkan Library defines so that MoltenVK is dynamically loaded versus the Vulkan loader + # on iOS we can control Vulkan library loading priority by selecting which libraries are embedded in the iOS application bundle + if(IOS) + add_compile_definitions(_HPP_VULKAN_LIBRARY="MoltenVK.framework/MoltenVK") + # unset FindVulkan.cmake cache variables so Vulkan loader and Validation Layer libraries are not embedded on iOS Simulator + # the iOS Simulator supports arm64 & x86_64 hosts, but the Vulkan loader and Validation Layer are compiled for arm64 only + unset(Vulkan_LIBRARY CACHE) + unset(Vulkan_Layer_VALIDATION CACHE) + + # on macOS make sure that MoltenVK_LIBRARY_PATH points to the MoltenVK project installation and not to the Vulkan_LIBRARY location + # otherwise if DYLD_LIBRARY_PATH points to a common search path, Volk may dynamically load libvulkan.dylib versus libMoltenVK.dylib + elseif(NOT Vulkan_LIBRARY MATCHES "${MoltenVK_LIBRARY_PATH}") + add_compile_definitions(_HPP_VULKAN_LIBRARY="libMoltenVK.dylib") + add_compile_definitions(_GLFW_VULKAN_LIBRARY="libMoltenVK.dylib") + set(ENV{DYLD_LIBRARY_PATH} "${MoltenVK_LIBRARY_PATH}:$ENV{DYLD_LIBRARY_PATH}") else() - message(FATAL_ERROR "Can't find MoltenVK library. Please install the Vulkan SDK or MoltenVK project and set VULKAN_SDK.") + message(FATAL_ERROR "Vulkan loader found in MoltenVK search path. Please set VULKAN_SDK to the MoltenVK project install location.") endif() - #else() - # if not using MoltenVK standalone, retain find_package() results for MoltenVK, Vulkan loader, and Validation Layer library defines - # no need to override with _HPP_VULKAN_LIBRARY in this case since Vulkan DynamicLoader will find/load Vulkan library on macOS & iOS + message(STATUS "Using MoltenVK standalone: ${Vulkan_MoltenVK_LIBRARY}") + else() + message(FATAL_ERROR "Can't find MoltenVK library. Please install the Vulkan SDK or MoltenVK project and set VULKAN_SDK.") endif() + #elseif(OTHER_VULKAN_DRIVER) + # handle any special processing here for other Vulkan driver (e.g. KosmicKrisp) for standalone usage on macOS or deployment to iOS + # would likely require extensions to CMake find_package() OPTIONAL_COMPONENTS and library variables to identify & use other driver + #else() + # if not using standalone driver, retain find_package() results for Vulkan driver, Vulkan loader, and Validation Layer library variables + # no need to override with _HPP_VULKAN_LIBRARY in this case since Vulkan DynamicLoader will find/load Vulkan library on macOS & iOS endif() if(CMAKE_GENERATOR MATCHES "Xcode") @@ -106,7 +110,7 @@ if(APPLE) endif() endif() else() - option(VKB_ENABLE_PORTABILITY "Enable portability enumeration and subset features in the framework. This is default off on non-Apple platforms." OFF) + option(VKB_ENABLE_PORTABILITY "Enable portability enumeration and subset features in the framework. This is default OFF for non-Apple platforms." OFF) endif() set(VKB_WARNINGS_AS_ERRORS ON CACHE BOOL "Enable Warnings as Errors")