diff --git a/runtime/Includes/Core/Application.inl b/runtime/Includes/Core/Application.inl index 0296216..915b9e9 100644 --- a/runtime/Includes/Core/Application.inl +++ b/runtime/Includes/Core/Application.inl @@ -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& gs){ return *static_cast(win) == gs->GetID(); }) != m_graphics.end()) \ + else if(std::find_if(m_graphics.begin(), m_graphics.end(), [win](const std::unique_ptr& gs){ return *static_cast(win) == gs->GetID(); }) == m_graphics.end()) \ { \ Error("invalid window ptr"); \ return; \ diff --git a/runtime/Includes/Core/Graphics.inl b/runtime/Includes/Core/Graphics.inl index c0f4c02..5ffa9f9 100644 --- a/runtime/Includes/Core/Graphics.inl +++ b/runtime/Includes/Core/Graphics.inl @@ -39,10 +39,10 @@ namespace mlx { Sprite& new_sprite = p_scene->CreateSprite(texture); new_sprite.SetPosition(Vec3f{ static_cast(x), static_cast(y), static_cast(m_current_depth) }); + m_current_depth++; } else sprite->SetPosition(Vec3f{ static_cast(x), static_cast(y), static_cast(m_current_depth) }); - m_current_depth++; } void GraphicsSupport::LoadFont(const std::filesystem::path& filepath, float scale) diff --git a/runtime/Includes/Graphics/Mesh.h b/runtime/Includes/Graphics/Mesh.h index 999213f..215736b 100644 --- a/runtime/Includes/Graphics/Mesh.h +++ b/runtime/Includes/Graphics/Mesh.h @@ -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; diff --git a/runtime/Includes/Renderer/Buffer.h b/runtime/Includes/Renderer/Buffer.h index d6574fa..27e7716 100644 --- a/runtime/Includes/Renderer/Buffer.h +++ b/runtime/Includes/Renderer/Buffer.h @@ -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; diff --git a/runtime/Includes/Renderer/Image.h b/runtime/Includes/Renderer/Image.h index ebde1ad..ae070d7 100644 --- a/runtime/Includes/Renderer/Image.h +++ b/runtime/Includes/Renderer/Image.h @@ -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 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; diff --git a/runtime/Includes/Renderer/Memory.h b/runtime/Includes/Renderer/Memory.h index 2470630..26f0b99 100644 --- a/runtime/Includes/Renderer/Memory.h +++ b/runtime/Includes/Renderer/Memory.h @@ -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; diff --git a/runtime/Includes/Renderer/RenderCore.h b/runtime/Includes/Renderer/RenderCore.h index a119534..f17b8d6 100644 --- a/runtime/Includes/Renderer/RenderCore.h +++ b/runtime/Includes/Renderer/RenderCore.h @@ -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: diff --git a/runtime/Includes/Renderer/Vulkan/VulkanDefs.h b/runtime/Includes/Renderer/Vulkan/VulkanDefs.h index 2c9972d..5ee802e 100644 --- a/runtime/Includes/Renderer/Vulkan/VulkanDefs.h +++ b/runtime/Includes/Renderer/Vulkan/VulkanDefs.h @@ -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 diff --git a/runtime/Sources/Core/Application.cpp b/runtime/Sources/Core/Application.cpp index cd53f58..066df7e 100644 --- a/runtime/Sources/Core/Application.cpp +++ b/runtime/Sources/Core/Application.cpp @@ -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; diff --git a/runtime/Sources/Graphics/Mesh.cpp b/runtime/Sources/Graphics/Mesh.cpp index 3df2e95..751d12e 100644 --- a/runtime/Sources/Graphics/Mesh.cpp +++ b/runtime/Sources/Graphics/Mesh.cpp @@ -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(); diff --git a/runtime/Sources/Graphics/PixelPutManager.cpp b/runtime/Sources/Graphics/PixelPutManager.cpp deleted file mode 100644 index 81c0c6f..0000000 --- a/runtime/Sources/Graphics/PixelPutManager.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include - -#include -#include - -namespace mlx -{ - NonOwningPtr 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(); - } -} diff --git a/runtime/Sources/Graphics/PutPixelManager.cpp b/runtime/Sources/Graphics/PutPixelManager.cpp new file mode 100644 index 0000000..67f42dd --- /dev/null +++ b/runtime/Sources/Graphics/PutPixelManager.cpp @@ -0,0 +1,31 @@ +#include + +#include +#include + +namespace mlx +{ + NonOwningPtr 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(); + } +} diff --git a/runtime/Sources/Graphics/Scene.cpp b/runtime/Sources/Graphics/Scene.cpp index 94eac69..dd48850 100644 --- a/runtime/Sources/Graphics/Scene.cpp +++ b/runtime/Sources/Graphics/Scene.cpp @@ -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) noexcept { + MLX_PROFILE_FUNCTION(); std::shared_ptr sprite = std::make_shared(texture); m_sprites.push_back(sprite); return *sprite; @@ -21,6 +23,7 @@ namespace mlx NonOwningPtr Scene::GetSpriteFromTextureAndPosition(NonOwningPtr 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) { 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) { + MLX_PROFILE_FUNCTION(); auto it = m_sprites.begin(); do { diff --git a/runtime/Sources/Graphics/Sprite.cpp b/runtime/Sources/Graphics/Sprite.cpp index e6792ae..533270b 100644 --- a/runtime/Sources/Graphics/Sprite.cpp +++ b/runtime/Sources/Graphics/Sprite.cpp @@ -7,6 +7,7 @@ namespace mlx { std::shared_ptr CreateQuad(float x, float y, float width, float height) { + MLX_PROFILE_FUNCTION(); std::vector data(4); data[0].position = Vec4f(x, y, 0.0f, 1.0f); @@ -37,6 +38,7 @@ namespace mlx Sprite::Sprite(NonOwningPtr texture) { + MLX_PROFILE_FUNCTION(); Verify((bool)texture, "Sprite: invalid texture"); p_mesh = CreateQuad(0, 0, texture->GetWidth(), texture->GetHeight()); p_texture = texture; diff --git a/runtime/Sources/Renderer/Buffer.cpp b/runtime/Sources/Renderer/Buffer.cpp index b60233d..b1cf50a 100644 --- a/runtime/Sources/Renderer/Buffer.cpp +++ b/runtime/Sources/Renderer/Buffer.cpp @@ -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(); } diff --git a/runtime/Sources/Renderer/Descriptor.cpp b/runtime/Sources/Renderer/Descriptor.cpp index 11a4411..ac3b2ab 100644 --- a/runtime/Sources/Renderer/Descriptor.cpp +++ b/runtime/Sources/Renderer/Descriptor.cpp @@ -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& 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 writes; std::vector 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); } diff --git a/runtime/Sources/Renderer/Image.cpp b/runtime/Sources/Renderer/Image.cpp index 03cf018..61b778b 100644 --- a/runtime/Sources/Renderer/Image.cpp +++ b/runtime/Sources/Renderer/Image.cpp @@ -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(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); diff --git a/runtime/Sources/Renderer/Memory.cpp b/runtime/Sources/Renderer/Memory.cpp index 3587dca..01e1a5f 100644 --- a/runtime/Sources/Renderer/Memory.cpp +++ b/runtime/Sources/Renderer/Memory.cpp @@ -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(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(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) diff --git a/runtime/Sources/Renderer/Pipelines/Graphics.cpp b/runtime/Sources/Renderer/Pipelines/Graphics.cpp index 6fa92e0..a466786 100644 --- a/runtime/Sources/Renderer/Pipelines/Graphics.cpp +++ b/runtime/Sources/Renderer/Pipelines/Graphics.cpp @@ -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 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>& render_targets, bool clear_attachments) { + MLX_PROFILE_FUNCTION(); std::vector attachments; std::vector 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); diff --git a/runtime/Sources/Renderer/Pipelines/Shader.cpp b/runtime/Sources/Renderer/Pipelines/Shader.cpp index 651e560..7dd4691 100644 --- a/runtime/Sources/Renderer/Pipelines/Shader.cpp +++ b/runtime/Sources/Renderer/Pipelines/Shader.cpp @@ -6,6 +6,7 @@ namespace mlx { Shader::Shader(const std::vector& 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 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) diff --git a/runtime/Sources/Renderer/RenderCore.cpp b/runtime/Sources/Renderer/RenderCore.cpp index cbb3be0..872406e 100644 --- a/runtime/Sources/Renderer/RenderCore.cpp +++ b/runtime/Sources/Renderer/RenderCore.cpp @@ -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"); diff --git a/runtime/Sources/Renderer/RenderPasses/2DPass.cpp b/runtime/Sources/Renderer/RenderPasses/2DPass.cpp index 19ba2d7..a93a2e7 100644 --- a/runtime/Sources/Renderer/RenderPasses/2DPass.cpp +++ b/runtime/Sources/Renderer/RenderPasses/2DPass.cpp @@ -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(p_fragment_shader->GetShaderLayout().set_layouts[0].second, p_fragment_shader->GetPipelineLayout().set_layouts[0], ShaderType::Fragment); p_viewer_data_buffer = std::make_shared(); - 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(); diff --git a/runtime/Sources/Renderer/RenderPasses/FinalPass.cpp b/runtime/Sources/Renderer/RenderPasses/FinalPass.cpp index 5a4014b..b292109 100644 --- a/runtime/Sources/Renderer/RenderPasses/FinalPass.cpp +++ b/runtime/Sources/Renderer/RenderPasses/FinalPass.cpp @@ -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(); diff --git a/runtime/Sources/Renderer/RenderPasses/Passes.cpp b/runtime/Sources/Renderer/RenderPasses/Passes.cpp index 83024f1..0a4b2bc 100644 --- a/runtime/Sources/Renderer/RenderPasses/Passes.cpp +++ b/runtime/Sources/Renderer/RenderPasses/Passes.cpp @@ -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 }); diff --git a/runtime/Sources/Renderer/Renderer.cpp b/runtime/Sources/Renderer/Renderer.cpp index b240290..a7f3fcf 100644 --- a/runtime/Sources/Renderer/Renderer.cpp +++ b/runtime/Sources/Renderer/Renderer.cpp @@ -27,6 +27,7 @@ namespace mlx void Renderer::Init(NonOwningPtr window) { + MLX_PROFILE_FUNCTION(); func::function 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++) diff --git a/runtime/Sources/Renderer/SceneRenderer.cpp b/runtime/Sources/Renderer/SceneRenderer.cpp index 8c176a0..09903cb 100644 --- a/runtime/Sources/Renderer/SceneRenderer.cpp +++ b/runtime/Sources/Renderer/SceneRenderer.cpp @@ -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(); } } diff --git a/third_party/kvf.h b/third_party/kvf.h index 6b6fcc6..164466e 100755 --- a/third_party/kvf.h +++ b/third_party/kvf.h @@ -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;