VulkanInstance

This commit is contained in:
2026-09-09 00:31:38 +02:00
parent 6895daa676
commit fcf9bfa19e
7 changed files with 304 additions and 1 deletions
@@ -0,0 +1,43 @@
/*********************************************************************
* \file GraphicsInstance.hpp
*
* \author Romain BOULLARD
* \date September 2026
*********************************************************************/
#ifndef BIGFOOT_GRAPHICSINTERFACE_GRAPHICSINSTANCE_HPP
#define BIGFOOT_GRAPHICSINTERFACE_GRAPHICSINSTANCE_HPP
#include <Utils/Factory.hpp>
#include <Utils/Version.hpp>
#include <GraphicsInterface/GraphicsAPI_generated.hpp>
#include <EASTL/functional.h>
#include <EASTL/string_view.h>
#include <EASTL/unique_ptr.h>
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<GraphicsInstance,
GraphicsAPI,
eastl::function<eastl::unique_ptr<GraphicsInstance>(eastl::string_view, Version)>>;
} // namespace Bigfoot
#endif
@@ -7,7 +7,8 @@ set(PublicDependencies
set(PrivateDependencies)
set(BigfootPublicDependencies
GraphicsInterface)
set(BigfootPrivateDependencies)
set(BigfootPrivateDependencies
Engine)
bigfoot_create_package_lib(
"${PublicDependencies}"
@@ -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 <vulkan/vulkan.hpp>
#endif
@@ -0,0 +1,59 @@
/*********************************************************************
* \file VulkanInstance.hpp
*
* \author Romain BOULLARD
* \date September 2026
*********************************************************************/
#ifndef BIGFOOT_GRAPHICSVULKAN_VULKANINSTANCE_HPP
#define BIGFOOT_GRAPHICSVULKAN_VULKANINSTANCE_HPP
#include <GraphicsVulkan/VulkanInclude.hpp>
#include <GraphicsInterface/GraphicsInstance.hpp>
#include <Utils/TargetMacros.h>
#include <Utils/Version.hpp>
#include <EASTL/string_view.h>
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
@@ -0,0 +1,160 @@
/*********************************************************************
* \file VulkanInstance.cpp
*
* \author Romain BOULLARD
* \date September 2026
*********************************************************************/
#include <GraphicsVulkan/VulkanInstance.hpp>
#include <GraphicsVulkan/GraphicsVulkanAssertHandler.hpp>
#include <GraphicsVulkan/VulkanFormatters.hpp>
#include <Engine/EngineInfo_generated.hpp>
#include <EASTL/algorithm.h>
#include <EASTL/string.h>
#include <EASTL/vector.h>
#include <cstdint>
#include <vector>
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<PFN_vkGetInstanceProcAddr>(
"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<const char*> enabledLayers;
eastl::vector<const char*> 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<std::vector<vk::LayerProperties>> 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<vk::Instance> 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<vk::DebugUtilsMessengerEXT> 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
@@ -23,6 +23,7 @@ namespace Bigfoot::Vulkan
{
class VulkanFormattersFixture: public ::testing::Test
{
protected:
};
/****************************************************************************************/
@@ -0,0 +1,26 @@
/*********************************************************************
* \file VulkanInstance.cpp
*
* \author Romain BOULLARD
* \date September 2026
*********************************************************************/
#include <GraphicsVulkan/VulkanInstance.hpp>
#include <gtest/gtest.h>
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