Reimplemented RenderResourceManager.
This commit is contained in:
parent
396810d203
commit
afec1e3e32
|
|
@ -13,45 +13,66 @@ struct Device;
|
||||||
|
|
||||||
struct Buffer
|
struct Buffer
|
||||||
{
|
{
|
||||||
|
const Device *m_Device = nullptr; ///< Will be used for book-keeping when buffer is invalid.
|
||||||
|
|
||||||
vk::Buffer m_Buffer = nullptr;
|
vk::Buffer m_Buffer = nullptr;
|
||||||
VmaAllocation m_Allocation = nullptr;
|
VmaAllocation m_Allocation = nullptr;
|
||||||
|
|
||||||
// If the buffer is host visible, it should be (and stay) mapped.
|
u8 *m_Mapped = nullptr; ///< If the buffer is host visible, it should be (and stay) mapped.
|
||||||
u8 *m_Mapped = nullptr;
|
|
||||||
|
|
||||||
[[nodiscard]] usize GetSize() const;
|
usize m_Size = 0;
|
||||||
[[nodiscard]] bool IsHostVisible() const;
|
std::atomic<u32> m_RefCount = 0;
|
||||||
[[nodiscard]] bool IsValid() const;
|
|
||||||
[[nodiscard]] bool IsMapped() const;
|
|
||||||
[[nodiscard]] bool IsOwned() const;
|
|
||||||
[[nodiscard]] bool IsCommitted() const;
|
|
||||||
void SetCommitted(bool committed);
|
|
||||||
|
|
||||||
void Destroy(const Device *device);
|
[[nodiscard]] bool
|
||||||
void Write(const Device *device, usize offset, usize size, const void *data);
|
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<u32>);
|
||||||
|
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,
|
void Allocate(const Device *device, usize size, vk::BufferUsageFlags bufferUsage,
|
||||||
VmaAllocationCreateFlags allocationFlags, VmaMemoryUsage memoryUsage, cstr name);
|
VmaAllocationCreateFlags allocationFlags, VmaMemoryUsage memoryUsage, cstr name);
|
||||||
|
|
||||||
uptr
|
uptr GetDeviceAddress(const Device *device) const;
|
||||||
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<usize>(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);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template <>
|
|
||||||
constexpr bool concepts::Resource<Buffer> = 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
|
struct UniformBuffer : Buffer
|
||||||
{
|
{
|
||||||
void Init(const Device *device, usize size, cstr name = nullptr);
|
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);
|
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);
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -35,33 +35,56 @@ ToOffset3D(const vk::Extent3D &extent)
|
||||||
|
|
||||||
struct Image
|
struct Image
|
||||||
{
|
{
|
||||||
|
const Device *m_Device = nullptr;
|
||||||
vk::Image m_Image = nullptr;
|
vk::Image m_Image = nullptr;
|
||||||
vk::ImageView m_View = nullptr;
|
|
||||||
VmaAllocation m_Allocation = nullptr;
|
VmaAllocation m_Allocation = nullptr;
|
||||||
|
vk::ImageView m_View = nullptr;
|
||||||
vk::Extent3D m_Extent;
|
vk::Extent3D m_Extent;
|
||||||
// Image.m_MipLevels_ is used for bookkeeping
|
std::atomic<u32> m_RefCount;
|
||||||
// If the image is Invalid, the remaining data in Image is used intrusively by `GpuResourceManager`.
|
|
||||||
u8 m_EmptyPadding_ = 0;
|
u8 m_EmptyPadding_ = 0;
|
||||||
u8 m_Flags_ = 0;
|
u8 m_Flags_ = 0;
|
||||||
u8 m_LayerCount = 0;
|
u8 m_LayerCount = 0;
|
||||||
u8 m_MipLevels = 0;
|
u8 m_MipLevels = 0;
|
||||||
|
|
||||||
[[nodiscard]] bool IsValid() const;
|
[[nodiscard]] bool
|
||||||
[[nodiscard]] bool IsOwned() const;
|
IsValid() const
|
||||||
[[nodiscard]] u32 GetMipLevels() const;
|
{
|
||||||
[[nodiscard]] bool IsCommitted() const;
|
return m_Image;
|
||||||
void SetCommitted(bool committed);
|
}
|
||||||
|
|
||||||
void Destroy(const Device *device);
|
[[nodiscard]] bool
|
||||||
|
IsReferenced() const
|
||||||
|
{
|
||||||
|
return m_RefCount;
|
||||||
|
}
|
||||||
|
|
||||||
constexpr static u8 VALID_BIT = 1u << 7;
|
[[nodiscard]] u32
|
||||||
constexpr static u8 OWNED_BIT = 1u << 6;
|
GetMipLevels() const
|
||||||
constexpr static u8 COMMITTED_BIT = 1u << 5;
|
{
|
||||||
|
return m_MipLevels;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
AddRef()
|
||||||
|
{
|
||||||
|
const auto rc = ++m_RefCount;
|
||||||
|
assert(rc > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Release()
|
||||||
|
{
|
||||||
|
const auto rc = --m_RefCount;
|
||||||
|
assert(rc < MaxValue<u32>);
|
||||||
|
if (rc == 0)
|
||||||
|
{
|
||||||
|
Destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Destroy();
|
||||||
};
|
};
|
||||||
|
|
||||||
template <>
|
|
||||||
constexpr bool concepts::Resource<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);
|
||||||
|
|
@ -105,33 +128,3 @@ struct StorageTextureCube : StorageTexture
|
||||||
};
|
};
|
||||||
|
|
||||||
static_assert(sizeof(StorageTextureCube) == sizeof(Image));
|
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);
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -14,33 +14,34 @@ struct Device;
|
||||||
struct Sampler
|
struct Sampler
|
||||||
{
|
{
|
||||||
vk::Sampler m_Sampler = nullptr;
|
vk::Sampler m_Sampler = nullptr;
|
||||||
bool m_Committed = false;
|
std::atomic<u32> m_RefCount = 0;
|
||||||
|
|
||||||
void Init(const Device *device, const vk::SamplerCreateInfo &samplerCreateInfo, cstr name);
|
void Init(const Device *device, const vk::SamplerCreateInfo &samplerCreateInfo, cstr name);
|
||||||
void Destroy(const Device *device);
|
void Destroy(const Device *device);
|
||||||
|
|
||||||
[[nodiscard]] bool IsValid() const;
|
void
|
||||||
[[nodiscard]] bool IsCommitted() const;
|
AddRef()
|
||||||
void SetCommitted(bool committed);
|
{
|
||||||
};
|
const auto rc = ++m_RefCount;
|
||||||
|
assert(rc > 0);
|
||||||
|
}
|
||||||
|
|
||||||
template <>
|
void
|
||||||
constexpr bool concepts::Opaque<Sampler> = true;
|
Release()
|
||||||
|
{
|
||||||
|
const auto rc = --m_RefCount;
|
||||||
|
assert(rc < MaxValue<u32>);
|
||||||
|
}
|
||||||
|
|
||||||
inline bool
|
[[nodiscard]] bool
|
||||||
Sampler::IsValid() const
|
IsReferenced() const
|
||||||
|
{
|
||||||
|
return m_RefCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] bool
|
||||||
|
IsValid() const
|
||||||
{
|
{
|
||||||
return m_Sampler;
|
return m_Sampler;
|
||||||
}
|
}
|
||||||
|
};
|
||||||
inline bool
|
|
||||||
Sampler::IsCommitted() const
|
|
||||||
{
|
|
||||||
return m_Committed;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void
|
|
||||||
Sampler::SetCommitted(const bool committed)
|
|
||||||
{
|
|
||||||
m_Committed = committed;
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -9,42 +9,25 @@ struct Device;
|
||||||
|
|
||||||
namespace concepts
|
namespace concepts
|
||||||
{
|
{
|
||||||
template <typename THandle, typename TValue>
|
template <typename T>
|
||||||
concept Fetches = requires(THandle h)
|
concept RefCounted = requires(T a) {
|
||||||
{
|
{ a.AddRef() } -> std::same_as<void>;
|
||||||
{ h.Fetch() } -> std::same_as<TValue*>;
|
{ a.Release() } -> std::same_as<void>;
|
||||||
|
{ a.IsReferenced() } -> std::convertible_to<bool>;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
concept DeviceDestructible = requires(T a, Device *p) {
|
concept DeviceDestructible = requires(T a, Device *p) {
|
||||||
{ a.Destroy(p) } -> std::convertible_to<void>;
|
{ a.Destroy(p) } -> std::same_as<void>;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
concept Committable = requires(T a, bool v) {
|
concept SelfDestructible = requires(T a) {
|
||||||
{ a.IsCommitted() } -> std::convertible_to<bool>;
|
{ a.Destroy() } -> std::same_as<void>;
|
||||||
{ a.SetCommitted(v) } -> std::convertible_to<void>;
|
{ T::m_Device } -> std::convertible_to<const Device *>;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
constexpr bool Resource = false;
|
concept Manageable = std::is_default_constructible_v<T> and (DeviceDestructible<T> or SelfDestructible<T>) and RefCounted<T>;
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
constexpr bool Opaque = false;
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
concept Consistent = (Resource<T> and !Opaque<T>) or (Opaque<T> and !Resource<T>);
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
concept Manageable = std::is_default_constructible_v<T> and std::is_trivially_copyable_v<T> and DeviceDestructible<T>;
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
concept ShaderObject = Consistent<T> and Manageable<T> and Committable<T>;
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
concept ShaderResource = ShaderObject<T> and Resource<T>;
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
concept ShaderOpaque = ShaderObject<T> and Opaque<T>;
|
|
||||||
|
|
||||||
} // namespace concepts
|
} // namespace concepts
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
|
|
||||||
namespace systems
|
namespace systems
|
||||||
{
|
{
|
||||||
using BufferHandle = Handle<Buffer>;
|
using BufferHandle = Manager<Buffer>::Handle;
|
||||||
|
|
||||||
class BufferManager final : public Manager<Buffer>
|
class BufferManager final : public Manager<Buffer>
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ struct DepthStencilImageCreateInfo
|
||||||
cstr m_Name = nullptr;
|
cstr m_Name = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
using ImageHandle = Handle<Image>;
|
using ImageHandle = Manager<Image>::Handle;
|
||||||
|
|
||||||
class ImageManager final : public Manager<Image>
|
class ImageManager final : public Manager<Image>
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -8,24 +8,20 @@
|
||||||
#include "aster/aster.h"
|
#include "aster/aster.h"
|
||||||
#include "aster/core/type_traits.h"
|
#include "aster/core/type_traits.h"
|
||||||
|
|
||||||
|
#include <EASTL/intrusive_ptr.h>
|
||||||
|
#include <EASTL/vector.h>
|
||||||
|
|
||||||
struct Device;
|
struct Device;
|
||||||
|
|
||||||
namespace systems
|
namespace systems
|
||||||
{
|
{
|
||||||
|
|
||||||
template <concepts::ShaderObject T>
|
template <concepts::Manageable T>
|
||||||
class Handle;
|
|
||||||
|
|
||||||
template <concepts::ShaderObject T>
|
|
||||||
class Manager
|
class Manager
|
||||||
{
|
{
|
||||||
friend Handle<T>;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using Type = T;
|
using Type = T;
|
||||||
using Handle = Handle<Type>;
|
using Handle = eastl::intrusive_ptr<Type>;
|
||||||
static_assert(sizeof(Handle) == sizeof(u32));
|
|
||||||
constexpr static u32 MAX_HANDLES = Handle::INDEX_MASK + 1;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor for the Manager class template.
|
* 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.
|
* @param binding The shader binding at which this manager will bind its resources.
|
||||||
*/
|
*/
|
||||||
explicit Manager(const Device *device, const u32 maxCount, const u8 binding)
|
explicit Manager(const Device *device, const u32 maxCount, const u8 binding)
|
||||||
: m_MaxCount{maxCount}
|
: m_Data{maxCount}
|
||||||
, m_Binding{binding}
|
, m_Binding{binding}
|
||||||
, m_Device{device}
|
, m_Device{device}
|
||||||
{
|
{
|
||||||
assert(!m_Instance && "Attempting to initialize a second Manager");
|
assert(!m_Instance && "Attempting to initialize a second Manager");
|
||||||
assert(maxCount <= MAX_HANDLES);
|
|
||||||
|
|
||||||
m_Data = new Type[m_MaxCount];
|
u32 i = 0;
|
||||||
m_RefCount = new std::atomic<u32>[m_MaxCount];
|
for (auto& element : m_Data)
|
||||||
|
|
||||||
for (u32 i = 0; i < m_MaxCount; ++i)
|
|
||||||
{
|
{
|
||||||
*Recast<u32 *>(&m_Data[i]) = (i + 1);
|
*Recast<u32 *>(&element) = ++i;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_Instance = this;
|
m_Instance = this;
|
||||||
|
|
@ -54,87 +47,48 @@ class Manager
|
||||||
|
|
||||||
virtual ~Manager()
|
virtual ~Manager()
|
||||||
{
|
{
|
||||||
if (!m_Data)
|
for (auto& element: m_Data)
|
||||||
return;
|
|
||||||
|
|
||||||
for (u32 i = 0; i < m_MaxCount; ++i)
|
|
||||||
{
|
{
|
||||||
m_Data[i].Destroy(m_Device);
|
if constexpr (concepts::SelfDestructible<Type>)
|
||||||
|
{
|
||||||
|
element.Destroy();
|
||||||
|
}
|
||||||
|
else if constexpr (concepts::DeviceDestructible<Type>)
|
||||||
|
{
|
||||||
|
element.Destroy(m_Device);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
delete[] m_Data;
|
|
||||||
delete[] m_RefCount;
|
|
||||||
m_Data = nullptr;
|
|
||||||
m_RefCount = nullptr;
|
|
||||||
m_MaxCount = 0;
|
|
||||||
m_FreeHead = 0;
|
m_FreeHead = 0;
|
||||||
m_Device = nullptr;
|
m_Device = nullptr;
|
||||||
|
|
||||||
m_Instance = nullptr;
|
m_Instance = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
void
|
||||||
* @warning only to be used internally.
|
Sweep()
|
||||||
* @return The only constructed instance of this manager.
|
requires concepts::DeviceDestructible<Type>
|
||||||
*/
|
|
||||||
static Manager *
|
|
||||||
Instance()
|
|
||||||
{
|
{
|
||||||
assert(m_Instance && "Not initialized yet.");
|
for (i64 i = m_Data.size() - 1; i >= 0; --i)
|
||||||
return m_Instance;
|
{
|
||||||
|
if (auto *pIter = &m_Data[i]; !pIter->IsValid())
|
||||||
|
{
|
||||||
|
pIter->Destroy(m_Device);
|
||||||
|
*Recast<u32 *>(pIter) = m_FreeHead;
|
||||||
|
m_FreeHead = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PIN_MEMORY(Manager);
|
PIN_MEMORY(Manager);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Type *m_Data = nullptr; // Data also keeps the freelist during 'not use'.
|
eastl::vector<Type> m_Data; // Data also keeps the freelist during 'not use'.
|
||||||
std::atomic<u32> *m_RefCount = nullptr; // Associated reference count for each of the instances in Data.
|
|
||||||
u32 m_MaxCount = 0; // Max number of resources supported.
|
|
||||||
u32 m_FreeHead = 0;
|
u32 m_FreeHead = 0;
|
||||||
u8 m_Binding = 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
|
|
||||||
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<u32>);
|
|
||||||
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:
|
protected:
|
||||||
const Device *m_Device;
|
const Device *m_Device;
|
||||||
|
|
||||||
|
|
@ -142,221 +96,20 @@ class Manager
|
||||||
* Internal Method to Allocate a resource on the manager.
|
* Internal Method to Allocate a resource on the manager.
|
||||||
* @return [Handle, Type*] Where Type* is available to initialize the resource.
|
* @return [Handle, Type*] Where Type* is available to initialize the resource.
|
||||||
*/
|
*/
|
||||||
[[nodiscard]] std::pair<Handle, Type *>
|
[[nodiscard]] Handle
|
||||||
Alloc()
|
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;
|
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, m_Binding}, pAlloc};
|
memset(pAlloc, 0, sizeof *pAlloc);
|
||||||
|
if constexpr (concepts::SelfDestructible<Type>)
|
||||||
|
{
|
||||||
|
pAlloc->m_Device = m_Device;
|
||||||
}
|
}
|
||||||
};
|
return {pAlloc};
|
||||||
|
|
||||||
template <concepts::ShaderObject 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 *
|
|
||||||
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>(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 <concepts::ShaderObject T>
|
|
||||||
class Handle
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
using Type = T;
|
|
||||||
using Manager = Manager<Type>;
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
// 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<T>;
|
|
||||||
|
|
||||||
public:
|
|
||||||
[[nodiscard]] Ref<T>
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
Release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void
|
|
||||||
AddRef()
|
|
||||||
{
|
|
||||||
Manager::Instance()->AddRef(GetIndex());
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Release()
|
|
||||||
{
|
|
||||||
Manager::Instance()->Release(GetIndex());
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
} // namespace systems
|
} // namespace systems
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,16 +10,250 @@
|
||||||
#include "image_manager.h"
|
#include "image_manager.h"
|
||||||
#include "sampler_manager.h"
|
#include "sampler_manager.h"
|
||||||
|
|
||||||
|
#include "aster/util/intrusive_slist.h"
|
||||||
|
|
||||||
#include "EASTL/deque.h"
|
#include "EASTL/deque.h"
|
||||||
#include "EASTL/vector.h"
|
#include "EASTL/intrusive_hash_map.h"
|
||||||
#include <variant>
|
#include "EASTL/bonus/fixed_ring_buffer.h"
|
||||||
|
|
||||||
namespace systems
|
namespace systems
|
||||||
{
|
{
|
||||||
|
|
||||||
|
class RenderResourceManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CommitEntry manages the lifetime of the committed resource.
|
||||||
|
* @tparam T Type of the committed resource.
|
||||||
|
*/
|
||||||
|
template <concepts::Manageable T>
|
||||||
|
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
|
class RenderResourceManager
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
template <concepts::Manageable T>
|
||||||
|
struct HandleMapper
|
||||||
|
{
|
||||||
|
using Type = T;
|
||||||
|
using Manager = Manager<Type>;
|
||||||
|
using Handle = typename Manager::Handle;
|
||||||
|
using CommitE = CommitEntry<Type>;
|
||||||
|
|
||||||
|
struct Entry : public eastl::intrusive_hash_node_key<Handle>
|
||||||
|
{
|
||||||
|
std::atomic<u32> m_CommitCount;
|
||||||
|
|
||||||
|
void
|
||||||
|
AddRef()
|
||||||
|
{
|
||||||
|
const auto rc = ++m_CommitCount;
|
||||||
|
assert(rc > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Release()
|
||||||
|
{
|
||||||
|
const auto rc = --m_CommitCount;
|
||||||
|
assert(rc < MaxValue<u32>);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
IsReferenced() const
|
||||||
|
{
|
||||||
|
return m_CommitCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
operator==(const Entry &other) const
|
||||||
|
{
|
||||||
|
return this->mKey == other.mKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
Entry *
|
||||||
|
Next()
|
||||||
|
{
|
||||||
|
return Recast<Entry *>(this->mpNext);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SetNext(Entry &entry)
|
||||||
|
{
|
||||||
|
this->mpNext = &entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Hash
|
||||||
|
{
|
||||||
|
usize
|
||||||
|
operator()(const Handle &e)
|
||||||
|
{
|
||||||
|
return eastl::hash<Type *>()(e.get());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
static_assert(sizeof(Entry) == 24);
|
||||||
|
|
||||||
|
eastl::vector<Entry> m_Data;
|
||||||
|
IntrusiveStack<Entry> m_FreeList;
|
||||||
|
eastl::intrusive_hash_map<typename Entry::key_type, Entry, 31, typename Entry::Hash> m_InUse;
|
||||||
|
std::array<IntrusiveStack<Entry>, 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<CommitE, bool>
|
||||||
|
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<u32>(&entry - m_Data.begin());
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
QueueDelete(Entry &entry)
|
||||||
|
{
|
||||||
|
m_InUse.remove(entry);
|
||||||
|
m_ToDelete[m_ToDeleteIndex].Push(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ClearEntries(IntrusiveStack<Entry>& entries)
|
||||||
|
{
|
||||||
|
while (auto item = entries.TryPop())
|
||||||
|
{
|
||||||
|
Entry &entry = item.value();
|
||||||
|
entry.mKey.reset();
|
||||||
|
entry.m_CommitCount = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
union WriteInfo {
|
union WriteInfo {
|
||||||
vk::DescriptorBufferInfo uBufferInfo;
|
vk::DescriptorBufferInfo uBufferInfo;
|
||||||
vk::DescriptorImageInfo uImageInfo;
|
vk::DescriptorImageInfo uImageInfo;
|
||||||
|
|
@ -37,28 +271,15 @@ class RenderResourceManager
|
||||||
public:
|
public:
|
||||||
const Device *m_Device;
|
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();
|
~RenderResourceManager();
|
||||||
|
|
||||||
PIN_MEMORY(RenderResourceManager);
|
PIN_MEMORY(RenderResourceManager);
|
||||||
|
|
||||||
// Buffer
|
CommitEntry<Buffer> Commit(const BufferHandle &buffer);
|
||||||
[[nodiscard]] BufferHandle CreateStorageBuffer(usize size, cstr name = nullptr);
|
CommitEntry<Image> Commit(const ImageHandle &handle);
|
||||||
[[nodiscard]] BufferHandle CreateUniformBuffer(usize size, cstr name = nullptr);
|
CommitEntry<Image> Commit(const ImageHandle &image, const SamplerHandle &sampler);
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
void Update();
|
void Update();
|
||||||
|
|
||||||
|
|
@ -68,32 +289,73 @@ class RenderResourceManager
|
||||||
return m_SetLayout;
|
return m_SetLayout;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] const vk::DescriptorSet& GetDescriptorSet() const
|
[[nodiscard]] const vk::DescriptorSet &
|
||||||
|
GetDescriptorSet() const
|
||||||
{
|
{
|
||||||
return m_DescriptorSet;
|
return m_DescriptorSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
static RenderResourceManager *
|
||||||
BufferManager m_BufferManager;
|
Instance()
|
||||||
ImageManager m_ImageManager;
|
{
|
||||||
SamplerManager m_SamplerManager;
|
return m_Instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
vk::DescriptorPool m_DescriptorPool;
|
vk::DescriptorPool m_DescriptorPool;
|
||||||
vk::DescriptorSetLayout m_SetLayout;
|
vk::DescriptorSetLayout m_SetLayout;
|
||||||
vk::DescriptorSet m_DescriptorSet;
|
vk::DescriptorSet m_DescriptorSet;
|
||||||
|
|
||||||
constexpr static u8 BUFFER_BINDING_INDEX = 0x0;
|
constexpr static u8 BUFFER_BINDING_INDEX = 0x0;
|
||||||
constexpr static u8 IMAGE_BINDING_INDEX = 0x1;
|
constexpr static u8 IMAGE_BINDING_INDEX = 0x1;
|
||||||
constexpr static u8 SAMPLER_TYPE_INDEX = 0xF;
|
|
||||||
|
HandleMapper<Buffer> m_Buffers;
|
||||||
|
HandleMapper<Image> m_Images;
|
||||||
|
SamplerHandle m_DefaultSampler;
|
||||||
|
|
||||||
eastl::vector<vk::WriteDescriptorSet> m_Writes;
|
eastl::vector<vk::WriteDescriptorSet> m_Writes;
|
||||||
eastl::deque<WriteInfo> m_WriteInfos;
|
eastl::deque<WriteInfo> m_WriteInfos;
|
||||||
// eastl::vector<WriteOwner> m_WriteOwner;
|
// eastl::vector<WriteOwner> m_WriteOwner;
|
||||||
|
|
||||||
#if !defined(ASTER_NDEBUG)
|
static RenderResourceManager *m_Instance;
|
||||||
usize m_CommitedBufferCount = 0;
|
friend CommitEntry<Buffer>;
|
||||||
usize m_CommitedTextureCount = 0;
|
friend CommitEntry<Image>;
|
||||||
usize m_CommitedStorageTextureCount = 0;
|
|
||||||
#endif
|
void
|
||||||
|
AddRef(const CommitEntry<Buffer> &handle)
|
||||||
|
{
|
||||||
|
m_Buffers.AddRef(handle);
|
||||||
|
}
|
||||||
|
void
|
||||||
|
AddRef(const CommitEntry<Image> &handle)
|
||||||
|
{
|
||||||
|
m_Images.AddRef(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Release(const CommitEntry<Buffer> &handle)
|
||||||
|
{
|
||||||
|
m_Buffers.Release(handle);
|
||||||
|
}
|
||||||
|
void
|
||||||
|
Release(const CommitEntry<Image> &handle)
|
||||||
|
{
|
||||||
|
m_Images.Release(handle);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <concepts::Manageable T>
|
||||||
|
void
|
||||||
|
CommitEntry<T>::AddRef() const
|
||||||
|
{
|
||||||
|
RenderResourceManager::Instance()->AddRef(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <concepts::Manageable T>
|
||||||
|
void
|
||||||
|
CommitEntry<T>::Release() const
|
||||||
|
{
|
||||||
|
RenderResourceManager::Instance()->Release(*this);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace systems
|
} // namespace systems
|
||||||
|
|
@ -12,7 +12,7 @@
|
||||||
|
|
||||||
namespace systems
|
namespace systems
|
||||||
{
|
{
|
||||||
using SamplerHandle = Handle<Sampler>;
|
using SamplerHandle = Manager<Sampler>::Handle;
|
||||||
|
|
||||||
struct SamplerCreateInfo : vk::SamplerCreateInfo
|
struct SamplerCreateInfo : vk::SamplerCreateInfo
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -3,4 +3,4 @@
|
||||||
cmake_minimum_required(VERSION 3.13)
|
cmake_minimum_required(VERSION 3.13)
|
||||||
|
|
||||||
target_sources(aster_core
|
target_sources(aster_core
|
||||||
INTERFACE "logger.h")
|
INTERFACE "logger.h" "intrusive_slist.h")
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,127 @@
|
||||||
|
// =============================================
|
||||||
|
// Aster: intrusive_slist.h
|
||||||
|
// Copyright (c) 2020-2024 Anish Bhobe
|
||||||
|
// =============================================
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
concept HasNext = requires(T &a) {
|
||||||
|
{ a.Next() } -> std::same_as<T *>;
|
||||||
|
{ a.SetNext(a) };
|
||||||
|
};
|
||||||
|
|
||||||
|
struct IntrusiveStackNode
|
||||||
|
{
|
||||||
|
IntrusiveStackNode *m_Next;
|
||||||
|
|
||||||
|
IntrusiveStackNode *
|
||||||
|
Next() const
|
||||||
|
{
|
||||||
|
return m_Next;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SetNext(IntrusiveStackNode &a)
|
||||||
|
{
|
||||||
|
m_Next = &a;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <HasNext T = IntrusiveStackNode>
|
||||||
|
struct IntrusiveStack
|
||||||
|
{
|
||||||
|
using Value = T;
|
||||||
|
using Reference = T &;
|
||||||
|
using OptionalRef = std::optional<std::reference_wrapper<T>>;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -8,21 +8,22 @@
|
||||||
#include "core/device.h"
|
#include "core/device.h"
|
||||||
|
|
||||||
void
|
void
|
||||||
Buffer::Destroy(const Device *device)
|
Buffer::Destroy()
|
||||||
{
|
{
|
||||||
if (!IsValid() || !IsOwned())
|
if (!m_Buffer)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
vmaDestroyBuffer(device->m_Allocator, m_Buffer, m_Allocation);
|
vmaDestroyBuffer(m_Device->m_Allocator, Take(m_Buffer), m_Allocation);
|
||||||
m_Size_ = 0;
|
m_Size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Buffer::Allocate(const Device *device, usize size, vk::BufferUsageFlags bufferUsage,
|
Buffer::Allocate(const Device *device, usize size, vk::BufferUsageFlags bufferUsage,
|
||||||
VmaAllocationCreateFlags allocationFlags, VmaMemoryUsage memoryUsage, cstr name)
|
VmaAllocationCreateFlags allocationFlags, VmaMemoryUsage memoryUsage, cstr name)
|
||||||
{
|
{
|
||||||
assert(!IsValid());
|
assert(!m_Buffer);
|
||||||
assert(size <= SIZE_MASK);
|
|
||||||
|
m_Device = device;
|
||||||
|
|
||||||
vk::BufferCreateInfo bufferCreateInfo = {
|
vk::BufferCreateInfo bufferCreateInfo = {
|
||||||
.size = size,
|
.size = size,
|
||||||
|
|
@ -48,7 +49,7 @@ Buffer::Allocate(const Device *device, usize size, vk::BufferUsageFlags bufferUs
|
||||||
// bool hostAccessible = Cast<bool>(memoryPropertyFlags & vk::MemoryPropertyFlagBits::eHostVisible);
|
// bool hostAccessible = Cast<bool>(memoryPropertyFlags & vk::MemoryPropertyFlagBits::eHostVisible);
|
||||||
|
|
||||||
m_Buffer = buffer;
|
m_Buffer = buffer;
|
||||||
m_Size_ = size | VALID_BUFFER_BIT | OWNED_BIT;
|
m_Size = size;
|
||||||
m_Allocation = allocation;
|
m_Allocation = allocation;
|
||||||
m_Mapped = Cast<u8 *>(allocationInfo.pMappedData);
|
m_Mapped = Cast<u8 *>(allocationInfo.pMappedData);
|
||||||
|
|
||||||
|
|
@ -56,28 +57,28 @@ Buffer::Allocate(const Device *device, usize size, vk::BufferUsageFlags bufferUs
|
||||||
}
|
}
|
||||||
|
|
||||||
uptr
|
uptr
|
||||||
Buffer::GetDeviceAddress(const Device *device)
|
Buffer::GetDeviceAddress(const Device *device) const
|
||||||
{
|
{
|
||||||
vk::BufferDeviceAddressInfo addressInfo = {.buffer = m_Buffer};
|
vk::BufferDeviceAddressInfo addressInfo = {.buffer = m_Buffer};
|
||||||
return device->m_Device.getBufferAddress(&addressInfo);
|
return device->m_Device.getBufferAddress(&addressInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Buffer::Write(const Device *device, usize offset, usize size, const void *data)
|
Buffer::Write(usize offset, usize size, const void *data)
|
||||||
{
|
{
|
||||||
assert(IsHostVisible());
|
assert(IsHostVisible());
|
||||||
|
|
||||||
if (!IsMapped())
|
if (!IsMapped())
|
||||||
{
|
{
|
||||||
void *mapped;
|
void *mapped;
|
||||||
auto result = Cast<vk::Result>(vmaMapMemory(device->m_Allocator, m_Allocation, &mapped));
|
auto result = Cast<vk::Result>(vmaMapMemory(m_Device->m_Allocator, m_Allocation, &mapped));
|
||||||
ERROR_IF(Failed(result), "Memory mapping failed. Cause: {}", result);
|
ERROR_IF(Failed(result), "Memory mapping failed. Cause: {}", result);
|
||||||
if (!Failed(result))
|
if (!Failed(result))
|
||||||
{
|
{
|
||||||
m_Mapped = Cast<u8 *>(mapped);
|
m_Mapped = Cast<u8 *>(mapped);
|
||||||
memcpy(m_Mapped + offset, data, size);
|
memcpy(m_Mapped + offset, data, size);
|
||||||
|
|
||||||
vmaUnmapMemory(device->m_Allocator, m_Allocation);
|
vmaUnmapMemory(m_Device->m_Allocator, m_Allocation);
|
||||||
m_Mapped = nullptr;
|
m_Mapped = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,16 +8,13 @@
|
||||||
#include "core/device.h"
|
#include "core/device.h"
|
||||||
|
|
||||||
void
|
void
|
||||||
Image::Destroy(const Device *device)
|
Image::Destroy()
|
||||||
{
|
{
|
||||||
if (!IsValid() || !IsOwned())
|
if (!IsValid())
|
||||||
{
|
|
||||||
m_Flags_ = 0;
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
device->m_Device.destroy(m_View, nullptr);
|
m_Device->m_Device.destroy(m_View, nullptr);
|
||||||
vmaDestroyImage(device->m_Allocator, m_Image, m_Allocation);
|
vmaDestroyImage(m_Device->m_Allocator, Take(m_Image), m_Allocation);
|
||||||
m_Flags_ = 0;
|
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);
|
result = device->m_Device.createImageView(&imageViewCreateInfo, nullptr, &view);
|
||||||
ERROR_IF(Failed(result), "Could not create image view {}. Cause: {}", name, result) THEN_ABORT(result);
|
ERROR_IF(Failed(result), "Could not create image view {}. Cause: {}", name, result) THEN_ABORT(result);
|
||||||
|
|
||||||
|
m_Device = device;
|
||||||
m_Image = image;
|
m_Image = image;
|
||||||
m_View = view;
|
m_View = view;
|
||||||
m_Allocation = allocation;
|
m_Allocation = allocation;
|
||||||
m_Extent = imageCreateInfo.extent;
|
m_Extent = imageCreateInfo.extent;
|
||||||
m_Flags_ = OWNED_BIT | VALID_BIT;
|
|
||||||
m_LayerCount = 1;
|
m_LayerCount = 1;
|
||||||
m_MipLevels = mipLevels;
|
m_MipLevels = mipLevels;
|
||||||
|
|
||||||
|
|
@ -109,7 +106,8 @@ Remember, we use upside down viewport.
|
||||||
void
|
void
|
||||||
TextureCube::Init(const Device *device, u32 cubeSide, vk::Format imageFormat, bool isMipMapped, cstr name)
|
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 : "<unnamed>");
|
WARN_IF(!IsPowerOfTwo(cubeSide), "Image Cube {1} has side {0}x{0} (Non Power of Two)", cubeSide,
|
||||||
|
name ? name : "<unnamed>");
|
||||||
|
|
||||||
const u8 mipLevels = isMipMapped ? 1 + Cast<u8>(floor(log2(cubeSide))) : 1;
|
const u8 mipLevels = isMipMapped ? 1 + Cast<u8>(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);
|
result = device->m_Device.createImageView(&imageViewCreateInfo, nullptr, &view);
|
||||||
ERROR_IF(Failed(result), "Could not create image view {}. Cause: {}", name, result) THEN_ABORT(result);
|
ERROR_IF(Failed(result), "Could not create image view {}. Cause: {}", name, result) THEN_ABORT(result);
|
||||||
|
|
||||||
|
m_Device = device;
|
||||||
m_Image = image;
|
m_Image = image;
|
||||||
m_View = view;
|
m_View = view;
|
||||||
m_Allocation = allocation;
|
m_Allocation = allocation;
|
||||||
m_Extent = extent;
|
m_Extent = extent;
|
||||||
m_MipLevels = mipLevels;
|
m_MipLevels = mipLevels;
|
||||||
m_Flags_ = OWNED_BIT | VALID_BIT;
|
|
||||||
m_LayerCount = 6;
|
m_LayerCount = 6;
|
||||||
|
|
||||||
device->SetName(m_Image, name);
|
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);
|
result = device->m_Device.createImageView(&imageViewCreateInfo, nullptr, &view);
|
||||||
ERROR_IF(Failed(result), "Could not create attachment image view {}. Cause: {}", name, result) THEN_ABORT(result);
|
ERROR_IF(Failed(result), "Could not create attachment image view {}. Cause: {}", name, result) THEN_ABORT(result);
|
||||||
|
|
||||||
|
m_Device = device;
|
||||||
m_Image = image;
|
m_Image = image;
|
||||||
m_View = view;
|
m_View = view;
|
||||||
m_Allocation = allocation;
|
m_Allocation = allocation;
|
||||||
m_Extent = imageCreateInfo.extent;
|
m_Extent = imageCreateInfo.extent;
|
||||||
m_MipLevels = 1;
|
m_MipLevels = 1;
|
||||||
m_Flags_ = OWNED_BIT | VALID_BIT;
|
|
||||||
m_LayerCount = 1;
|
m_LayerCount = 1;
|
||||||
|
|
||||||
device->SetName(m_Image, name);
|
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);
|
result = device->m_Device.createImageView(&imageViewCreateInfo, nullptr, &view);
|
||||||
ERROR_IF(Failed(result), "Could not create depth image view {}. Cause: {}", name, result) THEN_ABORT(result);
|
ERROR_IF(Failed(result), "Could not create depth image view {}. Cause: {}", name, result) THEN_ABORT(result);
|
||||||
|
|
||||||
|
m_Device = device;
|
||||||
m_Image = image;
|
m_Image = image;
|
||||||
m_View = view;
|
m_View = view;
|
||||||
m_Allocation = allocation;
|
m_Allocation = allocation;
|
||||||
m_Extent = imageCreateInfo.extent;
|
m_Extent = imageCreateInfo.extent;
|
||||||
m_MipLevels = 1;
|
m_MipLevels = 1;
|
||||||
m_Flags_ = OWNED_BIT | VALID_BIT;
|
|
||||||
m_LayerCount = 1;
|
m_LayerCount = 1;
|
||||||
|
|
||||||
device->SetName(m_Image, name);
|
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);
|
result = device->m_Device.createImageView(&imageViewCreateInfo, nullptr, &view);
|
||||||
ERROR_IF(Failed(result), "Could not create image view {}. Cause: {}", name, result) THEN_ABORT(result);
|
ERROR_IF(Failed(result), "Could not create image view {}. Cause: {}", name, result) THEN_ABORT(result);
|
||||||
|
|
||||||
|
m_Device = device;
|
||||||
m_Image = image;
|
m_Image = image;
|
||||||
m_View = view;
|
m_View = view;
|
||||||
m_Allocation = allocation;
|
m_Allocation = allocation;
|
||||||
m_Extent = imageCreateInfo.extent;
|
m_Extent = imageCreateInfo.extent;
|
||||||
m_MipLevels = 1;
|
m_MipLevels = 1;
|
||||||
m_Flags_ = OWNED_BIT | VALID_BIT;
|
|
||||||
m_LayerCount = 1;
|
m_LayerCount = 1;
|
||||||
|
|
||||||
device->SetName(m_Image, name);
|
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);
|
result = device->m_Device.createImageView(&imageViewCreateInfo, nullptr, &view);
|
||||||
ERROR_IF(Failed(result), "Could not create image view {}. Cause: {}", name, result) THEN_ABORT(result);
|
ERROR_IF(Failed(result), "Could not create image view {}. Cause: {}", name, result) THEN_ABORT(result);
|
||||||
|
|
||||||
|
m_Device = device;
|
||||||
m_Image = image;
|
m_Image = image;
|
||||||
m_View = view;
|
m_View = view;
|
||||||
m_Allocation = allocation;
|
m_Allocation = allocation;
|
||||||
m_Extent = imageCreateInfo.extent;
|
m_Extent = imageCreateInfo.extent;
|
||||||
m_MipLevels = mipLevels;
|
m_MipLevels = mipLevels;
|
||||||
m_Flags_ = OWNED_BIT | VALID_BIT;
|
|
||||||
m_LayerCount = 6;
|
m_LayerCount = 6;
|
||||||
|
|
||||||
device->SetName(m_Image, name);
|
device->SetName(m_Image, name);
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ Manager<Buffer> *Manager<Buffer>::m_Instance = nullptr;
|
||||||
BufferHandle
|
BufferHandle
|
||||||
BufferManager::CreateStorageBuffer(const usize size, const cstr name)
|
BufferManager::CreateStorageBuffer(const usize size, const cstr name)
|
||||||
{
|
{
|
||||||
auto [handle, object] = Alloc();
|
auto object = Alloc();
|
||||||
|
|
||||||
// TODO: Storage and Index buffer are set.
|
// TODO: Storage and Index buffer are set.
|
||||||
// This is hacky and should be improved.
|
// 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;
|
constexpr VmaMemoryUsage memoryUsage = VMA_MEMORY_USAGE_AUTO;
|
||||||
object->Allocate(m_Device, size, usage, createFlags, memoryUsage, name);
|
object->Allocate(m_Device, size, usage, createFlags, memoryUsage, name);
|
||||||
|
|
||||||
return std::move(handle);
|
return object;
|
||||||
}
|
}
|
||||||
|
|
||||||
Manager<Buffer>::Handle
|
Manager<Buffer>::Handle
|
||||||
BufferManager::CreateUniformBuffer(const usize size, const cstr name)
|
BufferManager::CreateUniformBuffer(const usize size, const cstr name)
|
||||||
{
|
{
|
||||||
auto [handle, object] = Alloc();
|
auto object = Alloc();
|
||||||
|
|
||||||
constexpr vk::BufferUsageFlags usage = vk::BufferUsageFlagBits::eUniformBuffer;
|
constexpr vk::BufferUsageFlags usage = vk::BufferUsageFlagBits::eUniformBuffer;
|
||||||
constexpr VmaAllocationCreateFlags createFlags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT |
|
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;
|
constexpr VmaMemoryUsage memoryUsage = VMA_MEMORY_USAGE_AUTO;
|
||||||
object->Allocate(m_Device, size, usage, createFlags, memoryUsage, name);
|
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)
|
BufferManager::BufferManager(const Device *device, const u32 maxCount, const u8 binding)
|
||||||
|
|
|
||||||
|
|
@ -61,18 +61,17 @@ ImageManager::CreateTexture2D(const Texture2DCreateInfo &createInfo)
|
||||||
ERROR_IF(Failed(result), "Could not create image view {}. Cause: {}", createInfo.m_Name, result)
|
ERROR_IF(Failed(result), "Could not create image view {}. Cause: {}", createInfo.m_Name, result)
|
||||||
THEN_ABORT(result);
|
THEN_ABORT(result);
|
||||||
|
|
||||||
auto [handle, object] = Alloc();
|
auto object = Alloc();
|
||||||
object->m_Image = image;
|
object->m_Image = image;
|
||||||
object->m_View = view;
|
object->m_View = view;
|
||||||
object->m_Allocation = allocation;
|
object->m_Allocation = allocation;
|
||||||
object->m_Extent = imageCreateInfo.extent;
|
object->m_Extent = imageCreateInfo.extent;
|
||||||
object->m_Flags_ = Image::OWNED_BIT | Image::VALID_BIT;
|
|
||||||
object->m_LayerCount = Cast<u8>(imageCreateInfo.arrayLayers);
|
object->m_LayerCount = Cast<u8>(imageCreateInfo.arrayLayers);
|
||||||
object->m_MipLevels = Cast<u8>(imageCreateInfo.mipLevels);
|
object->m_MipLevels = Cast<u8>(imageCreateInfo.mipLevels);
|
||||||
|
|
||||||
m_Device->SetName(object->m_Image, createInfo.m_Name);
|
m_Device->SetName(object->m_Image, createInfo.m_Name);
|
||||||
|
|
||||||
return handle;
|
return object;
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageHandle
|
ImageHandle
|
||||||
|
|
@ -109,18 +108,17 @@ ImageManager::CreateTextureCube(const TextureCubeCreateInfo &createInfo)
|
||||||
ERROR_IF(Failed(result), "Could not create image view {}. Cause: {}", createInfo.m_Name, result)
|
ERROR_IF(Failed(result), "Could not create image view {}. Cause: {}", createInfo.m_Name, result)
|
||||||
THEN_ABORT(result);
|
THEN_ABORT(result);
|
||||||
|
|
||||||
auto [handle, object] = Alloc();
|
auto object = Alloc();
|
||||||
object->m_Image = image;
|
object->m_Image = image;
|
||||||
object->m_View = view;
|
object->m_View = view;
|
||||||
object->m_Allocation = allocation;
|
object->m_Allocation = allocation;
|
||||||
object->m_Extent = imageCreateInfo.extent;
|
object->m_Extent = imageCreateInfo.extent;
|
||||||
object->m_Flags_ = Image::OWNED_BIT | Image::VALID_BIT;
|
|
||||||
object->m_LayerCount = Cast<u8>(imageCreateInfo.arrayLayers);
|
object->m_LayerCount = Cast<u8>(imageCreateInfo.arrayLayers);
|
||||||
object->m_MipLevels = Cast<u8>(imageCreateInfo.mipLevels);
|
object->m_MipLevels = Cast<u8>(imageCreateInfo.mipLevels);
|
||||||
|
|
||||||
m_Device->SetName(object->m_Image, createInfo.m_Name);
|
m_Device->SetName(object->m_Image, createInfo.m_Name);
|
||||||
|
|
||||||
return handle;
|
return object;
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageHandle
|
ImageHandle
|
||||||
|
|
@ -157,18 +155,17 @@ ImageManager::CreateAttachment(const AttachmentCreateInfo &createInfo)
|
||||||
ERROR_IF(Failed(result), "Could not create image view {}. Cause: {}", createInfo.m_Name, result)
|
ERROR_IF(Failed(result), "Could not create image view {}. Cause: {}", createInfo.m_Name, result)
|
||||||
THEN_ABORT(result);
|
THEN_ABORT(result);
|
||||||
|
|
||||||
auto [handle, object] = Alloc();
|
auto object = Alloc();
|
||||||
object->m_Image = image;
|
object->m_Image = image;
|
||||||
object->m_View = view;
|
object->m_View = view;
|
||||||
object->m_Allocation = allocation;
|
object->m_Allocation = allocation;
|
||||||
object->m_Extent = imageCreateInfo.extent;
|
object->m_Extent = imageCreateInfo.extent;
|
||||||
object->m_Flags_ = Image::OWNED_BIT | Image::VALID_BIT;
|
|
||||||
object->m_LayerCount = Cast<u8>(imageCreateInfo.arrayLayers);
|
object->m_LayerCount = Cast<u8>(imageCreateInfo.arrayLayers);
|
||||||
object->m_MipLevels = Cast<u8>(imageCreateInfo.mipLevels);
|
object->m_MipLevels = Cast<u8>(imageCreateInfo.mipLevels);
|
||||||
|
|
||||||
m_Device->SetName(object->m_Image, createInfo.m_Name);
|
m_Device->SetName(object->m_Image, createInfo.m_Name);
|
||||||
|
|
||||||
return handle;
|
return object;
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageHandle
|
ImageHandle
|
||||||
|
|
@ -205,18 +202,17 @@ ImageManager::CreateDepthStencilImage(const DepthStencilImageCreateInfo &createI
|
||||||
ERROR_IF(Failed(result), "Could not create image view {}. Cause: {}", createInfo.m_Name, result)
|
ERROR_IF(Failed(result), "Could not create image view {}. Cause: {}", createInfo.m_Name, result)
|
||||||
THEN_ABORT(result);
|
THEN_ABORT(result);
|
||||||
|
|
||||||
auto [handle, object] = Alloc();
|
auto object = Alloc();
|
||||||
object->m_Image = image;
|
object->m_Image = image;
|
||||||
object->m_View = view;
|
object->m_View = view;
|
||||||
object->m_Allocation = allocation;
|
object->m_Allocation = allocation;
|
||||||
object->m_Extent = imageCreateInfo.extent;
|
object->m_Extent = imageCreateInfo.extent;
|
||||||
object->m_Flags_ = Image::OWNED_BIT | Image::VALID_BIT;
|
|
||||||
object->m_LayerCount = Cast<u8>(imageCreateInfo.arrayLayers);
|
object->m_LayerCount = Cast<u8>(imageCreateInfo.arrayLayers);
|
||||||
object->m_MipLevels = Cast<u8>(imageCreateInfo.mipLevels);
|
object->m_MipLevels = Cast<u8>(imageCreateInfo.mipLevels);
|
||||||
|
|
||||||
m_Device->SetName(object->m_Image, createInfo.m_Name);
|
m_Device->SetName(object->m_Image, createInfo.m_Name);
|
||||||
|
|
||||||
return handle;
|
return object;
|
||||||
}
|
}
|
||||||
|
|
||||||
vk::ImageCreateInfo
|
vk::ImageCreateInfo
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,8 @@
|
||||||
|
|
||||||
#include "systems/render_resource_manager.h"
|
#include "systems/render_resource_manager.h"
|
||||||
|
|
||||||
#include "core/device.h"
|
|
||||||
#include "EASTL/array.h"
|
#include "EASTL/array.h"
|
||||||
|
#include "core/device.h"
|
||||||
|
|
||||||
#define AbortIfFailed(RESULT) \
|
#define AbortIfFailed(RESULT) \
|
||||||
do \
|
do \
|
||||||
|
|
@ -33,13 +33,17 @@
|
||||||
|
|
||||||
using namespace systems;
|
using namespace systems;
|
||||||
|
|
||||||
|
RenderResourceManager *RenderResourceManager::m_Instance = nullptr;
|
||||||
|
|
||||||
RenderResourceManager::RenderResourceManager(const Device *device, u32 const maxBuffers, const u32 maxImages,
|
RenderResourceManager::RenderResourceManager(const Device *device, u32 const maxBuffers, const u32 maxImages,
|
||||||
const u32 maxSamplers)
|
const SamplerHandle &defaultSampler)
|
||||||
: m_Device{device}
|
: m_Device{device}
|
||||||
, m_BufferManager{device, maxBuffers, BUFFER_BINDING_INDEX}
|
, m_Buffers{maxBuffers}
|
||||||
, m_ImageManager{device, maxImages, IMAGE_BINDING_INDEX}
|
, m_Images{maxImages}
|
||||||
, m_SamplerManager{device, maxSamplers, SAMPLER_TYPE_INDEX}
|
, m_DefaultSampler{defaultSampler}
|
||||||
{
|
{
|
||||||
|
assert(!m_Instance);
|
||||||
|
|
||||||
eastl::array poolSizes = {
|
eastl::array poolSizes = {
|
||||||
vk::DescriptorPoolSize{
|
vk::DescriptorPoolSize{
|
||||||
.type = vk::DescriptorType::eStorageBuffer,
|
.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_SetLayout, "Bindless Layout");
|
||||||
device->SetName(m_DescriptorPool, "Bindless Pool");
|
device->SetName(m_DescriptorPool, "Bindless Pool");
|
||||||
device->SetName(m_DescriptorSet, "Bindless Set");
|
device->SetName(m_DescriptorSet, "Bindless Set");
|
||||||
|
|
||||||
|
m_Instance = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
RenderResourceManager::~RenderResourceManager()
|
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_SetLayout, nullptr);
|
||||||
m_Device->m_Device.destroy(m_DescriptorPool, nullptr);
|
m_Device->m_Device.destroy(m_DescriptorPool, nullptr);
|
||||||
|
|
||||||
|
#if !defined(ASTER_NDEBUG)
|
||||||
|
u32 bufferCount = 0;
|
||||||
|
for (const auto &entry : m_Buffers.m_Data)
|
||||||
|
{
|
||||||
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
CommitEntry<Buffer>
|
||||||
RenderResourceManager::Write(const BufferHandle &handle, const usize offset, const usize size, const void *data) const
|
RenderResourceManager::Commit(const BufferHandle &buffer)
|
||||||
{
|
{
|
||||||
handle.Fetch()->Write(m_Device, offset, size, data);
|
auto [commit, isNew] = m_Buffers.Create(buffer);
|
||||||
}
|
|
||||||
|
|
||||||
BufferHandle RenderResourceManager::CreateStorageBuffer(const usize size, const cstr name)
|
if (!isNew)
|
||||||
{
|
return commit;
|
||||||
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())
|
|
||||||
{
|
|
||||||
WARN("Buffer is already committed");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_WriteInfos.emplace_back(vk::DescriptorBufferInfo{
|
m_WriteInfos.emplace_back(vk::DescriptorBufferInfo{
|
||||||
.buffer = buffer->m_Buffer,
|
.buffer = buffer->m_Buffer,
|
||||||
.offset = 0,
|
.offset = 0,
|
||||||
.range = buffer->GetSize(),
|
.range = buffer->m_Size,
|
||||||
});
|
});
|
||||||
m_Writes.push_back({
|
m_Writes.push_back({
|
||||||
.dstSet = m_DescriptorSet,
|
.dstSet = m_DescriptorSet,
|
||||||
.dstBinding = BUFFER_BINDING_INDEX,
|
.dstBinding = BUFFER_BINDING_INDEX,
|
||||||
.dstArrayElement = handle.GetIndex(),
|
.dstArrayElement = commit.m_Index,
|
||||||
.descriptorCount = 1,
|
.descriptorCount = 1,
|
||||||
.descriptorType = vk::DescriptorType::eStorageBuffer,
|
.descriptorType = vk::DescriptorType::eStorageBuffer,
|
||||||
.pBufferInfo = &m_WriteInfos.back().uBufferInfo,
|
.pBufferInfo = &m_WriteInfos.back().uBufferInfo,
|
||||||
});
|
});
|
||||||
|
|
||||||
buffer->SetCommitted(true);
|
return commit;
|
||||||
#if !defined(ASTER_NDEBUG)
|
|
||||||
++m_CommitedBufferCount;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
CommitEntry<Image>
|
||||||
RenderResourceManager::Commit(const ImageHandle &handle)
|
RenderResourceManager::Commit(const ImageHandle &handle)
|
||||||
{
|
{
|
||||||
const auto sampler = m_SamplerManager.Create({});
|
return Commit(handle, m_DefaultSampler);
|
||||||
Commit(handle, sampler);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
CommitEntry<Image>
|
||||||
RenderResourceManager::Commit(const ImageHandle &handle, const SamplerHandle &samplerHandle)
|
RenderResourceManager::Commit(const ImageHandle &image, const SamplerHandle &sampler)
|
||||||
{
|
{
|
||||||
Image *image = handle.Fetch();
|
auto [commit, isNew] = m_Images.Create(image);
|
||||||
if (image->IsCommitted())
|
if (!isNew)
|
||||||
{
|
return commit;
|
||||||
WARN("Image is already committed");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Sampler *sampler = samplerHandle.Fetch();
|
|
||||||
|
|
||||||
m_WriteInfos.emplace_back(vk::DescriptorImageInfo{
|
m_WriteInfos.emplace_back(vk::DescriptorImageInfo{
|
||||||
.sampler = sampler->m_Sampler,
|
.sampler = sampler->m_Sampler,
|
||||||
|
|
@ -230,17 +194,13 @@ RenderResourceManager::Commit(const ImageHandle &handle, const SamplerHandle &sa
|
||||||
m_Writes.push_back({
|
m_Writes.push_back({
|
||||||
.dstSet = m_DescriptorSet,
|
.dstSet = m_DescriptorSet,
|
||||||
.dstBinding = IMAGE_BINDING_INDEX,
|
.dstBinding = IMAGE_BINDING_INDEX,
|
||||||
.dstArrayElement = handle.GetIndex(),
|
.dstArrayElement = commit.m_Index,
|
||||||
.descriptorCount = 1,
|
.descriptorCount = 1,
|
||||||
.descriptorType = vk::DescriptorType::eCombinedImageSampler,
|
.descriptorType = vk::DescriptorType::eCombinedImageSampler,
|
||||||
.pImageInfo = &m_WriteInfos.back().uImageInfo,
|
.pImageInfo = &m_WriteInfos.back().uImageInfo,
|
||||||
});
|
});
|
||||||
|
|
||||||
image->SetCommitted(true);
|
return commit;
|
||||||
sampler->SetCommitted(true);
|
|
||||||
#if !defined(ASTER_NDEBUG)
|
|
||||||
++m_CommitedTextureCount;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RenderResourceManager::WriteInfo::WriteInfo(const vk::DescriptorBufferInfo &info)
|
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
|
void
|
||||||
RenderResourceManager::Update()
|
RenderResourceManager::Update()
|
||||||
{
|
{
|
||||||
|
|
@ -275,4 +229,7 @@ RenderResourceManager::Update()
|
||||||
m_Writes.clear();
|
m_Writes.clear();
|
||||||
m_WriteInfos.clear();
|
m_WriteInfos.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_Buffers.Update();
|
||||||
|
m_Images.Update();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -56,11 +56,11 @@ SamplerManager::Create(const SamplerCreateInfo &createInfo)
|
||||||
return iter->second;
|
return iter->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto [handle, object] = Alloc();
|
auto object = Alloc();
|
||||||
|
|
||||||
object->Init(m_Device, createInfo, createInfo.m_Name ? createInfo.m_Name : nullptr);
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -122,7 +122,7 @@ main(int, char **)
|
||||||
{
|
{
|
||||||
StagingBuffer staging;
|
StagingBuffer staging;
|
||||||
staging.Init(&device, vertices.size() * sizeof vertices[0], "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::Fence fence;
|
||||||
vk::FenceCreateInfo fenceCreateInfo = {};
|
vk::FenceCreateInfo fenceCreateInfo = {};
|
||||||
|
|
@ -133,7 +133,7 @@ main(int, char **)
|
||||||
result = copyBuffer.begin(&beginInfo);
|
result = copyBuffer.begin(&beginInfo);
|
||||||
ERROR_IF(Failed(result), "Copy begin failed. Cause: {}", result) THEN_ABORT(result);
|
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);
|
copyBuffer.copyBuffer(staging.m_Buffer, vbo.m_Buffer, 1, &bufferCopy);
|
||||||
|
|
||||||
result = copyBuffer.end();
|
result = copyBuffer.end();
|
||||||
|
|
@ -154,7 +154,7 @@ main(int, char **)
|
||||||
ERROR_IF(Failed(result), "Couldn't reset command pool. Cause: {}", result) THEN_ABORT(result);
|
ERROR_IF(Failed(result), "Couldn't reset command pool. Cause: {}", result) THEN_ABORT(result);
|
||||||
|
|
||||||
device.m_Device.destroy(fence, nullptr);
|
device.m_Device.destroy(fence, nullptr);
|
||||||
staging.Destroy(&device);
|
staging.Destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Persistent variables
|
// Persistent variables
|
||||||
|
|
@ -352,7 +352,7 @@ main(int, char **)
|
||||||
device.WaitIdle();
|
device.WaitIdle();
|
||||||
|
|
||||||
device.m_Device.destroy(copyPool, nullptr);
|
device.m_Device.destroy(copyPool, nullptr);
|
||||||
vbo.Destroy(&device);
|
vbo.Destroy();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -128,7 +128,12 @@ main(int, char **)
|
||||||
Device device = {&context, &deviceToUse, &enabledDeviceFeatures, {queueAllocation}, "Primary Device"};
|
Device device = {&context, &deviceToUse, &enabledDeviceFeatures, {queueAllocation}, "Primary Device"};
|
||||||
vk::Queue commandQueue = device.GetQueue(queueAllocation.m_Family, 0);
|
vk::Queue commandQueue = device.GetQueue(queueAllocation.m_Family, 0);
|
||||||
Swapchain swapchain = {&surface, &device, window.GetSize(), "Primary Chain"};
|
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);
|
Pipeline pipeline = CreatePipeline(&renderResourceManager, &swapchain);
|
||||||
|
|
||||||
|
|
@ -206,22 +211,21 @@ main(int, char **)
|
||||||
assert(loaded);
|
assert(loaded);
|
||||||
INFO("Image {}x{} : {} channels", imageFile.m_Width, imageFile.m_Height, imageFile.m_NumChannels);
|
INFO("Image {}x{} : {} channels", imageFile.m_Width, imageFile.m_Height, imageFile.m_NumChannels);
|
||||||
|
|
||||||
auto vbo = renderResourceManager.CreateStorageBuffer(vertices.size() * sizeof vertices[0], "Vertex Buffer");
|
auto vbo = bufferManager.CreateStorageBuffer(vertices.size() * sizeof vertices[0], "Vertex Buffer");
|
||||||
renderResourceManager.Write(vbo, 0, vertices.size() * sizeof vertices[0], vertices.data());
|
vbo->Write(0, vertices.size() * sizeof vertices[0], vertices.data());
|
||||||
|
|
||||||
auto crate = renderResourceManager
|
auto crate = imageManager
|
||||||
.CreateTexture2D({
|
.CreateTexture2D({
|
||||||
.m_Format = vk::Format::eR8G8B8A8Srgb,
|
.m_Format = vk::Format::eR8G8B8A8Srgb,
|
||||||
.m_Extent = {imageFile.m_Width, imageFile.m_Height},
|
.m_Extent = {imageFile.m_Width, imageFile.m_Height},
|
||||||
.m_Name = "Crate Texture",
|
.m_Name = "Crate Texture",
|
||||||
})
|
});
|
||||||
.ToPointer();
|
|
||||||
|
|
||||||
{
|
{
|
||||||
StagingBuffer imageStaging;
|
StagingBuffer imageStaging;
|
||||||
|
|
||||||
imageStaging.Init(&device, imageFile.GetSize(), "Image Staging");
|
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 = {
|
vk::ImageMemoryBarrier2 imageReadyToWrite = {
|
||||||
.srcStageMask = vk::PipelineStageFlagBits2::eTransfer,
|
.srcStageMask = vk::PipelineStageFlagBits2::eTransfer,
|
||||||
|
|
@ -315,17 +319,11 @@ main(int, char **)
|
||||||
AbortIfFailedM(device.m_Device.resetCommandPool(copyPool, {}), "Couldn't reset command pool.");
|
AbortIfFailedM(device.m_Device.resetCommandPool(copyPool, {}), "Couldn't reset command pool.");
|
||||||
|
|
||||||
device.m_Device.destroy(fence, nullptr);
|
device.m_Device.destroy(fence, nullptr);
|
||||||
imageStaging.Destroy(&device);
|
imageStaging.Destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ubo = renderResourceManager.CreateStorageBuffer(sizeof camera, "Camera UBO");
|
auto ubo = bufferManager.CreateStorageBuffer(sizeof camera, "Camera UBO");
|
||||||
renderResourceManager.Write(ubo, 0, sizeof camera, &camera);
|
ubo->Write(0, sizeof camera, &camera);
|
||||||
|
|
||||||
renderResourceManager.Commit(ubo);
|
|
||||||
renderResourceManager.Commit(vbo);
|
|
||||||
renderResourceManager.Commit(crate);
|
|
||||||
|
|
||||||
renderResourceManager.Update();
|
|
||||||
|
|
||||||
// Persistent variables
|
// Persistent variables
|
||||||
vk::Viewport viewport = {
|
vk::Viewport viewport = {
|
||||||
|
|
@ -391,13 +389,13 @@ main(int, char **)
|
||||||
};
|
};
|
||||||
|
|
||||||
FrameManager frameManager = {&device, queueAllocation.m_Family, MAX_FRAMES_IN_FLIGHT};
|
FrameManager frameManager = {&device, queueAllocation.m_Family, MAX_FRAMES_IN_FLIGHT};
|
||||||
eastl::fixed_vector<systems::Ref<Image>, MAX_FRAMES_IN_FLIGHT> depthImages;
|
eastl::fixed_vector<systems::ImageHandle, MAX_FRAMES_IN_FLIGHT> 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)
|
for (u32 i = 0; i < frameManager.m_FramesInFlight; ++i)
|
||||||
{
|
{
|
||||||
depthImages.push_back(
|
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
|
struct PCB
|
||||||
{
|
{
|
||||||
systems::BufferHandle m_Camera;
|
systems::CommitEntry<Buffer> m_Camera;
|
||||||
systems::BufferHandle m_VertexBuffer;
|
systems::CommitEntry<Buffer> m_VertexBuffer;
|
||||||
systems::ImageHandle m_Texture;
|
systems::CommitEntry<Image> m_Texture;
|
||||||
};
|
};
|
||||||
|
|
||||||
PCB pcb = {
|
PCB pcb = {
|
||||||
.m_Camera = std::move(ubo),
|
.m_Camera = renderResourceManager.Commit(ubo),
|
||||||
.m_VertexBuffer = std::move(vbo),
|
.m_VertexBuffer = renderResourceManager.Commit(vbo),
|
||||||
.m_Texture = std::move(crate),
|
.m_Texture = renderResourceManager.Commit(crate),
|
||||||
};
|
};
|
||||||
|
|
||||||
Time::Init();
|
Time::Init();
|
||||||
|
|
@ -428,9 +426,10 @@ main(int, char **)
|
||||||
while (window.Poll())
|
while (window.Poll())
|
||||||
{
|
{
|
||||||
Time::Update();
|
Time::Update();
|
||||||
|
renderResourceManager.Update();
|
||||||
|
|
||||||
camera.m_Model *= rotate(mat4{1.0f}, Cast<f32>(45.0_deg * Time::m_Delta), vec3(0.0f, 1.0f, 0.0f));
|
camera.m_Model *= rotate(mat4{1.0f}, Cast<f32>(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());
|
Frame *currentFrame = frameManager.GetNextFrame(&swapchain, &surface, window.GetSize());
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,5 +5,5 @@ cmake_minimum_required(VERSION 3.13)
|
||||||
add_subdirectory("00_util")
|
add_subdirectory("00_util")
|
||||||
add_subdirectory("01_triangle")
|
add_subdirectory("01_triangle")
|
||||||
add_subdirectory("02_box")
|
add_subdirectory("02_box")
|
||||||
add_subdirectory("03_model_render")
|
# add_subdirectory("03_model_render")
|
||||||
add_subdirectory("04_scenes")
|
# add_subdirectory("04_scenes")
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue