From 542279270575ba907bab5ed5daca6640ca9f8f95 Mon Sep 17 00:00:00 2001 From: light7734 Date: Mon, 27 Oct 2025 23:29:08 +0330 Subject: [PATCH] feat(renderer): storage & staging buffer types --- .../private/backend/vk/data/buffer.cpp | 70 ++++++++++++++----- .../private/backend/vk/data/buffer.hpp | 23 +++++- .../renderer/private/frontend/data/buffer.cpp | 2 - .../renderer/private/frontend/data/buffer.hpp | 13 +++- .../private/frontend/data/buffer.test.cpp | 27 +++---- 5 files changed, 101 insertions(+), 34 deletions(-) diff --git a/modules/renderer/private/backend/vk/data/buffer.cpp b/modules/renderer/private/backend/vk/data/buffer.cpp index 8236612..513efd9 100644 --- a/modules/renderer/private/backend/vk/data/buffer.cpp +++ b/modules/renderer/private/backend/vk/data/buffer.cpp @@ -16,7 +16,7 @@ Buffer::Buffer(IDevice *device, IGpu *gpu, const CreateInfo &info) .sharingMode = VK_SHARING_MODE_EXCLUSIVE, } ) - , m_memory(m_device, m_buffer, allocation_info_from_memory_requirements()) + , m_memory(m_device, m_buffer, determine_allocation_info(info.usage)) , m_size(info.size) { } @@ -31,30 +31,18 @@ void Buffer::unmap() /* override */ m_device->unmap_memory(m_memory); } -[[nodiscard]] auto Buffer::to_native_usage_flags(Usage usage) const -> VkBufferUsageFlags -{ - switch (usage) - { - case Usage::vertex: return VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; - case Usage::index: return VK_BUFFER_USAGE_INDEX_BUFFER_BIT; - } - - std::unreachable(); -} - -[[nodiscard]] auto Buffer::allocation_info_from_memory_requirements() const -> VkMemoryAllocateInfo +[[nodiscard]] auto Buffer::determine_allocation_info(Usage usage) const -> VkMemoryAllocateInfo { const auto requirements = m_device->get_memory_requirements(m_buffer); auto memory_properties = m_gpu->get_memory_properties(); - const auto required_properties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT - | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; + const auto required_properties = to_native_memory_properties(usage); auto type = 0u; for (auto idx = 0; idx < memory_properties.memoryTypeCount; ++idx) { - if ((requirements.memoryTypeBits & (1 << idx)) - && ((memory_properties.memoryTypes[idx].propertyFlags & required_properties) - == required_properties)) + const auto property_flags = memory_properties.memoryTypes[idx].propertyFlags; + if (has_correct_memory_type_bit(requirements.memoryTypeBits, idx) + && has_required_memory_properties(required_properties, property_flags)) { type = idx; @@ -69,4 +57,50 @@ void Buffer::unmap() /* override */ }; } +[[nodiscard]] auto Buffer::to_native_usage_flags(Usage usage) const -> VkBufferUsageFlags +{ + switch (usage) + { + case Usage::vertex: return VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; + + case Usage::index: return VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; + + case Usage::storage: + return VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; + + case Usage::staging: return VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + } + + std::unreachable(); +} + +[[nodiscard]] auto Buffer::to_native_memory_properties(Usage usage) const -> VkMemoryPropertyFlags +{ + switch (usage) + { + case Usage::vertex: + case Usage::index: + case Usage::storage: return VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + + case Usage::staging: + return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; + } + + std::unreachable(); +} + +[[nodiscard]] auto Buffer::has_correct_memory_type_bit(uint32_t type_bits, uint32_t type_idx) const + -> bool +{ + return type_bits & (1 << type_idx); +} + +[[nodiscard]] auto Buffer::has_required_memory_properties( + uint32_t required_properties, + uint32_t property_flags +) const -> bool +{ + return (property_flags & required_properties) == required_properties; +} + } // namespace lt::renderer::vk diff --git a/modules/renderer/private/backend/vk/data/buffer.hpp b/modules/renderer/private/backend/vk/data/buffer.hpp index 4529987..f6d4c35 100644 --- a/modules/renderer/private/backend/vk/data/buffer.hpp +++ b/modules/renderer/private/backend/vk/data/buffer.hpp @@ -14,15 +14,36 @@ public: void unmap() override; + // TODO(Light): this is to make copying possible. + // But it should be removed in the future, + // Right now it's not possible because: buffers can't understand CommandBuffers. + // And I'm not sure how to properly abstract over command buffers, + // before using other APIs... + [[nodiscard]] auto vk() + { + return *m_buffer; + } + [[nodiscard]] auto get_size() const -> size_t override { return m_size; } private: + [[nodiscard]] auto determine_allocation_info(Usage usage) const -> VkMemoryAllocateInfo; + [[nodiscard]] auto to_native_usage_flags(Usage usage) const -> VkBufferUsageFlags; - [[nodiscard]] auto allocation_info_from_memory_requirements() const -> VkMemoryAllocateInfo; + [[nodiscard]] auto to_native_memory_properties(Usage usage) const -> VkMemoryPropertyFlags; + + + [[nodiscard]] auto has_correct_memory_type_bit(uint32_t type_bits, uint32_t type_idx) const + -> bool; + + [[nodiscard]] auto has_required_memory_properties( + uint32_t required_properties, + uint32_t property_flags + ) const -> bool; Device *m_device {}; diff --git a/modules/renderer/private/frontend/data/buffer.cpp b/modules/renderer/private/frontend/data/buffer.cpp index 2f77ea2..6591241 100644 --- a/modules/renderer/private/frontend/data/buffer.cpp +++ b/modules/renderer/private/frontend/data/buffer.cpp @@ -1,5 +1,3 @@ -#pragma once - #include #include diff --git a/modules/renderer/private/frontend/data/buffer.hpp b/modules/renderer/private/frontend/data/buffer.hpp index b88b8c0..b223aab 100644 --- a/modules/renderer/private/frontend/data/buffer.hpp +++ b/modules/renderer/private/frontend/data/buffer.hpp @@ -8,11 +8,15 @@ namespace lt::renderer { class IBuffer { public: - enum Usage : uint8_t + enum class Usage : uint8_t { vertex, index, + + storage, + + staging, }; struct CreateInfo @@ -24,6 +28,13 @@ public: std::string debug_name; }; + struct CopyInfo + { + size_t offset; + + size_t size; + }; + [[nodiscard]] static auto create( Api target_api, class IDevice *device, diff --git a/modules/renderer/private/frontend/data/buffer.test.cpp b/modules/renderer/private/frontend/data/buffer.test.cpp index ac1c2ef..b7a53cc 100644 --- a/modules/renderer/private/frontend/data/buffer.test.cpp +++ b/modules/renderer/private/frontend/data/buffer.test.cpp @@ -8,16 +8,19 @@ Suite raii = "buffer_raii"_suite = [] { Case { "happy path won't throw" } = [] { auto fixture = FixtureDeviceSwapchain {}; - ignore = IBuffer::create( - lt::renderer::Api::vulkan, - fixture.device(), - fixture.gpu(), - IBuffer::CreateInfo { - .usage = IBuffer::Usage::vertex, - .size = 1000u, - .debug_name = "", - } - ); + for (auto idx = 0; idx <= std::to_underlying(IBuffer::Usage::staging); ++idx) + { + ignore = IBuffer::create( + lt::renderer::Api::vulkan, + fixture.device(), + fixture.gpu(), + IBuffer::CreateInfo { + .usage = static_cast(idx), + .size = 1000u, + .debug_name = "", + } + ); + } expect_false(fixture.has_any_messages_of(error)); expect_false(fixture.has_any_messages_of(warning)); @@ -77,7 +80,7 @@ Suite raii = "buffer_raii"_suite = [] { ); }); - /** Make sure the default-case was good */ + /** Make sure the default-case was OK */ ignore = IBuffer::create(lt::renderer::Api::vulkan, fixture.device(), fixture.gpu(), info); expect_false(fixture.has_any_messages_of(error)); @@ -96,7 +99,7 @@ Suite mapping = "buffer_mapping"_suite = [] { fixture.device(), fixture.gpu(), IBuffer::CreateInfo { - .usage = IBuffer::Usage::vertex, + .usage = IBuffer::Usage::staging, .size = size, .debug_name = "", }