diff --git a/framework/core/hpp_instance.cpp b/framework/core/hpp_instance.cpp index 60ef351fb..95ed680f2 100644 --- a/framework/core/hpp_instance.cpp +++ b/framework/core/hpp_instance.cpp @@ -74,6 +74,41 @@ static VKAPI_ATTR VkBool32 VKAPI_CALL debug_callback(VkDebugReportFlagsEXT flags } #endif +bool validate_layers(std::unordered_map &required, + const std::vector &available) +{ + std::vector remove_vec; + for (auto layer : required) + { + bool found = false; + for (auto &available_layer : available) + { + if (strcmp(available_layer.layerName, layer.first) == 0) + { + found = true; + break; + } + } + + if (!found) + { + if (!layer.second) + { + LOGW("Optional Layer {} not found, removing it", layer.first) + remove_vec.push_back(layer.first); + continue; + } + LOGE("Validation Layer {} not found", layer.first) + return false; + } + } + for (auto &rem : remove_vec) + { + required.erase(rem); + } + return true; +} + bool validate_layers(const std::vector &required, const std::vector &available) { @@ -186,6 +221,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::unordered_map &requested_layers, bool headless, uint32_t api_version) { @@ -299,6 +335,20 @@ HPPInstance::HPPInstance(const std::string &applicati throw std::runtime_error("Required validation layers are missing."); } + std::unordered_map layers = (std::unordered_map) (requested_layers); + if (validate_layers(layers, supported_validation_layers)) + { + 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, requested_validation_layers, enabled_extensions); diff --git a/framework/core/hpp_instance.h b/framework/core/hpp_instance.h index f247d8bb2..53e4560cd 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 requested_layers The layers that are requested to be enabled (second parameter in unordered map is if required). * @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::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 06131f0ba..255121f04 100644 --- a/framework/core/instance.cpp +++ b/framework/core/instance.cpp @@ -76,6 +76,41 @@ static VKAPI_ATTR VkBool32 VKAPI_CALL debug_callback(VkDebugReportFlagsEXT flags } #endif +bool validate_layers(std::unordered_map &required, + const std::vector &available) +{ + std::vector remove_vec; + for (auto layer : required) + { + bool found = false; + for (auto &available_layer : available) + { + if (strcmp(available_layer.layerName, layer.first) == 0) + { + found = true; + break; + } + } + + if (!found) + { + if (!layer.second) + { + LOGW("Optional Layer {} not found, removing it", layer.first) + remove_vec.push_back(layer.first); + continue; + } + LOGE("Validation Layer {} not found", layer.first) + return false; + } + } + for (auto &rem : remove_vec) + { + required.erase(rem); + } + return true; +} + bool validate_layers(const std::vector &required, const std::vector &available) { @@ -186,6 +221,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::unordered_map &requested_layers, bool headless, uint32_t api_version) { @@ -311,6 +347,20 @@ Instance::Instance(const std::string &application_nam throw std::runtime_error("Required validation layers are missing."); } + std::unordered_map layers = (std::unordered_map) (requested_layers); + if (validate_layers(layers, supported_validation_layers)) + { + 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}; app_info.pApplicationName = application_name.c_str(); diff --git a/framework/core/instance.h b/framework/core/instance.h index eba3deb87..36e2f1c18 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 requested_layers The layers that are requested to be enabled (second parameter in unordered map is if required). * @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::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 c631d50ff..d4747703e 100644 --- a/framework/vulkan_sample.h +++ b/framework/vulkan_sample.h @@ -27,7 +27,7 @@ #include "scene_graph/scripts/animation.h" #if defined(PLATFORM__MACOS) -#include +# include #endif namespace vkb @@ -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,7 @@ 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 +464,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 +489,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 +775,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 { @@ -957,9 +974,9 @@ inline bool VulkanSample::prepare(const ApplicationOptions &options // initialize C++-Bindings default dispatcher, first step #if TARGET_OS_IPHONE - static vk::DynamicLoader dl("vulkan.framework/vulkan"); + static vk::DynamicLoader dl("vulkan.framework/vulkan"); #else - static vk::DynamicLoader dl; + static vk::DynamicLoader dl; #endif VULKAN_HPP_DEFAULT_DISPATCHER.init(dl.getProcAddress("vkGetInstanceProcAddr")); diff --git a/samples/api/hello_triangle/hello_triangle.cpp b/samples/api/hello_triangle/hello_triangle.cpp index e3a5f8eff..ea27053e6 100644 --- a/samples/api/hello_triangle/hello_triangle.cpp +++ b/samples/api/hello_triangle/hello_triangle.cpp @@ -162,10 +162,10 @@ void HelloTriangle::init_instance(Context &context, { LOGI("Initializing vulkan instance."); - if (volkInitialize()) - { - throw std::runtime_error("Failed to initialize volk."); - } + if (volkInitialize()) + { + throw std::runtime_error("Failed to initialize volk."); + } uint32_t instance_extension_count; VK_CHECK(vkEnumerateInstanceExtensionProperties(nullptr, &instance_extension_count, nullptr)); diff --git a/samples/extensions/shader_object/README.adoc b/samples/extensions/shader_object/README.adoc index c7e50cc22..4962363db 100644 --- a/samples/extensions/shader_object/README.adoc +++ b/samples/extensions/shader_object/README.adoc @@ -1,5 +1,5 @@ //// -- Copyright 2023 Nintendo +- Copyright 2024 Nintendo - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. @@ -436,13 +436,15 @@ 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. +This +sample repurposes this mechanism to instead load the emulation layer. NB: the layer is set to be optional as that's +what the false does. [,CPP] ---- -const std::vector ShaderObject::get_validation_layers() +const std::unordered_map ShaderObject::get_validation_layers() { - return {"VK_LAYER_KHRONOS_shader_object"}; + return {"VK_LAYER_KHRONOS_shader_object", false}; } ---- diff --git a/samples/extensions/shader_object/shader_object.cpp b/samples/extensions/shader_object/shader_object.cpp index c85ad3312..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::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()) @@ -229,6 +225,11 @@ void ShaderObject::setup_framebuffer() // Create render pass for UI drawing void ShaderObject::setup_render_pass() { + // delete existing render pass + if (render_pass != VK_NULL_HANDLE) + { + vkDestroyRenderPass(get_device().get_handle(), render_pass, VK_NULL_HANDLE); + } VkAttachmentDescription color_attachment{}; // Color attachment set to load color and ignore stencil @@ -414,6 +415,10 @@ void ShaderObject::load_assets() VkSamplerCreateInfo sampler_create_info = vkb::initializers::sampler_create_info(); + // destroy created sampler before re-creating + vkDestroySampler(get_device().get_handle(), heightmap_texture.sampler, nullptr); + vkDestroySampler(get_device().get_handle(), terrain_array_textures.sampler, nullptr); + // Setup a mirroring sampler for the height map vkDestroySampler(get_device().get_handle(), heightmap_texture.sampler, nullptr); sampler_create_info.magFilter = filter; @@ -1950,7 +1955,7 @@ void ShaderObject::build_linked_shaders(VkDevice device, ShaderObject::Shader *v shader_create.flags |= VK_SHADER_CREATE_LINK_STAGE_BIT_EXT; } - VkShaderEXT shaderEXTs[2]; + VkShaderEXT shaderEXTs[2] = {VK_NULL_HANDLE, VK_NULL_HANDLE}; // Create the shader objects VkResult result = vkCreateShadersEXT(device, diff --git a/samples/extensions/shader_object/shader_object.h b/samples/extensions/shader_object/shader_object.h index f56819460..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::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;