mirror of
https://github.com/seekrs/MacroLibX.git
synced 2026-01-11 14:43:34 +00:00
adding debug vulkan resources names
This commit is contained in:
@@ -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; \
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
31
runtime/Sources/Graphics/PutPixelManager.cpp
git.filemode.normal_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();
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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");
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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 });
|
||||
|
||||
@@ -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++)
|
||||
|
||||
@@ -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
20
third_party/kvf.h
vendored
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user