Created basalt::context class and its implementation. Creates an underlying VkInstance, and if debug layers are present, creates a VkDebugUtilsMessengerEXT. There are two flags, should_free that controls whether the destructor will do anything, and using_validation_layers that states whether validation layers and debug utils have been setup. This is primarilly done to free them later and signify a runtime debug configuration.
This commit is contained in:
25
include/vulkan/basalt_context.h
Normal file
25
include/vulkan/basalt_context.h
Normal file
@@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
#include "vulkan/basalt_window.h"
|
||||
#include "containers/basalt_darray.h"
|
||||
|
||||
namespace basalt
|
||||
{
|
||||
class Context
|
||||
{
|
||||
public:
|
||||
Context(const Context& src) = delete;
|
||||
Context& operator=(const Context& src) = delete;
|
||||
Context(Context&& src) noexcept;
|
||||
Context& operator=(Context&& src) noexcept;
|
||||
|
||||
Context(const char* app_name, const basalt::darray<const char*>& required_layers, const basalt::darray<const char*>& required_extensions, uint32_t app_version=VK_MAKE_API_VERSION(1, 1, 0, 0), uint32_t vulkan_version = VK_MAKE_API_VERSION(0, 1, 2, 0));
|
||||
~Context();
|
||||
|
||||
VkInstance inst = VK_NULL_HANDLE;
|
||||
VkAllocationCallbacks* vk_alloc = VK_NULL_HANDLE;
|
||||
VkDebugUtilsMessengerEXT dbg_msger = VK_NULL_HANDLE;
|
||||
|
||||
bool should_free = true;
|
||||
bool using_validation_layers = false;
|
||||
};
|
||||
}
|
||||
147
src/vulkan/basalt_context.cpp
Normal file
147
src/vulkan/basalt_context.cpp
Normal file
@@ -0,0 +1,147 @@
|
||||
#include "vulkan/basalt_context.h"
|
||||
#include <stdexcept>
|
||||
|
||||
|
||||
static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(
|
||||
VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
|
||||
VkDebugUtilsMessageTypeFlagsEXT messageType,
|
||||
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
|
||||
void* pUserData);
|
||||
|
||||
basalt::Context::Context(Context&& src) noexcept
|
||||
{
|
||||
this->inst = src.inst;
|
||||
this->vk_alloc = src.vk_alloc;
|
||||
src.inst = VK_NULL_HANDLE;
|
||||
src.vk_alloc = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
basalt::Context& basalt::Context::operator=(Context&& src) noexcept
|
||||
{
|
||||
if (&src == this) return *this;
|
||||
if (this->inst == src.inst && this->inst != VK_NULL_HANDLE)
|
||||
vkDestroyInstance(this->inst, this->vk_alloc);
|
||||
this->inst = src.inst;
|
||||
this->vk_alloc = src.vk_alloc;
|
||||
src.inst = VK_NULL_HANDLE;
|
||||
src.vk_alloc = VK_NULL_HANDLE;
|
||||
return *this;
|
||||
}
|
||||
|
||||
basalt::Context::Context(const char* app_name,
|
||||
const basalt::darray<const char*>& required_layers,
|
||||
const basalt::darray<const char*>& required_extensions,
|
||||
uint32_t app_version, uint32_t vulkan_version)
|
||||
{
|
||||
VkDebugUtilsMessengerCreateInfoEXT dbg_ci = { VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT };
|
||||
VkResult err = VK_SUCCESS;
|
||||
|
||||
VkApplicationInfo appinfo = { VK_STRUCTURE_TYPE_APPLICATION_INFO };
|
||||
appinfo.apiVersion = vulkan_version;
|
||||
appinfo.applicationVersion = app_version;
|
||||
appinfo.engineVersion = VK_MAKE_API_VERSION(0, 1, 0, 0);
|
||||
appinfo.pApplicationName = app_name;
|
||||
appinfo.pEngineName = "basalt";
|
||||
appinfo.pNext = VK_NULL_HANDLE;
|
||||
|
||||
VkInstanceCreateInfo ci = { VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO };
|
||||
ci.pApplicationInfo = &appinfo;
|
||||
|
||||
u32 n_exts;
|
||||
const char** glfw_exts = glfwGetRequiredInstanceExtensions(&n_exts);
|
||||
basalt::darray<const char*> exts(required_extensions.m_nelements + n_exts);
|
||||
exts.push_back(glfw_exts, glfw_exts + n_exts);
|
||||
exts.push_back(required_extensions);
|
||||
|
||||
ci.enabledExtensionCount = exts.m_nelements;
|
||||
ci.ppEnabledExtensionNames = exts.m_pdata;
|
||||
|
||||
u32 n_layers = 0;
|
||||
VkLayerProperties* p_layers = nullptr;
|
||||
VK_ASSERT(vkEnumerateInstanceLayerProperties(&n_layers, nullptr), "Failed to enumerate instance layer properties\n\tAt %s:%d\n\tError %s\n", string_VkResult(err));
|
||||
p_layers = basalt::mem::allocT<VkLayerProperties>(n_layers, MEMORY_TAG_CLASS_ARRAY | MEMORY_TAG_ZONE_ENGINE | MEMORY_TAG_ALIGN_ANY);
|
||||
VK_ASSERT(vkEnumerateInstanceLayerProperties(&n_layers, p_layers), "Failed to enumerate instance layer properties\n\tAt %s:%d\n\tError %s\n", string_VkResult(err));
|
||||
for (u32 i = 0; i < required_layers.m_nelements; ++i)
|
||||
{
|
||||
bool found = false;
|
||||
this->using_validation_layers |= strcmp(required_layers[i], "VK_LAYER_KHRONOS_validation") == 0;
|
||||
for (u32 j = 0; j < n_layers; ++j)
|
||||
{
|
||||
if (strcmp(p_layers[j].layerName, required_layers[i]) == 0)
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
BASSERT_FATAL(found, "Assertion %s failed at %s:%d\n\nRequired instance layer %s is not present\n", required_layers[i]);
|
||||
}
|
||||
ci.enabledLayerCount = required_layers.m_nelements;
|
||||
ci.ppEnabledLayerNames = required_layers.m_pdata;
|
||||
|
||||
if (this->using_validation_layers)
|
||||
{
|
||||
dbg_ci.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT;
|
||||
dbg_ci.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;
|
||||
dbg_ci.pfnUserCallback = debugCallback;
|
||||
dbg_ci.pUserData = this;
|
||||
ci.pNext = &dbg_ci;
|
||||
}
|
||||
|
||||
VK_ASSERT(vkCreateInstance(&ci, this->vk_alloc, &this->inst), "Failed to create vulkan instance\n\tAt %s:%d\n\tError %s\n", string_VkResult(err));
|
||||
basalt::mem::dealloc(p_layers, n_layers*sizeof(VkLayerProperties), MEMORY_TAG_CLASS_ARRAY | MEMORY_TAG_ZONE_ENGINE | MEMORY_TAG_ALIGN_ANY);
|
||||
|
||||
if (this->using_validation_layers)
|
||||
{
|
||||
dbg_ci.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT;
|
||||
dbg_ci.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;
|
||||
dbg_ci.pfnUserCallback = debugCallback;
|
||||
dbg_ci.pUserData = this;
|
||||
PFN_vkCreateDebugUtilsMessengerEXT fn = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(this->inst, "vkCreateDebugUtilsMessengerEXT");
|
||||
BASSERT_FATAL(fn != VK_NULL_HANDLE, "Assertion %s failed at %s:%d\n\tFailed to get extension function vkCreateDebugUtilsMessengerEXT when creating validation layers\n\tIs the extension present?\n");
|
||||
VK_ASSERT(fn(this->inst, &dbg_ci, this->vk_alloc, &this->dbg_msger), "Failed to create vulkan debug messenger\n\tAt %s:%d\n\tError %d\n", string_VkResult(err));
|
||||
}
|
||||
}
|
||||
|
||||
basalt::Context::~Context()
|
||||
{
|
||||
if (this->using_validation_layers && this->should_free)
|
||||
{
|
||||
PFN_vkDestroyDebugUtilsMessengerEXT fn = (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr(this->inst, "vkDestroyDebugUtilsMessengerEXT");
|
||||
BASSERT_ERROR(fn != VK_NULL_HANDLE, {}, "Assertion %s failed at %s:%d\n\tFailed to get extension function vkDestroyDebugUtilsMessengerEXT when destroying validation layers\n\tIs the extension present?\n");
|
||||
if (fn != VK_NULL_HANDLE)
|
||||
fn(this->inst, this->dbg_msger, this->vk_alloc);
|
||||
}
|
||||
if (this->inst != VK_NULL_HANDLE && this->should_free)
|
||||
vkDestroyInstance(this->inst, this->vk_alloc);
|
||||
}
|
||||
|
||||
|
||||
static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(
|
||||
VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
|
||||
VkDebugUtilsMessageTypeFlagsEXT messageType,
|
||||
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
|
||||
void* pUserData)
|
||||
{
|
||||
switch (messageSeverity)
|
||||
{
|
||||
case VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT:
|
||||
basalt_log(LOG_TRACE, "%s\n", pCallbackData->pMessage);
|
||||
break;
|
||||
case VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT:
|
||||
basalt_log(LOG_INFO, "%s\n", pCallbackData->pMessage);
|
||||
break;
|
||||
case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT:
|
||||
basalt_log(LOG_WARN, "%s\n", pCallbackData->pMessage);
|
||||
break;
|
||||
case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT:
|
||||
basalt_log(LOG_ERROR, "%s\n", pCallbackData->pMessage);
|
||||
break;
|
||||
case VK_DEBUG_UTILS_MESSAGE_SEVERITY_FLAG_BITS_MAX_ENUM_EXT:
|
||||
basalt_log(LOG_WEIRD, "%s\n", pCallbackData->pMessage);
|
||||
break;
|
||||
default:
|
||||
basalt_log(LOG_WEIRD, "%s\n", pCallbackData->pMessage);
|
||||
break;
|
||||
}
|
||||
return VK_FALSE;
|
||||
}
|
||||
Reference in New Issue
Block a user