big refactoring ! ci skip

This commit is contained in:
2024-09-02 09:44:42 +02:00
parent d95233e728
commit f65ac577bc
581 changed files with 42971 additions and 99170 deletions

View File

@@ -1,15 +1,3 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* Application.cpp :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2022/10/04 22:10:52 by maldavid #+# #+# */
/* Updated: 2024/05/25 16:06:57 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
#include <PreCompiled.h>
#include <Core/Application.h>

View File

@@ -1,15 +1,3 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* Bridge.cpp :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2022/10/04 17:35:20 by maldavid #+# #+# */
/* Updated: 2024/04/23 14:44:27 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
#include <PreCompiled.h>
#include <Core/Application.h>

View File

@@ -1,15 +1,3 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* EventBus.cpp :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2024/03/27 17:36:05 by maldavid #+# #+# */
/* Updated: 2024/03/27 17:37:01 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
#include <PreCompiled.h>
#include <Core/EventBus.h>
#include <Core/Logs.h>

View File

@@ -1,15 +1,3 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* EventListener.cpp :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2024/03/27 17:37:09 by maldavid #+# #+# */
/* Updated: 2024/03/27 17:37:38 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
#include <PreCompiled.h>
#include <Core/EventListener.h>

View File

@@ -1,15 +1,3 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* Fps.cpp :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2024/01/18 14:56:17 by maldavid #+# #+# */
/* Updated: 2024/03/27 20:53:11 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
#include <PreCompiled.h>
#include <Core/Fps.h>

View File

@@ -1,15 +1,3 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* Graphics.cpp :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/04/02 15:13:55 by maldavid #+# #+# */
/* Updated: 2024/04/23 14:03:51 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
#include <PreCompiled.h>
#include <Core/Graphics.h>

View File

@@ -1,15 +1,3 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* Logs.cpp :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2024/03/27 17:20:55 by maldavid #+# #+# */
/* Updated: 2024/07/05 13:31:02 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
#include <PreCompiled.h>
#include <Utils/Ansi.h>

View File

@@ -1,15 +1,3 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* Memory.cpp :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/12/07 16:32:01 by kbz_8 #+# #+# */
/* Updated: 2024/04/23 14:05:52 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
#include <PreCompiled.h>
#include <Core/Memory.h>

View File

@@ -1,15 +1,3 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* Profiler.cpp :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2024/01/10 13:56:21 by maldavid #+# #+# */
/* Updated: 2024/04/23 14:08:51 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
#include <PreCompiled.h>
#include <Core/Profiler.h>

View File

@@ -1,15 +1,3 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* SDLManager.cpp :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2024/05/25 15:44:03 by maldavid #+# #+# */
/* Updated: 2024/05/25 16:46:48 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
#include <PreCompiled.h>
#include <Core/SDLManager.h>
#include <Core/Memory.h>
@@ -52,14 +40,76 @@ namespace mlx
if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS | SDL_INIT_TIMER) != 0)
FatalError("SDL : unable to init all subsystems; %", SDL_GetError());
struct WatcherData
{
func::function<void(mlx_event_type, int, void*)> callback;
NonOwningPtr<SDLManager> manager;
void* userdata;
};
WatcherData watcher_data;
watcher_data.callback = f_callback;
watcher_data.userdata = p_callback_data;
SDL_AddEventWatch([](void* userdata, SDL_Event* event) -> int
{
WatcherData* data = static_cast<WatcherData*>(userdata);
if(event->type == SDL_MOUSEMOTION)
{
}
std::uint32_t id = event->window.windowID;
if(events_hooks.find(id) == events_hooks.end())
continue;
switch(event->type)
{
case SDL_KEYUP: data->callback(MLX_KEYUP, event->key.keysym.scancode, data->userdata); break;
case SDL_KEYDOWN: data->callback(MLX_KEYDOWN, event->key.keysym.scancode, data->userdata); break;
case SDL_MOUSEBUTTONUP: data->callback(MLX_MOUSEUP, event->button.button, data->userdata); break;
case SDL_MOUSEBUTTONDOWN: data->callback(MLX_MOUSEDOWN, event->button.button, data->userdata); break;
case SDL_MOUSEWHEEL:
{
if(event->wheel.y > 0) // scroll up
data->callback(MLX_MOUSEWHEEL, 1, data->userdata);
else if(event->wheel.y < 0) // scroll down
data->callback(MLX_MOUSEWHEEL, 2, data->userdata);
if(event->wheel.x > 0) // scroll right
data->callback(MLX_MOUSEWHEEL, 3, data->userdata);
else if(event->wheel.x < 0) // scroll left
data->callback(MLX_MOUSEWHEEL, 4, data->userdata);
break;
}
case SDL_WINDOWEVENT:
{
switch(event.window.event)
{
case SDL_WINDOWEVENT_CLOSE: data->callback(MLX_WINDOW_EVENT, 0, data->userdata); break;
case SDL_WINDOWEVENT_MOVED: data->callback(MLX_WINDOW_EVENT, 1, data->userdata); break;
case SDL_WINDOWEVENT_MINIMIZED: data->callback(MLX_WINDOW_EVENT, 2, data->userdata); break;
case SDL_WINDOWEVENT_MAXIMIZED: data->callback(MLX_WINDOW_EVENT, 3, data->userdata); break;
case SDL_WINDOWEVENT_ENTER: data->callback(MLX_WINDOW_EVENT, 4, data->userdata); break;
case SDL_WINDOWEVENT_FOCUS_GAINED: data->callback(MLX_WINDOW_EVENT, 5, data->userdata); break;
case SDL_WINDOWEVENT_LEAVE: data->callback(MLX_WINDOW_EVENT, 6, data->userdata); break;
case SDL_WINDOWEVENT_FOCUS_LOST: data->callback(MLX_WINDOW_EVENT, 7, data->userdata); break;
default : break;
}
break;
}
default: break;
}
}, &watcher_data);
}
void* SDLManager::CreateWindow(const std::string& title, std::size_t w, std::size_t h)
void* SDLManager::CreateWindow(const std::string& title, std::size_t w, std::size_t h, bool hidden)
{
details::WindowInfos* infos = new details::WindowInfos;
Verify(infos != nullptr, "SDL : window allocation failed");
infos->window = SDL_CreateWindow(title.c_str(), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, w, h, SDL_WINDOW_VULKAN | SDL_WINDOW_SHOWN);
infos->window = SDL_CreateWindow(title.c_str(), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, w, h, SDL_WINDOW_VULKAN | (hidden ? SDL_WINDOW_HIDDEN : SDL_WINDOW_SHOWN));
if(!infos->window)
FatalError("SDL : unable to open a new window; %", SDL_GetError());
infos->icon = SDL_CreateRGBSurfaceFrom(static_cast<void*>(logo_mlx), logo_mlx_width, logo_mlx_height, 32, 4 * logo_mlx_width, rmask, gmask, bmask, amask);
@@ -84,6 +134,34 @@ namespace mlx
delete infos;
}
VkSurfaceKHR SDLManager::CreateVulkanSurface(Handle window, VkInstance instance) const noexcept
{
VkSurfaceKHR surface;
if(!SDL_Vulkan_CreateSurface(static_cast<SDL_Window*>(window), instance, &surface))
FatalError("SDL : could not create a Vulkan surface; %", SDL_GetError());
return surface;
}
std::vector<const char*> SDLManager::GetRequiredVulkanInstanceExtentions(Handle window) const noexcept
{
std::uint32_t count;
if(!SDL_Vulkan_GetInstanceExtensions(static_cast<SDL_Window*>(window), &count, nullptr))
FatalError("Vulkan : cannot get instance extentions from window : %", SDL_GetError());
std::vector<const char*> extensions(count);
if(!SDL_Vulkan_GetInstanceExtensions(static_cast<SDL_Window*>(window), &count, extensions.data()))
FatalError("Vulkan : cannot get instance extentions from window : %", SDL_GetError());
return extentions;
}
Vec2ui SDLManager::GetVulkanDrawableSize(Handle window) const noexcept
{
Vec2ui extent;
SDL_Vulkan_GetDrawableSize(window, &extent.x, &extent.y);
return extent;
}
void SDLManager::Shutdown() noexcept
{
if(m_drop_sdl_responsability)

View File

@@ -1,18 +1,6 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* UUID.cpp :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2024/01/06 11:26:37 by maldavid #+# #+# */
/* Updated: 2024/04/23 14:09:35 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
#include <pre_compiled.h>
#include <core/UUID.h>
#include <Core/UUID.h>
namespace mlx
{

31
runtime/Sources/Graphics/Mesh.cpp git.filemode.normal_file
View File

@@ -0,0 +1,31 @@
#include <PreCompiled.h>
#include <Graphics/Mesh.h>
#include <Utils/Buffer.h>
namespace mlx
{
void Mesh::Draw(VkCommandBuffer cmd, std::size_t& drawcalls, std::size_t& polygondrawn) const noexcept
{
for(std::size_t i = 0; i < m_sub_meshes.size(); i++)
Draw(cmd, drawcalls, polygondrawn, i);
}
void Mesh::Draw(VkCommandBuffer cmd, std::size_t& drawcalls, std::size_t& polygondrawn, std::size_t submesh_index) const noexcept
{
Verify(submesh_index < m_sub_meshes.size(), "invalid submesh index");
m_sub_meshes[submesh_index].vbo.Bind(cmd);
m_sub_meshes[submesh_index].ibo.Bind(cmd);
vkCmdDrawIndexed(cmd, static_cast<std::uint32_t>(m_sub_meshes[submesh_index].ibo.GetSize() / sizeof(std::uint32_t)), 1, 0, 0, 0);
polygondrawn += m_sub_meshes[submesh_index].triangle_count;
drawcalls++;
}
Mesh::~Mesh()
{
for(auto& mesh : m_sub_meshes)
{
mesh.vbo.Destroy();
mesh.ibo.Destroy();
}
}
}

19
runtime/Sources/Graphics/Scene.cpp git.filemode.normal_file
View File

@@ -0,0 +1,19 @@
#include <PreCompiled.h>
#include <Graphics/Scene.h>
#include <Renderer/Renderer.h>
#include <Renderer/RenderCore.h>
namespace Scop
{
Scene::Scene(SceneDescriptor desc)
: m_descriptor(std::move(desc))
{
}
Sprite& Scene::CreateSprite(std::shared_ptr<Texture> texture) noexcept
{
std::shared_ptr<Sprite> sprite = std::make_shared<Sprite>(texture);
m_sprites.push_back(sprite);
return *sprite;
}
}

44
runtime/Sources/Graphics/Sprite.cpp git.filemode.normal_file
View File

@@ -0,0 +1,44 @@
#include <PreCompiled.h>
#include <Graphics/Sprite.h>
#include <Renderer/Image.h>
#include <Renderer/Vertex.h>
namespace mlx
{
std::shared_ptr<Mesh> CreateQuad(float x, float y, float width, float height)
{
std::vector<Vertex> data(4);
data[0].position = Vec4f(x, y, 0.0f, 1.0f);
data[0].uv = Vec2f(1.0f, 1.0f);
data[1].position = Vec4f(x + width, y, 0.0f, 1.0f);
data[1].uv = Vec2f(0.0f, 1.0f);
data[2].position = Vec4f(x + width, y + height, 0.0f, 1.0f);
data[2].uv = Vec2f(0.0f, 0.0f);
data[3].position = Vec4f(x, y + height, 0.0f, 1.0f);
data[3].uv = Vec2f(1.0f, 0.0f);
std::vector<std::uint32_t> indices = {
0,
1,
2,
2,
3,
0,
};
std::shared_ptr<Mesh> mesh = std::make_shared<Mesh>();
mesh->AddSubMesh({ std::move(data), std::move(indices) });
return mesh;
}
Sprite::Sprite(std::shared_ptr<Texture> texture)
{
Verify((bool)texture, "Sprite: invalid texture");
p_mesh = CreateQuad(0, 0, texture->GetWidth(), texture->GetHeight());
p_texture = texture;
}
}

View File

@@ -1,20 +1,6 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* inputs.cpp :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2022/10/05 16:30:19 by maldavid #+# #+# */
/* Updated: 2024/03/27 15:50:07 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
#include <PreCompiled.h>
#include <pre_compiled.h>
#include "inputs.h"
#include <mlx.h>
#include <core/profiler.h>
#include <Platform/Inputs.h>
namespace mlx
{

View File

@@ -1,15 +1,3 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* Window.cpp :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2022/10/04 17:36:44 by maldavid #+# #+# */
/* Updated: 2024/07/05 13:12:51 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
#include <PreCompiled.h>
#include <Core/SDLManager.h>
@@ -17,10 +5,10 @@
namespace mlx
{
Window::Window(std::size_t w, std::size_t h, const std::string& title) : m_width(w), m_height(h)
Window::Window(std::size_t w, std::size_t h, const std::string& title, bool hidden) : m_width(w), m_height(h)
{
static std::uint64_t ids = 0;
p_window = SDLManager::Get().CreateWindow(title, w, h);
p_window = SDLManager::Get().CreateWindow(title, w, h, hidden);
m_id = ids++;
}

175
runtime/Sources/Renderer/Buffer.cpp git.filemode.normal_file
View File

@@ -0,0 +1,175 @@
#include <PreCompiled.h>
#include <Renderer/RenderCore.h>
#include <Renderer/Buffer.h>
namespace mlx
{
void GPUBuffer::Init(BufferType type, VkDeviceSize size, VkBufferUsageFlags usage, CPUBuffer data)
{
VmaAllocationCreateInfo alloc_info{};
alloc_info.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT;
alloc_info.usage = VMA_MEMORY_USAGE_AUTO;
if(type == BufferType::Constant)
{
if(data.Empty())
{
Warning("Vulkan : trying to create constant buffer without data (constant buffers cannot be modified after creation)");
return;
}
m_usage = usage | VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
}
else if(type == BufferType::HighDynamic)
m_usage = usage;
else // LowDynamic or Staging
m_usage = usage | VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
if(type == BufferType::Staging && data.Empty())
Warning("Vulkan : trying to create staging buffer without data (wtf?)");
CreateBuffer(size, m_usage, alloc_info);
if(!data.Empty())
{
if(p_map != nullptr)
std::memcpy(m_memory.map, data.GetData(), data.GetSize());
}
if(type == BufferType::Constant || type == BufferType::LowDynamic)
PushToGPU();
}
void GPUBuffer::CreateBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VmaAllocationCreateInfo alloc_info)
{
VkBufferCreateInfo bufferInfo{};
bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
bufferInfo.size = size;
bufferInfo.usage = usage;
bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
m_allocation = RenderCore::Get().GetAllocator().CreateBuffer(&bufferInfo, &info, m_buffer, nullptr);
if(alloc_info.flags != 0)
RenderCore::Get().GetAllocator().MapMemory(m_allocation, &p_map);
}
bool GPUBuffer::CopyFrom(const GPUBuffer& buffer) noexcept
{
if(!(m_usage & VK_BUFFER_USAGE_TRANSFER_DST_BIT))
{
Error("Vulkan : buffer cannot be the destination of a copy because it does not have the correct usage flag");
return false;
}
if(!(buffer.m_usage & VK_BUFFER_USAGE_TRANSFER_SRC_BIT))
{
Error("Vulkan : buffer cannot be the source of a copy because it does not have the correct usage flag");
return false;
}
VkCommandBuffer cmd = kvfCreateCommandBuffer(RenderCore::Get().GetDevice());
kvfBeginCommandBuffer(cmd, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT);
kvfCopyBufferToBuffer(cmd, m_buffer, buffer.Get(), m_memory.size);
kvfEndCommandBuffer(cmd);
VkFence fence = kvfCreateFence(RenderCore::Get().GetDevice());
kvfSubmitSingleTimeCommandBuffer(RenderCore::Get().GetDevice(), cmd, KVF_GRAPHICS_QUEUE, fence);
kvfWaitForFence(RenderCore::Get().GetDevice(), fence);
kvfDestroyFence(RenderCore::Get().GetDevice(), fence);
return true;
}
void GPUBuffer::PushToGPU() noexcept
{
VmaAllocationCreateInfo alloc_info{};
alloc_info.usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE;
GPUBuffer new_buffer;
new_buffer.m_usage = (this->m_usage & 0xFFFFFFFC) | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
new_buffer.CreateBuffer(m_memory.size, new_buffer.m_usage, alloc_info);
if(new_buffer.CopyFrom(*this))
Swap(new_buffer);
new_buffer.Destroy();
DebugLog("Vulkan : pushed buffer to GPU memory");
}
void GPUBuffer::Destroy() noexcept
{
if(m_buffer == VK_NULL_HANDLE)
return;
RenderCore::Get().GetAllocator().UnmapMemory(m_allocation);
RenderCore::Get().GetAllocator().DestroyBuffer(m_allocation, m_buffer);
m_buffer = VK_NULL_HANDLE;
}
void GPUBuffer::Swap(GPUBuffer& buffer) noexcept
{
std::swap(m_buffer, buffer.m_buffer);
std::swap(m_allocation, buffer.m_allocation);
std::swap(m_size, buffer.m_size);
std::swap(m_offset, buffer.m_offset);
std::swap(p_map, buffer.p_map);
std::swap(m_usage, buffer.m_usage);
}
void VertexBuffer::SetData(CPUBuffer data)
{
if(data.GetSize() > m_memory.size)
{
Error("Vulkan : trying to store to much data in a vertex buffer (% bytes in % bytes)", data.GetSize(), m_memory.size);
return;
}
if(data.Empty())
{
Warning("Vulkan : cannot set empty data in a vertex buffer");
return;
}
GPUBuffer staging;
staging.Init(BufferType::Staging, data.GetSize(), VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, data);
CopyFrom(staging);
staging.Destroy();
}
void IndexBuffer::SetData(CPUBuffer data)
{
if(data.GetSize() > m_memory.size)
{
Error("Vulkan : trying to store to much data in an index buffer (% bytes in % bytes)", data.GetSize(), m_memory.size);
return;
}
if(data.Empty())
{
Warning("Vulkan : cannot set empty data in an index buffer");
return;
}
GPUBuffer staging;
staging.Init(BufferType::Staging, data.GetSize(), VK_BUFFER_USAGE_INDEX_BUFFER_BIT, data);
CopyFrom(staging);
staging.Destroy();
}
void UniformBuffer::Init(std::uint32_t size)
{
for(int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++)
{
m_buffers[i].Init(BufferType::HighDynamic, size, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, {});
m_maps[i] = m_buffers[i].GetMap();
if(m_maps[i] == nullptr)
FatalError("Vulkan : unable to map a uniform buffer");
}
}
void UniformBuffer::SetData(CPUBuffer data, std::size_t frame_index)
{
if(data.GetSize() != m_buffers[frame_index].GetSize())
{
Error("Vulkan : invalid data size to update to a uniform buffer, % != %", data.GetSize(), m_buffers[frame_index].GetSize());
return;
}
if(m_maps[frame_index] != nullptr)
std::memcpy(m_maps[frame_index], data.GetData(), data.GetSize());
}
void UniformBuffer::Destroy() noexcept
{
for(int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++)
m_buffers[i].Destroy();
}
}

View File

@@ -1,150 +0,0 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* Buffer.cpp :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2022/10/08 18:55:57 by maldavid #+# #+# */
/* Updated: 2024/04/23 14:20:13 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
#include <PreCompiled.h>
#include <Renderer/Buffers/Buffer.h>
#include <Renderer/Command/CommandPool.h>
#include <Renderer/Command/CommandBuffer.h>
#include <Renderer/Core/RenderCore.h>
namespace mlx
{
void Buffer::Create(BufferType type, VkDeviceSize size, VkBufferUsageFlags usage, const char* name, const void* data)
{
MLX_PROFILE_FUNCTION();
m_usage = usage;
if(type == BufferType::Constant || type == BufferType::LowDynamic)
{
if(data == nullptr && type == BufferType::Constant)
{
Warning("Vulkan : trying to create constant buffer without data (constant buffers cannot be modified after creation)");
return;
}
m_usage |= VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
}
VmaAllocationCreateInfo alloc_info{};
alloc_info.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT;
alloc_info.usage = VMA_MEMORY_USAGE_AUTO;
CreateBuffer(m_usage, alloc_info, size, name);
if(data != nullptr)
{
void* mapped = nullptr;
MapMem(&mapped);
std::memcpy(mapped, data, size);
UnmapMem();
if(type == BufferType::constant || type == BufferType::LowDynamic)
PushToGPU();
}
}
void Buffer::Destroy() noexcept
{
MLX_PROFILE_FUNCTION();
if(m_is_mapped)
UnmapMem();
if(m_buffer != VK_NULL_HANDLE)
RenderCore::Get().GetAllocator().DestroyBuffer(m_allocation, m_buffer);
m_buffer = VK_NULL_HANDLE;
}
void Buffer::CreateBuffer(VkBufferUsageFlags usage, VmaAllocationCreateInfo info, VkDeviceSize size, [[maybe_unused]] const char* name)
{
MLX_PROFILE_FUNCTION();
VkBufferCreateInfo bufferInfo{};
bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
bufferInfo.size = size;
bufferInfo.usage = usage;
bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
#ifdef DEBUG
m_name = name;
std::string alloc_name = m_name;
if(usage & VK_BUFFER_USAGE_INDEX_BUFFER_BIT)
alloc_name.append("_index_buffer");
else if(usage & VK_BUFFER_USAGE_VERTEX_BUFFER_BIT)
alloc_name.append("_vertex_buffer");
else if(!(usage & VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT))
alloc_name.append("_buffer");
m_allocation = RenderCore::Get().GetAllocator().CreateBuffer(&bufferInfo, &info, m_buffer, alloc_name.c_str());
#else
m_allocation = RenderCore::Get().GetAllocator().CreateBuffer(&bufferInfo, &info, m_buffer, nullptr);
#endif
m_size = size;
}
bool Buffer::CopyFromBuffer(const Buffer& buffer) noexcept
{
MLX_PROFILE_FUNCTION();
if(!(m_usage & VK_BUFFER_USAGE_TRANSFER_DST_BIT))
{
Error("Vulkan : buffer cannot be the destination of a copy because it does not have the correct usage flag");
return false;
}
if(!(buffer.m_usage & VK_BUFFER_USAGE_TRANSFER_SRC_BIT))
{
Error("Vulkan : buffer cannot be the source of a copy because it does not have the correct usage flag");
return false;
}
CmdBuffer& cmd = RenderCore::Get().GetSingleTimeCmdBuffer();
cmd.BeginRecord();
cmd.CopyBuffer(*this, const_cast<Buffer&>(buffer));
cmd.EndRecord();
cmd.SubmitIdle();
return true;
}
void Buffer::PushToGPU() noexcept
{
MLX_PROFILE_FUNCTION();
VmaAllocationCreateInfo alloc_info{};
alloc_info.usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE;
Buffer new_buffer;
new_buffer.m_usage = (m_usage & 0xFFFFFFFC) | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
#ifdef DEBUG
std::string new_name = m_name + "_GPU";
new_buffer.CreateBuffer(new_buffer.m_usage, alloc_info, m_size, new_name.c_str());
#else
new_buffer.CreateBuffer(new_buffer.m_usage, alloc_info, m_size, nullptr);
#endif
if(new_buffer.CopyFromBuffer(*this)) // if the copy succeded we swap the buffers, otherwise the new one is deleted
this->Swap(new_buffer);
new_buffer.Destroy(); // destroying the old buffer as they have been swapped
}
void Buffer::Swap(Buffer& buffer) noexcept
{
std::swap(m_buffer, buffer.m_buffer);
std::swap(m_allocation, buffer.m_allocation);
std::swap(m_size, buffer.m_size);
std::swap(m_offset, buffer.m_offset);
#ifdef DEBUG
std::swap(m_name, buffer.m_name);
#endif
std::swap(m_usage, buffer.m_usage);
std::swap(m_is_mapped, buffer.m_is_mapped);
}
void Buffer::Flush(VkDeviceSize size, VkDeviceSize offset)
{
RenderCore::Get().GetAllocator().Flush(m_allocation, size, offset);
}
}

View File

@@ -1,78 +0,0 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* UniformBuffer.cpp :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2022/10/06 18:45:52 by maldavid #+# #+# */
/* Updated: 2024/04/23 14:25:17 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
#include <PreCompiled.h>
#include <Renderer/Buffers/UniformBuffer.h>
#include <Renderer/Renderer.h>
namespace mlx
{
void UniformBuffer::create(NonOwningPtr<Renderer> renderer, std::uint32_t size, [[maybe_unused]] const char* name)
{
MLX_PROFILE_FUNCTION();
p_renderer = renderer;
for(int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++)
{
#ifdef DEBUG
std::string name_frame = name;
name_frame.append(std::to_string(i));
m_buffers[i].create(BufferType::HighDynamic, size, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, name_frame.c_str());
#else
_buffers[i].Create(BufferType::HighDynamic, size, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, nullptr);
#endif
m_buffers[i].MapMem(&_maps[i]);
if(m_maps[i] == nullptr)
FatalError("Vulkan : unable to map a uniform buffer");
}
}
void UniformBuffer::SetData(std::uint32_t size, const void* data)
{
MLX_PROFILE_FUNCTION();
std::memcpy(m_maps[p_renderer->GetActiveImageIndex()], data, static_cast<std::size_t>(size));
}
void UniformBuffer::SetDynamicData(std::uint32_t size, const void* data)
{
MLX_PROFILE_FUNCTION();
std::memcpy(m_maps[p_renderer->GetActiveImageIndex()], data, static_cast<std::size_t>(size));
m_buffers[p_renderer->GetActiveImageIndex()].Flush();
}
unsigned int UniformBuffer::GetSize() noexcept
{
return m_buffers[p_renderer->GetActiveImageIndex()].GetSize();
}
unsigned int UniformBuffer::GetOffset() noexcept
{
return m_buffers[p_renderer->GetActiveImageIndex()].GetOffset();
}
VkBuffer& UniformBuffer::operator()() noexcept
{
return m_buffers[p_renderer->GetActiveImageIndex()].Get();
}
VkBuffer& UniformBuffer::Get() noexcept
{
return m_buffers[p_renderer->GetActiveImageIndex()].Get();
}
void UniformBuffer::Destroy() noexcept
{
for(int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++)
m_buffers[i].Destroy();
}
}

View File

@@ -1,56 +0,0 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* VertexBuffer.cpp :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2022/10/06 18:28:08 by maldavid #+# #+# */
/* Updated: 2024/04/23 14:48:15 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
#include <PreCompiled.h>
#include <Renderer/Buffers/VertexBuffer.h>
namespace mlx
{
void RAMVertexBuffer::SetData(std::uint32_t size, const void* data)
{
if(size > GetSize())
{
Error("Vulkan : trying to store to much data in a vertex buffer (% bytes in % bytes)", size, GetSize());
return;
}
if(data == nullptr)
Warning("Vulkan : mapping null data in a vertex buffer");
void* temp = nullptr;
MapMem(&temp);
std::memcpy(temp, data, static_cast<std::size_t>(size));
UnmapMem();
}
void DeviceVertexBuffer::SetData(std::uint32_t size, const void* data)
{
if(size > GetSize())
{
Error("Vulkan : trying to store to much data in a vertex buffer (% bytes in % bytes)", size, GetSize());
return;
}
if(data == nullptr)
Warning("Vulkan : mapping null data in a vertex buffer");
Buffer tmp_buf;
#ifdef DEBUG
tmp_buf.Create(BufferType::HighDynamic, size, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT, "tmp_buffer", data);
#else
tmp_buf.Create(BufferType::HighDynamic, size, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT, nullptr, data);
#endif
CopyFromBuffer(tmp_buf);
tmp_buf.Destroy();
}
}

View File

@@ -1,365 +0,0 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* CommandBuffer.cpp :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2022/10/06 18:26:06 by maldavid #+# #+# */
/* Updated: 2024/04/23 18:02:20 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
#include <PreCompiled.h>
#include <Renderer/Command/CommandBuffer.h>
#include <Renderer/Core/CommandResource.h>
#include <Renderer/Core/RenderCore.h>
#include <Renderer/Command/CommandManager.h>
#include <Renderer/Core/Semaphore.h>
#include <Renderer/Buffers/Buffer.h>
#include <Renderer/Images/Image.h>
namespace mlx
{
bool VectorPushBackIfNotFound(std::vector<NonOwningPtr<CommandResource>>& vector, NonOwningPtr<CommandResource> res)
{
auto it = std::find_if(vector.begin(), vector.end(), [=](const NonOwningPtr<CommandResource> vres)
{
return vres->GetUUID() == res->GetUUID();
});
if(it == vector.end())
{
vector.push_back(res);
return true;
}
return false;
}
void CmommanBuffer::Init(CommandBufferType type, NonOwningPtr<CommandManager> manager)
{
Init(type, &manager->GetCmdPool());
}
void CommandBuffer::Init(CommandBufferType type, NonOwningPtr<CommandPool> pool)
{
MLX_PROFILE_FUNCTION();
m_type = type;
m_pool = pool;
VkCommandBufferAllocateInfo alloc_info{};
alloc_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
alloc_info.commandPool = pool->get();
alloc_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
alloc_info.commandBufferCount = 1;
VkResult res = vkAllocateCommandBuffers(RenderCore::Get().getDevice().get(), &allocInfo, &_cmd_buffer);
if(res != VK_SUCCESS)
FatalError("Vulkan : failed to allocate command buffer, %s", RCore::verbaliseResultVk(res));
#ifdef DEBUG
Message("Vulkan : created new command buffer");
#endif
m_fence.init();
state = CommandBufferState::Idle;
}
void CommandBuffer::BeginRecord(VkCommandBufferUsageFlags usage)
{
MLX_PROFILE_FUNCTION();
if(!IsInit())
FatalError("Vulkan : begenning record on un uninit command buffer");
if(m_state == CommandBufferState::Recording)
return;
VkCommandBufferBeginInfo begin_info{};
begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
begin_info.flags = usage;
if(vkBeginCommandBuffer(m_cmd_buffer, &begin_info) != VK_SUCCESS)
FatalError("Vulkan : failed to begin recording command buffer");
m_state = CommandBufferState::Recording;
}
void CommandBuffer::BindVertexBuffer(Buffer& buffer) noexcept
{
MLX_PROFILE_FUNCTION();
if(!IsRecording())
{
Warning("Vulkan : trying to bind a vertex buffer to a non recording command buffer");
return;
}
VkDeviceSize offset[] = { buffer.GetOffset() };
vkCmdBindVertexBuffers(m_cmd_buffer, 0, 1, &buffer.Get(), offset);
buffer.RecordedInCommandBuffer();
VectorPushBackIfNotFound(m_cmd_resources, &buffer);
}
void CommandBuffer::NindIndexBuffer(Buffer& buffer) noexcept
{
MLX_PROFILE_FUNCTION();
if(!IsRecording())
{
Warning("Vulkan : trying to bind a index buffer to a non recording command buffer");
return;
}
vkCmdBindIndexBuffer(m_cmd_buffer, buffer.Get(), buffer.GetOffset(), VK_INDEX_TYPE_UINT16);
buffer.RecordedInCommandBuffer();
VectorPushBackIfNotFound(m_cmd_resources, &buffer);
}
void CommandBuffer::CopyBuffer(Buffer& dst, Buffer& src) noexcept
{
MLX_PROFILE_FUNCTION();
if(!IsRecording())
{
Warning("Vulkan : trying to do a buffer to buffer copy in a non recording command buffer");
return;
}
PreTransferBarrier();
VkBufferCopy copy_region{};
copy_region.size = src.GetSize();
vkCmdCopyBuffer(m_cmd_buffer, src.Get(), dst.Get(), 1, &copy_region);
PostTransferBarrier();
dst.RecordedInCommandBuffer();
src.RecordedInCommandBuffer();
VectorPushBackIfNotFound(m_cmd_resources, &dst);
VectorPushBackIfNotFound(m_cmd_resources, &src);
}
void CommandBuffer::CopyBufferToImage(Buffer& buffer, Image& image) noexcept
{
MLX_PROFILE_FUNCTION();
if(!IsRecording())
{
Warning("Vulkan : trying to do a buffer to image copy in a non recording command buffer");
return;
}
PreTransferBarrier();
VkBufferImageCopy region{};
region.bufferOffset = 0;
region.bufferRowLength = 0;
region.bufferImageHeight = 0;
region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
region.imageSubresource.mipLevel = 0;
region.imageSubresource.baseArrayLayer = 0;
region.imageSubresource.layerCount = 1;
region.imageOffset = { 0, 0, 0 };
region.imageExtent = { image.GetWidth(), image.GetHeight(), 1 };
vkCmdCopyBufferToImage(m_cmd_buffer, buffer.Get(), image.Get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
PostTransferBarrier();
image.RecordedInCommandBuffer();
buffer.RecordedInCommandBuffer();
VectorPushBackIfNotFound(m_cmd_resources, &image);
VectorPushBackIfNotFound(m_cmd_resources, &buffer);
}
void CommandBuffer::CopyImagetoBuffer(Image& image, Buffer& buffer) noexcept
{
MLX_PROFILE_FUNCTION();
if(!IsRecording())
{
Warning("Vulkan : trying to do an image to buffer copy in a non recording command buffer");
return;
}
PreTransferBarrier();
VkBufferImageCopy region{};
region.bufferOffset = 0;
region.bufferRowLength = 0;
region.bufferImageHeight = 0;
region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
region.imageSubresource.mipLevel = 0;
region.imageSubresource.baseArrayLayer = 0;
region.imageSubresource.layerCount = 1;
region.imageOffset = { 0, 0, 0 };
region.imageExtent = { image.GetWidth(), image.GetHeight(), 1 };
vkCmdCopyImageToBuffer(m_cmd_buffer, image.Get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, buffer.Get(), 1, &region);
PostTransferBarrier();
image.RecordedInCommandBuffer();
buffer.RecordedInCommandBuffer();
VectorPushBackIfNotFound(m_cmd_resources, &buffer);
VectorPushBackIfNotFound(m_cmd_resources, &image);
}
void CommandBuffer::TransitionImageLayout(Image& image, VkImageLayout new_layout) noexcept
{
MLX_PROFILE_FUNCTION();
if(!IsRecording())
{
Warning("Vulkan : trying to do an image layout transition in a non recording command buffer");
return;
}
VkImageMemoryBarrier barrier{};
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
barrier.oldLayout = image.GetLayout();
barrier.newLayout = new_layout;
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.image = image.Get();
barrier.subresourceRange.aspectMask = IsDepthFormat(image.GetFormat()) ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT;
barrier.subresourceRange.baseMipLevel = 0;
barrier.subresourceRange.levelCount = 1;
barrier.subresourceRange.baseArrayLayer = 0;
barrier.subresourceRange.layerCount = 1;
barrier.srcAccessMask = LayoutToAccessMask(image.GetLayout(), false);
barrier.dstAccessMask = LayoutToAccessMask(new_layout, true);
if(IsStencilFormat(image.GetFormat()))
barrier.subresourceRange.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
VkPipelineStageFlags source_stage = 0;
if(barrier.oldLayout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR)
source_stage = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
else if(barrier.srcAccessMask != 0)
source_stage = AccessFlagsToPipelineStage(barrier.srcAccessMask, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
else
source_stage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
VkPipelineStageFlags destination_stage = 0;
if(barrier.newLayout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR)
destination_stage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
else if(barrier.dstAccessMask != 0)
destination_stage = AccessFlagsToPipelineStage(barrier.dstAccessMask, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
else
destination_stage = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
vkCmdPipelineBarrier(m_cmd_buffer, source_stage, destination_stage, 0, 0, nullptr, 0, nullptr, 1, &barrier);
image.RecordedInCommandBuffer();
VectorPushBackIfNotFound(m_cmd_resources, &image);
}
void CommandBuffer::EndRecord()
{
MLX_PROFILE_FUNCTION();
if(!IsInit())
FatalError("Vulkan : ending record on un uninit command buffer");
if(m_state != CommandBufferState::Recording)
return;
if(vkEndCommandBuffer(m_cmd_buffer) != VK_SUCCESS)
FatalError("Vulkan : failed to end recording command buffer");
m_state = CommandBufferState::Idle;
}
void CommandBuffer::SubmitIdle(bool should_wait_for_execution) noexcept
{
MLX_PROFILE_FUNCTION();
if(m_type != CommandBufferType::SingleTime)
{
Error("Vulkan : try to perform an idle submit on a command buffer that is not single-time, this is not allowed");
return;
}
m_fence.Reset();
VkSubmitInfo submit_info{};
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submit_info.commandBufferCount = 1;
submit_info.pCommandBuffers = &m_cmd_buffer;
VkResult res = vkQueueSubmit(RenderCore::Get().GetQueue().GetGraphic(), 1, &submit_info, m_fence.Get());
if(res != VK_SUCCESS)
FatalError("Vulkan error : failed to submit a single time command buffer, %", VerbaliseVkResult(res));
m_state = CommandBufferState::Submitted;
if(should_wait_for_execution)
WaitForExecution();
}
void CommandBuffer::Submit(NonOwningPtr<Semaphore> signal, NonOwningPtr<Semaphore> wait) noexcept
{
MLX_PROFILE_FUNCTION();
std::array<VkSemaphore, 1> signal_semaphores;
std::array<VkSemaphore, 1> wait_semaphores;
signal_semaphores[0] = (signal ? signal->Get() : VK_NULL_HANDLE);
wait_semaphores[0] = (wait ? wait->Get() : VK_NULL_HANDLE);
VkPipelineStageFlags wait_stages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
m_fence.Reset();
VkSubmitInfo submit_info{};
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submit_info.waitSemaphoreCount = (!wait ? 0 : wait_semaphores.size());
submit_info.pWaitSemaphores = wait_semaphores.data();
submit_info.pWaitDstStageMask = wait_stages;
submit_info.commandBufferCount = 1;
submit_info.pCommandBuffers = &m_cmd_buffer;
submit_info.signalSemaphoreCount = (!signal ? 0 : signal_semaphores.size());
submit_info.pSignalSemaphores = signal_semaphores.data();
VkResult res = vkQueueSubmit(RenderCore::Get().GetQueue().GetGraphic(), 1, &submit_info, m_fence.get());
if(res != VK_SUCCESS)
FatalError("Vulkan error : failed to submit draw command buffer, %", VerbaliseVkResult(res));
m_state = CommandBufferState::Submitted;
}
void CommandBuffer::UpdateSubmitState() noexcept
{
MLX_PROFILE_FUNCTION();
if(!m_fence.IsReady())
return;
for(NonOwningPtr<CommandResource> res : m_cmd_resources)
{
if(res)
res->RemovedFromCommandBuffer();
}
m_cmd_resources.clear();
m_state = CommandBufferState::Ready;
}
void CommandBuffer::PreTransferBarrier() noexcept
{
MLX_PROFILE_FUNCTION();
VkMemoryBarrier memory_barrier{};
memory_barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
memory_barrier.pNext = nullptr;
memory_barrier.srcAccessMask = 0U;
memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
vkCmdPipelineBarrier(m_cmd_buffer, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 1, &memory_barrier, 0, nullptr, 0, nullptr);
}
void CommandBuffer::PostTransferBarrier() noexcept
{
MLX_PROFILE_FUNCTION();
VkMemoryBarrier memory_barrier{};
memory_barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
memory_barrier.pNext = nullptr;
memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_UNIFORM_READ_BIT;
vkCmdPipelineBarrier(m_cmd_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT, 0, 1, &memory_barrier, 0, nullptr, 0, nullptr);
}
void CommandBuffer::Destroy() noexcept
{
MLX_PROFILE_FUNCTION();
m_fence.Destroy();
m_cmd_buffer = VK_NULL_HANDLE;
m_state = CommandBufferState::Uninit;
#ifdef DEBUG
Message("Vulkan : destroyed command buffer");
#endif
}
}

View File

@@ -1,42 +0,0 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* CommandManager.cpp :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/04/02 17:50:52 by maldavid #+# #+# */
/* Updated: 2024/04/23 14:55:04 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
#include <PreCompiled.h>
#include <Renderer/Command/CommandManager.h>
namespace mlx
{
void CommandManager::Init() noexcept
{
m_cmd_pool.Init();
for(int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++)
m_cmd_buffers[i].Init(CommandBufferType::LongTime, this);
}
void CommandManager::BeginRecord(int active_image_index)
{
m_cmd_buffers[active_image_index].BeginRecord();
}
void CommandManager::EndRecord(int active_image_index)
{
m_cmd_buffers[active_image_index].EndRecord();
}
void CommandManager::Destroy() noexcept
{
for(int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++)
m_cmd_buffers[i].Destroy();
m_cmd_pool.Destroy();
}
}

View File

@@ -1,37 +0,0 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* CommandPool.cpp :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2022/10/06 18:24:33 by maldavid #+# #+# */
/* Updated: 2024/04/23 14:57:15 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
#include <PreCompiled.h>
#include <Renderer/Command/CommandPool.h>
#include <Renderer/Core/RenderCore.h>
namespace mlx
{
void CommandPool::Init()
{
VkCommandPoolCreateInfo pool_info{};
pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
pool_info.queueFamilyIndex = RenderCore::Get().GetQueue().GetFamilies().graphics_family.value();
VkResult res = vkCreateCommandPool(RenderCore::Get().GetDevice().Get(), &pool_info, nullptr, &m_cmd_pool);
if(res != VK_SUCCESS)
FatalError("Vulkan : failed to create command pool, %", VerbaliseVkResult(res));
}
void CommandPool::Destroy() noexcept
{
vkDestroyCommandPool(RenderCore::Get().GetDevice().Get(), m_cmd_pool, nullptr);
m_cmd_pool = VK_NULL_HANDLE;
}
}

View File

@@ -1,64 +0,0 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* SingleTimeCommandManager.cpp :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/12/15 19:57:49 by maldavid #+# #+# */
/* Updated: 2024/04/23 15:05:19 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
#include <PreCompiled.h>
#include <Renderer/Command/SingleTimeCommandManager.h>
#include <Renderer/Core/RenderCore.h>
namespace mlx
{
void SingleTimeCmdManager::Init() noexcept
{
m_pool.init();
for(int i = 0; i < BASE_POOL_SIZE; i++)
{
m_buffers.emplace_back();
m_buffers.back().Init(CommandBufferType::SingleTime, &m_pool);
}
}
CommandBuffer& SingleTimeCmdManager::GetCmdBuffer() noexcept
{
for(CmdBuffer& buf : m_buffers)
{
if(buf.IsReadyToBeUsed())
{
buf.reset();
return buf;
}
}
m_buffers.emplace_back().Init(CommandBufferType::SingleTime, &m_pool);
return m_buffers.back();
}
void SingleTimeCmdManager::UpdateSingleTimesCmdBuffersSubmitState() noexcept
{
for(CmdBuffer& cmd : m_buffers)
cmd.UpdateSubmitState();
}
void SingleTimeCmdManager::WaitForAllExecutions() noexcept
{
for(CmdBuffer& cmd : m_buffers)
cmd.WaitForExecution();
}
void SingleTimeCmdManager::Destroy() noexcept
{
std::for_each(m_buffers.begin(), m_buffers.end(), [](CommandBuffer& buf)
{
buf.Destroy();
});
m_pool.Destroy();
}
}

View File

@@ -1,142 +0,0 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* Device.cpp :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2022/10/08 19:14:29 by maldavid #+# #+# */
/* Updated: 2024/04/23 18:10:08 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
#include <PreCmpiled.h>
#include <Renderer/Core/RenderCore.h>
namespace mlx
{
const std::vector<const char*> device_extensions = { VK_KHR_SWAPCHAIN_EXTENSION_NAME };
void Device::Init()
{
PickPhysicalDevice();
Queues::QueueFamilyIndices indices = RenderCore::Get().GetQueue().GetFamilies();
std::vector<VkDeviceQueueCreateInfo> queue_create_infos;
std::set<std::uint32_t> unique_queue_families = { indices.graphics_family.value(), indices.present_family.value() };
float queue_priority = 1.0f;
for(std::uint32_t queue_family : unique_queue_families)
{
VkDeviceQueueCreateInfo queue_create_info{};
queue_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
queue_create_info.queueFamilyIndex = queue_family;
queue_create_info.queueCount = 1;
queue_create_info.pQueuePriorities = &queue_priority;
queue_create_infos.push_back(queue_create_info);
}
VkPhysicalDeviceFeatures device_features{};
VkDeviceCreateInfo create_info{};
create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
create_info.queueCreateInfoCount = static_cast<std::uint32_t>(queue_create_infos.size());
create_info.pQueueCreateInfos = queue_create_infos.data();
create_info.pEnabledFeatures = &device_features;
create_info.enabledExtensionCount = static_cast<std::uint32_t>(device_extensions.size());
create_info.ppEnabledExtensionNames = device_extensions.data();
create_info.enabledLayerCount = 0;
VkResult res;
if((res = vkCreateDevice(m_physical_device, &create_info, nullptr, &m_device)) != VK_SUCCESS)
FatalError("Vulkan : failed to create logcal device, %", VerbaliseVkResult(res));
DebugLog("Vulkan : created new logical device");
}
void Device::PickPhysicalDevice()
{
std::uint32_t device_count = 0;
vkEnumeratePhysicalDevices(RenderCore::Get().GetInstance().Get(), &device_count, nullptr);
if(device_count == 0)
FatalError("Vulkan : failed to find GPUs with Vulkan support");
std::vector<VkPhysicalDevice> devices(device_count);
vkEnumeratePhysicalDevices(RenderCore::Get().GetInstance().Get(), &device_count, 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)
m_physical_device = devices_score.rbegin()->second;
else
FatalError("Vulkan : failed to find a suitable GPU");
#ifdef DEBUG
VkPhysicalDeviceProperties props;
vkGetPhysicalDeviceProperties(m_physical_device, &props);
DebugLog("Vulkan : picked a physical device, %s", props.deviceName);
#endif
RenderCore::Get().GetQueue().FindQueueFamilies(m_physical_device); // update queue indicies to current physical device
}
int Device::DeviceScore(VkPhysicalDevice device)
{
Queues::QueueFamilyIndices indices = RenderCore::Get().GetQueue().FindQueueFamilies(device);
bool extensions_supported = CheckDeviceExtensionSupport(device);
VkPhysicalDeviceProperties props;
vkGetPhysicalDeviceProperties(device, &props);
if(!indices.IsComplete() || !extensions_supported)
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 extension_count;
vkEnumerateDeviceExtensionProperties(device, nullptr, &extension_count, nullptr);
std::vector<VkExtensionProperties> available_extensions(extensionCount);
vkEnumerateDeviceExtensionProperties(device, nullptr, &extension_count, available_extensions.data());
std::set<std::string> required_extensions(device_extensions.begin(), device_extensions.end());
for(const auto& extension : available_extensions)
required_extensions.erase(extension.extensionName);
return required_extensions.empty();
}
void Device::Destroy() noexcept
{
vkDestroyDevice(m_device, nullptr);
m_device = VK_NULL_HANDLE;
DebugLog("Vulkan : destroyed a logical device");
}
}

View File

@@ -1,54 +0,0 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* Fence.cpp :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/04/02 17:53:06 by maldavid #+# #+# */
/* Updated: 2024/04/23 18:13:09 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
#include <Precompiled.h>
#include <Renderer/Core/Fence.h>
#include <Renderer/Core/RenderCore.h>
namespace mlx
{
void Fence::Init()
{
VkFenceCreateInfo fence_info{};
fence_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
fence_info.flags = VK_FENCE_CREATE_SIGNALED_BIT;
VkResult res;
if((res = vkCreateFence(RenderCore::Get().GetDevice().Get(), &fence_info, nullptr, &m_fence)) != VK_SUCCESS)
FatalError("Vulkan : failed to create a synchronization object (fence), %", VerbaliseVkResult(res));
DebugLog("Vulkan : created new fence");
}
void Fence::Wait() noexcept
{
vkWaitForFences(RenderCore::Get().GetDevice().Get(), 1, &m_fence, VK_TRUE, UINT64_MAX);
}
void Fence::Reset() noexcept
{
vkResetFences(RenderCore::Get().GetDevice().Get(), 1, &m_fence);
}
bool Fence::IsReady() const noexcept
{
return vkGetFenceStatus(RenderCore::Get().GetDevice().Get(), m_fence) == VK_SUCCESS;
}
void Fence::destroy() noexcept
{
if(m_fence != VK_NULL_HANDLE)
vkDestroyFence(RenderCore::Get().GetDevice().Get(), m_fence, nullptr);
m_fence = VK_NULL_HANDLE;
DebugLog("Vulkan : destroyed fence");
}
}

View File

@@ -1,88 +0,0 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* Instance.cpp :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2022/10/08 19:04:21 by maldavid #+# #+# */
/* Updated: 2024/04/23 18:43:47 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
#include <PreCompiled.h>
#include <Renderer/Core/Instance.h>
#include <Renderer/Core/RenderCore.h>
namespace mlx
{
void Instance::Init()
{
std::uint32_t api_version = std::min(volkGetInstanceVersion(), MLX_TARGET_VULKAN_API_VERSION);
if(api_version == 0)
FatalError("Vulkan API is not supported by this driver");
m_instance_version = api_version;
VkApplicationInfo app_info{};
app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
app_info.pEngineName = "MacroLibX";
app_info.engineVersion = MLX_VERSION;
app_info.apiVersion = api_version;
auto extensions = GetRequiredExtensions();
VkInstanceCreateInfo create_info{};
create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
create_info.pApplicationInfo = &app_info;
create_info.enabledExtensionCount = static_cast<std::uint32_t>(extensions.size());
create_info.ppEnabledExtensionNames = extensions.data();
create_info.enabledLayerCount = 0; // will be replaced if validation layers are enabled
create_info.pNext = nullptr;
VkDebugUtilsMessengerCreateInfoEXT debug_create_info;
if constexpr(enable_validation_layers)
{
if(RenderCore::Get().GetLayers().CheckValidationLayerSupport())
{
create_info.enabledLayerCount = static_cast<std::uint32_t>(validation_layers.size());
create_info.ppEnabledLayerNames = validation_layers.data();
RenderCore::Get().GetLayers().PopulateDebugMessengerCreateInfo(debug_create_info);
create_info.pNext = static_cast<VkDebugUtilsMessengerCreateInfoEXT*>(&debug_create_info);
}
}
VkResult res;
if((res = vkCreateInstance(&create_info, nullptr, &m_instance)) != VK_SUCCESS)
FatalError("Vulkan : failed to create Vulkan instance, %", VerbaliseVkResult(res));
volkLoadInstance(m_instance);
DebugLog("Vulkan : created new instance");
}
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(m_instance, nullptr);
m_instance = VK_NULL_HANDLE;
DebugLog("Vulkan : destroyed an instance");
}
}

View File

@@ -1,199 +0,0 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* Memory.cpp :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: kbz_8 <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/10/20 22:02:37 by kbz_8 #+# #+# */
/* Updated: 2024/04/23 18:49:10 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_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 <PreCompiled.h>
#include <Renderer/Core/RenderCore.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;
#if VMA_DEDICATED_ALLOCATION || VMA_VULKAN_VERSION >= 1001000
vma_vulkan_func.vkGetBufferMemoryRequirements2KHR = vkGetBufferMemoryRequirements2,
vma_vulkan_func.vkGetImageMemoryRequirements2KHR = vkGetImageMemoryRequirements2,
#endif
#if VMA_BIND_MEMORY2 || VMA_VULKAN_VERSION >= 1001000
vma_vulkan_func.vkBindBufferMemory2KHR = vkBindBufferMemory2,
vma_vulkan_func.vkBindImageMemory2KHR = vkBindImageMemory2,
#endif
#if VMA_MEMORY_BUDGET || VMA_VULKAN_VERSION >= 1001000
vma_vulkan_func.vkGetPhysicalDeviceMemoryProperties2KHR = vkGetPhysicalDeviceMemoryProperties2,
#endif
#if VMA_VULKAN_VERSION >= 1003000
vma_vulkan_func.vkGetDeviceBufferMemoryRequirements = vkGetDeviceBufferMemoryRequirements,
vma_vulkan_func.vkGetDeviceImageMemoryRequirements = vkGetDeviceImageMemoryRequirements,
#endif
VmaAllocatorCreateInfo allocator_create_info{};
allocator_create_info.vulkanApiVersion = RenderCore::Get().GetInstance().GetInstanceVersion();
allocator_create_info.physicalDevice = RenderCore::Get().GetDevice().GetPhysicalDevice();
allocator_create_info.device = RenderCore::Get().GetDevice().Get();
allocator_create_info.instance = RenderCore::Get().GetInstance().Get();
allocator_create_info.pVulkanFunctions = &vma_vulkan_func;
VkResult res = vmaCreateAllocator(&allocator_create_info, &m_allocator);
if(res != VK_SUCCESS)
FatalError("Graphics allocator : failed to create graphics memory allocator, %", VerbaliseVkResult(res));
DebugLog("Graphics allocator : created new allocator");
}
VmaAllocation GPUallocator::CreateBuffer(const VkBufferCreateInfo* binfo, const VmaAllocationCreateInfo* vinfo, VkBuffer& buffer, const char* name) noexcept
{
MLX_PROFILE_FUNCTION();
VmaAllocation allocation;
VkResult res = vmaCreateBuffer(m_allocator, binfo, vinfo, &buffer, &allocation, nullptr);
if(res != VK_SUCCESS)
FatalError("Graphics allocator : failed to allocate a buffer, %s", RCore::verbaliseResultVk(res));
if(name != nullptr)
{
RenderCore::Get().GetLayers().SetDebugUtilsObjectNameEXT(VK_OBJECT_TYPE_BUFFER, (std::uint64_t)buffer, name);
vmaSetAllocationName(m_allocator, allocation, name);
}
DebugLog("Graphics Allocator : created new buffer '%s'", name);
m_active_buffers_allocations++;
return allocation;
}
void GPUallocator::DestroyBuffer(VmaAllocation allocation, VkBuffer buffer) noexcept
{
MLX_PROFILE_FUNCTION();
vkDeviceWaitIdle(RenderCore::Get().GetDevice().Get());
vmaDestroyBuffer(m_allocator, buffer, allocation);
DebugLog("Graphics Allocator : destroyed buffer");
m_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(m_allocator, iminfo, vinfo, &image, &allocation, nullptr);
if(res != VK_SUCCESS)
FatalError("Graphics allocator : failed to allocate an image, %", VerbaliseVkResult(res));
if(name != nullptr)
{
RenderCore::Get().GetLayers().SetDebugUtilsObjectNameEXT(VK_OBJECT_TYPE_IMAGE, (std::uint64_t)image, name);
vmaSetAllocationName(m_allocator, allocation, name);
}
DebugLog("Graphics Allocator : created new image '%s'", name);
m_active_images_allocations++;
return allocation;
}
void GPUallocator::DestroyImage(VmaAllocation allocation, VkImage image) noexcept
{
MLX_PROFILE_FUNCTION();
vkDeviceWaitIdle(RenderCore::Get().GetDevice().Get());
vmaDestroyImage(m_allocator, image, allocation);
DebugLog("Graphics Allocator : destroyed image");
m_active_images_allocations--;
}
void GPUallocator::MapMemory(VmaAllocation allocation, void** data) noexcept
{
MLX_PROFILE_FUNCTION();
VkResult res = vmaMapMemory(m_allocator, allocation, data);
if(res != VK_SUCCESS)
FatalError("Graphics allocator : unable to map GPU memory to CPU memory, %", VerbaliseVkResult(res));
}
void GPUallocator::unmapMemory(VmaAllocation allocation) noexcept
{
MLX_PROFILE_FUNCTION();
vmaUnmapMemory(m_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())
{
Error("Graphics allocator : unable to dump memory to a json file");
return;
}
char* str = nullptr;
vmaBuildStatsString(m_allocator, &str, true);
file << str;
vmaFreeStatsString(m_allocator, str);
file.close();
id++;
}
void GPUallocator::Flush(VmaAllocation allocation, VkDeviceSize size, VkDeviceSize offset) noexcept
{
MLX_PROFILE_FUNCTION();
vmaFlushAllocation(m_allocator, allocation, offset, size);
}
void GPUallocator::Destroy() noexcept
{
if(m_active_images_allocations != 0)
Error("Graphics allocator : some user-dependant allocations were not freed before destroying the display (% active allocations). You may have not destroyed all the MLX resources you've created", m_active_images_allocations);
else if(m_active_buffers_allocations != 0)
Error("Graphics allocator : some MLX-dependant allocations were not freed before destroying the display (% active allocations). This is an error in the MLX, please report this should not happen", m_active_buffers_allocations);
if(m_active_images_allocations < 0 || m_active_buffers_allocations < 0)
Warning("Graphics allocator : the impossible happened, the MLX has freed more allocations than it has made (wtf)");
vmaDestroyAllocator(m_allocator);
m_active_buffers_allocations = 0;
m_active_images_allocations = 0;
DebugLog("Vulkan : destroyed a graphics allocator");
}
}

View File

@@ -1,53 +0,0 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* Queues.cpp :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2022/10/08 19:02:42 by maldavid #+# #+# */
/* Updated: 2024/04/23 18:51:21 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
#include <PreCompiled.h>
#include <Renderer/Core/RenderCore.h>
namespace mlx
{
Queues::QueueFamilyIndices Queues::findQueueFamilies(VkPhysicalDevice device)
{
std::uint32_t queue_family_count = 0;
vkGetPhysicalDeviceQueueFamilyProperties(device, &queue_family_count, nullptr);
std::vector<VkQueueFamilyProperties> queue_families(queueFamilyCount);
vkGetPhysicalDeviceQueueFamilyProperties(device, &queue_family_count, queue_families.data());
n_families = Queues::QueueFamilyIndices{};
int i = 0;
for(const auto& queue_family : queue_families)
{
if(queue_family.queueFlags & VK_QUEUE_GRAPHICS_BIT)
m_families->graphics_family = i;
if(glfwGetPhysicalDevicePresentationSupport(RenderCore::Get().GetInstance().Get(), device, i))
m_families->present_family = i;
if(m_families->IsComplete())
return *m_families;
i++;
}
return *m_families;
}
void Queues::Init()
{
if(!m_families.has_value())
FindQueueFamilies(RenderCore::Get().GetDevice().GetPhysicalDevice());
vkGetDeviceQueue(RenderCore::Get().GetDevice().Get(), m_families->graphics_family.value(), 0, &m_graphics_queue);
vkGetDeviceQueue(RenderCore::Get().GetDevice().Get(), m_families->present_family.value(), 0, &m_present_queue);
DebugLog("Vulkan : got graphics and present queues");
}
}

View File

@@ -1,134 +0,0 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* RenderCore.cpp :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2022/12/17 23:33:34 by maldavid #+# #+# */
/* Updated: 2024/04/23 18:54:26 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
#define VK_NO_PROTOTYPES
#define VOLK_IMPLEMENTATION
#include <volk.h>
#include <PreCompiled.h>
#include <Renderer/Core/RenderCore.h>
#include <Renderer/Command/CommandBuffer.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
{
const char* VerbaliseVkResult(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 access_flags, VkPipelineStageFlags stage_flags)
{
VkPipelineStageFlags stages = 0;
while(access_flags != 0)
{
VkAccessFlagBits Access_flag = static_cast<VkAccessFlagBits>(access_flags & (~(access_flags - 1)));
if(Access_flag == 0 || (Access_flag & (Access_flag - 1)) != 0)
FatalError("Vulkan : an error has been caught during access flag to pipeline stage operation");
access_flags &= ~Access_flag;
switch(Access_flag)
{
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 |= stage_flags | 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 |= stage_flags | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; break;
case VK_ACCESS_SHADER_WRITE_BIT: stages |= stage_flags | 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: Error("Vulkan : unknown access flag"); break;
}
}
return stages;
}
void RenderCore::Init()
{
if(volkInitialize() != VK_SUCCESS)
FatalError("Vulkan loader : cannot load %, are you sure Vulkan is installed on your system ?", VULKAN_LIB_NAME);
m_instance.Init();
volkLoadInstance(m_instance.Get());
m_layers.Init();
m_device.Init();
volkLoadDevice(m_device.Get());
m_queues.Init();
m_allocator.Init();
m_cmd_manager.Init();
m_is_init = true;
}
void RenderCore::Destroy()
{
if(!m_is_init)
return;
vkDeviceWaitIdle(m_device.Get());
m_pool_manager.DestroyAllPools();
m_cmd_manager.Destroy();
m_allocator.Destroy();
m_device.Destroy();
m_layers.Destroy();
m_instance.Destroy();
m_is_init = false;
}
}

View File

@@ -1,36 +0,0 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* Semaphore.cpp :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2022/10/08 19:01:08 by maldavid #+# #+# */
/* Updated: 2024/04/23 18:55:42 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
#include <PreCompiled.h>
#include <Renderer/Core/RenderCore.h>
#include <Renderer/Core/Semaphore.h>
namespace mlx
{
void Semaphore::Init()
{
VkSemaphoreCreateInfo semaphore_info{};
semaphore_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
VkResult res;
if((res = vkCreateSemaphore(RenderCore::Get().GetDevice().Get(), &semaphore_info, nullptr, &m_semaphore)) != VK_SUCCESS)
FatalError("Vulkan : failed to create a synchronization object (semaphore), %", VerbaliseVkResult(res));
DebugLog("Vulkan : created new semaphores");
}
void Semaphore::Destroy() noexcept
{
vkDestroySemaphore(RenderCore::Get().GetDevice().Get(), m_semaphore, nullptr);
m_semaphore = VK_NULL_HANDLE;
DebugLog("Vulkan : destroyed semaphore");
}
}

View File

@@ -1,43 +0,0 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* Surface.cpp :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2022/10/08 18:58:49 by maldavid #+# #+# */
/* Updated: 2024/04/23 18:56:56 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(RenderCore::Get().GetInstance().Get(), renderer.GetWindow()->GetNativeWindow(), NULL, &m_surface) != VK_SUCCESS)
FatalError("Vulkan : failed to create a surface");
DebugLog("Vulkan : created new surface");
}
VkSurfaceFormatKHR Surface::ChooseSwapSurfaceFormat(const std::vector<VkSurfaceFormatKHR>& available_formats)
{
auto it = std::find_if(available_formats.begin(), available_formats.end(), [](VkSurfaceFormatKHR format)
{
return format.format == VK_FORMAT_R8G8B8A8_SRGB && format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
});
return (it == available_formats.end() ? available_formats[0] : *it);
}
void Surface::Destroy() noexcept
{
vkDestroySurfaceKHR(RenderCore::Get().GetInstance().Get(), m_surface, nullptr);
m_surface = VK_NULL_HANDLE;
DebugLog("Vulkan : destroyed a surface");
}
}

View File

@@ -1,122 +0,0 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* ValidationLayers.cpp :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2022/12/19 14:05:25 by maldavid #+# #+# */
/* Updated: 2024/04/23 19:20:21 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
#include <PreCompiled.h>
#include <Renderer/Core/RenderCore.h>
namespace mlx
{
void ValidationLayers::Init()
{
if constexpr(!enable_validation_layers)
return;
std::uint32_t extension_count;
vkEnumerateInstanceExtensionProperties(nullptr, &extension_count, nullptr);
std::vector<VkExtensionProperties> extensions(extension_count);
vkEnumerateInstanceExtensionProperties(nullptr, &extension_count, extensions.data());
if(!std::any_of(extensions.begin(), extensions.end(), [=](VkExtensionProperties ext) { return std::strcmp(ext.extensionName, VK_EXT_DEBUG_UTILS_EXTENSION_NAME) == 0; }))
{
Warning("Vulkan : %s not present, debug utils are disabled", VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
return;
}
VkDebugUtilsMessengerCreateInfoEXT create_info{};
populateDebugMessengerCreateInfo(create_info);
VkResult res = createDebugUtilsMessengerEXT(&create_info, nullptr);
if(res != VK_SUCCESS)
Warning("Vulkan : failed to set up debug messenger, %", VerbaliseVkResult(res));
else
DebugLog("Vulkan : enabled validation layers");
f_vkSetDebugUtilsObjectNameEXT = (PFN_vkSetDebugUtilsObjectNameEXT)vkGetInstanceProcAddr(RenderCore::Get().GetInstance().Get(), "vkSetDebugUtilsObjectNameEXT");
if(!f_vkSetDebugUtilsObjectNameEXT)
Warning("Vulkan : failed to set up debug object names, %", VerbaliseVkResult(VK_ERROR_EXTENSION_NOT_PRESENT));
else
DebugLog("Vulkan : enabled debug object names");
}
bool ValidationLayers::CheckValidationLayerSupport()
{
std::uint32_t layer_count;
vkEnumerateInstanceLayerProperties(&layer_count, nullptr);
std::vector<VkLayerProperties> available_layers(layer_count);
vkEnumerateInstanceLayerProperties(&layer_count, available_layers.data());
return std::all_of(validation_layers.begin(), validation_layers.end(), [&](const char* layer_name)
{
if(!std::any_of(available_layers.begin(), available_layers.end(), [=](VkLayerProperties props) { return std::strcmp(layer_name, props.layer_name) == 0; }))
{
Error("Vulkan : a validation layer was requested but was not found ('%')", layer_name);
return false;
}
return true;
});
}
VkResult ValidationLayers::SetDebugUtilsObjectNameEXT(VkObjectType object_type, std::uint64_t object_handle, const char* object_name)
{
if(!f_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 f_vkSetDebugUtilsObjectNameEXT(RenderCore::Get().GetDevice().Get(), &name_info);
}
void ValidationLayers::PopulateDebugMessengerCreateInfo(VkDebugUtilsMessengerCreateInfoEXT& create_info)
{
create_info = {};
create_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
create_info.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;
create_info.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;
create_info.pfnUserCallback = ValidationLayers::DebugCallback;
}
void ValidationLayers::Destroy()
{
if constexpr(enable_validation_layers)
{
DestroyDebugUtilsMessengerEXT(nullptr);
#ifdef DEBUG
DebugLog("Vulkan : destroyed validation layers");
#endif
}
}
VkResult ValidationLayers::CreateDebugUtilsMessengerEXT(const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator)
{
auto func = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(RenderCore::Get().GetInstance().Get(), "vkCreateDebugUtilsMessengerEXT");
return func != nullptr ? func(RenderCore::Get().GetInstance().Get(), pCreateInfo, pAllocator, &m_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)
Error(pCallbackData->pMessage);
else if(messageSeverity == VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT)
Warning(pCallbackData->pMessage);
return VK_FALSE;
}
void ValidationLayers::destroyDebugUtilsMessengerEXT(const VkAllocationCallbacks* pAllocator)
{
auto func = (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr(RenderCore::Get().GetInstance().Get(), "vkDestroyDebugUtilsMessengerEXT");
if(func != nullptr)
func(RenderCore::Get().GetInstance().Get(), m_debug_messenger, pAllocator);
}
}

141
runtime/Sources/Renderer/Descriptor.cpp git.filemode.normal_file
View File

@@ -0,0 +1,141 @@
#include <PreCompiled.h>
#include <Renderer/Image.h>
#include <Renderer/Enums.h>
#include <Renderer/Buffer.h>
#include <Renderer/Descriptor.h>
#include <Renderer/RenderCore.h>
namespace mlx
{
void TransitionImageToCorrectLayout(Image& image, VkCommandBuffer cmd)
{
if(!image.IsInit())
return;
if(image.GetType() == ImageType::Color)
image.TransitionLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, cmd);
else
Error("Vulkan : cannot transition descriptor image layout, unkown image type");
}
DescriptorSet::DescriptorSet(const ShaderSetLayout& layout, VkDescriptorSetLayout vklayout, ShaderType shader_type)
: m_set_layout(vklayout)
{
for(auto& [binding, type] : layout.binds)
{
m_descriptors.emplace_back();
m_descriptors.back().type = type;
m_descriptors.back().shader_type = shader_type;
m_descriptors.back().binding = binding;
}
for(std::size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++)
m_set[i] = kvfAllocateDescriptorSet(RenderCore::Get().GetDevice(), vklayout);
}
DescriptorSet::DescriptorSet(VkDescriptorSetLayout layout, const std::vector<Descriptor>& descriptors)
: m_set_layout(layout), m_descriptors(descriptors)
{
for(std::size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++)
m_set[i] = kvfAllocateDescriptorSet(RenderCore::Get().GetDevice(), layout);
}
void DescriptorSet::SetImage(std::size_t i, std::uint32_t binding, class Image& image)
{
Verify(m_set[i] != VK_NULL_HANDLE, "invalid descriptor");
auto it = std::find_if(m_descriptors.begin(), m_descriptors.end(), [=](Descriptor descriptor)
{
return binding == descriptor.binding;
});
if(it == m_descriptors.end())
{
Warning("Vulkan : cannot update descriptor set image; invalid binding");
return;
}
if(it->type != VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
{
Error("Vulkan : trying to bind an image to the wrong descriptor");
return;
}
it->image_ptr = &image;
}
void DescriptorSet::SetStorageBuffer(std::size_t i, std::uint32_t binding, class GPUBuffer& buffer)
{
Verify(m_set[i] != VK_NULL_HANDLE, "invalid descriptor");
auto it = std::find_if(m_descriptors.begin(), m_descriptors.end(), [=](Descriptor descriptor)
{
return binding == descriptor.binding;
});
if(it == m_descriptors.end())
{
Warning("Vulkan : cannot update descriptor set buffer; invalid binding");
return;
}
if(it->type != VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
{
Error("Vulkan : trying to bind a buffer to the wrong descriptor");
return;
}
it->storage_buffer_ptr = &buffer;
}
void DescriptorSet::SetUniformBuffer(std::size_t i, std::uint32_t binding, class GPUBuffer& buffer)
{
Verify(m_set[i] != VK_NULL_HANDLE, "invalid descriptor");
auto it = std::find_if(m_descriptors.begin(), m_descriptors.end(), [=](Descriptor descriptor)
{
return binding == descriptor.binding;
});
if(it == m_descriptors.end())
{
Warning("Vulkan : cannot update descriptor set buffer; invalid binding");
return;
}
if(it->type != VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER)
{
Error("Vulkan : trying to bind a buffer to the wrong descriptor");
return;
}
it->uniform_buffer_ptr = &buffer;
}
void DescriptorSet::Update(std::size_t i, VkCommandBuffer cmd) noexcept
{
Verify(m_set[i] != VK_NULL_HANDLE, "invalid descriptor");
std::vector<VkWriteDescriptorSet> writes;
std::vector<VkDescriptorBufferInfo> buffer_infos;
std::vector<VkDescriptorImageInfo> image_infos;
for(auto& descriptor : m_descriptors)
{
if(descriptor.image_ptr)
{
TransitionImageToCorrectLayout(*descriptor.image_ptr, cmd);
VkDescriptorImageInfo info{};
info.sampler = descriptor.image_ptr->GetSampler();
info.imageLayout = descriptor.image_ptr->GetLayout();
info.imageView = descriptor.image_ptr->GetImageView();
image_infos.push_back(info);
writes.push_back(kvfWriteImageToDescriptorSet(RenderCore::Get().GetDevice(), m_set[i], &image_infos.back(), descriptor.binding));
}
else if(descriptor.uniform_buffer_ptr)
{
VkDescriptorBufferInfo info{};
info.buffer = descriptor.uniform_buffer_ptr->Get();
info.offset = descriptor.uniform_buffer_ptr->GetOffset();
info.range = VK_WHOLE_SIZE;
buffer_infos.push_back(info);
writes.push_back(kvfWriteUniformBufferToDescriptorSet(RenderCore::Get().GetDevice(), m_set[i], &buffer_infos.back(), descriptor.binding));
}
else if(descriptor.storage_buffer_ptr)
{
VkDescriptorBufferInfo info{};
info.buffer = descriptor.storage_buffer_ptr->Get();
info.offset = descriptor.storage_buffer_ptr->GetOffset();
info.range = VK_WHOLE_SIZE;
buffer_infos.push_back(info);
writes.push_back(kvfWriteStorageBufferToDescriptorSet(RenderCore::Get().GetDevice(), m_set[i], &buffer_infos.back(), descriptor.binding));
}
}
vkUpdateDescriptorSets(RenderCore::Get().GetDevice(), writes.size(), writes.data(), 0, nullptr);
}
}

View File

@@ -1,69 +0,0 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* DescriptorPool.cpp :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/01/23 18:34:23 by maldavid #+# #+# */
/* Updated: 2024/04/23 19:39:39 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
#include <PreCompiled.h>
#include <Renderer/Descriptors/DescriptorPool.h>
#include <Renderer/Descriptors/DescriptorSet.h>
#include <Renderer/Core/RenderCore.h>
namespace mlx
{
void DescriptorPool::Init(std::vector<VkDescriptorPoolSize> sizes)
{
VkDescriptorPoolCreateInfo pool_info{};
pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
pool_info.poolSizeCount = sizes.size();
pool_info.pPoolSizes = sizes.data();
pool_info.maxSets = MAX_SETS_PER_POOL;
pool_info.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT;
VkResult res = vkCreateDescriptorPool(RenderCore::Get().GetDevice().Get(), &pool_info, nullptr, &m_pool);
if(res != VK_SUCCESS)
FatalError("Vulkan : failed to create descriptor pool, %", VerbaliseVkResult(res));
DebugLog("Vulkan : created new descriptor pool");
}
VkDescriptorSet DescriptorPool::AllocateDescriptorSet(class DescriptorSetLayout& layout)
{
VkDescriptorSet set;
VkDescriptorSetAllocateInfo alloc_info{};
alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
alloc_info.descriptorPool = m_pool;
alloc_info.descriptorSetCount = 1;
alloc_info.pSetLayouts = layouts.Get();
VkResult res = vkAllocateDescriptorSets(RenderCore::Get().GetDevice().Get(), &alloc_info, &set);
if(res != VK_SUCCESS)
FatalError("Vulkan : failed to allocate descriptor set, %", VerbaliseVkResult(res));
m_allocated_sets++;
DebugLog("Vulkan : created new descriptor set");
return set;
}
void DescriptorPool::FreeDescriptor(VkDescriptorSet set)
{
if(!IsInit())
return;
vkFreeDescriptorSets(RenderCore::Get().GetDevice().Get(), m_pool, 1, set);
m_allocated_sets--; // if this goes underflow I quit
}
void DescriptorPool::Destroy() noexcept
{
if(m_pool != VK_NULL_HANDLE)
vkDestroyDescriptorPool(RenderCore::Get().GetDevice().Get(), m_pool, nullptr);
m_pool = VK_NULL_HANDLE;
DebugLog("Vulkan : destroyed a descriptor pool");
}
}

View File

@@ -1,41 +0,0 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* DescriptorPoolManager.cpp :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2024/01/20 06:51:47 by maldavid #+# #+# */
/* Updated: 2024/04/23 19:41:38 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
#include <PreCompiled.h>
#include <Renderer/Core/RenderCore.h>
#include <Renderer/Descriptors/DescriptorPoolManager.h>
namespace mlx
{
DescriptorPool& DescriptorPoolManager::GetAvailablePool()
{
for(auto& pool : m_pools)
{
if(pool.GetNumberOfSetsAllocated() < MAX_SETS_PER_POOL)
return pool;
}
std::vector<VkDescriptorPoolSize> pool_sizes = {
{ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, (MAX_FRAMES_IN_FLIGHT * NUMBER_OF_UNIFORM_BUFFERS) },
{ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, MAX_SETS_PER_POOL - (MAX_FRAMES_IN_FLIGHT * NUMBER_OF_UNIFORM_BUFFERS) }
};
m_pools.emplace_front().Init(std::move(pool_sizes));
return m_pools.front();
}
void DescriptorPoolManager::DestroyAllPools()
{
for(auto& pool : m_pools)
pool.Destroy();
m_pools.clear();
}
}

View File

@@ -1,116 +0,0 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* DescriptorSet.cpp :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/01/23 18:40:44 by maldavid #+# #+# */
/* Updated: 2024/04/23 21:17:39 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
#include <PreCompiled.h>
#include <Renderer/Descriptors/DescriptorSet.h>
#include <Renderer/Core/RenderCore.h>
#include <Renderer/Descriptors/DescriptorPool.h>
#include <Renderer/Buffers/UniformBuffer.h>
#include <Renderer/Renderer.h>
#include <Renderer/Images/Image.h>
namespace mlx
{
void DescriptorSet::Init(NonOwningPtr<Renderer> renderer, NonOwningPtr<DescriptorPool> pool, DescriptorSetLayout layout)
{
MLX_PROFILE_FUNCTION();
p_renderer = renderer;
m_layout = layout;
p_pool = pool;
for(int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++)
m_desc_set[i] = pool->AllocateDescriptorSet(layout);
}
void DescriptorSet::WriteDescriptor(int binding, NonOwningPtr<UniformBuffer> ubo) const noexcept
{
MLX_PROFILE_FUNCTION();
auto device = RenderCore::Get().GetDevice().Get();
for(int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++)
{
VkDescriptorBufferInfo buffer_info{};
buffer_info.buffer = ubo->Get(i);
buffer_info.offset = ubo->GetOffset(i);
buffer_info.range = ubo->GetSize(i);
VkWriteDescriptorSet descriptor_write{};
descriptor_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
descriptor_write.dstSet = m_desc_set[i];
descriptor_write.dstBinding = binding;
descriptor_write.dstArrayElement = 0;
descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
descriptor_write.descriptorCount = 1;
descriptor_write.pBufferInfo = &buffer_info;
vkUpdateDescriptorSets(device, 1, &descriptor_write, 0, nullptr);
}
}
void DescriptorSet::WriteDescriptor(int binding, const Image& image) const noexcept
{
MLX_PROFILE_FUNCTION();
auto device = RenderCore::Get().GetDevice().Get();
VkDescriptorImageInfo image_info{};
image_info.imageLayout = image.GetLayout();
image_info.imageView = image.GetImageView();
image_info.sampler = image.GetSampler();
VkWriteDescriptorSet descriptor_write{};
descriptor_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
descriptor_write.dstSet = m_desc_set[m_renderer->GetActiveImageIndex()];
descriptor_write.dstBinding = binding;
descriptor_write.dstArrayElement = 0;
descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
descriptor_write.descriptorCount = 1;
descriptor_write.pImageInfo = &image_info;
vkUpdateDescriptorSets(device, 1, &descriptor_write, 0, nullptr);
}
void DescriptorSet::Bind() noexcept
{
vkCmdBindDescriptorSets(p_renderer->GetActiveCmdBuffer().Get(), VK_PIPELINE_BIND_POINT_GRAPHICS, p_renderer->GetPipeline().GetPipelineLayout(), 0, 1, m_desc_set[p_renderer->GetActiveImageIndex()], 0, nullptr);
}
DescriptorSet DescriptorSet::Duplicate()
{
MLX_PROFILE_FUNCTION();
DescriptorSet set;
set.Init(p_renderer, &RenderCore::Get().GetDescriptorPool(), m_layout);
return set;
}
VkDescriptorSet& DescriptorSet::operator()() noexcept
{
return m_desc_set[p_renderer->GetActiveImageIndex()];
}
VkDescriptorSet& DescriptorSet::Get() noexcept
{
return m_desc_set[p_renderer->GetActiveImageIndex()];
}
void DescriptorSet::Destroy() noexcept
{
MLX_PROFILE_FUNCTION();
if(p_pool != nullptr && RenderCore::Get().IsInit()) // checks if the render core is still init (it should always be init but just in case)
p_pool->FreeDescriptor(*this);
for(auto& set : m_desc_set)
{
if(set != VK_NULL_HANDLE)
set = VK_NULL_HANDLE;
}
}
}

View File

@@ -1,49 +0,0 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* DescriptorSetLayout.cpp :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/01/23 18:37:28 by maldavid #+# #+# */
/* Updated: 2024/04/23 19:52:41 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
#include <PreCompiled.h>
#include <Renderer/Descriptors/DescriptorSetLayout.h>
#include <Renderer/Core/Rendercore.h>
namespace mlx
{
void DescriptorSetLayout::Init(std::vector<std::pair<int, VkDescriptorType>> binds, VkShaderStageFlagBits stage)
{
std::vector<VkDescriptorSetLayoutBinding> bindings(binds.size());
for(std::size_t i = 0; i < binds.size(); i++)
{
bindings[i].binding = binds[i].first;
bindings[i].descriptorCount = 1;
bindings[i].descriptorType = binds[i].second;
bindings[i].pImmutableSamplers = nullptr;
bindings[i].stageFlags = stage;
}
m_bindings = std::move(binds);
VkDescriptorSetLayoutCreateInfo layout_info{};
layout_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
layout_info.bindingCount = m_bindings.size();
layout_info.pBindings = m_bindings.data();
VkResult res = vkCreateDescriptorSetLayout(RenderCore::Get().GetDevice().Get(), &layout_info, nullptr, &m_layout);
if(res != VK_SUCCESS)
FatalError("Vulkan : failed to create descriptor set layout, %", VerbaliseVkResult(res));
}
void DescriptorSetLayout::Destroy() noexcept
{
vkDestroyDescriptorSetLayout(RenderCore::Get().GetDevice().Get(), m_layout, nullptr);
m_layout = VK_NULL_HANDLE;
}
}

113
runtime/Sources/Renderer/Image.cpp git.filemode.normal_file
View File

@@ -0,0 +1,113 @@
#include <PreCompiled.h>
#include <Renderer/Image.h>
#include <Maths/Vec4.h>
#include <Renderer/RenderCore.h>
namespace mlx
{
void Image::Init(ImageType type, std::uint32_t width, std::uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, bool is_multisampled)
{
m_type = type;
m_width = width;
m_height = height;
m_format = format;
m_tiling = tiling;
m_is_multisampled = is_multisampled;
VmaAllocationCreateInfo alloc_info{};
alloc_info.usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE;
VkImageCreateInfo image_info{};
image_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
image_info.imageType = VK_IMAGE_TYPE_2D;
image_info.extent.width = width;
image_info.extent.height = height;
image_info.extent.depth = 1;
image_info.mipLevels = 1;
image_info.arrayLayers = 1;
image_info.format = format;
image_info.tiling = tiling;
image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
image_info.usage = usage;
image_info.samples = (m_is_multisampled ? VK_SAMPLE_COUNT_4_BIT : VK_SAMPLE_COUNT_1_BIT);
image_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
m_allocation = RenderCore::Get().GetAllocator().CreateImage(&image_info, alloc_info, &m_image);
}
void Image::CreateImageView(VkImageViewType type, VkImageAspectFlags aspect_flags, int layer_count) noexcept
{
m_image_view = kvfCreateImageView(RenderCore::Get().GetDevice(), m_image, m_format, type, aspect_flags, layer_count);
}
void Image::CreateSampler() noexcept
{
m_sampler = kvfCreateSampler(RenderCore::Get().GetDevice(), VK_FILTER_NEAREST, VK_SAMPLER_ADDRESS_MODE_REPEAT, VK_SAMPLER_MIPMAP_MODE_NEAREST);
}
void Image::TransitionLayout(VkImageLayout new_layout, VkCommandBuffer cmd)
{
if(new_layout == m_layout)
return;
bool is_single_time_cmd_buffer = (cmd == VK_NULL_HANDLE);
if(is_single_time_cmd_buffer)
cmd = kvfCreateCommandBuffer(RenderCore::Get().GetDevice());
KvfImageType kvf_type = KVF_IMAGE_OTHER;
switch(m_type)
{
case ImageType::Color: kvf_type = KVF_IMAGE_COLOR; break;
default: break;
}
kvfTransitionImageLayout(RenderCore::Get().GetDevice(), m_image, kvf_type, cmd, m_format, m_layout, new_layout, is_single_time_cmd_buffer);
m_layout = new_layout;
}
void Image::Clear(VkCommandBuffer cmd, Vec4f color)
{
VkImageSubresourceRange subresource_range{};
subresource_range.baseMipLevel = 0;
subresource_range.layerCount = (m_type == ImageType::Cube ? 6 : 1);
subresource_range.levelCount = 1;
subresource_range.baseArrayLayer = 0;
if(m_type == ImageType::Color || m_type == ImageType::Cube)
{
VkImageLayout old_layout = m_layout;
TransitionLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, cmd);
subresource_range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
VkClearColorValue clear_color = VkClearColorValue({ { color.x, color.y, color.z, color.w } });
vkCmdClearColorImage(cmd, m_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clear_color, 1, &subresource_range);
TransitionLayout(old_layout, cmd);
}
else if(m_type == ImageType::Depth)
{
VkClearDepthStencilValue clear_depth_stencil = { 1.0f, 1 };
subresource_range.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
TransitionLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, cmd);
vkCmdClearDepthStencilImage(cmd, m_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clear_depth_stencil, 1, &subresource_range);
}
}
void Image::DestroySampler() noexcept
{
if(m_sampler != VK_NULL_HANDLE)
kvfDestroySampler(RenderCore::Get().GetDevice(), m_sampler);
m_sampler = VK_NULL_HANDLE;
}
void Image::DestroyImageView() noexcept
{
if(m_image_view != VK_NULL_HANDLE)
kvfDestroyImageView(RenderCore::Get().GetDevice(), m_image_view);
m_image_view = VK_NULL_HANDLE;
}
void Image::Destroy() noexcept
{
DestroySampler();
DestroyImageView();
if(m_image != VK_NULL_HANDLE)
RenderCore::Get().GetAllocator().DestroyImage(m_allocation, m_image);
m_image = VK_NULL_HANDLE;
}
}

View File

@@ -1,393 +0,0 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* Image.cpp :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/01/25 11:59:07 by maldavid #+# #+# */
/* Updated: 2024/04/23 20:02:25 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
#include <PreCompiled.h>
#include <Renderer/Images/Image.h>
#include <Renderer/Core/RenderCore.h>
namespace mlx
{
bool IsStencilFormat(VkFormat format)
{
switch(format)
{
case VK_FORMAT_D32_SFLOAT_S8_UINT:
case VK_FORMAT_D24_UNORM_S8_UINT:
return true;
default: return false;
}
}
bool IsDepthFormat(VkFormat format)
{
switch(format)
{
case VK_FORMAT_D16_UNORM:
case VK_FORMAT_D32_SFLOAT:
case VK_FORMAT_D32_SFLOAT_S8_UINT:
case VK_FORMAT_D24_UNORM_S8_UINT:
case VK_FORMAT_D16_UNORM_S8_UINT:
return true;
default: return false;
}
}
VkFormat BitsToFormat(std::uint32_t bits)
{
switch(bits)
{
case 8: return VK_FORMAT_R8_UNORM;
case 16: return VK_FORMAT_R8G8_UNORM;
case 24: return VK_FORMAT_R8G8B8_UNORM;
case 32: return VK_FORMAT_R8G8B8A8_UNORM;
case 48: return VK_FORMAT_R16G16B16_SFLOAT;
case 64: return VK_FORMAT_R16G16B16A16_SFLOAT;
case 96: return VK_FORMAT_R32G32B32_SFLOAT;
case 128: return VK_FORMAT_R32G32B32A32_SFLOAT;
default:
FatalError("Vulkan : unsupported image bit-depth");
return VK_FORMAT_R8G8B8A8_UNORM;
}
}
VkPipelineStageFlags LayoutToAccessMask(VkImageLayout layout, bool is_destination)
{
VkPipelineStageFlags access_mask = 0;
switch(layout)
{
case VK_IMAGE_LAYOUT_UNDEFINED:
if(is_destination)
Error("Vulkan : the new layout used in a transition must not be VK_IMAGE_LAYOUT_UNDEFINED");
break;
case VK_IMAGE_LAYOUT_GENERAL: access_mask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; break;
case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: access_mask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; break;
case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: access_mask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; break;
case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL:
access_mask = VK_ACCESS_SHADER_READ_BIT; // VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
break;
case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: access_mask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_INPUT_ATTACHMENT_READ_BIT; break;
case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: access_mask = VK_ACCESS_TRANSFER_READ_BIT; break;
case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: access_mask = VK_ACCESS_TRANSFER_WRITE_BIT; break;
case VK_IMAGE_LAYOUT_PREINITIALIZED:
if(!is_destination)
access_mask = VK_ACCESS_HOST_WRITE_BIT;
else
Error("Vulkan : the new layout used in a transition must not be VK_IMAGE_LAYOUT_PREINITIALIZED");
break;
case VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL: access_mask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT; break;
case VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL: access_mask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT; break;
case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR: access_mask = VK_ACCESS_MEMORY_READ_BIT; break;
default: Error("Vulkan : unexpected image layout"); break;
}
return access_mask;
}
void Image::Create(std::uint32_t width, std::uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, const char* name, bool dedicated_memory)
{
m_width = width;
m_height = height;
m_format = format;
m_tiling = tiling;
VkImageCreateInfo image_info{};
image_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
image_info.imageType = VK_IMAGE_TYPE_2D;
image_info.extent.width = width;
image_info.extent.height = height;
image_info.extent.depth = 1;
image_info.mipLevels = 1;
image_info.arrayLayers = 1;
image_info.format = format;
image_info.tiling = tiling;
image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
image_info.usage = usage;
image_info.samples = VK_SAMPLE_COUNT_1_BIT;
image_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
VmaAllocationCreateInfo alloc_info{};
alloc_info.usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE;
if(dedicated_memory)
{
alloc_info.flags = VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT;
alloc_info.priority = 1.0f;
}
m_allocation = RenderCore::Get().GetAllocator().CreateImage(&image_info, &alloc_info, m_image, name);
#ifdef DEBUG
m_name = name;
#endif
}
void Image::CreateImageView(VkImageViewType type, VkImageAspectFlags aspect_flags) noexcept
{
VkImageViewCreateInfo view_info{};
view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
view_info.image = m_image;
view_info.viewType = type;
view_info.format = m_format;
view_info.subresourceRange.aspectMask = aspect_flags;
view_info.subresourceRange.baseMipLevel = 0;
view_info.subresourceRange.levelCount = 1;
view_info.subresourceRange.baseArrayLayer = 0;
view_info.subresourceRange.layerCount = 1;
VkResult res = vkCreateImageView(RenderCore::Get().GetDevice().Get(), &view_info, nullptr, &m_image_view);
if(res != VK_SUCCESS)
FatalError("Vulkan : failed to create an image view, %s", VerbaliseVkResult(res));
#ifdef DEBUG
else
RenderCore::Get().GetLayers().SetDebugUtilsObjectNameEXT(VK_OBJECT_TYPE_IMAGE_VIEW, (std::uint64_t)m_image_view, m_name.c_str());
#endif
}
void Image::CreateSampler() noexcept
{
VkSamplerCreateInfo info{};
info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
info.magFilter = VK_FILTER_NEAREST;
info.minFilter = VK_FILTER_NEAREST;
info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST;
info.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
info.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
info.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
info.minLod = -1000;
info.maxLod = 1000;
info.anisotropyEnable = VK_FALSE;
info.maxAnisotropy = 1.0f;
VkResult res = vkCreateSampler(RenderCore::Get().GetDevice().Get(), &info, nullptr, &m_sampler);
if(res != VK_SUCCESS)
FatalError("Vulkan : failed to create an image sampler, %", VerbaliseVkResult(res));
#ifdef DEBUG
else
RenderCore::Get().GetLayers().SetDebugUtilsObjectNameEXT(VK_OBJECT_TYPE_SAMPLER, (std::uint64_t)m_sampler, m_name.c_str());
#endif
}
void Image::CopyFromBuffer(Buffer& buffer)
{
CommandBuffer& cmd = RenderCore::Get().GetSingleTimeCmdBuffer();
cmd.BeginRecord();
VkImageLayout layout_save = m_layout;
TransitionLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &cmd);
cmd.CopyBufferToImage(buffer, *this);
TransitionLayout(layout_save, &cmd);
cmd.EndRecord();
cmd.SubmitIdle();
}
void Image::CopyToBuffer(Buffer& buffer)
{
CommandBuffer& cmd = RenderCore::Get().GetSingleTimeCmdBuffer();
cmd.BeginRecord();
VkImageLayout layout_save = m_layout;
TransitionLayout(VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, &cmd);
cmd.CopyImagetoBuffer(*this, buffer);
TransitionLayout(layout_save, &cmd);
cmd.EndRecord();
cmd.SubmitIdle();
}
void Image::TransitionLayout(VkImageLayout new_layout, NonOwningPtr<CommandBuffer> cmd)
{
if(new_layout == m_layout)
return;
bool single_time = (cmd == nullptr);
if(single_time)
{
cmd = &RenderCore::Get().GetSingleTimeCmdBuffer();
cmd->BeginRecord();
}
cmd->TransitionImageLayout(*this, new_layout);
if(single_time)
{
cmd->EndRecord();
cmd->SubmitIdle();
}
m_layout = new_layout;
}
void Image::DestroySampler() noexcept
{
if(m_sampler != VK_NULL_HANDLE)
vkDestroySampler(RenderCore::Get().GetDevice().Get(), m_sampler, nullptr);
m_sampler = VK_NULL_HANDLE;
}
void Image::DestroyImageView() noexcept
{
if(m_image_view != VK_NULL_HANDLE)
vkDestroyImageView(RenderCore::Get().GetDevice().Get(), m_image_view, nullptr);
m_image_view = VK_NULL_HANDLE;
}
void Image::Destroy() noexcept
{
DestroySampler();
DestroyImageView();
if(m_image != VK_NULL_HANDLE)
RenderCore::Get().GetAllocator().DestroyImage(m_allocation, m_image);
m_image = VK_NULL_HANDLE;
}
std::uint32_t FormatSize(VkFormat format)
{
switch(format)
{
case VK_FORMAT_UNDEFINED: return 0;
case VK_FORMAT_R4G4_UNORM_PACK8: return 1;
case VK_FORMAT_R4G4B4A4_UNORM_PACK16: return 2;
case VK_FORMAT_B4G4R4A4_UNORM_PACK16: return 2;
case VK_FORMAT_R5G6B5_UNORM_PACK16: return 2;
case VK_FORMAT_B5G6R5_UNORM_PACK16: return 2;
case VK_FORMAT_R5G5B5A1_UNORM_PACK16: return 2;
case VK_FORMAT_B5G5R5A1_UNORM_PACK16: return 2;
case VK_FORMAT_A1R5G5B5_UNORM_PACK16: return 2;
case VK_FORMAT_R8_UNORM: return 1;
case VK_FORMAT_R8_SNORM: return 1;
case VK_FORMAT_R8_USCALED: return 1;
case VK_FORMAT_R8_SSCALED: return 1;
case VK_FORMAT_R8_UINT: return 1;
case VK_FORMAT_R8_SINT: return 1;
case VK_FORMAT_R8_SRGB: return 1;
case VK_FORMAT_R8G8_UNORM: return 2;
case VK_FORMAT_R8G8_SNORM: return 2;
case VK_FORMAT_R8G8_USCALED: return 2;
case VK_FORMAT_R8G8_SSCALED: return 2;
case VK_FORMAT_R8G8_UINT: return 2;
case VK_FORMAT_R8G8_SINT: return 2;
case VK_FORMAT_R8G8_SRGB: return 2;
case VK_FORMAT_R8G8B8_UNORM: return 3;
case VK_FORMAT_R8G8B8_SNORM: return 3;
case VK_FORMAT_R8G8B8_USCALED: return 3;
case VK_FORMAT_R8G8B8_SSCALED: return 3;
case VK_FORMAT_R8G8B8_UINT: return 3;
case VK_FORMAT_R8G8B8_SINT: return 3;
case VK_FORMAT_R8G8B8_SRGB: return 3;
case VK_FORMAT_B8G8R8_UNORM: return 3;
case VK_FORMAT_B8G8R8_SNORM: return 3;
case VK_FORMAT_B8G8R8_USCALED: return 3;
case VK_FORMAT_B8G8R8_SSCALED: return 3;
case VK_FORMAT_B8G8R8_UINT: return 3;
case VK_FORMAT_B8G8R8_SINT: return 3;
case VK_FORMAT_B8G8R8_SRGB: return 3;
case VK_FORMAT_R8G8B8A8_UNORM: return 4;
case VK_FORMAT_R8G8B8A8_SNORM: return 4;
case VK_FORMAT_R8G8B8A8_USCALED: return 4;
case VK_FORMAT_R8G8B8A8_SSCALED: return 4;
case VK_FORMAT_R8G8B8A8_UINT: return 4;
case VK_FORMAT_R8G8B8A8_SINT: return 4;
case VK_FORMAT_R8G8B8A8_SRGB: return 4;
case VK_FORMAT_B8G8R8A8_UNORM: return 4;
case VK_FORMAT_B8G8R8A8_SNORM: return 4;
case VK_FORMAT_B8G8R8A8_USCALED: return 4;
case VK_FORMAT_B8G8R8A8_SSCALED: return 4;
case VK_FORMAT_B8G8R8A8_UINT: return 4;
case VK_FORMAT_B8G8R8A8_SINT: return 4;
case VK_FORMAT_B8G8R8A8_SRGB: return 4;
case VK_FORMAT_A8B8G8R8_UNORM_PACK32: return 4;
case VK_FORMAT_A8B8G8R8_SNORM_PACK32: return 4;
case VK_FORMAT_A8B8G8R8_USCALED_PACK32: return 4;
case VK_FORMAT_A8B8G8R8_SSCALED_PACK32: return 4;
case VK_FORMAT_A8B8G8R8_UINT_PACK32: return 4;
case VK_FORMAT_A8B8G8R8_SINT_PACK32: return 4;
case VK_FORMAT_A8B8G8R8_SRGB_PACK32: return 4;
case VK_FORMAT_A2R10G10B10_UNORM_PACK32: return 4;
case VK_FORMAT_A2R10G10B10_SNORM_PACK32: return 4;
case VK_FORMAT_A2R10G10B10_USCALED_PACK32: return 4;
case VK_FORMAT_A2R10G10B10_SSCALED_PACK32: return 4;
case VK_FORMAT_A2R10G10B10_UINT_PACK32: return 4;
case VK_FORMAT_A2R10G10B10_SINT_PACK32: return 4;
case VK_FORMAT_A2B10G10R10_UNORM_PACK32: return 4;
case VK_FORMAT_A2B10G10R10_SNORM_PACK32: return 4;
case VK_FORMAT_A2B10G10R10_USCALED_PACK32: return 4;
case VK_FORMAT_A2B10G10R10_SSCALED_PACK32: return 4;
case VK_FORMAT_A2B10G10R10_UINT_PACK32: return 4;
case VK_FORMAT_A2B10G10R10_SINT_PACK32: return 4;
case VK_FORMAT_R16_UNORM: return 2;
case VK_FORMAT_R16_SNORM: return 2;
case VK_FORMAT_R16_USCALED: return 2;
case VK_FORMAT_R16_SSCALED: return 2;
case VK_FORMAT_R16_UINT: return 2;
case VK_FORMAT_R16_SINT: return 2;
case VK_FORMAT_R16_SFLOAT: return 2;
case VK_FORMAT_R16G16_UNORM: return 4;
case VK_FORMAT_R16G16_SNORM: return 4;
case VK_FORMAT_R16G16_USCALED: return 4;
case VK_FORMAT_R16G16_SSCALED: return 4;
case VK_FORMAT_R16G16_UINT: return 4;
case VK_FORMAT_R16G16_SINT: return 4;
case VK_FORMAT_R16G16_SFLOAT: return 4;
case VK_FORMAT_R16G16B16_UNORM: return 6;
case VK_FORMAT_R16G16B16_SNORM: return 6;
case VK_FORMAT_R16G16B16_USCALED: return 6;
case VK_FORMAT_R16G16B16_SSCALED: return 6;
case VK_FORMAT_R16G16B16_UINT: return 6;
case VK_FORMAT_R16G16B16_SINT: return 6;
case VK_FORMAT_R16G16B16_SFLOAT: return 6;
case VK_FORMAT_R16G16B16A16_UNORM: return 8;
case VK_FORMAT_R16G16B16A16_SNORM: return 8;
case VK_FORMAT_R16G16B16A16_USCALED: return 8;
case VK_FORMAT_R16G16B16A16_SSCALED: return 8;
case VK_FORMAT_R16G16B16A16_UINT: return 8;
case VK_FORMAT_R16G16B16A16_SINT: return 8;
case VK_FORMAT_R16G16B16A16_SFLOAT: return 8;
case VK_FORMAT_R32_UINT: return 4;
case VK_FORMAT_R32_SINT: return 4;
case VK_FORMAT_R32_SFLOAT: return 4;
case VK_FORMAT_R32G32_UINT: return 8;
case VK_FORMAT_R32G32_SINT: return 8;
case VK_FORMAT_R32G32_SFLOAT: return 8;
case VK_FORMAT_R32G32B32_UINT: return 12;
case VK_FORMAT_R32G32B32_SINT: return 12;
case VK_FORMAT_R32G32B32_SFLOAT: return 12;
case VK_FORMAT_R32G32B32A32_UINT: return 16;
case VK_FORMAT_R32G32B32A32_SINT: return 16;
case VK_FORMAT_R32G32B32A32_SFLOAT: return 16;
case VK_FORMAT_R64_UINT: return 8;
case VK_FORMAT_R64_SINT: return 8;
case VK_FORMAT_R64_SFLOAT: return 8;
case VK_FORMAT_R64G64_UINT: return 16;
case VK_FORMAT_R64G64_SINT: return 16;
case VK_FORMAT_R64G64_SFLOAT: return 16;
case VK_FORMAT_R64G64B64_UINT: return 24;
case VK_FORMAT_R64G64B64_SINT: return 24;
case VK_FORMAT_R64G64B64_SFLOAT: return 24;
case VK_FORMAT_R64G64B64A64_UINT: return 32;
case VK_FORMAT_R64G64B64A64_SINT: return 32;
case VK_FORMAT_R64G64B64A64_SFLOAT: return 32;
case VK_FORMAT_B10G11R11_UFLOAT_PACK32: return 4;
case VK_FORMAT_E5B9G9R9_UFLOAT_PACK32: return 4;
default: return 0;
}
}
}

View File

@@ -1,190 +0,0 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* Texture.cpp :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/03/31 18:03:35 by maldavid #+# #+# */
/* Updated: 2024/04/23 21:52:23 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
#define STB_IMAGE_IMPLEMENTATION
#include <stb_image.h>
#include <Precompiled.h>
#include <Renderer/Images/Texture.h>
#include <Renderer/Buffers/Buffer.h>
#include <Renderer/Renderer.h>
#ifdef IMAGE_OPTIMIZED
#define TILING VK_IMAGE_TILING_OPTIMAL
#else
#define TILING VK_IMAGE_TILING_LINEAR
#endif
namespace mlx
{
void Texture::Create(std::uint8_t* pixels, std::uint32_t width, std::uint32_t height, VkFormat format, const char* name, bool dedicated_memory)
{
MLX_PROFILE_FUNCTION();
Image::Create(width, height, format, TILING, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, name, dedicated_memory);
Image::CreateImageView(VK_IMAGE_VIEW_TYPE_2D, VK_IMAGE_ASPECT_COLOR_BIT);
Image::CreateSampler();
TransitionLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
std::vector<Vertex> vertex_data = {
{{0, 0}, {1.f, 1.f, 1.f, 1.f}, {0.0f, 0.0f}},
{{width, 0}, {1.f, 1.f, 1.f, 1.f}, {1.0f, 0.0f}},
{{width, height}, {1.f, 1.f, 1.f, 1.f}, {1.0f, 1.0f}},
{{0, height}, {1.f, 1.f, 1.f, 1.f}, {0.0f, 1.0f}}
};
std::vector<std::uint16_t> index_data = { 0, 1, 2, 2, 3, 0 };
#ifdef DEBUG
m_vbo.Create(sizeof(Vertex) * vertex_data.size(), vertex_data.data(), name);
m_ibo.Create(sizeof(std::uint16_t) * index_data.size(), index_data.data(), name);
m_name = name;
#else
m_vbo.Create(sizeof(Vertex) * vertex_data.size(), vertex_data.data(), nullptr);
m_ibo.Create(sizeof(std::uint16_t) * index_data.size(), index_data.data(), nullptr);
#endif
Buffer staging_buffer;
std::size_t size = width * height * formatSize(format);
if(pixels != nullptr)
{
#ifdef DEBUG
staging_buffer.Create(BufferType::HighDynamic, size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, name, pixels);
#else
staging_buffer.Create(BufferType::HighDynamic, size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, nullptr, pixels);
#endif
}
else
{
std::vector<std::uint32_t> default_pixels(width * height, 0x00000000);
#ifdef DEBUG
staging_buffer.Create(BufferType::HighDynamic, size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, name, default_pixels.data());
#else
staging_buffer.Create(BufferType::HighDynamic, size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, nullptr, default_pixels.data());
#endif
}
Image::CopyFromBuffer(staging_buffer);
staging_buffer.Destroy();
}
void Texture::SetPixel(int x, int y, std::uint32_t color) noexcept
{
MLX_PROFILE_FUNCTION();
if(x < 0 || y < 0 || static_cast<std::uint32_t>(x) > GetWidth() || static_cast<std::uint32_t>(y) > GetHeight())
return;
if(m_map == nullptr)
PpenCPUmap();
m_cpu_map[(y * GetWidth()) + x] = color;
m_has_been_modified = true;
}
int Texture::GetPixel(int x, int y) noexcept
{
MLX_PROFILE_FUNCTION();
if(x < 0 || y < 0 || static_cast<std::uint32_t>(x) > GetWidth() || static_cast<std::uint32_t>(y) > GetHeight())
return 0;
if(m_map == nullptr)
OpenCPUmap();
std::uint32_t color = m_cpu_map[(y * GetWidth()) + x];
std::uint8_t* bytes = reinterpret_cast<std::uint8_t*>(&color);
std::uint8_t tmp = bytes[0];
bytes[0] = bytes[2];
bytes[2] = tmp;
return *reinterpret_cast<int*>(bytes);
}
void Texture::OpenCPUmap()
{
MLX_PROFILE_FUNCTION();
if(m_map != nullptr)
return;
DebugLog("Texture : enabling CPU mapping");
std::size_t size = GetWidth() * GetHeight() * FormatSize(GetFormat());
m_buf_map.emplace();
#ifdef DEBUG
m_buf_map->Create(BufferType::HighDynamic, size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, m_name.c_str());
#else
m_buf_map->Create(BufferType::HighDynamic, size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, nullptr);
#endif
Image::CopyToBuffer(*m_buf_map);
m_buf_map->MapMem(&_map);
m_cpu_map = std::vector<std::uint32_t>(GetWidth() * GetHeight(), 0);
std::memcpy(m_cpu_map.data(), m_map, size);
DebugLog("Texture : mapped CPU memory using staging buffer");
}
void Texture::Render(Renderer& renderer, int x, int y)
{
MLX_PROFILE_FUNCTION();
if(m_has_been_modified)
{
std::memcpy(m_map, m_cpu_map.data(), m_cpu_map.size() * FormatSize(GetFormat()));
Image::copyFromBuffer(*m_buf_map);
m_has_been_modified = false;
}
if(!m_set.IsInit())
m_set = renderer.GetFragDescriptorSet().Duplicate();
if(GetLayout() != VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
TransitionLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
if(!m_has_set_been_updated)
UpdateSet(0);
auto cmd = renderer.GetActiveCmdBuffer();
m_vbo.bind(renderer);
m_ibo.bind(renderer);
glm::vec2 translate(x, y);
vkCmdPushConstants(cmd.Get(), renderer.GetPipeline().GetPipelineLayout(), VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(translate), &translate);
m_set.Bind();
vkCmdDrawIndexed(cmd.Get(), static_cast<std::uint32_t>(m_ibo.GetSize() / sizeof(std::uint16_t)), 1, 0, 0, 0);
}
void Texture::Destroy() noexcept
{
MLX_PROFILE_FUNCTION();
Image::Destroy();
m_set.Destroy();
if(m_buf_map.has_value())
m_buf_map->Destroy();
m_vbo.destroy();
m_ibo.destroy();
}
Texture stbTextureLoad(std::filesystem::path file, int* w, int* h)
{
MLX_PROFILE_FUNCTION();
Texture* texture = new Texture;
int channels;
std::uint8_t* data = nullptr;
std::string filename = file.string();
if(!std::filesystem::exists(std::move(file)))
{
Error("Image : file not found '%s'", filename.c_str());
return nullptr;
}
if(stbi_is_hdr(filename.c_str()))
{
Error("Texture : unsupported image format '%s'", filename.c_str());
return nullptr;
}
int dummy_w;
int dummy_h;
data = stbi_load(filename.c_str(), (w == nullptr ? &dummy_w : w), (h == nullptr ? &dummy_h : h), &channels, 4);
#ifdef DEBUG
texture->Create(data, (w == nullptr ? dummy_w : *w), (h == nullptr ? dummy_h : *h), VK_FORMAT_R8G8B8A8_UNORM, filename.c_str());
#else
texture->Create(data, (w == nullptr ? dummy_w : *w), (h == nullptr ? dummy_h : *h), VK_FORMAT_R8G8B8A8_UNORM, nullptr);
#endif
stbi_image_free(data);
return texture;
}
}

View File

@@ -1,58 +0,0 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* TextureAtlas.cpp :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/04/07 16:40:09 by maldavid #+# #+# */
/* Updated: 2024/04/23 21:54:05 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
#include <PreCompiled.h>
#include <Renderer/Images/TextureAtlas.h>
#ifdef IMAGE_OPTIMIZED
#define TILING VK_IMAGE_TILING_OPTIMAL
#else
#define TILING VK_IMAGE_TILING_LINEAR
#endif
namespace mlx
{
void TextureAtlas::Create(std::uint8_t* pixels, std::uint32_t width, std::uint32_t height, VkFormat format, const char* name, bool dedicated_memory)
{
Image::Create(width, height, format, TILING, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, name, dedicated_memory);
Image::CreateImageView(VK_IMAGE_VIEW_TYPE_2D, VK_IMAGE_ASPECT_COLOR_BIT);
Image::CreateSampler();
TransitionLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
if(pixels == nullptr)
{
Warning("Renderer : creating an empty texture atlas. They cannot be updated after creation, this might be a mistake or a bug, please report");
return;
}
Buffer staging_buffer;
std::size_t size = width * height * FormatSize(format);
staging_buffer.Create(BufferType::HighDynamic, size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, name, pixels);
Image::CopyFromBuffer(staging_buffer);
staging_buffer.Destroy();
}
void TextureAtlas::Render(Renderer& renderer, int x, int y, std::uint32_t ibo_size) const
{
auto cmd = renderer.GetActiveCmdBuffer().Get();
glm::vec2 translate(x, y);
vkCmdPushConstants(cmd, renderer.GetPipeline().GetPipelineLayout(), VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(translate), &translate);
vkCmdDrawIndexed(cmd, ibo_size / sizeof(std::uint16_t), 1, 0, 0, 0);
}
void TextureAtlas::Destroy() noexcept
{
Image::Destroy();
m_set.Destroy();
}
}

159
runtime/Sources/Renderer/Memory.cpp git.filemode.normal_file
View File

@@ -0,0 +1,159 @@
#include <mlx_profile.h>
#define VMA_STATIC_VULKAN_FUNCTIONS 0
#define VMA_DYNAMIC_VULKAN_FUNCTIONS 0
#define VMA_VULKAN_VERSION 1000000
#define VMA_ASSERT(expr) ((void)0)
#define VMA_IMPLEMENTATION
#ifdef MLX_COMPILER_CLANG
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Weverything"
#include <PreCompiled.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 <PreCompiled.h>
#pragma GCC diagnostic pop
#else
#include <PreCompiled.h>
#endif
#include <Renderer/RenderCore.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;
VmaAllocatorCreateInfo allocator_create_info{};
allocator_create_info.vulkanApiVersion = VK_API_VERSION_1_0;
allocator_create_info.physicalDevice = RenderCore::Get().GetPhysicalDevice();
allocator_create_info.device = RenderCore::Get().GetDevice();
allocator_create_info.instance = RenderCore::Get().GetInstance();
allocator_create_info.pVulkanFunctions = &vma_vulkan_func;
kvfCheckVk(vmaCreateAllocator(&allocator_create_info, &m_allocator));
DebugLog("Graphics allocator : created new allocator");
}
VmaAllocation GPUAllocator::CreateBuffer(const VkBufferCreateInfo* binfo, const VmaAllocationCreateInfo* vinfo, VkBuffer& buffer, const char* name) noexcept
{
MLX_PROFILE_FUNCTION();
VmaAllocation allocation;
kvfCheckVk(vmaCreateBuffer(m_allocator, binfo, vinfo, &buffer, &allocation, nullptr));
if(name != nullptr)
{
vmaSetAllocationName(m_allocator, allocation, name);
}
DebugLog("Graphics Allocator : created new buffer '%'", name);
m_active_buffers_allocations++;
return allocation;
}
void GPUAllocator::DestroyBuffer(VmaAllocation allocation, VkBuffer buffer) noexcept
{
MLX_PROFILE_FUNCTION();
RenderCore::Get().WaitDeviceIdle();
vmaDestroyBuffer(m_allocator, buffer, allocation);
DebugLog("Graphics Allocator : destroyed buffer");
m_active_buffers_allocations--;
}
VmaAllocation GPUAllocator::CreateImage(const VkImageCreateInfo* iminfo, const VmaAllocationCreateInfo* vinfo, VkImage& image, const char* name) noexcept
{
MLX_PROFILE_FUNCTION();
VmaAllocation allocation;
kvfCheckVk(vmaCreateImage(m_allocator, iminfo, vinfo, &image, &allocation, nullptr));
if(name != nullptr)
{
vmaSetAllocationName(m_allocator, allocation, name);
}
DebugLog("Graphics Allocator : created new image '%'", name);
m_active_images_allocations++;
return allocation;
}
void GPUAllocator::DestroyImage(VmaAllocation allocation, VkImage image) noexcept
{
MLX_PROFILE_FUNCTION();
RenderCore::Get().WaitDeviceIdle();
vmaDestroyImage(m_allocator, image, allocation);
DebugLog("Graphics Allocator : destroyed image");
m_active_images_allocations--;
}
void GPUAllocator::MapMemory(VmaAllocation allocation, void** data) noexcept
{
MLX_PROFILE_FUNCTION();
kvfCheckVk(vmaMapMemory(m_allocator, allocation, data));
}
void GPUAllocator::UnmapMemory(VmaAllocation allocation) noexcept
{
MLX_PROFILE_FUNCTION();
vmaUnmapMemory(m_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())
{
Error("Graphics allocator : unable to dump memory to a json file");
return;
}
char* str = nullptr;
vmaBuildStatsString(m_allocator, &str, true);
file << str;
vmaFreeStatsString(m_allocator, str);
file.close();
id++;
}
void GPUAllocator::Flush(VmaAllocation allocation, VkDeviceSize size, VkDeviceSize offset) noexcept
{
MLX_PROFILE_FUNCTION();
vmaFlushAllocation(m_allocator, allocation, offset, size);
}
void GPUAllocator::Destroy() noexcept
{
if(m_active_images_allocations != 0)
Error("Graphics allocator : some user-dependant allocations were not freed before destroying the display (% active allocations). You may have not destroyed all the MLX resources you've created", m_active_images_allocations);
else if(m_active_buffers_allocations != 0)
Error("Graphics allocator : some MLX-dependant allocations were not freed before destroying the display (% active allocations). This is an error in the MLX, please report this should not happen", m_active_buffers_allocations);
if(m_active_images_allocations < 0 || m_active_buffers_allocations < 0)
Warning("Graphics allocator : the impossible happened, the MLX has freed more allocations than it has made (wtf)");
vmaDestroyAllocator(m_allocator);
m_active_buffers_allocations = 0;
m_active_images_allocations = 0;
DebugLog("Vulkan : destroyed a graphics allocator");
}
}

View File

@@ -0,0 +1,164 @@
#include <PreCompiled.h>
#include <Renderer/Pipelines/Graphics.h>
#include <Renderer/RenderCore.h>
#include <Renderer/Renderer.h>
#include <Renderer/Vertex.h>
#include <Core/EventBus.h>
namespace Scop
{
void GraphicPipeline::Init(const GraphicPipelineDescriptor& descriptor)
{
if(!descriptor.vertex_shader || !descriptor.fragment_shader)
FatalError("Vulkan : invalid shaders");
m_attachments = descriptor.color_attachments;
p_vertex_shader = descriptor.vertex_shader;
p_fragment_shader = descriptor.fragment_shader;
p_renderer = descriptor.renderer;
std::vector<VkPushConstantRange> push_constants;
std::vector<VkDescriptorSetLayout> set_layouts;
push_constants.insert(push_constants.end(), p_vertex_shader->GetPipelineLayout().push_constants.begin(), p_vertex_shader->GetPipelineLayout().push_constants.end());
push_constants.insert(push_constants.end(), p_fragment_shader->GetPipelineLayout().push_constants.begin(), p_fragment_shader->GetPipelineLayout().push_constants.end());
set_layouts.insert(set_layouts.end(), p_vertex_shader->GetPipelineLayout().set_layouts.begin(), p_vertex_shader->GetPipelineLayout().set_layouts.end());
set_layouts.insert(set_layouts.end(), p_fragment_shader->GetPipelineLayout().set_layouts.begin(), p_fragment_shader->GetPipelineLayout().set_layouts.end());
m_pipeline_layout = kvfCreatePipelineLayout(RenderCore::Get().GetDevice(), set_layouts.data(), set_layouts.size(), push_constants.data(), push_constants.size());
TransitionAttachments();
CreateFramebuffers(m_attachments, descriptor.clear_color_attachments);
VkPhysicalDeviceFeatures features{};
vkGetPhysicalDeviceFeatures(RenderCore::Get().GetPhysicalDevice(), &features);
KvfGraphicsPipelineBuilder* builder = kvfCreateGPipelineBuilder();
kvfGPipelineBuilderAddShaderStage(builder, p_vertex_shader->GetShaderStage(), p_vertex_shader->GetShaderModule(), "main");
kvfGPipelineBuilderAddShaderStage(builder, p_fragment_shader->GetShaderStage(), p_fragment_shader->GetShaderModule(), "main");
kvfGPipelineBuilderSetInputTopology(builder, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST);
kvfGPipelineBuilderSetCullMode(builder, VK_CULL_MODE_NONE, VK_FRONT_FACE_CLOCKWISE);
kvfGPipelineBuilderEnableAlphaBlending(builder);
kvfGPipelineBuilderDisableDepthTest(builder);
kvfGPipelineBuilderSetPolygonMode(builder, VK_POLYGON_MODE_FILL, 1.0f);
if(features.sampleRateShading)
kvfGPipelineBuilderSetMultisamplingShading(builder, VK_SAMPLE_COUNT_1_BIT, 0.25f);
else
kvfGPipelineBuilderSetMultisampling(builder, VK_SAMPLE_COUNT_1_BIT);
if(!descriptor.no_vertex_inputs)
{
VkVertexInputBindingDescription binding_description = Vertex::GetBindingDescription();
auto attributes_description = Vertex::GetAttributeDescriptions();
kvfGPipelineBuilderSetVertexInputs(builder, binding_description, attributes_description.data(), attributes_description.size());
}
m_pipeline = kvfCreateGraphicsPipeline(RenderCore::Get().GetDevice(), m_pipeline_layout, builder, m_renderpass);
DebugLog("Vulkan : graphics pipeline created");
kvfDestroyGPipelineBuilder(builder);
}
bool GraphicPipeline::BindPipeline(VkCommandBuffer command_buffer, std::size_t framebuffer_index, std::array<float, 4> clear) noexcept
{
TransitionAttachments(command_buffer);
VkFramebuffer fb = m_framebuffers[framebuffer_index];
VkExtent2D fb_extent = kvfGetFramebufferSize(fb);
VkViewport viewport{};
viewport.x = 0.0f;
viewport.y = 0.0f;
viewport.width = fb_extent.width;
viewport.height = fb_extent.height;
viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f;
vkCmdSetViewport(command_buffer, 0, 1, &viewport);
VkRect2D scissor{};
scissor.offset = { 0, 0 };
scissor.extent = fb_extent;
vkCmdSetScissor(command_buffer, 0, 1, &scissor);
for(int i = 0; i < m_clears.size(); i++)
{
m_clears[i].color.float32[0] = clear[0];
m_clears[i].color.float32[1] = clear[1];
m_clears[i].color.float32[2] = clear[2];
m_clears[i].color.float32[3] = clear[3];
}
kvfBeginRenderPass(m_renderpass, command_buffer, fb, fb_extent, m_clears.data(), m_clears.size());
vkCmdBindPipeline(command_buffer, GetPipelineBindPoint(), GetPipeline());
return true;
}
void GraphicPipeline::EndPipeline(VkCommandBuffer command_buffer) noexcept
{
vkCmdEndRenderPass(command_buffer);
}
void GraphicPipeline::Destroy() noexcept
{
p_vertex_shader.reset();
p_fragment_shader.reset();
for(auto& fb : m_framebuffers)
{
kvfDestroyFramebuffer(RenderCore::Get().GetDevice(), fb);
DebugLog("Vulkan : framebuffer destroyed");
}
m_framebuffers.clear();
kvfDestroyPipelineLayout(RenderCore::Get().GetDevice(), m_pipeline_layout);
m_pipeline_layout = VK_NULL_HANDLE;
DebugLog("Vulkan : graphics pipeline layout destroyed");
kvfDestroyRenderPass(RenderCore::Get().GetDevice(), m_renderpass);
m_renderpass = VK_NULL_HANDLE;
DebugLog("Vulkan : renderpass destroyed");
kvfDestroyPipeline(RenderCore::Get().GetDevice(), m_pipeline);
m_pipeline = VK_NULL_HANDLE;
DebugLog("Vulkan : graphics pipeline destroyed");
}
void GraphicPipeline::CreateFramebuffers(const std::vector<NonOwningPtr<Texture>>& render_targets, bool clear_attachments)
{
std::vector<VkAttachmentDescription> attachments;
std::vector<VkImageView> attachment_views;
if(p_renderer)
{
attachments.push_back(kvfBuildSwapchainAttachmentDescription(p_renderer->GetSwapchain(), clear_attachments));
attachment_views.push_back(p_renderer->GetSwapchainImages()[0].GetImageView());
}
for(NonOwningPtr<Texture> image : render_targets)
{
attachments.push_back(kvfBuildAttachmentDescription(KVF_IMAGE_COLOR, image->GetFormat(), image->GetLayout(), image->GetLayout(), clear_attachments, VK_SAMPLE_COUNT_1_BIT));
attachment_views.push_back(image->GetImageView());
}
m_renderpass = kvfCreateRenderPass(RenderCore::Get().GetDevice(), attachments.data(), attachments.size(), GetPipelineBindPoint());
m_clears.clear();
m_clears.resize(attachments.size());
DebugLog("Vulkan : renderpass created");
if(p_renderer)
{
for(const Image& image : p_renderer->GetSwapchainImages())
{
attachment_views[0] = image.GetImageView();
m_framebuffers.push_back(kvfCreateFramebuffer(RenderCore::Get().GetDevice(), m_renderpass, attachment_views.data(), attachment_views.size(), { .width = image.GetWidth(), .height = image.GetHeight() }));
DebugLog("Vulkan : framebuffer created");
}
}
for(NonOwningPtr<Texture> image : render_targets)
{
m_framebuffers.push_back(kvfCreateFramebuffer(RenderCore::Get().GetDevice(), m_renderpass, attachment_views.data(), attachment_views.size(), { .width = image->GetWidth(), .height = image->GetHeight() }));
DebugLog("Vulkan : framebuffer created");
}
}
void GraphicPipeline::TransitionAttachments(VkCommandBuffer cmd)
{
for(NonOwningPtr<Texture> image : m_attachments)
{
if(!image->IsInit())
continue;
image->TransitionLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, cmd);
}
}
}

View File

@@ -1,331 +0,0 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* Pipeline.cpp :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2022/12/18 21:27:38 by maldavid #+# #+# */
/* Updated: 2024/04/23 22:24:13 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
#include <PreCompiled.h>
#include <Renderer/Pipelines/Pipeline.h>
#include <Renderer/Renderer.h>
#include <Renderer/Core/RenderCore.h>
#include <Renderer/Descriptors/DescriptorSetLayout.h>
namespace mlx
{
/**
#version 450 core
layout(location = 0) in vec2 aPos;
layout(location = 1) in vec4 aColor;
layout(location = 2) in vec2 aUV;
layout(set = 0, binding = 0) uniform uProjection
{
mat4 mat;
} uProj;
layout(push_constant) uniform uModelPushConstant
{
vec2 vec;
} uTranslate;
out gl_PerVertex
{
vec4 gl_Position;
};
layout(location = 0) out struct
{
vec4 Color;
vec2 UV;
} Out;
void main()
{
Out.Color = aColor;
Out.UV = aUV;
vec2 pos = aPos + uTranslate.vec;
gl_Position = uProj.mat * vec4(pos.x, pos.y, 0.0, 1.0);
}
*/
const std::vector<std::uint32_t> vertex_shader = { // precompiled vertex shader
0x07230203,0x00010000,0x0008000b,0x0000003b,0x00000000,0x00020011,0x00000001,0x0006000b,
0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001,
0x000a000f,0x00000000,0x00000004,0x6e69616d,0x00000000,0x0000000b,0x0000000f,0x00000015,
0x0000001b,0x00000026,0x00030003,0x00000002,0x000001c2,0x00040005,0x00000004,0x6e69616d,
0x00000000,0x00030005,0x00000009,0x00000000,0x00050006,0x00000009,0x00000000,0x6f6c6f43,
0x00000072,0x00040006,0x00000009,0x00000001,0x00005655,0x00030005,0x0000000b,0x0074754f,
0x00040005,0x0000000f,0x6c6f4361,0x0000726f,0x00030005,0x00000015,0x00565561,0x00030005,
0x0000001a,0x00736f70,0x00040005,0x0000001b,0x736f5061,0x00000000,0x00070005,0x0000001d,
0x646f4d75,0x75506c65,0x6f436873,0x6174736e,0x0000746e,0x00040006,0x0000001d,0x00000000,
0x00636576,0x00050005,0x0000001f,0x61725475,0x616c736e,0x00006574,0x00060005,0x00000024,
0x505f6c67,0x65567265,0x78657472,0x00000000,0x00060006,0x00000024,0x00000000,0x505f6c67,
0x7469736f,0x006e6f69,0x00030005,0x00000026,0x00000000,0x00050005,0x00000028,0x6f725075,
0x7463656a,0x006e6f69,0x00040006,0x00000028,0x00000000,0x0074616d,0x00040005,0x0000002a,
0x6f725075,0x0000006a,0x00040047,0x0000000b,0x0000001e,0x00000000,0x00040047,0x0000000f,
0x0000001e,0x00000001,0x00040047,0x00000015,0x0000001e,0x00000002,0x00040047,0x0000001b,
0x0000001e,0x00000000,0x00050048,0x0000001d,0x00000000,0x00000023,0x00000000,0x00030047,
0x0000001d,0x00000002,0x00050048,0x00000024,0x00000000,0x0000000b,0x00000000,0x00030047,
0x00000024,0x00000002,0x00040048,0x00000028,0x00000000,0x00000005,0x00050048,0x00000028,
0x00000000,0x00000023,0x00000000,0x00050048,0x00000028,0x00000000,0x00000007,0x00000010,
0x00030047,0x00000028,0x00000002,0x00040047,0x0000002a,0x00000022,0x00000000,0x00040047,
0x0000002a,0x00000021,0x00000000,0x00020013,0x00000002,0x00030021,0x00000003,0x00000002,
0x00030016,0x00000006,0x00000020,0x00040017,0x00000007,0x00000006,0x00000004,0x00040017,
0x00000008,0x00000006,0x00000002,0x0004001e,0x00000009,0x00000007,0x00000008,0x00040020,
0x0000000a,0x00000003,0x00000009,0x0004003b,0x0000000a,0x0000000b,0x00000003,0x00040015,
0x0000000c,0x00000020,0x00000001,0x0004002b,0x0000000c,0x0000000d,0x00000000,0x00040020,
0x0000000e,0x00000001,0x00000007,0x0004003b,0x0000000e,0x0000000f,0x00000001,0x00040020,
0x00000011,0x00000003,0x00000007,0x0004002b,0x0000000c,0x00000013,0x00000001,0x00040020,
0x00000014,0x00000001,0x00000008,0x0004003b,0x00000014,0x00000015,0x00000001,0x00040020,
0x00000017,0x00000003,0x00000008,0x00040020,0x00000019,0x00000007,0x00000008,0x0004003b,
0x00000014,0x0000001b,0x00000001,0x0003001e,0x0000001d,0x00000008,0x00040020,0x0000001e,
0x00000009,0x0000001d,0x0004003b,0x0000001e,0x0000001f,0x00000009,0x00040020,0x00000020,
0x00000009,0x00000008,0x0003001e,0x00000024,0x00000007,0x00040020,0x00000025,0x00000003,
0x00000024,0x0004003b,0x00000025,0x00000026,0x00000003,0x00040018,0x00000027,0x00000007,
0x00000004,0x0003001e,0x00000028,0x00000027,0x00040020,0x00000029,0x00000002,0x00000028,
0x0004003b,0x00000029,0x0000002a,0x00000002,0x00040020,0x0000002b,0x00000002,0x00000027,
0x00040015,0x0000002e,0x00000020,0x00000000,0x0004002b,0x0000002e,0x0000002f,0x00000000,
0x00040020,0x00000030,0x00000007,0x00000006,0x0004002b,0x0000002e,0x00000033,0x00000001,
0x0004002b,0x00000006,0x00000036,0x00000000,0x0004002b,0x00000006,0x00000037,0x3f800000,
0x00050036,0x00000002,0x00000004,0x00000000,0x00000003,0x000200f8,0x00000005,0x0004003b,
0x00000019,0x0000001a,0x00000007,0x0004003d,0x00000007,0x00000010,0x0000000f,0x00050041,
0x00000011,0x00000012,0x0000000b,0x0000000d,0x0003003e,0x00000012,0x00000010,0x0004003d,
0x00000008,0x00000016,0x00000015,0x00050041,0x00000017,0x00000018,0x0000000b,0x00000013,
0x0003003e,0x00000018,0x00000016,0x0004003d,0x00000008,0x0000001c,0x0000001b,0x00050041,
0x00000020,0x00000021,0x0000001f,0x0000000d,0x0004003d,0x00000008,0x00000022,0x00000021,
0x00050081,0x00000008,0x00000023,0x0000001c,0x00000022,0x0003003e,0x0000001a,0x00000023,
0x00050041,0x0000002b,0x0000002c,0x0000002a,0x0000000d,0x0004003d,0x00000027,0x0000002d,
0x0000002c,0x00050041,0x00000030,0x00000031,0x0000001a,0x0000002f,0x0004003d,0x00000006,
0x00000032,0x00000031,0x00050041,0x00000030,0x00000034,0x0000001a,0x00000033,0x0004003d,
0x00000006,0x00000035,0x00000034,0x00070050,0x00000007,0x00000038,0x00000032,0x00000035,
0x00000036,0x00000037,0x00050091,0x00000007,0x00000039,0x0000002d,0x00000038,0x00050041,
0x00000011,0x0000003a,0x00000026,0x0000000d,0x0003003e,0x0000003a,0x00000039,0x000100fd,
0x00010038
};
/**
#version 450 core
layout(location = 0) out vec4 fColor;
layout(set = 1, binding = 0) uniform sampler2D sTexture;
layout(location = 0) in struct
{
vec4 Color;
vec2 UV;
} In;
void main()
{
vec4 process_color = In.Color * texture(sTexture, In.UV.st);
if(process_color.w == 0)
discard;
fColor = process_color;
}
*/
const std::vector<std::uint32_t> fragment_shader = { // pre compiled fragment shader
0x07230203,0x00010000,0x0008000b,0x0000002c,0x00000000,0x00020011,0x00000001,0x0006000b,
0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001,
0x0007000f,0x00000004,0x00000004,0x6e69616d,0x00000000,0x0000000d,0x0000002a,0x00030010,
0x00000004,0x00000007,0x00030003,0x00000002,0x000001c2,0x00040005,0x00000004,0x6e69616d,
0x00000000,0x00060005,0x00000009,0x636f7270,0x5f737365,0x6f6c6f63,0x00000072,0x00030005,
0x0000000b,0x00000000,0x00050006,0x0000000b,0x00000000,0x6f6c6f43,0x00000072,0x00040006,
0x0000000b,0x00000001,0x00005655,0x00030005,0x0000000d,0x00006e49,0x00050005,0x00000016,
0x78655473,0x65727574,0x00000000,0x00040005,0x0000002a,0x6c6f4366,0x0000726f,0x00040047,
0x0000000d,0x0000001e,0x00000000,0x00040047,0x00000016,0x00000022,0x00000001,0x00040047,
0x00000016,0x00000021,0x00000000,0x00040047,0x0000002a,0x0000001e,0x00000000,0x00020013,
0x00000002,0x00030021,0x00000003,0x00000002,0x00030016,0x00000006,0x00000020,0x00040017,
0x00000007,0x00000006,0x00000004,0x00040020,0x00000008,0x00000007,0x00000007,0x00040017,
0x0000000a,0x00000006,0x00000002,0x0004001e,0x0000000b,0x00000007,0x0000000a,0x00040020,
0x0000000c,0x00000001,0x0000000b,0x0004003b,0x0000000c,0x0000000d,0x00000001,0x00040015,
0x0000000e,0x00000020,0x00000001,0x0004002b,0x0000000e,0x0000000f,0x00000000,0x00040020,
0x00000010,0x00000001,0x00000007,0x00090019,0x00000013,0x00000006,0x00000001,0x00000000,
0x00000000,0x00000000,0x00000001,0x00000000,0x0003001b,0x00000014,0x00000013,0x00040020,
0x00000015,0x00000000,0x00000014,0x0004003b,0x00000015,0x00000016,0x00000000,0x0004002b,
0x0000000e,0x00000018,0x00000001,0x00040020,0x00000019,0x00000001,0x0000000a,0x00040015,
0x0000001e,0x00000020,0x00000000,0x0004002b,0x0000001e,0x0000001f,0x00000003,0x00040020,
0x00000020,0x00000007,0x00000006,0x0004002b,0x00000006,0x00000023,0x00000000,0x00020014,
0x00000024,0x00040020,0x00000029,0x00000003,0x00000007,0x0004003b,0x00000029,0x0000002a,
0x00000003,0x00050036,0x00000002,0x00000004,0x00000000,0x00000003,0x000200f8,0x00000005,
0x0004003b,0x00000008,0x00000009,0x00000007,0x00050041,0x00000010,0x00000011,0x0000000d,
0x0000000f,0x0004003d,0x00000007,0x00000012,0x00000011,0x0004003d,0x00000014,0x00000017,
0x00000016,0x00050041,0x00000019,0x0000001a,0x0000000d,0x00000018,0x0004003d,0x0000000a,
0x0000001b,0x0000001a,0x00050057,0x00000007,0x0000001c,0x00000017,0x0000001b,0x00050085,
0x00000007,0x0000001d,0x00000012,0x0000001c,0x0003003e,0x00000009,0x0000001d,0x00050041,
0x00000020,0x00000021,0x00000009,0x0000001f,0x0004003d,0x00000006,0x00000022,0x00000021,
0x000500b4,0x00000024,0x00000025,0x00000022,0x00000023,0x000300f7,0x00000027,0x00000000,
0x000400fa,0x00000025,0x00000026,0x00000027,0x000200f8,0x00000026,0x000100fc,0x000200f8,
0x00000027,0x0004003d,0x00000007,0x0000002b,0x00000009,0x0003003e,0x0000002a,0x0000002b,
0x000100fd,0x00010038
};
void GraphicPipeline::Init(Renderer& renderer)
{
VkShaderModuleCreateInfo create_info{};
create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
create_info.codeSize = vertex_shader.size() * sizeof(std::uint32_t);
create_info.pCode = vertex_shader.data();
VkShaderModule vshader;
if(vkCreateShaderModule(RenderCore::Get().GetDevice().Get(), &create_info, nullptr, &vshader) != VK_SUCCESS)
FatalError("Vulkan : failed to create a vertex shader module");
VkPushConstantRange push_constant;
push_constant.offset = 0;
push_constant.size = sizeof(glm::vec2);
push_constant.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
create_info.codeSize = fragment_shader.size() * sizeof(std::uint32_t);
create_info.pCode = fragment_shader.data();
VkShaderModule fshader;
if(vkCreateShaderModule(RenderCore::Get().GetDevice().Get(), &create_info, nullptr, &fshader) != VK_SUCCESS)
FatalError("Vulkan : failed to create a fragment shader module");
VkPipelineShaderStageCreateInfo vert_shader_stage_info{};
vert_shader_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
vert_shader_stage_info.stage = VK_SHADER_STAGE_VERTEX_BIT;
vert_shader_stage_info.module = vshader;
vert_shader_stage_info.pName = "main";
VkPipelineShaderStageCreateInfo frag_shader_stage_info{};
frag_shader_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
frag_shader_stage_info.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
frag_shader_stage_info.module = fshader;
frag_shader_stage_info.pName = "main";
std::array<VkPipelineShaderStageCreateInfo, 2> stages = { vert_shader_stage_info, frag_shader_stage_info };
auto binding_description = Vertex::GetBindingDescription();
auto attribute_descriptions = Vertex::GetAttributeDescriptions();
VkPipelineVertexInputStateCreateInfo vertex_input_state_create_info{};
vertex_input_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
vertex_input_state_create_info.vertexBindingDescriptionCount = 1;
vertex_input_state_create_info.pVertexBindingDescriptions = &binding_description;
vertex_input_state_create_info.vertexAttributeDescriptionCount = static_cast<std::uint32_t>(attribute_descriptions.size());
vertex_input_state_create_info.pVertexAttributeDescriptions = attribute_descriptions.data();
VkPipelineInputAssemblyStateCreateInfo input_assembly{};
input_assembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
input_assembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
input_assembly.primitiveRestartEnable = VK_FALSE;
VkDynamicState states[] = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR };
constexpr std::size_t states_count = sizeof(states) / sizeof(VkDynamicState);
VkPipelineDynamicStateCreateInfo dynamic_states{};
dynamic_states.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
dynamic_states.dynamicStateCount = states_count;
dynamic_states.pDynamicStates = states;
VkViewport viewport{};
viewport.x = 0.0f;
viewport.y = 0.0f;
viewport.width = (float)renderer.GetFrameBuffer(0).GetWidth();
viewport.height = (float)renderer.GetFrameBuffer(0).GetHeight();
viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f;
VkRect2D scissor{};
scissor.offset = { 0, 0 };
scissor.extent = { renderer.GetFrameBuffer(0).GetWidth(), renderer.GetFrameBuffer(0).GetHeight()};
VkPipelineViewportStateCreateInfo viewport_state{};
viewport_state.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
viewport_state.viewportCount = 1;
viewport_state.pViewports = &viewport;
viewport_state.scissorCount = 1;
viewport_state.pScissors = &scissor;
VkPipelineRasterizationStateCreateInfo rasterizer{};
rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
rasterizer.depthClampEnable = VK_FALSE;
rasterizer.rasterizerDiscardEnable = VK_FALSE;
rasterizer.polygonMode = VK_POLYGON_MODE_FILL;
rasterizer.lineWidth = 1.0f;
rasterizer.cullMode = VK_CULL_MODE_NONE;
rasterizer.frontFace = VK_FRONT_FACE_CLOCKWISE;
rasterizer.depthBiasEnable = VK_FALSE;
VkPipelineMultisampleStateCreateInfo multisampling{};
multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
multisampling.sampleShadingEnable = VK_FALSE;
multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
VkPipelineColorBlendAttachmentState color_blend_attachment{};
color_blend_attachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
color_blend_attachment.blendEnable = VK_TRUE;
color_blend_attachment.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
color_blend_attachment.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
color_blend_attachment.colorBlendOp = VK_BLEND_OP_ADD;
color_blend_attachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
color_blend_attachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
color_blend_attachment.alphaBlendOp = VK_BLEND_OP_ADD;
VkPipelineColorBlendStateCreateInfo color_blending{};
color_blending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
color_blending.logicOpEnable = VK_FALSE;
color_blending.logicOp = VK_LOGIC_OP_COPY;
color_blending.attachmentCount = 1;
color_blending.pAttachments = &color_blend_attachment;
color_blending.blendConstants[0] = 1.0f;
color_blending.blendConstants[1] = 1.0f;
color_blending.blendConstants[2] = 1.0f;
color_blending.blendConstants[3] = 1.0f;
VkDescriptorSetLayout layouts[] = {
renderer.GetVertDescriptorSet().GetLayout(),
renderer.GetFragDescriptorSet().GetLayout()
};
VkPipelineLayoutCreateInfo pipeline_layout_info{};
pipeline_layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
pipeline_layout_info.setLayoutCount = 2;
pipeline_layout_info.pSetLayouts = layouts;
pipeline_layout_info.pushConstantRangeCount = 1;
pipeline_layout_info.pPushConstantRanges = &push_constant;
if(vkCreatePipelineLayout(RenderCore::Get().GetDevice().Get(), &pipeline_layout_info, nullptr, &m_pipeline_layout) != VK_SUCCESS)
FatalError("Vulkan : failed to create a graphics pipeline layout");
VkGraphicsPipelineCreateInfo pipeline_info{};
pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
pipeline_info.stageCount = stages.size();
pipeline_info.pStages = stages.data();
pipeline_info.pVertexInputState = &vertex_input_state_create_info;
pipeline_info.pInputAssemblyState = &input_assembly;
pipeline_info.pViewportState = &viewport_state;
pipeline_info.pRasterizationState = &rasterizer;
pipeline_info.pMultisampleState = &multisampling;
pipeline_info.pColorBlendState = &color_blending;
pipeline_info.pDynamicState = &dynamic_states;
pipeline_info.layout = m_pipeline_layout;
pipeline_info.renderPass = renderer.GetRenderPass().Get();
pipeline_info.subpass = 0;
pipeline_info.basePipelineHandle = VK_NULL_HANDLE;
VkResult res = vkCreateGraphicsPipelines(RenderCore::Get().GetDevice().Get(), VK_NULL_HANDLE, 1, &pipeline_info, nullptr, &m_graphics_pipeline);
if(res != VK_SUCCESS)
FatalError("Vulkan : failed to create a graphics pipeline, %", VerbaliseVkResult(res));
DebugLog("Vulkan : created new graphic pipeline");
vkDestroyShaderModule(RenderCore::Get().GetDevice().Get(), fshader, nullptr);
vkDestroyShaderModule(RenderCore::Get().GetDevice().Get(), vshader, nullptr);
}
void GraphicPipeline::Destroy() noexcept
{
vkDestroyPipeline(RenderCore::Get().GetDevice().Get(), m_graphics_pipeline, nullptr);
vkDestroyPipelineLayout(RenderCore::Get().GetDevice().Get(), m_pipeline_layout, nullptr);
m_graphics_pipeline = VK_NULL_HANDLE;
DebugLog("Vulkan : destroyed a graphics pipeline");
}
}

83
runtime/Sources/Renderer/Pipelines/Shader.cpp git.filemode.normal_file
View File

@@ -0,0 +1,83 @@
#include <PreCompiled.h>
#include <Renderer/Pipelines/Shader.h>
#include <Renderer/RenderCore.h>
namespace Scop
{
Shader::Shader(const std::vector<std::uint8_t>& bytecode, ShaderType type, ShaderLayout layout) : m_bytecode(bytecode), m_layout(std::move(layout))
{
switch(type)
{
case ShaderType::Vertex : m_stage = VK_SHADER_STAGE_VERTEX_BIT; break;
case ShaderType::Fragment : m_stage = VK_SHADER_STAGE_FRAGMENT_BIT; break;
case ShaderType::Compute : m_stage = VK_SHADER_STAGE_COMPUTE_BIT; break;
default : FatalError("wtf"); break;
}
m_module = kvfCreateShaderModule(RenderCore::Get().GetDevice(), m_bytecode.data(), m_bytecode.size() * 4);
DebugLog("Vulkan : shader module created");
GeneratePipelineLayout(m_layout);
}
void Shader::GeneratePipelineLayout(ShaderLayout layout)
{
for(auto& [n, set] : layout.set_layouts)
{
std::vector<VkDescriptorSetLayoutBinding> bindings(set.binds.size());
for(std::size_t i = 0; i < set.binds.size(); i++)
{
bindings[i].binding = set.binds[i].first;
bindings[i].descriptorCount = 1;
bindings[i].descriptorType = set.binds[i].second;
bindings[i].pImmutableSamplers = nullptr;
bindings[i].stageFlags = m_stage;
}
m_set_layouts.emplace_back(kvfCreateDescriptorSetLayout(RenderCore::Get().GetDevice(), bindings.data(), bindings.size()));
DebugLog("Vulkan : descriptor set layout created");
m_pipeline_layout_part.set_layouts.push_back(m_set_layouts.back());
}
std::size_t i = 0;
std::vector<VkPushConstantRange> push_constants(layout.push_constants.size());
m_pipeline_layout_part.push_constants.resize(layout.push_constants.size());
for(auto& pc : layout.push_constants)
{
VkPushConstantRange push_constant_range = {};
push_constant_range.offset = pc.offset;
push_constant_range.size = pc.size;
push_constant_range.stageFlags = m_stage;
push_constants[i] = push_constant_range;
m_pipeline_layout_part.push_constants[i] = push_constant_range;
i++;
}
}
Shader::~Shader()
{
kvfDestroyShaderModule(RenderCore::Get().GetDevice(), m_module);
DebugLog("Vulkan : shader module destroyed");
for(auto& layout : m_set_layouts)
{
kvfDestroyDescriptorSetLayout(RenderCore::Get().GetDevice(), layout);
DebugLog("Vulkan : descriptor set layout destroyed");
}
}
std::shared_ptr<Shader> LoadShaderFromFile(const std::filesystem::path& filepath, ShaderType type, ShaderLayout layout)
{
std::ifstream stream(filepath, std::ios::binary);
if(!stream.is_open())
FatalError("Renderer : unable to open a spirv shader file, %", filepath);
std::vector<std::uint32_t> data;
stream.seekg(0);
std::uint32_t part = 0;
while(stream.read(reinterpret_cast<char*>(&part), sizeof(part)))
data.push_back(part);
stream.close();
std::shared_ptr<Shader> shader = std::make_shared<Shader>(data, type, layout);
DebugLog("Vulkan : shader loaded %", filepath);
return shader;
}
}

View File

@@ -1,67 +0,0 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* PixelPut.cpp :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/03/31 15:14:50 by maldavid #+# #+# */
/* Updated: 2024/04/24 01:46:06 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
#include <PreCompiled.h>
#include <Renderer/PixelPut.h>
namespace mlx
{
void PixelPutPipeline::Init(std::uint32_t width, std::uint32_t height, Renderer& renderer) noexcept
{
MLX_PROFILE_FUNCTION();
m_texture.Create(nullptr, width, height, VK_FORMAT_R8G8B8A8_UNORM, "__mlx_pixel_put_pipeline_texture", true);
m_texture.SetDescriptor(renderer.GetFragDescriptorSet().Duplicate());
m_buffer.Create(BufferType::HighDynamic, sizeof(std::uint32_t) * (width * height), VK_BUFFER_USAGE_TRANSFER_SRC_BIT, "__mlx_pixel_put_pipeline_texture");
m_buffer.MapMem(&_buffer_map);
m_cpu_map = std::vector<std::uint32_t>(height * width + 1, 0);
m_width = width;
m_height = height;
}
void PixelPutPipeline::SetPixel(int x, int y, std::uint32_t color) noexcept
{
MLX_PROFILE_FUNCTION();
if(x < 0 || y < 0 || x > static_cast<int>(m_width) || y > static_cast<int>(m_height))
return;
m_cpu_map[(y * m_width) + x] = color;
m_has_been_modified = true;
}
void PixelPutPipeline::Clear()
{
MLX_PROFILE_FUNCTION();
m_cpu_map.assign(m_width * m_height, 0);
m_has_been_modified = true;
}
void PixelPutPipeline::Render(Renderer& renderer) noexcept
{
MLX_PROFILE_FUNCTION();
if(m_has_been_modified)
{
std::memcpy(m_buffer_map, m_cpu_map.data(), sizeof(std::uint32_t) * m_cpu_map.size());
m_texture.CopyFromBuffer(m_buffer);
m_has_been_modified = false;
}
m_texture.UpdateSet(0);
m_texture.Render(renderer, 0, 0);
}
void PixelPutPipeline::Destroy() noexcept
{
MLX_PROFILE_FUNCTION();
m_buffer.Destroy();
m_texture.Destroy();
}
}

78
runtime/Sources/Renderer/RenderCore.cpp git.filemode.normal_file
View File

@@ -0,0 +1,78 @@
#define KVF_IMPLEMENTATION
#ifdef DEBUG
#define KVF_ENABLE_VALIDATION_LAYERS
#endif
#include <PreCompiled.h>
#include <Renderer/RenderCore.h>
#include <Renderer/Vulkan/VulkanLoader.h>
#include <Core/SDLManager.h>
#include <Platform/Window.h>
#include <Maths/Mat4.h>
namespace mlx
{
static VulkanLoader loader;
void ErrorCallback(const char* message) noexcept
{
FatalError(message);
std::cout << std::endl;
}
void ValidationErrorCallback(const char* message) noexcept
{
Error(message);
std::cout << std::endl;
}
void ValidationWarningCallback(const char* message) noexcept
{
Warning(message);
std::cout << std::endl;
}
void RenderCore::Init() noexcept
{
kvfSetErrorCallback(&ErrorCallback);
kvfSetValidationErrorCallback(&ValidationErrorCallback);
kvfSetValidationWarningCallback(&ValidationWarningCallback);
//kvfAddLayer("VK_LAYER_MESA_overlay");
Window window(1, 1, "", true);
std::vector<const char*> instance_extentions = window.GetRequiredVulkanInstanceExtentions();
m_instance = kvfCreateInstance(instance_extensions.data(), instance_extensions.size());
DebugLog("Vulkan : instance created");
loader.LoadInstance(m_instance);
VkSurfaceKHR surface = window.CreateVulkanSurface(m_instance);
m_physical_device = kvfPickGoodDefaultPhysicalDevice(m_instance, surface);
// just for style
VkPhysicalDeviceProperties props;
vkGetPhysicalDeviceProperties(m_physical_device, &props);
DebugLog("Vulkan : physical device picked '%'", props.deviceName);
const char* device_extensions[] = { VK_KHR_SWAPCHAIN_EXTENSION_NAME };
VkPhysicalDeviceFeatures features{};
vkGetPhysicalDeviceFeatures(m_physical_device, &features);
m_device = kvfCreateDevice(m_physical_device, device_extensions, sizeof(device_extensions) / sizeof(device_extensions[0]), &features);
DebugLog("Vulkan : logical device created");
vkDestroySurfaceKHR(m_instance, surface, nullptr);
window.Destroy();
}
void RenderCore::Destroy() noexcept
{
WaitDeviceIdle();
kvfDestroyDevice(m_device);
DebugLog("Vulkan : logical device destroyed");
kvfDestroyInstance(m_instance);
DebugLog("Vulkan : instance destroyed");
}
}

View File

@@ -0,0 +1,112 @@
#include <PreCompiled.h>
#include <Renderer/RenderPasses/2DPass.h>
#include <Renderer/Pipelines/Graphics.h>
#include <Renderer/ViewerData.h>
#include <Renderer/Renderer.h>
#include <Graphics/Scene.h>
#include <Maths/Mat4.h>
namespace mlx
{
struct SpriteData
{
Vec4f color;
Vec2f position;
};
void Render2DPass::Init()
{
ShaderLayout vertex_shader_layout(
{
{ 0,
ShaderSetLayout({
{ 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER }
})
}
}, { ShaderPushConstantLayout({ 0, sizeof(SpriteData) }) }
);
std::vector<std::uint8_t> vertex_shader_code = {
#include <Embedded/2DVertex.spv.h>
};
p_vertex_shader = std::make_shared<Shader>(vertex_shader_code, ShaderType::Vertex, std::move(vertex_shader_layout));
ShaderLayout fragment_shader_layout(
{
{ 1,
ShaderSetLayout({
{ 0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER }
})
}
}, {}
);
std::vector<std::uint8_t> fragment_shader_code = {
#include <Embedded/2DFragment.spv.h>
};
p_fragment_shader = std::make_shared<Shader>(fragment_shader, ShaderType::Fragment, std::move(fragment_shader_layout));
std::function<void(const EventBase&)> functor = [this](const EventBase& event)
{
if(event.What() == Event::ResizeEventCode)
m_pipeline.Destroy();
};
EventBus::RegisterListener({ functor, "__ScopRender2DPass" });
p_viewer_data_set = std::make_shared<DescriptorSet>(p_vertex_shader->GetShaderLayout().set_layouts[0].second, p_vertex_shader->GetPipelineLayout().set_layouts[0], ShaderType::Vertex);
p_texture_set = std::make_shared<DescriptorSet>(p_fragment_shader->GetShaderLayout().set_layouts[0].second, p_fragment_shader->GetPipelineLayout().set_layouts[0], ShaderType::Fragment);
p_viewer_data_buffer = std::make_shared<UniformBuffer>();
p_viewer_data_buffer->Init(sizeof(ViewerData2D));
for(std::size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++)
{
p_viewer_data_set->SetUniformBuffer(i, 0, p_viewer_data_buffer->Get(i));
p_viewer_data_set->Update(i);
}
}
void Render2DPass::Pass(Scene& scene, Renderer& renderer, Texture& render_target)
{
if(m_pipeline.GetPipeline() == VK_NULL_HANDLE)
{
GraphicPipelineDescriptor pipeline_descriptor;
pipeline_descriptor.vertex_shader = p_vertex_shader;
pipeline_descriptor.fragment_shader = p_fragment_shader;
pipeline_descriptor.color_attachments = { &render_target };
pipeline_descriptor.clear_color_attachments = false;
m_pipeline.Init(pipeline_descriptor);
}
std::uint32_t frame_index = renderer.GetCurrentFrameIndex();
ViewerData viewer_data;
viewer_data.projection = Mat4f::Ortho(0.0f, render_target.GetWidth(), render_target.GetHeight(), 0.0f);
static CPUBuffer buffer(sizeof(ViewerData2D));
std::memcpy(buffer.GetData(), &viewer_data, buffer.GetSize());
p_viewer_data_buffer->SetData(buffer, frame_index);
VkCommandBuffer cmd = renderer.GetActiveCommandBuffer();
m_pipeline.BindPipeline(cmd, 0, {});
for(auto sprite : scene.GetSprites())
{
SpriteData sprite_data;
sprite_data.position = Vec2f{ static_cast<float>(sprite->GetPosition().x), static_cast<float>(sprite->GetPosition().y) };
sprite_data.color = sprite->GetColor();
if(!sprite->IsSetInit())
sprite->UpdateDescriptorSet(*p_texture_set);
sprite->Bind(frame_index, cmd);
std::array<VkDescriptorSet, 2> sets = { p_viewer_data_set->GetSet(frame_index), sprite->GetSet(frame_index) };
vkCmdBindDescriptorSets(cmd, m_pipeline.GetPipelineBindPoint(), m_pipeline.GetPipelineLayout(), 0, sets.size(), sets.data(), 0, nullptr);
vkCmdPushConstants(cmd, m_pipeline.GetPipelineLayout(), VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(SpriteData), &sprite_data);
sprite->GetMesh()->Draw(cmd, renderer.GetDrawCallsCounterRef(), renderer.GetPolygonDrawnCounterRef());
}
m_pipeline.EndPipeline(cmd);
}
void Render2DPass::Destroy()
{
m_pipeline.Destroy();
p_vertex_shader.reset();
p_fragment_shader.reset();
p_viewer_data_set.reset();
p_viewer_data_buffer->Destroy();
p_texture_set.reset();
}
}

View File

@@ -0,0 +1,76 @@
#include <PreCompiled.h>
#include <Renderer/RenderPasses/FinalPass.h>
#include <Renderer/Pipelines/Graphics.h>
#include <Renderer/Renderer.h>
#include <Graphics/Scene.h>
#include <Core/EventBus.h>
namespace mlx
{
void FinalPass::Init()
{
ShaderLayout vertex_shader_layout(
{}, {}
);
std::vector<std::uint8_t> vertex_shader_code = {
#include <Embedded/ScreenVertex.spv.h>
};
p_vertex_shader = std::make_shared<Shader>(vertex_shader_code, ShaderType::Vertex, std::move(vertex_shader_layout));
ShaderLayout fragment_shader_layout(
{
{ 0,
ShaderSetLayout({
{ 0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER }
})
}
}, {}
);
std::vector<std::uint8_t> fragment_shader_code = {
#include <Embedded/ScreenFragment.spv.h>
};
p_fragment_shader = std::make_shared<Shader>(fragment_shader_code, ShaderType::Fragment, std::move(fragment_shader_layout));
std::function<void(const EventBase&)> functor = [this](const EventBase& event)
{
if(event.What() == Event::ResizeEventCode)
m_pipeline.Destroy();
};
EventBus::RegisterListener({ functor, "__ScopFinalPass" });
p_set = std::make_shared<DescriptorSet>(p_fragment_shader->GetShaderLayout().set_layouts[0].second, p_fragment_shader->GetPipelineLayout().set_layouts[0], ShaderType::Fragment);
}
void FinalPass::Pass(Scene& scene, Renderer& renderer, Texture& render_target)
{
if(m_pipeline.GetPipeline() == VK_NULL_HANDLE)
{
GraphicPipelineDescriptor pipeline_descriptor;
pipeline_descriptor.vertex_shader = p_vertex_shader;
pipeline_descriptor.fragment_shader = p_fragment_shader;
pipeline_descriptor.renderer = &renderer;
pipeline_descriptor.no_vertex_inputs = true;
m_pipeline.Init(pipeline_descriptor);
}
VkCommandBuffer cmd = renderer.GetActiveCommandBuffer();
p_set->SetImage(renderer.GetCurrentFrameIndex(), 0, render_target);
p_set->Update(renderer.GetCurrentFrameIndex(), cmd);
m_pipeline.BindPipeline(cmd, renderer.GetSwapchainImageIndex(), { 0.0f, 0.0f, 0.0f, 1.0f });
VkDescriptorSet set = p_set->GetSet(renderer.GetCurrentFrameIndex());
vkCmdBindDescriptorSets(cmd, m_pipeline.GetPipelineBindPoint(), m_pipeline.GetPipelineLayout(), 0, 1, &set, 0, nullptr);
vkCmdDraw(cmd, 3, 1, 0, 0);
renderer.GetDrawCallsCounterRef()++;
renderer.GetPolygonDrawnCounterRef()++;
m_pipeline.EndPipeline(cmd);
}
void FinalPass::Destroy()
{
m_pipeline.Destroy();
p_vertex_shader.reset();
p_fragment_shader.reset();
p_set.reset();
}
}

View File

@@ -0,0 +1,45 @@
#include <PreCompiled.h>
#include <Renderer/RenderPasses/Passes.h>
#include <Renderer/Renderer.h>
#include <Graphics/Scene.h>
namespace mlx
{
void RenderPasses::Init()
{
m_2Dpass.Init();
m_final.Init();
}
void RenderPasses::Pass(Scene& scene, Renderer& renderer)
{
if(!m_main_render_texture.IsInit())
{
std::function<void(const EventBase&)> functor = [this, renderer](const EventBase& event)
{
if(event.What() == Event::ResizeEventCode)
{
m_main_render_texture.Destroy();
auto extent = kvfGetSwapchainImagesSize(renderer.GetSwapchain());
m_main_render_texture.Init({}, extent.width, extent.height);
}
};
EventBus::RegisterListener({ functor, "__ScopRenderPasses" });
auto extent = kvfGetSwapchainImagesSize(renderer.GetSwapchain());
m_main_render_texture.Init({}, extent.width, extent.height);
}
m_main_render_texture.Clear(renderer.GetActiveCommandBuffer(), Vec4f{ 0.0f, 0.0f, 0.0f, 1.0f });
m_2Dpass.Pass(scene, renderer, m_main_render_texture);
m_final.Pass(scene, renderer, m_main_render_texture);
}
void RenderPasses::Destroy()
{
m_2Dpass.Destroy();
m_final.Destroy();
m_main_render_texture.Destroy();
}
}

View File

@@ -1,195 +1,139 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* Renderer.cpp :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2022/12/18 17:25:16 by maldavid #+# #+# */
/* Updated: 2024/04/24 01:58:51 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
#include <PreCompiled.h>
#include <Renderer/Renderer.h>
#include <Renderer/Images/Texture.h>
#include <Renderer/Core/RenderCore.h>
#include <Renderer/RenderCore.h>
#include <Core/Enums.h>
#include <Renderer/Pipelines/Shader.h>
#include <Core/EventBus.h>
namespace mlx
{
void Renderer::Init(NonOwningPtr<Texture> render_target)
namespace Internal
{
MLX_PROFILE_FUNCTION();
if(!render_target)
struct ResizeEventBroadcast : public EventBase
{
m_surface.Create(*this);
m_swapchain.Init(this);
m_pass.Init(m_swapchain.GetImagesFormat(), VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
for(std::size_t i = 0; i < m_swapchain.GetImagesNumber(); i++)
m_framebuffers.emplace_back().Init(m_pass, m_swapchain.GetImage(i));
}
else
Event What() const override { return Event::ResizeEventCode; }
};
struct FrameBeginEventBroadcast : public EventBase
{
m_render_target = render_target;
m_render_target->TransitionLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
m_pass.Init(m_render_target->GetFormat(), m_render_target->GetLayout());
m_framebuffers.emplace_back().Init(m_pass, *static_cast<Image*>(m_render_target));
}
m_cmd.Init();
Event What() const override { return Event::FrameBeginEventCode; }
};
}
void Renderer::Init(NonOwningPtr<Window> window)
{
std::function<void(const EventBase&)> functor = [this](const EventBase& event)
{
if(event.What() == Event::ResizeEventCode)
this->RequireFramebufferResize();
};
EventBus::RegisterListener({ functor, "__ScopRenderer" });
p_window = window;
auto& render_core = RenderCore::Get();
m_surface = p_window->CreateVulkanSurface(render_core::GetInstance());
DebugLog("Vulkan : surface created");
CreateSwapchain();
for(std::size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++)
{
m_render_finished_semaphores[i].Init();
m_image_available_semaphores[i].Init();
m_image_available_semaphores[i] = kvfCreateSemaphore(render_core.GetDevice());
DebugLog("Vulkan : image available semaphore created");
m_render_finished_semaphores[i] = kvfCreateSemaphore(render_core.GetDevice());
DebugLog("Vulkan : render finished semaphore created");
m_cmd_buffers[i] = kvfCreateCommandBuffer(render_core.GetDevice());
DebugLog("Vulkan : command buffer created");
m_cmd_fences[i] = kvfCreateFence(render_core.GetDevice());
DebugLog("Vulkan : fence created");
}
m_uniform_buffer.reset(new UniformBuffer);
#ifdef DEBUG
m_uniform_buffer->Create(this, sizeof(glm::mat4), "__mlx_matrices_uniform_buffer_");
#else
m_uniform_buffer->Create(this, sizeof(glm::mat4), nullptr);
#endif
DescriptorSetLayout vert_layout;
DescriptorSetLayout frag_layout;
vert_layout.Init({
{0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER}
}, VK_SHADER_STAGE_VERTEX_BIT);
frag_layout.Init({
{0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER}
}, VK_SHADER_STAGE_FRAGMENT_BIT);
m_vert_set.Init(this, &RenderCore::Get().GetDescriptorPool(), std::move(vert_layout));
m_frag_set.Init(this, &RenderCore::Get().GetDescriptorPool(), std::move(frag_layout));
m_vert_set.WriteDescriptor(0, m_uniform_buffer.Get());
m_pipeline.Init(*this);
m_framebuffer_resized = false;
}
bool Renderer::BeginFrame()
{
MLX_PROFILE_FUNCTION();
auto device = RenderCore::Get().GetDevice().Get();
if(!m_render_target)
kvfWaitForFence(RenderCore::Get().GetDevice(), m_cmd_fences[m_current_frame_index]);
VkResult result = vkAcquireNextImageKHR(RenderCore::Get().GetDevice(), m_swapchain, UINT64_MAX, m_image_available_semaphores[m_current_frame_index], VK_NULL_HANDLE, &m_swapchain_image_index);
if(result == VK_ERROR_OUT_OF_DATE_KHR)
{
m_cmd.GetCmdBuffer(m_current_frame_index).WaitForExecution();
VkResult result = vkAcquireNextImageKHR(device, m_swapchain.Get(), UINT64_MAX, m_image_available_semaphores[m_current_frame_index].Get(), VK_NULL_HANDLE, &m_image_index);
if(result == VK_ERROR_OUT_OF_DATE_KHR)
{
RecreateRenderData();
return false;
}
else if(result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR)
FatalError("Vulkan error : failed to acquire swapchain image");
}
else
{
m_image_index = 0;
if(m_render_target->GetLayout() != VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)
m_render_target->TransitionLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
DestroySwapchain();
CreateSwapchain();
EventBus::SendBroadcast(Internal::ResizeEventBroadcast{});
return false;
}
else if(result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR)
FatalError("Vulkan error : failed to acquire swapchain image, %", kvfVerbaliseVkResult(result));
m_cmd.GetCmdBuffer(m_current_frame_index).Reset();
m_cmd.GetCmdBuffer(m_current_frame_index).BeginRecord();
auto& fb = _framebuffers[_image_index];
m_pass.Begin(GetActiveCmdBuffer(), fb);
m_pipeline.BindPipeline(m_cmd.GetCmdBuffer(m_current_frame_index));
VkViewport viewport{};
viewport.x = 0.0f;
viewport.y = 0.0f;
viewport.width = static_cast<float>(fb.GetWidth());
viewport.height = static_cast<float>(fb.GetHeight());
viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f;
vkCmdSetViewport(m_cmd.GetCmdBuffer(m_current_frame_index).Get(), 0, 1, &viewport);
VkRect2D scissor{};
scissor.offset = { 0, 0 };
scissor.extent = { fb.GetWidth(), fb.GetHeight()};
vkCmdSetScissor(m_cmd.GetCmdBuffer(m_current_frame_index).Get(), 0, 1, &scissor);
vkResetCommandBuffer(m_cmd_buffers[m_current_frame_index], 0);
kvfBeginCommandBuffer(m_cmd_buffers[m_current_frame_index], 0);
m_drawcalls = 0;
m_polygons_drawn = 0;
EventBus::SendBroadcast(Internal::FrameBeginEventBroadcast{});
return true;
}
void Renderer::EndFrame()
{
MLX_PROFILE_FUNCTION();
m_pass.End(GetActiveCmdBuffer());
m_cmd.GetCmdBuffer(m_current_frame_index).EndRecord();
if(!m_render_target)
VkPipelineStageFlags wait_stages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
kvfEndCommandBuffer(m_cmd_buffers[m_current_frame_index]);
kvfSubmitCommandBuffer(RenderCore::Get().GetDevice(), m_cmd_buffers[m_current_frame_index], KVF_GRAPHICS_QUEUE, m_render_finished_semaphores[m_current_frame_index], m_image_available_semaphores[m_current_frame_index], m_cmd_fences[m_current_frame_index], wait_stages);
if(!kvfQueuePresentKHR(RenderCore::Get().GetDevice(), m_render_finished_semaphores[m_current_frame_index], m_swapchain, m_swapchain_image_index) || m_framebuffers_resize)
{
m_cmd.GetCmdBuffer(m_current_frame_index).Submit(&m_render_finished_semaphores[m_current_frame_index]);
VkSwapchainKHR swapchain = m_swapchain.Get();
VkSemaphore signal_semaphores[] = { m_render_finished_semaphores[m_current_frame_index].Get() };
VkPresentInfoKHR present_info{};
present_info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
present_info.waitSemaphoreCount = 1;
present_info.pWaitSemaphores = signal_semaphores;
present_info.swapchainCount = 1;
present_info.pSwapchains = &swapchain;
present_info.pImageIndices = &m_image_index;
VkResult result = vkQueuePresentKHR(RenderCore::Get().GetQueue().GetPresent(), &present_info);
if(result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || m_framebuffer_resized)
{
m_framebuffer_resized = false;
RecreateRenderData();
}
else if(result != VK_SUCCESS)
FatalError("Vulkan error : failed to present swap chain image");
m_current_frame_index = (m_current_frame_index + 1) % MAX_FRAMES_IN_FLIGHT;
}
else
{
m_cmd.GetCmdBuffer(m_current_frame_index).SubmitIdle(true);
m_current_frame_index = 0;
m_framebuffers_resize = false;
DestroySwapchain();
CreateSwapchain();
EventBus::SendBroadcast(Internal::ResizeEventBroadcast{});
}
m_current_frame_index = (m_current_frame_index + 1) % MAX_FRAMES_IN_FLIGHT;
kvfResetDeviceDescriptorPools(RenderCore::Get().GetDevice());
}
void Renderer::RecreateRenderData()
void Renderer::CreateSwapchain()
{
m_swapchain.Recreate();
m_pass.Destroy();
m_pass.Init(m_swapchain.GetImagesFormat(), VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
for(auto& fb : m_framebuffers)
fb.Destroy();
m_framebuffers.clear();
for(std::size_t i = 0; i < m_swapchain.GetImagesNumber(); i++)
m_framebuffers.emplace_back().Init(m_pass, m_swapchain.GetImage(i));
Vec2ui drawable_size = p_window->GetVulkanDrawableSize();
VkExtent2D extent = { drawable_size.x, drawable_size.y };
m_swapchain = kvfCreateSwapchainKHR(RenderCore::Get().GetDevice(), RenderCore::Get().GetPhysicalDevice(), m_surface, extent, false);
std::uint32_t images_count = kvfGetSwapchainImagesCount(m_swapchain);
std::vector<VkImage> tmp(images_count);
m_swapchain_images.resize(images_count);
vkGetSwapchainImagesKHR(RenderCore::Get().GetDevice(), m_swapchain, &images_count, tmp.data());
for(std::size_t i = 0; i < images_count; i++)
{
m_swapchain_images[i].Init(tmp[i], kvfGetSwapchainImagesFormat(m_swapchain), extent.width, extent.height);
m_swapchain_images[i].TransitionLayout(VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
m_swapchain_images[i].CreateImageView(VK_IMAGE_VIEW_TYPE_2D, VK_IMAGE_ASPECT_COLOR_BIT);
}
DebugLog("Vulkan : swapchain created");
}
void Renderer::Destroy()
void Renderer::DestroySwapchain()
{
MLX_PROFILE_FUNCTION();
vkDeviceWaitIdle(RenderCore::Get().GetDevice().Get());
RenderCore::Get().WaitDeviceIdle();
for(Image& img : m_swapchain_images)
img.DestroyImageView();
kvfDestroySwapchainKHR(RenderCore::Get().GetDevice(), m_swapchain);
DebugLog("Vulkan : swapchain destroyed");
}
m_ipeline.Destroy();
muniform_buffer->Destroy();
mvert_layout.Destroy();
mfrag_layout.Destroy();
mfrag_set.Destroy();
mvert_set.Destroy();
mcmd.Destroy();
mpass.Destroy();
if(!m_render_target)
void Renderer::Destroy() noexcept
{
auto& render_core = RenderCore::Get();
render_core.WaitDeviceIdle();
for(std::size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++)
{
m_swapchain.Destroy();
m_surface.Destroy();
kvfDestroySemaphore(render_core.GetDevice(), m_image_available_semaphores[i]);
DebugLog("Vulkan : image available semaphore destroyed");
kvfDestroySemaphore(render_core.GetDevice(), m_render_finished_semaphores[i]);
DebugLog("Vulkan : render finished semaphore destroyed");
kvfDestroyFence(render_core.GetDevice(), m_cmd_fences[i]);
DebugLog("Vulkan : fence destroyed");
}
for(auto& fb : m_framebuffers)
fb.Destroy();
for(int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++)
m_semaphores[i].Destroy();
DestroySwapchain();
vkDestroySurfaceKHR(render_core.GetInstance(), m_surface, nullptr);
DebugLog("Vulkan : surface destroyed");
m_surface = VK_NULL_HANDLE;
}
}

View File

@@ -1,49 +0,0 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* Framebuffer.cpp :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2022/10/06 18:18:06 by maldavid #+# #+# */
/* Updated: 2024/04/23 22:28:07 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
#include <PreCompiled.h>
#include <Renderer/Core/RenderCore.h>
#include <Renderer/Renderer.h>
#include <Renderer/Images/Image.h>
namespace mlx
{
void FrameBuffer::Init(RenderPass& renderpass, Image& image)
{
VkImageView attachments[] = { image.GetImageView() };
m_width = image.GetWidth();
m_height = image.GetHeight();
VkFramebufferCreateInfo framebuffer_info{};
framebuffer_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
framebuffer_info.renderPass = renderpass.get();
framebuffer_info.attachmentCount = 1;
framebuffer_info.pAttachments = attachments;
framebuffer_info.width = _width;
framebuffer_info.height = _height;
framebuffer_info.layers = 1;
VkResult res = vkCreateFramebuffer(RenderCore::Get().GetDevice().Get(), &framebuffer_info, nullptr, &m_framebuffer);
if(res != VK_SUCCESS)
FatalError("Vulkan : failed to create a framebuffer, %s", RCore::verbaliseResultVk(res));
DebugLog("Vulkan : created new framebuffer");
}
void FrameBuffer::Destroy() noexcept
{
vkDestroyFramebuffer(RenderCore::Get().GetDevice().Get(), m_framebuffer, nullptr);
m_framebuffer = VK_NULL_HANDLE;
DebugLog("Vulkan : destroyed a framebuffer");
}
}

View File

@@ -1,117 +0,0 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* Renderpass.cpp :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2022/10/06 18:21:36 by maldavid #+# #+# */
/* Updated: 2024/04/23 22:31:09 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
#include <pre_compiled.h>
#include "vk_render_pass.h"
#include <renderer/core/render_core.h>
#include <renderer/renderer.h>
#include <renderer/renderpass/vk_framebuffer.h>
#include <core/profiler.h>
namespace mlx
{
static const VkClearValue clear_color = {{{ 0.f, 0.f, 0.f, 1.0f }}}; // wtf, this mess to satisfy a warning
void RenderPass::Init(VkFormat attachement_format, VkImageLayout layout)
{
VkAttachmentDescription color_attachment{};
color_attachment.format = attachement_format;
color_attachment.samples = VK_SAMPLE_COUNT_1_BIT;
color_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
color_attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
color_attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
color_attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
color_attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
color_attachment.finalLayout = layout;
VkAttachmentReference color_attachment_ref{};
colorAttachmentRef.attachment = 0;
colorAttachmentRef.layout = (layout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : layout);
VkSubpassDescription subpass1{};
subpass1.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpass1.colorAttachmentCount = 1;
subpass1.pColorAttachments = &colorAttachmentRef;
VkSubpassDescription subpasses[] = { subpass1 };
std::vector<VkSubpassDependency> subpasses_deps;
subpasses_deps.emplace_back();
subpasses_deps.back().srcSubpass = VK_SUBPASS_EXTERNAL;
subpasses_deps.back().dstSubpass = 0;
subpasses_deps.back().srcStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
subpasses_deps.back().dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
subpasses_deps.back().srcAccessMask = VK_ACCESS_MEMORY_READ_BIT;
subpasses_deps.back().dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
subpasses_deps.back().dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
subpasses_deps.emplace_back();
subpasses_deps.back().srcSubpass = 0;
subpasses_deps.back().dstSubpass = VK_SUBPASS_EXTERNAL;
subpasses_deps.back().srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
subpasses_deps.back().dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
subpasses_deps.back().srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
subpasses_deps.back().dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
subpasses_deps.back().dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
VkRenderPassCreateInfo render_pass_info{};
render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
render_pass_info.attachmentCount = 1;
render_pass_info.pAttachments = &color_attachment;
render_pass_info.subpassCount = sizeof(subpasses) / sizeof(VkSubpassDescription);
render_pass_info.pSubpasses = subpasses;
render_pass_info.dependencyCount = static_cast<std::uint32_t>(subpasses_deps.size());
render_pass_info.pDependencies = subpasses_deps.data();
VkResult res = vkCreateRenderPass(RenderCore::Get().GetDevice().Get(), &render_pass_info, nullptr, &m_render_pass);
if(res != VK_SUCCESS)
FatalError("Vulkan : failed to create render pass, %", VerbaliseVkResult(res));
DebugLog("Vulkan : created new render pass");
}
void RenderPass::Begin(class CommandBuffer& cmd, class FrameBuffer& fb)
{
MLX_PROFILE_FUNCTION();
if(m_is_running)
return;
VkRenderPassBeginInfo render_pass_info{};
render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
render_pass_info.renderPass = m_render_pass;
render_pass_info.framebuffer = fb.Get();
render_pass_info.renderArea.offset = { 0, 0 };
render_pass_info.renderArea.extent = { fb.GetWidth(), fb.GetHeight() };
render_pass_info.clearValueCount = 1;
render_pass_info.pClearValues = &clear_color;
vkCmdBeginRenderPass(cmd.Get(), &render_pass_info, VK_SUBPASS_CONTENTS_INLINE);
m_is_running = true;
}
void RenderPass::End(class CommandBuffer& cmd)
{
MLX_PROFILE_FUNCTION();
if(!m_is_running)
return;
vkCmdEndRenderPass(cmdd.Get());
m_is_running = false;
}
void RenderPass::Destroy() noexcept
{
vkDestroyRenderPass(RenderCore::Get().GetDevice().Get(), m_render_pass, nullptr);
m_render_pass = VK_NULL_HANDLE;
DebugLog("Vulkan : destroyed a renderpass");
}
}

View File

@@ -1,150 +0,0 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* Swapchain.cpp :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2022/10/06 18:22:28 by maldavid #+# #+# */
/* Updated: 2024/04/23 22:43:10 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
#include <PreCompiled.h>
#include <Renderer/Core/RenderCore.h>
#include <Renderer/Renderer.h>
#include <Platform/Window.h>
namespace mlx
{
void SwapChain::Init(NonOwningPtr<Renderer> renderer)
{
VkDevice device = RenderCore::get().GetDevice().Get();
m_renderer = renderer;
m_swapchain_support = QuerySwapChainSupport(RenderCore::Get().GetDevice().GetPhysicalDevice());
VkSurfaceFormatKHR surface_format = renderer->GetSurface().ChooseSwapSurfaceFormat(m_swapchain_support.formats);
VkPresentModeKHR present_mode = ChooseSwapPresentMode(m_swapchain_support.present_modes);
m_extent = ChooseSwapExtent(m_swapchain_support.capabilities);
std::uint32_t image_count = m_swapchain_support.capabilities.minImageCount + 1;
if(m_swapchain_support.capabilities.maxImageCount > 0 && image_count > m_swapchain_support.capabilities.maxImageCount)
image_count = m_swapchain_support.capabilities.maxImageCount;
Queues::QueueFamilyIndices indices = RenderCore::Get().GetQueue().FindQueueFamilies(RenderCore::Get().GetDevice().GetPhysicalDevice());
std::uint32_t queue_family_indices[] = { indices.graphics_family.value(), indices.present_family.value() };
VkSwapchainCreateInfoKHR create_info{};
create_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
create_info.surface = renderer->GetSurface().Get();
create_info.minImageCount = image_count;
create_info.imageFormat = surface_format.format;
create_info.imageColorSpace = surface_format.colorSpace;
create_info.imageExtent = m_extent;
create_info.imageArrayLayers = 1;
create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
create_info.preTransform = m_swapchain_support.capabilities.currentTransform;
create_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
create_info.presentMode = present_mode;
create_info.clipped = VK_TRUE;
create_info.oldSwapchain = VK_NULL_HANDLE;
if(indices.graphics_family != indices.present_family)
{
create_info.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
create_info.queueFamilyIndexCount = 2;
create_info.pQueueFamilyIndices = queue_family_indices;
}
else
create_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
VkResult res = vkCreateSwapchainKHR(device, &create_info, nullptr, &m_swapchain);
if(res != VK_SUCCESS)
FatalError("Vulkan : failed to create the swapchain, %", VerbaliseVkResult(res));
std::vector<VkImage> tmp;
vkGetSwapchainImagesKHR(device, m_swapchain, &image_count, nullptr);
m_images.resize(image_count);
tmp.resize(image_count);
vkGetSwapchainImagesKHR(device, m_swapchain, &image_count, tmp.data());
for(std::size_t i = 0; i < image_count; i++)
{
m_images[i].Create(tmp[i], surface_format.format, m_extent.width, m_extent.height);
m_images[i].TransitionLayout(VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
m_images[i].CreateImageView(VK_IMAGE_VIEW_TYPE_2D, VK_IMAGE_ASPECT_COLOR_BIT);
}
m_swapchain_image_format = surface_format.format;
DebugLog("Vulkan : created new swapchain");
}
SwapChain::SwapChainSupportDetails SwapChain::QuerySwapChainSupport(VkPhysicalDevice device)
{
SwapChain::SwapChainSupportDetails details;
VkSurfaceKHR surface = m_renderer->GetSurface().Get();
if(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device, surface, &details.capabilities) != VK_SUCCESS)
FatalError("Vulkan : unable to retrieve surface capabilities");
std::uint32_t format_count = 0;
vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &format_count, nullptr);
if(format_count != 0)
{
details.formats.resize(format_count);
vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &format_count, details.formats.data());
}
std::uint32_t present_mode_count;
vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &present_mode_count, nullptr);
if(present_mode_count != 0)
{
details.present_modes.resize(present_mode_count);
vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &present_mode_count, details.present_modes.data());
}
return details;
}
VkPresentModeKHR SwapChain::chooseSwapPresentMode([[maybe_unused]] const std::vector<VkPresentModeKHR>& available_present_modes)
{
// in the future, you may choose to activate vsync or not
return VK_PRESENT_MODE_IMMEDIATE_KHR;
}
VkExtent2D SwapChain::ChooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities)
{
if(capabilities.currentExtent.width != std::numeric_limits<std::uint32_t>::max())
return capabilities.currentExtent;
int width, height;
glfwGetFramebufferSize(m_renderer->GetWindow()->GetNativeWindow(), &width, &height);
VkExtent2D actual_extent = { static_cast<std::uint32_t>(width), static_cast<std::uint32_t>(height) };
actual_extent.width = std::clamp(actual_extent.width, capabilities.minImageExtent.width, capabilities.maxImageExtent.width);
actual_extent.height = std::clamp(actual_extent.height, capabilities.minImageExtent.height, capabilities.maxImageExtent.height);
return actual_extent;
}
void SwapChain::Recreate()
{
Destroy();
Init(m_renderer);
}
void SwapChain::Destroy() noexcept
{
if(m_swapchain == VK_NULL_HANDLE)
return;
vkDeviceWaitIdle(RenderCore::Get().GetDevice().Get());
vkDestroySwapchainKHR(RenderCore::Get().GetDevice().Get(), m_swapchain, nullptr);
m_swapchain = VK_NULL_HANDLE;
for(Image& img : m_images)
img.DestroyImageView();
}
}

23
runtime/Sources/Renderer/SceneRenderer.cpp git.filemode.normal_file
View File

@@ -0,0 +1,23 @@
#include <PreCompiled.h>
#include <Renderer/ScenesRenderer.h>
#include <Renderer/Renderer.h>
#include <Graphics/Scene.h>
#include <Renderer/ViewerData.h>
namespacemlx
{
void SceneRenderer::Init()
{
m_passes.Init();
}
void SceneRenderer::Render(Scene& scene, Renderer& renderer)
{
m_passes.Pass(scene, renderer);
}
void SceneRenderer::Destroy()
{
m_passes.Destroy();
}
}

View File

@@ -1,88 +0,0 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* Font.cpp :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/12/11 22:06:09 by kbz_8 #+# #+# */
/* Updated: 2024/04/23 22:48:30 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
#include <PreCompiled.h>
#include <Renderer/Texts/Font.h>
#include <Renderer/Renderer.h>
constexpr const int RANGE = 1024;
namespace mlx
{
Font::Font(Renderer& renderer, const std::filesystem::path& path, float scale) : m_name(path.string()), m_renderer(renderer), m_scale(scale)
{
m_build_data = path;
}
Font::Font(class Renderer& renderer, const std::string& name, const std::vector<std::uint8_t>& ttf_data, float scale) : m_name(name), m_renderer(renderer), m_scale(scale)
{
m_build_data = ttf_data;
}
void Font::BuildFont()
{
MLX_PROFILE_FUNCTION();
std::vector<std::uint8_t> file_bytes;
if(std::holds_alternative<std::filesystem::path>(m_build_data))
{
std::ifstream file(std::get<std::filesystem::path>(m_build_data), std::ios::binary);
if(!file.is_open())
{
Error("Font load : cannot open font file, %", m_name.c_str());
return;
}
std::ifstream::pos_type fileSize = std::filesystem::file_size(std::get<std::filesystem::path>(m_build_data));
file.seekg(0, std::ios::beg);
file_bytes.resize(fileSize);
file.read(reinterpret_cast<char*>(file_bytes.data()), fileSize);
file.close();
}
std::vector<std::uint8_t> tmp_bitmap(RANGE * RANGE);
std::vector<std::uint8_t> vulkan_bitmap(RANGE * RANGE * 4);
stbtt_pack_context pc;
stbtt_PackBegin(&pc, tmp_bitmap.data(), RANGE, RANGE, RANGE, 1, nullptr);
if(std::holds_alternative<std::filesystem::path>(m_build_data))
stbtt_PackFontRange(&pc, file_bytes.data(), 0, m_scale, 32, 96, m_cdata.data());
else
stbtt_PackFontRange(&pc, std::get<std::vector<std::uint8_t>>(m_build_data).data(), 0, m_scale, 32, 96, m_cdata.data());
stbtt_PackEnd(&pc);
for(int i = 0, j = 0; i < RANGE * RANGE; i++, j += 4)
{
vulkan_bitmap[j + 0] = tmp_bitmap[i];
vulkan_bitmap[j + 1] = tmp_bitmap[i];
vulkan_bitmap[j + 2] = tmp_bitmap[i];
vulkan_bitmap[j + 3] = tmp_bitmap[i];
}
#ifdef DEBUG
m_atlas.Create(vulkan_bitmap.data(), RANGE, RANGE, VK_FORMAT_R8G8B8A8_UNORM, std::string(m_name + "_font_altas").c_str(), true);
#else
m_atlas.Create(vulkan_bitmap.data(), RANGE, RANGE, VK_FORMAT_R8G8B8A8_UNORM, nullptr, true);
#endif
m_atlas.SetDescriptor(m_renderer.GetFragDescriptorSet().Duplicate());
m_is_init = true;
}
void Font::Destroy()
{
MLX_PROFILE_FUNCTION();
m_atlas.Destroy();
m_is_init = false;
}
Font::~Font()
{
if(m_is_init)
destroy();
}
}

View File

@@ -1,68 +0,0 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* FontLibrary.cpp :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2024/01/18 09:28:14 by maldavid #+# #+# */
/* Updated: 2024/04/24 01:28:40 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
#include <PreCompiled.h>
#include <Renderer/Texts/FontLibrary.h>
#include <Renderer/Texts/Font.h>
#include <Renderer/Renderer.h>
namespace mlx
{
std::shared_ptr<Font> FontLibrary::GetFontData(FontID id)
{
MLX_PROFILE_FUNCTION();
if(!m_cache.count(id) || std::find(m_invalid_ids.begin(), m_invalid_ids.end(), id) != m_invalid_ids.end())
FatalError("Font Library : wrong font ID '%'", id);
return m_cache[id];
}
FontID FontLibrary::AddFontToLibrary(std::shared_ptr<Font> font)
{
MLX_PROFILE_FUNCTION();
auto it = std::find_if(m_cache.begin(), m_cache.end(), [&](const std::pair<FontID, std::shared_ptr<Font>>& v)
{
return v.second->GetScale() == font->GetScale() &&
v.second->GetName() == font->GetName() &&
std::find(m_invalid_ids.begin(), m_invalid_ids.end(), v.first) == m_invalid_ids.end();
});
if(it != m_cache.end())
return it->first;
font->BuildFont();
m_cache[m_current_id] = font;
m_current_id++;
return m_current_id - 1;
}
void FontLibrary::RemoveFontFromLibrary(FontID id)
{
MLX_PROFILE_FUNCTION();
if(!m_cache.count(id) || std::find(m_invalid_ids.begin(), m_invalid_ids.end(), id) != m_invalid_ids.end())
{
Warning("Font Library : trying to remove a font with an unkown or invalid ID '%'", id);
return;
}
m_cache[id]->Destroy();
m_invalid_ids.push_back(id);
}
void FontLibrary::ClearLibrary()
{
MLX_PROFILE_FUNCTION();
for(auto& [id, font] : m_cache)
{
font->Destroy();
m_invalid_ids.push_back(id);
}
// do not `_cache.clear();` as it releases the fonts and may not destroy the texture atlas that is in use by command buffers
}
}

View File

@@ -1,78 +0,0 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* Text.cpp :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2024/01/11 00:11:56 by maldavid #+# #+# */
/* Updated: 2024/04/24 01:33:58 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
#include <PreCompiled.h>
#include <Renderer/Texts/Text.h>
#include <Renderer/Renderer.h>
namespace mlx
{
void Text::Init(std::string text, FontID font, std::uint32_t color, std::vector<Vertex> vbo_data, std::vector<std::uint16_t> ibo_data)
{
MLX_PROFILE_FUNCTION();
if(m_is_init)
return;
m_text = std::move(text);
m_color = color;
m_font = font;
#ifdef DEBUG
std::string debug_name = m_text;
for(char& c : debug_name)
{
if(c == ' ' || c == '"' || c == '\'')
c = '_';
}
for(int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++)
m_vbo[i].Create(sizeof(Vertex) * vbo_data.size(), static_cast<const void*>(vbo_data.data()), debug_name.c_str());
m_ibo.Create(sizeof(std::uint16_t) * ibo_data.size(), ibo_data.data(), debug_name.c_str());
#else
for(int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++)
m_vbo[i].Create(sizeof(Vertex) * vbo_data.size(), static_cast<const void*>(vbo_data.data()), nullptr);
m_ibo.Create(sizeof(std::uint16_t) * ibo_data.size(), ibo_data.data(), nullptr);
#endif
m_is_init = true;
}
void Text::Bind(Renderer& renderer) noexcept
{
MLX_PROFILE_FUNCTION();
if(!m_is_init)
return;
m_vbo[renderer.GetActiveImageIndex()].Bind(renderer);
m_ibo.Bind(renderer);
}
void Text::updateVertexData(int frame, std::vector<Vertex> vbo_data)
{
MLX_PROFILE_FUNCTION();
if(!m_is_init)
return;
m_vbo[frame].SetData(sizeof(Vertex) * vbo_data.size(), static_cast<const void*>(vbo_data.data()));
}
void Text::destroy() noexcept
{
MLX_PROFILE_FUNCTION();
if(!m_is_init)
return;
for(int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++)
m_vbo[i].Destroy();
m_ibo.Destroy();
m_is_init = false;
}
Text::~Text()
{
Destroy();
}
}

View File

@@ -1,107 +0,0 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* TextDescriptor.cpp :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2024/01/11 00:23:11 by maldavid #+# #+# */
/* Updated: 2024/04/24 01:38:40 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
#include <Preompiled.h>
#include <Renderer/Images/TextureAtlas.h>
#include <Renderer/Texts/TextDescriptor.h>
#include <Renderer/Texts/Font.h>
#include <Renderer/Texts/Text.h>
#define STB_RECT_PACK_IMPLEMENTATION
#include <stb_rect_pack.h>
#include <Core/Memory.h>
#define STB_TRUETYPE_IMPLEMENTATION
#define STB_malloc(x, u) ((void)(u), MemManager::Malloc(x))
#define STB_free(x, u) ((void)(u), MemManager::Free(x))
#include <stb_truetype.h>
constexpr const int RANGE = 1024;
namespace mlx
{
TextDrawDescriptor::TextDrawDescriptor(std::string text, std::uint32_t _color, int _x, int _y) : color(_color), x(_x), y(_y), m_text(std::move(text))
{}
void TextDrawDescriptor::Init(FontID font) noexcept
{
MLX_PROFILE_FUNCTION();
std::vector<Vertex> vertex_data;
std::vector<std::uint16_t> index_data;
float stb_x = 0.0f;
float stb_y = 0.0f;
{
std::shared_ptr<Font> font_data = FontLibrary::Get().GetFontData(font);
for(char c : m_text)
{
if(c < 32)
continue;
stbtt_aligned_quad q;
stbtt_GetPackedQuad(font_data->GetCharData().data(), RANGE, RANGE, c - 32, &stb_x, &stb_y, &q, 1);
std::size_t index = vertex_data.size();
glm::vec4 vertex_color = {
static_cast<float>((color & 0x000000FF)) / 255.f,
static_cast<float>((color & 0x0000FF00) >> 8) / 255.f,
static_cast<float>((color & 0x00FF0000) >> 16) / 255.f,
static_cast<float>((color & 0xFF000000) >> 24) / 255.f
};
vertex_data.emplace_back(glm::vec2{q.x0, q.y0}, vertex_color, glm::vec2{q.s0, q.t0});
vertex_data.emplace_back(glm::vec2{q.x1, q.y0}, vertex_color, glm::vec2{q.s1, q.t0});
vertex_data.emplace_back(glm::vec2{q.x1, q.y1}, vertex_color, glm::vec2{q.s1, q.t1});
vertex_data.emplace_back(glm::vec2{q.x0, q.y1}, vertex_color, glm::vec2{q.s0, q.t1});
index_data.emplace_back(index + 0);
index_data.emplace_back(index + 1);
index_data.emplace_back(index + 2);
index_data.emplace_back(index + 2);
index_data.emplace_back(index + 3);
index_data.emplace_back(index + 0);
}
}
std::shared_ptr<Text> text_data = std::make_shared<Text>();
text_data->Init(m_text, font, color, std::move(vertex_data), std::move(index_data));
id = TextLibrary::Get().AddTextToLibrary(text_data);
DebugLog("Text put : registered new text to render");
}
void TextDrawDescriptor::Render(Renderer& renderer)
{
MLX_PROFILE_FUNCTION();
std::shared_ptr<Text> draw_data = TextLibrary::Get().GetTextData(id);
std::shared_ptr<Font> font_data = FontLibrary::Get().GetFontData(draw_data->GetFontInUse());
TextureAtlas& atlas = const_cast<TextureAtlas&>(font_data->GetAtlas());
draw_data->Bind(renderer);
if(!atlas.GetSet().IsInit())
atlas.SetDescriptor(renderer.GetFragDescriptorSet().Duplicate());
if(!atlas.HasBeenUpdated())
atlas.UpdateSet(0);
atlas.GetSet().Bind();
atlas.Render(renderer, x, y, draw_data->GetIBOsize());
}
void TextDrawDescriptor::ResetUpdate()
{
std::shared_ptr<Text> draw_data = TextLibrary::Get().GetTextData(id);
std::shared_ptr<Font> font_data = FontLibrary::Get().GetFontData(draw_data->GetFontInUse());
TextureAtlas& atlas = const_cast<TextureAtlas&>(font_data->GetAtlas());
atlas.ResetUpdate();
}
}

View File

@@ -1,62 +0,0 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* TextLibrary.cpp :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/04/10 11:59:57 by maldavid #+# #+# */
/* Updated: 2024/04/24 01:40:28 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
#include <PreCompiled.h>
#include <Renderer/Texts/TextLibrary.h>
#include <Renderer/Texts/Text.h>
#include <Renderer/Renderer.h>
namespace mlx
{
std::shared_ptr<Text> TextLibrary::GetTextData(TextID id)
{
MLX_PROFILE_FUNCTION();
if(!m_cache.count(id))
FatalError("Text Library : wrong text ID '%d'", id);
return m_cache[id];
}
TextID TextLibrary::AddTextToLibrary(std::shared_ptr<Text> text)
{
MLX_PROFILE_FUNCTION();
auto it = std::find_if(m_cache.begin(), m_cache.end(), [&](const std::pair<TextID, std::shared_ptr<Text>>& v)
{
return v.second->GetText() == text->GetText() && v.second->GetColor() == text->GetColor();
});
if(it != m_cache.end())
return it->first;
m_cache[m_current_id] = text;
m_current_id++;
return m_current_id - 1;
}
void TextLibrary::RemoveTextFromLibrary(TextID id)
{
MLX_PROFILE_FUNCTION();
if(!m_cache.count(id))
{
Warning("Text Library : trying to remove a text with an unkown or invalid ID '%d'", id);
return;
}
m_cache[id]->Destroy();
m_cache.erase(id);
}
void TextLibrary::ClearLibrary()
{
MLX_PROFILE_FUNCTION();
for(auto& [id, text] : m_cache)
text->Destroy();
m_cache.clear();
}
}

View File

@@ -1,65 +0,0 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* TextManager.cpp :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: maldavid <kbz_8.dev@akel-engine.com> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2023/04/06 16:41:13 by maldavid #+# #+# */
/* Updated: 2024/04/24 01:42:19 by maldavid ### ########.fr */
/* */
/* ************************************************************************** */
#include <PreCompiled.h>
#include <Renderer/Texts/TextDescriptor.h>
#include <Renderer/Texts/TextLibrary.h>
#include <Renderer/Texts/Text.h>
#include <Renderer/Texts/TextManager.h>
#include <Utils/DogicaTTF.h>
namespace mlx
{
void TextManager::Init(Renderer& renderer) noexcept
{
MLX_PROFILE_FUNCTION();
LoadFont(renderer, "default", 6.f);
}
void TextManager::LoadFont(Renderer& renderer, const std::filesystem::path& filepath, float scale)
{
MLX_PROFILE_FUNCTION();
std::shared_ptr<Font> font;
if(filepath.string() == "default")
font = std::make_shared<Font>(renderer, "default", dogica_ttf, scale);
else
font = std::make_shared<Font>(renderer, filepath, scale);
m_font_in_use = FontLibrary::Get().AddFontToLibrary(font);
}
std::pair<DrawableResource*, bool> TextManager::RegisterText(int x, int y, std::uint32_t color, std::string str)
{
MLX_PROFILE_FUNCTION();
auto res = m_text_descriptors.emplace(std::move(str), color, x, y);
if(res.second)
{
const_cast<TextDrawDescriptor&>(*res.first).Init(m_font_in_use);
return std::make_pair(static_cast<DrawableResource*>(&const_cast<TextDrawDescriptor&>(*res.first)), true);
}
auto text_ptr = TextLibrary::Get().GetTextData(res.first->id);
if(_font_in_use != text_ptr->GetFontInUse())
{
// TODO : update text vertex buffers rather than destroying it and recreating it
TextLibrary::Get().RemoveTextFromLibrary(res.first->id);
const_cast<TextDrawDescriptor&>(*res.first).Init(_font_in_use);
}
return std::make_pair(static_cast<DrawableResource*>(&const_cast<TextDrawDescriptor&>(*res.first)), false);
}
void TextManager::Destroy() noexcept
{
MLX_PROFILE_FUNCTION();
m_text_descriptors.clear();
}
}

View File

@@ -0,0 +1,416 @@
#include <PreCompiled.h>
#include <Renderer/Vulkan/VulkanLoader.h>
#ifdef _WIN32
__declspec(dllimport) HMODULE __stdcall LoadLibraryA(LPCSTR);
__declspec(dllimport) FARPROC __stdcall GetProcAddress(HMODULE, LPCSTR);
__declspec(dllimport) int __stdcall FreeLibrary(HMODULE);
#endif
#if defined(MLX_COMPILER_GCC)
#define DISABLE_GCC_PEDANTIC_WARNINGS \
_Pragma("GCC diagnostic push") \
_Pragma("GCC diagnostic ignored \"-Wpedantic\"")
#define RESTORE_GCC_PEDANTIC_WARNINGS \
_Pragma("GCC diagnostic pop")
#else
#define DISABLE_GCC_PEDANTIC_WARNINGS
#define RESTORE_GCC_PEDANTIC_WARNINGS
#endif
namespace mlx
{
namespace Internal
{
static PFN_vkVoidFunction vkGetInstanceProcAddrStub(Handle context, const char* name)
{
return vkGetInstanceProcAddr((VkInstance)context, name);
}
}
VulkanLoader::VulkanLoader()
{
#if defined(_WIN32)
p_module = LoadLibraryA("vulkan-1.dll");
if(!p_module)
FatalError("Vulkan loader : failed to load libvulkan");
vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)(void(*)(void))GetProcAddress(p_module, "vkGetInstanceProcAddr");
#elif defined(__APPLE__)
p_module = dlopen("libvulkan.dylib", RTLD_NOW | RTLD_LOCAL);
if(!p_module)
p_module = dlopen("libvulkan.1.dylib", RTLD_NOW | RTLD_LOCAL);
if(!p_module)
p_module = dlopen("libMoltenVK.dylib", RTLD_NOW | RTLD_LOCAL);
// Add support for using Vulkan and MoltenVK in a Framework. App store rules for iOS
// strictly enforce no .dylib's. If they aren't found it just falls through
if(!p_module)
p_module = dlopen("vulkan.framework/vulkan", RTLD_NOW | RTLD_LOCAL);
if(!p_module)
p_module = dlopen("MoltenVK.framework/MoltenVK", RTLD_NOW | RTLD_LOCAL);
// modern versions of macOS don't search /usr/local/lib automatically contrary to what man dlopen says
// Vulkan SDK uses this as the system-wide installation location, so we're going to fallback to this if all else fails
if(!p_module && getenv("DYLD_FALLBACK_LIBRARY_PATH") == NULL)
p_module = dlopen("/usr/local/lib/libvulkan.dylib", RTLD_NOW | RTLD_LOCAL);
if(!p_module)
FatalError("Vulkan loader : failed to load libvulkan");
vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)dlsym(p_module, "vkGetInstanceProcAddr");
#else
p_module = dlopen("libvulkan.so.1", RTLD_NOW | RTLD_LOCAL);
if(!p_module)
p_module = dlopen("libvulkan.so", RTLD_NOW | RTLD_LOCAL);
if(!p_module)
FatalError("Vulkan loader : failed to load libvulkan");
DISABLE_GCC_PEDANTIC_WARNINGS
vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)dlsym(p_module, "vkGetInstanceProcAddr");
RESTORE_GCC_PEDANTIC_WARNINGS
#endif
DebugLog("Vulkan loader : libvulkan loaded");
LoadGlobalFunctions(nullptr, Internal::vkGetInstanceProcAddrStub);
}
void VulkanLoader::LoadInstance(VkInstance instance)
{
LoadInstanceFunctions(instance, Internal::vkGetInstanceProcAddrStub);
LoadDeviceFunctions(instance, Internal::vkGetInstanceProcAddrStub);
}
void VulkanLoader::LoadGlobalFunctions(void* context, PFN_vkVoidFunction (*load)(void*, const char*)) noexcept
{
#if defined(VK_VERSION_1_0)
vkCreateInstance = (PFN_vkCreateInstance)load(context, "vkCreateInstance");
vkEnumerateInstanceExtensionProperties = (PFN_vkEnumerateInstanceExtensionProperties)load(context, "vkEnumerateInstanceExtensionProperties");
vkEnumerateInstanceLayerProperties = (PFN_vkEnumerateInstanceLayerProperties)load(context, "vkEnumerateInstanceLayerProperties");
#endif /* defined(VK_VERSION_1_0) */
DebugLog("Vulkan loader : global functions loaded");
}
void VulkanLoader::LoadInstanceFunctions(void* context, PFN_vkVoidFunction (*load)(void*, const char*)) noexcept
{
#if defined(VK_VERSION_1_0)
vkCreateDevice = (PFN_vkCreateDevice)load(context, "vkCreateDevice");
vkDestroyInstance = (PFN_vkDestroyInstance)load(context, "vkDestroyInstance");
vkEnumerateDeviceExtensionProperties = (PFN_vkEnumerateDeviceExtensionProperties)load(context, "vkEnumerateDeviceExtensionProperties");
vkEnumerateDeviceLayerProperties = (PFN_vkEnumerateDeviceLayerProperties)load(context, "vkEnumerateDeviceLayerProperties");
vkEnumeratePhysicalDevices = (PFN_vkEnumeratePhysicalDevices)load(context, "vkEnumeratePhysicalDevices");
vkGetDeviceProcAddr = (PFN_vkGetDeviceProcAddr)load(context, "vkGetDeviceProcAddr");
vkGetPhysicalDeviceFeatures = (PFN_vkGetPhysicalDeviceFeatures)load(context, "vkGetPhysicalDeviceFeatures");
vkGetPhysicalDeviceFormatProperties = (PFN_vkGetPhysicalDeviceFormatProperties)load(context, "vkGetPhysicalDeviceFormatProperties");
vkGetPhysicalDeviceImageFormatProperties = (PFN_vkGetPhysicalDeviceImageFormatProperties)load(context, "vkGetPhysicalDeviceImageFormatProperties");
vkGetPhysicalDeviceMemoryProperties = (PFN_vkGetPhysicalDeviceMemoryProperties)load(context, "vkGetPhysicalDeviceMemoryProperties");
vkGetPhysicalDeviceProperties = (PFN_vkGetPhysicalDeviceProperties)load(context, "vkGetPhysicalDeviceProperties");
vkGetPhysicalDeviceQueueFamilyProperties = (PFN_vkGetPhysicalDeviceQueueFamilyProperties)load(context, "vkGetPhysicalDeviceQueueFamilyProperties");
vkGetPhysicalDeviceSparseImageFormatProperties = (PFN_vkGetPhysicalDeviceSparseImageFormatProperties)load(context, "vkGetPhysicalDeviceSparseImageFormatProperties");
#endif /* defined(VK_VERSION_1_0) */
#if defined(VK_KHR_surface)
vkDestroySurfaceKHR = (PFN_vkDestroySurfaceKHR)load(context, "vkDestroySurfaceKHR");
vkGetPhysicalDeviceSurfaceCapabilitiesKHR = (PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR)load(context, "vkGetPhysicalDeviceSurfaceCapabilitiesKHR");
vkGetPhysicalDeviceSurfaceFormatsKHR = (PFN_vkGetPhysicalDeviceSurfaceFormatsKHR)load(context, "vkGetPhysicalDeviceSurfaceFormatsKHR");
vkGetPhysicalDeviceSurfacePresentModesKHR = (PFN_vkGetPhysicalDeviceSurfacePresentModesKHR)load(context, "vkGetPhysicalDeviceSurfacePresentModesKHR");
vkGetPhysicalDeviceSurfaceSupportKHR = (PFN_vkGetPhysicalDeviceSurfaceSupportKHR)load(context, "vkGetPhysicalDeviceSurfaceSupportKHR");
#endif /* defined(VK_KHR_surface) */
DebugLog("Vulkan loader : instance functions loaded");
}
void VulkanLoader::LoadDeviceFunctions(void* context, PFN_vkVoidFunction (*load)(void*, const char*)) noexcept
{
#if defined(VK_VERSION_1_0)
vkAllocateCommandBuffers = (PFN_vkAllocateCommandBuffers)load(context, "vkAllocateCommandBuffers");
vkAllocateDescriptorSets = (PFN_vkAllocateDescriptorSets)load(context, "vkAllocateDescriptorSets");
vkAllocateMemory = (PFN_vkAllocateMemory)load(context, "vkAllocateMemory");
vkBeginCommandBuffer = (PFN_vkBeginCommandBuffer)load(context, "vkBeginCommandBuffer");
vkBindBufferMemory = (PFN_vkBindBufferMemory)load(context, "vkBindBufferMemory");
vkBindImageMemory = (PFN_vkBindImageMemory)load(context, "vkBindImageMemory");
vkCmdBeginQuery = (PFN_vkCmdBeginQuery)load(context, "vkCmdBeginQuery");
vkCmdBeginRenderPass = (PFN_vkCmdBeginRenderPass)load(context, "vkCmdBeginRenderPass");
vkCmdBindDescriptorSets = (PFN_vkCmdBindDescriptorSets)load(context, "vkCmdBindDescriptorSets");
vkCmdBindIndexBuffer = (PFN_vkCmdBindIndexBuffer)load(context, "vkCmdBindIndexBuffer");
vkCmdBindPipeline = (PFN_vkCmdBindPipeline)load(context, "vkCmdBindPipeline");
vkCmdBindVertexBuffers = (PFN_vkCmdBindVertexBuffers)load(context, "vkCmdBindVertexBuffers");
vkCmdBlitImage = (PFN_vkCmdBlitImage)load(context, "vkCmdBlitImage");
vkCmdClearAttachments = (PFN_vkCmdClearAttachments)load(context, "vkCmdClearAttachments");
vkCmdClearColorImage = (PFN_vkCmdClearColorImage)load(context, "vkCmdClearColorImage");
vkCmdClearDepthStencilImage = (PFN_vkCmdClearDepthStencilImage)load(context, "vkCmdClearDepthStencilImage");
vkCmdCopyBuffer = (PFN_vkCmdCopyBuffer)load(context, "vkCmdCopyBuffer");
vkCmdCopyBufferToImage = (PFN_vkCmdCopyBufferToImage)load(context, "vkCmdCopyBufferToImage");
vkCmdCopyImage = (PFN_vkCmdCopyImage)load(context, "vkCmdCopyImage");
vkCmdCopyImageToBuffer = (PFN_vkCmdCopyImageToBuffer)load(context, "vkCmdCopyImageToBuffer");
vkCmdCopyQueryPoolResults = (PFN_vkCmdCopyQueryPoolResults)load(context, "vkCmdCopyQueryPoolResults");
vkCmdDispatch = (PFN_vkCmdDispatch)load(context, "vkCmdDispatch");
vkCmdDispatchIndirect = (PFN_vkCmdDispatchIndirect)load(context, "vkCmdDispatchIndirect");
vkCmdDraw = (PFN_vkCmdDraw)load(context, "vkCmdDraw");
vkCmdDrawIndexed = (PFN_vkCmdDrawIndexed)load(context, "vkCmdDrawIndexed");
vkCmdDrawIndexedIndirect = (PFN_vkCmdDrawIndexedIndirect)load(context, "vkCmdDrawIndexedIndirect");
vkCmdDrawIndirect = (PFN_vkCmdDrawIndirect)load(context, "vkCmdDrawIndirect");
vkCmdEndQuery = (PFN_vkCmdEndQuery)load(context, "vkCmdEndQuery");
vkCmdEndRenderPass = (PFN_vkCmdEndRenderPass)load(context, "vkCmdEndRenderPass");
vkCmdExecuteCommands = (PFN_vkCmdExecuteCommands)load(context, "vkCmdExecuteCommands");
vkCmdFillBuffer = (PFN_vkCmdFillBuffer)load(context, "vkCmdFillBuffer");
vkCmdNextSubpass = (PFN_vkCmdNextSubpass)load(context, "vkCmdNextSubpass");
vkCmdPipelineBarrier = (PFN_vkCmdPipelineBarrier)load(context, "vkCmdPipelineBarrier");
vkCmdPushConstants = (PFN_vkCmdPushConstants)load(context, "vkCmdPushConstants");
vkCmdResetEvent = (PFN_vkCmdResetEvent)load(context, "vkCmdResetEvent");
vkCmdResetQueryPool = (PFN_vkCmdResetQueryPool)load(context, "vkCmdResetQueryPool");
vkCmdResolveImage = (PFN_vkCmdResolveImage)load(context, "vkCmdResolveImage");
vkCmdSetBlendConstants = (PFN_vkCmdSetBlendConstants)load(context, "vkCmdSetBlendConstants");
vkCmdSetDepthBias = (PFN_vkCmdSetDepthBias)load(context, "vkCmdSetDepthBias");
vkCmdSetDepthBounds = (PFN_vkCmdSetDepthBounds)load(context, "vkCmdSetDepthBounds");
vkCmdSetEvent = (PFN_vkCmdSetEvent)load(context, "vkCmdSetEvent");
vkCmdSetLineWidth = (PFN_vkCmdSetLineWidth)load(context, "vkCmdSetLineWidth");
vkCmdSetScissor = (PFN_vkCmdSetScissor)load(context, "vkCmdSetScissor");
vkCmdSetStencilCompareMask = (PFN_vkCmdSetStencilCompareMask)load(context, "vkCmdSetStencilCompareMask");
vkCmdSetStencilReference = (PFN_vkCmdSetStencilReference)load(context, "vkCmdSetStencilReference");
vkCmdSetStencilWriteMask = (PFN_vkCmdSetStencilWriteMask)load(context, "vkCmdSetStencilWriteMask");
vkCmdSetViewport = (PFN_vkCmdSetViewport)load(context, "vkCmdSetViewport");
vkCmdUpdateBuffer = (PFN_vkCmdUpdateBuffer)load(context, "vkCmdUpdateBuffer");
vkCmdWaitEvents = (PFN_vkCmdWaitEvents)load(context, "vkCmdWaitEvents");
vkCmdWriteTimestamp = (PFN_vkCmdWriteTimestamp)load(context, "vkCmdWriteTimestamp");
vkCreateBuffer = (PFN_vkCreateBuffer)load(context, "vkCreateBuffer");
vkCreateBufferView = (PFN_vkCreateBufferView)load(context, "vkCreateBufferView");
vkCreateCommandPool = (PFN_vkCreateCommandPool)load(context, "vkCreateCommandPool");
vkCreateComputePipelines = (PFN_vkCreateComputePipelines)load(context, "vkCreateComputePipelines");
vkCreateDescriptorPool = (PFN_vkCreateDescriptorPool)load(context, "vkCreateDescriptorPool");
vkCreateDescriptorSetLayout = (PFN_vkCreateDescriptorSetLayout)load(context, "vkCreateDescriptorSetLayout");
vkCreateEvent = (PFN_vkCreateEvent)load(context, "vkCreateEvent");
vkCreateFence = (PFN_vkCreateFence)load(context, "vkCreateFence");
vkCreateFramebuffer = (PFN_vkCreateFramebuffer)load(context, "vkCreateFramebuffer");
vkCreateGraphicsPipelines = (PFN_vkCreateGraphicsPipelines)load(context, "vkCreateGraphicsPipelines");
vkCreateImage = (PFN_vkCreateImage)load(context, "vkCreateImage");
vkCreateImageView = (PFN_vkCreateImageView)load(context, "vkCreateImageView");
vkCreatePipelineCache = (PFN_vkCreatePipelineCache)load(context, "vkCreatePipelineCache");
vkCreatePipelineLayout = (PFN_vkCreatePipelineLayout)load(context, "vkCreatePipelineLayout");
vkCreateQueryPool = (PFN_vkCreateQueryPool)load(context, "vkCreateQueryPool");
vkCreateRenderPass = (PFN_vkCreateRenderPass)load(context, "vkCreateRenderPass");
vkCreateSampler = (PFN_vkCreateSampler)load(context, "vkCreateSampler");
vkCreateSemaphore = (PFN_vkCreateSemaphore)load(context, "vkCreateSemaphore");
vkCreateShaderModule = (PFN_vkCreateShaderModule)load(context, "vkCreateShaderModule");
vkDestroyBuffer = (PFN_vkDestroyBuffer)load(context, "vkDestroyBuffer");
vkDestroyBufferView = (PFN_vkDestroyBufferView)load(context, "vkDestroyBufferView");
vkDestroyCommandPool = (PFN_vkDestroyCommandPool)load(context, "vkDestroyCommandPool");
vkDestroyDescriptorPool = (PFN_vkDestroyDescriptorPool)load(context, "vkDestroyDescriptorPool");
vkDestroyDescriptorSetLayout = (PFN_vkDestroyDescriptorSetLayout)load(context, "vkDestroyDescriptorSetLayout");
vkDestroyDevice = (PFN_vkDestroyDevice)load(context, "vkDestroyDevice");
vkDestroyEvent = (PFN_vkDestroyEvent)load(context, "vkDestroyEvent");
vkDestroyFence = (PFN_vkDestroyFence)load(context, "vkDestroyFence");
vkDestroyFramebuffer = (PFN_vkDestroyFramebuffer)load(context, "vkDestroyFramebuffer");
vkDestroyImage = (PFN_vkDestroyImage)load(context, "vkDestroyImage");
vkDestroyImageView = (PFN_vkDestroyImageView)load(context, "vkDestroyImageView");
vkDestroyPipeline = (PFN_vkDestroyPipeline)load(context, "vkDestroyPipeline");
vkDestroyPipelineCache = (PFN_vkDestroyPipelineCache)load(context, "vkDestroyPipelineCache");
vkDestroyPipelineLayout = (PFN_vkDestroyPipelineLayout)load(context, "vkDestroyPipelineLayout");
vkDestroyQueryPool = (PFN_vkDestroyQueryPool)load(context, "vkDestroyQueryPool");
vkDestroyRenderPass = (PFN_vkDestroyRenderPass)load(context, "vkDestroyRenderPass");
vkDestroySampler = (PFN_vkDestroySampler)load(context, "vkDestroySampler");
vkDestroySemaphore = (PFN_vkDestroySemaphore)load(context, "vkDestroySemaphore");
vkDestroyShaderModule = (PFN_vkDestroyShaderModule)load(context, "vkDestroyShaderModule");
vkDeviceWaitIdle = (PFN_vkDeviceWaitIdle)load(context, "vkDeviceWaitIdle");
vkEndCommandBuffer = (PFN_vkEndCommandBuffer)load(context, "vkEndCommandBuffer");
vkFlushMappedMemoryRanges = (PFN_vkFlushMappedMemoryRanges)load(context, "vkFlushMappedMemoryRanges");
vkFreeCommandBuffers = (PFN_vkFreeCommandBuffers)load(context, "vkFreeCommandBuffers");
vkFreeDescriptorSets = (PFN_vkFreeDescriptorSets)load(context, "vkFreeDescriptorSets");
vkFreeMemory = (PFN_vkFreeMemory)load(context, "vkFreeMemory");
vkGetBufferMemoryRequirements = (PFN_vkGetBufferMemoryRequirements)load(context, "vkGetBufferMemoryRequirements");
vkGetDeviceMemoryCommitment = (PFN_vkGetDeviceMemoryCommitment)load(context, "vkGetDeviceMemoryCommitment");
vkGetDeviceQueue = (PFN_vkGetDeviceQueue)load(context, "vkGetDeviceQueue");
vkGetEventStatus = (PFN_vkGetEventStatus)load(context, "vkGetEventStatus");
vkGetFenceStatus = (PFN_vkGetFenceStatus)load(context, "vkGetFenceStatus");
vkGetImageMemoryRequirements = (PFN_vkGetImageMemoryRequirements)load(context, "vkGetImageMemoryRequirements");
vkGetImageSparseMemoryRequirements = (PFN_vkGetImageSparseMemoryRequirements)load(context, "vkGetImageSparseMemoryRequirements");
vkGetImageSubresourceLayout = (PFN_vkGetImageSubresourceLayout)load(context, "vkGetImageSubresourceLayout");
vkGetPipelineCacheData = (PFN_vkGetPipelineCacheData)load(context, "vkGetPipelineCacheData");
vkGetQueryPoolResults = (PFN_vkGetQueryPoolResults)load(context, "vkGetQueryPoolResults");
vkGetRenderAreaGranularity = (PFN_vkGetRenderAreaGranularity)load(context, "vkGetRenderAreaGranularity");
vkInvalidateMappedMemoryRanges = (PFN_vkInvalidateMappedMemoryRanges)load(context, "vkInvalidateMappedMemoryRanges");
vkMapMemory = (PFN_vkMapMemory)load(context, "vkMapMemory");
vkMergePipelineCaches = (PFN_vkMergePipelineCaches)load(context, "vkMergePipelineCaches");
vkQueueBindSparse = (PFN_vkQueueBindSparse)load(context, "vkQueueBindSparse");
vkQueueSubmit = (PFN_vkQueueSubmit)load(context, "vkQueueSubmit");
vkQueueWaitIdle = (PFN_vkQueueWaitIdle)load(context, "vkQueueWaitIdle");
vkResetCommandBuffer = (PFN_vkResetCommandBuffer)load(context, "vkResetCommandBuffer");
vkResetCommandPool = (PFN_vkResetCommandPool)load(context, "vkResetCommandPool");
vkResetDescriptorPool = (PFN_vkResetDescriptorPool)load(context, "vkResetDescriptorPool");
vkResetEvent = (PFN_vkResetEvent)load(context, "vkResetEvent");
vkResetFences = (PFN_vkResetFences)load(context, "vkResetFences");
vkSetEvent = (PFN_vkSetEvent)load(context, "vkSetEvent");
vkUnmapMemory = (PFN_vkUnmapMemory)load(context, "vkUnmapMemory");
vkUpdateDescriptorSets = (PFN_vkUpdateDescriptorSets)load(context, "vkUpdateDescriptorSets");
vkWaitForFences = (PFN_vkWaitForFences)load(context, "vkWaitForFences");
#endif /* defined(VK_VERSION_1_0) */
#if defined(VK_KHR_swapchain)
vkAcquireNextImageKHR = (PFN_vkAcquireNextImageKHR)load(context, "vkAcquireNextImageKHR");
vkCreateSwapchainKHR = (PFN_vkCreateSwapchainKHR)load(context, "vkCreateSwapchainKHR");
vkDestroySwapchainKHR = (PFN_vkDestroySwapchainKHR)load(context, "vkDestroySwapchainKHR");
vkGetSwapchainImagesKHR = (PFN_vkGetSwapchainImagesKHR)load(context, "vkGetSwapchainImagesKHR");
vkQueuePresentKHR = (PFN_vkQueuePresentKHR)load(context, "vkQueuePresentKHR");
#endif /* defined(VK_KHR_swapchain) */
DebugLog("Vulkan loader : device functions loaded");
}
VulkanLoader::~VulkanLoader()
{
#if defined(_WIN32)
FreeLibrary((HMODULE)p_module);
#else
dlclose(p_module);
#endif
p_module = nullptr;
DebugLog("Vulkan loader : libvulkan unloaded");
}
}
#if defined(VK_VERSION_1_0)
PFN_vkAllocateCommandBuffers vkAllocateCommandBuffers;
PFN_vkAllocateDescriptorSets vkAllocateDescriptorSets;
PFN_vkAllocateMemory vkAllocateMemory;
PFN_vkBeginCommandBuffer vkBeginCommandBuffer;
PFN_vkBindBufferMemory vkBindBufferMemory;
PFN_vkBindImageMemory vkBindImageMemory;
PFN_vkCmdBeginQuery vkCmdBeginQuery;
PFN_vkCmdBeginRenderPass vkCmdBeginRenderPass;
PFN_vkCmdBindDescriptorSets vkCmdBindDescriptorSets;
PFN_vkCmdBindIndexBuffer vkCmdBindIndexBuffer;
PFN_vkCmdBindPipeline vkCmdBindPipeline;
PFN_vkCmdBindVertexBuffers vkCmdBindVertexBuffers;
PFN_vkCmdBlitImage vkCmdBlitImage;
PFN_vkCmdClearAttachments vkCmdClearAttachments;
PFN_vkCmdClearColorImage vkCmdClearColorImage;
PFN_vkCmdClearDepthStencilImage vkCmdClearDepthStencilImage;
PFN_vkCmdCopyBuffer vkCmdCopyBuffer;
PFN_vkCmdCopyBufferToImage vkCmdCopyBufferToImage;
PFN_vkCmdCopyImage vkCmdCopyImage;
PFN_vkCmdCopyImageToBuffer vkCmdCopyImageToBuffer;
PFN_vkCmdCopyQueryPoolResults vkCmdCopyQueryPoolResults;
PFN_vkCmdDispatch vkCmdDispatch;
PFN_vkCmdDispatchIndirect vkCmdDispatchIndirect;
PFN_vkCmdDraw vkCmdDraw;
PFN_vkCmdDrawIndexed vkCmdDrawIndexed;
PFN_vkCmdDrawIndexedIndirect vkCmdDrawIndexedIndirect;
PFN_vkCmdDrawIndirect vkCmdDrawIndirect;
PFN_vkCmdEndQuery vkCmdEndQuery;
PFN_vkCmdEndRenderPass vkCmdEndRenderPass;
PFN_vkCmdExecuteCommands vkCmdExecuteCommands;
PFN_vkCmdFillBuffer vkCmdFillBuffer;
PFN_vkCmdNextSubpass vkCmdNextSubpass;
PFN_vkCmdPipelineBarrier vkCmdPipelineBarrier;
PFN_vkCmdPushConstants vkCmdPushConstants;
PFN_vkCmdResetEvent vkCmdResetEvent;
PFN_vkCmdResetQueryPool vkCmdResetQueryPool;
PFN_vkCmdResolveImage vkCmdResolveImage;
PFN_vkCmdSetBlendConstants vkCmdSetBlendConstants;
PFN_vkCmdSetDepthBias vkCmdSetDepthBias;
PFN_vkCmdSetDepthBounds vkCmdSetDepthBounds;
PFN_vkCmdSetEvent vkCmdSetEvent;
PFN_vkCmdSetLineWidth vkCmdSetLineWidth;
PFN_vkCmdSetScissor vkCmdSetScissor;
PFN_vkCmdSetStencilCompareMask vkCmdSetStencilCompareMask;
PFN_vkCmdSetStencilReference vkCmdSetStencilReference;
PFN_vkCmdSetStencilWriteMask vkCmdSetStencilWriteMask;
PFN_vkCmdSetViewport vkCmdSetViewport;
PFN_vkCmdUpdateBuffer vkCmdUpdateBuffer;
PFN_vkCmdWaitEvents vkCmdWaitEvents;
PFN_vkCmdWriteTimestamp vkCmdWriteTimestamp;
PFN_vkCreateBuffer vkCreateBuffer;
PFN_vkCreateBufferView vkCreateBufferView;
PFN_vkCreateCommandPool vkCreateCommandPool;
PFN_vkCreateComputePipelines vkCreateComputePipelines;
PFN_vkCreateDescriptorPool vkCreateDescriptorPool;
PFN_vkCreateDescriptorSetLayout vkCreateDescriptorSetLayout;
PFN_vkCreateDevice vkCreateDevice;
PFN_vkCreateEvent vkCreateEvent;
PFN_vkCreateFence vkCreateFence;
PFN_vkCreateFramebuffer vkCreateFramebuffer;
PFN_vkCreateGraphicsPipelines vkCreateGraphicsPipelines;
PFN_vkCreateImage vkCreateImage;
PFN_vkCreateImageView vkCreateImageView;
PFN_vkCreateInstance vkCreateInstance;
PFN_vkCreatePipelineCache vkCreatePipelineCache;
PFN_vkCreatePipelineLayout vkCreatePipelineLayout;
PFN_vkCreateQueryPool vkCreateQueryPool;
PFN_vkCreateRenderPass vkCreateRenderPass;
PFN_vkCreateSampler vkCreateSampler;
PFN_vkCreateSemaphore vkCreateSemaphore;
PFN_vkCreateShaderModule vkCreateShaderModule;
PFN_vkDestroyBuffer vkDestroyBuffer;
PFN_vkDestroyBufferView vkDestroyBufferView;
PFN_vkDestroyCommandPool vkDestroyCommandPool;
PFN_vkDestroyDescriptorPool vkDestroyDescriptorPool;
PFN_vkDestroyDescriptorSetLayout vkDestroyDescriptorSetLayout;
PFN_vkDestroyDevice vkDestroyDevice;
PFN_vkDestroyEvent vkDestroyEvent;
PFN_vkDestroyFence vkDestroyFence;
PFN_vkDestroyFramebuffer vkDestroyFramebuffer;
PFN_vkDestroyImage vkDestroyImage;
PFN_vkDestroyImageView vkDestroyImageView;
PFN_vkDestroyInstance vkDestroyInstance;
PFN_vkDestroyPipeline vkDestroyPipeline;
PFN_vkDestroyPipelineCache vkDestroyPipelineCache;
PFN_vkDestroyPipelineLayout vkDestroyPipelineLayout;
PFN_vkDestroyQueryPool vkDestroyQueryPool;
PFN_vkDestroyRenderPass vkDestroyRenderPass;
PFN_vkDestroySampler vkDestroySampler;
PFN_vkDestroySemaphore vkDestroySemaphore;
PFN_vkDestroyShaderModule vkDestroyShaderModule;
PFN_vkDeviceWaitIdle vkDeviceWaitIdle;
PFN_vkEndCommandBuffer vkEndCommandBuffer;
PFN_vkEnumerateDeviceExtensionProperties vkEnumerateDeviceExtensionProperties;
PFN_vkEnumerateDeviceLayerProperties vkEnumerateDeviceLayerProperties;
PFN_vkEnumerateInstanceExtensionProperties vkEnumerateInstanceExtensionProperties;
PFN_vkEnumerateInstanceLayerProperties vkEnumerateInstanceLayerProperties;
PFN_vkEnumeratePhysicalDevices vkEnumeratePhysicalDevices;
PFN_vkFlushMappedMemoryRanges vkFlushMappedMemoryRanges;
PFN_vkFreeCommandBuffers vkFreeCommandBuffers;
PFN_vkFreeDescriptorSets vkFreeDescriptorSets;
PFN_vkFreeMemory vkFreeMemory;
PFN_vkGetBufferMemoryRequirements vkGetBufferMemoryRequirements;
PFN_vkGetDeviceMemoryCommitment vkGetDeviceMemoryCommitment;
PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr;
PFN_vkGetDeviceQueue vkGetDeviceQueue;
PFN_vkGetEventStatus vkGetEventStatus;
PFN_vkGetFenceStatus vkGetFenceStatus;
PFN_vkGetImageMemoryRequirements vkGetImageMemoryRequirements;
PFN_vkGetImageSparseMemoryRequirements vkGetImageSparseMemoryRequirements;
PFN_vkGetImageSubresourceLayout vkGetImageSubresourceLayout;
PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr;
PFN_vkGetPhysicalDeviceFeatures vkGetPhysicalDeviceFeatures;
PFN_vkGetPhysicalDeviceFormatProperties vkGetPhysicalDeviceFormatProperties;
PFN_vkGetPhysicalDeviceImageFormatProperties vkGetPhysicalDeviceImageFormatProperties;
PFN_vkGetPhysicalDeviceMemoryProperties vkGetPhysicalDeviceMemoryProperties;
PFN_vkGetPhysicalDeviceProperties vkGetPhysicalDeviceProperties;
PFN_vkGetPhysicalDeviceQueueFamilyProperties vkGetPhysicalDeviceQueueFamilyProperties;
PFN_vkGetPhysicalDeviceSparseImageFormatProperties vkGetPhysicalDeviceSparseImageFormatProperties;
PFN_vkGetPipelineCacheData vkGetPipelineCacheData;
PFN_vkGetQueryPoolResults vkGetQueryPoolResults;
PFN_vkGetRenderAreaGranularity vkGetRenderAreaGranularity;
PFN_vkInvalidateMappedMemoryRanges vkInvalidateMappedMemoryRanges;
PFN_vkMapMemory vkMapMemory;
PFN_vkMergePipelineCaches vkMergePipelineCaches;
PFN_vkQueueBindSparse vkQueueBindSparse;
PFN_vkQueueSubmit vkQueueSubmit;
PFN_vkQueueWaitIdle vkQueueWaitIdle;
PFN_vkResetCommandBuffer vkResetCommandBuffer;
PFN_vkResetCommandPool vkResetCommandPool;
PFN_vkResetDescriptorPool vkResetDescriptorPool;
PFN_vkResetEvent vkResetEvent;
PFN_vkResetFences vkResetFences;
PFN_vkSetEvent vkSetEvent;
PFN_vkUnmapMemory vkUnmapMemory;
PFN_vkUpdateDescriptorSets vkUpdateDescriptorSets;
PFN_vkWaitForFences vkWaitForFences;
#endif /* defined(VK_VERSION_1_0) */
#if defined(VK_KHR_swapchain)
PFN_vkAcquireNextImageKHR vkAcquireNextImageKHR;
PFN_vkCreateSwapchainKHR vkCreateSwapchainKHR;
PFN_vkDestroySwapchainKHR vkDestroySwapchainKHR;
PFN_vkGetSwapchainImagesKHR vkGetSwapchainImagesKHR;
PFN_vkQueuePresentKHR vkQueuePresentKHR;
#endif /* defined(VK_KHR_swapchain) */
#if defined(VK_KHR_surface)
PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR;
PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vkGetPhysicalDeviceSurfaceCapabilitiesKHR;
PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vkGetPhysicalDeviceSurfaceFormatsKHR;
PFN_vkGetPhysicalDeviceSurfacePresentModesKHR vkGetPhysicalDeviceSurfacePresentModesKHR;
PFN_vkGetPhysicalDeviceSurfaceSupportKHR vkGetPhysicalDeviceSurfaceSupportKHR;
#endif /* defined(VK_KHR_surface) */

View File

@@ -0,0 +1,42 @@
#ifndef __MLX_VULKAN_LOADER__
#define __MLX_VULKAN_LOADER__
#ifdef _WIN32
typedef const char* LPCSTR;
typedef struct HINSTANCE__* HINSTANCE;
typedef HINSTANCE HMODULE;
#if defined(_MINWINDEF_)
/* minwindef.h defines FARPROC, and attempting to redefine it may conflict with -Wstrict-prototypes */
#elif defined(_WIN64)
typedef __int64 (__stdcall* FARPROC)(void);
#else
typedef int (__stdcall* FARPROC)(void);
#endif
#else
#include <dlfcn.h>
#endif
namespace mlx
{
class VulkanLoader
{
public:
VulkanLoader();
void LoadInstance(VkInstance instance);
~VulkanLoader();
private:
void LoadGlobalFunctions(void* context, PFN_vkVoidFunction (*load)(void*, const char*)) noexcept;
void LoadInstanceFunctions(void* context, PFN_vkVoidFunction (*load)(void*, const char*)) noexcept;
void LoadDeviceFunctions(void* context, PFN_vkVoidFunction (*load)(void*, const char*)) noexcept;
private:
#ifdef _WIN32
HMODULE p_module = nullptr;
#else
Handle p_module = nullptr;
#endif
};
}
#endif