diff --git a/.gitignore b/.gitignore index 4fa0b48cb..6b3486857 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ tests/system_test/tmp output/* .mypy_cache tags +.DS_Store # vim backup and temp files *~ diff --git a/CMakeLists.txt b/CMakeLists.txt index a1579cb59..9ab97d554 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,11 +34,13 @@ endif() cmake_minimum_required(VERSION 3.16) +project(vulkan_samples) + # search for Vulkan SDK find_package(Vulkan) -if(VULKAN_FOUND) - if(NOT Vulkan_dxc_EXECUTABLE) +if(Vulkan_FOUND) + if(NOT Vulkan_dxc_exe_FOUND) find_program(Vulkan_dxc_EXECUTABLE NAMES dxc HINTS @@ -46,20 +48,16 @@ if(VULKAN_FOUND) "$ENV{VULKAN_SDK}/bin" ) endif() - if(DEFINED Vulkan_dxc_EXECUTABLE) - message("Found DirectX Shader Compiler under ${Vulkan_dxc_EXECUTABLE}") - elseif() - message("Couldn't find DirectX Shader Compiler executable, make sure it is present in Vulkan SDK or add it manually via Vulkan_dxc_EXECUTABLE env variable") + if(Vulkan_dxc_EXECUTABLE) + message(STATUS "Found DirectX Shader Compiler under ${Vulkan_dxc_EXECUTABLE}") + else() + message(STATUS "Couldn't find DirectX Shader Compiler executable, make sure it is present in Vulkan SDK or add it manually via Vulkan_dxc_EXECUTABLE cmake variable. HLSL shaders won't be compiled.") endif() -else() - message("VULKAN_SDK path not found, HLSL shaders won't be compiled") endif() # globally add VKB_DEBUG for the debug build add_compile_definitions($<$:VKB_DEBUG>) -project(vulkan_samples) - if(MSVC AND (DEFINED CMAKE_C_COMPILER_LAUNCHER)) message(DEBUG "Setting MSVC flags to /Z7 for ccache compatibility. Current flags: ${CMAKE_CXX_FLAGS_DEBUG}") string(REPLACE "/Zi" "/Z7" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}") diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 3786757a4..0d7471690 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -37,17 +37,15 @@ if(ANDROID) endif() add_library(${PROJECT_NAME} SHARED ${SRC}) -elseif (APPLE) - if(IOS) - list(REMOVE_AT SRC 0) - list(APPEND SRC - ${CMAKE_CURRENT_SOURCE_DIR}/ios/main.mm - ${CMAKE_CURRENT_SOURCE_DIR}/ios/AppDelegate.h - ${CMAKE_CURRENT_SOURCE_DIR}/ios/AppDelegate.m - ${CMAKE_CURRENT_SOURCE_DIR}/ios/ViewController.h - ${CMAKE_CURRENT_SOURCE_DIR}/ios/ViewController.mm - ) - endif () +elseif(IOS) + list(REMOVE_AT SRC 0) + list(APPEND SRC + ${CMAKE_CURRENT_SOURCE_DIR}/ios/main.mm + ${CMAKE_CURRENT_SOURCE_DIR}/ios/AppDelegate.h + ${CMAKE_CURRENT_SOURCE_DIR}/ios/AppDelegate.m + ${CMAKE_CURRENT_SOURCE_DIR}/ios/ViewController.h + ${CMAKE_CURRENT_SOURCE_DIR}/ios/ViewController.mm + ) add_executable(${PROJECT_NAME} MACOSX_BUNDLE ${SRC}) else() add_executable(${PROJECT_NAME} WIN32 ${SRC}) diff --git a/bldsys/cmake/global_options.cmake b/bldsys/cmake/global_options.cmake index 9eac0ae5e..6e206f62a 100644 --- a/bldsys/cmake/global_options.cmake +++ b/bldsys/cmake/global_options.cmake @@ -33,15 +33,10 @@ 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) if(IOS) set(CMAKE_XCODE_GENERATE_SCHEME TRUE) -endif () - find_package(Vulkan) - if(Vulkan_VERSION GREATER_EQUAL 1.3) - set(VKB_ENABLE_PORTABILITY ON CACHE BOOL "Enable portability extension enumeration in the framework. This is required to be set if running MoltenVK and Vulkan 1.3+" FORCE) - else() - set(VKB_ENABLE_PORTABILITY OFF CACHE BOOL "Enable portability extension enumeration in the framework. This is required to be off if running Vulkan less than 1.3" FORCE) - endif() +endif() endif() set(VKB_WARNINGS_AS_ERRORS ON CACHE BOOL "Enable Warnings as Errors") diff --git a/bldsys/cmake/sample_helper.cmake b/bldsys/cmake/sample_helper.cmake index 1a7239a64..065e27aaa 100644 --- a/bldsys/cmake/sample_helper.cmake +++ b/bldsys/cmake/sample_helper.cmake @@ -197,7 +197,7 @@ endif() set_target_properties(${PROJECT_NAME} PROPERTIES CXX_CLANG_TIDY "${VKB_DO_CLANG_TIDY}") endif() - if(DEFINED Vulkan_dxc_EXECUTABLE AND DEFINED SHADERS_HLSL) + if(Vulkan_dxc_EXECUTABLE AND DEFINED SHADERS_HLSL) compile_hlsl_shaders( SHADERS_HLSL ${TARGET_SHADERS_HLSL} DXC_ADDITIONAL_ARGUMENTS ${TARGET_DXC_ADDITIONAL_ARGUMENTS} diff --git a/docs/build.adoc b/docs/build.adoc index 062bd5168..f56fd259f 100644 --- a/docs/build.adoc +++ b/docs/build.adoc @@ -260,7 +260,7 @@ cmake --build build/mac --config Release --target vulkan_samples -j4 `Step 3.` Run the *Vulkan Samples* application to display the help message ---- -./build/mac/app/bin/Release/x86_64/vulkan_samples --help +./build/mac/app/bin/Release//vulkan_samples --help ---- == iOS diff --git a/framework/CMakeLists.txt b/framework/CMakeLists.txt index 4fc85a065..d7b359cdc 100644 --- a/framework/CMakeLists.txt +++ b/framework/CMakeLists.txt @@ -499,7 +499,7 @@ if(${VKB_VULKAN_DEBUG}) endif() if(${VKB_ENABLE_PORTABILITY}) - message(STATUS "Vulkan Portability extension is enabled") + message(STATUS "Vulkan Portability Enumeration and Portability Subset extensions are enabled") target_compile_definitions(${PROJECT_NAME} PUBLIC VKB_ENABLE_PORTABILITY) endif() diff --git a/framework/common/error.h b/framework/common/error.h index b1549bba3..fdb6f5918 100644 --- a/framework/common/error.h +++ b/framework/common/error.h @@ -81,15 +81,14 @@ class VulkanException : public std::runtime_error } // namespace vkb /// @brief Helper macro to test the result of Vulkan calls which can return an error. -#define VK_CHECK(x) \ - do \ - { \ - VkResult err = x; \ - if (err) \ - { \ - LOGE("Detected Vulkan error: {}", vkb::to_string(err)); \ - abort(); \ - } \ +#define VK_CHECK(x) \ + do \ + { \ + VkResult err = x; \ + if (err) \ + { \ + throw std::runtime_error("Detected Vulkan error: " + vkb::to_string(err)); \ + } \ } while (0) #define ASSERT_VK_HANDLE(handle) \ diff --git a/framework/common/strings.cpp b/framework/common/strings.cpp index fb6aca69f..f7a0d45f6 100644 --- a/framework/common/strings.cpp +++ b/framework/common/strings.cpp @@ -686,6 +686,13 @@ const std::string to_string(VkResult result) STR(ERROR_INCOMPATIBLE_DRIVER); STR(ERROR_TOO_MANY_OBJECTS); STR(ERROR_FORMAT_NOT_SUPPORTED); + STR(ERROR_FRAGMENTED_POOL); + STR(ERROR_UNKNOWN); + STR(ERROR_OUT_OF_POOL_MEMORY); + STR(ERROR_INVALID_EXTERNAL_HANDLE); + STR(ERROR_FRAGMENTATION); + STR(ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS); + STR(PIPELINE_COMPILE_REQUIRED); STR(ERROR_SURFACE_LOST_KHR); STR(ERROR_NATIVE_WINDOW_IN_USE_KHR); STR(SUBOPTIMAL_KHR); diff --git a/framework/core/hpp_instance.cpp b/framework/core/hpp_instance.cpp index 3cb77b661..27d381b4b 100644 --- a/framework/core/hpp_instance.cpp +++ b/framework/core/hpp_instance.cpp @@ -186,6 +186,7 @@ bool enable_all_extensions(const std::vector required_ HPPInstance::HPPInstance(const std::string &application_name, const std::unordered_map &required_extensions, const std::vector &required_validation_layers, + const std::vector &required_layer_settings, bool headless, uint32_t api_version) { @@ -211,7 +212,7 @@ HPPInstance::HPPInstance(const std::string &applicati #if (defined(VKB_ENABLE_PORTABILITY)) enable_extension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, available_instance_extensions, enabled_extensions); - enable_extension(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME, available_instance_extensions, enabled_extensions); + bool portability_enumeration_available = enable_extension(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME, available_instance_extensions, enabled_extensions); #endif #ifdef USE_VALIDATION_LAYER_FEATURES @@ -326,7 +327,10 @@ HPPInstance::HPPInstance(const std::string &applicati #endif #if (defined(VKB_ENABLE_PORTABILITY)) - instance_info.flags |= vk::InstanceCreateFlagBits::eEnumeratePortabilityKHR; + if (portability_enumeration_available) + { + instance_info.flags |= vk::InstanceCreateFlagBits::eEnumeratePortabilityKHR; + } #endif #ifdef USE_VALIDATION_LAYER_FEATURES @@ -347,6 +351,17 @@ HPPInstance::HPPInstance(const std::string &applicati } #endif + vk::LayerSettingsCreateInfoEXT layerSettingsCreateInfo; + + // If layer settings extension enabled by sample, then activate layer settings during instance creation + if (std::find(enabled_extensions.begin(), enabled_extensions.end(), VK_EXT_LAYER_SETTINGS_EXTENSION_NAME) != enabled_extensions.end()) + { + layerSettingsCreateInfo.settingCount = static_cast(required_layer_settings.size()); + layerSettingsCreateInfo.pSettings = required_layer_settings.data(); + layerSettingsCreateInfo.pNext = instance_info.pNext; + instance_info.pNext = &layerSettingsCreateInfo; + } + // Create the Vulkan instance handle = vk::createInstance(instance_info); diff --git a/framework/core/hpp_instance.h b/framework/core/hpp_instance.h index f247d8bb2..087b14da0 100644 --- a/framework/core/hpp_instance.h +++ b/framework/core/hpp_instance.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2022-2023, NVIDIA CORPORATION. All rights reserved. +/* Copyright (c) 2022-2024, NVIDIA CORPORATION. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 * @@ -53,6 +53,7 @@ class HPPInstance * @param application_name The name of the application * @param required_extensions The extensions requested to be enabled * @param required_validation_layers The validation layers to be enabled + * @param required_layer_settings The layer settings to be enabled * @param headless Whether the application is requesting a headless setup or not * @param api_version The Vulkan API version that the instance will be using * @throws runtime_error if the required extensions and validation layers are not found @@ -60,6 +61,7 @@ class HPPInstance HPPInstance(const std::string &application_name, const std::unordered_map &required_extensions = {}, const std::vector &required_validation_layers = {}, + const std::vector &required_layer_settings = {}, bool headless = false, uint32_t api_version = VK_API_VERSION_1_0); diff --git a/framework/core/instance.cpp b/framework/core/instance.cpp index ffaa6707d..5a28e8be6 100644 --- a/framework/core/instance.cpp +++ b/framework/core/instance.cpp @@ -186,6 +186,7 @@ bool enable_all_extensions(const std::vector required_ex Instance::Instance(const std::string &application_name, const std::unordered_map &required_extensions, const std::vector &required_validation_layers, + const std::vector &required_layer_settings, bool headless, uint32_t api_version) { @@ -215,7 +216,7 @@ Instance::Instance(const std::string &application_nam #if (defined(VKB_ENABLE_PORTABILITY)) enable_extension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, available_instance_extensions, enabled_extensions); - enable_extension(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME, available_instance_extensions, enabled_extensions); + bool portability_enumeration_available = enable_extension(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME, available_instance_extensions, enabled_extensions); #endif #ifdef USE_VALIDATION_LAYER_FEATURES @@ -350,7 +351,10 @@ Instance::Instance(const std::string &application_nam #endif #if (defined(VKB_ENABLE_PORTABILITY)) - instance_info.flags |= VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR; + if (portability_enumeration_available) + { + instance_info.flags |= VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR; + } #endif // Some of the specialized layers need to be enabled explicitly @@ -376,6 +380,17 @@ Instance::Instance(const std::string &application_nam } #endif + VkLayerSettingsCreateInfoEXT layerSettingsCreateInfo{VK_STRUCTURE_TYPE_LAYER_SETTINGS_CREATE_INFO_EXT}; + + // If layer settings extension enabled by sample, then activate layer settings during instance creation + if (std::find(enabled_extensions.begin(), enabled_extensions.end(), VK_EXT_LAYER_SETTINGS_EXTENSION_NAME) != enabled_extensions.end()) + { + layerSettingsCreateInfo.settingCount = static_cast(required_layer_settings.size()); + layerSettingsCreateInfo.pSettings = required_layer_settings.data(); + layerSettingsCreateInfo.pNext = instance_info.pNext; + instance_info.pNext = &layerSettingsCreateInfo; + } + // Create the Vulkan instance VkResult result = vkCreateInstance(&instance_info, nullptr, &handle); diff --git a/framework/core/instance.h b/framework/core/instance.h index eba3deb87..500b12479 100644 --- a/framework/core/instance.h +++ b/framework/core/instance.h @@ -50,6 +50,7 @@ class Instance * @param application_name The name of the application * @param required_extensions The extensions requested to be enabled * @param required_validation_layers The validation layers to be enabled + * @param required_layer_settings The layer settings to be enabled * @param headless Whether the application is requesting a headless setup or not * @param api_version The Vulkan API version that the instance will be using * @throws runtime_error if the required extensions and validation layers are not found @@ -57,6 +58,7 @@ class Instance Instance(const std::string &application_name, const std::unordered_map &required_extensions = {}, const std::vector &required_validation_layers = {}, + const std::vector &required_layer_settings = {}, bool headless = false, uint32_t api_version = VK_API_VERSION_1_0); diff --git a/framework/platform/platform.cpp b/framework/platform/platform.cpp index 9cfc96efa..0db87360a 100644 --- a/framework/platform/platform.cpp +++ b/framework/platform/platform.cpp @@ -31,6 +31,7 @@ #include "core/util/logging.hpp" #include "filesystem/legacy.h" #include "force_close/force_close.h" +#include "glsl_compiler.h" #include "platform/parsers/CLI11.h" #include "platform/plugins/plugin.h" #include "vulkan_sample.h" @@ -142,8 +143,7 @@ ExitCode Platform::main_loop_frame() { if (!start_app()) { - LOGE("Failed to load requested application"); - return ExitCode::FatalError; + throw std::runtime_error("Failed to load requested application"); } // Compensate for load times of the app by rendering the first frame pre-emptively @@ -169,17 +169,17 @@ ExitCode Platform::main_loop_frame() on_app_error(active_app->get_name()); - if (app_requested()) - { - LOGI("Attempting to load next application"); - } - else - { + if (app_requested()) + { + LOGI("Attempting to load next application"); + } + else + { set_last_error(e.what()); - return ExitCode::FatalError; - } - } - } + return ExitCode::FatalError; + } + } + } return ExitCode::Success; } @@ -200,8 +200,7 @@ ExitCode Platform::main_loop() { if (!start_app()) { - LOGE("Failed to load requested application"); - return ExitCode::FatalError; + throw std::runtime_error("Failed to load requested application"); } // Compensate for load times of the app by rendering the first frame pre-emptively @@ -233,7 +232,7 @@ ExitCode Platform::main_loop() } else { - set_last_error(e.what()); + set_last_error(e.what()); return ExitCode::FatalError; } } @@ -443,6 +442,9 @@ bool Platform::start_app() active_app->finish(); } + // Reset target environment to default prior to each sample to properly support batch mode + vkb::GLSLCompiler::reset_target_environment(); + active_app = requested_app_info->create(); if (!active_app) diff --git a/framework/rendering/hpp_render_context.cpp b/framework/rendering/hpp_render_context.cpp index 8b72c1216..b4d982528 100644 --- a/framework/rendering/hpp_render_context.cpp +++ b/framework/rendering/hpp_render_context.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2023, NVIDIA CORPORATION. All rights reserved. +/* Copyright (c) 2023-2024, NVIDIA CORPORATION. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 * @@ -310,7 +310,8 @@ void HPPRenderContext::begin_frame() } } - if (result != vk::Result::eSuccess) + // eSuboptimalKHR can legitimately occur in batch mode when exiting certain samples (e.g. afbc, msaa, surface_rotation, swapchain_images) + if (result != vk::Result::eSuccess && result != vk::Result::eSuboptimalKHR) { prev_frame.reset(); return; diff --git a/framework/rendering/render_context.cpp b/framework/rendering/render_context.cpp index ebf2b8e42..4ce45fc1c 100644 --- a/framework/rendering/render_context.cpp +++ b/framework/rendering/render_context.cpp @@ -335,7 +335,8 @@ void RenderContext::begin_frame() } } - if (result != VK_SUCCESS) + // VK_SUBOPTIMAL_KHR can legitimately occur in batch mode when exiting certain samples (e.g. afbc, msaa, surface_rotation, swapchain_images) + if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) { prev_frame.reset(); return; @@ -375,7 +376,7 @@ VkSemaphore RenderContext::submit(const Queue &queue, const std::vector +# include #endif namespace vkb @@ -145,6 +145,7 @@ class VulkanSample : public vkb::Application using RenderTargetType = typename std::conditional::type; using StatsType = typename std::conditional::type; using Extent2DType = typename std::conditional::type; + using LayerSettingType = typename std::conditional::type; using SurfaceFormatType = typename std::conditional::type; using SurfaceType = typename std::conditional::type; @@ -250,6 +251,12 @@ class VulkanSample : public vkb::Application */ void add_instance_extension(const char *extension, bool optional = false); + /** + * @brief Add a sample-specific layer setting + * @param layerSetting The layer setting + */ + void add_layer_setting(LayerSettingType const &layerSetting); + void create_gui(const Window &window, StatsType const *stats = nullptr, const float font_size = 21.0f, bool explicit_update = false); /** @@ -358,6 +365,13 @@ class VulkanSample : public vkb::Application */ std::unordered_map const &get_instance_extensions() const; + /** + * @brief Get sample-specific layer settings. + * + * @return Vector of layer settings. Default is empty vector. + */ + std::vector const &get_layer_settings() const; + /// /// PRIVATE MEMBERS /// @@ -416,6 +430,9 @@ class VulkanSample : public vkb::Application /** @brief Set of instance extensions to be enabled for this example and whether they are optional (must be set in the derived constructor) */ std::unordered_map instance_extensions; + /** @brief Vector of layer settings to be enabled for this example (must be set in the derived constructor) */ + std::vector layer_settings; + /** @brief The Vulkan API version to request for this sample at instance creation time */ uint32_t api_version = VK_API_VERSION_1_0; @@ -459,6 +476,19 @@ inline void VulkanSample::add_instance_extension(const char *extens instance_extensions[extension] = optional; } +template +inline void VulkanSample::add_layer_setting(LayerSettingType const &layerSetting) +{ + if constexpr (bindingType == BindingType::Cpp) + { + layer_settings.push_back(layerSetting); + } + else + { + layer_settings.push_back(reinterpret_cast(layerSetting)); + } +} + template inline std::unique_ptr::DeviceType> VulkanSample::create_device(PhysicalDeviceType &gpu) { @@ -478,7 +508,7 @@ inline std::unique_ptr::DeviceType> VulkanSam template inline std::unique_ptr::InstanceType> VulkanSample::create_instance(bool headless) { - return std::make_unique(get_name(), get_instance_extensions(), get_validation_layers(), headless, api_version); + return std::make_unique(get_name(), get_instance_extensions(), get_validation_layers(), get_layer_settings(), headless, api_version); } template @@ -764,6 +794,19 @@ inline std::unordered_map const &VulkanSample:: return instance_extensions; } +template +inline std::vector::LayerSettingType> const &VulkanSample::get_layer_settings() const +{ + if constexpr (bindingType == BindingType::Cpp) + { + return layer_settings; + } + else + { + return reinterpret_cast const &>(layer_settings); + } +} + template inline typename VulkanSample::RenderContextType const &VulkanSample::get_render_context() const { @@ -1044,6 +1087,11 @@ 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) + add_device_extension(VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME, /*optional=*/true); +#endif + #ifdef VKB_VULKAN_DEBUG if (!debug_utils) { diff --git a/samples/api/hello_triangle/hello_triangle.cpp b/samples/api/hello_triangle/hello_triangle.cpp index 646be38a6..33aec7d81 100644 --- a/samples/api/hello_triangle/hello_triangle.cpp +++ b/samples/api/hello_triangle/hello_triangle.cpp @@ -170,14 +170,14 @@ void HelloTriangle::init_instance(Context &context, uint32_t instance_extension_count; VK_CHECK(vkEnumerateInstanceExtensionProperties(nullptr, &instance_extension_count, nullptr)); - std::vector instance_extensions(instance_extension_count); - VK_CHECK(vkEnumerateInstanceExtensionProperties(nullptr, &instance_extension_count, instance_extensions.data())); + std::vector available_instance_extensions(instance_extension_count); + VK_CHECK(vkEnumerateInstanceExtensionProperties(nullptr, &instance_extension_count, available_instance_extensions.data())); std::vector active_instance_extensions(required_instance_extensions); #if defined(VKB_DEBUG) || defined(VKB_VALIDATION_LAYERS) bool has_debug_report = false; - for (const auto &ext : instance_extensions) + for (const auto &ext : available_instance_extensions) { if (strcmp(ext.extensionName, VK_EXT_DEBUG_REPORT_EXTENSION_NAME) == 0) { @@ -197,7 +197,14 @@ void HelloTriangle::init_instance(Context &context, #if (defined(VKB_ENABLE_PORTABILITY)) active_instance_extensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); - active_instance_extensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME); + bool portability_enumeration_available = false; + if (std::any_of(available_instance_extensions.begin(), + available_instance_extensions.end(), + [](VkExtensionProperties extension) { return strcmp(extension.extensionName, VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME) == 0; })) + { + active_instance_extensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME); + portability_enumeration_available = true; + } #endif #if defined(VK_USE_PLATFORM_ANDROID_KHR) @@ -218,7 +225,7 @@ void HelloTriangle::init_instance(Context &context, # pragma error Platform not supported #endif - if (!validate_extensions(active_instance_extensions, instance_extensions)) + if (!validate_extensions(active_instance_extensions, available_instance_extensions)) { throw std::runtime_error("Required instance extensions are missing."); } @@ -274,7 +281,10 @@ void HelloTriangle::init_instance(Context &context, #endif #if (defined(VKB_ENABLE_PORTABILITY)) - instance_info.flags |= VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR; + if (portability_enumeration_available) + { + instance_info.flags |= VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR; + } #endif // Create the Vulkan instance diff --git a/samples/api/hpp_hello_triangle/hpp_hello_triangle.cpp b/samples/api/hpp_hello_triangle/hpp_hello_triangle.cpp index e9f0534c6..5ef3b4cff 100644 --- a/samples/api/hpp_hello_triangle/hpp_hello_triangle.cpp +++ b/samples/api/hpp_hello_triangle/hpp_hello_triangle.cpp @@ -435,7 +435,14 @@ vk::Instance HPPHelloTriangle::create_instance(std::vector const & #if (defined(VKB_ENABLE_PORTABILITY)) active_instance_extensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); - active_instance_extensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME); + bool portability_enumeration_available = false; + if (std::any_of(available_instance_extensions.begin(), + available_instance_extensions.end(), + [](vk::ExtensionProperties extension) { return strcmp(extension.extensionName, VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME) == 0; })) + { + active_instance_extensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME); + portability_enumeration_available = true; + } #endif #if defined(VK_USE_PLATFORM_ANDROID_KHR) @@ -499,7 +506,10 @@ vk::Instance HPPHelloTriangle::create_instance(std::vector const & #endif #if (defined(VKB_ENABLE_PORTABILITY)) - instance_info.flags |= vk::InstanceCreateFlagBits::eEnumeratePortabilityKHR; + if (portability_enumeration_available) + { + instance_info.flags |= vk::InstanceCreateFlagBits::eEnumeratePortabilityKHR; + } #endif // Create the Vulkan instance diff --git a/samples/api/texture_mipmap_generation/texture_mipmap_generation.h b/samples/api/texture_mipmap_generation/texture_mipmap_generation.h index a7d7a6b56..8fc6966dc 100644 --- a/samples/api/texture_mipmap_generation/texture_mipmap_generation.h +++ b/samples/api/texture_mipmap_generation/texture_mipmap_generation.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2019-2023, Sascha Willems +/* Copyright (c) 2019-2024, Sascha Willems * * SPDX-License-Identifier: Apache-2.0 * @@ -63,10 +63,10 @@ class TextureMipMapGeneration : public ApiVulkanSample } ubo; std::unique_ptr uniform_buffer; - VkPipeline pipeline; - VkPipelineLayout pipeline_layout; - VkDescriptorSet descriptor_set; - VkDescriptorSetLayout descriptor_set_layout; + VkPipeline pipeline = VK_NULL_HANDLE; + VkPipelineLayout pipeline_layout = VK_NULL_HANDLE; + VkDescriptorSet descriptor_set = VK_NULL_HANDLE; + VkDescriptorSetLayout descriptor_set_layout = VK_NULL_HANDLE; TextureMipMapGeneration(); ~TextureMipMapGeneration(); diff --git a/samples/extensions/descriptor_indexing/descriptor_indexing.cpp b/samples/extensions/descriptor_indexing/descriptor_indexing.cpp index 8056e329a..eb4add9e6 100644 --- a/samples/extensions/descriptor_indexing/descriptor_indexing.cpp +++ b/samples/extensions/descriptor_indexing/descriptor_indexing.cpp @@ -31,6 +31,27 @@ 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) && TARGET_OS_OSX + // On macOS use layer setting to configure MoltenVK for using Metal argument buffers (needed for descriptor indexing) + 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); + + // On macOS also set environment variable as fallback in case layer settings not available at runtime with older SDKs + // Will not work in batch mode, but is the best we can do short of using the deprecated MoltenVK private config API + setenv("MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS", "1", 1); +#endif } DescriptorIndexing::~DescriptorIndexing() @@ -193,9 +214,17 @@ void DescriptorIndexing::create_immutable_sampler_descriptor_set() void DescriptorIndexing::create_bindless_descriptors() { - VkDescriptorSetLayoutBinding binding = vkb::initializers::descriptor_set_layout_binding(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, VK_SHADER_STAGE_FRAGMENT_BIT, 0, - descriptor_indexing_properties.maxDescriptorSetUpdateAfterBindSampledImages); + 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); // We're going to use update-after-bind, so we need to make sure the flag is set correctly in the set layout. @@ -235,7 +264,17 @@ void DescriptorIndexing::create_bindless_descriptors() // We're going to allocate two separate descriptor sets from the same pool, and here VARIABLE_DESCRIPTOR_COUNT comes in handy! // 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. - VkDescriptorPoolSize pool_size = vkb::initializers::descriptor_pool_size(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, NumDescriptorsStreaming + NumDescriptorsNonUniform); + 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); // The pool is marked update-after-bind. Be aware that there is a global limit to the number of descriptors can be allocated at any one time. diff --git a/samples/extensions/fragment_shader_barycentric/fragment_shader_barycentric.cpp b/samples/extensions/fragment_shader_barycentric/fragment_shader_barycentric.cpp index d28fcdd07..62698cee1 100644 --- a/samples/extensions/fragment_shader_barycentric/fragment_shader_barycentric.cpp +++ b/samples/extensions/fragment_shader_barycentric/fragment_shader_barycentric.cpp @@ -272,7 +272,7 @@ void FragmentShaderBarycentric::create_pipeline() graphics_create.layout = pipeline_layout; // Skybox pipeline (background cube) - vkCreateGraphicsPipelines(get_device().get_handle(), pipeline_cache, 1, &graphics_create, VK_NULL_HANDLE, &pipelines.skybox); + VK_CHECK(vkCreateGraphicsPipelines(get_device().get_handle(), pipeline_cache, 1, &graphics_create, VK_NULL_HANDLE, &pipelines.skybox)); // Object pipeline shader_stages[0] = load_shader("fragment_shader_barycentric/object.vert", VK_SHADER_STAGE_VERTEX_BIT); @@ -280,7 +280,7 @@ void FragmentShaderBarycentric::create_pipeline() // Flip cull mode rasterization_state.cullMode = VK_CULL_MODE_FRONT_BIT; - vkCreateGraphicsPipelines(get_device().get_handle(), pipeline_cache, 1, &graphics_create, VK_NULL_HANDLE, &pipelines.object); + VK_CHECK(vkCreateGraphicsPipelines(get_device().get_handle(), pipeline_cache, 1, &graphics_create, VK_NULL_HANDLE, &pipelines.object)); } /** diff --git a/samples/extensions/portability/portability.cpp b/samples/extensions/portability/portability.cpp index ced008332..e227d7b14 100644 --- a/samples/extensions/portability/portability.cpp +++ b/samples/extensions/portability/portability.cpp @@ -36,7 +36,7 @@ Portability::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); + add_instance_extension(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME, /*optional*/ true); } Portability::~Portability() @@ -832,7 +832,7 @@ bool Portability::prepare(const vkb::ApplicationOptions &options) // Note: Using reversed depth-buffer for increased precision, so Znear and Zfar are flipped camera.set_perspective(60.0f, static_cast(width) / static_cast(height), 256.0f, 0.1f); -#ifdef VK_ENABLE_BETA_EXTENSIONS +#ifdef VKB_ENABLE_PORTABILITY portability_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_FEATURES_KHR; VkPhysicalDeviceFeatures2 device_features{}; device_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; @@ -867,7 +867,7 @@ void Portability::render(float delta_time) void Portability::on_update_ui_overlay(vkb::Drawer &drawer) { -#ifdef VK_ENABLE_BETA_EXTENSIONS +#ifdef VKB_ENABLE_PORTABILITY std::string portability_support_list; if (portability_features.constantAlphaColorBlendFactors) portability_support_list += "constantAlphaColorBlendFactors\n"; @@ -901,7 +901,7 @@ void Portability::on_update_ui_overlay(vkb::Drawer &drawer) portability_support_list += "vertexAttributeAccessBeyondStride\n"; drawer.text("Device Portability feature support list:\n%s", portability_support_list.c_str()); #else - drawer.text("VK_ENABLE_BETA_EXTENSIONS not enabled can't list portability feature set"); + drawer.text("VKB_ENABLE_PORTABILITY not enabled can't list portability feature set"); #endif if (drawer.header("Settings")) { diff --git a/samples/extensions/portability/portability.h b/samples/extensions/portability/portability.h index dc4ef14fc..2e889d256 100644 --- a/samples/extensions/portability/portability.h +++ b/samples/extensions/portability/portability.h @@ -28,7 +28,7 @@ class Portability : public ApiVulkanSample public: bool bloom = true; bool display_skysphere = true; -#ifdef VK_ENABLE_BETA_EXTENSIONS +#ifdef VKB_ENABLE_PORTABILITY VkPhysicalDevicePortabilitySubsetFeaturesKHR portability_features{}; #endif diff --git a/samples/extensions/shader_debugprintf/README.adoc b/samples/extensions/shader_debugprintf/README.adoc index 01e429352..424f8e6b8 100644 --- a/samples/extensions/shader_debugprintf/README.adoc +++ b/samples/extensions/shader_debugprintf/README.adoc @@ -84,6 +84,47 @@ This then needs to be chained into the instance creation: instance_create_info.pNext = &validation_features; ---- +*UPDATE:* This sample now leverages an alternative mechanism provided by the Vulkan Samples framework to simplify enablement of the `VK_LAYER_KHRONOS_validation` layer and the `VK_VALIDATION_FEATURE_ENABLE_DEBUG_PRINTF_EXT` feature: + +[,cpp] +---- +const std::vector ShaderDebugPrintf::get_validation_layers() +{ + // Initialize validation layer override list to default (empty) + std::vector validation_layers = ApiVulkanSample::get_validation_layers(); + + // Force activation of validation layer for access to debugPrintfEXT feature + validation_layers.push_back("VK_LAYER_KHRONOS_validation"); + + return validation_layers; +} +---- + +The `VK_VALIDATION_FEATURE_ENABLE_DEBUG_PRINTF_EXT` feature is enabled by the new `VK_EXT_layer_settings` extension which is supported by the Vulkan Samples framework and used during instance creation. If the layer settings extension is available at runtime, the Vulkan Samples framework will enable the requested `debugPrintfEXT` feature using the `VkLayerSettingEXT` structure shown below. If `VK_EXT_layer_settings` is not available at runtime, the sample falls back to the custom `create_instance()` logic described above. + +[,cpp] +---- +ShaderDebugPrintf::ShaderDebugPrintf() +{ + ... + + // If layer settings available, use it to configure validation layer for debugPrintfEXT + add_instance_extension(VK_EXT_LAYER_SETTINGS_EXTENSION_NAME, /*optional*/ true); + + VkLayerSettingEXT layerSetting; + layerSetting.pLayerName = "VK_LAYER_KHRONOS_validation"; + layerSetting.pSettingName = "enables"; + layerSetting.type = VK_LAYER_SETTING_TYPE_STRING_EXT; + layerSetting.valueCount = 1; + + // Make this static so layer setting reference remains valid after leaving constructor scope + static const char *layerEnables = "VK_VALIDATION_FEATURE_ENABLE_DEBUG_PRINTF_EXT"; + layerSetting.pValues = &layerEnables; + + add_layer_setting(layerSetting); +} +---- + == Displaying debug printf output in your application If all you want to do is read the shader printf messages in a debugger like RenderDoc there's no additional work involved. Simply run your application with above instance setup and a printf in your shader and you can read those messages. Or use VkConfig from the LunarG SDK to redirect the messages to a specific output. diff --git a/samples/extensions/shader_debugprintf/shader_debugprintf.cpp b/samples/extensions/shader_debugprintf/shader_debugprintf.cpp index b345dbe45..6b83be395 100644 --- a/samples/extensions/shader_debugprintf/shader_debugprintf.cpp +++ b/samples/extensions/shader_debugprintf/shader_debugprintf.cpp @@ -27,7 +27,8 @@ VKAPI_ATTR VkBool32 VKAPI_CALL ShaderDebugPrintf::debug_utils_message_callback( const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData, void *pUserData) { - if (strcmp(pCallbackData->pMessageIdName, "WARNING-DEBUG-PRINTF") == 0) + // Look for Validation Layer message id names: WARNING-DEBUG-PRINTF or UNASSIGNED-DEBUG-PRINTF (have observed UNASSIGNED with older Vulkan SDKs) + if (strcmp(pCallbackData->pMessageIdName, "WARNING-DEBUG-PRINTF") == 0 || strcmp(pCallbackData->pMessageIdName, "UNASSIGNED-DEBUG-PRINTF") == 0) { // Validation messages are a bit verbose, but we only want the text from the shader, so we cut off everything before the first word from the shader message // See scene.vert: debugPrintfEXT("Position = %v4f", outPos); @@ -43,6 +44,21 @@ ShaderDebugPrintf::ShaderDebugPrintf() title = "Shader debugprintf"; add_device_extension(VK_KHR_SHADER_NON_SEMANTIC_INFO_EXTENSION_NAME); + + // If layer settings available, use it to configure validation layer for debugPrintfEXT + add_instance_extension(VK_EXT_LAYER_SETTINGS_EXTENSION_NAME, /*optional*/ true); + + VkLayerSettingEXT layerSetting; + layerSetting.pLayerName = "VK_LAYER_KHRONOS_validation"; + layerSetting.pSettingName = "enables"; + layerSetting.type = VK_LAYER_SETTING_TYPE_STRING_EXT; + layerSetting.valueCount = 1; + + // Make this static so layer setting reference remains valid after leaving constructor scope + static const char *layerEnables = "VK_VALIDATION_FEATURE_ENABLE_DEBUG_PRINTF_EXT"; + layerSetting.pValues = &layerEnables; + + add_layer_setting(layerSetting); } ShaderDebugPrintf::~ShaderDebugPrintf() @@ -375,6 +391,13 @@ bool ShaderDebugPrintf::prepare(const vkb::ApplicationOptions &options) return false; } + // Register debug utils callback here vs in ShaderDebugPrintf::create_instance() so it works with both override and layer settings + VkDebugUtilsMessengerCreateInfoEXT debug_utils_messenger_create_info{VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT}; + debug_utils_messenger_create_info.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT; + debug_utils_messenger_create_info.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT; + debug_utils_messenger_create_info.pfnUserCallback = debug_utils_message_callback; + VK_CHECK(vkCreateDebugUtilsMessengerEXT(get_instance().get_handle(), &debug_utils_messenger_create_info, nullptr, &debug_utils_messenger)); + camera.type = vkb::CameraType::LookAt; camera.set_position(glm::vec3(0.0f, 0.0f, -6.0f)); camera.set_rotation(glm::vec3(0.0f, 180.0f, 0.0f)); @@ -393,9 +416,39 @@ bool ShaderDebugPrintf::prepare(const vkb::ApplicationOptions &options) return true; } +// This sample overrides the per-sample layer framework to force activation of the validation layer +const std::vector ShaderDebugPrintf::get_validation_layers() +{ + // Validation layer is already enabled for debug builds, so initialize override list to default (empty) + std::vector validation_layers = ApiVulkanSample::get_validation_layers(); + +#if !defined(VKB_DEBUG) && !defined(VKB_VALIDATION_LAYERS) + // Force activation of validation layer on release builds for access to debugPrintfEXT feature + validation_layers.push_back("VK_LAYER_KHRONOS_validation"); +#endif + + return validation_layers; +} + // This sample overrides the instance creation part of the framework to chain in additional structures std::unique_ptr ShaderDebugPrintf::create_instance(bool headless) { + 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())); + + // When VK_EXT_layer_settings is available at runtime, the debugPrintfEXT layer feature is enabled using the standard framework + // For backwards compatibility with SDKs < 1.3.272 without VK_EXT_layer_settings, the remainder of this custom override is required + if (std::any_of(available_instance_extensions.begin(), + available_instance_extensions.end(), + [](VkExtensionProperties extension) { return strcmp(extension.extensionName, VK_EXT_LAYER_SETTINGS_EXTENSION_NAME) == 0; })) + { + // Run standard create_instance() from framework (with layer settings support) and return + return VulkanSample::create_instance(headless); + } + + // Run remainder of this custom create_instance() (without layer settings support) and return std::vector enabled_extensions; enabled_extensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME); @@ -406,11 +459,21 @@ std::unique_ptr ShaderDebugPrintf::create_instance(bool headless) enabled_extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); enabled_extensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); +#if (defined(VKB_ENABLE_PORTABILITY)) + bool portability_enumeration_available = false; + if (std::any_of(available_instance_extensions.begin(), + available_instance_extensions.end(), + [](VkExtensionProperties extension) { return strcmp(extension.extensionName, VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME) == 0; })) + { + enabled_extensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME); + portability_enumeration_available = true; + } +#endif VkApplicationInfo app_info{VK_STRUCTURE_TYPE_APPLICATION_INFO}; app_info.pApplicationName = "Shader debugprintf"; app_info.pEngineName = "Vulkan Samples"; - app_info.apiVersion = VK_API_VERSION_1_1; + app_info.apiVersion = VK_API_VERSION_1_0; // Shader printf is a feature of the validation layers that needs to be enabled std::vector validation_feature_enables = {VK_VALIDATION_FEATURE_ENABLE_DEBUG_PRINTF_EXT}; @@ -427,7 +490,13 @@ std::unique_ptr ShaderDebugPrintf::create_instance(bool headless) instance_create_info.pApplicationInfo = &app_info; instance_create_info.ppEnabledLayerNames = validation_layers.data(); instance_create_info.enabledLayerCount = static_cast(validation_layers.size()); - instance_create_info.pNext = &validation_features; +#if (defined(VKB_ENABLE_PORTABILITY)) + if (portability_enumeration_available) + { + instance_create_info.flags |= VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR; + } +#endif + instance_create_info.pNext = &validation_features; VkInstance vulkan_instance; VkResult result = vkCreateInstance(&instance_create_info, nullptr, &vulkan_instance); @@ -439,13 +508,6 @@ std::unique_ptr ShaderDebugPrintf::create_instance(bool headless) volkLoadInstance(vulkan_instance); - VkDebugUtilsMessengerCreateInfoEXT debug_utils_messenger_create_info{VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT}; - debug_utils_messenger_create_info.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT; - debug_utils_messenger_create_info.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT; - debug_utils_messenger_create_info.pfnUserCallback = debug_utils_message_callback; - - VK_CHECK(vkCreateDebugUtilsMessengerEXT(vulkan_instance, &debug_utils_messenger_create_info, nullptr, &debug_utils_messenger)); - return std::make_unique(vulkan_instance, enabled_extensions); } diff --git a/samples/extensions/shader_debugprintf/shader_debugprintf.h b/samples/extensions/shader_debugprintf/shader_debugprintf.h index b3609326d..7ce0daff1 100644 --- a/samples/extensions/shader_debugprintf/shader_debugprintf.h +++ b/samples/extensions/shader_debugprintf/shader_debugprintf.h @@ -81,21 +81,22 @@ class ShaderDebugPrintf : public ApiVulkanSample ShaderDebugPrintf(); ~ShaderDebugPrintf(); - virtual void request_gpu_features(vkb::PhysicalDevice &gpu) override; - void build_command_buffers() override; - void load_assets(); - void setup_descriptor_pool(); - void setup_descriptor_set_layout(); - void setup_descriptor_sets(); - void prepare_pipelines(); - void prepare_uniform_buffers(); - void update_uniform_buffers(); - void draw(); - bool prepare(const vkb::ApplicationOptions &options) override; - std::unique_ptr create_instance(bool headless) override; - virtual void render(float delta_time) override; - virtual void on_update_ui_overlay(vkb::Drawer &drawer) override; - virtual bool resize(const uint32_t width, const uint32_t height) override; + virtual void request_gpu_features(vkb::PhysicalDevice &gpu) override; + void build_command_buffers() override; + void load_assets(); + void setup_descriptor_pool(); + void setup_descriptor_set_layout(); + void setup_descriptor_sets(); + void prepare_pipelines(); + void prepare_uniform_buffers(); + void update_uniform_buffers(); + void draw(); + bool prepare(const vkb::ApplicationOptions &options) override; + const std::vector get_validation_layers() override; + std::unique_ptr create_instance(bool headless) override; + virtual void render(float delta_time) override; + virtual void on_update_ui_overlay(vkb::Drawer &drawer) override; + virtual bool resize(const uint32_t width, const uint32_t height) override; }; std::unique_ptr create_shader_debugprintf(); diff --git a/samples/performance/async_compute/async_compute.cpp b/samples/performance/async_compute/async_compute.cpp index 4b7ef3552..567427984 100644 --- a/samples/performance/async_compute/async_compute.cpp +++ b/samples/performance/async_compute/async_compute.cpp @@ -38,6 +38,15 @@ AsyncComputeSample::AsyncComputeSample() config.insert(1, double_buffer_hdr_frames, true); } +void AsyncComputeSample::request_gpu_features(vkb::PhysicalDevice &gpu) +{ +#ifdef VKB_ENABLE_PORTABILITY + // Since sampler_info.compareEnable = VK_TRUE, must enable the mutableComparisonSamplers feature of VK_KHR_portability_subset + auto &requested_portability_subset_features = gpu.request_extension_features(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_FEATURES_KHR); + requested_portability_subset_features.mutableComparisonSamplers = VK_TRUE; +#endif +} + void AsyncComputeSample::draw_gui() { get_gui().show_options_window( @@ -717,18 +726,21 @@ void AsyncComputeSample::update(float delta_time) void AsyncComputeSample::finish() { - for (auto &sem : hdr_wait_semaphores) + if (has_device()) { - // We're outside a frame context, so free the semaphore manually. - get_device().wait_idle(); - vkDestroySemaphore(get_device().get_handle(), sem, nullptr); - } + for (auto &sem : hdr_wait_semaphores) + { + // We're outside a frame context, so free the semaphore manually. + get_device().wait_idle(); + vkDestroySemaphore(get_device().get_handle(), sem, nullptr); + } - if (compute_post_semaphore) - { - // We're outside a frame context, so free the semaphore manually. - get_device().wait_idle(); - vkDestroySemaphore(get_device().get_handle(), compute_post_semaphore, nullptr); + if (compute_post_semaphore) + { + // We're outside a frame context, so free the semaphore manually. + get_device().wait_idle(); + vkDestroySemaphore(get_device().get_handle(), compute_post_semaphore, nullptr); + } } } diff --git a/samples/performance/async_compute/async_compute.h b/samples/performance/async_compute/async_compute.h index 46e58d215..d2f9281ac 100644 --- a/samples/performance/async_compute/async_compute.h +++ b/samples/performance/async_compute/async_compute.h @@ -33,6 +33,8 @@ class AsyncComputeSample : public vkb::VulkanSample virtual ~AsyncComputeSample() = default; + virtual void request_gpu_features(vkb::PhysicalDevice &gpu) override; + virtual bool prepare(const vkb::ApplicationOptions &options) override; virtual void update(float delta_time) override; diff --git a/samples/performance/multithreading_render_passes/multithreading_render_passes.cpp b/samples/performance/multithreading_render_passes/multithreading_render_passes.cpp index 59fe27a23..1e04d9462 100644 --- a/samples/performance/multithreading_render_passes/multithreading_render_passes.cpp +++ b/samples/performance/multithreading_render_passes/multithreading_render_passes.cpp @@ -39,6 +39,15 @@ MultithreadingRenderPasses::MultithreadingRenderPasses() config.insert(2, multithreading_mode, 2); } +void MultithreadingRenderPasses::request_gpu_features(vkb::PhysicalDevice &gpu) +{ +#ifdef VKB_ENABLE_PORTABILITY + // Since shadowmap_sampler_create_info.compareEnable = VK_TRUE, must enable the mutableComparisonSamplers feature of VK_KHR_portability_subset + auto &requested_portability_subset_features = gpu.request_extension_features(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_FEATURES_KHR); + requested_portability_subset_features.mutableComparisonSamplers = VK_TRUE; +#endif +} + bool MultithreadingRenderPasses::prepare(const vkb::ApplicationOptions &options) { if (!VulkanSample::prepare(options)) diff --git a/samples/performance/multithreading_render_passes/multithreading_render_passes.h b/samples/performance/multithreading_render_passes/multithreading_render_passes.h index 2dcc4979a..dda664139 100644 --- a/samples/performance/multithreading_render_passes/multithreading_render_passes.h +++ b/samples/performance/multithreading_render_passes/multithreading_render_passes.h @@ -49,6 +49,8 @@ class MultithreadingRenderPasses : public vkb::VulkanSample virtual ~MultithreadingRenderPasses() = default; + virtual void request_gpu_features(vkb::PhysicalDevice &gpu) override; + virtual bool prepare(const vkb::ApplicationOptions &options) override; virtual void update(float delta_time) override; diff --git a/samples/performance/pipeline_cache/pipeline_cache.cpp b/samples/performance/pipeline_cache/pipeline_cache.cpp index 16e8da5bd..052034cbe 100644 --- a/samples/performance/pipeline_cache/pipeline_cache.cpp +++ b/samples/performance/pipeline_cache/pipeline_cache.cpp @@ -42,15 +42,29 @@ PipelineCache::~PipelineCache() if (pipeline_cache != VK_NULL_HANDLE) { /* Get size of pipeline cache */ - size_t size{}; - VK_CHECK(vkGetPipelineCacheData(get_device().get_handle(), pipeline_cache, &size, nullptr)); - - /* Get data of pipeline cache */ - std::vector data(size); - VK_CHECK(vkGetPipelineCacheData(get_device().get_handle(), pipeline_cache, &size, data.data())); - - /* Write pipeline cache data to a file in binary format */ - vkb::fs::write_temp(data, "pipeline_cache.data"); + size_t size{}; + VkResult result = vkGetPipelineCacheData(get_device().get_handle(), pipeline_cache, &size, nullptr); + if (result == VK_SUCCESS && size > 0) + { + /* Get data of pipeline cache */ + std::vector data(size); + result = vkGetPipelineCacheData(get_device().get_handle(), pipeline_cache, &size, data.data()); + if (result == VK_SUCCESS && size > 0) + { + if (size < data.size()) + { + data.resize(size); + } + + /* Write pipeline cache data to a file in binary format */ + vkb::fs::write_temp(data, "pipeline_cache.data"); + } + } + + if (result != VK_SUCCESS || size == 0) + { + LOGE("Detected Vulkan error: {}, pipeline cache not saved.", vkb::to_string(result)); + } /* Destroy Vulkan pipeline cache */ vkDestroyPipelineCache(get_device().get_handle(), pipeline_cache, nullptr); diff --git a/third_party/CMakeLists.txt b/third_party/CMakeLists.txt index 0562aea6b..03a9fa87e 100644 --- a/third_party/CMakeLists.txt +++ b/third_party/CMakeLists.txt @@ -49,6 +49,10 @@ target_include_directories(vulkan SYSTEM INTERFACE ${VULKAN_INCLUDE_DIR}) target_compile_definitions(vulkan INTERFACE VK_NO_PROTOTYPES) +if(VKB_ENABLE_PORTABILITY) + # When portability is enabled, must enable Vulkan beta extensions for access to VK_KHR_portability_subset + target_compile_definitions(vulkan INTERFACE VK_ENABLE_BETA_EXTENSIONS) +endif() if(ANDROID) target_compile_definitions(vulkan INTERFACE VK_USE_PLATFORM_ANDROID_KHR)