Moved BufferManager to handles again.
This commit is contained in:
parent
058a6512ea
commit
300fa7449c
|
|
@ -3,6 +3,7 @@
|
||||||
cmake_minimum_required(VERSION 3.13)
|
cmake_minimum_required(VERSION 3.13)
|
||||||
|
|
||||||
add_subdirectory("core")
|
add_subdirectory("core")
|
||||||
|
add_subdirectory("systems")
|
||||||
add_subdirectory("util")
|
add_subdirectory("util")
|
||||||
|
|
||||||
target_sources(aster_core
|
target_sources(aster_core
|
||||||
|
|
|
||||||
|
|
@ -11,11 +11,14 @@
|
||||||
|
|
||||||
namespace systems
|
namespace systems
|
||||||
{
|
{
|
||||||
|
|
||||||
|
using BufferHandle = Handle<Buffer>;
|
||||||
|
|
||||||
class BufferManager final : public Manager<Buffer>
|
class BufferManager final : public Manager<Buffer>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
BufferManager(const Device *device, const u32 maxCount);
|
BufferManager(const Device *device, const u32 maxCount);
|
||||||
|
|
||||||
Ref CreateStorageBuffer(usize size, cstr name = nullptr);
|
Handle CreateStorageBuffer(usize size, cstr name = nullptr);
|
||||||
};
|
};
|
||||||
} // namespace systems
|
} // namespace systems
|
||||||
|
|
|
||||||
|
|
@ -7,55 +7,53 @@
|
||||||
|
|
||||||
#include "aster/aster.h"
|
#include "aster/aster.h"
|
||||||
|
|
||||||
#include <EASTL/intrusive_ptr.h>
|
|
||||||
|
|
||||||
struct Device;
|
struct Device;
|
||||||
|
|
||||||
|
|
||||||
template <typename T>
|
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
|
class Manager
|
||||||
{
|
{
|
||||||
using InternalType = T;
|
friend Handle<T>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
struct Type : InternalType
|
using Type = T;
|
||||||
|
using Handle = Handle<Type>;
|
||||||
|
static_assert(sizeof(Handle) == sizeof(u32));
|
||||||
|
|
||||||
|
static Manager *
|
||||||
|
Instance()
|
||||||
{
|
{
|
||||||
void
|
assert(m_Instance);
|
||||||
AddRef()
|
|
||||||
{
|
|
||||||
m_Instance->AddRef(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
return m_Instance;
|
||||||
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();
|
|
||||||
|
|
||||||
explicit Manager(const Device *device, const u32 maxCount)
|
explicit Manager(const Device *device, const u32 maxCount)
|
||||||
: m_MaxCount{maxCount}
|
: m_MaxCount{maxCount}
|
||||||
, m_FreeHead{0}
|
, m_FreeHead{0}
|
||||||
, m_Device{device}
|
, m_Device{device}
|
||||||
{
|
{
|
||||||
|
assert(!m_Instance);
|
||||||
|
|
||||||
m_Data = new Type[m_MaxCount];
|
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)
|
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()
|
virtual ~Manager()
|
||||||
|
|
@ -79,69 +77,219 @@ class Manager
|
||||||
|
|
||||||
PIN_MEMORY(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:
|
private:
|
||||||
Type *m_Data = nullptr;
|
Type *m_Data = nullptr; // Data also keeps the freelist during 'not use'.
|
||||||
u32 *m_RefCount = nullptr;
|
std::atomic<u32> *m_RefCount = nullptr;
|
||||||
u32 m_MaxCount = 0;
|
u32 m_MaxCount = 0;
|
||||||
u32 m_FreeHead = 0;
|
u32 m_FreeHead = 0;
|
||||||
|
|
||||||
static Manager *m_Instance;
|
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:
|
protected:
|
||||||
const Device *m_Device;
|
const Device *m_Device;
|
||||||
|
|
||||||
void
|
std::pair<Handle, Type *>
|
||||||
SetInstance(Manager *instance)
|
|
||||||
{
|
|
||||||
assert(!m_Instance);
|
|
||||||
m_Instance = instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ref
|
|
||||||
Alloc()
|
Alloc()
|
||||||
{
|
{
|
||||||
ERROR_IF(m_FreeHead >= m_MaxCount, "Max buffers allocated.") THEN_ABORT(-1);
|
ERROR_IF(m_FreeHead >= m_MaxCount, "Max buffers allocated.") THEN_ABORT(-1);
|
||||||
|
|
||||||
const auto index = m_FreeHead;
|
const auto index = m_FreeHead;
|
||||||
m_FreeHead = m_RefCount[index];
|
Type *pAlloc = &m_Data[index];
|
||||||
m_RefCount[index] = 0;
|
m_FreeHead = *Recast<u32 *>(pAlloc);
|
||||||
return Ref{&m_Data[index]};
|
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);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue