diff --git a/include/vulkan/graphics.h b/include/vulkan/graphics.h index e93c4bc..fc95e78 100644 --- a/include/vulkan/graphics.h +++ b/include/vulkan/graphics.h @@ -9,15 +9,20 @@ class Graphics final { Graphics(gsl::not_null window); ~Graphics(); - private: void InitializeVulkan(); void CreateInstance(); - static gsl::span GetSuggestedExtentions(); + std::vector GetRequiredInstanceExtentions(); + + static gsl::span GetSuggestedInstanceExtentions(); static std::vector GetSupprotedInstanceExtensions(); static bool AreAllExtensionsSupported(gsl::span extensions); + static std::vector GetSupprotedValidationLayers(); + static bool AreAllLayersSupported(gsl::span extensions); + VkInstance instance_ = nullptr; gsl::not_null window_; + bool validation_enabled_ = false; }; } // namespace veng diff --git a/src/vulkan/graphics.cpp b/src/vulkan/graphics.cpp index 4912f64..733909a 100644 --- a/src/vulkan/graphics.cpp +++ b/src/vulkan/graphics.cpp @@ -2,11 +2,45 @@ #include +#include + #include "precomp.h" namespace veng { +static VKAPI_ATTR VkBool32 VKAPI_CALL +ValidationCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, + VkDebugUtilsMessageTypeFlagsEXT messageTypes, + const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, + void* pUserData) { + if (messageSeverity >= VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) { + std::cerr << "Validation Error : " << pCallbackData->pMessage << std::endl; + } else { + std::cout << "Validation Message : " << pCallbackData->pMessage + << std::endl; + } + return VK_FALSE; +} + +static VkDebugUtilsMessengerCreateInfoEXT GetCreateMessengerInfo() { + VkDebugUtilsMessengerCreateInfoEXT creation_info = {}; + creation_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT; + creation_info.messageSeverity = + VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT; + creation_info.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT; + creation_info.pfnUserCallback = ValidationCallback; + creation_info.pUserData = nullptr; + + return creation_info; +} + Graphics::Graphics(gsl::not_null window) : window_(window) { +#if !defined(NDEBUG) + validation_enabled_ = true; +#endif InitializeVulkan(); } @@ -17,8 +51,13 @@ Graphics::~Graphics() { void Graphics::InitializeVulkan() { CreateInstance(); } void Graphics::CreateInstance() { - gsl::span suggested_extentions = GetSuggestedExtentions(); - if (!AreAllExtensionsSupported(suggested_extentions)) std::exit(EXIT_FAILURE); + std::array validation_layers = { + "VK_LAYER_KHRONOS_validation"}; + + if (!AreAllLayersSupported(validation_layers)) validation_enabled_ = false; + + std::vector required_extentions = + GetRequiredInstanceExtentions(); VkApplicationInfo app_info = {}; app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; @@ -33,24 +72,48 @@ void Graphics::CreateInstance() { instance_creation_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; instance_creation_info.pNext = nullptr; instance_creation_info.pApplicationInfo = &app_info; - instance_creation_info.enabledExtensionCount = suggested_extentions.size(); - instance_creation_info.ppEnabledExtensionNames = suggested_extentions.data(); - instance_creation_info.enabledLayerCount = 0; + instance_creation_info.enabledExtensionCount = required_extentions.size(); + instance_creation_info.ppEnabledExtensionNames = required_extentions.data(); + + VkDebugUtilsMessengerCreateInfoEXT messenger_create_info = + GetCreateMessengerInfo(); + if (validation_enabled_) { + instance_creation_info.pNext = &messenger_create_info; + instance_creation_info.enabledLayerCount = validation_layers.size(); + instance_creation_info.ppEnabledLayerNames = validation_layers.data(); + } else { + instance_creation_info.enabledLayerCount = 0; + instance_creation_info.ppEnabledLayerNames = nullptr; + } VkResult result = vkCreateInstance(&instance_creation_info, nullptr, &instance_); if (result != VK_SUCCESS) std::exit(EXIT_FAILURE); } -gsl::span Graphics::GetSuggestedExtentions() { +gsl::span Graphics::GetSuggestedInstanceExtentions() { std::uint32_t glfw_extention_count = 0; gsl::czstring* glfw_extentions = glfwGetRequiredInstanceExtensions(&glfw_extention_count); return {glfw_extentions, glfw_extention_count}; } +std::vector Graphics::GetRequiredInstanceExtentions() { + gsl::span suggested_extentions = + GetSuggestedInstanceExtentions(); + std::vector required_extentions(suggested_extentions.size()); + std::copy(suggested_extentions.begin(), suggested_extentions.end(), + required_extentions.begin()); + + if (validation_enabled_) + required_extentions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); + + if (!AreAllExtensionsSupported(suggested_extentions)) std::exit(EXIT_FAILURE); + + return required_extentions; +} + std::vector Graphics::GetSupprotedInstanceExtensions() { - VkExtensionProperties buffer[32]; std::uint32_t count; vkEnumerateInstanceExtensionProperties(nullptr, &count, nullptr); @@ -81,4 +144,32 @@ bool Graphics::AreAllExtensionsSupported(gsl::span extensions) { std::bind_front(IsExtensionSupported, supported_extensions)); } +std::vector Graphics::GetSupprotedValidationLayers() { + std::uint32_t count; + vkEnumerateInstanceLayerProperties(&count, nullptr); + + if (count == 0) return {}; + + std::vector properties(count); + vkEnumerateInstanceLayerProperties(&count, properties.data()); + return properties; +} + +bool LayerMatchesName(gsl::czstring name, const VkLayerProperties& properties) { + return streq(properties.layerName, name); +} + +bool IsLayerSupported(gsl::span layers, gsl::czstring name) { + return std::any_of(layers.begin(), layers.end(), + std::bind_front(LayerMatchesName, name)); +} + +bool Graphics::AreAllLayersSupported(gsl::span layers) { + std::vector supported_layers = + GetSupprotedValidationLayers(); + + return std::all_of(layers.begin(), layers.end(), + std::bind_front(IsLayerSupported, supported_layers)); +} + } // namespace veng