Moved BufferManager to handles again.

This commit is contained in:
Anish Bhobe 2025-02-23 00:05:15 +01:00
parent 058a6512ea
commit 300fa7449c
3 changed files with 232 additions and 80 deletions

View File

@ -3,6 +3,7 @@
cmake_minimum_required(VERSION 3.13)
add_subdirectory("core")
add_subdirectory("systems")
add_subdirectory("util")
target_sources(aster_core

View File

@ -11,11 +11,14 @@
namespace systems
{
using BufferHandle = Handle<Buffer>;
class BufferManager final : public Manager<Buffer>
{
public:
BufferManager(const Device *device, const u32 maxCount);
Ref CreateStorageBuffer(usize size, cstr name = nullptr);
Handle CreateStorageBuffer(usize size, cstr name = nullptr);
};
} // namespace systems

View File

@ -7,55 +7,53 @@
#include "aster/aster.h"
#include <EASTL/intrusive_ptr.h>
struct Device;
template <typename T>
requires std::is_default_constructible_v<T>
concept IsDeviceDestructible = requires(T a, Device *p) {
{ a.Destroy(p) } -> std::convertible_to<void>;
};
template <typename T>
requires IsDeviceDestructible<T>
class Handle;
template <typename T>
requires std::is_default_constructible_v<T> && IsDeviceDestructible<T>
class Manager
{
using InternalType = T;
friend Handle<T>;
public:
struct Type : InternalType
using Type = T;
using Handle = Handle<Type>;
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<Type>;
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<u32>[m_MaxCount];
for (u32 i = 0; i < m_MaxCount; ++i)
{
m_RefCount[i] = (i + 1);
*Recast<u32 *>(&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<u32>);
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<u32>(index);
}
private:
Type *m_Data = nullptr;
u32 *m_RefCount = nullptr;
Type *m_Data = nullptr; // Data also keeps the freelist during 'not use'.
std::atomic<u32> *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<u32>);
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<Handle, Type *>
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<u32 *>(pAlloc);
return {Handle{index}, pAlloc};
}
};
template <typename T>
requires IsDeviceDestructible<T>
class Ref
{
public:
using Type = T;
using Handle = Handle<Type>;
using Manager = Manager<Type>;
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 <typename T>
requires IsDeviceDestructible<T>
class Handle
{
public:
using Type = T;
using Manager = Manager<Type>;
protected:
constexpr static u32 INVALID_HANDLE = MaxValue<u32>;
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<T>;
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<T>
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);
}
};