From fcf9bfa19e4cd7bda8335537ee8ed692a170d627 Mon Sep 17 00:00:00 2001 From: Romain BOULLARD Date: Wed, 9 Sep 2026 00:31:38 +0200 Subject: [PATCH] VulkanInstance --- .../GraphicsInterface/GraphicsInstance.hpp | 43 +++++ .../Graphics/GraphicsVulkan/CMakeLists.txt | 3 +- .../Include/GraphicsVulkan/VulkanInclude.hpp | 13 ++ .../Include/GraphicsVulkan/VulkanInstance.hpp | 59 +++++++ .../GraphicsVulkan/VulkanInstance.cpp | 160 ++++++++++++++++++ .../GraphicsVulkan/VulkanFormatters.cpp | 1 + .../GraphicsVulkan/VulkanInstance.cpp | 26 +++ 7 files changed, 304 insertions(+), 1 deletion(-) create mode 100644 Bigfoot/Libs/Graphics/GraphicsInterface/Include/GraphicsInterface/GraphicsInstance.hpp create mode 100644 Bigfoot/Libs/Graphics/GraphicsVulkan/Include/GraphicsVulkan/VulkanInclude.hpp create mode 100644 Bigfoot/Libs/Graphics/GraphicsVulkan/Include/GraphicsVulkan/VulkanInstance.hpp create mode 100644 Bigfoot/Libs/Graphics/GraphicsVulkan/VulkanInstance.cpp create mode 100644 Bigfoot/Tests/Graphics/GraphicsVulkan/VulkanInstance.cpp diff --git a/Bigfoot/Libs/Graphics/GraphicsInterface/Include/GraphicsInterface/GraphicsInstance.hpp b/Bigfoot/Libs/Graphics/GraphicsInterface/Include/GraphicsInterface/GraphicsInstance.hpp new file mode 100644 index 0000000..82b0420 --- /dev/null +++ b/Bigfoot/Libs/Graphics/GraphicsInterface/Include/GraphicsInterface/GraphicsInstance.hpp @@ -0,0 +1,43 @@ +/********************************************************************* + * \file GraphicsInstance.hpp + * + * \author Romain BOULLARD + * \date September 2026 + *********************************************************************/ +#ifndef BIGFOOT_GRAPHICSINTERFACE_GRAPHICSINSTANCE_HPP +#define BIGFOOT_GRAPHICSINTERFACE_GRAPHICSINSTANCE_HPP +#include +#include + +#include + +#include +#include +#include + +namespace Bigfoot +{ +class GraphicsInstance +{ + public: + virtual ~GraphicsInstance() = default; + + GraphicsInstance(const GraphicsInstance& p_instance) = delete; + GraphicsInstance(GraphicsInstance&& p_instance) = delete; + + GraphicsInstance& operator=(const GraphicsInstance& p_instance) = delete; + GraphicsInstance& operator=(GraphicsInstance&& p_instance) = delete; + + protected: + GraphicsInstance() = default; +}; + +/****************************************************************************************/ + +using GraphicsInstanceFactory = + Factory(eastl::string_view, Version)>>; +} // namespace Bigfoot + +#endif diff --git a/Bigfoot/Libs/Graphics/GraphicsVulkan/CMakeLists.txt b/Bigfoot/Libs/Graphics/GraphicsVulkan/CMakeLists.txt index 0b72187..2120d98 100644 --- a/Bigfoot/Libs/Graphics/GraphicsVulkan/CMakeLists.txt +++ b/Bigfoot/Libs/Graphics/GraphicsVulkan/CMakeLists.txt @@ -7,7 +7,8 @@ set(PublicDependencies set(PrivateDependencies) set(BigfootPublicDependencies GraphicsInterface) -set(BigfootPrivateDependencies) +set(BigfootPrivateDependencies + Engine) bigfoot_create_package_lib( "${PublicDependencies}" diff --git a/Bigfoot/Libs/Graphics/GraphicsVulkan/Include/GraphicsVulkan/VulkanInclude.hpp b/Bigfoot/Libs/Graphics/GraphicsVulkan/Include/GraphicsVulkan/VulkanInclude.hpp new file mode 100644 index 0000000..438e828 --- /dev/null +++ b/Bigfoot/Libs/Graphics/GraphicsVulkan/Include/GraphicsVulkan/VulkanInclude.hpp @@ -0,0 +1,13 @@ +/********************************************************************* + * \file VulkanInclude.hpp + * + * \author Romain BOULLARD + * \date September 2026 + *********************************************************************/ +#ifndef BIGFOOT_GRAPHICSVULKAN_VULKANINCLUDE_HPP +#define BIGFOOT_GRAPHICSVULKAN_VULKANINCLUDE_HPP +#define VULKAN_HPP_ASSERT(result) +#define VULKAN_HPP_ASSERT_ON_RESULT(result) +#include + +#endif diff --git a/Bigfoot/Libs/Graphics/GraphicsVulkan/Include/GraphicsVulkan/VulkanInstance.hpp b/Bigfoot/Libs/Graphics/GraphicsVulkan/Include/GraphicsVulkan/VulkanInstance.hpp new file mode 100644 index 0000000..327331a --- /dev/null +++ b/Bigfoot/Libs/Graphics/GraphicsVulkan/Include/GraphicsVulkan/VulkanInstance.hpp @@ -0,0 +1,59 @@ +/********************************************************************* + * \file VulkanInstance.hpp + * + * \author Romain BOULLARD + * \date September 2026 + *********************************************************************/ +#ifndef BIGFOOT_GRAPHICSVULKAN_VULKANINSTANCE_HPP +#define BIGFOOT_GRAPHICSVULKAN_VULKANINSTANCE_HPP +#include + +#include + +#include +#include + +#include + +namespace Bigfoot::Vulkan +{ +class VulkanInstance final: public GraphicsInstance +{ + public: + /** + * Constructor. Creates a vk::Instance + * + * \param p_applicationName The name of the application + * \param p_applicationVersion The version of the application + */ + VulkanInstance(eastl::string_view p_applicationName, Version p_applicationVersion); + + ~VulkanInstance() override; + + /** + * Get the underlying Vulkan instance handle + * + * \return The vk::Instance handle + */ + [[nodiscard]] + vk::Instance GetHandle() const; + + private: + /** + * The vulkan loader. + */ + vk::detail::DynamicLoader m_loader; + + /** + * The vulkan instance. + */ + vk::Instance m_instance; + + /** + * The debug messenger (used for validation callbacks). + */ + BIGFOOT_NOT_OPTIMIZED_ONLY(vk::DebugUtilsMessengerEXT m_debugMessenger); +}; +} // namespace Bigfoot::Vulkan + +#endif diff --git a/Bigfoot/Libs/Graphics/GraphicsVulkan/VulkanInstance.cpp b/Bigfoot/Libs/Graphics/GraphicsVulkan/VulkanInstance.cpp new file mode 100644 index 0000000..5c5521c --- /dev/null +++ b/Bigfoot/Libs/Graphics/GraphicsVulkan/VulkanInstance.cpp @@ -0,0 +1,160 @@ +/********************************************************************* + * \file VulkanInstance.cpp + * + * \author Romain BOULLARD + * \date September 2026 + *********************************************************************/ +#include + +#include +#include + +#include + +#include +#include +#include + +#include +#include + +VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE + +namespace Bigfoot::Vulkan +{ +[[nodiscard]] +std::uint32_t ToVulkanVersion(const Bigfoot::Version p_version) +{ + return VK_MAKE_VERSION(p_version.GetMajor(), p_version.GetMinor(), p_version.GetPatch()); +} + +/****************************************************************************************/ + +#ifdef BIGFOOT_NOT_OPTIMIZED +vk::Bool32 VulkanDebugCallback(const vk::DebugUtilsMessageSeverityFlagBitsEXT p_severity, + [[maybe_unused]] vk::DebugUtilsMessageTypeFlagsEXT p_type, + const vk::DebugUtilsMessengerCallbackDataEXT* p_callbackData, + [[maybe_unused]] void* p_userData) +{ + switch (p_severity) + { + case vk::DebugUtilsMessageSeverityFlagBitsEXT::eError: + BIGFOOT_LOG_ERROR(::Bigfoot::GRAPHICSVULKAN_LOGGER, "{}", p_callbackData->pMessage); + break; + case vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning: + BIGFOOT_LOG_WARN(::Bigfoot::GRAPHICSVULKAN_LOGGER, "{}", p_callbackData->pMessage); + break; + case vk::DebugUtilsMessageSeverityFlagBitsEXT::eInfo: + BIGFOOT_LOG_INFO(::Bigfoot::GRAPHICSVULKAN_LOGGER, "{}", p_callbackData->pMessage); + break; + case vk::DebugUtilsMessageSeverityFlagBitsEXT::eVerbose: + default: + BIGFOOT_LOG_TRACE(::Bigfoot::GRAPHICSVULKAN_LOGGER, "{}", p_callbackData->pMessage); + break; + } + return VK_FALSE; +} +#endif + +/****************************************************************************************/ + +VulkanInstance::VulkanInstance(const eastl::string_view p_applicationName, const Version p_applicationVersion) +{ + const PFN_vkGetInstanceProcAddr getInstanceProcAddr = m_loader.getProcAddress( + "vkGetInstanceProcAddr"); + CRITICAL_ASSERT(GraphicsVulkanAssertHandler, getInstanceProcAddr != nullptr, "vkGetInstanceProcAddr not found!"); + + VULKAN_HPP_DEFAULT_DISPATCHER.init(getInstanceProcAddr); + + const eastl::string applicationName {p_applicationName}; + const vk::ApplicationInfo applicationInfo {applicationName.c_str(), + ToVulkanVersion(p_applicationVersion), + BIGFOOT_NAME.data(), + ToVulkanVersion(BIGFOOT_VERSION), + VK_API_VERSION_1_3}; + + eastl::vector enabledLayers; + eastl::vector enabledExtensions { + VK_KHR_SURFACE_EXTENSION_NAME, + BIGFOOT_WINDOWS_OR_LINUX(VK_KHR_WIN32_SURFACE_EXTENSION_NAME, VK_KHR_XLIB_SURFACE_EXTENSION_NAME)}; + +#ifdef BIGFOOT_NOT_OPTIMIZED + const vk::ResultValue> availableLayers = vk::enumerateInstanceLayerProperties(); + CRITICAL_ASSERT(GraphicsVulkanAssertHandler, + availableLayers.result == vk::Result::eSuccess, + "({}) Failed to enumerate Vulkan instance layers", + availableLayers.result); + + const bool validationLayerAvailable = eastl::find_if(availableLayers.value.begin(), + availableLayers.value.end(), + [](const vk::LayerProperties& p_layer) + { + return eastl::string_view {p_layer.layerName.data()} == + "VK_LAYER_KHRONOS_validation"; + }) != availableLayers.value.end(); + + if (validationLayerAvailable) + { + enabledLayers.push_back("VK_LAYER_KHRONOS_validation"); + enabledExtensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); + } + else + { + BIGFOOT_LOG_WARN(GRAPHICSVULKAN_LOGGER, "Vulkan validation layer requested but not available"); + } +#endif + + const vk::InstanceCreateInfo instanceCreateInfo {{}, &applicationInfo, enabledLayers, enabledExtensions}; + + const vk::ResultValue instance = vk::createInstance(instanceCreateInfo); + CRITICAL_ASSERT(GraphicsVulkanAssertHandler, + instance.result == vk::Result::eSuccess, + "({}) Failed to create Vulkan instance", + instance.result); + m_instance = instance.value; + + VULKAN_HPP_DEFAULT_DISPATCHER.init(m_instance); + +#ifdef BIGFOOT_NOT_OPTIMIZED + if (validationLayerAvailable) + { + vk::DebugUtilsMessengerCreateInfoEXT messengerCreateInfo {}; + messengerCreateInfo.messageSeverity = vk::DebugUtilsMessageSeverityFlagsEXT { + vk::DebugUtilsMessageSeverityFlagBitsEXT::eVerbose | vk::DebugUtilsMessageSeverityFlagBitsEXT::eInfo | + vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning | vk::DebugUtilsMessageSeverityFlagBitsEXT::eError}; + messengerCreateInfo.messageType = vk::DebugUtilsMessageTypeFlagsEXT { + vk::DebugUtilsMessageTypeFlagBitsEXT::eGeneral | vk::DebugUtilsMessageTypeFlagBitsEXT::eValidation | + vk::DebugUtilsMessageTypeFlagBitsEXT::ePerformance}; + messengerCreateInfo.pfnUserCallback = &VulkanDebugCallback; + + const vk::ResultValue messenger = m_instance.createDebugUtilsMessengerEXT( + messengerCreateInfo); + CRITICAL_ASSERT(GraphicsVulkanAssertHandler, + messenger.result == vk::Result::eSuccess, + "({}) Failed to create Vulkan debug messenger", + messenger.result); + m_debugMessenger = messenger.value; + } +#endif +} + +/****************************************************************************************/ + +VulkanInstance::~VulkanInstance() +{ +#ifdef BIGFOOT_NOT_OPTIMIZED + if (m_debugMessenger) + { + m_instance.destroyDebugUtilsMessengerEXT(m_debugMessenger); + } +#endif + m_instance.destroy(); +} + +/****************************************************************************************/ + +vk::Instance VulkanInstance::GetHandle() const +{ + return m_instance; +} +} // namespace Bigfoot::Vulkan diff --git a/Bigfoot/Tests/Graphics/GraphicsVulkan/VulkanFormatters.cpp b/Bigfoot/Tests/Graphics/GraphicsVulkan/VulkanFormatters.cpp index 465616c..0c2b866 100644 --- a/Bigfoot/Tests/Graphics/GraphicsVulkan/VulkanFormatters.cpp +++ b/Bigfoot/Tests/Graphics/GraphicsVulkan/VulkanFormatters.cpp @@ -23,6 +23,7 @@ namespace Bigfoot::Vulkan { class VulkanFormattersFixture: public ::testing::Test { + protected: }; /****************************************************************************************/ diff --git a/Bigfoot/Tests/Graphics/GraphicsVulkan/VulkanInstance.cpp b/Bigfoot/Tests/Graphics/GraphicsVulkan/VulkanInstance.cpp new file mode 100644 index 0000000..bc75e92 --- /dev/null +++ b/Bigfoot/Tests/Graphics/GraphicsVulkan/VulkanInstance.cpp @@ -0,0 +1,26 @@ +/********************************************************************* + * \file VulkanInstance.cpp + * + * \author Romain BOULLARD + * \date September 2026 + *********************************************************************/ +#include + +#include + +namespace Bigfoot::Vulkan +{ +class VulkanInstanceFixture: public ::testing::Test +{ + protected: +}; + +/****************************************************************************************/ + +TEST_F(VulkanInstanceFixture, Constructor_ShouldCreateAValidInstance) +{ + const VulkanInstance instance {"VulkanInstanceTests", Version {1, 0, 0}}; + + EXPECT_TRUE(instance.GetHandle()); +} +} // namespace Bigfoot::Vulkan