From 300fa7449c3efa2f2916f9a2c5f7401cdead9462 Mon Sep 17 00:00:00 2001 From: Anish Bhobe Date: Sun, 23 Feb 2025 00:05:15 +0100 Subject: [PATCH] Moved BufferManager to handles again. --- aster/include/aster/CMakeLists.txt | 1 + aster/include/aster/systems/buffer_manager.h | 5 +- aster/include/aster/systems/manager.h | 306 ++++++++++++++----- 3 files changed, 232 insertions(+), 80 deletions(-) diff --git a/aster/include/aster/CMakeLists.txt b/aster/include/aster/CMakeLists.txt index eb3e272..928e8f0 100644 --- a/aster/include/aster/CMakeLists.txt +++ b/aster/include/aster/CMakeLists.txt @@ -3,6 +3,7 @@ cmake_minimum_required(VERSION 3.13) add_subdirectory("core") +add_subdirectory("systems") add_subdirectory("util") target_sources(aster_core diff --git a/aster/include/aster/systems/buffer_manager.h b/aster/include/aster/systems/buffer_manager.h index 1f66a8e..6447c11 100644 --- a/aster/include/aster/systems/buffer_manager.h +++ b/aster/include/aster/systems/buffer_manager.h @@ -11,11 +11,14 @@ namespace systems { + +using BufferHandle = Handle; + class BufferManager final : public Manager { public: BufferManager(const Device *device, const u32 maxCount); - Ref CreateStorageBuffer(usize size, cstr name = nullptr); + Handle CreateStorageBuffer(usize size, cstr name = nullptr); }; } // namespace systems diff --git a/aster/include/aster/systems/manager.h b/aster/include/aster/systems/manager.h index becd42f..ee6c954 100644 --- a/aster/include/aster/systems/manager.h +++ b/aster/include/aster/systems/manager.h @@ -7,55 +7,53 @@ #include "aster/aster.h" -#include - struct Device; + template - requires std::is_default_constructible_v +concept IsDeviceDestructible = requires(T a, Device *p) { + { a.Destroy(p) } -> std::convertible_to; +}; + +template + requires IsDeviceDestructible +class Handle; + +template + requires std::is_default_constructible_v && IsDeviceDestructible class Manager { - using InternalType = T; + friend Handle; public: - struct Type : InternalType + using Type = T; + using Handle = Handle; + static_assert(sizeof(Handle) == sizeof(u32)); + + static Manager * + Instance() { - void - AddRef() - { - m_Instance->AddRef(this); - } + assert(m_Instance); - void - Release() - { - m_Instance->Release(this); - } - - u32 - GetIndex() - { - return m_Instance->GetIndex(this); - } - }; - static_assert(sizeof(Type) == sizeof(InternalType)); - - using Ref = eastl::intrusive_ptr; - - static Manager *Instance(); + return m_Instance; + } explicit Manager(const Device *device, const u32 maxCount) : m_MaxCount{maxCount} , m_FreeHead{0} , m_Device{device} { + assert(!m_Instance); + m_Data = new Type[m_MaxCount]; - m_RefCount = new u32[m_MaxCount]; + m_RefCount = new std::atomic[m_MaxCount]; for (u32 i = 0; i < m_MaxCount; ++i) { - m_RefCount[i] = (i + 1); + *Recast(&m_Data[i]) = (i + 1); } + + m_Instance = this; } virtual ~Manager() @@ -79,69 +77,219 @@ class Manager PIN_MEMORY(Manager); - void - AddRef(Type *p) - { - auto index = GetIndex(p); - - ++m_RefCount[index]; - } - - void - Release(Type *p) - { - assert(p->IsValid()); - - auto index = GetIndex(p); - - auto rc = --m_RefCount[index]; - - // Overflow case. - assert(rc != MaxValue); - if (rc == 0) - { - p->Destroy(m_Device); - - m_RefCount[index] = m_FreeHead; - m_FreeHead = index; - } - } - - u32 - GetIndex(Type *p) - { - auto index = p - m_Data; - assert(index >= 0 && index < m_MaxCount); - - return Cast(index); - } - private: - Type *m_Data = nullptr; - u32 *m_RefCount = nullptr; + Type *m_Data = nullptr; // Data also keeps the freelist during 'not use'. + std::atomic *m_RefCount = nullptr; u32 m_MaxCount = 0; u32 m_FreeHead = 0; static Manager *m_Instance; + void + AddRef(const u32 index) + { + assert(index < m_MaxCount); + ++m_RefCount[index]; + } + + void + Release(const u32 index) + { + assert(index < m_MaxCount); + const u32 rc = --m_RefCount[index]; + assert(rc != MaxValue); + if (rc == 0) + { + m_Data[index].Destroy(m_Device); + } + } + + Type * + Fetch(const u32 index) + { + assert(index < m_MaxCount); + return &m_Data[index]; + } + protected: const Device *m_Device; - void - SetInstance(Manager *instance) - { - assert(!m_Instance); - m_Instance = instance; - } - - Ref + std::pair Alloc() { ERROR_IF(m_FreeHead >= m_MaxCount, "Max buffers allocated.") THEN_ABORT(-1); const auto index = m_FreeHead; - m_FreeHead = m_RefCount[index]; - m_RefCount[index] = 0; - return Ref{&m_Data[index]}; + Type *pAlloc = &m_Data[index]; + m_FreeHead = *Recast(pAlloc); + return {Handle{index}, pAlloc}; + } +}; + +template + requires IsDeviceDestructible +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 * + Get() + { + assert(m_Pointer); + return m_Pointer; + } + + const Type * + Get() const + { + assert(m_Pointer); + return m_Pointer; + } + + Type * + operator->() + { + return Get(); + } + + const Type * + operator->() const + { + return Get(); + } + + Type & + operator*() + { + return *Get(); + } + + const Type & + operator*() const + { + return Get(); + } + + // The only constructor requires a valid construction. + explicit Ref(Handle &&handle) + : m_Handle{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 + requires IsDeviceDestructible +class Handle +{ + public: + using Type = T; + using Manager = Manager; + + protected: + constexpr static u32 INVALID_HANDLE = MaxValue; + u32 m_Internal = INVALID_HANDLE; + + // The only constructor requires a valid construction. + explicit Handle(const u32 index) + : m_Internal{index} + { + AddRef(); + } + + friend Manager; + friend Ref; + + public: + Handle(const Handle &other) + : m_Internal(other.m_Internal) + { + AddRef(); + } + + Handle(Handle &&other) noexcept + { + std::swap(this->m_Internal, other.m_Internal); + } + + 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) + { + Release(); + } + } + + Ref + ToPointer() + { + return Ref{std::move(*this)}; + } + + protected: + void + AddRef() + { + Manager::Instance()->AddRef(m_Internal); + } + + void + Release() + { + Manager::Instance()->Release(m_Internal); + } + + Type * + Fetch() + { + return Manager::Instance()->Fetch(m_Internal); } };