From 892f2893407f7081618eaf54bf4801a3eb60794c Mon Sep 17 00:00:00 2001 From: swinston Date: Thu, 16 May 2024 16:46:27 -0700 Subject: [PATCH] Refactor validation layers to use vector instead of map Related functions and variables have been updated to accommodate the change. This ensures consistency and optimizes the performance for layer searches and validations. --- framework/core/hpp_instance.cpp | 72 +++++++++++++----- framework/core/hpp_instance.h | 5 +- framework/core/instance.cpp | 75 +++++++++++++------ framework/core/instance.h | 5 +- framework/vulkan_sample.h | 22 +++++- samples/api/hello_triangle/hello_triangle.cpp | 4 +- .../shader_object/shader_object.cpp | 12 +-- .../extensions/shader_object/shader_object.h | 2 - 8 files changed, 138 insertions(+), 59 deletions(-) diff --git a/framework/core/hpp_instance.cpp b/framework/core/hpp_instance.cpp index 630b5c55c..8ce600571 100644 --- a/framework/core/hpp_instance.cpp +++ b/framework/core/hpp_instance.cpp @@ -106,6 +106,30 @@ bool validate_layers(std::unordered_map &required, { required.erase(rem); } + return true; +} + +bool validate_layers(const std::vector &required, + const std::vector &available) +{ + for (auto layer : required) + { + bool found = false; + for (auto &available_layer : available) + { + if (strcmp(available_layer.layerName, layer) == 0) + { + found = true; + break; + } + } + + if (!found) + { + LOGE("Validation Layer {} not found", layer); + return false; + } + } return true; } @@ -113,27 +137,27 @@ bool validate_layers(std::unordered_map &required, namespace core { -std::unordered_map get_optimal_validation_layers(const std::vector &supported_instance_layers) +std::vector get_optimal_validation_layers(const std::vector &supported_instance_layers) { - std::vector> validation_layer_priority_list = + std::vector> validation_layer_priority_list = { // The preferred validation layer is "VK_LAYER_KHRONOS_validation" - {{"VK_LAYER_KHRONOS_validation", true}}, + {"VK_LAYER_KHRONOS_validation"}, // Otherwise we fallback to using the LunarG meta layer - {{"VK_LAYER_LUNARG_standard_validation", true}}, + {"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", true}, - {"VK_LAYER_LUNARG_parameter_validation", true}, - {"VK_LAYER_LUNARG_object_tracker", true}, - {"VK_LAYER_LUNARG_core_validation", true}, - {"VK_LAYER_GOOGLE_unique_objects", true}, + "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", true}}}; + {"VK_LAYER_LUNARG_core_validation"}}; for (auto &validation_layers : validation_layer_priority_list) { @@ -196,7 +220,8 @@ bool enable_all_extensions(const std::vector required_ HPPInstance::HPPInstance(const std::string &application_name, const std::unordered_map &required_extensions, - const std::unordered_map &required_validation_layers, + const std::vector &required_validation_layers, + const std::unordered_map &requested_layers, bool headless, uint32_t api_version) { @@ -289,12 +314,12 @@ HPPInstance::HPPInstance(const std::string &applicati std::vector supported_validation_layers = vk::enumerateInstanceLayerProperties(); - std::unordered_map requested_validation_layers(required_validation_layers); + std::vector requested_validation_layers(required_validation_layers); #ifdef USE_VALIDATION_LAYERS // Determine the optimal validation layers to enable that are necessary for useful debugging - std::unordered_map optimal_validation_layers = get_optimal_validation_layers(supported_validation_layers); - requested_validation_layers.insert(optimal_validation_layers.begin(), optimal_validation_layers.end()); + 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)) @@ -302,7 +327,7 @@ HPPInstance::HPPInstance(const std::string &applicati LOGI("Enabled Validation Layers:") for (const auto &layer : requested_validation_layers) { - LOGI(" \t{}", layer.first) + LOGI(" \t{}", layer); } } else @@ -310,16 +335,23 @@ HPPInstance::HPPInstance(const std::string &applicati throw std::runtime_error("Required validation layers are missing."); } - std::vector final_validation_layers; - final_validation_layers.reserve(requested_validation_layers.size()); - for (auto layer : requested_validation_layers) + std::unordered_map layers = (std::unordered_map)(requested_layers); + if(validate_layers(layers, supported_validation_layers)) { - final_validation_layers.push_back(layer.first); + LOGI("Enabled Validation Layers:") + for (const auto &layer : layers) + { + LOGI(" \t{}", layer.first); + } + } + else + { + throw std::runtime_error("Required validation layers are missing."); } vk::ApplicationInfo app_info(application_name.c_str(), 0, "Vulkan Samples", 0, api_version); - vk::InstanceCreateInfo instance_info({}, &app_info, final_validation_layers, enabled_extensions); + vk::InstanceCreateInfo instance_info({}, &app_info, requested_validation_layers, enabled_extensions); #ifdef USE_VALIDATION_LAYERS vk::DebugUtilsMessengerCreateInfoEXT debug_utils_create_info; diff --git a/framework/core/hpp_instance.h b/framework/core/hpp_instance.h index d494c89b3..aef23baba 100644 --- a/framework/core/hpp_instance.h +++ b/framework/core/hpp_instance.h @@ -32,7 +32,7 @@ class HPPPhysicalDevice; * 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::unordered_map get_optimal_validation_layers(const std::vector &supported_instance_layers); +std::vector get_optimal_validation_layers(const std::vector &supported_instance_layers); /** * @brief A wrapper class for vk::Instance @@ -59,7 +59,8 @@ class HPPInstance */ HPPInstance(const std::string &application_name, const std::unordered_map &required_extensions = {}, - const std::unordered_map &required_validation_layers = {}, + const std::vector &required_validation_layers = {}, + const std::unordered_map &requested_layers = {}, 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 e975ba937..af1447770 100644 --- a/framework/core/instance.cpp +++ b/framework/core/instance.cpp @@ -108,31 +108,56 @@ bool validate_layers(std::unordered_map &required, { required.erase(rem); } + return true; +} + +bool validate_layers(const std::vector &required, + const std::vector &available) +{ + for (auto layer : required) + { + bool found = false; + for (auto &available_layer : available) + { + if (strcmp(available_layer.layerName, layer) == 0) + { + found = true; + break; + } + } + + if (!found) + { + LOGE("Validation Layer {} not found", layer); + return false; + } + } return true; } } // namespace -std::unordered_map get_optimal_validation_layers(const std::vector &supported_instance_layers) +std::vector get_optimal_validation_layers(const std::vector &supported_instance_layers) { - std::vector> validation_layer_priority_list = + std::vector> validation_layer_priority_list = { // The preferred validation layer is "VK_LAYER_KHRONOS_validation" - {{"VK_LAYER_KHRONOS_validation", true}}, + {"VK_LAYER_KHRONOS_validation"}, // Otherwise we fallback to using the LunarG meta layer - {{"VK_LAYER_LUNARG_standard_validation", true}}, + {"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", true}, - {"VK_LAYER_LUNARG_parameter_validation", true}, - {"VK_LAYER_LUNARG_object_tracker", true}, - {"VK_LAYER_LUNARG_core_validation", true}, - {"VK_LAYER_GOOGLE_unique_objects", true}}, + "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", true}}}; + {"VK_LAYER_LUNARG_core_validation"}}; for (auto &validation_layers : validation_layer_priority_list) { @@ -195,7 +220,8 @@ bool enable_all_extensions(const std::vector required_ex Instance::Instance(const std::string &application_name, const std::unordered_map &required_extensions, - const std::unordered_map &required_validation_layers, + const std::vector &required_validation_layers, + const std::unordered_map &requested_layers, bool headless, uint32_t api_version) { @@ -300,12 +326,12 @@ Instance::Instance(const std::string &application_nam std::vector supported_validation_layers(instance_layer_count); VK_CHECK(vkEnumerateInstanceLayerProperties(&instance_layer_count, supported_validation_layers.data())); - std::unordered_map requested_validation_layers(required_validation_layers); + std::vector requested_validation_layers(required_validation_layers); #ifdef USE_VALIDATION_LAYERS // Determine the optimal validation layers to enable that are necessary for useful debugging - std::unordered_map optimal_validation_layers = get_optimal_validation_layers(supported_validation_layers); - requested_validation_layers.insert(optimal_validation_layers.begin(), optimal_validation_layers.end()); + 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)) @@ -313,7 +339,7 @@ Instance::Instance(const std::string &application_nam LOGI("Enabled Validation Layers:") for (const auto &layer : requested_validation_layers) { - LOGI(" \t{}", layer.first) + LOGI(" \t{}", layer); } } else @@ -321,11 +347,18 @@ Instance::Instance(const std::string &application_nam throw std::runtime_error("Required validation layers are missing."); } - std::vector final_validation_layers; - final_validation_layers.reserve(requested_validation_layers.size()); - for (auto layer : requested_validation_layers) + std::unordered_map layers = (std::unordered_map)(requested_layers); + if(validate_layers(layers, supported_validation_layers)) { - final_validation_layers.push_back(layer.first); + LOGI("Enabled Validation Layers:") + for (const auto &layer : layers) + { + LOGI(" \t{}", layer.first); + } + } + else + { + throw std::runtime_error("Required validation layers are missing."); } VkApplicationInfo app_info{VK_STRUCTURE_TYPE_APPLICATION_INFO}; @@ -343,8 +376,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(final_validation_layers.size()); - instance_info.ppEnabledLayerNames = final_validation_layers.data(); + instance_info.enabledLayerCount = to_u32(requested_validation_layers.size()); + instance_info.ppEnabledLayerNames = requested_validation_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 0df9bdb41..cb8e4ee68 100644 --- a/framework/core/instance.h +++ b/framework/core/instance.h @@ -29,7 +29,7 @@ class PhysicalDevice; * 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::unordered_map get_optimal_validation_layers(const std::vector &supported_instance_layers); +std::vector get_optimal_validation_layers(const std::vector &supported_instance_layers); /** * @brief A wrapper class for VkInstance @@ -56,7 +56,8 @@ class Instance */ Instance(const std::string &application_name, const std::unordered_map &required_extensions = {}, - const std::unordered_map &required_validation_layers = {}, + const std::vector &required_validation_layers = {}, + const std::unordered_map &requested_layers = {}, bool headless = false, uint32_t api_version = VK_API_VERSION_1_0); diff --git a/framework/vulkan_sample.h b/framework/vulkan_sample.h index 6f4d6570b..ce701681f 100644 --- a/framework/vulkan_sample.h +++ b/framework/vulkan_sample.h @@ -203,7 +203,7 @@ class VulkanSample : public vkb::Application * * @return Vector of additional instance layers. Default is empty vector. */ - virtual const std::unordered_map get_validation_layers(); + virtual const std::vector get_validation_layers(); /** * @brief Override this to customise the creation of the swapchain and render_context @@ -250,6 +250,8 @@ class VulkanSample : public vkb::Application */ void add_instance_extension(const char *extension, bool optional = false); + void add_layer(const char *layer, bool optional = false); + void create_gui(const Window &window, StatsType const *stats = nullptr, const float font_size = 21.0f, bool explicit_update = false); /** @@ -358,6 +360,8 @@ class VulkanSample : public vkb::Application */ std::unordered_map const &get_instance_extensions() const; + std::unordered_map const &get_layers() const; + /// /// PRIVATE MEMBERS /// @@ -415,6 +419,8 @@ 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; + std::unordered_map instance_layers; + /** @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 +465,12 @@ inline void VulkanSample::add_instance_extension(const char *extens instance_extensions[extension] = optional; } +template +inline void VulkanSample::add_layer(const char *layer, bool optional) +{ + instance_layers[layer] = optional; +} + template inline std::unique_ptr::DeviceType> VulkanSample::create_device(PhysicalDeviceType &gpu) { @@ -478,7 +490,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_layers(), headless, api_version); } template @@ -764,6 +776,12 @@ inline std::unordered_map const &VulkanSample:: return instance_extensions; } +template +inline std::unordered_map const &VulkanSample::get_layers() const +{ + return instance_layers; +} + template inline typename VulkanSample::RenderContextType const &VulkanSample::get_render_context() const { diff --git a/samples/api/hello_triangle/hello_triangle.cpp b/samples/api/hello_triangle/hello_triangle.cpp index d3a6f31d7..d8cf4a6dc 100644 --- a/samples/api/hello_triangle/hello_triangle.cpp +++ b/samples/api/hello_triangle/hello_triangle.cpp @@ -217,12 +217,12 @@ void HelloTriangle::init_instance(Context &context, #ifdef VKB_VALIDATION_LAYERS // Determine the optimal validation layers to enable that are necessary for useful debugging - std::unordered_map optimal_validation_layers_map = vkb::get_optimal_validation_layers(supported_validation_layers); + std::vector optimal_validation_layers_map = vkb::get_optimal_validation_layers(supported_validation_layers); std::vector optimal_validation_layers; optimal_validation_layers.reserve(optimal_validation_layers_map.size()); for (auto &layer : optimal_validation_layers_map) { - optimal_validation_layers.push_back(layer.first); + optimal_validation_layers.push_back(layer); } requested_validation_layers.insert(requested_validation_layers.end(), optimal_validation_layers.begin(), optimal_validation_layers.end()); #endif diff --git a/samples/extensions/shader_object/shader_object.cpp b/samples/extensions/shader_object/shader_object.cpp index 29de544a2..1684c4a85 100644 --- a/samples/extensions/shader_object/shader_object.cpp +++ b/samples/extensions/shader_object/shader_object.cpp @@ -41,6 +41,9 @@ ShaderObject::ShaderObject() // Enable extensions for sample add_device_extension(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME); + + // Enable the shader object layer if it's available. Its optional. + add_layer("VK_LAYER_KHRONOS_shader_object", false); } ShaderObject::~ShaderObject() @@ -105,13 +108,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::unordered_map ShaderObject::get_validation_layers() -{ - return {{"VK_LAYER_KHRONOS_shader_object", false}}; -} - bool ShaderObject::resize(const uint32_t _width, const uint32_t _height) { if (!has_device()) @@ -232,7 +228,7 @@ void ShaderObject::setup_render_pass() // delete existing render pass if (render_pass != VK_NULL_HANDLE) { - vkDestroyRenderPass(device->get_handle(), render_pass, VK_NULL_HANDLE); + vkDestroyRenderPass(get_device().get_handle(), render_pass, VK_NULL_HANDLE); } VkAttachmentDescription color_attachment{}; diff --git a/samples/extensions/shader_object/shader_object.h b/samples/extensions/shader_object/shader_object.h index 953ef4ab1..29be564e5 100644 --- a/samples/extensions/shader_object/shader_object.h +++ b/samples/extensions/shader_object/shader_object.h @@ -128,8 +128,6 @@ class ShaderObject : public ApiVulkanSample ShaderObject(); ~ShaderObject() override; - const std::unordered_map 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;