mirror of
https://github.com/seekrs/MacroLibX.git
synced 2026-01-11 22:53:34 +00:00
big refactoring ! ci skip
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
31
runtime/Sources/Graphics/Mesh.cpp
git.filemode.normal_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
19
runtime/Sources/Graphics/Scene.cpp
git.filemode.normal_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
44
runtime/Sources/Graphics/Sprite.cpp
git.filemode.normal_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;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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
175
runtime/Sources/Renderer/Buffer.cpp
git.filemode.normal_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();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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, ©_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, ®ion);
|
||||
|
||||
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, ®ion);
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
@@ -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
141
runtime/Sources/Renderer/Descriptor.cpp
git.filemode.normal_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 = ℑ
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
113
runtime/Sources/Renderer/Image.cpp
git.filemode.normal_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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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
159
runtime/Sources/Renderer/Memory.cpp
git.filemode.normal_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");
|
||||
}
|
||||
}
|
||||
164
runtime/Sources/Renderer/Pipelines/Graphics.cpp
git.filemode.normal_file
164
runtime/Sources/Renderer/Pipelines/Graphics.cpp
git.filemode.normal_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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
83
runtime/Sources/Renderer/Pipelines/Shader.cpp
git.filemode.normal_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;
|
||||
}
|
||||
}
|
||||
@@ -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
78
runtime/Sources/Renderer/RenderCore.cpp
git.filemode.normal_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");
|
||||
}
|
||||
}
|
||||
112
runtime/Sources/Renderer/RenderPasses/2DPass.cpp
git.filemode.normal_file
112
runtime/Sources/Renderer/RenderPasses/2DPass.cpp
git.filemode.normal_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();
|
||||
}
|
||||
}
|
||||
76
runtime/Sources/Renderer/RenderPasses/FinalPass.cpp
git.filemode.normal_file
76
runtime/Sources/Renderer/RenderPasses/FinalPass.cpp
git.filemode.normal_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();
|
||||
}
|
||||
}
|
||||
45
runtime/Sources/Renderer/RenderPasses/Passes.cpp
git.filemode.normal_file
45
runtime/Sources/Renderer/RenderPasses/Passes.cpp
git.filemode.normal_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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
@@ -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
23
runtime/Sources/Renderer/SceneRenderer.cpp
git.filemode.normal_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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
416
runtime/Sources/Renderer/Vulkan/VulkanLoader.cpp
git.filemode.normal_file
416
runtime/Sources/Renderer/Vulkan/VulkanLoader.cpp
git.filemode.normal_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) */
|
||||
42
runtime/Sources/Renderer/Vulkan/VulkanLoader.h
git.filemode.normal_file
42
runtime/Sources/Renderer/Vulkan/VulkanLoader.h
git.filemode.normal_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
|
||||
Reference in New Issue
Block a user