From afec1e3e32cd70afd7b1367e5d47a2373f5edbe8 Mon Sep 17 00:00:00 2001 From: Anish Bhobe Date: Mon, 24 Mar 2025 22:31:47 +0100 Subject: [PATCH] Reimplemented RenderResourceManager. --- aster/include/aster/core/buffer.h | 119 +++---- aster/include/aster/core/image.h | 83 ++--- aster/include/aster/core/sampler.h | 51 +-- aster/include/aster/core/type_traits.h | 37 +- aster/include/aster/systems/buffer_manager.h | 2 +- aster/include/aster/systems/image_manager.h | 2 +- aster/include/aster/systems/manager.h | 321 ++--------------- .../aster/systems/render_resource_manager.h | 328 ++++++++++++++++-- aster/include/aster/systems/sampler_manager.h | 2 +- aster/include/aster/util/CMakeLists.txt | 2 +- aster/include/aster/util/intrusive_slist.h | 127 +++++++ aster/src/aster/core/buffer.cpp | 23 +- aster/src/aster/core/image.cpp | 26 +- aster/src/aster/systems/buffer_manager.cpp | 8 +- aster/src/aster/systems/image_manager.cpp | 20 +- .../aster/systems/render_resource_manager.cpp | 141 +++----- aster/src/aster/systems/sampler_manager.cpp | 6 +- aster/src/aster/util/CMakeLists.txt | 2 +- samples/01_triangle/triangle.cpp | 8 +- samples/02_box/box.cpp | 51 ++- samples/CMakeLists.txt | 4 +- 21 files changed, 706 insertions(+), 657 deletions(-) create mode 100644 aster/include/aster/util/intrusive_slist.h diff --git a/aster/include/aster/core/buffer.h b/aster/include/aster/core/buffer.h index 5d88958..1eb4ed5 100644 --- a/aster/include/aster/core/buffer.h +++ b/aster/include/aster/core/buffer.h @@ -13,45 +13,66 @@ struct Device; struct Buffer { + const Device *m_Device = nullptr; ///< Will be used for book-keeping when buffer is invalid. + vk::Buffer m_Buffer = nullptr; VmaAllocation m_Allocation = nullptr; - // If the buffer is host visible, it should be (and stay) mapped. - u8 *m_Mapped = nullptr; + u8 *m_Mapped = nullptr; ///< If the buffer is host visible, it should be (and stay) mapped. - [[nodiscard]] usize GetSize() const; - [[nodiscard]] bool IsHostVisible() const; - [[nodiscard]] bool IsValid() const; - [[nodiscard]] bool IsMapped() const; - [[nodiscard]] bool IsOwned() const; - [[nodiscard]] bool IsCommitted() const; - void SetCommitted(bool committed); + usize m_Size = 0; + std::atomic m_RefCount = 0; - void Destroy(const Device *device); - void Write(const Device *device, usize offset, usize size, const void *data); + [[nodiscard]] bool + IsHostVisible() const + { + return m_Mapped; + } + + [[nodiscard]] bool + IsValid() const + { + return m_Buffer; + } + + [[nodiscard]] bool + IsMapped() const + { + return m_Mapped; + } + + void + AddRef() + { + assert(++m_RefCount > 0); + } + + void + Release() + { + const auto rc = --m_RefCount; + assert(rc < MaxValue); + if (rc == 0) + { + Destroy(); + } + } + + [[nodiscard]] bool + IsReferenced() + { + return m_RefCount; + } + + void Destroy(); + void Write(usize offset, usize size, const void *data); void Allocate(const Device *device, usize size, vk::BufferUsageFlags bufferUsage, VmaAllocationCreateFlags allocationFlags, VmaMemoryUsage memoryUsage, cstr name); - uptr - GetDeviceAddress(const Device *device); - - // Buffer.size is used for bookkeeping - // If the buffer is Invalid, the remaining data in Buffer is used intrusively by `GpuResourceManager`. - usize m_Size_ = 0; - - constexpr static usize VALID_BUFFER_BIT = Cast(1llu << 63); - constexpr static usize OWNED_BIT = 1llu << 62; - constexpr static usize COMMITTED_BIT = 1llu << 61; - constexpr static usize SIZE_MASK = ~(VALID_BUFFER_BIT | OWNED_BIT | COMMITTED_BIT); + uptr GetDeviceAddress(const Device *device) const; }; -template <> -constexpr bool concepts::Resource = true; - -// Ensure that m_Size doesn't get used intrusively since it manages the state. -static_assert(offsetof(Buffer, m_Size_) > sizeof(usize)); - struct UniformBuffer : Buffer { void Init(const Device *device, usize size, cstr name = nullptr); @@ -89,45 +110,3 @@ struct StagingBuffer : Buffer { void Init(const Device *device, usize size, cstr name = nullptr); }; - -inline usize -Buffer::GetSize() const -{ - return m_Size_ & SIZE_MASK; -} - -inline bool -Buffer::IsHostVisible() const -{ - return IsMapped(); -} - -inline bool -Buffer::IsValid() const -{ - return m_Size_ & VALID_BUFFER_BIT; -} - -inline bool -Buffer::IsMapped() const -{ - return m_Mapped; -} - -inline bool -Buffer::IsOwned() const -{ - return m_Size_ & OWNED_BIT; -} - -inline bool -Buffer::IsCommitted() const -{ - return m_Size_ & COMMITTED_BIT; -} - -inline void -Buffer::SetCommitted(const bool committed) -{ - m_Size_ = committed ? (m_Size_ | COMMITTED_BIT) : (m_Size_ & ~COMMITTED_BIT); -} diff --git a/aster/include/aster/core/image.h b/aster/include/aster/core/image.h index bdd6c14..b5f9a9c 100644 --- a/aster/include/aster/core/image.h +++ b/aster/include/aster/core/image.h @@ -35,33 +35,56 @@ ToOffset3D(const vk::Extent3D &extent) struct Image { + const Device *m_Device = nullptr; vk::Image m_Image = nullptr; - vk::ImageView m_View = nullptr; VmaAllocation m_Allocation = nullptr; + vk::ImageView m_View = nullptr; vk::Extent3D m_Extent; - // Image.m_MipLevels_ is used for bookkeeping - // If the image is Invalid, the remaining data in Image is used intrusively by `GpuResourceManager`. + std::atomic m_RefCount; u8 m_EmptyPadding_ = 0; u8 m_Flags_ = 0; u8 m_LayerCount = 0; u8 m_MipLevels = 0; - [[nodiscard]] bool IsValid() const; - [[nodiscard]] bool IsOwned() const; - [[nodiscard]] u32 GetMipLevels() const; - [[nodiscard]] bool IsCommitted() const; - void SetCommitted(bool committed); + [[nodiscard]] bool + IsValid() const + { + return m_Image; + } - void Destroy(const Device *device); + [[nodiscard]] bool + IsReferenced() const + { + return m_RefCount; + } - constexpr static u8 VALID_BIT = 1u << 7; - constexpr static u8 OWNED_BIT = 1u << 6; - constexpr static u8 COMMITTED_BIT = 1u << 5; + [[nodiscard]] u32 + GetMipLevels() const + { + return m_MipLevels; + } + + void + AddRef() + { + const auto rc = ++m_RefCount; + assert(rc > 0); + } + + void + Release() + { + const auto rc = --m_RefCount; + assert(rc < MaxValue); + if (rc == 0) + { + Destroy(); + } + } + + void Destroy(); }; -template <> -constexpr bool concepts::Resource = true; - struct Texture : Image { void Init(const Device *device, vk::Extent2D extent, vk::Format imageFormat, bool isMipMapped, cstr name = nullptr); @@ -105,33 +128,3 @@ struct StorageTextureCube : StorageTexture }; static_assert(sizeof(StorageTextureCube) == sizeof(Image)); - -inline bool -Image::IsValid() const -{ - return m_Flags_ & VALID_BIT; -} - -inline bool -Image::IsOwned() const -{ - return m_Flags_ & OWNED_BIT; -} - -inline u32 -Image::GetMipLevels() const -{ - return m_MipLevels; -} - -inline bool -Image::IsCommitted() const -{ - return m_Flags_ & COMMITTED_BIT; -} - -inline void -Image::SetCommitted(const bool committed) -{ - m_Flags_ = committed ? (m_Flags_ | COMMITTED_BIT) : (m_Flags_ & ~COMMITTED_BIT); -} diff --git a/aster/include/aster/core/sampler.h b/aster/include/aster/core/sampler.h index 4dfeff1..11eae4d 100644 --- a/aster/include/aster/core/sampler.h +++ b/aster/include/aster/core/sampler.h @@ -14,33 +14,34 @@ struct Device; struct Sampler { vk::Sampler m_Sampler = nullptr; - bool m_Committed = false; + std::atomic m_RefCount = 0; void Init(const Device *device, const vk::SamplerCreateInfo &samplerCreateInfo, cstr name); void Destroy(const Device *device); - [[nodiscard]] bool IsValid() const; - [[nodiscard]] bool IsCommitted() const; - void SetCommitted(bool committed); + void + AddRef() + { + const auto rc = ++m_RefCount; + assert(rc > 0); + } + + void + Release() + { + const auto rc = --m_RefCount; + assert(rc < MaxValue); + } + + [[nodiscard]] bool + IsReferenced() const + { + return m_RefCount; + } + + [[nodiscard]] bool + IsValid() const + { + return m_Sampler; + } }; - -template <> -constexpr bool concepts::Opaque = true; - -inline bool -Sampler::IsValid() const -{ - return m_Sampler; -} - -inline bool -Sampler::IsCommitted() const -{ - return m_Committed; -} - -inline void -Sampler::SetCommitted(const bool committed) -{ - m_Committed = committed; -} diff --git a/aster/include/aster/core/type_traits.h b/aster/include/aster/core/type_traits.h index caddf03..08864eb 100644 --- a/aster/include/aster/core/type_traits.h +++ b/aster/include/aster/core/type_traits.h @@ -9,42 +9,25 @@ struct Device; namespace concepts { -template -concept Fetches = requires(THandle h) -{ - { h.Fetch() } -> std::same_as; +template +concept RefCounted = requires(T a) { + { a.AddRef() } -> std::same_as; + { a.Release() } -> std::same_as; + { a.IsReferenced() } -> std::convertible_to; }; template concept DeviceDestructible = requires(T a, Device *p) { - { a.Destroy(p) } -> std::convertible_to; + { a.Destroy(p) } -> std::same_as; }; template -concept Committable = requires(T a, bool v) { - { a.IsCommitted() } -> std::convertible_to; - { a.SetCommitted(v) } -> std::convertible_to; +concept SelfDestructible = requires(T a) { + { a.Destroy() } -> std::same_as; + { T::m_Device } -> std::convertible_to; }; template -constexpr bool Resource = false; - -template -constexpr bool Opaque = false; - -template -concept Consistent = (Resource and !Opaque) or (Opaque and !Resource); - -template -concept Manageable = std::is_default_constructible_v and std::is_trivially_copyable_v and DeviceDestructible; - -template -concept ShaderObject = Consistent and Manageable and Committable; - -template -concept ShaderResource = ShaderObject and Resource; - -template -concept ShaderOpaque = ShaderObject and Opaque; +concept Manageable = std::is_default_constructible_v and (DeviceDestructible or SelfDestructible) and RefCounted; } // namespace concepts \ No newline at end of file diff --git a/aster/include/aster/systems/buffer_manager.h b/aster/include/aster/systems/buffer_manager.h index 363b6c1..b626c07 100644 --- a/aster/include/aster/systems/buffer_manager.h +++ b/aster/include/aster/systems/buffer_manager.h @@ -11,7 +11,7 @@ namespace systems { -using BufferHandle = Handle; +using BufferHandle = Manager::Handle; class BufferManager final : public Manager { diff --git a/aster/include/aster/systems/image_manager.h b/aster/include/aster/systems/image_manager.h index 77a7d13..72aa0cb 100644 --- a/aster/include/aster/systems/image_manager.h +++ b/aster/include/aster/systems/image_manager.h @@ -45,7 +45,7 @@ struct DepthStencilImageCreateInfo cstr m_Name = nullptr; }; -using ImageHandle = Handle; +using ImageHandle = Manager::Handle; class ImageManager final : public Manager { diff --git a/aster/include/aster/systems/manager.h b/aster/include/aster/systems/manager.h index 9594966..aff3837 100644 --- a/aster/include/aster/systems/manager.h +++ b/aster/include/aster/systems/manager.h @@ -8,24 +8,20 @@ #include "aster/aster.h" #include "aster/core/type_traits.h" +#include +#include + struct Device; namespace systems { -template -class Handle; - -template +template class Manager { - friend Handle; - public: using Type = T; - using Handle = Handle; - static_assert(sizeof(Handle) == sizeof(u32)); - constexpr static u32 MAX_HANDLES = Handle::INDEX_MASK + 1; + using Handle = eastl::intrusive_ptr; /** * Constructor for the Manager class template. @@ -34,19 +30,16 @@ class Manager * @param binding The shader binding at which this manager will bind its resources. */ explicit Manager(const Device *device, const u32 maxCount, const u8 binding) - : m_MaxCount{maxCount} + : m_Data{maxCount} , m_Binding{binding} , m_Device{device} { assert(!m_Instance && "Attempting to initialize a second Manager"); - assert(maxCount <= MAX_HANDLES); - m_Data = new Type[m_MaxCount]; - m_RefCount = new std::atomic[m_MaxCount]; - - for (u32 i = 0; i < m_MaxCount; ++i) + u32 i = 0; + for (auto& element : m_Data) { - *Recast(&m_Data[i]) = (i + 1); + *Recast(&element) = ++i; } m_Instance = this; @@ -54,87 +47,48 @@ class Manager virtual ~Manager() { - if (!m_Data) - return; - - for (u32 i = 0; i < m_MaxCount; ++i) + for (auto& element: m_Data) { - m_Data[i].Destroy(m_Device); + if constexpr (concepts::SelfDestructible) + { + element.Destroy(); + } + else if constexpr (concepts::DeviceDestructible) + { + element.Destroy(m_Device); + } } - delete[] m_Data; - delete[] m_RefCount; - m_Data = nullptr; - m_RefCount = nullptr; - m_MaxCount = 0; m_FreeHead = 0; m_Device = nullptr; m_Instance = nullptr; } - /** - * @warning only to be used internally. - * @return The only constructed instance of this manager. - */ - static Manager * - Instance() + void + Sweep() + requires concepts::DeviceDestructible { - assert(m_Instance && "Not initialized yet."); - return m_Instance; + for (i64 i = m_Data.size() - 1; i >= 0; --i) + { + if (auto *pIter = &m_Data[i]; !pIter->IsValid()) + { + pIter->Destroy(m_Device); + *Recast(pIter) = m_FreeHead; + m_FreeHead = i; + } + } } PIN_MEMORY(Manager); private: - Type *m_Data = nullptr; // Data also keeps the freelist during 'not use'. - std::atomic *m_RefCount = nullptr; // Associated reference count for each of the instances in Data. - u32 m_MaxCount = 0; // Max number of resources supported. + eastl::vector m_Data; // Data also keeps the freelist during 'not use'. u32 m_FreeHead = 0; u8 m_Binding = 0; static Manager *m_Instance; - /** - * User is expected to type-check. - * @param index Actual index of the resource in the m_Data array. Not type checked. - */ - void - AddRef(const u32 index) - { - assert(index < m_MaxCount); - ++m_RefCount[index]; - } - - /** - * User is expected to type-check. - * @param index Actual index of the resource in the m_Data array. Not type checked. - */ - void - Release(const u32 index) - { - assert(index < m_MaxCount); - const u32 rc = --m_RefCount[index]; - assert(rc != MaxValue); - if (rc == 0) - { - // TODO: Don't destroy here. Separate out to a cleanup routine. - m_Data[index].Destroy(m_Device); - } - } - - /** - * User is expected to type-check. - * @param index Actual index of the resource in the m_Data array. Not type checked. - * @return Pointer to the resource at the index. - */ - Type * - Fetch(const u32 index) - { - assert(index < m_MaxCount); - return &m_Data[index]; - } - protected: const Device *m_Device; @@ -142,221 +96,20 @@ class Manager * Internal Method to Allocate a resource on the manager. * @return [Handle, Type*] Where Type* is available to initialize the resource. */ - [[nodiscard]] std::pair + [[nodiscard]] Handle Alloc() { - ERROR_IF(m_FreeHead >= m_MaxCount, "Max buffers allocated.") THEN_ABORT(-1); + ERROR_IF(m_FreeHead >= m_Data.size(), "Max buffers allocated.") THEN_ABORT(-1); const auto index = m_FreeHead; Type *pAlloc = &m_Data[index]; m_FreeHead = *Recast(pAlloc); - return {Handle{index, m_Binding}, pAlloc}; - } -}; - -template -class Ref -{ - public: - using Type = T; - using Handle = Handle; - using Manager = Manager; - - protected: - Handle m_Handle; - Type *m_Pointer = nullptr; - - friend Handle; - - void - InitPtr() - { - m_Pointer = m_Handle.Fetch(); - } - - public: - Type * - Fetch() - { - assert(m_Pointer); - return m_Pointer; - } - - const Type * - Fetch() const - { - assert(m_Pointer); - return m_Pointer; - } - - Type * - operator->() - { - return Fetch(); - } - - const Type * - operator->() const - { - return Fetch(); - } - - Type & - operator*() - { - return *Fetch(); - } - - const Type & - operator*() const - { - return Fetch(); - } - - operator Handle &() - { - return m_Handle; - } - - operator const Handle &() const - { - return m_Handle; - } - - // The only constructor requires a valid construction. - explicit Ref(Handle &&handle) - : m_Handle{std::forward(handle)} - { - InitPtr(); - } - - // The only constructor requires a valid construction. - explicit Ref(const Handle &&handle) - : m_Handle{handle} - { - InitPtr(); - } - - Ref(const Ref &other) = default; - Ref(Ref &&other) noexcept = default; - Ref &operator=(const Ref &other) = default; - Ref &operator=(Ref &&other) noexcept = default; - ~Ref() = default; -}; - -template -class Handle -{ - public: - using Type = T; - using Manager = Manager; - - protected: - constexpr static u32 INVALID_HANDLE = MaxValue; - constexpr static u32 INDEX_MASK = 0x0FFFFFFF; - constexpr static u32 TYPE_MASK = ~INDEX_MASK; - constexpr static u32 TYPE_OFFSET = GetMaskOffset(TYPE_MASK); - u32 m_Internal = INVALID_HANDLE; - - // The only constructor requires a valid construction. - Handle(const u32 index, const u8 typeId) - : m_Internal{(index & INDEX_MASK) | ((typeId << TYPE_OFFSET) & TYPE_MASK)} - - { - AddRef(); - } - - friend Manager; - friend Ref; - - public: - [[nodiscard]] Ref - ToPointer() - { - return Ref{std::move(*this)}; - } - - [[nodiscard]] Type * - Fetch() const - { - return Manager::Instance()->Fetch(GetIndex()); - } - - [[nodiscard]] bool - IsValid() const - { - return m_Internal != INVALID_HANDLE; - } - - [[nodiscard]] u32 - GetIndex() const - { - return m_Internal & INDEX_MASK; - } - - [[nodiscard]] u32 - GetType() const - { - return (m_Internal & TYPE_MASK) >> TYPE_OFFSET; - } - - bool - operator==(const Handle &other) const - { - return m_Internal == other.m_Internal; - } - - Handle(const Handle &other) - { - m_Internal = other.m_Internal; - AddRef(); - } - - Handle(Handle &&other) noexcept - { - m_Internal = other.m_Internal; - other.m_Internal = INVALID_HANDLE; - } - - Handle & - operator=(const Handle &other) - { - if (this == &other) - return *this; - m_Internal = other.m_Internal; - AddRef(); - return *this; - } - - Handle & - operator=(Handle &&other) noexcept - { - if (this == &other) - return *this; - std::swap(m_Internal, other.m_Internal); - return *this; - } - - ~Handle() - { - if (m_Internal != INVALID_HANDLE) + memset(pAlloc, 0, sizeof *pAlloc); + if constexpr (concepts::SelfDestructible) { - Release(); + pAlloc->m_Device = m_Device; } - } - - protected: - void - AddRef() - { - Manager::Instance()->AddRef(GetIndex()); - } - - void - Release() - { - Manager::Instance()->Release(GetIndex()); + return {pAlloc}; } }; } // namespace systems - diff --git a/aster/include/aster/systems/render_resource_manager.h b/aster/include/aster/systems/render_resource_manager.h index 1a487b6..57b26fa 100644 --- a/aster/include/aster/systems/render_resource_manager.h +++ b/aster/include/aster/systems/render_resource_manager.h @@ -10,16 +10,250 @@ #include "image_manager.h" #include "sampler_manager.h" +#include "aster/util/intrusive_slist.h" + #include "EASTL/deque.h" -#include "EASTL/vector.h" -#include +#include "EASTL/intrusive_hash_map.h" +#include "EASTL/bonus/fixed_ring_buffer.h" namespace systems { +class RenderResourceManager; + +/** + * CommitEntry manages the lifetime of the committed resource. + * @tparam T Type of the committed resource. + */ +template +class CommitEntry +{ + private: + u32 m_Index; + + explicit CommitEntry(const u32 index) + : m_Index{index} + { + AddRef(); + } + + friend class RenderResourceManager; + + public: + CommitEntry(const CommitEntry &other) + : m_Index{other.m_Index} + { + AddRef(); + } + + CommitEntry(CommitEntry &&other) noexcept + : m_Index{other.m_Index} + { + AddRef(); + } + + CommitEntry & + operator=(const CommitEntry &other) + { + if (this == &other) + return *this; + m_Index = other.m_Index; + AddRef(); + return *this; + } + + CommitEntry & + operator=(CommitEntry &&other) noexcept + { + if (this == &other) + return *this; + m_Index = other.m_Index; + AddRef(); + return *this; + } + + ~CommitEntry() + { + Release(); + } + + private: + void AddRef() const; ///< Increases the refcount in the RenderResourceManager. + void Release() const; ///< Decreases the refcount in the RenderResourceManager. +}; + class RenderResourceManager { private: + template + struct HandleMapper + { + using Type = T; + using Manager = Manager; + using Handle = typename Manager::Handle; + using CommitE = CommitEntry; + + struct Entry : public eastl::intrusive_hash_node_key + { + std::atomic m_CommitCount; + + void + AddRef() + { + const auto rc = ++m_CommitCount; + assert(rc > 0); + } + + void + Release() + { + const auto rc = --m_CommitCount; + assert(rc < MaxValue); + } + + bool + IsReferenced() const + { + return m_CommitCount; + } + + bool + operator==(const Entry &other) const + { + return this->mKey == other.mKey; + } + + Entry * + Next() + { + return Recast(this->mpNext); + } + + void + SetNext(Entry &entry) + { + this->mpNext = &entry; + } + + struct Hash + { + usize + operator()(const Handle &e) + { + return eastl::hash()(e.get()); + } + }; + }; + static_assert(sizeof(Entry) == 24); + + eastl::vector m_Data; + IntrusiveStack m_FreeList; + eastl::intrusive_hash_map m_InUse; + std::array, 4> m_ToDelete; + u8 m_ToDeleteIndex = 0; + + explicit HandleMapper(const u32 maxCount) + : m_Data{maxCount} + { + // Setup freelist + for (auto it = m_Data.rbegin(); it != m_Data.rend(); ++it) + { + m_FreeList.Push(*it); + } + } + + ~HandleMapper() + { + for (auto & toDelete : m_ToDelete) + { + ClearEntries(toDelete); + } + } + + PIN_MEMORY(HandleMapper); + + /// Returns a commit, and a bool signifying if it is a new commit. + std::tuple + Create(const Handle &object) + { + // Get-from freelist + assert(!m_FreeList.Empty()); + + auto it = m_InUse.find(object); + if (it != m_InUse.end()) + { + it->AddRef(); + auto i = GetIndex(*it); + return {CommitE{i}, false}; + } + + Entry &data = m_FreeList.Pop(); + + data.mKey = object; + data.m_CommitCount = 1; + + m_InUse.insert(data); + + auto i = GetIndex(data); + + return {CommitE{i}, true}; + } + + void + AddRef(const CommitE &commit) + { + m_Data.at(commit.m_Index).AddRef(); + } + + void + Release(const CommitE &commit) + { + auto &entry = m_Data.at(commit.m_Index); + entry.Release(); + if (!entry.IsReferenced()) + { + QueueDelete(entry); + } + } + + /** + * Sweeps through the delete queue. + * All freed items are cleared. (With a 3 frame delay) + */ + void + Update() + { + m_ToDeleteIndex = (m_ToDeleteIndex + 1) % m_ToDelete.size(); + auto &list = m_ToDelete[m_ToDeleteIndex]; + ClearEntries(list); + } + + private: + u32 + GetIndex(const Entry &entry) + { + return Cast(&entry - m_Data.begin()); + } + + void + QueueDelete(Entry &entry) + { + m_InUse.remove(entry); + m_ToDelete[m_ToDeleteIndex].Push(entry); + } + + void + ClearEntries(IntrusiveStack& entries) + { + while (auto item = entries.TryPop()) + { + Entry &entry = item.value(); + entry.mKey.reset(); + entry.m_CommitCount = 0; + } + } + }; + union WriteInfo { vk::DescriptorBufferInfo uBufferInfo; vk::DescriptorImageInfo uImageInfo; @@ -32,68 +266,96 @@ class RenderResourceManager using WriteCommand = vk::WriteDescriptorSet; - //using WriteOwner = std::variant, Handle>; + // using WriteOwner = std::variant, Handle>; public: const Device *m_Device; - RenderResourceManager(const Device *device, u32 maxBuffers, u32 maxImages, u32 maxSamplers); + RenderResourceManager(const Device *device, u32 const maxBuffers, const u32 maxImages, + const SamplerHandle &defaultSampler); ~RenderResourceManager(); PIN_MEMORY(RenderResourceManager); - // Buffer - [[nodiscard]] BufferHandle CreateStorageBuffer(usize size, cstr name = nullptr); - [[nodiscard]] BufferHandle CreateUniformBuffer(usize size, cstr name = nullptr); - - void Write(const BufferHandle &handle, usize offset, usize size, const void *data) const; - void Commit(const BufferHandle &handle); - void Release(const BufferHandle &handle); - - - [[nodiscard]] ImageHandle CreateTexture2D(const Texture2DCreateInfo &createInfo); - [[nodiscard]] ImageHandle CreateTextureCube(const TextureCubeCreateInfo &createInfo); - [[nodiscard]] ImageHandle CreateAttachment(const AttachmentCreateInfo &createInfo); - [[nodiscard]] ImageHandle CreateDepthStencilImage(const DepthStencilImageCreateInfo &createInfo); - [[nodiscard]] SamplerHandle CreateSampler(const SamplerCreateInfo &createInfo); - - void Commit(const ImageHandle &handle); - void Commit(const ImageHandle &handle, const SamplerHandle &samplerHandle); + CommitEntry Commit(const BufferHandle &buffer); + CommitEntry Commit(const ImageHandle &handle); + CommitEntry Commit(const ImageHandle &image, const SamplerHandle &sampler); void Update(); - [[nodiscard]] const vk::DescriptorSetLayout& + [[nodiscard]] const vk::DescriptorSetLayout & GetDescriptorSetLayout() const { return m_SetLayout; } - [[nodiscard]] const vk::DescriptorSet& GetDescriptorSet() const + [[nodiscard]] const vk::DescriptorSet & + GetDescriptorSet() const { return m_DescriptorSet; } -private: - BufferManager m_BufferManager; - ImageManager m_ImageManager; - SamplerManager m_SamplerManager; + static RenderResourceManager * + Instance() + { + return m_Instance; + } + private: vk::DescriptorPool m_DescriptorPool; vk::DescriptorSetLayout m_SetLayout; vk::DescriptorSet m_DescriptorSet; constexpr static u8 BUFFER_BINDING_INDEX = 0x0; constexpr static u8 IMAGE_BINDING_INDEX = 0x1; - constexpr static u8 SAMPLER_TYPE_INDEX = 0xF; + + HandleMapper m_Buffers; + HandleMapper m_Images; + SamplerHandle m_DefaultSampler; eastl::vector m_Writes; eastl::deque m_WriteInfos; // eastl::vector m_WriteOwner; -#if !defined(ASTER_NDEBUG) - usize m_CommitedBufferCount = 0; - usize m_CommitedTextureCount = 0; - usize m_CommitedStorageTextureCount = 0; -#endif + static RenderResourceManager *m_Instance; + friend CommitEntry; + friend CommitEntry; + + void + AddRef(const CommitEntry &handle) + { + m_Buffers.AddRef(handle); + } + void + AddRef(const CommitEntry &handle) + { + m_Images.AddRef(handle); + } + + void + Release(const CommitEntry &handle) + { + m_Buffers.Release(handle); + } + void + Release(const CommitEntry &handle) + { + m_Images.Release(handle); + } }; + +template +void +CommitEntry::AddRef() const +{ + RenderResourceManager::Instance()->AddRef(*this); +} + +template +void +CommitEntry::Release() const +{ + RenderResourceManager::Instance()->Release(*this); +} + } // namespace systems \ No newline at end of file diff --git a/aster/include/aster/systems/sampler_manager.h b/aster/include/aster/systems/sampler_manager.h index 0a75d77..db8425a 100644 --- a/aster/include/aster/systems/sampler_manager.h +++ b/aster/include/aster/systems/sampler_manager.h @@ -12,7 +12,7 @@ namespace systems { -using SamplerHandle = Handle; +using SamplerHandle = Manager::Handle; struct SamplerCreateInfo : vk::SamplerCreateInfo { diff --git a/aster/include/aster/util/CMakeLists.txt b/aster/include/aster/util/CMakeLists.txt index 0d19944..242a09d 100644 --- a/aster/include/aster/util/CMakeLists.txt +++ b/aster/include/aster/util/CMakeLists.txt @@ -3,4 +3,4 @@ cmake_minimum_required(VERSION 3.13) target_sources(aster_core - INTERFACE "logger.h") + INTERFACE "logger.h" "intrusive_slist.h") diff --git a/aster/include/aster/util/intrusive_slist.h b/aster/include/aster/util/intrusive_slist.h new file mode 100644 index 0000000..e0ff4fe --- /dev/null +++ b/aster/include/aster/util/intrusive_slist.h @@ -0,0 +1,127 @@ +// ============================================= +// Aster: intrusive_slist.h +// Copyright (c) 2020-2024 Anish Bhobe +// ============================================= + +#pragma once + +#include + +template +concept HasNext = requires(T &a) { + { a.Next() } -> std::same_as; + { a.SetNext(a) }; +}; + +struct IntrusiveStackNode +{ + IntrusiveStackNode *m_Next; + + IntrusiveStackNode * + Next() const + { + return m_Next; + } + + void + SetNext(IntrusiveStackNode &a) + { + m_Next = &a; + } +}; + +template +struct IntrusiveStack +{ + using Value = T; + using Reference = T &; + using OptionalRef = std::optional>; + using ConstReference = const T &; + using Pointer = T *; + + Pointer m_Top; + + IntrusiveStack() + : m_Top{nullptr} + { + } + + IntrusiveStack(IntrusiveStack &&other) noexcept + : m_Top{Take(other.m_Top)} + { + } + + IntrusiveStack & + operator=(IntrusiveStack &&other) noexcept + { + if (this == &other) + return *this; + m_Top = Take(other.m_Top); + return *this; + } + + DISALLOW_COPY_AND_ASSIGN(IntrusiveStack); + + ~IntrusiveStack() + { + m_Top = nullptr; + } + + [[nodiscard]] bool + Empty() const + { + return !m_Top; + } + + [[nodiscard]] Reference + Pop() + { + assert(m_Top); + Reference ref = *m_Top; + m_Top = m_Top->Next(); + return ref; + } + + [[nodiscard]] OptionalRef + TryPop() + { + if (m_Top) + return Pop(); + return std::nullopt; + } + + void + Push(Reference ref) + { + ref.SetNext(*m_Top); + m_Top = &ref; + } + + [[nodiscard]] ConstReference + Peek() const + { + assert(m_Top); + return *m_Top; + } + + [[nodiscard]] Reference + Peek() + { + assert(m_Top); + return *m_Top; + } + + [[nodiscard]] OptionalRef + TryPeek() + { + if (m_Top) + return Peek(); + return std::nullopt; + } + + void + Clear() + { + m_Top = nullptr; + } +}; diff --git a/aster/src/aster/core/buffer.cpp b/aster/src/aster/core/buffer.cpp index a8fc1d2..2e64345 100644 --- a/aster/src/aster/core/buffer.cpp +++ b/aster/src/aster/core/buffer.cpp @@ -8,21 +8,22 @@ #include "core/device.h" void -Buffer::Destroy(const Device *device) +Buffer::Destroy() { - if (!IsValid() || !IsOwned()) + if (!m_Buffer) return; - vmaDestroyBuffer(device->m_Allocator, m_Buffer, m_Allocation); - m_Size_ = 0; + vmaDestroyBuffer(m_Device->m_Allocator, Take(m_Buffer), m_Allocation); + m_Size = 0; } void Buffer::Allocate(const Device *device, usize size, vk::BufferUsageFlags bufferUsage, VmaAllocationCreateFlags allocationFlags, VmaMemoryUsage memoryUsage, cstr name) { - assert(!IsValid()); - assert(size <= SIZE_MASK); + assert(!m_Buffer); + + m_Device = device; vk::BufferCreateInfo bufferCreateInfo = { .size = size, @@ -48,7 +49,7 @@ Buffer::Allocate(const Device *device, usize size, vk::BufferUsageFlags bufferUs // bool hostAccessible = Cast(memoryPropertyFlags & vk::MemoryPropertyFlagBits::eHostVisible); m_Buffer = buffer; - m_Size_ = size | VALID_BUFFER_BIT | OWNED_BIT; + m_Size = size; m_Allocation = allocation; m_Mapped = Cast(allocationInfo.pMappedData); @@ -56,28 +57,28 @@ Buffer::Allocate(const Device *device, usize size, vk::BufferUsageFlags bufferUs } uptr -Buffer::GetDeviceAddress(const Device *device) +Buffer::GetDeviceAddress(const Device *device) const { vk::BufferDeviceAddressInfo addressInfo = {.buffer = m_Buffer}; return device->m_Device.getBufferAddress(&addressInfo); } void -Buffer::Write(const Device *device, usize offset, usize size, const void *data) +Buffer::Write(usize offset, usize size, const void *data) { assert(IsHostVisible()); if (!IsMapped()) { void *mapped; - auto result = Cast(vmaMapMemory(device->m_Allocator, m_Allocation, &mapped)); + auto result = Cast(vmaMapMemory(m_Device->m_Allocator, m_Allocation, &mapped)); ERROR_IF(Failed(result), "Memory mapping failed. Cause: {}", result); if (!Failed(result)) { m_Mapped = Cast(mapped); memcpy(m_Mapped + offset, data, size); - vmaUnmapMemory(device->m_Allocator, m_Allocation); + vmaUnmapMemory(m_Device->m_Allocator, m_Allocation); m_Mapped = nullptr; } } diff --git a/aster/src/aster/core/image.cpp b/aster/src/aster/core/image.cpp index df895d1..4ae8f09 100644 --- a/aster/src/aster/core/image.cpp +++ b/aster/src/aster/core/image.cpp @@ -8,16 +8,13 @@ #include "core/device.h" void -Image::Destroy(const Device *device) +Image::Destroy() { - if (!IsValid() || !IsOwned()) - { - m_Flags_ = 0; + if (!IsValid()) return; - } - device->m_Device.destroy(m_View, nullptr); - vmaDestroyImage(device->m_Allocator, m_Image, m_Allocation); + m_Device->m_Device.destroy(m_View, nullptr); + vmaDestroyImage(m_Device->m_Allocator, Take(m_Image), m_Allocation); m_Flags_ = 0; } @@ -77,11 +74,11 @@ Texture::Init(const Device *device, const vk::Extent2D extent, vk::Format imageF result = device->m_Device.createImageView(&imageViewCreateInfo, nullptr, &view); ERROR_IF(Failed(result), "Could not create image view {}. Cause: {}", name, result) THEN_ABORT(result); + m_Device = device; m_Image = image; m_View = view; m_Allocation = allocation; m_Extent = imageCreateInfo.extent; - m_Flags_ = OWNED_BIT | VALID_BIT; m_LayerCount = 1; m_MipLevels = mipLevels; @@ -109,7 +106,8 @@ Remember, we use upside down viewport. void TextureCube::Init(const Device *device, u32 cubeSide, vk::Format imageFormat, bool isMipMapped, cstr name) { - WARN_IF(!IsPowerOfTwo(cubeSide), "Image Cube {1} has side {0}x{0} (Non Power of Two)", cubeSide, name ? name : ""); + WARN_IF(!IsPowerOfTwo(cubeSide), "Image Cube {1} has side {0}x{0} (Non Power of Two)", cubeSide, + name ? name : ""); const u8 mipLevels = isMipMapped ? 1 + Cast(floor(log2(cubeSide))) : 1; @@ -163,12 +161,12 @@ TextureCube::Init(const Device *device, u32 cubeSide, vk::Format imageFormat, bo result = device->m_Device.createImageView(&imageViewCreateInfo, nullptr, &view); ERROR_IF(Failed(result), "Could not create image view {}. Cause: {}", name, result) THEN_ABORT(result); + m_Device = device; m_Image = image; m_View = view; m_Allocation = allocation; m_Extent = extent; m_MipLevels = mipLevels; - m_Flags_ = OWNED_BIT | VALID_BIT; m_LayerCount = 6; device->SetName(m_Image, name); @@ -218,12 +216,12 @@ AttachmentImage::Init(const Device *device, vk::Extent2D extent, vk::Format imag result = device->m_Device.createImageView(&imageViewCreateInfo, nullptr, &view); ERROR_IF(Failed(result), "Could not create attachment image view {}. Cause: {}", name, result) THEN_ABORT(result); + m_Device = device; m_Image = image; m_View = view; m_Allocation = allocation; m_Extent = imageCreateInfo.extent; m_MipLevels = 1; - m_Flags_ = OWNED_BIT | VALID_BIT; m_LayerCount = 1; device->SetName(m_Image, name); @@ -274,12 +272,12 @@ DepthImage::Init(const Device *device, vk::Extent2D extent, cstr name) result = device->m_Device.createImageView(&imageViewCreateInfo, nullptr, &view); ERROR_IF(Failed(result), "Could not create depth image view {}. Cause: {}", name, result) THEN_ABORT(result); + m_Device = device; m_Image = image; m_View = view; m_Allocation = allocation; m_Extent = imageCreateInfo.extent; m_MipLevels = 1; - m_Flags_ = OWNED_BIT | VALID_BIT; m_LayerCount = 1; device->SetName(m_Image, name); @@ -342,12 +340,12 @@ StorageTexture::Init(const Device *device, vk::Extent2D extent, const vk::Format result = device->m_Device.createImageView(&imageViewCreateInfo, nullptr, &view); ERROR_IF(Failed(result), "Could not create image view {}. Cause: {}", name, result) THEN_ABORT(result); + m_Device = device; m_Image = image; m_View = view; m_Allocation = allocation; m_Extent = imageCreateInfo.extent; m_MipLevels = 1; - m_Flags_ = OWNED_BIT | VALID_BIT; m_LayerCount = 1; device->SetName(m_Image, name); @@ -413,12 +411,12 @@ StorageTextureCube::Init(const Device *device, u32 cubeSide, vk::Format imageFor result = device->m_Device.createImageView(&imageViewCreateInfo, nullptr, &view); ERROR_IF(Failed(result), "Could not create image view {}. Cause: {}", name, result) THEN_ABORT(result); + m_Device = device; m_Image = image; m_View = view; m_Allocation = allocation; m_Extent = imageCreateInfo.extent; m_MipLevels = mipLevels; - m_Flags_ = OWNED_BIT | VALID_BIT; m_LayerCount = 6; device->SetName(m_Image, name); diff --git a/aster/src/aster/systems/buffer_manager.cpp b/aster/src/aster/systems/buffer_manager.cpp index 5013de3..acb67f2 100644 --- a/aster/src/aster/systems/buffer_manager.cpp +++ b/aster/src/aster/systems/buffer_manager.cpp @@ -12,7 +12,7 @@ Manager *Manager::m_Instance = nullptr; BufferHandle BufferManager::CreateStorageBuffer(const usize size, const cstr name) { - auto [handle, object] = Alloc(); + auto object = Alloc(); // TODO: Storage and Index buffer are set. // This is hacky and should be improved. @@ -24,13 +24,13 @@ BufferManager::CreateStorageBuffer(const usize size, const cstr name) constexpr VmaMemoryUsage memoryUsage = VMA_MEMORY_USAGE_AUTO; object->Allocate(m_Device, size, usage, createFlags, memoryUsage, name); - return std::move(handle); + return object; } Manager::Handle BufferManager::CreateUniformBuffer(const usize size, const cstr name) { - auto [handle, object] = Alloc(); + auto object = Alloc(); constexpr vk::BufferUsageFlags usage = vk::BufferUsageFlagBits::eUniformBuffer; constexpr VmaAllocationCreateFlags createFlags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | @@ -39,7 +39,7 @@ BufferManager::CreateUniformBuffer(const usize size, const cstr name) constexpr VmaMemoryUsage memoryUsage = VMA_MEMORY_USAGE_AUTO; object->Allocate(m_Device, size, usage, createFlags, memoryUsage, name); - return std::move(handle); + return object; } BufferManager::BufferManager(const Device *device, const u32 maxCount, const u8 binding) diff --git a/aster/src/aster/systems/image_manager.cpp b/aster/src/aster/systems/image_manager.cpp index 4a0e3d1..8d65144 100644 --- a/aster/src/aster/systems/image_manager.cpp +++ b/aster/src/aster/systems/image_manager.cpp @@ -61,18 +61,17 @@ ImageManager::CreateTexture2D(const Texture2DCreateInfo &createInfo) ERROR_IF(Failed(result), "Could not create image view {}. Cause: {}", createInfo.m_Name, result) THEN_ABORT(result); - auto [handle, object] = Alloc(); + auto object = Alloc(); object->m_Image = image; object->m_View = view; object->m_Allocation = allocation; object->m_Extent = imageCreateInfo.extent; - object->m_Flags_ = Image::OWNED_BIT | Image::VALID_BIT; object->m_LayerCount = Cast(imageCreateInfo.arrayLayers); object->m_MipLevels = Cast(imageCreateInfo.mipLevels); m_Device->SetName(object->m_Image, createInfo.m_Name); - return handle; + return object; } ImageHandle @@ -109,18 +108,17 @@ ImageManager::CreateTextureCube(const TextureCubeCreateInfo &createInfo) ERROR_IF(Failed(result), "Could not create image view {}. Cause: {}", createInfo.m_Name, result) THEN_ABORT(result); - auto [handle, object] = Alloc(); + auto object = Alloc(); object->m_Image = image; object->m_View = view; object->m_Allocation = allocation; object->m_Extent = imageCreateInfo.extent; - object->m_Flags_ = Image::OWNED_BIT | Image::VALID_BIT; object->m_LayerCount = Cast(imageCreateInfo.arrayLayers); object->m_MipLevels = Cast(imageCreateInfo.mipLevels); m_Device->SetName(object->m_Image, createInfo.m_Name); - return handle; + return object; } ImageHandle @@ -157,18 +155,17 @@ ImageManager::CreateAttachment(const AttachmentCreateInfo &createInfo) ERROR_IF(Failed(result), "Could not create image view {}. Cause: {}", createInfo.m_Name, result) THEN_ABORT(result); - auto [handle, object] = Alloc(); + auto object = Alloc(); object->m_Image = image; object->m_View = view; object->m_Allocation = allocation; object->m_Extent = imageCreateInfo.extent; - object->m_Flags_ = Image::OWNED_BIT | Image::VALID_BIT; object->m_LayerCount = Cast(imageCreateInfo.arrayLayers); object->m_MipLevels = Cast(imageCreateInfo.mipLevels); m_Device->SetName(object->m_Image, createInfo.m_Name); - return handle; + return object; } ImageHandle @@ -205,18 +202,17 @@ ImageManager::CreateDepthStencilImage(const DepthStencilImageCreateInfo &createI ERROR_IF(Failed(result), "Could not create image view {}. Cause: {}", createInfo.m_Name, result) THEN_ABORT(result); - auto [handle, object] = Alloc(); + auto object = Alloc(); object->m_Image = image; object->m_View = view; object->m_Allocation = allocation; object->m_Extent = imageCreateInfo.extent; - object->m_Flags_ = Image::OWNED_BIT | Image::VALID_BIT; object->m_LayerCount = Cast(imageCreateInfo.arrayLayers); object->m_MipLevels = Cast(imageCreateInfo.mipLevels); m_Device->SetName(object->m_Image, createInfo.m_Name); - return handle; + return object; } vk::ImageCreateInfo diff --git a/aster/src/aster/systems/render_resource_manager.cpp b/aster/src/aster/systems/render_resource_manager.cpp index 3862f51..7e765d8 100644 --- a/aster/src/aster/systems/render_resource_manager.cpp +++ b/aster/src/aster/systems/render_resource_manager.cpp @@ -5,8 +5,8 @@ #include "systems/render_resource_manager.h" -#include "core/device.h" #include "EASTL/array.h" +#include "core/device.h" #define AbortIfFailed(RESULT) \ do \ @@ -33,13 +33,17 @@ using namespace systems; +RenderResourceManager *RenderResourceManager::m_Instance = nullptr; + RenderResourceManager::RenderResourceManager(const Device *device, u32 const maxBuffers, const u32 maxImages, - const u32 maxSamplers) + const SamplerHandle &defaultSampler) : m_Device{device} - , m_BufferManager{device, maxBuffers, BUFFER_BINDING_INDEX} - , m_ImageManager{device, maxImages, IMAGE_BINDING_INDEX} - , m_SamplerManager{device, maxSamplers, SAMPLER_TYPE_INDEX} + , m_Buffers{maxBuffers} + , m_Images{maxImages} + , m_DefaultSampler{defaultSampler} { + assert(!m_Instance); + eastl::array poolSizes = { vk::DescriptorPoolSize{ .type = vk::DescriptorType::eStorageBuffer, @@ -117,110 +121,70 @@ RenderResourceManager::RenderResourceManager(const Device *device, u32 const max device->SetName(m_SetLayout, "Bindless Layout"); device->SetName(m_DescriptorPool, "Bindless Pool"); device->SetName(m_DescriptorSet, "Bindless Set"); + + m_Instance = this; } RenderResourceManager::~RenderResourceManager() { - -#if !defined(ASTER_NDEBUG) - WARN_IF(m_CommitedBufferCount > 0 || m_CommitedTextureCount > 0 || m_CommitedStorageTextureCount > 0, - "Resources alive: SSBO = {}, Textures = {}, RWTexture = {}", m_CommitedBufferCount, m_CommitedTextureCount, - m_CommitedStorageTextureCount); -#endif - m_Device->m_Device.destroy(m_SetLayout, nullptr); m_Device->m_Device.destroy(m_DescriptorPool, nullptr); -} -void -RenderResourceManager::Write(const BufferHandle &handle, const usize offset, const usize size, const void *data) const -{ - handle.Fetch()->Write(m_Device, offset, size, data); -} - -BufferHandle RenderResourceManager::CreateStorageBuffer(const usize size, const cstr name) -{ - return m_BufferManager.CreateStorageBuffer(size, name); -} - -BufferHandle -RenderResourceManager::CreateUniformBuffer(const usize size, const cstr name) -{ - return m_BufferManager.CreateUniformBuffer(size, name); -} - -ImageHandle -RenderResourceManager::CreateTexture2D(const Texture2DCreateInfo &createInfo) -{ - return m_ImageManager.CreateTexture2D(createInfo); -} - -ImageHandle -RenderResourceManager::CreateTextureCube(const TextureCubeCreateInfo &createInfo) -{ - return m_ImageManager.CreateTextureCube(createInfo); -} - -ImageHandle -RenderResourceManager::CreateAttachment(const AttachmentCreateInfo &createInfo) -{ - return m_ImageManager.CreateAttachment(createInfo); -} - -ImageHandle -RenderResourceManager::CreateDepthStencilImage(const DepthStencilImageCreateInfo &createInfo) -{ - return m_ImageManager.CreateDepthStencilImage(createInfo); -} - -void -RenderResourceManager::Commit(const BufferHandle &handle) -{ - Buffer *buffer = handle.Fetch(); - if (buffer->IsCommitted()) +#if !defined(ASTER_NDEBUG) + u32 bufferCount = 0; + for (const auto &entry : m_Buffers.m_Data) { - WARN("Buffer is already committed"); - return; + bufferCount += entry.m_CommitCount; } + u32 imageCount = 0; + for (const auto &entry : m_Images.m_Data) + { + imageCount += entry.m_CommitCount; + } + if (bufferCount > 0 || imageCount > 0) + { + WARN("Committed resources at destruction. Buffers: {}, Images: {}", bufferCount, imageCount); + } +#endif +} + +CommitEntry +RenderResourceManager::Commit(const BufferHandle &buffer) +{ + auto [commit, isNew] = m_Buffers.Create(buffer); + + if (!isNew) + return commit; m_WriteInfos.emplace_back(vk::DescriptorBufferInfo{ .buffer = buffer->m_Buffer, .offset = 0, - .range = buffer->GetSize(), + .range = buffer->m_Size, }); m_Writes.push_back({ .dstSet = m_DescriptorSet, .dstBinding = BUFFER_BINDING_INDEX, - .dstArrayElement = handle.GetIndex(), + .dstArrayElement = commit.m_Index, .descriptorCount = 1, .descriptorType = vk::DescriptorType::eStorageBuffer, .pBufferInfo = &m_WriteInfos.back().uBufferInfo, }); - buffer->SetCommitted(true); -#if !defined(ASTER_NDEBUG) - ++m_CommitedBufferCount; -#endif + return commit; } -void +CommitEntry RenderResourceManager::Commit(const ImageHandle &handle) { - const auto sampler = m_SamplerManager.Create({}); - Commit(handle, sampler); + return Commit(handle, m_DefaultSampler); } -void -RenderResourceManager::Commit(const ImageHandle &handle, const SamplerHandle &samplerHandle) +CommitEntry +RenderResourceManager::Commit(const ImageHandle &image, const SamplerHandle &sampler) { - Image *image = handle.Fetch(); - if (image->IsCommitted()) - { - WARN("Image is already committed"); - return; - } - - Sampler *sampler = samplerHandle.Fetch(); + auto [commit, isNew] = m_Images.Create(image); + if (!isNew) + return commit; m_WriteInfos.emplace_back(vk::DescriptorImageInfo{ .sampler = sampler->m_Sampler, @@ -230,17 +194,13 @@ RenderResourceManager::Commit(const ImageHandle &handle, const SamplerHandle &sa m_Writes.push_back({ .dstSet = m_DescriptorSet, .dstBinding = IMAGE_BINDING_INDEX, - .dstArrayElement = handle.GetIndex(), + .dstArrayElement = commit.m_Index, .descriptorCount = 1, .descriptorType = vk::DescriptorType::eCombinedImageSampler, .pImageInfo = &m_WriteInfos.back().uImageInfo, }); - image->SetCommitted(true); - sampler->SetCommitted(true); -#if !defined(ASTER_NDEBUG) - ++m_CommitedTextureCount; -#endif + return commit; } RenderResourceManager::WriteInfo::WriteInfo(const vk::DescriptorBufferInfo &info) @@ -258,12 +218,6 @@ RenderResourceManager::WriteInfo::WriteInfo(const vk::BufferView &info) { } -SamplerHandle -RenderResourceManager::CreateSampler(const SamplerCreateInfo &createInfo) -{ - return m_SamplerManager.Create(createInfo); -} - void RenderResourceManager::Update() { @@ -275,4 +229,7 @@ RenderResourceManager::Update() m_Writes.clear(); m_WriteInfos.clear(); } + + m_Buffers.Update(); + m_Images.Update(); } diff --git a/aster/src/aster/systems/sampler_manager.cpp b/aster/src/aster/systems/sampler_manager.cpp index 0d27449..c93080c 100644 --- a/aster/src/aster/systems/sampler_manager.cpp +++ b/aster/src/aster/systems/sampler_manager.cpp @@ -56,11 +56,11 @@ SamplerManager::Create(const SamplerCreateInfo &createInfo) return iter->second; } - auto [handle, object] = Alloc(); + auto object = Alloc(); object->Init(m_Device, createInfo, createInfo.m_Name ? createInfo.m_Name : nullptr); - m_HashToSamplerIdx.emplace(hash, handle); + m_HashToSamplerIdx.emplace(hash, object); - return handle; + return object; } diff --git a/aster/src/aster/util/CMakeLists.txt b/aster/src/aster/util/CMakeLists.txt index 642cdda..6803276 100644 --- a/aster/src/aster/util/CMakeLists.txt +++ b/aster/src/aster/util/CMakeLists.txt @@ -2,4 +2,4 @@ cmake_minimum_required(VERSION 3.13) -target_sources(aster_core PRIVATE "logger.cpp") +target_sources(aster_core PRIVATE "logger.cpp" ) diff --git a/samples/01_triangle/triangle.cpp b/samples/01_triangle/triangle.cpp index 52ea71c..ce7ed4d 100644 --- a/samples/01_triangle/triangle.cpp +++ b/samples/01_triangle/triangle.cpp @@ -122,7 +122,7 @@ main(int, char **) { StagingBuffer staging; staging.Init(&device, vertices.size() * sizeof vertices[0], "Staging"); - staging.Write(&device, 0, vertices.size() * sizeof vertices[0], vertices.data()); + staging.Write(0, vertices.size() * sizeof vertices[0], vertices.data()); vk::Fence fence; vk::FenceCreateInfo fenceCreateInfo = {}; @@ -133,7 +133,7 @@ main(int, char **) result = copyBuffer.begin(&beginInfo); ERROR_IF(Failed(result), "Copy begin failed. Cause: {}", result) THEN_ABORT(result); - vk::BufferCopy bufferCopy = {.srcOffset = 0, .dstOffset = 0, .size = staging.GetSize()}; + vk::BufferCopy bufferCopy = {.srcOffset = 0, .dstOffset = 0, .size = staging.m_Size}; copyBuffer.copyBuffer(staging.m_Buffer, vbo.m_Buffer, 1, &bufferCopy); result = copyBuffer.end(); @@ -154,7 +154,7 @@ main(int, char **) ERROR_IF(Failed(result), "Couldn't reset command pool. Cause: {}", result) THEN_ABORT(result); device.m_Device.destroy(fence, nullptr); - staging.Destroy(&device); + staging.Destroy(); } // Persistent variables @@ -352,7 +352,7 @@ main(int, char **) device.WaitIdle(); device.m_Device.destroy(copyPool, nullptr); - vbo.Destroy(&device); + vbo.Destroy(); return 0; } diff --git a/samples/02_box/box.cpp b/samples/02_box/box.cpp index a620743..fd2d5f1 100644 --- a/samples/02_box/box.cpp +++ b/samples/02_box/box.cpp @@ -128,7 +128,12 @@ main(int, char **) Device device = {&context, &deviceToUse, &enabledDeviceFeatures, {queueAllocation}, "Primary Device"}; vk::Queue commandQueue = device.GetQueue(queueAllocation.m_Family, 0); Swapchain swapchain = {&surface, &device, window.GetSize(), "Primary Chain"}; - systems::RenderResourceManager renderResourceManager{&device, 12, 12, 1}; + + systems::BufferManager bufferManager{&device, 12, 0}; + systems::ImageManager imageManager{&device, 12, 1}; + systems::SamplerManager samplerManager{&device, 1, 0xF}; + + systems::RenderResourceManager renderResourceManager{&device, 12, 12, samplerManager.Create({})}; Pipeline pipeline = CreatePipeline(&renderResourceManager, &swapchain); @@ -206,22 +211,21 @@ main(int, char **) assert(loaded); INFO("Image {}x{} : {} channels", imageFile.m_Width, imageFile.m_Height, imageFile.m_NumChannels); - auto vbo = renderResourceManager.CreateStorageBuffer(vertices.size() * sizeof vertices[0], "Vertex Buffer"); - renderResourceManager.Write(vbo, 0, vertices.size() * sizeof vertices[0], vertices.data()); + auto vbo = bufferManager.CreateStorageBuffer(vertices.size() * sizeof vertices[0], "Vertex Buffer"); + vbo->Write(0, vertices.size() * sizeof vertices[0], vertices.data()); - auto crate = renderResourceManager + auto crate = imageManager .CreateTexture2D({ .m_Format = vk::Format::eR8G8B8A8Srgb, .m_Extent = {imageFile.m_Width, imageFile.m_Height}, .m_Name = "Crate Texture", - }) - .ToPointer(); + }); { StagingBuffer imageStaging; imageStaging.Init(&device, imageFile.GetSize(), "Image Staging"); - imageStaging.Write(&device, 0, imageFile.GetSize(), imageFile.m_Data); + imageStaging.Write(0, imageFile.GetSize(), imageFile.m_Data); vk::ImageMemoryBarrier2 imageReadyToWrite = { .srcStageMask = vk::PipelineStageFlagBits2::eTransfer, @@ -315,17 +319,11 @@ main(int, char **) AbortIfFailedM(device.m_Device.resetCommandPool(copyPool, {}), "Couldn't reset command pool."); device.m_Device.destroy(fence, nullptr); - imageStaging.Destroy(&device); + imageStaging.Destroy(); } - auto ubo = renderResourceManager.CreateStorageBuffer(sizeof camera, "Camera UBO"); - renderResourceManager.Write(ubo, 0, sizeof camera, &camera); - - renderResourceManager.Commit(ubo); - renderResourceManager.Commit(vbo); - renderResourceManager.Commit(crate); - - renderResourceManager.Update(); + auto ubo = bufferManager.CreateStorageBuffer(sizeof camera, "Camera UBO"); + ubo->Write(0, sizeof camera, &camera); // Persistent variables vk::Viewport viewport = { @@ -391,13 +389,13 @@ main(int, char **) }; FrameManager frameManager = {&device, queueAllocation.m_Family, MAX_FRAMES_IN_FLIGHT}; - eastl::fixed_vector, MAX_FRAMES_IN_FLIGHT> depthImages; + eastl::fixed_vector depthImages; - auto initDepthImages = [&depthImages, &frameManager, &renderResourceManager](const vk::Extent2D extent) { + auto initDepthImages = [&depthImages, &frameManager, &imageManager](const vk::Extent2D extent) { for (u32 i = 0; i < frameManager.m_FramesInFlight; ++i) { depthImages.push_back( - renderResourceManager.CreateDepthStencilImage({.m_Extent = extent, .m_Name = "Depth"}).ToPointer()); + imageManager.CreateDepthStencilImage({.m_Extent = extent, .m_Name = "Depth"})); } }; @@ -411,15 +409,15 @@ main(int, char **) struct PCB { - systems::BufferHandle m_Camera; - systems::BufferHandle m_VertexBuffer; - systems::ImageHandle m_Texture; + systems::CommitEntry m_Camera; + systems::CommitEntry m_VertexBuffer; + systems::CommitEntry m_Texture; }; PCB pcb = { - .m_Camera = std::move(ubo), - .m_VertexBuffer = std::move(vbo), - .m_Texture = std::move(crate), + .m_Camera = renderResourceManager.Commit(ubo), + .m_VertexBuffer = renderResourceManager.Commit(vbo), + .m_Texture = renderResourceManager.Commit(crate), }; Time::Init(); @@ -428,9 +426,10 @@ main(int, char **) while (window.Poll()) { Time::Update(); + renderResourceManager.Update(); camera.m_Model *= rotate(mat4{1.0f}, Cast(45.0_deg * Time::m_Delta), vec3(0.0f, 1.0f, 0.0f)); - renderResourceManager.Write(pcb.m_Camera, 0, sizeof camera, &camera); + ubo->Write(0, sizeof camera, &camera); Frame *currentFrame = frameManager.GetNextFrame(&swapchain, &surface, window.GetSize()); diff --git a/samples/CMakeLists.txt b/samples/CMakeLists.txt index e7456b4..33fa944 100644 --- a/samples/CMakeLists.txt +++ b/samples/CMakeLists.txt @@ -5,5 +5,5 @@ cmake_minimum_required(VERSION 3.13) add_subdirectory("00_util") add_subdirectory("01_triangle") add_subdirectory("02_box") -add_subdirectory("03_model_render") -add_subdirectory("04_scenes") +# add_subdirectory("03_model_render") +# add_subdirectory("04_scenes")