adding debug vulkan resources names

This commit is contained in:
2024-09-21 12:18:42 +02:00
parent 2e08c37624
commit 904b6d31ac
27 changed files with 306 additions and 104 deletions

View File

@@ -8,7 +8,7 @@
Error("invalid window ptr (NULL)"); \
return; \
} \
else if(std::find_if(m_graphics.begin(), m_graphics.end(), [win](const std::unique_ptr<GraphicsSupport>& gs){ return *static_cast<int*>(win) == gs->GetID(); }) != m_graphics.end()) \
else if(std::find_if(m_graphics.begin(), m_graphics.end(), [win](const std::unique_ptr<GraphicsSupport>& gs){ return *static_cast<int*>(win) == gs->GetID(); }) == m_graphics.end()) \
{ \
Error("invalid window ptr"); \
return; \

View File

@@ -39,10 +39,10 @@ namespace mlx
{
Sprite& new_sprite = p_scene->CreateSprite(texture);
new_sprite.SetPosition(Vec3f{ static_cast<float>(x), static_cast<float>(y), static_cast<float>(m_current_depth) });
m_current_depth++;
}
else
sprite->SetPosition(Vec3f{ static_cast<float>(x), static_cast<float>(y), static_cast<float>(m_current_depth) });
m_current_depth++;
}
void GraphicsSupport::LoadFont(const std::filesystem::path& filepath, float scale)

View File

@@ -20,12 +20,12 @@ namespace mlx
{
CPUBuffer vb(vertices.size() * sizeof(Vertex));
std::memcpy(vb.GetData(), vertices.data(), vb.GetSize());
vbo.Init(vb.GetSize());
vbo.Init(vb.GetSize(), 0, "mlx_mesh");
vbo.SetData(std::move(vb));
CPUBuffer ib(indices.size() * sizeof(std::uint32_t));
std::memcpy(ib.GetData(), indices.data(), ib.GetSize());
ibo.Init(ib.GetSize());
ibo.Init(ib.GetSize(), 0, "mlx_mesh");
ibo.SetData(std::move(ib));
triangle_count = vertices.size() / 3;

View File

@@ -12,7 +12,7 @@ namespace mlx
public:
GPUBuffer() = default;
void Init(BufferType type, VkDeviceSize size, VkBufferUsageFlags usage, CPUBuffer data);
void Init(BufferType type, VkDeviceSize size, VkBufferUsageFlags usage, CPUBuffer data, std::string_view debug_name);
void Destroy() noexcept;
bool CopyFrom(const GPUBuffer& buffer) noexcept;
@@ -33,6 +33,9 @@ namespace mlx
void PushToGPU() noexcept;
protected:
#ifdef DEBUG
std::string m_debug_name;
#endif
VkBuffer m_buffer = VK_NULL_HANDLE;
VmaAllocation m_allocation;
VkDeviceSize m_offset = 0;
@@ -40,7 +43,7 @@ namespace mlx
void* p_map = nullptr;
private:
void CreateBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VmaAllocationCreateInfo alloc_info);
void CreateBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VmaAllocationCreateInfo alloc_info, std::string_view debug_name);
private:
VkBufferUsageFlags m_usage = 0;
@@ -49,7 +52,7 @@ namespace mlx
class VertexBuffer : public GPUBuffer
{
public:
inline void Init(std::uint32_t size, VkBufferUsageFlags additional_flags = 0) { GPUBuffer::Init(BufferType::LowDynamic, size, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | additional_flags, {}); }
inline void Init(std::uint32_t size, VkBufferUsageFlags additional_flags, std::string_view debug_name) { GPUBuffer::Init(BufferType::LowDynamic, size, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | additional_flags, {}, std::move(debug_name)); }
void SetData(CPUBuffer data);
inline void Bind(VkCommandBuffer cmd) const noexcept { VkDeviceSize offset = 0; RenderCore::Get().vkCmdBindVertexBuffers(cmd, 0, 1, &m_buffer, &offset); }
};
@@ -57,7 +60,7 @@ namespace mlx
class IndexBuffer : public GPUBuffer
{
public:
inline void Init(std::uint32_t size, VkBufferUsageFlags additional_flags = 0) { GPUBuffer::Init(BufferType::LowDynamic, size, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | additional_flags, {}); }
inline void Init(std::uint32_t size, VkBufferUsageFlags additional_flags, std::string_view debug_name) { GPUBuffer::Init(BufferType::LowDynamic, size, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | additional_flags, {}, std::move(debug_name)); }
void SetData(CPUBuffer data);
inline void Bind(VkCommandBuffer cmd) const noexcept { RenderCore::Get().vkCmdBindIndexBuffer(cmd, m_buffer, 0, VK_INDEX_TYPE_UINT32); }
};
@@ -65,7 +68,7 @@ namespace mlx
class UniformBuffer
{
public:
void Init(std::uint32_t size);
void Init(std::uint32_t size, std::string_view debug_name);
void SetData(CPUBuffer data, std::size_t frame_index);
void Destroy() noexcept;

View File

@@ -14,16 +14,19 @@ namespace mlx
public:
Image() = default;
inline void Init(VkImage image, VkFormat format, std::uint32_t width, std::uint32_t height, VkImageLayout layout = VK_IMAGE_LAYOUT_UNDEFINED) noexcept
inline void Init(VkImage image, VkFormat format, std::uint32_t width, std::uint32_t height, VkImageLayout layout, std::string_view debug_name) noexcept
{
m_image = image;
m_format = format;
m_width = width;
m_height = height;
m_layout = layout;
#ifdef DEBUG
m_debug_name = std::move(debug_name);
#endif
}
void Init(ImageType type, std::uint32_t width, std::uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, bool is_multisampled = false);
void Init(ImageType type, std::uint32_t width, std::uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, bool is_multisampled, std::string_view debug_name);
void CreateImageView(VkImageViewType type, VkImageAspectFlags aspectFlags, int layer_count = 1) noexcept;
void CreateSampler() noexcept;
void TransitionLayout(VkImageLayout new_layout, VkCommandBuffer cmd = VK_NULL_HANDLE);
@@ -48,6 +51,9 @@ namespace mlx
virtual ~Image() = default;
protected:
#ifdef DEBUG
std::string m_debug_name;
#endif
VmaAllocation m_allocation;
VkImage m_image = VK_NULL_HANDLE;
VkImageView m_image_view = VK_NULL_HANDLE;
@@ -65,11 +71,12 @@ namespace mlx
{
public:
DepthImage() = default;
inline void Init(std::uint32_t width, std::uint32_t height, bool is_multisampled = false)
inline void Init(std::uint32_t width, std::uint32_t height, bool is_multisampled, std::string_view debug_name)
{
MLX_PROFILE_FUNCTION();
std::vector<VkFormat> candidates = { VK_FORMAT_D32_SFLOAT, VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT };
VkFormat format = kvfFindSupportFormatInCandidates(RenderCore::Get().GetDevice(), candidates.data(), candidates.size(), VK_IMAGE_TILING_OPTIMAL, VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT);
Image::Init(ImageType::Depth, width, height, format, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, is_multisampled);
Image::Init(ImageType::Depth, width, height, format, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, is_multisampled, std::move(debug_name));
Image::CreateImageView(VK_IMAGE_VIEW_TYPE_2D, VK_IMAGE_ASPECT_DEPTH_BIT);
Image::TransitionLayout(VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
}
@@ -80,33 +87,12 @@ namespace mlx
{
public:
Texture() = default;
Texture(CPUBuffer pixels, std::uint32_t width, std::uint32_t height, VkFormat format = VK_FORMAT_R8G8B8A8_SRGB, bool is_multisampled = false)
Texture(CPUBuffer pixels, std::uint32_t width, std::uint32_t height, VkFormat format, bool is_multisampled, std::string_view debug_name)
{
Init(std::move(pixels), width, height, format, is_multisampled);
Init(std::move(pixels), width, height, format, is_multisampled, std::move(debug_name));
}
inline void Init(CPUBuffer pixels, std::uint32_t width, std::uint32_t height, VkFormat format = VK_FORMAT_R8G8B8A8_SRGB, bool is_multisampled = false)
{
Image::Init(ImageType::Color, width, height, format, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, is_multisampled);
Image::CreateImageView(VK_IMAGE_VIEW_TYPE_2D, VK_IMAGE_ASPECT_COLOR_BIT);
Image::CreateSampler();
if(pixels)
{
GPUBuffer staging_buffer;
std::size_t size = width * height * kvfFormatSize(format);
staging_buffer.Init(BufferType::Staging, size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, pixels);
VkCommandBuffer cmd = kvfCreateCommandBuffer(RenderCore::Get().GetDevice());
kvfBeginCommandBuffer(cmd, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT);
TransitionLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, cmd);
kvfCopyBufferToImage(cmd, Image::Get(), staging_buffer.Get(), staging_buffer.GetOffset(), VK_IMAGE_ASPECT_COLOR_BIT, { width, height, 1 });
RenderCore::Get().vkEndCommandBuffer(cmd);
VkFence fence = kvfCreateFence(RenderCore::Get().GetDevice());
kvfSubmitSingleTimeCommandBuffer(RenderCore::Get().GetDevice(), cmd, KVF_GRAPHICS_QUEUE, fence);
kvfDestroyFence(RenderCore::Get().GetDevice(), fence);
staging_buffer.Destroy();
}
TransitionLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
}
void Init(CPUBuffer pixels, std::uint32_t width, std::uint32_t height, VkFormat format, bool is_multisampled, std::string_view debug_name);
void SetPixel(int x, int y, std::uint32_t color) noexcept;
int GetPixel(int x, int y) noexcept;

View File

@@ -12,10 +12,10 @@ namespace mlx
void Destroy() noexcept;
VmaAllocation CreateBuffer(const VkBufferCreateInfo* binfo, const VmaAllocationCreateInfo* vinfo, VkBuffer& buffer, const char* name = nullptr) noexcept;
void DestroyBuffer(VmaAllocation allocation, VkBuffer buffer) noexcept;
void DestroyBuffer(VmaAllocation allocation, VkBuffer buffer, const char* name) noexcept;
VmaAllocation CreateImage(const VkImageCreateInfo* iminfo, const VmaAllocationCreateInfo* vinfo, VkImage& image, const char* name = nullptr) noexcept;
void DestroyImage(VmaAllocation allocation, VkImage image) noexcept;
void DestroyImage(VmaAllocation allocation, VkImage image, const char* name) noexcept;
void MapMemory(VmaAllocation allocation, void** data) noexcept;
void UnmapMemory(VmaAllocation allocation) noexcept;

View File

@@ -31,6 +31,12 @@ namespace mlx
#undef MLX_VULKAN_INSTANCE_FUNCTION
#undef MLX_VULKAN_DEVICE_FUNCTION
#if defined(DEBUG) && defined(VK_EXT_debug_utils)
inline static constexpr bool HAS_DEBUG_UTILS_FUNCTIONS = true;
#else
inline static constexpr bool HAS_DEBUG_UTILS_FUNCTIONS = false;
#endif
~RenderCore();
private:

View File

@@ -20,6 +20,12 @@
MLX_VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceMemoryProperties)
MLX_VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceProperties)
MLX_VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceQueueFamilyProperties)
#ifdef DEBUG
#ifdef VK_EXT_debug_utils
MLX_VULKAN_INSTANCE_FUNCTION(vkSetDebugUtilsObjectNameEXT)
//MLX_VULKAN_INSTANCE_FUNCTION(vkSetDebugUtilsObjectTagEXT)
#endif
#endif
#endif
#ifdef MLX_VULKAN_DEVICE_FUNCTION

View File

@@ -49,7 +49,7 @@ namespace mlx
{
MLX_PROFILE_FUNCTION();
Texture* texture;
try { texture = new Texture({}, w, h); }
try { texture = new Texture({}, w, h, VK_FORMAT_R8G8B8A8_SRGB, false, "mlx_user_image"); }
catch(...) { return NULL; }
m_image_registry.RegisterTexture(texture);
return texture;

View File

@@ -6,12 +6,14 @@ namespace mlx
{
void Mesh::Draw(VkCommandBuffer cmd, std::size_t& drawcalls, std::size_t& polygondrawn) const noexcept
{
MLX_PROFILE_FUNCTION();
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
{
MLX_PROFILE_FUNCTION();
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);
@@ -22,6 +24,7 @@ namespace mlx
Mesh::~Mesh()
{
MLX_PROFILE_FUNCTION();
for(auto& mesh : m_sub_meshes)
{
mesh.vbo.Destroy();

View File

@@ -1,32 +0,0 @@
#include <PreCompiled.h>
#include <Graphics/PutPixelManager.h>
#include <Renderer/Renderer.h>
namespace mlx
{
NonOwningPtr<Texture> PutPixelManager::DrawPixel(int x, int y, std::uint64_t z, std::uint32_t color)
{
Verify((bool)p_renderer, "invalid renderer pointer");
auto it = m_textures.find(z);
if(it == m_textures.end())
{
VkExtent2D swapchain_extent = kvfGetSwapchainImagesSize(p_renderer->GetSwapchain());
Texture& texture = m_textures[z] = Texture({}, swapchain_extent.width, swapchain_extent.height);
texture.SetPixel(x, y, color);
return &texture;
}
it->second.SetPixel(x, y, color);
return nullptr;
}
void PutPixelManager::ResetRenderData()
{
m_textures.clear();
}
PutPixelManager::~PutPixelManager()
{
ResetRenderData();
}
}

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

@@ -0,0 +1,31 @@
#include <PreCompiled.h>
#include <Graphics/PutPixelManager.h>
#include <Renderer/Renderer.h>
namespace mlx
{
NonOwningPtr<Texture> PutPixelManager::DrawPixel(int x, int y, std::uint64_t z, std::uint32_t color)
{
Verify((bool)p_renderer, "invalid renderer pointer");
VkExtent2D swapchain_extent = kvfGetSwapchainImagesSize(p_renderer->GetSwapchain());
#ifdef DEBUG
auto res = m_textures.try_emplace(z, CPUBuffer{}, swapchain_extent.width, swapchain_extent.height, VK_FORMAT_R8G8B8A8_SRGB, false, "mlx_put_pixel_layer_" + std::to_string(z));
#else
auto res = m_textures.try_emplace(z, CPUBuffer{}, swapchain_extent.width, swapchain_extent.height, VK_FORMAT_R8G8B8A8_SRGB, false, {});
#endif
res.first->second.SetPixel(x, y, color);
return (res.second ? &res.first->second : nullptr);
}
void PutPixelManager::ResetRenderData()
{
m_textures.clear();
}
PutPixelManager::~PutPixelManager()
{
ResetRenderData();
}
}

View File

@@ -8,12 +8,14 @@ namespace mlx
Scene::Scene(SceneDescriptor desc)
: m_descriptor(std::move(desc))
{
MLX_PROFILE_FUNCTION();
Verify((bool)m_descriptor.renderer, "invalid renderer");
m_depth.Init(m_descriptor.renderer->GetSwapchainImages().back().GetWidth(), m_descriptor.renderer->GetSwapchainImages().back().GetHeight());
m_depth.Init(m_descriptor.renderer->GetSwapchainImages().back().GetWidth(), m_descriptor.renderer->GetSwapchainImages().back().GetHeight(), false, "mlx_scene_depth");
}
Sprite& Scene::CreateSprite(NonOwningPtr<Texture> texture) noexcept
{
MLX_PROFILE_FUNCTION();
std::shared_ptr<Sprite> sprite = std::make_shared<Sprite>(texture);
m_sprites.push_back(sprite);
return *sprite;
@@ -21,6 +23,7 @@ namespace mlx
NonOwningPtr<Sprite> Scene::GetSpriteFromTextureAndPosition(NonOwningPtr<Texture> texture, const Vec2f& position) const
{
MLX_PROFILE_FUNCTION();
auto it = std::find_if(m_sprites.begin(), m_sprites.end(), [texture, position](std::shared_ptr<Sprite> sprite)
{
return sprite->GetPosition().x == position.x && sprite->GetPosition().y == position.y && sprite->GetTexture() == texture;
@@ -30,6 +33,7 @@ namespace mlx
void Scene::TryEraseSpriteFromTexture(NonOwningPtr<Texture> texture)
{
MLX_PROFILE_FUNCTION();
auto it = m_sprites.begin();
do
{

View File

@@ -7,6 +7,7 @@ namespace mlx
{
std::shared_ptr<Mesh> CreateQuad(float x, float y, float width, float height)
{
MLX_PROFILE_FUNCTION();
std::vector<Vertex> data(4);
data[0].position = Vec4f(x, y, 0.0f, 1.0f);
@@ -37,6 +38,7 @@ namespace mlx
Sprite::Sprite(NonOwningPtr<Texture> texture)
{
MLX_PROFILE_FUNCTION();
Verify((bool)texture, "Sprite: invalid texture");
p_mesh = CreateQuad(0, 0, texture->GetWidth(), texture->GetHeight());
p_texture = texture;

View File

@@ -4,8 +4,9 @@
namespace mlx
{
void GPUBuffer::Init(BufferType type, VkDeviceSize size, VkBufferUsageFlags usage, CPUBuffer data)
void GPUBuffer::Init(BufferType type, VkDeviceSize size, VkBufferUsageFlags usage, CPUBuffer data, std::string_view debug_name)
{
MLX_PROFILE_FUNCTION();
VmaAllocationCreateInfo alloc_info{};
alloc_info.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT;
alloc_info.usage = VMA_MEMORY_USAGE_AUTO;
@@ -24,10 +25,7 @@ namespace mlx
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);
CreateBuffer(size, m_usage, alloc_info, std::move(debug_name));
if(!data.Empty())
{
@@ -38,21 +36,38 @@ namespace mlx
PushToGPU();
}
void GPUBuffer::CreateBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VmaAllocationCreateInfo alloc_info)
void GPUBuffer::CreateBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VmaAllocationCreateInfo alloc_info, std::string_view debug_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;
m_allocation = RenderCore::Get().GetAllocator().CreateBuffer(&bufferInfo, &alloc_info, m_buffer, nullptr);
#ifdef DEBUG
std::string alloc_name{ debug_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("_uniform_buffer");
else
alloc_name.append("_buffer");
m_allocation = RenderCore::Get().GetAllocator().CreateBuffer(&bufferInfo, &alloc_info, m_buffer, alloc_name.c_str());
m_debug_name = std::move(alloc_name);
#else
m_allocation = RenderCore::Get().GetAllocator().CreateBuffer(&bufferInfo, &alloc_info, m_buffer, nullptr);
#endif
if(alloc_info.flags != 0)
RenderCore::Get().GetAllocator().MapMemory(m_allocation, &p_map);
m_size = size;
}
bool GPUBuffer::CopyFrom(const GPUBuffer& 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");
@@ -77,12 +92,19 @@ namespace mlx
void GPUBuffer::PushToGPU() noexcept
{
MLX_PROFILE_FUNCTION();
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_size, new_buffer.m_usage, alloc_info);
#ifdef DEBUG
std::string new_name = m_debug_name + "_gpu";
new_buffer.CreateBuffer(m_size, new_buffer.m_usage, alloc_info, new_name);
#else
new_buffer.CreateBuffer(m_size, new_buffer.m_usage, alloc_info, {});
#endif
if(new_buffer.CopyFrom(*this))
Swap(new_buffer);
@@ -92,15 +114,21 @@ namespace mlx
void GPUBuffer::Destroy() noexcept
{
MLX_PROFILE_FUNCTION();
if(m_buffer == VK_NULL_HANDLE)
return;
RenderCore::Get().GetAllocator().UnmapMemory(m_allocation);
RenderCore::Get().GetAllocator().DestroyBuffer(m_allocation, m_buffer);
#ifdef DEBUG
RenderCore::Get().GetAllocator().DestroyBuffer(m_allocation, m_buffer, m_debug_name.c_str());
#else
RenderCore::Get().GetAllocator().DestroyBuffer(m_allocation, m_buffer, nullptr);
#endif
m_buffer = VK_NULL_HANDLE;
}
void GPUBuffer::Swap(GPUBuffer& buffer) noexcept
{
MLX_PROFILE_FUNCTION();
std::swap(m_buffer, buffer.m_buffer);
std::swap(m_allocation, buffer.m_allocation);
std::swap(m_size, buffer.m_size);
@@ -111,6 +139,7 @@ namespace mlx
void VertexBuffer::SetData(CPUBuffer data)
{
MLX_PROFILE_FUNCTION();
if(data.GetSize() > m_size)
{
Error("Vulkan : trying to store to much data in a vertex buffer (% bytes in % bytes)", data.GetSize(), m_size);
@@ -122,13 +151,18 @@ namespace mlx
return;
}
GPUBuffer staging;
staging.Init(BufferType::Staging, data.GetSize(), VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, data);
#ifdef DEBUG
staging.Init(BufferType::Staging, data.GetSize(), VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, data, m_debug_name);
#else
staging.Init(BufferType::Staging, data.GetSize(), VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, data, {});
#endif
CopyFrom(staging);
staging.Destroy();
}
void IndexBuffer::SetData(CPUBuffer data)
{
MLX_PROFILE_FUNCTION();
if(data.GetSize() > m_size)
{
Error("Vulkan : trying to store to much data in an index buffer (% bytes in % bytes)", data.GetSize(), m_size);
@@ -140,16 +174,25 @@ namespace mlx
return;
}
GPUBuffer staging;
staging.Init(BufferType::Staging, data.GetSize(), VK_BUFFER_USAGE_INDEX_BUFFER_BIT, data);
#ifdef DEBUG
staging.Init(BufferType::Staging, data.GetSize(), VK_BUFFER_USAGE_INDEX_BUFFER_BIT, data, m_debug_name);
#else
staging.Init(BufferType::Staging, data.GetSize(), VK_BUFFER_USAGE_INDEX_BUFFER_BIT, data, {});
#endif
CopyFrom(staging);
staging.Destroy();
}
void UniformBuffer::Init(std::uint32_t size)
void UniformBuffer::Init(std::uint32_t size, std::string_view debug_name)
{
MLX_PROFILE_FUNCTION();
for(int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++)
{
m_buffers[i].Init(BufferType::HighDynamic, size, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, {});
#ifdef DEBUG
m_buffers[i].Init(BufferType::HighDynamic, size, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, {}, std::string{ debug_name } + '_' + std::to_string(i));
#else
m_buffers[i].Init(BufferType::HighDynamic, size, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, {}, {});
#endif
m_maps[i] = m_buffers[i].GetMap();
if(m_maps[i] == nullptr)
FatalError("Vulkan : unable to map a uniform buffer");
@@ -158,6 +201,7 @@ namespace mlx
void UniformBuffer::SetData(CPUBuffer data, std::size_t frame_index)
{
MLX_PROFILE_FUNCTION();
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());
@@ -169,6 +213,7 @@ namespace mlx
void UniformBuffer::Destroy() noexcept
{
MLX_PROFILE_FUNCTION();
for(int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++)
m_buffers[i].Destroy();
}

View File

@@ -10,6 +10,7 @@ namespace mlx
{
void TransitionImageToCorrectLayout(Image& image, VkCommandBuffer cmd)
{
MLX_PROFILE_FUNCTION();
if(!image.IsInit())
return;
if(image.GetType() == ImageType::Color)
@@ -21,6 +22,7 @@ namespace mlx
DescriptorSet::DescriptorSet(const ShaderSetLayout& layout, VkDescriptorSetLayout vklayout, ShaderType shader_type)
: m_set_layout(vklayout)
{
MLX_PROFILE_FUNCTION();
for(auto& [binding, type] : layout.binds)
{
m_descriptors.emplace_back();
@@ -35,12 +37,14 @@ namespace mlx
DescriptorSet::DescriptorSet(VkDescriptorSetLayout layout, const std::vector<Descriptor>& descriptors)
: m_descriptors(descriptors), m_set_layout(layout)
{
MLX_PROFILE_FUNCTION();
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)
{
MLX_PROFILE_FUNCTION();
Verify(m_set[i] != VK_NULL_HANDLE, "invalid descriptor");
auto it = std::find_if(m_descriptors.begin(), m_descriptors.end(), [=](Descriptor descriptor)
{
@@ -61,6 +65,7 @@ namespace mlx
void DescriptorSet::SetStorageBuffer(std::size_t i, std::uint32_t binding, class GPUBuffer& buffer)
{
MLX_PROFILE_FUNCTION();
Verify(m_set[i] != VK_NULL_HANDLE, "invalid descriptor");
auto it = std::find_if(m_descriptors.begin(), m_descriptors.end(), [=](Descriptor descriptor)
{
@@ -81,6 +86,7 @@ namespace mlx
void DescriptorSet::SetUniformBuffer(std::size_t i, std::uint32_t binding, class GPUBuffer& buffer)
{
MLX_PROFILE_FUNCTION();
Verify(m_set[i] != VK_NULL_HANDLE, "invalid descriptor");
auto it = std::find_if(m_descriptors.begin(), m_descriptors.end(), [=](Descriptor descriptor)
{
@@ -101,6 +107,7 @@ namespace mlx
void DescriptorSet::Update(std::size_t i, VkCommandBuffer cmd) noexcept
{
MLX_PROFILE_FUNCTION();
Verify(m_set[i] != VK_NULL_HANDLE, "invalid descriptor");
std::vector<VkWriteDescriptorSet> writes;
std::vector<VkDescriptorBufferInfo> buffer_infos;
@@ -141,6 +148,7 @@ namespace mlx
void DescriptorSet::Reallocate() noexcept
{
MLX_PROFILE_FUNCTION();
for(std::size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++)
m_set[i] = kvfAllocateDescriptorSet(RenderCore::Get().GetDevice(), m_set_layout);
}

View File

@@ -15,14 +15,18 @@
namespace mlx
{
void Image::Init(ImageType type, std::uint32_t width, std::uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, bool is_multisampled)
void Image::Init(ImageType type, std::uint32_t width, std::uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, bool is_multisampled, std::string_view debug_name)
{
MLX_PROFILE_FUNCTION();
m_type = type;
m_width = width;
m_height = height;
m_format = format;
m_tiling = tiling;
m_is_multisampled = is_multisampled;
#ifdef DEBUG
m_debug_name = std::move(debug_name);
#endif
VmaAllocationCreateInfo alloc_info{};
alloc_info.usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE;
@@ -41,21 +45,39 @@ namespace mlx
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);
#ifdef DEBUG
m_allocation = RenderCore::Get().GetAllocator().CreateImage(&image_info, &alloc_info, m_image, m_debug_name.c_str());
#else
m_allocation = RenderCore::Get().GetAllocator().CreateImage(&image_info, &alloc_info, m_image, nullptr);
#endif
}
void Image::CreateImageView(VkImageViewType type, VkImageAspectFlags aspect_flags, int layer_count) noexcept
{
MLX_PROFILE_FUNCTION();
m_image_view = kvfCreateImageView(RenderCore::Get().GetDevice(), m_image, m_format, type, aspect_flags, layer_count);
#ifdef DEBUG
if constexpr(RenderCore::HAS_DEBUG_UTILS_FUNCTIONS)
{
VkDebugUtilsObjectNameInfoEXT name_info{};
name_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
name_info.objectType = VK_OBJECT_TYPE_IMAGE_VIEW;
name_info.objectHandle = reinterpret_cast<std::uint64_t>(m_image_view);
name_info.pObjectName = m_debug_name.c_str();
RenderCore::Get().vkSetDebugUtilsObjectNameEXT(RenderCore::Get().GetDevice(), &name_info);
}
#endif
}
void Image::CreateSampler() noexcept
{
MLX_PROFILE_FUNCTION();
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)
{
MLX_PROFILE_FUNCTION();
if(new_layout == m_layout)
return;
bool is_single_time_cmd_buffer = (cmd == VK_NULL_HANDLE);
@@ -74,6 +96,7 @@ namespace mlx
void Image::Clear(VkCommandBuffer cmd, Vec4f color)
{
MLX_PROFILE_FUNCTION();
VkImageSubresourceRange subresource_range{};
subresource_range.baseMipLevel = 0;
subresource_range.layerCount = 1;
@@ -100,6 +123,7 @@ namespace mlx
void Image::DestroySampler() noexcept
{
MLX_PROFILE_FUNCTION();
if(m_sampler != VK_NULL_HANDLE)
kvfDestroySampler(RenderCore::Get().GetDevice(), m_sampler);
m_sampler = VK_NULL_HANDLE;
@@ -107,6 +131,7 @@ namespace mlx
void Image::DestroyImageView() noexcept
{
MLX_PROFILE_FUNCTION();
if(m_image_view != VK_NULL_HANDLE)
kvfDestroyImageView(RenderCore::Get().GetDevice(), m_image_view);
m_image_view = VK_NULL_HANDLE;
@@ -114,14 +139,45 @@ namespace mlx
void Image::Destroy() noexcept
{
MLX_PROFILE_FUNCTION();
DestroySampler();
DestroyImageView();
if(m_image != VK_NULL_HANDLE)
RenderCore::Get().GetAllocator().DestroyImage(m_allocation, m_image);
{
#ifdef DEBUG
RenderCore::Get().GetAllocator().DestroyImage(m_allocation, m_image, m_debug_name.c_str());
#else
RenderCore::Get().GetAllocator().DestroyImage(m_allocation, m_image, nullptr);
#endif
}
m_image = VK_NULL_HANDLE;
}
void Texture::Init(CPUBuffer pixels, std::uint32_t width, std::uint32_t height, VkFormat format, bool is_multisampled, std::string_view debug_name)
{
MLX_PROFILE_FUNCTION();
Image::Init(ImageType::Color, width, height, format, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, is_multisampled, std::move(debug_name));
Image::CreateImageView(VK_IMAGE_VIEW_TYPE_2D, VK_IMAGE_ASPECT_COLOR_BIT);
Image::CreateSampler();
if(pixels)
{
GPUBuffer staging_buffer;
std::size_t size = width * height * kvfFormatSize(format);
staging_buffer.Init(BufferType::Staging, size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, std::move(pixels), debug_name);
VkCommandBuffer cmd = kvfCreateCommandBuffer(RenderCore::Get().GetDevice());
kvfBeginCommandBuffer(cmd, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT);
TransitionLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, cmd);
kvfCopyBufferToImage(cmd, Image::Get(), staging_buffer.Get(), staging_buffer.GetOffset(), VK_IMAGE_ASPECT_COLOR_BIT, { width, height, 1 });
RenderCore::Get().vkEndCommandBuffer(cmd);
VkFence fence = kvfCreateFence(RenderCore::Get().GetDevice());
kvfSubmitSingleTimeCommandBuffer(RenderCore::Get().GetDevice(), cmd, KVF_GRAPHICS_QUEUE, fence);
kvfDestroyFence(RenderCore::Get().GetDevice(), fence);
staging_buffer.Destroy();
}
TransitionLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
}
void Texture::SetPixel(int x, int y, std::uint32_t color) noexcept
{
MLX_PROFILE_FUNCTION();
@@ -150,6 +206,7 @@ namespace mlx
void Texture::Update(VkCommandBuffer cmd)
{
MLX_PROFILE_FUNCTION();
if(!m_has_been_modified)
return;
std::memcpy(m_staging_buffer->GetMap(), m_cpu_buffer.data(), m_cpu_buffer.size() * kvfFormatSize(m_format));
@@ -167,10 +224,12 @@ namespace mlx
MLX_PROFILE_FUNCTION();
if(m_staging_buffer.has_value())
return;
DebugLog("Texture : enabling CPU mapping");
#ifdef DEBUG
DebugLog("Texture : enabling CPU mapping for '%'", m_debug_name);
#endif
m_staging_buffer.emplace();
std::size_t size = m_width * m_height * kvfFormatSize(m_format);
m_staging_buffer->Init(BufferType::Staging, size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, {});
m_staging_buffer->Init(BufferType::Staging, size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, {}, m_debug_name);
VkImageLayout old_layout = m_layout;
VkCommandBuffer cmd = kvfCreateCommandBuffer(RenderCore::Get().GetDevice());
@@ -199,7 +258,7 @@ namespace mlx
}
if(stbi_is_hdr(filename.c_str()))
{
Error("Texture : unsupported image format %", file);
Error("Texture : unsupported image format % (HDR image)", file);
return nullptr;
}
int dummy_w;
@@ -210,7 +269,7 @@ namespace mlx
std::memcpy(buffer.GetData(), data, buffer.GetSize());
Texture* texture;
try { texture = new Texture(buffer, (w == nullptr ? dummy_w : *w), (h == nullptr ? dummy_h : *h)); }
try { texture = new Texture(buffer, (w == nullptr ? dummy_w : *w), (h == nullptr ? dummy_h : *h), VK_FORMAT_R8G8B8A8_SRGB, false, std::move(filename)); }
catch(...) { return NULL; }
stbi_image_free(data);

View File

@@ -26,6 +26,7 @@ namespace mlx
{
void GPUAllocator::Init() noexcept
{
MLX_PROFILE_FUNCTION();
VmaVulkanFunctions vma_vulkan_func{};
vma_vulkan_func.vkAllocateMemory = RenderCore::Get().vkAllocateMemory;
vma_vulkan_func.vkBindBufferMemory = RenderCore::Get().vkBindBufferMemory;
@@ -63,6 +64,15 @@ namespace mlx
kvfCheckVk(vmaCreateBuffer(m_allocator, binfo, vinfo, &buffer, &allocation, nullptr));
if(name != nullptr)
{
if constexpr(RenderCore::HAS_DEBUG_UTILS_FUNCTIONS)
{
VkDebugUtilsObjectNameInfoEXT name_info{};
name_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
name_info.objectType = VK_OBJECT_TYPE_BUFFER;
name_info.objectHandle = reinterpret_cast<std::uint64_t>(buffer);
name_info.pObjectName = name;
RenderCore::Get().vkSetDebugUtilsObjectNameEXT(RenderCore::Get().GetDevice(), &name_info);
}
vmaSetAllocationName(m_allocator, allocation, name);
}
DebugLog("Graphics Allocator : created new buffer '%'", name);
@@ -70,12 +80,15 @@ namespace mlx
return allocation;
}
void GPUAllocator::DestroyBuffer(VmaAllocation allocation, VkBuffer buffer) noexcept
void GPUAllocator::DestroyBuffer(VmaAllocation allocation, VkBuffer buffer, const char* name) noexcept
{
MLX_PROFILE_FUNCTION();
RenderCore::Get().WaitDeviceIdle();
vmaDestroyBuffer(m_allocator, buffer, allocation);
DebugLog("Graphics Allocator : destroyed buffer");
if(name != nullptr)
DebugLog("Graphics Allocator : destroyed buffer '%'", name);
else
DebugLog("Graphics Allocator : destroyed buffer");
m_active_buffers_allocations--;
}
@@ -86,6 +99,15 @@ namespace mlx
kvfCheckVk(vmaCreateImage(m_allocator, iminfo, vinfo, &image, &allocation, nullptr));
if(name != nullptr)
{
if constexpr(RenderCore::HAS_DEBUG_UTILS_FUNCTIONS)
{
VkDebugUtilsObjectNameInfoEXT name_info{};
name_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
name_info.objectType = VK_OBJECT_TYPE_IMAGE;
name_info.objectHandle = reinterpret_cast<std::uint64_t>(image);
name_info.pObjectName = name;
RenderCore::Get().vkSetDebugUtilsObjectNameEXT(RenderCore::Get().GetDevice(), &name_info);
}
vmaSetAllocationName(m_allocator, allocation, name);
}
DebugLog("Graphics Allocator : created new image '%'", name);
@@ -93,12 +115,15 @@ namespace mlx
return allocation;
}
void GPUAllocator::DestroyImage(VmaAllocation allocation, VkImage image) noexcept
void GPUAllocator::DestroyImage(VmaAllocation allocation, VkImage image, const char* name) noexcept
{
MLX_PROFILE_FUNCTION();
RenderCore::Get().WaitDeviceIdle();
vmaDestroyImage(m_allocator, image, allocation);
DebugLog("Graphics Allocator : destroyed image");
if(name != nullptr)
DebugLog("Graphics Allocator : destroyed image '%'", name);
else
DebugLog("Graphics Allocator : destroyed image");
m_active_images_allocations--;
}
@@ -141,6 +166,7 @@ namespace mlx
void GPUAllocator::Destroy() noexcept
{
MLX_PROFILE_FUNCTION();
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)

View File

@@ -9,6 +9,7 @@ namespace mlx
{
void GraphicPipeline::Init(const GraphicPipelineDescriptor& descriptor)
{
MLX_PROFILE_FUNCTION();
if(!descriptor.vertex_shader || !descriptor.fragment_shader)
FatalError("Vulkan : invalid shaders");
@@ -62,6 +63,7 @@ namespace mlx
bool GraphicPipeline::BindPipeline(VkCommandBuffer command_buffer, std::size_t framebuffer_index, std::array<float, 4> clear) noexcept
{
MLX_PROFILE_FUNCTION();
TransitionAttachments(command_buffer);
VkFramebuffer fb = m_framebuffers[framebuffer_index];
VkExtent2D fb_extent = kvfGetFramebufferSize(fb);
@@ -98,11 +100,13 @@ namespace mlx
void GraphicPipeline::EndPipeline(VkCommandBuffer command_buffer) noexcept
{
MLX_PROFILE_FUNCTION();
RenderCore::Get().vkCmdEndRenderPass(command_buffer);
}
void GraphicPipeline::Destroy() noexcept
{
MLX_PROFILE_FUNCTION();
p_vertex_shader.reset();
p_fragment_shader.reset();
for(auto& fb : m_framebuffers)
@@ -124,6 +128,7 @@ namespace mlx
void GraphicPipeline::CreateFramebuffers(const std::vector<NonOwningPtr<Texture>>& render_targets, bool clear_attachments)
{
MLX_PROFILE_FUNCTION();
std::vector<VkAttachmentDescription> attachments;
std::vector<VkImageView> attachment_views;
if(p_renderer)
@@ -167,6 +172,7 @@ namespace mlx
void GraphicPipeline::TransitionAttachments(VkCommandBuffer cmd)
{
MLX_PROFILE_FUNCTION();
if(p_depth)
p_depth->TransitionLayout(VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, cmd);

View File

@@ -6,6 +6,7 @@ namespace mlx
{
Shader::Shader(const std::vector<std::uint8_t>& bytecode, ShaderType type, ShaderLayout layout) : m_layout(std::move(layout)), m_bytecode(bytecode)
{
MLX_PROFILE_FUNCTION();
switch(type)
{
case ShaderType::Vertex : m_stage = VK_SHADER_STAGE_VERTEX_BIT; break;
@@ -22,6 +23,7 @@ namespace mlx
void Shader::GeneratePipelineLayout(ShaderLayout layout)
{
MLX_PROFILE_FUNCTION();
for(auto& [n, set] : layout.set_layouts)
{
std::vector<VkDescriptorSetLayoutBinding> bindings(set.binds.size());
@@ -55,6 +57,7 @@ namespace mlx
Shader::~Shader()
{
MLX_PROFILE_FUNCTION();
kvfDestroyShaderModule(RenderCore::Get().GetDevice(), m_module);
DebugLog("Vulkan : shader module destroyed");
for(auto& layout : m_set_layouts)

View File

@@ -37,7 +37,7 @@ namespace mlx
std::cout << std::endl;
}
void ValidationWarningCallback(const char* message) noexcept
void WarningCallback(const char* message) noexcept
{
Logs::Report(LogType::Warning, 0, "", "", message);
std::cout << std::endl;
@@ -54,8 +54,9 @@ namespace mlx
LoadKVFGlobalVulkanFunctionPointers();
kvfSetErrorCallback(&ErrorCallback);
kvfSetWarningCallback(&WarningCallback);
kvfSetValidationErrorCallback(&ValidationErrorCallback);
kvfSetValidationWarningCallback(&ValidationWarningCallback);
kvfSetValidationWarningCallback(&WarningCallback);
//kvfAddLayer("VK_LAYER_MESA_overlay");

View File

@@ -16,6 +16,7 @@ namespace mlx
void Render2DPass::Init()
{
MLX_PROFILE_FUNCTION();
ShaderLayout vertex_shader_layout(
{
{ 0,
@@ -64,7 +65,7 @@ namespace mlx
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(ViewerData));
p_viewer_data_buffer->Init(sizeof(ViewerData), "mlx_2d_pass_viewer_data");
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));
@@ -74,6 +75,7 @@ namespace mlx
void Render2DPass::Pass(Scene& scene, Renderer& renderer, Texture& render_target)
{
MLX_PROFILE_FUNCTION();
if(m_pipeline.GetPipeline() == VK_NULL_HANDLE)
{
GraphicPipelineDescriptor pipeline_descriptor;
@@ -115,6 +117,7 @@ namespace mlx
void Render2DPass::Destroy()
{
MLX_PROFILE_FUNCTION();
m_pipeline.Destroy();
p_vertex_shader.reset();
p_fragment_shader.reset();

View File

@@ -9,6 +9,7 @@ namespace mlx
{
void FinalPass::Init()
{
MLX_PROFILE_FUNCTION();
ShaderLayout vertex_shader_layout(
{}, {}
);
@@ -44,6 +45,7 @@ namespace mlx
void FinalPass::Pass([[maybe_unused]] Scene& scene, Renderer& renderer, Texture& render_target)
{
MLX_PROFILE_FUNCTION();
if(m_pipeline.GetPipeline() == VK_NULL_HANDLE)
{
GraphicPipelineDescriptor pipeline_descriptor;
@@ -70,6 +72,7 @@ namespace mlx
void FinalPass::Destroy()
{
MLX_PROFILE_FUNCTION();
m_pipeline.Destroy();
p_vertex_shader.reset();
p_fragment_shader.reset();

View File

@@ -21,13 +21,21 @@ namespace mlx
{
m_main_render_texture.Destroy();
auto extent = kvfGetSwapchainImagesSize(renderer.GetSwapchain());
m_main_render_texture.Init({}, extent.width, extent.height);
#ifdef DEBUG
m_main_render_texture.Init({}, extent.width, extent.height, VK_FORMAT_R8G8B8A8_SRGB, false, "mlx_renderpasses_target");
#else
m_main_render_texture.Init({}, extent.width, extent.height, VK_FORMAT_R8G8B8A8_SRGB, false, {});
#endif
}
};
EventBus::RegisterListener({ functor, "__MlxRenderPasses" });
auto extent = kvfGetSwapchainImagesSize(renderer.GetSwapchain());
m_main_render_texture.Init({}, extent.width, extent.height);
#ifdef DEBUG
m_main_render_texture.Init({}, extent.width, extent.height, VK_FORMAT_R8G8B8A8_SRGB, false, "mlx_renderpasses_target");
#else
m_main_render_texture.Init({}, extent.width, extent.height, VK_FORMAT_R8G8B8A8_SRGB, false, {});
#endif
}
m_main_render_texture.Clear(renderer.GetActiveCommandBuffer(), Vec4f{ 0.0f, 0.0f, 0.0f, 1.0f });

View File

@@ -27,6 +27,7 @@ namespace mlx
void Renderer::Init(NonOwningPtr<Window> window)
{
MLX_PROFILE_FUNCTION();
func::function<void(const EventBase&)> functor = [this](const EventBase& event)
{
if(event.What() == Event::ResizeEventCode)
@@ -56,6 +57,7 @@ namespace mlx
bool Renderer::BeginFrame()
{
MLX_PROFILE_FUNCTION();
kvfWaitForFence(RenderCore::Get().GetDevice(), m_cmd_fences[m_current_frame_index]);
VkResult result = RenderCore::Get().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)
@@ -78,6 +80,7 @@ namespace mlx
void Renderer::EndFrame()
{
MLX_PROFILE_FUNCTION();
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);
@@ -95,6 +98,7 @@ namespace mlx
void Renderer::CreateSwapchain()
{
MLX_PROFILE_FUNCTION();
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);
@@ -105,7 +109,11 @@ namespace mlx
RenderCore::Get().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);
#ifdef DEBUG
m_swapchain_images[i].Init(tmp[i], kvfGetSwapchainImagesFormat(m_swapchain), extent.width, extent.height, VK_IMAGE_LAYOUT_UNDEFINED, "mlx_swapchain_image_" + std::to_string(i));
#else
m_swapchain_images[i].Init(tmp[i], kvfGetSwapchainImagesFormat(m_swapchain), extent.width, extent.height, VK_IMAGE_LAYOUT_UNDEFINED, {});
#endif
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);
}
@@ -114,6 +122,7 @@ namespace mlx
void Renderer::DestroySwapchain()
{
MLX_PROFILE_FUNCTION();
RenderCore::Get().WaitDeviceIdle();
for(Image& img : m_swapchain_images)
img.DestroyImageView();
@@ -123,6 +132,7 @@ namespace mlx
void Renderer::Destroy() noexcept
{
MLX_PROFILE_FUNCTION();
RenderCore::Get().WaitDeviceIdle();
for(std::size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++)

View File

@@ -8,16 +8,19 @@ namespace mlx
{
void SceneRenderer::Init()
{
MLX_PROFILE_FUNCTION();
m_passes.Init();
}
void SceneRenderer::Render(Scene& scene, Renderer& renderer)
{
MLX_PROFILE_FUNCTION();
m_passes.Pass(scene, renderer);
}
void SceneRenderer::Destroy()
{
MLX_PROFILE_FUNCTION();
m_passes.Destroy();
}
}

20
third_party/kvf.h vendored
View File

@@ -93,6 +93,7 @@ typedef void (*KvfErrorCallback)(const char* message);
typedef struct KvfGraphicsPipelineBuilder KvfGraphicsPipelineBuilder;
void kvfSetErrorCallback(KvfErrorCallback callback);
void kvfSetWarningCallback(KvfErrorCallback callback);
void kvfSetValidationErrorCallback(KvfErrorCallback callback);
void kvfSetValidationWarningCallback(KvfErrorCallback callback);
@@ -469,6 +470,7 @@ size_t __kvf_internal_framebuffers_capacity = 0;
#endif
KvfErrorCallback __kvf_error_callback = NULL;
KvfErrorCallback __kvf_warning_callback = NULL;
KvfErrorCallback __kvf_validation_error_callback = NULL;
KvfErrorCallback __kvf_validation_warning_callback = NULL;
@@ -479,7 +481,7 @@ KvfErrorCallback __kvf_validation_warning_callback = NULL;
void __kvfCheckVk(VkResult result, const char* function)
{
if(result != VK_SUCCESS)
if(result < VK_SUCCESS)
{
if(__kvf_error_callback != NULL)
{
@@ -493,6 +495,17 @@ void __kvfCheckVk(VkResult result, const char* function)
exit(EXIT_FAILURE);
#endif
}
else if(result > VK_SUCCESS)
{
if(__kvf_warning_callback != NULL)
{
char buffer[1024];
snprintf(buffer, 1024, "KVF Vulkan warning in '%s': %s", function, kvfVerbaliseVkResult(result));
__kvf_warning_callback(buffer);
return;
}
printf("KVF Vulkan warning in '%s': %s\n", function, kvfVerbaliseVkResult(result));
}
}
#undef __kvfCheckVk
@@ -817,6 +830,11 @@ void kvfSetErrorCallback(KvfErrorCallback callback)
__kvf_error_callback = callback;
}
void kvfSetWarningCallback(KvfErrorCallback callback)
{
__kvf_warning_callback = callback;
}
void kvfSetValidationErrorCallback(KvfErrorCallback callback)
{
__kvf_validation_error_callback = callback;