engine/src/gfx_device_vulkan.cpp

304 lines
8.4 KiB
C++
Raw Normal View History

2022-10-01 14:44:12 +00:00
// The implementation of the graphics layer using Vulkan 1.3
2022-09-13 18:25:18 +00:00
#ifdef ENGINE_BUILD_VULKAN
#include "gfx_device.hpp"
2022-10-04 10:54:23 +00:00
#include "util.hpp"
2022-09-13 18:25:18 +00:00
#include "config.h"
2022-09-13 21:43:24 +00:00
#include "log.hpp"
2022-09-13 21:55:08 +00:00
#define VOLK_IMPLEMENTATION
2022-10-09 13:57:41 +00:00
#include <volk.h>
#define VMA_STATIC_VULKAN_FUNCTIONS 0
2022-10-09 14:15:29 +00:00
#define VMA_DYNAMIC_VULKAN_FUNCTIONS 0
#define VMA_VULKAN_VERSION 1003000
2022-10-09 13:57:41 +00:00
#define VMA_IMPLEMENTATION
#include <vk_mem_alloc.h>
2022-09-13 18:25:18 +00:00
2022-09-17 00:22:35 +00:00
#include <SDL_vulkan.h>
2022-09-13 18:25:18 +00:00
#include <assert.h>
2022-09-13 21:43:24 +00:00
2022-10-02 15:34:51 +00:00
namespace engine {
2022-09-13 18:25:18 +00:00
2022-10-14 12:56:28 +00:00
// structures
struct LayerInfo {
std::vector<VkLayerProperties> layersAvailable{};
std::optional<std::vector<VkLayerProperties>::iterator> validationLayer;
};
// functions
2022-09-17 00:22:35 +00:00
static std::vector<const char*> getRequiredVulkanExtensions(SDL_Window* window)
{
SDL_bool res;
unsigned int sdlExtensionCount = 0;
res = SDL_Vulkan_GetInstanceExtensions(window, &sdlExtensionCount, nullptr);
assert(res == SDL_TRUE);
std::vector<const char*> requiredExtensions(sdlExtensionCount);
res = SDL_Vulkan_GetInstanceExtensions(window, &sdlExtensionCount, requiredExtensions.data());
assert(res == SDL_TRUE);
return requiredExtensions;
2022-10-14 12:56:28 +00:00
}
2022-09-17 00:22:35 +00:00
2022-10-14 12:56:28 +00:00
static LayerInfo getAvailableLayers(bool useValidation)
2022-09-21 19:52:26 +00:00
{
2022-10-14 12:56:28 +00:00
constexpr const char* VALIDATION_LAYER_NAME = "VK_LAYER_KHRONOS_validation";
2022-09-21 19:52:26 +00:00
2022-10-14 12:56:28 +00:00
LayerInfo info;
VkResult res;
2022-09-21 19:52:26 +00:00
2022-10-14 12:56:28 +00:00
uint32_t layerCount;
res = vkEnumerateInstanceLayerProperties(&layerCount, nullptr);
assert(res == VK_SUCCESS);
info.layersAvailable.resize(layerCount);
res = vkEnumerateInstanceLayerProperties(&layerCount, info.layersAvailable.data());
assert(res == VK_SUCCESS);
2022-09-21 19:52:26 +00:00
2022-10-14 12:56:28 +00:00
if (useValidation == true) {
// find validation layer and print all layers to log
for (auto it = info.layersAvailable.begin(); it != info.layersAvailable.end(); it++) {
if (strncmp(it->layerName, VALIDATION_LAYER_NAME, 256) == 0) {
info.validationLayer = it;
}
}
if (info.validationLayer.has_value() == false) {
throw std::runtime_error("The validation layer was not found. Quitting.");
2022-10-07 14:18:09 +00:00
}
2022-10-07 11:20:39 +00:00
}
2022-10-07 14:18:09 +00:00
2022-10-14 12:56:28 +00:00
return info;
2022-10-07 11:20:39 +00:00
}
2022-10-14 12:56:28 +00:00
static VkBool32 messengerCallback(
VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
VkDebugUtilsMessageTypeFlagsEXT messageTypes,
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
void* pUserData)
{
2022-09-22 12:15:34 +00:00
2022-10-14 12:56:28 +00:00
std::string msgType{};
if (messageTypes & VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT)
msgType += " (GENERAL)";
if (messageTypes & VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT)
msgType += " (PERF.)";
if (messageTypes & VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT)
msgType += " (VALID.)";
switch (messageSeverity) {
case VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT:
TRACE("VULKAN MESSAGE{}: ID: {} MSG: {}", msgType, pCallbackData->pMessageIdName, pCallbackData->pMessage);
break;
case VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT:
INFO("VULKAN MESSAGE{}: ID: {} MSG: {}", msgType, pCallbackData->pMessageIdName, pCallbackData->pMessage);
break;
case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT:
WARN("VULKAN MESSAGE{}: ID: {} MSG: {}", msgType, pCallbackData->pMessageIdName, pCallbackData->pMessage);
break;
case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT:
ERROR("VULKAN MESSAGE{}: ID: {} MSG: {}", msgType, pCallbackData->pMessageIdName, pCallbackData->pMessage);
break;
default:
break;
2022-09-19 08:57:02 +00:00
}
2022-10-14 12:56:28 +00:00
return VK_FALSE;
}
2022-09-13 21:43:24 +00:00
2022-10-14 12:56:28 +00:00
static VkDebugUtilsMessengerCreateInfoEXT getDebugMessengerCreateInfo()
{
VkDebugUtilsMessengerCreateInfoEXT debugMessengerInfo{
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT,
.pNext = nullptr,
.flags = 0,
.messageSeverity = 0,
.messageType =
VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT,
.pfnUserCallback = messengerCallback,
.pUserData = nullptr,
2022-09-19 17:33:56 +00:00
};
2022-10-14 12:56:28 +00:00
enum class MessageSeverity {
VERBOSE,
INFO,
WARNING,
ERROR
2022-09-17 00:22:35 +00:00
};
2022-09-13 21:43:24 +00:00
2022-10-14 12:56:28 +00:00
constexpr MessageSeverity MESSAGE_LEVEL = MessageSeverity::WARNING;
switch (MESSAGE_LEVEL) {
case MessageSeverity::VERBOSE:
debugMessengerInfo.messageSeverity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT;
// fall-through
case MessageSeverity::INFO:
debugMessengerInfo.messageSeverity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT;
// fall-through
case MessageSeverity::WARNING:
debugMessengerInfo.messageSeverity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT;
// fall-through
case MessageSeverity::ERROR:
debugMessengerInfo.messageSeverity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
// fall-through
default:
break;
}
2022-09-13 21:43:24 +00:00
2022-10-14 12:56:28 +00:00
return debugMessengerInfo;
}
2022-09-13 21:43:24 +00:00
2022-10-14 12:56:28 +00:00
struct GFXDevice::Impl {
VkInstance m_instance = VK_NULL_HANDLE;
VkDebugUtilsMessengerEXT m_debugMessenger = VK_NULL_HANDLE;
2022-09-17 00:22:35 +00:00
2022-10-14 12:56:28 +00:00
};
2022-09-17 00:22:35 +00:00
2022-10-14 12:56:28 +00:00
GFXDevice::GFXDevice(const char* appName, const char* appVersion, SDL_Window* window)
{
m_pimpl = std::make_unique<Impl>();
2022-09-17 00:22:35 +00:00
2022-10-14 12:56:28 +00:00
VkResult res;
2022-09-17 00:22:35 +00:00
2022-10-14 12:56:28 +00:00
// initialise vulkan
2022-09-13 21:43:24 +00:00
2022-10-14 12:56:28 +00:00
res = volkInitialize();
if (res == VK_ERROR_INITIALIZATION_FAILED) {
throw std::runtime_error("Unable to load vulkan, is it installed?");
}
2022-09-21 19:52:26 +00:00
2022-10-14 12:56:28 +00:00
assert(res == VK_SUCCESS);
2022-09-21 19:52:26 +00:00
2022-10-14 12:56:28 +00:00
uint32_t vulkanVersion = volkGetInstanceVersion();
if (vulkanVersion < VK_MAKE_VERSION(1, 3, 0)) {
throw std::runtime_error("The loaded Vulkan version must be at least 1.3");
}
2022-09-21 19:52:26 +00:00
2022-10-14 12:56:28 +00:00
bool useValidation;
#ifdef NDEBUG
useValidation = false; // release mode
#else
useValidation = true; // debug mode
#endif
2022-09-22 12:15:34 +00:00
2022-10-02 10:55:59 +00:00
2022-10-14 12:56:28 +00:00
// get the both the engine and application versions
int appVersionMajor = 0, appVersionMinor = 0, appVersionPatch = 0;
assert(versionFromCharArray(appVersion, &appVersionMajor, &appVersionMinor, &appVersionPatch));
int engineVersionMajor = 0, engineVersionMinor = 0, engineVersionPatch = 0;
assert(versionFromCharArray(ENGINE_VERSION, &engineVersionMajor, &engineVersionMinor, &engineVersionPatch));
2022-09-21 19:52:26 +00:00
2022-10-14 12:56:28 +00:00
VkApplicationInfo applicationInfo{
.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
.pNext = nullptr,
.pApplicationName = appName,
.applicationVersion = VK_MAKE_VERSION(appVersionMajor, appVersionMinor, appVersionPatch),
.pEngineName = "engine",
.engineVersion = VK_MAKE_VERSION(engineVersionMajor, engineVersionMinor, engineVersionPatch),
.apiVersion = VK_API_VERSION_1_3,
2022-09-21 19:52:26 +00:00
};
2022-09-19 21:10:44 +00:00
2022-09-22 12:15:34 +00:00
2022-10-14 12:56:28 +00:00
// make a list of all extensions to use
std::vector<const char*> extensions{};
2022-10-02 10:55:59 +00:00
2022-10-14 12:56:28 +00:00
const std::vector<const char*> windowExtensions = getRequiredVulkanExtensions(window);
extensions.insert(extensions.end(), windowExtensions.begin(), windowExtensions.end());
2022-10-02 10:55:59 +00:00
2022-10-14 12:56:28 +00:00
// also use debug utils extension
extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
2022-09-22 12:15:34 +00:00
2022-09-19 21:10:44 +00:00
2022-09-25 13:52:05 +00:00
2022-10-14 12:56:28 +00:00
// make a list of layers to use
std::vector<const char*> layers{};
2022-09-21 19:52:26 +00:00
2022-10-14 12:56:28 +00:00
const LayerInfo layerInfo = getAvailableLayers(useValidation);
2022-09-21 19:52:26 +00:00
2022-10-14 12:56:28 +00:00
if (layerInfo.validationLayer.has_value()) {
layers.push_back(layerInfo.validationLayer.value()->layerName);
}
2022-10-09 13:57:41 +00:00
2022-10-14 12:56:28 +00:00
VkInstanceCreateInfo instanceInfo{
.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
.pApplicationInfo = &applicationInfo,
.enabledLayerCount = (uint32_t)layers.size(),
.ppEnabledLayerNames = layers.data(),
.enabledExtensionCount = (uint32_t)extensions.size(),
.ppEnabledExtensionNames = extensions.data(),
2022-09-19 21:10:44 +00:00
};
2022-10-14 12:56:28 +00:00
// add the debug messenger
VkDebugUtilsMessengerCreateInfoEXT debugMessengerInfo;
if (layerInfo.validationLayer.has_value()) {
debugMessengerInfo = getDebugMessengerCreateInfo();
instanceInfo.pNext = &debugMessengerInfo;
}
else {
instanceInfo.pNext = nullptr;
}
2022-09-22 12:15:34 +00:00
2022-10-07 14:18:09 +00:00
2022-10-14 12:56:28 +00:00
#ifndef NDEBUG
for (const char* ext : extensions) {
TRACE("Using Vulkan instance extension: {}", ext);
}
#endif
2022-10-07 14:18:09 +00:00
2022-10-14 12:56:28 +00:00
res = vkCreateInstance(&instanceInfo, nullptr, &m_pimpl->m_instance);
if (res == VK_ERROR_INCOMPATIBLE_DRIVER) {
throw std::runtime_error("The graphics driver is incompatible with vulkan");
}
assert(res == VK_SUCCESS);
2022-10-07 14:18:09 +00:00
2022-10-14 12:56:28 +00:00
2022-10-06 15:26:29 +00:00
2022-10-14 12:56:28 +00:00
// load the instance functions
volkLoadInstanceOnly(m_pimpl->m_instance);
2022-10-09 13:57:41 +00:00
2022-09-17 00:22:35 +00:00
2022-09-13 18:25:18 +00:00
2022-10-14 12:56:28 +00:00
// create the debug messenger
{
VkDebugUtilsMessengerCreateInfoEXT createInfo = getDebugMessengerCreateInfo();
2022-09-17 00:22:35 +00:00
2022-10-14 12:56:28 +00:00
VkResult res = vkCreateDebugUtilsMessengerEXT(m_pimpl->m_instance, &createInfo, nullptr, &m_pimpl->m_debugMessenger);
assert(res == VK_SUCCESS);
2022-10-01 14:44:12 +00:00
}
2022-09-13 18:25:18 +00:00
}
2022-09-21 19:52:26 +00:00
GFXDevice::~GFXDevice()
2022-09-13 18:25:18 +00:00
{
2022-09-21 19:52:26 +00:00
TRACE("Destroying GFXDevice...");
2022-10-14 12:56:28 +00:00
vkDestroyDebugUtilsMessengerEXT(m_pimpl->m_instance, m_pimpl->m_debugMessenger, nullptr);
vkDestroyInstance(m_pimpl->m_instance, nullptr);
2022-09-13 18:25:18 +00:00
}
2022-10-02 12:56:13 +00:00
void GFXDevice::draw()
{
2022-10-06 15:26:29 +00:00
2022-10-02 12:56:13 +00:00
}
2022-10-08 11:28:36 +00:00
bool GFXDevice::createBuffer(const gfx::BufferDesc& desc, const void* data, gfx::BufferHandle* out)
{
return false;
}
2022-09-13 18:25:18 +00:00
}
2022-09-21 19:52:26 +00:00
#endif