Skip to content

Commit

Permalink
Refactor validation layers to use vector instead of map
Browse files Browse the repository at this point in the history
Related functions and variables have been updated to accommodate the change. This ensures consistency and optimizes the performance for layer searches and validations.
  • Loading branch information
gpx1000 committed May 16, 2024
1 parent d1cb82d commit 892f289
Show file tree
Hide file tree
Showing 8 changed files with 138 additions and 59 deletions.
72 changes: 52 additions & 20 deletions framework/core/hpp_instance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,34 +106,58 @@ bool validate_layers(std::unordered_map<const char *, bool> &required,
{
required.erase(rem);
}
return true;
}

bool validate_layers(const std::vector<const char *> &required,
const std::vector<vk::LayerProperties> &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

namespace core
{
std::unordered_map<const char *, bool> get_optimal_validation_layers(const std::vector<vk::LayerProperties> &supported_instance_layers)
std::vector<const char *> get_optimal_validation_layers(const std::vector<vk::LayerProperties> &supported_instance_layers)
{
std::vector<std::unordered_map<const char *, bool>> validation_layer_priority_list =
std::vector<std::vector<const char *>> 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)
{
Expand Down Expand Up @@ -196,7 +220,8 @@ bool enable_all_extensions(const std::vector<const char *> required_

HPPInstance::HPPInstance(const std::string &application_name,
const std::unordered_map<const char *, bool> &required_extensions,
const std::unordered_map<const char *, bool> &required_validation_layers,
const std::vector<const char *> &required_validation_layers,
const std::unordered_map<const char *, bool> &requested_layers,
bool headless,
uint32_t api_version)
{
Expand Down Expand Up @@ -289,37 +314,44 @@ HPPInstance::HPPInstance(const std::string &applicati

std::vector<vk::LayerProperties> supported_validation_layers = vk::enumerateInstanceLayerProperties();

std::unordered_map<const char *, bool> requested_validation_layers(required_validation_layers);
std::vector<const char *> 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<const char *, bool> optimal_validation_layers = get_optimal_validation_layers(supported_validation_layers);
requested_validation_layers.insert(optimal_validation_layers.begin(), optimal_validation_layers.end());
std::vector<const char *> 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))
{
LOGI("Enabled Validation Layers:")
for (const auto &layer : requested_validation_layers)
{
LOGI(" \t{}", layer.first)
LOGI(" \t{}", layer);
}
}
else
{
throw std::runtime_error("Required validation layers are missing.");
}

std::vector<const char *> final_validation_layers;
final_validation_layers.reserve(requested_validation_layers.size());
for (auto layer : requested_validation_layers)
std::unordered_map<const char*, bool> layers = (std::unordered_map<const char*, bool>)(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;
Expand Down
5 changes: 3 additions & 2 deletions framework/core/hpp_instance.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<const char *, bool> get_optimal_validation_layers(const std::vector<vk::LayerProperties> &supported_instance_layers);
std::vector<const char *> get_optimal_validation_layers(const std::vector<vk::LayerProperties> &supported_instance_layers);

/**
* @brief A wrapper class for vk::Instance
Expand All @@ -59,7 +59,8 @@ class HPPInstance
*/
HPPInstance(const std::string &application_name,
const std::unordered_map<const char *, bool> &required_extensions = {},
const std::unordered_map<const char *, bool> &required_validation_layers = {},
const std::vector<const char *> &required_validation_layers = {},
const std::unordered_map<const char *, bool> &requested_layers = {},
bool headless = false,
uint32_t api_version = VK_API_VERSION_1_0);

Expand Down
75 changes: 54 additions & 21 deletions framework/core/instance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,31 +108,56 @@ bool validate_layers(std::unordered_map<const char *, bool> &required,
{
required.erase(rem);
}
return true;
}

bool validate_layers(const std::vector<const char *> &required,
const std::vector<VkLayerProperties> &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<const char *, bool> get_optimal_validation_layers(const std::vector<VkLayerProperties> &supported_instance_layers)
std::vector<const char *> get_optimal_validation_layers(const std::vector<VkLayerProperties> &supported_instance_layers)
{
std::vector<std::unordered_map<const char *, bool>> validation_layer_priority_list =
std::vector<std::vector<const char *>> 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)
{
Expand Down Expand Up @@ -195,7 +220,8 @@ bool enable_all_extensions(const std::vector<const char *> required_ex

Instance::Instance(const std::string &application_name,
const std::unordered_map<const char *, bool> &required_extensions,
const std::unordered_map<const char *, bool> &required_validation_layers,
const std::vector<const char *> &required_validation_layers,
const std::unordered_map<const char *, bool> &requested_layers,
bool headless,
uint32_t api_version)
{
Expand Down Expand Up @@ -300,32 +326,39 @@ Instance::Instance(const std::string &application_nam
std::vector<VkLayerProperties> supported_validation_layers(instance_layer_count);
VK_CHECK(vkEnumerateInstanceLayerProperties(&instance_layer_count, supported_validation_layers.data()));

std::unordered_map<const char *, bool> requested_validation_layers(required_validation_layers);
std::vector<const char *> 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<const char *, bool> optimal_validation_layers = get_optimal_validation_layers(supported_validation_layers);
requested_validation_layers.insert(optimal_validation_layers.begin(), optimal_validation_layers.end());
std::vector<const char *> 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))
{
LOGI("Enabled Validation Layers:")
for (const auto &layer : requested_validation_layers)
{
LOGI(" \t{}", layer.first)
LOGI(" \t{}", layer);
}
}
else
{
throw std::runtime_error("Required validation layers are missing.");
}

std::vector<const char *> final_validation_layers;
final_validation_layers.reserve(requested_validation_layers.size());
for (auto layer : requested_validation_layers)
std::unordered_map<const char*, bool> layers = (std::unordered_map<const char*, bool>)(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};
Expand All @@ -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};
Expand Down
5 changes: 3 additions & 2 deletions framework/core/instance.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<const char *, bool> get_optimal_validation_layers(const std::vector<VkLayerProperties> &supported_instance_layers);
std::vector<const char *> get_optimal_validation_layers(const std::vector<VkLayerProperties> &supported_instance_layers);

/**
* @brief A wrapper class for VkInstance
Expand All @@ -56,7 +56,8 @@ class Instance
*/
Instance(const std::string &application_name,
const std::unordered_map<const char *, bool> &required_extensions = {},
const std::unordered_map<const char *, bool> &required_validation_layers = {},
const std::vector<const char *> &required_validation_layers = {},
const std::unordered_map<const char *, bool> &requested_layers = {},
bool headless = false,
uint32_t api_version = VK_API_VERSION_1_0);

Expand Down
22 changes: 20 additions & 2 deletions framework/vulkan_sample.h
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ class VulkanSample : public vkb::Application
*
* @return Vector of additional instance layers. Default is empty vector.
*/
virtual const std::unordered_map<const char *, bool> get_validation_layers();
virtual const std::vector<const char *> get_validation_layers();

/**
* @brief Override this to customise the creation of the swapchain and render_context
Expand Down Expand Up @@ -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);

/**
Expand Down Expand Up @@ -358,6 +360,8 @@ class VulkanSample : public vkb::Application
*/
std::unordered_map<const char *, bool> const &get_instance_extensions() const;

std::unordered_map<const char *, bool> const &get_layers() const;

/// <summary>
/// PRIVATE MEMBERS
/// </summary>
Expand Down Expand Up @@ -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<const char *, bool> instance_extensions;
std::unordered_map<const char *, bool> 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;
Expand Down Expand Up @@ -459,6 +465,12 @@ inline void VulkanSample<bindingType>::add_instance_extension(const char *extens
instance_extensions[extension] = optional;
}

template <vkb::BindingType bindingType>
inline void VulkanSample<bindingType>::add_layer(const char *layer, bool optional)
{
instance_layers[layer] = optional;
}

template <vkb::BindingType bindingType>
inline std::unique_ptr<typename VulkanSample<bindingType>::DeviceType> VulkanSample<bindingType>::create_device(PhysicalDeviceType &gpu)
{
Expand All @@ -478,7 +490,7 @@ inline std::unique_ptr<typename VulkanSample<bindingType>::DeviceType> VulkanSam
template <vkb::BindingType bindingType>
inline std::unique_ptr<typename VulkanSample<bindingType>::InstanceType> VulkanSample<bindingType>::create_instance(bool headless)
{
return std::make_unique<InstanceType>(get_name(), get_instance_extensions(), get_validation_layers(), headless, api_version);
return std::make_unique<InstanceType>(get_name(), get_instance_extensions(), get_validation_layers(), get_layers(), headless, api_version);
}

template <vkb::BindingType bindingType>
Expand Down Expand Up @@ -764,6 +776,12 @@ inline std::unordered_map<const char *, bool> const &VulkanSample<bindingType>::
return instance_extensions;
}

template <vkb::BindingType bindingType>
inline std::unordered_map<const char *, bool> const &VulkanSample<bindingType>::get_layers() const
{
return instance_layers;
}

template <vkb::BindingType bindingType>
inline typename VulkanSample<bindingType>::RenderContextType const &VulkanSample<bindingType>::get_render_context() const
{
Expand Down
4 changes: 2 additions & 2 deletions samples/api/hello_triangle/hello_triangle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<const char *, bool> optimal_validation_layers_map = vkb::get_optimal_validation_layers(supported_validation_layers);
std::vector<const char *> optimal_validation_layers_map = vkb::get_optimal_validation_layers(supported_validation_layers);
std::vector<const char *> 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
Expand Down
Loading

0 comments on commit 892f289

Please sign in to comment.