[WIP] Cleanup in prep for RenderResourceManager.
This commit is contained in:
parent
88d8a2acc2
commit
3a7bea902f
|
|
@ -17,4 +17,5 @@ INTERFACE
|
||||||
"image.h"
|
"image.h"
|
||||||
"surface.h"
|
"surface.h"
|
||||||
"size.h"
|
"size.h"
|
||||||
|
"type_traits.h"
|
||||||
"window.h")
|
"window.h")
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,8 @@ struct Buffer
|
||||||
[[nodiscard]] bool IsValid() const;
|
[[nodiscard]] bool IsValid() const;
|
||||||
[[nodiscard]] bool IsMapped() const;
|
[[nodiscard]] bool IsMapped() const;
|
||||||
[[nodiscard]] bool IsOwned() const;
|
[[nodiscard]] bool IsOwned() const;
|
||||||
|
[[nodiscard]] bool IsCommitted() const;
|
||||||
|
void SetCommitted(bool committed);
|
||||||
|
|
||||||
void Destroy(const Device *device);
|
void Destroy(const Device *device);
|
||||||
void Write(const Device *device, usize offset, usize size, const void *data);
|
void Write(const Device *device, usize offset, usize size, const void *data);
|
||||||
|
|
@ -40,9 +42,13 @@ struct Buffer
|
||||||
|
|
||||||
constexpr static usize VALID_BUFFER_BIT = Cast<usize>(1llu << 63);
|
constexpr static usize VALID_BUFFER_BIT = Cast<usize>(1llu << 63);
|
||||||
constexpr static usize OWNED_BIT = 1llu << 62;
|
constexpr static usize OWNED_BIT = 1llu << 62;
|
||||||
constexpr static usize SIZE_MASK = ~(VALID_BUFFER_BIT | OWNED_BIT);
|
constexpr static usize COMMITTED_BIT = 1llu << 61;
|
||||||
|
constexpr static usize SIZE_MASK = ~(VALID_BUFFER_BIT | OWNED_BIT | COMMITTED_BIT);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
constexpr bool concepts::GpuResource<Buffer> = true;
|
||||||
|
|
||||||
// Ensure that m_Size doesn't get used intrusively since it manages the state.
|
// Ensure that m_Size doesn't get used intrusively since it manages the state.
|
||||||
static_assert(offsetof(Buffer, m_Size_) > sizeof(usize));
|
static_assert(offsetof(Buffer, m_Size_) > sizeof(usize));
|
||||||
|
|
||||||
|
|
@ -113,3 +119,15 @@ Buffer::IsOwned() const
|
||||||
{
|
{
|
||||||
return m_Size_ & OWNED_BIT;
|
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);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,8 @@
|
||||||
#if !defined(NDEBUG)
|
#if !defined(NDEBUG)
|
||||||
#define VULKAN_HPP_ASSERT(expr) DEBUG_IF(!(expr), "Vulkan assert failed")
|
#define VULKAN_HPP_ASSERT(expr) DEBUG_IF(!(expr), "Vulkan assert failed")
|
||||||
#endif
|
#endif
|
||||||
|
#include "type_traits.h"
|
||||||
|
|
||||||
#include <EASTL/fixed_string.h>
|
#include <EASTL/fixed_string.h>
|
||||||
#include <EASTL/string.h>
|
#include <EASTL/string.h>
|
||||||
#include <vk_mem_alloc.h>
|
#include <vk_mem_alloc.h>
|
||||||
|
|
@ -175,6 +177,18 @@ ClosestPowerOfTwo(const u32 val)
|
||||||
return (smallerPo2 + largerPo2 <= (val << 1)) ? largerPo2 : smallerPo2;
|
return (smallerPo2 + largerPo2 <= (val << 1)) ? largerPo2 : smallerPo2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] constexpr u32
|
||||||
|
GetMaskOffset(u32 val)
|
||||||
|
{
|
||||||
|
u32 count = 0;
|
||||||
|
while ((val & 1) == 0)
|
||||||
|
{
|
||||||
|
count++;
|
||||||
|
val = val >> 1;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
struct fmt::formatter<vk::Result> : nested_formatter<std::string>
|
struct fmt::formatter<vk::Result> : nested_formatter<std::string>
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -49,13 +49,19 @@ struct Image
|
||||||
[[nodiscard]] bool IsValid() const;
|
[[nodiscard]] bool IsValid() const;
|
||||||
[[nodiscard]] bool IsOwned() const;
|
[[nodiscard]] bool IsOwned() const;
|
||||||
[[nodiscard]] u32 GetMipLevels() const;
|
[[nodiscard]] u32 GetMipLevels() const;
|
||||||
|
[[nodiscard]] bool IsCommitted() const;
|
||||||
|
void SetCommitted(bool committed);
|
||||||
|
|
||||||
void Destroy(const Device *device);
|
void Destroy(const Device *device);
|
||||||
|
|
||||||
constexpr static u8 VALID_BIT = 1u << 7;
|
constexpr static u8 VALID_BIT = 1u << 7;
|
||||||
constexpr static u8 OWNED_BIT = 1u << 6;
|
constexpr static u8 OWNED_BIT = 1u << 6;
|
||||||
|
constexpr static u8 COMMITTED_BIT = 1u << 5;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
constexpr bool concepts::GpuResource<Image> = true;
|
||||||
|
|
||||||
struct Texture : Image
|
struct Texture : Image
|
||||||
{
|
{
|
||||||
void Init(const Device *device, vk::Extent2D extent, vk::Format imageFormat, bool isMipMapped, cstr name = nullptr);
|
void Init(const Device *device, vk::Extent2D extent, vk::Format imageFormat, bool isMipMapped, cstr name = nullptr);
|
||||||
|
|
@ -116,4 +122,16 @@ inline u32
|
||||||
Image::GetMipLevels() const
|
Image::GetMipLevels() const
|
||||||
{
|
{
|
||||||
return m_MipLevels;
|
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);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
// =============================================
|
||||||
|
// Aster: type_traits.h
|
||||||
|
// Copyright (c) 2020-2024 Anish Bhobe
|
||||||
|
// =============================================
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
struct Device;
|
||||||
|
|
||||||
|
namespace concepts
|
||||||
|
{
|
||||||
|
template <typename T>
|
||||||
|
concept DeviceDestructible = requires(T a, Device *p) {
|
||||||
|
{ a.Destroy(p) } -> std::convertible_to<void>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
concept Committable = requires(T a, bool v) {
|
||||||
|
{ a.IsCommitted() } -> std::convertible_to<bool>;
|
||||||
|
{ a.SetCommitted(v) } -> std::convertible_to<void>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
constexpr bool GpuResource = false;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
concept RenderResource = GpuResource<T> and std::is_default_constructible_v<T> and std::is_trivially_copyable_v<T> and
|
||||||
|
DeviceDestructible<T> and Committable<T>;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
constexpr bool IsHandle = false;
|
||||||
|
|
||||||
|
template <typename THandle>
|
||||||
|
concept HandleType = IsHandle<THandle> and RenderResource<typename THandle::Type>;
|
||||||
|
|
||||||
|
} // namespace concepts
|
||||||
|
|
@ -6,4 +6,5 @@ target_sources(aster_core
|
||||||
INTERFACE
|
INTERFACE
|
||||||
"manager.h"
|
"manager.h"
|
||||||
"buffer_manager.h"
|
"buffer_manager.h"
|
||||||
"image_manager.h")
|
"image_manager.h"
|
||||||
|
"render_resource_manager.h")
|
||||||
|
|
|
||||||
|
|
@ -11,15 +11,14 @@
|
||||||
|
|
||||||
namespace systems
|
namespace systems
|
||||||
{
|
{
|
||||||
|
|
||||||
using BufferHandle = Handle<Buffer>;
|
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, const u8 binding);
|
||||||
|
|
||||||
Handle CreateStorageBuffer(usize size, cstr name = nullptr);
|
[[nodiscard]] Handle CreateStorageBuffer(usize size, cstr name = nullptr);
|
||||||
Handle CreateUniformBuffer(usize size, cstr name = nullptr);
|
[[nodiscard]] Handle CreateUniformBuffer(usize size, cstr name = nullptr);
|
||||||
};
|
};
|
||||||
} // namespace systems
|
} // namespace systems
|
||||||
|
|
|
||||||
|
|
@ -50,11 +50,11 @@ using ImageHandle = Handle<Image>;
|
||||||
class ImageManager final : public Manager<Image>
|
class ImageManager final : public Manager<Image>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ImageManager(const Device *device, const u32 maxCount);
|
ImageManager(const Device *device, const u32 maxCount, const u8 binding);
|
||||||
|
|
||||||
Handle CreateTexture2D(const Texture2DCreateInfo& createInfo);
|
[[nodiscard]] Handle CreateTexture2D(const Texture2DCreateInfo &createInfo);
|
||||||
Handle CreateTextureCube(const TextureCubeCreateInfo &createInfo);
|
[[nodiscard]] Handle CreateTextureCube(const TextureCubeCreateInfo &createInfo);
|
||||||
Handle CreateAttachment(const AttachmentCreateInfo &createInfo);
|
[[nodiscard]] Handle CreateAttachment(const AttachmentCreateInfo &createInfo);
|
||||||
Handle CreateDepthStencilImage(const DepthStencilImageCreateInfo &createInfo);
|
[[nodiscard]] Handle CreateDepthStencilImage(const DepthStencilImageCreateInfo &createInfo);
|
||||||
};
|
};
|
||||||
} // namespace systems
|
} // namespace systems
|
||||||
|
|
|
||||||
|
|
@ -6,21 +6,14 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "aster/aster.h"
|
#include "aster/aster.h"
|
||||||
|
#include "aster/core/type_traits.h"
|
||||||
|
|
||||||
struct Device;
|
struct Device;
|
||||||
|
|
||||||
|
template <concepts::RenderResource T>
|
||||||
template <typename T>
|
|
||||||
concept IsDeviceDestructible = requires(T a, Device *p) {
|
|
||||||
{ a.Destroy(p) } -> std::convertible_to<void>;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
requires IsDeviceDestructible<T>
|
|
||||||
class Handle;
|
class Handle;
|
||||||
|
|
||||||
template <typename T>
|
template <concepts::RenderResource T>
|
||||||
requires std::is_default_constructible_v<T> && IsDeviceDestructible<T>
|
|
||||||
class Manager
|
class Manager
|
||||||
{
|
{
|
||||||
friend Handle<T>;
|
friend Handle<T>;
|
||||||
|
|
@ -29,21 +22,21 @@ class Manager
|
||||||
using Type = T;
|
using Type = T;
|
||||||
using Handle = Handle<Type>;
|
using Handle = Handle<Type>;
|
||||||
static_assert(sizeof(Handle) == sizeof(u32));
|
static_assert(sizeof(Handle) == sizeof(u32));
|
||||||
|
constexpr static u32 MAX_HANDLES = Handle::INDEX_MASK + 1;
|
||||||
|
|
||||||
static Manager *
|
/**
|
||||||
Instance()
|
* Constructor for the Manager class template.
|
||||||
{
|
* @param device Device with which resources are created.
|
||||||
assert(m_Instance);
|
* @param maxCount Max number of resources that can be created (maxCount <= Handle::INDEX_MASK)
|
||||||
|
* @param binding The shader binding at which this manager will bind its resources.
|
||||||
return m_Instance;
|
*/
|
||||||
}
|
explicit Manager(const Device *device, const u32 maxCount, const u8 binding)
|
||||||
|
|
||||||
explicit Manager(const Device *device, const u32 maxCount)
|
|
||||||
: m_MaxCount{maxCount}
|
: m_MaxCount{maxCount}
|
||||||
, m_FreeHead{0}
|
, m_Binding{binding}
|
||||||
, m_Device{device}
|
, m_Device{device}
|
||||||
{
|
{
|
||||||
assert(!m_Instance);
|
assert(!m_Instance);
|
||||||
|
assert(maxCount <= MAX_HANDLES);
|
||||||
|
|
||||||
m_Data = new Type[m_MaxCount];
|
m_Data = new Type[m_MaxCount];
|
||||||
m_RefCount = new std::atomic<u32>[m_MaxCount];
|
m_RefCount = new std::atomic<u32>[m_MaxCount];
|
||||||
|
|
@ -73,18 +66,36 @@ class Manager
|
||||||
m_MaxCount = 0;
|
m_MaxCount = 0;
|
||||||
m_FreeHead = 0;
|
m_FreeHead = 0;
|
||||||
m_Device = nullptr;
|
m_Device = nullptr;
|
||||||
|
|
||||||
|
m_Instance = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @warning only to be used internally.
|
||||||
|
* @return The only constructed instance of this manager.
|
||||||
|
*/
|
||||||
|
static Manager *
|
||||||
|
Instance()
|
||||||
|
{
|
||||||
|
assert(m_Instance);
|
||||||
|
return m_Instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
PIN_MEMORY(Manager);
|
PIN_MEMORY(Manager);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Type *m_Data = nullptr; // Data also keeps the freelist during 'not use'.
|
Type *m_Data = nullptr; // Data also keeps the freelist during 'not use'.
|
||||||
std::atomic<u32> *m_RefCount = nullptr;
|
std::atomic<u32> *m_RefCount = nullptr; // Associated reference count for each of the instances in Data.
|
||||||
u32 m_MaxCount = 0;
|
u32 m_MaxCount = 0; // Max number of resources supported.
|
||||||
u32 m_FreeHead = 0;
|
u32 m_FreeHead = 0;
|
||||||
|
u8 m_Binding = 0;
|
||||||
|
|
||||||
static Manager *m_Instance;
|
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
|
void
|
||||||
AddRef(const u32 index)
|
AddRef(const u32 index)
|
||||||
{
|
{
|
||||||
|
|
@ -92,6 +103,10 @@ class Manager
|
||||||
++m_RefCount[index];
|
++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
|
void
|
||||||
Release(const u32 index)
|
Release(const u32 index)
|
||||||
{
|
{
|
||||||
|
|
@ -100,10 +115,16 @@ class Manager
|
||||||
assert(rc != MaxValue<u32>);
|
assert(rc != MaxValue<u32>);
|
||||||
if (rc == 0)
|
if (rc == 0)
|
||||||
{
|
{
|
||||||
|
// TODO: Don't destroy here. Separate out to a cleanup routine.
|
||||||
m_Data[index].Destroy(m_Device);
|
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 *
|
Type *
|
||||||
Fetch(const u32 index)
|
Fetch(const u32 index)
|
||||||
{
|
{
|
||||||
|
|
@ -114,7 +135,11 @@ class Manager
|
||||||
protected:
|
protected:
|
||||||
const Device *m_Device;
|
const Device *m_Device;
|
||||||
|
|
||||||
std::pair<Handle, Type *>
|
/**
|
||||||
|
* Internal Method to Allocate a resource on the manager.
|
||||||
|
* @return [Handle, Type*] Where Type* is available to initialize the resource.
|
||||||
|
*/
|
||||||
|
[[nodiscard]] std::pair<Handle, Type *>
|
||||||
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);
|
||||||
|
|
@ -122,12 +147,11 @@ class Manager
|
||||||
const auto index = m_FreeHead;
|
const auto index = m_FreeHead;
|
||||||
Type *pAlloc = &m_Data[index];
|
Type *pAlloc = &m_Data[index];
|
||||||
m_FreeHead = *Recast<u32 *>(pAlloc);
|
m_FreeHead = *Recast<u32 *>(pAlloc);
|
||||||
return {Handle{index}, pAlloc};
|
return {Handle{index, m_Binding}, pAlloc};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <concepts::RenderResource T>
|
||||||
requires IsDeviceDestructible<T>
|
|
||||||
class Ref
|
class Ref
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
@ -188,7 +212,7 @@ class Ref
|
||||||
|
|
||||||
// The only constructor requires a valid construction.
|
// The only constructor requires a valid construction.
|
||||||
explicit Ref(Handle &&handle)
|
explicit Ref(Handle &&handle)
|
||||||
: m_Handle{handle}
|
: m_Handle{std::forward<Handle>(handle)}
|
||||||
{
|
{
|
||||||
InitPtr();
|
InitPtr();
|
||||||
}
|
}
|
||||||
|
|
@ -207,21 +231,63 @@ class Ref
|
||||||
~Ref() = default;
|
~Ref() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
class RawHandle
|
||||||
requires IsDeviceDestructible<T>
|
{
|
||||||
class Handle
|
protected:
|
||||||
|
constexpr static u32 INVALID_HANDLE = MaxValue<u32>;
|
||||||
|
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;
|
||||||
|
|
||||||
|
RawHandle(const u32 index, const u8 typeId)
|
||||||
|
: m_Internal{(index & INDEX_MASK) | (typeId & TYPE_MASK)}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit RawHandle(const u32 internal)
|
||||||
|
: m_Internal{internal}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
[[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 RawHandle &other) const
|
||||||
|
{
|
||||||
|
return m_Internal == other.m_Internal;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <concepts::RenderResource T>
|
||||||
|
class Handle : public RawHandle
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using Type = T;
|
using Type = T;
|
||||||
using Manager = Manager<Type>;
|
using Manager = Manager<Type>;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
constexpr static u32 INVALID_HANDLE = MaxValue<u32>;
|
|
||||||
u32 m_Internal = INVALID_HANDLE;
|
|
||||||
|
|
||||||
// The only constructor requires a valid construction.
|
// The only constructor requires a valid construction.
|
||||||
explicit Handle(const u32 index)
|
Handle(const u32 index, const u8 typeId)
|
||||||
: m_Internal{index}
|
: RawHandle{index, typeId}
|
||||||
{
|
{
|
||||||
AddRef();
|
AddRef();
|
||||||
}
|
}
|
||||||
|
|
@ -231,14 +297,26 @@ class Handle
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Handle(const Handle &other)
|
Handle(const Handle &other)
|
||||||
: m_Internal(other.m_Internal)
|
: RawHandle{other}
|
||||||
{
|
{
|
||||||
AddRef();
|
AddRef();
|
||||||
}
|
}
|
||||||
|
|
||||||
Handle(Handle &&other) noexcept
|
Handle(Handle &&other) noexcept
|
||||||
|
: RawHandle{std::exchange(other.m_Internal, m_Internal)}
|
||||||
{
|
{
|
||||||
std::swap(this->m_Internal, other.m_Internal);
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] Ref<T>
|
||||||
|
ToPointer()
|
||||||
|
{
|
||||||
|
return Ref{std::move(*this)};
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] Type *
|
||||||
|
Fetch() const
|
||||||
|
{
|
||||||
|
return Manager::Instance()->Fetch(m_Internal);
|
||||||
}
|
}
|
||||||
|
|
||||||
Handle &
|
Handle &
|
||||||
|
|
@ -268,28 +346,16 @@ class Handle
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ref<T>
|
|
||||||
ToPointer()
|
|
||||||
{
|
|
||||||
return Ref{std::move(*this)};
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void
|
void
|
||||||
AddRef()
|
AddRef()
|
||||||
{
|
{
|
||||||
Manager::Instance()->AddRef(m_Internal);
|
Manager::Instance()->AddRef(GetIndex());
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Release()
|
Release()
|
||||||
{
|
{
|
||||||
Manager::Instance()->Release(m_Internal);
|
Manager::Instance()->Release(GetIndex());
|
||||||
}
|
|
||||||
|
|
||||||
Type *
|
|
||||||
Fetch()
|
|
||||||
{
|
|
||||||
return Manager::Instance()->Fetch(m_Internal);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,157 @@
|
||||||
|
// =============================================
|
||||||
|
// Aster: render_resource_manager.h
|
||||||
|
// Copyright (c) 2020-2024 Anish Bhobe
|
||||||
|
// =============================================
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "aster/aster.h"
|
||||||
|
#include "buffer_manager.h"
|
||||||
|
#include "image_manager.h"
|
||||||
|
|
||||||
|
#include "EASTL/deque.h"
|
||||||
|
#include "EASTL/vector.h"
|
||||||
|
|
||||||
|
namespace systems
|
||||||
|
{
|
||||||
|
|
||||||
|
class RenderResourceManager
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
union WriteInfo {
|
||||||
|
vk::DescriptorBufferInfo uBufferInfo;
|
||||||
|
vk::DescriptorImageInfo uImageInfo;
|
||||||
|
vk::BufferView uBufferView;
|
||||||
|
|
||||||
|
explicit WriteInfo(const vk::DescriptorBufferInfo &info);
|
||||||
|
explicit WriteInfo(const vk::DescriptorImageInfo &info);
|
||||||
|
explicit WriteInfo(const vk::BufferView &info);
|
||||||
|
};
|
||||||
|
|
||||||
|
using WriteCommand = vk::WriteDescriptorSet;
|
||||||
|
|
||||||
|
union WriteOwner {
|
||||||
|
Handle<Buffer> uBufferHandle;
|
||||||
|
Handle<Image> uImageHandle;
|
||||||
|
|
||||||
|
explicit WriteOwner(const Handle<Buffer> &handle);
|
||||||
|
explicit WriteOwner(const Handle<Image> &handle);
|
||||||
|
|
||||||
|
WriteOwner(const WriteOwner &other)
|
||||||
|
{
|
||||||
|
switch (uRawHandle.GetType())
|
||||||
|
{
|
||||||
|
case BUFFER_BINDING_INDEX:
|
||||||
|
uBufferHandle = other.uBufferHandle;
|
||||||
|
break;
|
||||||
|
case IMAGE_BINDING_INDEX:
|
||||||
|
uImageHandle = other.uImageHandle;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ERROR("Invalid Handle type.") THEN_ABORT(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WriteOwner(WriteOwner &&other) noexcept
|
||||||
|
{
|
||||||
|
switch (uRawHandle.GetType())
|
||||||
|
{
|
||||||
|
case BUFFER_BINDING_INDEX:
|
||||||
|
uBufferHandle = std::move(other.uBufferHandle);
|
||||||
|
break;
|
||||||
|
case IMAGE_BINDING_INDEX:
|
||||||
|
uImageHandle = std::move(other.uImageHandle);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ERROR("Invalid Handle type.") THEN_ABORT(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WriteOwner &
|
||||||
|
operator=(const WriteOwner &other)
|
||||||
|
{
|
||||||
|
if (this == &other)
|
||||||
|
return *this;
|
||||||
|
|
||||||
|
switch (uRawHandle.GetType())
|
||||||
|
{
|
||||||
|
case BUFFER_BINDING_INDEX:
|
||||||
|
uBufferHandle = other.uBufferHandle;
|
||||||
|
break;
|
||||||
|
case IMAGE_BINDING_INDEX:
|
||||||
|
uImageHandle = other.uImageHandle;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ERROR("Invalid Handle type.") THEN_ABORT(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
WriteOwner &
|
||||||
|
operator=(WriteOwner &&other) noexcept
|
||||||
|
{
|
||||||
|
if (this == &other)
|
||||||
|
return *this;
|
||||||
|
|
||||||
|
switch (uRawHandle.GetType())
|
||||||
|
{
|
||||||
|
case BUFFER_BINDING_INDEX:
|
||||||
|
uBufferHandle = std::move(other.uBufferHandle);
|
||||||
|
break;
|
||||||
|
case IMAGE_BINDING_INDEX:
|
||||||
|
uImageHandle = std::move(other.uImageHandle);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ERROR("Invalid Handle type.") THEN_ABORT(-1);
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
~WriteOwner()
|
||||||
|
{
|
||||||
|
switch (uRawHandle.GetType())
|
||||||
|
{
|
||||||
|
case BUFFER_BINDING_INDEX:
|
||||||
|
uBufferHandle.~Handle();
|
||||||
|
return;
|
||||||
|
case IMAGE_BINDING_INDEX:
|
||||||
|
uImageHandle.~Handle();
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
ERROR("Invalid Handle type.") THEN_ABORT(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
RawHandle uRawHandle;
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
RenderResourceManager(const Device *device, u32 maxBuffers, u32 maxImages);
|
||||||
|
|
||||||
|
void Commit(concepts::HandleType auto &handle);
|
||||||
|
|
||||||
|
private:
|
||||||
|
BufferManager m_BufferManager;
|
||||||
|
ImageManager m_ImageManager;
|
||||||
|
|
||||||
|
vk::DescriptorPool m_DescriptorPool;
|
||||||
|
vk::DescriptorSetLayout m_SetLayout;
|
||||||
|
vk::DescriptorSet m_DescriptorSet;
|
||||||
|
|
||||||
|
constexpr static u8 BUFFER_BINDING_INDEX = 0;
|
||||||
|
constexpr static u8 IMAGE_BINDING_INDEX = 1;
|
||||||
|
|
||||||
|
eastl::vector<vk::WriteDescriptorSet> m_Writes;
|
||||||
|
eastl::deque<WriteInfo> m_WriteInfos;
|
||||||
|
eastl::vector<WriteOwner> m_WriteOwner;
|
||||||
|
|
||||||
|
#if !defined(ASTER_NDEBUG)
|
||||||
|
usize m_CommitedBufferCount = 0;
|
||||||
|
usize m_CommitedTextureCount = 0;
|
||||||
|
usize m_CommitedStorageTextureCount = 0;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace systems
|
||||||
|
|
@ -6,4 +6,5 @@ target_sources(aster_core
|
||||||
PRIVATE
|
PRIVATE
|
||||||
"manager.cpp"
|
"manager.cpp"
|
||||||
"buffer_manager.cpp"
|
"buffer_manager.cpp"
|
||||||
"image_manager.cpp")
|
"image_manager.cpp"
|
||||||
|
"render_resource_manager.cpp")
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
#include "systems/buffer_manager.h"
|
#include "systems/buffer_manager.h"
|
||||||
|
|
||||||
Manager<Buffer> *Manager<Buffer>::m_Instance;
|
Manager<Buffer> *Manager<Buffer>::m_Instance = nullptr;
|
||||||
|
|
||||||
using namespace systems;
|
using namespace systems;
|
||||||
|
|
||||||
|
|
@ -28,7 +28,7 @@ BufferManager::CreateStorageBuffer(const usize size, const cstr name)
|
||||||
}
|
}
|
||||||
|
|
||||||
Manager<Buffer>::Handle
|
Manager<Buffer>::Handle
|
||||||
BufferManager::CreateUniformBuffer(usize size, cstr name)
|
BufferManager::CreateUniformBuffer(const usize size, const cstr name)
|
||||||
{
|
{
|
||||||
auto [handle, object] = Alloc();
|
auto [handle, object] = Alloc();
|
||||||
|
|
||||||
|
|
@ -42,7 +42,7 @@ BufferManager::CreateUniformBuffer(usize size, cstr name)
|
||||||
return std::move(handle);
|
return std::move(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
BufferManager::BufferManager(const Device *device, const u32 maxCount)
|
BufferManager::BufferManager(const Device *device, const u32 maxCount, const u8 binding)
|
||||||
: Manager{device, maxCount}
|
: Manager{device, maxCount, binding}
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
#include "core/device.h"
|
#include "core/device.h"
|
||||||
|
|
||||||
Manager<Image> *Manager<Image>::m_Instance;
|
Manager<Image> *Manager<Image>::m_Instance = nullptr;
|
||||||
|
|
||||||
using namespace systems;
|
using namespace systems;
|
||||||
|
|
||||||
|
|
@ -310,7 +310,7 @@ ToImageCreateInfo(const DepthStencilImageCreateInfo &createInfo)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageManager::ImageManager(const Device *device, const u32 maxCount)
|
ImageManager::ImageManager(const Device *device, const u32 maxCount, const u8 binding)
|
||||||
: Manager{device, maxCount}
|
: Manager{device, maxCount, binding}
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,195 @@
|
||||||
|
// =============================================
|
||||||
|
// Aster: render_resource_manager.cpp
|
||||||
|
// Copyright (c) 2020-2025 Anish Bhobe
|
||||||
|
// =============================================
|
||||||
|
|
||||||
|
#include "systems/render_resource_manager.h"
|
||||||
|
|
||||||
|
#include "EASTL/array.h"
|
||||||
|
#include "core/device.h"
|
||||||
|
|
||||||
|
#define AbortIfFailed(RESULT) \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
|
vk::Result _checkResultValue_; \
|
||||||
|
ERROR_IF(Failed(_checkResultValue_ = Cast<vk::Result>(RESULT)), "Cause: {}", _checkResultValue_) \
|
||||||
|
THEN_ABORT(_checkResultValue_); \
|
||||||
|
} while (false)
|
||||||
|
|
||||||
|
#define AbortIfFailedMV(RESULT, MSG, EXTRA) \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
|
vk::Result _checkResultValue_; \
|
||||||
|
ERROR_IF(Failed(_checkResultValue_ = Cast<vk::Result>(RESULT)), MSG " Cause: {}", EXTRA, _checkResultValue_) \
|
||||||
|
THEN_ABORT(_checkResultValue_); \
|
||||||
|
} while (false)
|
||||||
|
|
||||||
|
#define AbortIfFailedM(RESULT, MSG) \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
|
auto _checkResultValue_ = Cast<vk::Result>(RESULT); \
|
||||||
|
ERROR_IF(Failed(_checkResultValue_), MSG " Cause: {}", _checkResultValue_) THEN_ABORT(_checkResultValue_); \
|
||||||
|
} while (false)
|
||||||
|
|
||||||
|
|
||||||
|
using namespace systems;
|
||||||
|
|
||||||
|
u32
|
||||||
|
GetHandleInternal(concepts::HandleType auto &handle)
|
||||||
|
{
|
||||||
|
return *Recast<u32 *>(&handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderResourceManager::WriteOwner::WriteOwner(const Handle<Buffer> &handle)
|
||||||
|
: uBufferHandle(handle)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderResourceManager::WriteOwner::WriteOwner(const Handle<Image> &handle)
|
||||||
|
: uImageHandle(handle)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderResourceManager::RenderResourceManager(const Device *device, u32 const maxBuffers, const u32 maxImages)
|
||||||
|
: m_BufferManager{device, maxBuffers, BUFFER_BINDING_INDEX}
|
||||||
|
, m_ImageManager{device, maxImages, IMAGE_BINDING_INDEX}
|
||||||
|
{
|
||||||
|
eastl::array poolSizes = {
|
||||||
|
vk::DescriptorPoolSize{
|
||||||
|
.type = vk::DescriptorType::eStorageBuffer,
|
||||||
|
.descriptorCount = maxBuffers,
|
||||||
|
},
|
||||||
|
vk::DescriptorPoolSize{
|
||||||
|
.type = vk::DescriptorType::eCombinedImageSampler,
|
||||||
|
.descriptorCount = maxImages,
|
||||||
|
},
|
||||||
|
//vk::DescriptorPoolSize{
|
||||||
|
// .type = vk::DescriptorType::eStorageImage,
|
||||||
|
// .descriptorCount = storageTexturesCount,
|
||||||
|
//},
|
||||||
|
};
|
||||||
|
|
||||||
|
const vk::DescriptorPoolCreateInfo poolCreateInfo = {
|
||||||
|
.flags = vk::DescriptorPoolCreateFlagBits::eUpdateAfterBind,
|
||||||
|
.maxSets = 1,
|
||||||
|
.poolSizeCount = Cast<u32>(poolSizes.size()),
|
||||||
|
.pPoolSizes = poolSizes.data(),
|
||||||
|
};
|
||||||
|
AbortIfFailed(device->m_Device.createDescriptorPool(&poolCreateInfo, nullptr, &m_DescriptorPool));
|
||||||
|
|
||||||
|
eastl::array descriptorLayoutBindings = {
|
||||||
|
vk::DescriptorSetLayoutBinding{
|
||||||
|
.binding = BUFFER_BINDING_INDEX,
|
||||||
|
.descriptorType = vk::DescriptorType::eStorageBuffer,
|
||||||
|
.descriptorCount = Cast<u32>(maxBuffers),
|
||||||
|
.stageFlags = vk::ShaderStageFlagBits::eAll,
|
||||||
|
},
|
||||||
|
vk::DescriptorSetLayoutBinding{
|
||||||
|
.binding = IMAGE_BINDING_INDEX,
|
||||||
|
.descriptorType = vk::DescriptorType::eCombinedImageSampler,
|
||||||
|
.descriptorCount = Cast<u32>(maxImages),
|
||||||
|
.stageFlags = vk::ShaderStageFlagBits::eAll,
|
||||||
|
},
|
||||||
|
//vk::DescriptorSetLayoutBinding{
|
||||||
|
// .binding = STORAGE_TEXTURE_BINDING_INDEX,
|
||||||
|
// .descriptorType = vk::DescriptorType::eStorageImage,
|
||||||
|
// .descriptorCount = Cast<u32>(storageTexturesCount),
|
||||||
|
// .stageFlags = vk::ShaderStageFlagBits::eAll,
|
||||||
|
//},
|
||||||
|
};
|
||||||
|
|
||||||
|
vk::DescriptorBindingFlags bindingFlags =
|
||||||
|
vk::DescriptorBindingFlagBits::ePartiallyBound | vk::DescriptorBindingFlagBits::eUpdateAfterBind;
|
||||||
|
|
||||||
|
eastl::array<vk::DescriptorBindingFlags, decltype(descriptorLayoutBindings)::count> layoutBindingFlags;
|
||||||
|
layoutBindingFlags.fill(bindingFlags);
|
||||||
|
|
||||||
|
vk::DescriptorSetLayoutBindingFlagsCreateInfo bindingFlagsCreateInfo = {
|
||||||
|
.bindingCount = Cast<u32>(layoutBindingFlags.size()),
|
||||||
|
.pBindingFlags = layoutBindingFlags.data(),
|
||||||
|
};
|
||||||
|
|
||||||
|
static_assert(layoutBindingFlags.size() == descriptorLayoutBindings.size());
|
||||||
|
const vk::DescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo = {
|
||||||
|
.pNext = &bindingFlagsCreateInfo,
|
||||||
|
.flags = vk::DescriptorSetLayoutCreateFlagBits::eUpdateAfterBindPool,
|
||||||
|
.bindingCount = Cast<u32>(descriptorLayoutBindings.size()),
|
||||||
|
.pBindings = descriptorLayoutBindings.data(),
|
||||||
|
};
|
||||||
|
AbortIfFailed(device->m_Device.createDescriptorSetLayout(&descriptorSetLayoutCreateInfo, nullptr, &m_SetLayout));
|
||||||
|
|
||||||
|
// One descriptor is enough. Updating it at any time is safe. (Update until submit, data held when pending)
|
||||||
|
// https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_descriptor_indexing.html
|
||||||
|
// https://github.com/KhronosGroup/Vulkan-Guide/blob/main/chapters/extensions/VK_EXT_descriptor_indexing.adoc
|
||||||
|
const vk::DescriptorSetAllocateInfo descriptorSetAllocateInfo = {
|
||||||
|
.descriptorPool = m_DescriptorPool,
|
||||||
|
.descriptorSetCount = 1,
|
||||||
|
.pSetLayouts = &m_SetLayout,
|
||||||
|
};
|
||||||
|
AbortIfFailed(device->m_Device.allocateDescriptorSets(&descriptorSetAllocateInfo, &m_DescriptorSet));
|
||||||
|
|
||||||
|
device->SetName(m_SetLayout, "Bindless Layout");
|
||||||
|
device->SetName(m_DescriptorPool, "Bindless Pool");
|
||||||
|
device->SetName(m_DescriptorSet, "Bindless Set");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
systems::RenderResourceManager::Commit(concepts::HandleType auto &handle)
|
||||||
|
{
|
||||||
|
using HandleType = decltype(handle)::Type;
|
||||||
|
if constexpr (std::is_same_v<HandleType, Buffer>)
|
||||||
|
{
|
||||||
|
const Buffer *buffer = handle.Fetch();
|
||||||
|
|
||||||
|
m_WriteInfos.emplace_back(vk::DescriptorBufferInfo{
|
||||||
|
.buffer = buffer->m_Buffer,
|
||||||
|
.offset = 0,
|
||||||
|
.range = buffer->GetSize(),
|
||||||
|
});
|
||||||
|
m_Writes.push_back({
|
||||||
|
.dstSet = m_DescriptorSet,
|
||||||
|
.dstBinding = BUFFER_BINDING_INDEX,
|
||||||
|
.dstArrayElement = handle.GetIndex(),
|
||||||
|
.descriptorCount = 1,
|
||||||
|
.descriptorType = vk::DescriptorType::eStorageBuffer,
|
||||||
|
.pBufferInfo = &m_WriteInfos.back().uBufferInfo,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else if constexpr (std::is_same_v<HandleType, Image>)
|
||||||
|
{
|
||||||
|
const Image *image = handle.Fetch();
|
||||||
|
|
||||||
|
m_WriteInfos.emplace_back(vk::DescriptorImageInfo{
|
||||||
|
.sampler = nullptr /* TODO Sampler */,
|
||||||
|
.imageView = image->m_View,
|
||||||
|
.imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal,
|
||||||
|
});
|
||||||
|
m_Writes.push_back({
|
||||||
|
.dstSet = m_DescriptorSet,
|
||||||
|
.dstBinding = IMAGE_BINDING_INDEX,
|
||||||
|
.dstArrayElement = handle.GetIndex(),
|
||||||
|
.descriptorCount = 1,
|
||||||
|
.descriptorType = vk::DescriptorType::eSampledImage,
|
||||||
|
.pImageInfo = &m_WriteInfos.back().uImageInfo,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
static_assert(false && "Type is currently unsupported");
|
||||||
|
}
|
||||||
|
|
||||||
|
m_WriteOwner.emplace_back(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderResourceManager::WriteInfo::WriteInfo(const vk::DescriptorBufferInfo &info)
|
||||||
|
: uBufferInfo{info}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderResourceManager::WriteInfo::WriteInfo(const vk::DescriptorImageInfo &info)
|
||||||
|
: uImageInfo{info}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderResourceManager::WriteInfo::WriteInfo(const vk::BufferView &info)
|
||||||
|
: uBufferView{info}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
@ -115,8 +115,8 @@ main(int, char **)
|
||||||
Swapchain swapchain = {&surface, &device, window.GetSize(), "Primary Chain"};
|
Swapchain swapchain = {&surface, &device, window.GetSize(), "Primary Chain"};
|
||||||
Pipeline pipeline = CreatePipeline(&device, &swapchain);
|
Pipeline pipeline = CreatePipeline(&device, &swapchain);
|
||||||
|
|
||||||
systems::BufferManager bufferManager{&device, 12};
|
systems::BufferManager bufferManager{&device, 12, 0};
|
||||||
systems::ImageManager imageManager{&device, 12};
|
systems::ImageManager imageManager{&device, 12, 1};
|
||||||
|
|
||||||
Camera camera = {
|
Camera camera = {
|
||||||
.m_Model = {1.0f},
|
.m_Model = {1.0f},
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ TextureManager::Init(const u32 maxCapacity)
|
||||||
TextureHandle
|
TextureHandle
|
||||||
TextureManager::Commit(Texture *texture)
|
TextureManager::Commit(Texture *texture)
|
||||||
{
|
{
|
||||||
ERROR_IF(!texture || !texture->IsValid(), "Texture must be valid for commital")
|
ERROR_IF(!texture || !texture->IsValid(), "Texture must be valid for committal")
|
||||||
THEN_ABORT(-1);
|
THEN_ABORT(-1);
|
||||||
|
|
||||||
if (m_FreeHead != GpuResourceHandle::INVALID_HANDLE)
|
if (m_FreeHead != GpuResourceHandle::INVALID_HANDLE)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue