From 87849d4a63aa9595d2046008c7c551a24885aeec Mon Sep 17 00:00:00 2001 From: asuessenbach Date: Mon, 13 Jan 2025 08:30:06 +0100 Subject: [PATCH] Refactor instance extension and layer handling --- framework/core/hpp_instance.cpp | 201 ++++++++---------- framework/core/hpp_instance.h | 22 +- framework/core/instance.cpp | 198 ++++++++--------- framework/core/instance.h | 20 +- framework/vulkan_sample.h | 48 +++-- samples/api/hello_triangle/hello_triangle.cpp | 6 +- .../hello_triangle_1_3/hello_triangle_1_3.cpp | 6 +- .../hpp_hello_triangle/hpp_hello_triangle.cpp | 44 +--- .../full_screen_exclusive.cpp | 6 +- .../shader_debugprintf/shader_debugprintf.cpp | 18 +- .../shader_debugprintf/shader_debugprintf.h | 5 +- samples/extensions/shader_object/README.adoc | 10 +- .../shader_object/shader_object.cpp | 13 +- .../extensions/shader_object/shader_object.h | 4 +- 14 files changed, 235 insertions(+), 366 deletions(-) diff --git a/framework/core/hpp_instance.cpp b/framework/core/hpp_instance.cpp index 669de5948..2c5435b7b 100644 --- a/framework/core/hpp_instance.cpp +++ b/framework/core/hpp_instance.cpp @@ -1,5 +1,5 @@ -/* Copyright (c) 2022-2024, NVIDIA CORPORATION. All rights reserved. - * Copyright (c) 2024, Arm Limited and Contributors +/* Copyright (c) 2022-2025, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2024-2025, Arm Limited and Contributors * * SPDX-License-Identifier: Apache-2.0 * @@ -103,90 +103,70 @@ bool validate_layers(const std::vector &required, namespace core { -std::vector get_optimal_validation_layers(const std::vector &supported_instance_layers) -{ - std::vector> validation_layer_priority_list = - { - // The preferred validation layer is "VK_LAYER_KHRONOS_validation" - {"VK_LAYER_KHRONOS_validation"}, - - // Otherwise we fallback to using the LunarG meta layer - {"VK_LAYER_LUNARG_standard_validation"}, - - // Otherwise we attempt to enable the individual layers that compose the LunarG meta layer since it doesn't exist - { - "VK_LAYER_GOOGLE_threading", - "VK_LAYER_LUNARG_parameter_validation", - "VK_LAYER_LUNARG_object_tracker", - "VK_LAYER_LUNARG_core_validation", - "VK_LAYER_GOOGLE_unique_objects", - }, - - // Otherwise as a last resort we fallback to attempting to enable the LunarG core layer - {"VK_LAYER_LUNARG_core_validation"}}; - - for (auto &validation_layers : validation_layer_priority_list) - { - if (validate_layers(validation_layers, supported_instance_layers)) - { - return validation_layers; - } - - LOGW("Couldn't enable validation layers (see log for error) - falling back"); - } - - // Else return nothing - return {}; -} - Optional HPPInstance::selected_gpu_index; namespace { -bool enable_extension(const char *required_ext_name, - const std::vector &available_exts, +bool enable_extension(const char *requested_extension, + const std::vector &available_extensions, std::vector &enabled_extensions) { - for (auto &avail_ext_it : available_exts) - { - if (strcmp(avail_ext_it.extensionName, required_ext_name) == 0) + bool is_available = + std::any_of(available_extensions.begin(), + available_extensions.end(), + [&requested_extension](auto const &available_extension) { return strcmp(requested_extension, available_extension.extensionName) == 0; }); + if (is_available) + { + bool is_already_enabled = + std::any_of(enabled_extensions.begin(), + enabled_extensions.end(), + [&requested_extension](auto const &enabled_extension) { return strcmp(requested_extension, enabled_extension) == 0; }); + if (!is_already_enabled) { - auto it = std::find_if(enabled_extensions.begin(), enabled_extensions.end(), - [required_ext_name](const char *enabled_ext_name) { - return strcmp(enabled_ext_name, required_ext_name) == 0; - }); - if (it != enabled_extensions.end()) - { - // Extension is already enabled - } - else - { - LOGI("Extension {} found, enabling it", required_ext_name); - enabled_extensions.emplace_back(required_ext_name); - } - return true; + LOGI("Extension {} available, enabling it", requested_extension); + enabled_extensions.emplace_back(requested_extension); } } + else + { + LOGI("Extension {} not available", requested_extension); + } - LOGI("Extension {} not found", required_ext_name); - return false; + return is_available; } -bool enable_all_extensions(const std::vector required_ext_names, - const std::vector &available_exts, - std::vector &enabled_extensions) +bool enable_layer(const char *requested_layer, + const std::vector &available_layers, + std::vector &enabled_layers) { - using std::placeholders::_1; + bool is_available = + std::any_of(available_layers.begin(), + available_layers.end(), + [&requested_layer](auto const &available_layer) { return strcmp(requested_layer, available_layer.layerName) == 0; }); + if (is_available) + { + bool is_already_enabled = + std::any_of(enabled_layers.begin(), + enabled_layers.end(), + [&requested_layer](auto const &enabled_layer) { return strcmp(requested_layer, enabled_layer) == 0; }); + if (!is_already_enabled) + { + LOGI("Layer {} available, enabling it", requested_layer); + enabled_layers.emplace_back(requested_layer); + } + } + else + { + LOGI("Layer {} not available", requested_layer); + } - return std::all_of(required_ext_names.begin(), required_ext_names.end(), - std::bind(enable_extension, _1, available_exts, enabled_extensions)); + return is_available; } - } // namespace HPPInstance::HPPInstance(const std::string &application_name, - const std::unordered_map &required_extensions, - const std::vector &required_validation_layers, + const std::unordered_map &requested_extensions, + const std::unordered_map &requested_layers, const std::vector &required_layer_settings, uint32_t api_version) { @@ -194,18 +174,15 @@ HPPInstance::HPPInstance(const std::string &applicati #ifdef USE_VALIDATION_LAYERS // Check if VK_EXT_debug_utils is supported, which supersedes VK_EXT_Debug_Report - const bool has_debug_utils = enable_extension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, - available_instance_extensions, enabled_extensions); + const bool has_debug_utils = enable_extension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, available_instance_extensions, enabled_extensions); bool has_debug_report = false; if (!has_debug_utils) { - has_debug_report = enable_extension(VK_EXT_DEBUG_REPORT_EXTENSION_NAME, - available_instance_extensions, enabled_extensions); + has_debug_report = enable_extension(VK_EXT_DEBUG_REPORT_EXTENSION_NAME, available_instance_extensions, enabled_extensions); if (!has_debug_report) { - LOGW("Neither of {} or {} are available; disabling debug reporting", - VK_EXT_DEBUG_UTILS_EXTENSION_NAME, VK_EXT_DEBUG_REPORT_EXTENSION_NAME); + LOGW("Neither of {} or {} are available; disabling debug reporting", VK_EXT_DEBUG_UTILS_EXTENSION_NAME, VK_EXT_DEBUG_REPORT_EXTENSION_NAME); } } #endif @@ -220,34 +197,24 @@ HPPInstance::HPPInstance(const std::string &applicati { std::vector available_layer_instance_extensions = vk::enumerateInstanceExtensionProperties(std::string("VK_LAYER_KHRONOS_validation")); - for (auto &available_extension : available_layer_instance_extensions) - { - if (strcmp(available_extension.extensionName, VK_EXT_VALIDATION_FEATURES_EXTENSION_NAME) == 0) - { - validation_features = true; - LOGI("{} is available, enabling it", VK_EXT_VALIDATION_FEATURES_EXTENSION_NAME); - enabled_extensions.push_back(VK_EXT_VALIDATION_FEATURES_EXTENSION_NAME); - } - } + enable_extension(VK_EXT_VALIDATION_FEATURES_EXTENSION_NAME, available_layer_instance_extensions, enabled_extensions); } #endif // Specific surface extensions are obtained from Window::get_required_surface_extensions - // They are already added to required_extensions by VulkanSample::prepare + // They are already added to requested_extensions by VulkanSample::prepare - // If using VK_EXT_headless_surface, we still create and use a surface - enabled_extensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME); + // Even for a headless surface a swapchain is still required + enable_extension(VK_KHR_SURFACE_EXTENSION_NAME, available_instance_extensions, enabled_extensions); // VK_KHR_get_physical_device_properties2 is a prerequisite of VK_KHR_performance_query // which will be used for stats gathering where available. - enable_extension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, - available_instance_extensions, enabled_extensions); + enable_extension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, available_instance_extensions, enabled_extensions); - auto extension_error = false; - for (auto extension : required_extensions) + for (auto requested_extension : requested_extensions) { - auto extension_name = extension.first; - auto extension_is_optional = extension.second; + auto const &extension_name = requested_extension.first; + auto extension_is_optional = requested_extension.second; if (!enable_extension(extension_name, available_instance_extensions, enabled_extensions)) { if (extension_is_optional) @@ -257,43 +224,43 @@ HPPInstance::HPPInstance(const std::string &applicati else { LOGE("Required instance extension {} not available, cannot run", extension_name); - extension_error = true; + throw std::runtime_error("Required instance extensions are missing."); } - extension_error = extension_error || !extension_is_optional; } } - if (extension_error) - { - throw std::runtime_error("Required instance extensions are missing."); - } - - std::vector supported_validation_layers = vk::enumerateInstanceLayerProperties(); + std::vector supported_layers = vk::enumerateInstanceLayerProperties(); - std::vector requested_validation_layers(required_validation_layers); + std::vector enabled_layers; -#ifdef USE_VALIDATION_LAYERS - // Determine the optimal validation layers to enable that are necessary for useful debugging - std::vector optimal_validation_layers = get_optimal_validation_layers(supported_validation_layers); - requested_validation_layers.insert(requested_validation_layers.end(), optimal_validation_layers.begin(), optimal_validation_layers.end()); -#endif - - if (validate_layers(requested_validation_layers, supported_validation_layers)) + auto layer_error = false; + for (auto const &requested_layer : requested_layers) { - LOGI("Enabled Validation Layers:") - for (const auto &layer : requested_validation_layers) + auto const &layer_name = requested_layer.first; + auto layer_is_optional = requested_layer.second; + if (!enable_layer(layer_name, supported_layers, enabled_layers)) { - LOGI(" \t{}", layer); + if (layer_is_optional) + { + LOGW("Optional layer {} not available, some features may be disabled", layer_name); + } + else + { + LOGE("Required layer {} not available, cannot run", layer_name); + throw std::runtime_error("Required layers are missing."); + } } } - else - { - throw std::runtime_error("Required validation layers are missing."); - } + +#ifdef USE_VALIDATION_LAYERS + // NOTE: It's important to have the validation layer as the last one here!!!! + // Otherwise, device creation fails !?! + enable_layer("VK_LAYER_KHRONOS_validation", supported_layers, enabled_layers); +#endif vk::ApplicationInfo app_info(application_name.c_str(), 0, "Vulkan Samples", 0, api_version); - vk::InstanceCreateInfo instance_info({}, &app_info, requested_validation_layers, enabled_extensions); + vk::InstanceCreateInfo instance_info({}, &app_info, enabled_layers, enabled_extensions); #ifdef USE_VALIDATION_LAYERS vk::DebugUtilsMessengerCreateInfoEXT debug_utils_create_info; @@ -450,7 +417,7 @@ vkb::core::HPPPhysicalDevice &HPPInstance::get_suitable_gpu(vk::SurfaceKHR surfa } return *gpus[selected_gpu_index.value()]; } - if ( headless_surface ) + if (headless_surface) { LOGW("Using headless surface with multiple GPUs. Considered explicitly selecting the target GPU.") } diff --git a/framework/core/hpp_instance.h b/framework/core/hpp_instance.h index c220d87f0..ecf3e33ba 100644 --- a/framework/core/hpp_instance.h +++ b/framework/core/hpp_instance.h @@ -1,5 +1,5 @@ -/* Copyright (c) 2022-2024, NVIDIA CORPORATION. All rights reserved. - * Copyright (c) 2024, Arm Limited and Contributors +/* Copyright (c) 2022-2025, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2024-2025, Arm Limited and Contributors * * SPDX-License-Identifier: Apache-2.0 * @@ -28,12 +28,6 @@ namespace vkb namespace core { class HPPPhysicalDevice; -/** - * @brief Returns a list of Khronos/LunarG supported validation layers - * Attempting to enable them in order of preference, starting with later Vulkan SDK versions - * @param supported_instance_layers A list of validation layers to check against - */ -std::vector get_optimal_validation_layers(const std::vector &supported_instance_layers); /** * @brief A wrapper class for vk::Instance @@ -52,17 +46,17 @@ class HPPInstance /** * @brief Initializes the connection to Vulkan * @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 requested_extensions The extensions requested to be enabled + * @param requested_layers The validation layers to be enabled * @param required_layer_settings The layer settings to be enabled * @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 */ HPPInstance(const std::string &application_name, - const std::unordered_map &required_extensions = {}, - const std::vector &required_validation_layers = {}, - const std::vector &required_layer_settings = {}, - uint32_t api_version = VK_API_VERSION_1_0); + const std::unordered_map &requested_extensions = {}, + const std::unordered_map &requested_layers = {}, + const std::vector &required_layer_settings = {}, + uint32_t api_version = VK_API_VERSION_1_0); /** * @brief Queries the GPUs of a vk::Instance that is already created diff --git a/framework/core/instance.cpp b/framework/core/instance.cpp index 42e0886d0..1024eaa25 100644 --- a/framework/core/instance.cpp +++ b/framework/core/instance.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2024, Arm Limited and Contributors +/* Copyright (c) 2018-2025, Arm Limited and Contributors * * SPDX-License-Identifier: Apache-2.0 * @@ -102,90 +102,71 @@ bool validate_layers(const std::vector &required, } } // namespace -std::vector get_optimal_validation_layers(const std::vector &supported_instance_layers) -{ - std::vector> validation_layer_priority_list = - { - // The preferred validation layer is "VK_LAYER_KHRONOS_validation" - {"VK_LAYER_KHRONOS_validation"}, - - // Otherwise we fallback to using the LunarG meta layer - {"VK_LAYER_LUNARG_standard_validation"}, - - // Otherwise we attempt to enable the individual layers that compose the LunarG meta layer since it doesn't exist - { - "VK_LAYER_GOOGLE_threading", - "VK_LAYER_LUNARG_parameter_validation", - "VK_LAYER_LUNARG_object_tracker", - "VK_LAYER_LUNARG_core_validation", - "VK_LAYER_GOOGLE_unique_objects", - }, - - // Otherwise as a last resort we fallback to attempting to enable the LunarG core layer - {"VK_LAYER_LUNARG_core_validation"}}; - - for (auto &validation_layers : validation_layer_priority_list) - { - if (validate_layers(validation_layers, supported_instance_layers)) - { - return validation_layers; - } - - LOGW("Couldn't enable validation layers (see log for error) - falling back"); - } - - // Else return nothing - return {}; -} - Optional Instance::selected_gpu_index; namespace { -bool enable_extension(const char *required_ext_name, - const std::vector &available_exts, +bool enable_extension(const char *requested_extension, + const std::vector &available_extensions, std::vector &enabled_extensions) { - for (auto &avail_ext_it : available_exts) - { - if (strcmp(avail_ext_it.extensionName, required_ext_name) == 0) + bool is_available = + std::any_of(available_extensions.begin(), + available_extensions.end(), + [&requested_extension](auto const &available_extension) { return strcmp(requested_extension, available_extension.extensionName) == 0; }); + if (is_available) + { + bool is_already_enabled = + std::any_of(enabled_extensions.begin(), + enabled_extensions.end(), + [&requested_extension](auto const &enabled_extension) { return strcmp(requested_extension, enabled_extension) == 0; }); + if (!is_already_enabled) { - auto it = std::find_if(enabled_extensions.begin(), enabled_extensions.end(), - [required_ext_name](const char *enabled_ext_name) { - return strcmp(enabled_ext_name, required_ext_name) == 0; - }); - if (it != enabled_extensions.end()) - { - // Extension is already enabled - } - else - { - LOGI("Extension {} found, enabling it", required_ext_name); - enabled_extensions.emplace_back(required_ext_name); - } - return true; + LOGI("Extension {} available, enabling it", requested_extension); + enabled_extensions.emplace_back(requested_extension); } } + else + { + LOGI("Extension {} not available", requested_extension); + } - LOGI("Extension {} not found", required_ext_name); - return false; + return is_available; } -bool enable_all_extensions(const std::vector required_ext_names, - const std::vector &available_exts, - std::vector &enabled_extensions) +bool enable_layer(const char *requested_layer, + const std::vector &available_layers, + std::vector &enabled_layers) { - using std::placeholders::_1; + bool is_available = + std::any_of(available_layers.begin(), + available_layers.end(), + [&requested_layer](auto const &available_layer) { return strcmp(requested_layer, available_layer.layerName) == 0; }); + if (is_available) + { + bool is_already_enabled = + std::any_of(enabled_layers.begin(), + enabled_layers.end(), + [&requested_layer](auto const &enabled_layer) { return strcmp(requested_layer, enabled_layer) == 0; }); + if (!is_already_enabled) + { + LOGI("Layer {} available, enabling it", requested_layer); + enabled_layers.emplace_back(requested_layer); + } + } + else + { + LOGI("Layer {} not available", requested_layer); + } - return std::all_of(required_ext_names.begin(), required_ext_names.end(), - std::bind(enable_extension, _1, available_exts, enabled_extensions)); + return is_available; } } // namespace Instance::Instance(const std::string &application_name, - const std::unordered_map &required_extensions, - const std::vector &required_validation_layers, + const std::unordered_map &requested_extensions, + const std::unordered_map &requested_layers, const std::vector &required_layer_settings, uint32_t api_version) { @@ -197,18 +178,15 @@ Instance::Instance(const std::string &application_nam #ifdef USE_VALIDATION_LAYERS // Check if VK_EXT_debug_utils is supported, which supersedes VK_EXT_Debug_Report - const bool has_debug_utils = enable_extension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, - available_instance_extensions, enabled_extensions); + const bool has_debug_utils = enable_extension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, available_instance_extensions, enabled_extensions); bool has_debug_report = false; if (!has_debug_utils) { - has_debug_report = enable_extension(VK_EXT_DEBUG_REPORT_EXTENSION_NAME, - available_instance_extensions, enabled_extensions); + has_debug_report = enable_extension(VK_EXT_DEBUG_REPORT_EXTENSION_NAME, available_instance_extensions, enabled_extensions); if (!has_debug_report) { - LOGW("Neither of {} or {} are available; disabling debug reporting", - VK_EXT_DEBUG_UTILS_EXTENSION_NAME, VK_EXT_DEBUG_REPORT_EXTENSION_NAME); + LOGW("Neither of {} or {} are available; disabling debug reporting", VK_EXT_DEBUG_UTILS_EXTENSION_NAME, VK_EXT_DEBUG_REPORT_EXTENSION_NAME); } } #endif @@ -227,34 +205,24 @@ Instance::Instance(const std::string &application_nam std::vector available_layer_instance_extensions(layer_instance_extension_count); VK_CHECK(vkEnumerateInstanceExtensionProperties("VK_LAYER_KHRONOS_validation", &layer_instance_extension_count, available_layer_instance_extensions.data())); - for (auto &available_extension : available_layer_instance_extensions) - { - if (strcmp(available_extension.extensionName, VK_EXT_VALIDATION_FEATURES_EXTENSION_NAME) == 0) - { - validation_features = true; - LOGI("{} is available, enabling it", VK_EXT_VALIDATION_FEATURES_EXTENSION_NAME); - enabled_extensions.push_back(VK_EXT_VALIDATION_FEATURES_EXTENSION_NAME); - } - } + enable_extension(VK_EXT_VALIDATION_FEATURES_EXTENSION_NAME, available_layer_instance_extensions, enabled_extensions); } #endif // Specific surface extensions are obtained from Window::get_required_surface_extensions - // They are already added to required_extensions by VulkanSample::prepare + // They are already added to requested_extensions by VulkanSample::prepare // Even for a headless surface a swapchain is still required - enabled_extensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME); + enable_extension(VK_KHR_SURFACE_EXTENSION_NAME, available_instance_extensions, enabled_extensions); // VK_KHR_get_physical_device_properties2 is a prerequisite of VK_KHR_performance_query // which will be used for stats gathering where available. - enable_extension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, - available_instance_extensions, enabled_extensions); + enable_extension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, available_instance_extensions, enabled_extensions); - auto extension_error = false; - for (auto extension : required_extensions) + for (auto requested_extension : requested_extensions) { - auto extension_name = extension.first; - auto extension_is_optional = extension.second; + auto const &extension_name = requested_extension.first; + auto extension_is_optional = requested_extension.second; if (!enable_extension(extension_name, available_instance_extensions, enabled_extensions)) { if (extension_is_optional) @@ -264,43 +232,43 @@ Instance::Instance(const std::string &application_nam else { LOGE("Required instance extension {} not available, cannot run", extension_name); - extension_error = true; + throw std::runtime_error("Required instance extensions are missing."); } - extension_error = extension_error || !extension_is_optional; } } - if (extension_error) - { - throw std::runtime_error("Required instance extensions are missing."); - } - uint32_t instance_layer_count; VK_CHECK(vkEnumerateInstanceLayerProperties(&instance_layer_count, nullptr)); - std::vector supported_validation_layers(instance_layer_count); - VK_CHECK(vkEnumerateInstanceLayerProperties(&instance_layer_count, supported_validation_layers.data())); + std::vector supported_layers(instance_layer_count); + VK_CHECK(vkEnumerateInstanceLayerProperties(&instance_layer_count, supported_layers.data())); - std::vector requested_validation_layers(required_validation_layers); + std::vector enabled_layers; -#ifdef USE_VALIDATION_LAYERS - // Determine the optimal validation layers to enable that are necessary for useful debugging - std::vector optimal_validation_layers = get_optimal_validation_layers(supported_validation_layers); - requested_validation_layers.insert(requested_validation_layers.end(), optimal_validation_layers.begin(), optimal_validation_layers.end()); -#endif - - if (validate_layers(requested_validation_layers, supported_validation_layers)) + auto layer_error = false; + for (auto const &requested_layer : requested_layers) { - LOGI("Enabled Validation Layers:") - for (const auto &layer : requested_validation_layers) + auto const &layer_name = requested_layer.first; + auto layer_is_optional = requested_layer.second; + if (!enable_layer(layer_name, supported_layers, enabled_layers)) { - LOGI(" \t{}", layer); + if (layer_is_optional) + { + LOGW("Optional layer {} not available, some features may be disabled", layer_name); + } + else + { + LOGE("Required layer {} not available, cannot run", layer_name); + throw std::runtime_error("Required layers are missing."); + } } } - else - { - throw std::runtime_error("Required validation layers are missing."); - } + +#ifdef USE_VALIDATION_LAYERS + // NOTE: It's important to have the validation layer as the last one here!!!! + // Otherwise, device creation fails !?! + enable_layer("VK_LAYER_KHRONOS_validation", supported_layers, enabled_layers); +#endif VkApplicationInfo app_info{VK_STRUCTURE_TYPE_APPLICATION_INFO}; @@ -317,8 +285,8 @@ Instance::Instance(const std::string &application_nam instance_info.enabledExtensionCount = to_u32(enabled_extensions.size()); instance_info.ppEnabledExtensionNames = enabled_extensions.data(); - instance_info.enabledLayerCount = to_u32(requested_validation_layers.size()); - instance_info.ppEnabledLayerNames = requested_validation_layers.data(); + instance_info.enabledLayerCount = to_u32(enabled_layers.size()); + instance_info.ppEnabledLayerNames = enabled_layers.data(); #ifdef USE_VALIDATION_LAYERS VkDebugUtilsMessengerCreateInfoEXT debug_utils_create_info = {VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT}; diff --git a/framework/core/instance.h b/framework/core/instance.h index d4a1c9f47..bf76ab0bf 100644 --- a/framework/core/instance.h +++ b/framework/core/instance.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2024, Arm Limited and Contributors +/* Copyright (c) 2018-2025, Arm Limited and Contributors * * SPDX-License-Identifier: Apache-2.0 * @@ -24,12 +24,6 @@ namespace vkb { class PhysicalDevice; -/** - * @brief Returns a list of Khronos/LunarG supported validation layers - * Attempting to enable them in order of preference, starting with later Vulkan SDK versions - * @param supported_instance_layers A list of validation layers to check against - */ -std::vector get_optimal_validation_layers(const std::vector &supported_instance_layers); /** * @brief A wrapper class for VkInstance @@ -48,17 +42,17 @@ class Instance /** * @brief Initializes the connection to Vulkan * @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 requested_extensions The extensions requested to be enabled + * @param requested_layers The validation layers to be enabled * @param required_layer_settings The layer settings to be enabled * @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 */ Instance(const std::string &application_name, - const std::unordered_map &required_extensions = {}, - const std::vector &required_validation_layers = {}, - const std::vector &required_layer_settings = {}, - uint32_t api_version = VK_API_VERSION_1_0); + const std::unordered_map &requested_extensions = {}, + const std::unordered_map &requested_layers = {}, + const std::vector &required_layer_settings = {}, + uint32_t api_version = VK_API_VERSION_1_0); /** * @brief Queries the GPUs of a VkInstance that is already created diff --git a/framework/vulkan_sample.h b/framework/vulkan_sample.h index 4f9b7f9dd..006b5c168 100644 --- a/framework/vulkan_sample.h +++ b/framework/vulkan_sample.h @@ -1,5 +1,5 @@ -/* Copyright (c) 2019-2024, Arm Limited and Contributors - * Copyright (c) 2021-2024, NVIDIA CORPORATION. All rights reserved. +/* Copyright (c) 2019-2025, Arm Limited and Contributors + * Copyright (c) 2021-2025, NVIDIA CORPORATION. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 * @@ -201,13 +201,6 @@ class VulkanSample : public vkb::Application */ virtual void draw_renderpass(CommandBufferType &command_buffer, RenderTargetType &render_target); - /** - * @brief Get additional sample-specific instance layers. - * - * @return Vector of additional instance layers. Default is empty vector. - */ - virtual const std::vector get_validation_layers(); - /** * @brief Override this to customise the creation of the swapchain and render_context */ @@ -253,6 +246,13 @@ class VulkanSample : public vkb::Application */ void add_instance_extension(const char *extension, bool optional = false); + /** + * @brief Add a sample-specific instance layer + * @param layer The layer name + * @param optional (Optional) Whether the extension is optional + */ + void add_instance_layer(const char *layer, bool optional = false); + /** * @brief Add a sample-specific layer setting * @param layerSetting The layer setting @@ -367,6 +367,13 @@ class VulkanSample : public vkb::Application */ std::unordered_map const &get_instance_extensions() const; + /** + * @brief Get sample-specific instance layers. + * + * @return Map of instance layers and whether or not they are optional. Default is empty map. + */ + std::unordered_map const &get_instance_layers() const; + /** * @brief Get sample-specific layer settings. * @@ -432,6 +439,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 Set of instance layers to be enabled for this example and whether they are optional (must be set in the derived constructor) */ + std::unordered_map instance_layers; + /** @brief Vector of layer settings to be enabled for this example (must be set in the derived constructor) */ std::vector layer_settings; @@ -510,7 +520,7 @@ inline std::unique_ptr::DeviceType> VulkanSam template inline std::unique_ptr::InstanceType> VulkanSample::create_instance() { - return std::make_unique(get_name(), get_instance_extensions(), get_validation_layers(), get_layer_settings(), api_version); + return std::make_unique(get_name(), get_instance_extensions(), get_instance_layers(), get_layer_settings(), api_version); } template @@ -796,6 +806,18 @@ inline std::unordered_map const &VulkanSample:: return instance_extensions; } +template +inline std::unordered_map const &VulkanSample::get_instance_layers() const +{ + return instance_layers; +} + +template +inline void VulkanSample::add_instance_layer(const char *layer, bool optional) +{ + instance_layers[layer] = optional; +} + template inline std::vector::LayerSettingType> const &VulkanSample::get_layer_settings() const { @@ -905,12 +927,6 @@ inline typename VulkanSample::SurfaceType VulkanSample } } -template -inline const std::vector VulkanSample::get_validation_layers() -{ - return {}; -} - template inline bool VulkanSample::has_device() const { diff --git a/samples/api/hello_triangle/hello_triangle.cpp b/samples/api/hello_triangle/hello_triangle.cpp index a2b499a38..c5fee767d 100644 --- a/samples/api/hello_triangle/hello_triangle.cpp +++ b/samples/api/hello_triangle/hello_triangle.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2024, Arm Limited and Contributors +/* Copyright (c) 2018-2025, Arm Limited and Contributors * * SPDX-License-Identifier: Apache-2.0 * @@ -235,9 +235,7 @@ void HelloTriangle::init_instance() std::vector requested_validation_layers{}; #if defined(VKB_DEBUG) || defined(VKB_VALIDATION_LAYERS) - // Determine the optimal validation layers to enable that are necessary for useful debugging - std::vector optimal_validation_layers = vkb::get_optimal_validation_layers(supported_validation_layers); - requested_validation_layers.insert(requested_validation_layers.end(), optimal_validation_layers.begin(), optimal_validation_layers.end()); + requested_validation_layers.push_back("VK_LAYER_KHRONOS_validation"); #endif if (validate_layers(requested_validation_layers, supported_validation_layers)) 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 1e83561fe..785f8c5a0 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 @@ -1,4 +1,4 @@ -/* Copyright (c) 2024, Huawei Technologies Co., Ltd. +/* Copyright (c) 2024-2025, Huawei Technologies Co., Ltd. * * SPDX-License-Identifier: Apache-2.0 * @@ -197,9 +197,7 @@ void HelloTriangleV13::init_instance() std::vector requested_validation_layers{}; #if defined(VKB_DEBUG) || defined(VKB_VALIDATION_LAYERS) - // Determine the optimal validation layers to enable that are necessary for useful debugging - std::vector optimal_validation_layers = vkb::get_optimal_validation_layers(supported_validation_layers); - requested_validation_layers.insert(requested_validation_layers.end(), optimal_validation_layers.begin(), optimal_validation_layers.end()); + requested_validation_layers.push_back("VK_LAYER_KHRONOS_validation"); #endif if (validate_layers(requested_validation_layers, supported_validation_layers)) diff --git a/samples/api/hpp_hello_triangle/hpp_hello_triangle.cpp b/samples/api/hpp_hello_triangle/hpp_hello_triangle.cpp index 710065a4b..69af62e76 100644 --- a/samples/api/hpp_hello_triangle/hpp_hello_triangle.cpp +++ b/samples/api/hpp_hello_triangle/hpp_hello_triangle.cpp @@ -1,5 +1,5 @@ -/* Copyright (c) 2021-2024, NVIDIA CORPORATION. All rights reserved. - * Copyright (c) 2024, Arm Limited and Contributors +/* Copyright (c) 2021-2025, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2024-2025, Arm Limited and Contributors * * SPDX-License-Identifier: Apache-2.0 * @@ -92,42 +92,6 @@ bool validate_layers(const std::vector &required, return (requiredButNotFoundIt == required.end()); } -std::vector get_optimal_validation_layers(const std::vector &supported_instance_layers) -{ - std::vector> validation_layer_priority_list = - { - // The preferred validation layer is "VK_LAYER_KHRONOS_validation" - {"VK_LAYER_KHRONOS_validation"}, - - // Otherwise we fallback to using the LunarG meta layer - {"VK_LAYER_LUNARG_standard_validation"}, - - // Otherwise we attempt to enable the individual layers that compose the LunarG meta layer since it doesn't exist - { - "VK_LAYER_GOOGLE_threading", - "VK_LAYER_LUNARG_parameter_validation", - "VK_LAYER_LUNARG_object_tracker", - "VK_LAYER_LUNARG_core_validation", - "VK_LAYER_GOOGLE_unique_objects", - }, - - // Otherwise as a last resort we fallback to attempting to enable the LunarG core layer - {"VK_LAYER_LUNARG_core_validation"}}; - - for (auto &validation_layers : validation_layer_priority_list) - { - if (validate_layers(validation_layers, supported_instance_layers)) - { - return validation_layers; - } - - LOGW("Couldn't enable validation layers (see log for error) - falling back"); - } - - // Else return nothing - return {}; -} - HPPHelloTriangle::HPPHelloTriangle() { } @@ -482,9 +446,7 @@ vk::Instance HPPHelloTriangle::create_instance(std::vector const & std::vector requested_validation_layers(required_validation_layers); #ifdef VKB_VALIDATION_LAYERS - // Determine the optimal validation layers to enable that are necessary for useful debugging - std::vector optimal_validation_layers = get_optimal_validation_layers(supported_validation_layers); - requested_validation_layers.insert(requested_validation_layers.end(), optimal_validation_layers.begin(), optimal_validation_layers.end()); + requested_validation_layers.push_back("VK_LAYER_KHRONOS_validation"); #endif if (validate_layers(requested_validation_layers, supported_validation_layers)) diff --git a/samples/extensions/full_screen_exclusive/full_screen_exclusive.cpp b/samples/extensions/full_screen_exclusive/full_screen_exclusive.cpp index 6d92b7ab0..7642787d1 100644 --- a/samples/extensions/full_screen_exclusive/full_screen_exclusive.cpp +++ b/samples/extensions/full_screen_exclusive/full_screen_exclusive.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2023-2024, Holochip Corporation +/* Copyright (c) 2023-2025, Holochip Corporation * * SPDX-License-Identifier: Apache-2.0 * @@ -168,9 +168,7 @@ void FullScreenExclusive::init_instance(const std::vector &require std::vector requested_validation_layers(required_validation_layers); #if defined(VKB_DEBUG) || defined(VKB_VALIDATION_LAYERS) - // Determine the optimal validation layers to enable that are necessary for useful debugging - std::vector optimal_validation_layers = vkb::get_optimal_validation_layers(supported_validation_layers); - requested_validation_layers.insert(requested_validation_layers.end(), optimal_validation_layers.begin(), optimal_validation_layers.end()); + requested_validation_layers.push_back("VK_LAYER_KHRONOS_validation"); #endif if (validate_layers(requested_validation_layers, supported_validation_layers)) diff --git a/samples/extensions/shader_debugprintf/shader_debugprintf.cpp b/samples/extensions/shader_debugprintf/shader_debugprintf.cpp index 67bbb7b15..36fb2bec0 100644 --- a/samples/extensions/shader_debugprintf/shader_debugprintf.cpp +++ b/samples/extensions/shader_debugprintf/shader_debugprintf.cpp @@ -1,5 +1,5 @@ -/* Copyright (c) 2024, Sascha Willems - * Copyright (c) 2024, Arm Limited and Contributors +/* Copyright (c) 2024-2025, Sascha Willems + * Copyright (c) 2024-2025, Arm Limited and Contributors * * SPDX-License-Identifier: Apache-2.0 * @@ -417,20 +417,6 @@ 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() { diff --git a/samples/extensions/shader_debugprintf/shader_debugprintf.h b/samples/extensions/shader_debugprintf/shader_debugprintf.h index 546610453..3b0955089 100644 --- a/samples/extensions/shader_debugprintf/shader_debugprintf.h +++ b/samples/extensions/shader_debugprintf/shader_debugprintf.h @@ -1,5 +1,5 @@ -/* Copyright (c) 2024, Sascha Willems - * Copyright (c) 2024, Arm Limited and Contributors +/* Copyright (c) 2024-2025, Sascha Willems + * Copyright (c) 2024-2025, Arm Limited and Contributors * * SPDX-License-Identifier: Apache-2.0 * @@ -93,7 +93,6 @@ class ShaderDebugPrintf : public ApiVulkanSample 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() override; virtual void render(float delta_time) override; virtual void on_update_ui_overlay(vkb::Drawer &drawer) override; diff --git a/samples/extensions/shader_object/README.adoc b/samples/extensions/shader_object/README.adoc index c7e50cc22..63801febd 100644 --- a/samples/extensions/shader_object/README.adoc +++ b/samples/extensions/shader_object/README.adoc @@ -1,5 +1,5 @@ //// -- Copyright 2023 Nintendo +- Copyright 2023-2025 Nintendo - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. @@ -435,15 +435,11 @@ The layer can be shipped with your application, and it will disable itself if a The emulation layer can be enabled by adding `VK_LAYER_KHRONOS_shader_object` to `ppEnabledLayerNames` in `VkDeviceCreateInfo`. -The sample framework already has an existing abstraction normally used for enabling the validation layer. -This sample repurposes this mechanism to instead load the emulation layer. +Similar to enabling extensions, enabling layers is done through a common abstraction with the other samples. [,CPP] ---- -const std::vector ShaderObject::get_validation_layers() -{ - return {"VK_LAYER_KHRONOS_shader_object"}; -} + add_instance_layer("VK_LAYER_KHRONOS_shader_object"); ---- Because you can't rely on the Vulkan SDK to be installed on a user's system, this sample's method of loading the layer is not suitable for a real application. diff --git a/samples/extensions/shader_object/shader_object.cpp b/samples/extensions/shader_object/shader_object.cpp index 56bc33df7..ccf7d108c 100644 --- a/samples/extensions/shader_object/shader_object.cpp +++ b/samples/extensions/shader_object/shader_object.cpp @@ -1,6 +1,6 @@ /* - * Copyright 2023-2024 Nintendo - * Copyright 2023-2024, Sascha Willems + * Copyright 2023-2025 Nintendo + * Copyright 2023-2025, Sascha Willems * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,6 +30,8 @@ ShaderObject::ShaderObject() // Show that shader object is usable with Vulkan 1.1 + Dynamic Rendering set_api_version(VK_API_VERSION_1_1); + add_instance_layer("VK_LAYER_KHRONOS_shader_object"); + // Enable the Shader Object extension add_device_extension(VK_EXT_SHADER_OBJECT_EXTENSION_NAME); @@ -105,13 +107,6 @@ ShaderObject::~ShaderObject() } } -// Currently the sample calls through this function in order to get the list of any instance layers, not just validation layers. -// This is not suitable for a real application implementation using the layer, the layer will need to be shipped with the application. -const std::vector ShaderObject::get_validation_layers() -{ - return {"VK_LAYER_KHRONOS_shader_object"}; -} - bool ShaderObject::resize(const uint32_t _width, const uint32_t _height) { if (!has_device()) diff --git a/samples/extensions/shader_object/shader_object.h b/samples/extensions/shader_object/shader_object.h index 71ebbf03e..a76358fc8 100644 --- a/samples/extensions/shader_object/shader_object.h +++ b/samples/extensions/shader_object/shader_object.h @@ -1,5 +1,5 @@ /* - * Copyright 2023-2024 Nintendo + * Copyright 2023-2025 Nintendo * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -128,8 +128,6 @@ class ShaderObject : public ApiVulkanSample ShaderObject(); ~ShaderObject() override; - const std::vector get_validation_layers() override; - bool resize(const uint32_t width, const uint32_t height) override; bool prepare(const vkb::ApplicationOptions &options) override; void setup_framebuffer() override;