mirror of
https://github.com/seekrs/MacroLibX.git
synced 2026-01-12 15:13:34 +00:00
begenning the refactor
This commit is contained in:
149
runtime/Sources/Renderer/Core/Device.cpp
git.filemode.normal_file
149
runtime/Sources/Renderer/Core/Device.cpp
git.filemode.normal_file
@@ -0,0 +1,149 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* vk_device.cpp :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2022/10/08 19:14:29 by maldavid #+# #+# */
|
||||
/* Updated: 2024/03/25 22:31:54 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include <pre_compiled.h>
|
||||
|
||||
#include "render_core.h"
|
||||
|
||||
namespace mlx
|
||||
{
|
||||
const std::vector<const char*> deviceExtensions = {VK_KHR_SWAPCHAIN_EXTENSION_NAME};
|
||||
|
||||
void Device::init()
|
||||
{
|
||||
pickPhysicalDevice();
|
||||
|
||||
Queues::QueueFamilyIndices indices = Render_Core::get().getQueue().getFamilies();
|
||||
|
||||
std::vector<VkDeviceQueueCreateInfo> queueCreateInfos;
|
||||
std::set<std::uint32_t> uniqueQueueFamilies = { indices.graphics_family.value(), indices.present_family.value() };
|
||||
|
||||
float queuePriority = 1.0f;
|
||||
for(std::uint32_t queueFamily : uniqueQueueFamilies)
|
||||
{
|
||||
VkDeviceQueueCreateInfo queueCreateInfo{};
|
||||
queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
||||
queueCreateInfo.queueFamilyIndex = queueFamily;
|
||||
queueCreateInfo.queueCount = 1;
|
||||
queueCreateInfo.pQueuePriorities = &queuePriority;
|
||||
queueCreateInfos.push_back(queueCreateInfo);
|
||||
}
|
||||
|
||||
VkPhysicalDeviceFeatures deviceFeatures{};
|
||||
|
||||
VkDeviceCreateInfo createInfo{};
|
||||
createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
|
||||
|
||||
createInfo.queueCreateInfoCount = static_cast<std::uint32_t>(queueCreateInfos.size());
|
||||
createInfo.pQueueCreateInfos = queueCreateInfos.data();
|
||||
|
||||
createInfo.pEnabledFeatures = &deviceFeatures;
|
||||
|
||||
createInfo.enabledExtensionCount = static_cast<std::uint32_t>(deviceExtensions.size());
|
||||
createInfo.ppEnabledExtensionNames = deviceExtensions.data();
|
||||
createInfo.enabledLayerCount = 0;
|
||||
|
||||
VkResult res;
|
||||
if((res = vkCreateDevice(_physical_device, &createInfo, nullptr, &_device)) != VK_SUCCESS)
|
||||
core::error::report(e_kind::fatal_error, "Vulkan : failed to create logcal device, %s", RCore::verbaliseResultVk(res));
|
||||
#ifdef DEBUG
|
||||
core::error::report(e_kind::message, "Vulkan : created new logical device");
|
||||
#endif
|
||||
}
|
||||
|
||||
void Device::pickPhysicalDevice()
|
||||
{
|
||||
std::uint32_t deviceCount = 0;
|
||||
vkEnumeratePhysicalDevices(Render_Core::get().getInstance().get(), &deviceCount, nullptr);
|
||||
|
||||
if(deviceCount == 0)
|
||||
core::error::report(e_kind::fatal_error, "Vulkan : failed to find GPUs with Vulkan support");
|
||||
|
||||
std::vector<VkPhysicalDevice> devices(deviceCount);
|
||||
vkEnumeratePhysicalDevices(Render_Core::get().getInstance().get(), &deviceCount, devices.data());
|
||||
|
||||
std::multimap<int, VkPhysicalDevice> devices_score;
|
||||
|
||||
for(const auto& device : devices)
|
||||
{
|
||||
int score = deviceScore(device);
|
||||
devices_score.insert(std::make_pair(score, device));
|
||||
}
|
||||
|
||||
if(devices_score.rbegin()->first > 0)
|
||||
_physical_device = devices_score.rbegin()->second;
|
||||
else
|
||||
core::error::report(e_kind::fatal_error, "Vulkan : failed to find a suitable GPU");
|
||||
|
||||
#ifdef DEBUG
|
||||
VkPhysicalDeviceProperties props;
|
||||
vkGetPhysicalDeviceProperties(_physical_device, &props);
|
||||
core::error::report(e_kind::message, "Vulkan : picked a physical device, %s", props.deviceName);
|
||||
#endif
|
||||
Render_Core::get().getQueue().findQueueFamilies(_physical_device); // update queue indicies to current physical device
|
||||
}
|
||||
|
||||
int Device::deviceScore(VkPhysicalDevice device)
|
||||
{
|
||||
Queues::QueueFamilyIndices indices = Render_Core::get().getQueue().findQueueFamilies(device);
|
||||
bool extensionsSupported = checkDeviceExtensionSupport(device);
|
||||
|
||||
VkPhysicalDeviceProperties props;
|
||||
vkGetPhysicalDeviceProperties(device, &props);
|
||||
if(!indices.isComplete() || !extensionsSupported)
|
||||
return -1;
|
||||
|
||||
VkPhysicalDeviceFeatures features;
|
||||
vkGetPhysicalDeviceFeatures(device, &features);
|
||||
|
||||
int score = 0;
|
||||
#ifndef FORCE_INTEGRATED_GPU
|
||||
if(props.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU)
|
||||
score += 1000;
|
||||
#else
|
||||
if(props.deviceType != VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU)
|
||||
return -1;
|
||||
#endif
|
||||
|
||||
if(!features.geometryShader)
|
||||
return -1;
|
||||
|
||||
score += props.limits.maxImageDimension2D;
|
||||
score += props.limits.maxBoundDescriptorSets;
|
||||
return score;
|
||||
}
|
||||
|
||||
bool Device::checkDeviceExtensionSupport(VkPhysicalDevice device)
|
||||
{
|
||||
std::uint32_t extensionCount;
|
||||
vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, nullptr);
|
||||
|
||||
std::vector<VkExtensionProperties> availableExtensions(extensionCount);
|
||||
vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, availableExtensions.data());
|
||||
|
||||
std::set<std::string> requiredExtensions(deviceExtensions.begin(), deviceExtensions.end());
|
||||
|
||||
for(const auto& extension : availableExtensions)
|
||||
requiredExtensions.erase(extension.extensionName);
|
||||
|
||||
return requiredExtensions.empty();
|
||||
}
|
||||
|
||||
void Device::destroy() noexcept
|
||||
{
|
||||
vkDestroyDevice(_device, nullptr);
|
||||
_device = VK_NULL_HANDLE;
|
||||
#ifdef DEBUG
|
||||
core::error::report(e_kind::message, "Vulkan : destroyed a logical device");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
58
runtime/Sources/Renderer/Core/Fence.cpp
git.filemode.normal_file
58
runtime/Sources/Renderer/Core/Fence.cpp
git.filemode.normal_file
@@ -0,0 +1,58 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* vk_fence.cpp :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2023/04/02 17:53:06 by maldavid #+# #+# */
|
||||
/* Updated: 2024/03/25 19:02:14 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include <pre_compiled.h>
|
||||
|
||||
#include <renderer/core/vk_fence.h>
|
||||
#include <renderer/core/render_core.h>
|
||||
|
||||
namespace mlx
|
||||
{
|
||||
void Fence::init()
|
||||
{
|
||||
VkFenceCreateInfo fenceInfo{};
|
||||
fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
|
||||
fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
|
||||
|
||||
VkResult res;
|
||||
if((res = vkCreateFence(Render_Core::get().getDevice().get(), &fenceInfo, nullptr, &_fence)) != VK_SUCCESS)
|
||||
core::error::report(e_kind::fatal_error, "Vulkan : failed to create a synchronization object (fence), %s", RCore::verbaliseResultVk(res));
|
||||
#ifdef DEBUG
|
||||
core::error::report(e_kind::message, "Vulkan : created new fence");
|
||||
#endif
|
||||
}
|
||||
|
||||
void Fence::wait() noexcept
|
||||
{
|
||||
vkWaitForFences(Render_Core::get().getDevice().get(), 1, &_fence, VK_TRUE, UINT64_MAX);
|
||||
}
|
||||
|
||||
void Fence::reset() noexcept
|
||||
{
|
||||
vkResetFences(Render_Core::get().getDevice().get(), 1, &_fence);
|
||||
}
|
||||
|
||||
bool Fence::isReady() const noexcept
|
||||
{
|
||||
return vkGetFenceStatus(Render_Core::get().getDevice().get(), _fence) == VK_SUCCESS;
|
||||
}
|
||||
|
||||
void Fence::destroy() noexcept
|
||||
{
|
||||
if(_fence != VK_NULL_HANDLE)
|
||||
vkDestroyFence(Render_Core::get().getDevice().get(), _fence, nullptr);
|
||||
_fence = VK_NULL_HANDLE;
|
||||
#ifdef DEBUG
|
||||
core::error::report(e_kind::message, "Vulkan : destroyed fence");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
86
runtime/Sources/Renderer/Core/Instance.cpp
git.filemode.normal_file
86
runtime/Sources/Renderer/Core/Instance.cpp
git.filemode.normal_file
@@ -0,0 +1,86 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* vk_instance.cpp :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2022/10/08 19:04:21 by maldavid #+# #+# */
|
||||
/* Updated: 2024/03/25 23:10:37 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include <pre_compiled.h>
|
||||
|
||||
#include "vk_instance.h"
|
||||
#include "render_core.h"
|
||||
#include <platform/window.h>
|
||||
|
||||
namespace mlx
|
||||
{
|
||||
void Instance::init()
|
||||
{
|
||||
VkApplicationInfo appInfo{};
|
||||
appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
|
||||
appInfo.pEngineName = "MacroLibX";
|
||||
appInfo.engineVersion = VK_MAKE_VERSION(1, 3, 1);
|
||||
appInfo.apiVersion = VK_API_VERSION_1_2;
|
||||
|
||||
auto extensions = getRequiredExtensions();
|
||||
|
||||
VkInstanceCreateInfo createInfo{};
|
||||
createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
|
||||
createInfo.pApplicationInfo = &appInfo;
|
||||
createInfo.enabledExtensionCount = static_cast<std::uint32_t>(extensions.size());
|
||||
createInfo.ppEnabledExtensionNames = extensions.data();
|
||||
createInfo.enabledLayerCount = 0; // will be replaced if validation layers are enabled
|
||||
createInfo.pNext = nullptr;
|
||||
|
||||
VkDebugUtilsMessengerCreateInfoEXT debugCreateInfo;
|
||||
if constexpr(enableValidationLayers)
|
||||
{
|
||||
if(Render_Core::get().getLayers().checkValidationLayerSupport())
|
||||
{
|
||||
createInfo.enabledLayerCount = static_cast<std::uint32_t>(validationLayers.size());
|
||||
createInfo.ppEnabledLayerNames = validationLayers.data();
|
||||
Render_Core::get().getLayers().populateDebugMessengerCreateInfo(debugCreateInfo);
|
||||
createInfo.pNext = static_cast<VkDebugUtilsMessengerCreateInfoEXT*>(&debugCreateInfo);
|
||||
}
|
||||
}
|
||||
|
||||
VkResult res;
|
||||
if((res = vkCreateInstance(&createInfo, nullptr, &_instance)) != VK_SUCCESS)
|
||||
core::error::report(e_kind::fatal_error, "Vulkan : failed to create Vulkan instance, %s", RCore::verbaliseResultVk(res));
|
||||
volkLoadInstance(_instance);
|
||||
#ifdef DEBUG
|
||||
core::error::report(e_kind::message, "Vulkan : created new instance");
|
||||
#endif
|
||||
}
|
||||
|
||||
std::vector<const char*> Instance::getRequiredExtensions()
|
||||
{
|
||||
std::uint32_t glfw_extension_count = 0;
|
||||
const char** glfw_extensions = glfwGetRequiredInstanceExtensions(&glfw_extension_count);
|
||||
|
||||
std::vector<const char*> extensions(glfw_extensions, glfw_extensions + glfw_extension_count);
|
||||
|
||||
extensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
|
||||
|
||||
if constexpr(enableValidationLayers)
|
||||
{
|
||||
extensions.push_back(VK_EXT_DEBUG_REPORT_EXTENSION_NAME);
|
||||
extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
||||
}
|
||||
|
||||
return extensions;
|
||||
}
|
||||
|
||||
void Instance::destroy() noexcept
|
||||
{
|
||||
vkDestroyInstance(_instance, nullptr);
|
||||
_instance = VK_NULL_HANDLE;
|
||||
#ifdef DEBUG
|
||||
core::error::report(e_kind::message, "Vulkan : destroyed an instance");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
205
runtime/Sources/Renderer/Core/Memory.cpp
git.filemode.normal_file
205
runtime/Sources/Renderer/Core/Memory.cpp
git.filemode.normal_file
@@ -0,0 +1,205 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* memory.cpp :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: kbz_8 <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2023/10/20 22:02:37 by kbz_8 #+# #+# */
|
||||
/* Updated: 2024/03/25 19:27:44 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include <mlx_profile.h>
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
#define VK_NO_PROTOTYPES
|
||||
#define VMA_STATIC_VULKAN_FUNCTIONS 0
|
||||
#define VMA_DYNAMIC_VULKAN_FUNCTIONS 0
|
||||
#define VMA_VULKAN_VERSION 1002000
|
||||
#define VMA_ASSERT(expr) ((void)0)
|
||||
#define VMA_IMPLEMENTATION
|
||||
|
||||
#ifdef MLX_COMPILER_CLANG
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Weverything"
|
||||
#include <vma.h>
|
||||
#pragma clang diagnostic pop
|
||||
#elif defined(MLX_COMPILER_GCC)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
|
||||
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
|
||||
#pragma GCC diagnostic ignored "-Wunused-parameter"
|
||||
#pragma GCC diagnostic ignored "-Wunused-variable"
|
||||
#pragma GCC diagnostic ignored "-Wparentheses"
|
||||
#include <vma.h>
|
||||
#pragma GCC diagnostic pop
|
||||
#else
|
||||
#include <vma.h>
|
||||
#endif
|
||||
|
||||
#include <pre_compiled.h>
|
||||
|
||||
#include <core/errors.h>
|
||||
#include <core/profiler.h>
|
||||
#include <renderer/core/render_core.h>
|
||||
|
||||
namespace mlx
|
||||
{
|
||||
void GPUallocator::init() noexcept
|
||||
{
|
||||
VmaVulkanFunctions vma_vulkan_func{};
|
||||
vma_vulkan_func.vkAllocateMemory = vkAllocateMemory;
|
||||
vma_vulkan_func.vkBindBufferMemory = vkBindBufferMemory;
|
||||
vma_vulkan_func.vkBindImageMemory = vkBindImageMemory;
|
||||
vma_vulkan_func.vkCreateBuffer = vkCreateBuffer;
|
||||
vma_vulkan_func.vkCreateImage = vkCreateImage;
|
||||
vma_vulkan_func.vkDestroyBuffer = vkDestroyBuffer;
|
||||
vma_vulkan_func.vkDestroyImage = vkDestroyImage;
|
||||
vma_vulkan_func.vkFlushMappedMemoryRanges = vkFlushMappedMemoryRanges;
|
||||
vma_vulkan_func.vkFreeMemory = vkFreeMemory;
|
||||
vma_vulkan_func.vkGetBufferMemoryRequirements = vkGetBufferMemoryRequirements;
|
||||
vma_vulkan_func.vkGetImageMemoryRequirements = vkGetImageMemoryRequirements;
|
||||
vma_vulkan_func.vkGetPhysicalDeviceMemoryProperties = vkGetPhysicalDeviceMemoryProperties;
|
||||
vma_vulkan_func.vkGetPhysicalDeviceProperties = vkGetPhysicalDeviceProperties;
|
||||
vma_vulkan_func.vkInvalidateMappedMemoryRanges = vkInvalidateMappedMemoryRanges;
|
||||
vma_vulkan_func.vkMapMemory = vkMapMemory;
|
||||
vma_vulkan_func.vkUnmapMemory = vkUnmapMemory;
|
||||
vma_vulkan_func.vkCmdCopyBuffer = vkCmdCopyBuffer;
|
||||
vma_vulkan_func.vkGetBufferMemoryRequirements2KHR = vkGetBufferMemoryRequirements2;
|
||||
vma_vulkan_func.vkGetImageMemoryRequirements2KHR = vkGetImageMemoryRequirements2;
|
||||
vma_vulkan_func.vkBindBufferMemory2KHR = vkBindBufferMemory2;
|
||||
vma_vulkan_func.vkBindImageMemory2KHR = vkBindImageMemory2;
|
||||
vma_vulkan_func.vkGetPhysicalDeviceMemoryProperties2KHR = vkGetPhysicalDeviceMemoryProperties2;
|
||||
|
||||
VmaAllocatorCreateInfo allocatorCreateInfo{};
|
||||
allocatorCreateInfo.vulkanApiVersion = VK_API_VERSION_1_2;
|
||||
allocatorCreateInfo.physicalDevice = Render_Core::get().getDevice().getPhysicalDevice();
|
||||
allocatorCreateInfo.device = Render_Core::get().getDevice().get();
|
||||
allocatorCreateInfo.instance = Render_Core::get().getInstance().get();
|
||||
allocatorCreateInfo.pVulkanFunctions = &vma_vulkan_func;
|
||||
|
||||
VkResult res = vmaCreateAllocator(&allocatorCreateInfo, &_allocator);
|
||||
if(res != VK_SUCCESS)
|
||||
core::error::report(e_kind::fatal_error, "Graphics allocator : failed to create graphics memory allocator, %s", RCore::verbaliseResultVk(res));
|
||||
#ifdef DEBUG
|
||||
core::error::report(e_kind::message, "Graphics allocator : created new allocator");
|
||||
#endif
|
||||
}
|
||||
|
||||
VmaAllocation GPUallocator::createBuffer(const VkBufferCreateInfo* binfo, const VmaAllocationCreateInfo* vinfo, VkBuffer& buffer, const char* name) noexcept
|
||||
{
|
||||
MLX_PROFILE_FUNCTION();
|
||||
VmaAllocation allocation;
|
||||
VkResult res = vmaCreateBuffer(_allocator, binfo, vinfo, &buffer, &allocation, nullptr);
|
||||
if(res != VK_SUCCESS)
|
||||
core::error::report(e_kind::fatal_error, "Graphics allocator : failed to allocate a buffer, %s", RCore::verbaliseResultVk(res));
|
||||
if(name != nullptr)
|
||||
{
|
||||
Render_Core::get().getLayers().setDebugUtilsObjectNameEXT(VK_OBJECT_TYPE_BUFFER, (std::uint64_t)buffer, name);
|
||||
vmaSetAllocationName(_allocator, allocation, name);
|
||||
}
|
||||
#ifdef DEBUG
|
||||
core::error::report(e_kind::message, "Graphics Allocator : created new buffer '%s'", name);
|
||||
#endif
|
||||
_active_buffers_allocations++;
|
||||
return allocation;
|
||||
}
|
||||
|
||||
void GPUallocator::destroyBuffer(VmaAllocation allocation, VkBuffer buffer) noexcept
|
||||
{
|
||||
MLX_PROFILE_FUNCTION();
|
||||
vkDeviceWaitIdle(Render_Core::get().getDevice().get());
|
||||
vmaDestroyBuffer(_allocator, buffer, allocation);
|
||||
#ifdef DEBUG
|
||||
core::error::report(e_kind::message, "Graphics Allocator : destroyed buffer");
|
||||
#endif
|
||||
_active_buffers_allocations--;
|
||||
}
|
||||
|
||||
VmaAllocation GPUallocator::createImage(const VkImageCreateInfo* iminfo, const VmaAllocationCreateInfo* vinfo, VkImage& image, const char* name) noexcept
|
||||
{
|
||||
MLX_PROFILE_FUNCTION();
|
||||
VmaAllocation allocation;
|
||||
VkResult res = vmaCreateImage(_allocator, iminfo, vinfo, &image, &allocation, nullptr);
|
||||
if(res != VK_SUCCESS)
|
||||
core::error::report(e_kind::fatal_error, "Graphics allocator : failed to allocate an image, %s", RCore::verbaliseResultVk(res));
|
||||
if(name != nullptr)
|
||||
{
|
||||
Render_Core::get().getLayers().setDebugUtilsObjectNameEXT(VK_OBJECT_TYPE_IMAGE, (std::uint64_t)image, name);
|
||||
vmaSetAllocationName(_allocator, allocation, name);
|
||||
}
|
||||
#ifdef DEBUG
|
||||
core::error::report(e_kind::message, "Graphics Allocator : created new image '%s'", name);
|
||||
#endif
|
||||
_active_images_allocations++;
|
||||
return allocation;
|
||||
}
|
||||
|
||||
void GPUallocator::destroyImage(VmaAllocation allocation, VkImage image) noexcept
|
||||
{
|
||||
MLX_PROFILE_FUNCTION();
|
||||
vkDeviceWaitIdle(Render_Core::get().getDevice().get());
|
||||
vmaDestroyImage(_allocator, image, allocation);
|
||||
#ifdef DEBUG
|
||||
core::error::report(e_kind::message, "Graphics Allocator : destroyed image");
|
||||
#endif
|
||||
_active_images_allocations--;
|
||||
}
|
||||
|
||||
void GPUallocator::mapMemory(VmaAllocation allocation, void** data) noexcept
|
||||
{
|
||||
MLX_PROFILE_FUNCTION();
|
||||
VkResult res = vmaMapMemory(_allocator, allocation, data);
|
||||
if(res != VK_SUCCESS)
|
||||
core::error::report(e_kind::fatal_error, "Graphics allocator : unable to map GPU memory to CPU memory, %s", RCore::verbaliseResultVk(res));
|
||||
}
|
||||
|
||||
void GPUallocator::unmapMemory(VmaAllocation allocation) noexcept
|
||||
{
|
||||
MLX_PROFILE_FUNCTION();
|
||||
vmaUnmapMemory(_allocator, allocation);
|
||||
}
|
||||
|
||||
void GPUallocator::dumpMemoryToJson()
|
||||
{
|
||||
static std::uint32_t id = 0;
|
||||
std::string name("memory_dump");
|
||||
name.append(std::to_string(id) + ".json");
|
||||
std::ofstream file(name);
|
||||
if(!file.is_open())
|
||||
{
|
||||
core::error::report(e_kind::error, "Graphics allocator : unable to dump memory to a json file");
|
||||
return;
|
||||
}
|
||||
char* str = nullptr;
|
||||
vmaBuildStatsString(_allocator, &str, true);
|
||||
file << str;
|
||||
vmaFreeStatsString(_allocator, str);
|
||||
file.close();
|
||||
id++;
|
||||
}
|
||||
|
||||
void GPUallocator::flush(VmaAllocation allocation, VkDeviceSize size, VkDeviceSize offset) noexcept
|
||||
{
|
||||
MLX_PROFILE_FUNCTION();
|
||||
vmaFlushAllocation(_allocator, allocation, offset, size);
|
||||
}
|
||||
|
||||
void GPUallocator::destroy() noexcept
|
||||
{
|
||||
if(_active_images_allocations != 0)
|
||||
core::error::report(e_kind::error, "Graphics allocator : some user-dependant allocations were not freed before destroying the display (%d active allocations). You may have not destroyed all the MLX resources you've created", _active_images_allocations);
|
||||
else if(_active_buffers_allocations != 0)
|
||||
core::error::report(e_kind::error, "Graphics allocator : some MLX-dependant allocations were not freed before destroying the display (%d active allocations). This is an error in the MLX, please report this should not happen", _active_buffers_allocations);
|
||||
if(_active_images_allocations < 0 || _active_buffers_allocations < 0)
|
||||
core::error::report(e_kind::warning, "Graphics allocator : the impossible happened, the MLX has freed more allocations than it has made (wtf)");
|
||||
vmaDestroyAllocator(_allocator);
|
||||
_active_buffers_allocations = 0;
|
||||
_active_images_allocations = 0;
|
||||
#ifdef DEBUG
|
||||
core::error::report(e_kind::message, "Vulkan : destroyed a graphics allocator");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
55
runtime/Sources/Renderer/Core/Queues.cpp
git.filemode.normal_file
55
runtime/Sources/Renderer/Core/Queues.cpp
git.filemode.normal_file
@@ -0,0 +1,55 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* vk_queues.cpp :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2022/10/08 19:02:42 by maldavid #+# #+# */
|
||||
/* Updated: 2024/03/25 22:29:19 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include <pre_compiled.h>
|
||||
|
||||
#include "render_core.h"
|
||||
|
||||
namespace mlx
|
||||
{
|
||||
Queues::QueueFamilyIndices Queues::findQueueFamilies(VkPhysicalDevice device)
|
||||
{
|
||||
std::uint32_t queueFamilyCount = 0;
|
||||
vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, nullptr);
|
||||
|
||||
std::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);
|
||||
vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, queueFamilies.data());
|
||||
|
||||
_families = Queues::QueueFamilyIndices{};
|
||||
int i = 0;
|
||||
for(const auto& queueFamily : queueFamilies)
|
||||
{
|
||||
if(queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT)
|
||||
_families->graphics_family = i;
|
||||
|
||||
if(glfwGetPhysicalDevicePresentationSupport(Render_Core::get().getInstance().get(), device, i))
|
||||
_families->present_family = i;
|
||||
|
||||
if(_families->isComplete())
|
||||
return *_families;
|
||||
i++;
|
||||
}
|
||||
|
||||
return *_families;
|
||||
}
|
||||
|
||||
void Queues::init()
|
||||
{
|
||||
if(!_families.has_value())
|
||||
findQueueFamilies(Render_Core::get().getDevice().getPhysicalDevice());
|
||||
vkGetDeviceQueue(Render_Core::get().getDevice().get(), _families->graphics_family.value(), 0, &_graphics_queue);
|
||||
vkGetDeviceQueue(Render_Core::get().getDevice().get(), _families->present_family.value(), 0, &_present_queue);
|
||||
#ifdef DEBUG
|
||||
core::error::report(e_kind::message, "Vulkan : got graphics and present queues");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
152
runtime/Sources/Renderer/Core/RenderCore.cpp
git.filemode.normal_file
152
runtime/Sources/Renderer/Core/RenderCore.cpp
git.filemode.normal_file
@@ -0,0 +1,152 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* render_core.cpp :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2022/12/17 23:33:34 by maldavid #+# #+# */
|
||||
/* Updated: 2024/03/25 19:02:06 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#define VK_NO_PROTOTYPES
|
||||
#define VOLK_IMPLEMENTATION
|
||||
#include <volk.h>
|
||||
|
||||
#include <pre_compiled.h>
|
||||
|
||||
#include <renderer/core/render_core.h>
|
||||
#include <renderer/command/vk_cmd_buffer.h>
|
||||
|
||||
#ifdef DEBUG
|
||||
#ifdef MLX_COMPILER_MSVC
|
||||
#pragma NOTE("MLX is being compiled in debug mode, this activates Vulkan's validation layers and debug messages which may impact rendering performances")
|
||||
#else
|
||||
#warning "MLX is being compiled in debug mode, this activates Vulkan's validation layers and debug messages which may impact rendering performances"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace mlx
|
||||
{
|
||||
namespace RCore
|
||||
{
|
||||
std::optional<std::uint32_t> findMemoryType(std::uint32_t typeFilter, VkMemoryPropertyFlags properties, bool error)
|
||||
{
|
||||
VkPhysicalDeviceMemoryProperties memProperties;
|
||||
vkGetPhysicalDeviceMemoryProperties(Render_Core::get().getDevice().getPhysicalDevice(), &memProperties);
|
||||
|
||||
for(std::uint32_t i = 0; i < memProperties.memoryTypeCount; i++)
|
||||
{
|
||||
if((typeFilter & (1 << i)) && (memProperties.memoryTypes[i].propertyFlags & properties) == properties)
|
||||
return i;
|
||||
}
|
||||
if(error)
|
||||
core::error::report(e_kind::fatal_error, "Vulkan : failed to find suitable memory type");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
const char* verbaliseResultVk(VkResult result)
|
||||
{
|
||||
switch(result)
|
||||
{
|
||||
case VK_SUCCESS: return "Success";
|
||||
case VK_NOT_READY: return "A fence or query has not yet completed";
|
||||
case VK_TIMEOUT: return "A wait operation has not completed in the specified time";
|
||||
case VK_EVENT_SET: return "An event is signaled";
|
||||
case VK_EVENT_RESET: return "An event is unsignaled";
|
||||
case VK_INCOMPLETE: return "A return array was too small for the result";
|
||||
case VK_ERROR_OUT_OF_HOST_MEMORY: return "A host memory allocation has failed";
|
||||
case VK_ERROR_OUT_OF_DEVICE_MEMORY: return "A device memory allocation has failed";
|
||||
case VK_ERROR_INITIALIZATION_FAILED: return "Initialization of an object could not be completed for implementation-specific reasons";
|
||||
case VK_ERROR_DEVICE_LOST: return "The logical or physical device has been lost";
|
||||
case VK_ERROR_MEMORY_MAP_FAILED: return "Mapping of a memory object has failed";
|
||||
case VK_ERROR_LAYER_NOT_PRESENT: return "A requested layer is not present or could not be loaded";
|
||||
case VK_ERROR_EXTENSION_NOT_PRESENT: return "A requested extension is not supported";
|
||||
case VK_ERROR_FEATURE_NOT_PRESENT: return "A requested feature is not supported";
|
||||
case VK_ERROR_INCOMPATIBLE_DRIVER: return "The requested version of Vulkan is not supported by the driver or is otherwise incompatible";
|
||||
case VK_ERROR_TOO_MANY_OBJECTS: return "Too many objects of the type have already been created";
|
||||
case VK_ERROR_FORMAT_NOT_SUPPORTED: return "A requested format is not supported on this device";
|
||||
case VK_ERROR_SURFACE_LOST_KHR: return "A surface is no longer available";
|
||||
case VK_SUBOPTIMAL_KHR: return "A swapchain no longer matches the surface properties exactly, but can still be used";
|
||||
case VK_ERROR_OUT_OF_DATE_KHR: return "A surface has changed in such a way that it is no longer compatible with the swapchain";
|
||||
case VK_ERROR_INCOMPATIBLE_DISPLAY_KHR: return "The display used by a swapchain does not use the same presentable image layout";
|
||||
case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR: return "The requested window is already connected to a VkSurfaceKHR, or to some other non-Vulkan API";
|
||||
case VK_ERROR_VALIDATION_FAILED_EXT: return "A validation layer found an error";
|
||||
|
||||
default: return "Unknown Vulkan error";
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
VkPipelineStageFlags accessFlagsToPipelineStage(VkAccessFlags accessFlags, VkPipelineStageFlags stageFlags)
|
||||
{
|
||||
VkPipelineStageFlags stages = 0;
|
||||
|
||||
while(accessFlags != 0)
|
||||
{
|
||||
VkAccessFlagBits AccessFlag = static_cast<VkAccessFlagBits>(accessFlags & (~(accessFlags - 1)));
|
||||
if(AccessFlag == 0 || (AccessFlag & (AccessFlag - 1)) != 0)
|
||||
core::error::report(e_kind::fatal_error, "Vulkan : an error has been caught during access flag to pipeline stage operation");
|
||||
accessFlags &= ~AccessFlag;
|
||||
|
||||
switch(AccessFlag)
|
||||
{
|
||||
case VK_ACCESS_INDIRECT_COMMAND_READ_BIT: stages |= VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT; break;
|
||||
case VK_ACCESS_INDEX_READ_BIT: stages |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT; break;
|
||||
case VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT: stages |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT; break;
|
||||
case VK_ACCESS_UNIFORM_READ_BIT: stages |= stageFlags | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; break;
|
||||
case VK_ACCESS_INPUT_ATTACHMENT_READ_BIT: stages |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; break;
|
||||
case VK_ACCESS_SHADER_READ_BIT: stages |= stageFlags | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; break;
|
||||
case VK_ACCESS_SHADER_WRITE_BIT: stages |= stageFlags | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; break;
|
||||
case VK_ACCESS_COLOR_ATTACHMENT_READ_BIT: stages |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; break;
|
||||
case VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT: stages |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; break;
|
||||
case VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT: stages |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; break;
|
||||
case VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT: stages |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; break;
|
||||
case VK_ACCESS_TRANSFER_READ_BIT: stages |= VK_PIPELINE_STAGE_TRANSFER_BIT; break;
|
||||
case VK_ACCESS_TRANSFER_WRITE_BIT: stages |= VK_PIPELINE_STAGE_TRANSFER_BIT; break;
|
||||
case VK_ACCESS_HOST_READ_BIT: stages |= VK_PIPELINE_STAGE_HOST_BIT; break;
|
||||
case VK_ACCESS_HOST_WRITE_BIT: stages |= VK_PIPELINE_STAGE_HOST_BIT; break;
|
||||
case VK_ACCESS_MEMORY_READ_BIT: break;
|
||||
case VK_ACCESS_MEMORY_WRITE_BIT: break;
|
||||
|
||||
default: core::error::report(e_kind::error, "Vulkan : unknown access flag"); break;
|
||||
}
|
||||
}
|
||||
return stages;
|
||||
}
|
||||
}
|
||||
|
||||
void Render_Core::init()
|
||||
{
|
||||
if(volkInitialize() != VK_SUCCESS)
|
||||
core::error::report(e_kind::fatal_error, "Vulkan loader : cannot load %s, are you sure Vulkan is installed on your system ?", VULKAN_LIB_NAME);
|
||||
|
||||
_instance.init();
|
||||
volkLoadInstance(_instance.get());
|
||||
_layers.init();
|
||||
_device.init();
|
||||
volkLoadDevice(_device.get());
|
||||
_queues.init();
|
||||
_allocator.init();
|
||||
_cmd_manager.init();
|
||||
_is_init = true;
|
||||
}
|
||||
|
||||
void Render_Core::destroy()
|
||||
{
|
||||
if(!_is_init)
|
||||
return;
|
||||
|
||||
vkDeviceWaitIdle(_device());
|
||||
|
||||
_pool_manager.destroyAllPools();
|
||||
_cmd_manager.destroy();
|
||||
_allocator.destroy();
|
||||
_device.destroy();
|
||||
_layers.destroy();
|
||||
_instance.destroy();
|
||||
|
||||
_is_init = false;
|
||||
}
|
||||
}
|
||||
45
runtime/Sources/Renderer/Core/Semaphore.cpp
git.filemode.normal_file
45
runtime/Sources/Renderer/Core/Semaphore.cpp
git.filemode.normal_file
@@ -0,0 +1,45 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* vk_semaphore.cpp :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2022/10/08 19:01:08 by maldavid #+# #+# */
|
||||
/* Updated: 2024/03/25 19:02:25 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include <pre_compiled.h>
|
||||
|
||||
#include "vk_semaphore.h"
|
||||
#include "render_core.h"
|
||||
#include <renderer/renderer.h>
|
||||
|
||||
namespace mlx
|
||||
{
|
||||
void Semaphore::init()
|
||||
{
|
||||
VkSemaphoreCreateInfo semaphoreInfo{};
|
||||
semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
|
||||
|
||||
VkResult res;
|
||||
if( (res = vkCreateSemaphore(Render_Core::get().getDevice().get(), &semaphoreInfo, nullptr, &_image_available_semaphore)) != VK_SUCCESS ||
|
||||
(res = vkCreateSemaphore(Render_Core::get().getDevice().get(), &semaphoreInfo, nullptr, &_render_finished_semaphore)) != VK_SUCCESS)
|
||||
core::error::report(e_kind::fatal_error, "Vulkan : failed to create a synchronization object (semaphore), %s", RCore::verbaliseResultVk(res));
|
||||
#ifdef DEBUG
|
||||
core::error::report(e_kind::message, "Vulkan : created new semaphores");
|
||||
#endif
|
||||
}
|
||||
|
||||
void Semaphore::destroy() noexcept
|
||||
{
|
||||
vkDestroySemaphore(Render_Core::get().getDevice().get(), _render_finished_semaphore, nullptr);
|
||||
_render_finished_semaphore = VK_NULL_HANDLE;
|
||||
vkDestroySemaphore(Render_Core::get().getDevice().get(), _image_available_semaphore, nullptr);
|
||||
_image_available_semaphore = VK_NULL_HANDLE;
|
||||
#ifdef DEBUG
|
||||
core::error::report(e_kind::message, "Vulkan : destroyed semaphores");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
47
runtime/Sources/Renderer/Core/Surface.cpp
git.filemode.normal_file
47
runtime/Sources/Renderer/Core/Surface.cpp
git.filemode.normal_file
@@ -0,0 +1,47 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* vk_surface.cpp :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2022/10/08 18:58:49 by maldavid #+# #+# */
|
||||
/* Updated: 2024/03/25 22:25:55 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include <pre_compiled.h>
|
||||
#include "render_core.h"
|
||||
#include <platform/window.h>
|
||||
#include <renderer/renderer.h>
|
||||
|
||||
namespace mlx
|
||||
{
|
||||
void Surface::create(Renderer& renderer)
|
||||
{
|
||||
if(glfwCreateWindowSurface(Render_Core::get().getInstance().get(), renderer.getWindow()->getNativeWindow(), NULL, &_surface) != VK_SUCCESS)
|
||||
core::error::report(e_kind::fatal_error, "Vulkan : failed to create a surface");
|
||||
#ifdef DEBUG
|
||||
core::error::report(e_kind::message, "Vulkan : created new surface");
|
||||
#endif
|
||||
}
|
||||
|
||||
VkSurfaceFormatKHR Surface::chooseSwapSurfaceFormat(const std::vector<VkSurfaceFormatKHR>& availableFormats)
|
||||
{
|
||||
auto it = std::find_if(availableFormats.begin(), availableFormats.end(), [](VkSurfaceFormatKHR format)
|
||||
{
|
||||
return format.format == VK_FORMAT_R8G8B8A8_SRGB && format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
|
||||
});
|
||||
|
||||
return (it == availableFormats.end() ? availableFormats[0] : *it);
|
||||
}
|
||||
|
||||
void Surface::destroy() noexcept
|
||||
{
|
||||
vkDestroySurfaceKHR(Render_Core::get().getInstance().get(), _surface, nullptr);
|
||||
_surface = VK_NULL_HANDLE;
|
||||
#ifdef DEBUG
|
||||
core::error::report(e_kind::message, "Vulkan : destroyed a surface");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
129
runtime/Sources/Renderer/Core/ValidationLayers.cpp
git.filemode.normal_file
129
runtime/Sources/Renderer/Core/ValidationLayers.cpp
git.filemode.normal_file
@@ -0,0 +1,129 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* vk_validation_layers.cpp :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2022/12/19 14:05:25 by maldavid #+# #+# */
|
||||
/* Updated: 2024/03/25 19:00:06 by maldavid ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include <pre_compiled.h>
|
||||
#include "render_core.h"
|
||||
#include "vulkan/vulkan_core.h"
|
||||
|
||||
#include <core/errors.h>
|
||||
|
||||
namespace mlx
|
||||
{
|
||||
void ValidationLayers::init()
|
||||
{
|
||||
if constexpr(!enableValidationLayers)
|
||||
return;
|
||||
|
||||
std::uint32_t extensionCount;
|
||||
vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr);
|
||||
std::vector<VkExtensionProperties> extensions(extensionCount);
|
||||
vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, extensions.data());
|
||||
if(!std::any_of(extensions.begin(), extensions.end(), [=](VkExtensionProperties ext) { return std::strcmp(ext.extensionName, VK_EXT_DEBUG_UTILS_EXTENSION_NAME) == 0; }))
|
||||
{
|
||||
core::error::report(e_kind::warning , "Vulkan : %s not present, debug utils are disabled", VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
||||
return;
|
||||
}
|
||||
|
||||
VkDebugUtilsMessengerCreateInfoEXT createInfo{};
|
||||
populateDebugMessengerCreateInfo(createInfo);
|
||||
VkResult res = createDebugUtilsMessengerEXT(&createInfo, nullptr);
|
||||
if(res != VK_SUCCESS)
|
||||
core::error::report(e_kind::warning, "Vulkan : failed to set up debug messenger, %s", RCore::verbaliseResultVk(res));
|
||||
#ifdef DEBUG
|
||||
else
|
||||
core::error::report(e_kind::message, "Vulkan : enabled validation layers");
|
||||
#endif
|
||||
|
||||
_vkSetDebugUtilsObjectNameEXT = (PFN_vkSetDebugUtilsObjectNameEXT)vkGetInstanceProcAddr(Render_Core::get().getInstance().get(), "vkSetDebugUtilsObjectNameEXT");
|
||||
if(!_vkSetDebugUtilsObjectNameEXT)
|
||||
core::error::report(e_kind::warning, "Vulkan : failed to set up debug object names, %s", RCore::verbaliseResultVk(VK_ERROR_EXTENSION_NOT_PRESENT));
|
||||
#ifdef DEBUG
|
||||
else
|
||||
core::error::report(e_kind::message, "Vulkan : enabled debug object names");
|
||||
#endif
|
||||
}
|
||||
|
||||
bool ValidationLayers::checkValidationLayerSupport()
|
||||
{
|
||||
std::uint32_t layerCount;
|
||||
vkEnumerateInstanceLayerProperties(&layerCount, nullptr);
|
||||
|
||||
std::vector<VkLayerProperties> availableLayers(layerCount);
|
||||
vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data());
|
||||
|
||||
return std::all_of(validationLayers.begin(), validationLayers.end(), [&](const char* layerName)
|
||||
{
|
||||
if(!std::any_of(availableLayers.begin(), availableLayers.end(), [=](VkLayerProperties props) { return std::strcmp(layerName, props.layerName) == 0; }))
|
||||
{
|
||||
core::error::report(e_kind::error, "Vulkan : a validation layer was requested but was not found ('%s')", layerName);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
VkResult ValidationLayers::setDebugUtilsObjectNameEXT(VkObjectType object_type, std::uint64_t object_handle, const char* object_name)
|
||||
{
|
||||
if(!_vkSetDebugUtilsObjectNameEXT)
|
||||
return VK_ERROR_EXTENSION_NOT_PRESENT;
|
||||
|
||||
VkDebugUtilsObjectNameInfoEXT name_info{};
|
||||
name_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
|
||||
name_info.objectType = object_type;
|
||||
name_info.objectHandle = object_handle;
|
||||
name_info.pObjectName = object_name;
|
||||
return _vkSetDebugUtilsObjectNameEXT(Render_Core::get().getDevice().get(), &name_info);
|
||||
}
|
||||
|
||||
void ValidationLayers::populateDebugMessengerCreateInfo(VkDebugUtilsMessengerCreateInfoEXT& createInfo)
|
||||
{
|
||||
createInfo = {};
|
||||
createInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
|
||||
createInfo.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
|
||||
createInfo.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;
|
||||
createInfo.pfnUserCallback = ValidationLayers::debugCallback;
|
||||
}
|
||||
|
||||
void ValidationLayers::destroy()
|
||||
{
|
||||
if constexpr(enableValidationLayers)
|
||||
{
|
||||
destroyDebugUtilsMessengerEXT(nullptr);
|
||||
#ifdef DEBUG
|
||||
core::error::report(e_kind::message, "Vulkan : destroyed validation layers");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
VkResult ValidationLayers::createDebugUtilsMessengerEXT(const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator)
|
||||
{
|
||||
auto func = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(Render_Core::get().getInstance().get(), "vkCreateDebugUtilsMessengerEXT");
|
||||
return func != nullptr ? func(Render_Core::get().getInstance().get(), pCreateInfo, pAllocator, &_debug_messenger) : VK_ERROR_EXTENSION_NOT_PRESENT;
|
||||
}
|
||||
|
||||
VKAPI_ATTR VkBool32 VKAPI_CALL ValidationLayers::debugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, [[maybe_unused]] VkDebugUtilsMessageTypeFlagsEXT messageType, const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, [[maybe_unused]] void* pUserData)
|
||||
{
|
||||
if(messageSeverity == VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT)
|
||||
core::error::report(e_kind::error, pCallbackData->pMessage);
|
||||
else if(messageSeverity == VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT)
|
||||
core::error::report(e_kind::warning, pCallbackData->pMessage);
|
||||
return VK_FALSE;
|
||||
}
|
||||
|
||||
void ValidationLayers::destroyDebugUtilsMessengerEXT(const VkAllocationCallbacks* pAllocator)
|
||||
{
|
||||
auto func = (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr(Render_Core::get().getInstance().get(), "vkDestroyDebugUtilsMessengerEXT");
|
||||
if(func != nullptr)
|
||||
func(Render_Core::get().getInstance().get(), _debug_messenger, pAllocator);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user