RenderResourceManager handles images and bindless.
This commit is contained in:
parent
3a7bea902f
commit
396810d203
|
|
@ -18,4 +18,5 @@ INTERFACE
|
|||
"surface.h"
|
||||
"size.h"
|
||||
"type_traits.h"
|
||||
"window.h")
|
||||
"window.h"
|
||||
"sampler.h")
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ struct Buffer
|
|||
};
|
||||
|
||||
template <>
|
||||
constexpr bool concepts::GpuResource<Buffer> = true;
|
||||
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));
|
||||
|
|
|
|||
|
|
@ -211,3 +211,13 @@ struct fmt::formatter<eastl::fixed_string<TType, TCount, TOverflow>> : nested_fo
|
|||
return write_padded(ctx, [this, str](auto out) { return v10::format_to(out, "{}", nested(str.c_str())); });
|
||||
}
|
||||
};
|
||||
|
||||
namespace aster
|
||||
{
|
||||
template <typename TRef, typename TVal>
|
||||
TVal &
|
||||
Deref(TRef ref)
|
||||
{
|
||||
return ref.Deref();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ struct Image
|
|||
};
|
||||
|
||||
template <>
|
||||
constexpr bool concepts::GpuResource<Image> = true;
|
||||
constexpr bool concepts::Resource<Image> = true;
|
||||
|
||||
struct Texture : Image
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,46 @@
|
|||
// =============================================
|
||||
// Aster: sampler.h
|
||||
// Copyright (c) 2020-2024 Anish Bhobe
|
||||
// =============================================
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "global.h"
|
||||
|
||||
struct Device;
|
||||
|
||||
// TODO Refactor the Buffer Hierarchy
|
||||
|
||||
struct Sampler
|
||||
{
|
||||
vk::Sampler m_Sampler = nullptr;
|
||||
bool m_Committed = false;
|
||||
|
||||
void Init(const Device *device, const vk::SamplerCreateInfo &samplerCreateInfo, cstr name);
|
||||
void Destroy(const Device *device);
|
||||
|
||||
[[nodiscard]] bool IsValid() const;
|
||||
[[nodiscard]] bool IsCommitted() const;
|
||||
void SetCommitted(bool committed);
|
||||
};
|
||||
|
||||
template <>
|
||||
constexpr bool concepts::Opaque<Sampler> = true;
|
||||
|
||||
inline bool
|
||||
Sampler::IsValid() const
|
||||
{
|
||||
return m_Sampler;
|
||||
}
|
||||
|
||||
inline bool
|
||||
Sampler::IsCommitted() const
|
||||
{
|
||||
return m_Committed;
|
||||
}
|
||||
|
||||
inline void
|
||||
Sampler::SetCommitted(const bool committed)
|
||||
{
|
||||
m_Committed = committed;
|
||||
}
|
||||
|
|
@ -9,6 +9,12 @@ struct Device;
|
|||
|
||||
namespace concepts
|
||||
{
|
||||
template <typename THandle, typename TValue>
|
||||
concept Fetches = requires(THandle h)
|
||||
{
|
||||
{ h.Fetch() } -> std::same_as<TValue*>;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
concept DeviceDestructible = requires(T a, Device *p) {
|
||||
{ a.Destroy(p) } -> std::convertible_to<void>;
|
||||
|
|
@ -21,16 +27,24 @@ concept Committable = requires(T a, bool v) {
|
|||
};
|
||||
|
||||
template <typename T>
|
||||
constexpr bool GpuResource = false;
|
||||
constexpr bool Resource = 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>;
|
||||
constexpr bool Opaque = false;
|
||||
|
||||
template <typename T>
|
||||
constexpr bool IsHandle = false;
|
||||
concept Consistent = (Resource<T> and !Opaque<T>) or (Opaque<T> and !Resource<T>);
|
||||
|
||||
template <typename THandle>
|
||||
concept HandleType = IsHandle<THandle> and RenderResource<typename THandle::Type>;
|
||||
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
|
||||
|
|
@ -7,4 +7,5 @@ INTERFACE
|
|||
"manager.h"
|
||||
"buffer_manager.h"
|
||||
"image_manager.h"
|
||||
"sampler_manager.h"
|
||||
"render_resource_manager.h")
|
||||
|
|
|
|||
|
|
@ -10,10 +10,13 @@
|
|||
|
||||
struct Device;
|
||||
|
||||
template <concepts::RenderResource T>
|
||||
namespace systems
|
||||
{
|
||||
|
||||
template <concepts::ShaderObject T>
|
||||
class Handle;
|
||||
|
||||
template <concepts::RenderResource T>
|
||||
template <concepts::ShaderObject T>
|
||||
class Manager
|
||||
{
|
||||
friend Handle<T>;
|
||||
|
|
@ -35,7 +38,7 @@ class Manager
|
|||
, m_Binding{binding}
|
||||
, m_Device{device}
|
||||
{
|
||||
assert(!m_Instance);
|
||||
assert(!m_Instance && "Attempting to initialize a second Manager");
|
||||
assert(maxCount <= MAX_HANDLES);
|
||||
|
||||
m_Data = new Type[m_MaxCount];
|
||||
|
|
@ -77,7 +80,7 @@ class Manager
|
|||
static Manager *
|
||||
Instance()
|
||||
{
|
||||
assert(m_Instance);
|
||||
assert(m_Instance && "Not initialized yet.");
|
||||
return m_Instance;
|
||||
}
|
||||
|
||||
|
|
@ -151,7 +154,7 @@ class Manager
|
|||
}
|
||||
};
|
||||
|
||||
template <concepts::RenderResource T>
|
||||
template <concepts::ShaderObject T>
|
||||
class Ref
|
||||
{
|
||||
public:
|
||||
|
|
@ -173,14 +176,14 @@ class Ref
|
|||
|
||||
public:
|
||||
Type *
|
||||
Get()
|
||||
Fetch()
|
||||
{
|
||||
assert(m_Pointer);
|
||||
return m_Pointer;
|
||||
}
|
||||
|
||||
const Type *
|
||||
Get() const
|
||||
Fetch() const
|
||||
{
|
||||
assert(m_Pointer);
|
||||
return m_Pointer;
|
||||
|
|
@ -189,25 +192,35 @@ class Ref
|
|||
Type *
|
||||
operator->()
|
||||
{
|
||||
return Get();
|
||||
return Fetch();
|
||||
}
|
||||
|
||||
const Type *
|
||||
operator->() const
|
||||
{
|
||||
return Get();
|
||||
return Fetch();
|
||||
}
|
||||
|
||||
Type &
|
||||
operator*()
|
||||
{
|
||||
return *Get();
|
||||
return *Fetch();
|
||||
}
|
||||
|
||||
const Type &
|
||||
operator*() const
|
||||
{
|
||||
return Get();
|
||||
return Fetch();
|
||||
}
|
||||
|
||||
operator Handle &()
|
||||
{
|
||||
return m_Handle;
|
||||
}
|
||||
|
||||
operator const Handle &() const
|
||||
{
|
||||
return m_Handle;
|
||||
}
|
||||
|
||||
// The only constructor requires a valid construction.
|
||||
|
|
@ -231,8 +244,13 @@ class Ref
|
|||
~Ref() = default;
|
||||
};
|
||||
|
||||
class RawHandle
|
||||
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;
|
||||
|
|
@ -240,17 +258,29 @@ class RawHandle
|
|||
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)}
|
||||
// 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();
|
||||
}
|
||||
|
||||
explicit RawHandle(const u32 internal)
|
||||
: m_Internal{internal}
|
||||
{
|
||||
}
|
||||
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
|
||||
|
|
@ -271,52 +301,21 @@ class RawHandle
|
|||
}
|
||||
|
||||
bool
|
||||
operator==(const RawHandle &other) const
|
||||
operator==(const Handle &other) const
|
||||
{
|
||||
return m_Internal == other.m_Internal;
|
||||
}
|
||||
};
|
||||
|
||||
template <concepts::RenderResource T>
|
||||
class Handle : public RawHandle
|
||||
{
|
||||
public:
|
||||
using Type = T;
|
||||
using Manager = Manager<Type>;
|
||||
|
||||
protected:
|
||||
// The only constructor requires a valid construction.
|
||||
Handle(const u32 index, const u8 typeId)
|
||||
: RawHandle{index, typeId}
|
||||
{
|
||||
AddRef();
|
||||
}
|
||||
|
||||
friend Manager;
|
||||
friend Ref<T>;
|
||||
|
||||
public:
|
||||
Handle(const Handle &other)
|
||||
: RawHandle{other}
|
||||
{
|
||||
m_Internal = other.m_Internal;
|
||||
AddRef();
|
||||
}
|
||||
|
||||
Handle(Handle &&other) noexcept
|
||||
: RawHandle{std::exchange(other.m_Internal, m_Internal)}
|
||||
{
|
||||
}
|
||||
|
||||
[[nodiscard]] Ref<T>
|
||||
ToPointer()
|
||||
{
|
||||
return Ref{std::move(*this)};
|
||||
}
|
||||
|
||||
[[nodiscard]] Type *
|
||||
Fetch() const
|
||||
{
|
||||
return Manager::Instance()->Fetch(m_Internal);
|
||||
m_Internal = other.m_Internal;
|
||||
other.m_Internal = INVALID_HANDLE;
|
||||
}
|
||||
|
||||
Handle &
|
||||
|
|
@ -359,3 +358,5 @@ class Handle : public RawHandle
|
|||
Manager::Instance()->Release(GetIndex());
|
||||
}
|
||||
};
|
||||
} // namespace systems
|
||||
|
||||
|
|
|
|||
|
|
@ -8,9 +8,11 @@
|
|||
#include "aster/aster.h"
|
||||
#include "buffer_manager.h"
|
||||
#include "image_manager.h"
|
||||
#include "sampler_manager.h"
|
||||
|
||||
#include "EASTL/deque.h"
|
||||
#include "EASTL/vector.h"
|
||||
#include <variant>
|
||||
|
||||
namespace systems
|
||||
{
|
||||
|
|
@ -30,122 +32,63 @@ class RenderResourceManager
|
|||
|
||||
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;
|
||||
};
|
||||
//using WriteOwner = std::variant<Handle<Buffer>, Handle<Image>>;
|
||||
|
||||
public:
|
||||
RenderResourceManager(const Device *device, u32 maxBuffers, u32 maxImages);
|
||||
const Device *m_Device;
|
||||
|
||||
void Commit(concepts::HandleType auto &handle);
|
||||
RenderResourceManager(const Device *device, u32 maxBuffers, u32 maxImages, u32 maxSamplers);
|
||||
~RenderResourceManager();
|
||||
|
||||
private:
|
||||
PIN_MEMORY(RenderResourceManager);
|
||||
|
||||
// Buffer
|
||||
[[nodiscard]] BufferHandle CreateStorageBuffer(usize size, cstr name = nullptr);
|
||||
[[nodiscard]] BufferHandle CreateUniformBuffer(usize size, cstr name = nullptr);
|
||||
|
||||
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();
|
||||
|
||||
[[nodiscard]] const vk::DescriptorSetLayout&
|
||||
GetDescriptorSetLayout() const
|
||||
{
|
||||
return m_SetLayout;
|
||||
}
|
||||
|
||||
[[nodiscard]] const vk::DescriptorSet& GetDescriptorSet() const
|
||||
{
|
||||
return m_DescriptorSet;
|
||||
}
|
||||
|
||||
private:
|
||||
BufferManager m_BufferManager;
|
||||
ImageManager m_ImageManager;
|
||||
SamplerManager m_SamplerManager;
|
||||
|
||||
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;
|
||||
constexpr static u8 BUFFER_BINDING_INDEX = 0x0;
|
||||
constexpr static u8 IMAGE_BINDING_INDEX = 0x1;
|
||||
constexpr static u8 SAMPLER_TYPE_INDEX = 0xF;
|
||||
|
||||
eastl::vector<vk::WriteDescriptorSet> m_Writes;
|
||||
eastl::deque<WriteInfo> m_WriteInfos;
|
||||
eastl::vector<WriteOwner> m_WriteOwner;
|
||||
// eastl::vector<WriteOwner> m_WriteOwner;
|
||||
|
||||
#if !defined(ASTER_NDEBUG)
|
||||
usize m_CommitedBufferCount = 0;
|
||||
|
|
@ -153,5 +96,4 @@ class RenderResourceManager
|
|||
usize m_CommitedStorageTextureCount = 0;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace systems
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
// =============================================
|
||||
// Aster: sampler_manager.h
|
||||
// Copyright (c) 2020-2024 Anish Bhobe
|
||||
// =============================================
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "EASTL/vector_map.h"
|
||||
#include "aster/aster.h"
|
||||
#include "aster/core/sampler.h"
|
||||
#include "manager.h"
|
||||
|
||||
namespace systems
|
||||
{
|
||||
using SamplerHandle = Handle<Sampler>;
|
||||
|
||||
struct SamplerCreateInfo : vk::SamplerCreateInfo
|
||||
{
|
||||
cstr m_Name = nullptr;
|
||||
|
||||
SamplerCreateInfo()
|
||||
: vk::SamplerCreateInfo{
|
||||
.magFilter = vk::Filter::eLinear,
|
||||
.minFilter = vk::Filter::eLinear,
|
||||
.mipmapMode = vk::SamplerMipmapMode::eLinear,
|
||||
.addressModeU = vk::SamplerAddressMode::eRepeat,
|
||||
.addressModeV = vk::SamplerAddressMode::eRepeat,
|
||||
.addressModeW = vk::SamplerAddressMode::eRepeat,
|
||||
.mipLodBias = 0.0f,
|
||||
.anisotropyEnable = true,
|
||||
.maxAnisotropy = 16,
|
||||
.compareEnable = false,
|
||||
.minLod = 0,
|
||||
.maxLod = VK_LOD_CLAMP_NONE,
|
||||
.borderColor = vk::BorderColor::eFloatOpaqueBlack,
|
||||
.unnormalizedCoordinates = false,
|
||||
}
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @class SamplerManager sampler_manager.h
|
||||
*
|
||||
* Manages (and caches) objects of sampler. Currently Samplers are never deleted.
|
||||
*/
|
||||
class SamplerManager final : public Manager<Sampler>
|
||||
{
|
||||
eastl::vector_map<usize, Handle> m_HashToSamplerIdx;
|
||||
|
||||
public:
|
||||
SamplerManager(const Device *device, const u32 maxCount, const u8 typeId);
|
||||
~SamplerManager() override;
|
||||
|
||||
SamplerHandle Create(const SamplerCreateInfo &createInfo);
|
||||
};
|
||||
} // namespace systems
|
||||
|
|
@ -13,4 +13,5 @@ PRIVATE
|
|||
"buffer.cpp"
|
||||
"image.cpp"
|
||||
"surface.cpp"
|
||||
"window.cpp")
|
||||
"window.cpp"
|
||||
"sampler.cpp")
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
// =============================================
|
||||
// Aster: sampler.cpp
|
||||
// Copyright (c) 2020-2024 Anish Bhobe
|
||||
// =============================================
|
||||
|
||||
#include "core/sampler.h"
|
||||
|
||||
#include "core/device.h"
|
||||
|
||||
void
|
||||
Sampler::Destroy(const Device *device)
|
||||
{
|
||||
if (!IsValid())
|
||||
return;
|
||||
|
||||
device->m_Device.destroy(Take(m_Sampler), nullptr);
|
||||
}
|
||||
|
||||
void
|
||||
Sampler::Init(const Device *device, const vk::SamplerCreateInfo &samplerCreateInfo, cstr name)
|
||||
{
|
||||
const auto result = device->m_Device.createSampler(&samplerCreateInfo, nullptr, &m_Sampler);
|
||||
ERROR_IF(Failed(result), "Could not create a sampler {}", name ? name : "<unnamed>") THEN_ABORT(-1);
|
||||
}
|
||||
|
|
@ -7,4 +7,5 @@ PRIVATE
|
|||
"manager.cpp"
|
||||
"buffer_manager.cpp"
|
||||
"image_manager.cpp"
|
||||
"sampler_manager.cpp"
|
||||
"render_resource_manager.cpp")
|
||||
|
|
|
|||
|
|
@ -5,10 +5,10 @@
|
|||
|
||||
#include "systems/buffer_manager.h"
|
||||
|
||||
Manager<Buffer> *Manager<Buffer>::m_Instance = nullptr;
|
||||
|
||||
using namespace systems;
|
||||
|
||||
Manager<Buffer> *Manager<Buffer>::m_Instance = nullptr;
|
||||
|
||||
BufferHandle
|
||||
BufferManager::CreateStorageBuffer(const usize size, const cstr name)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -7,10 +7,10 @@
|
|||
|
||||
#include "core/device.h"
|
||||
|
||||
Manager<Image> *Manager<Image>::m_Instance = nullptr;
|
||||
|
||||
using namespace systems;
|
||||
|
||||
Manager<Image> *Manager<Image>::m_Instance = nullptr;
|
||||
|
||||
vk::ImageCreateInfo ToImageCreateInfo(const Texture2DCreateInfo &createInfo);
|
||||
vk::ImageCreateInfo ToImageCreateInfo(const TextureCubeCreateInfo &createInfo);
|
||||
vk::ImageCreateInfo ToImageCreateInfo(const AttachmentCreateInfo &createInfo);
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@
|
|||
|
||||
#include "systems/render_resource_manager.h"
|
||||
|
||||
#include "EASTL/array.h"
|
||||
#include "core/device.h"
|
||||
#include "EASTL/array.h"
|
||||
|
||||
#define AbortIfFailed(RESULT) \
|
||||
do \
|
||||
|
|
@ -31,28 +31,14 @@
|
|||
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}
|
||||
RenderResourceManager::RenderResourceManager(const Device *device, u32 const maxBuffers, const u32 maxImages,
|
||||
const u32 maxSamplers)
|
||||
: m_Device{device}
|
||||
, m_BufferManager{device, maxBuffers, BUFFER_BINDING_INDEX}
|
||||
, m_ImageManager{device, maxImages, IMAGE_BINDING_INDEX}
|
||||
, m_SamplerManager{device, maxSamplers, SAMPLER_TYPE_INDEX}
|
||||
{
|
||||
eastl::array poolSizes = {
|
||||
vk::DescriptorPoolSize{
|
||||
|
|
@ -63,10 +49,10 @@ RenderResourceManager::RenderResourceManager(const Device *device, u32 const max
|
|||
.type = vk::DescriptorType::eCombinedImageSampler,
|
||||
.descriptorCount = maxImages,
|
||||
},
|
||||
//vk::DescriptorPoolSize{
|
||||
// vk::DescriptorPoolSize{
|
||||
// .type = vk::DescriptorType::eStorageImage,
|
||||
// .descriptorCount = storageTexturesCount,
|
||||
//},
|
||||
// },
|
||||
};
|
||||
|
||||
const vk::DescriptorPoolCreateInfo poolCreateInfo = {
|
||||
|
|
@ -90,12 +76,12 @@ RenderResourceManager::RenderResourceManager(const Device *device, u32 const max
|
|||
.descriptorCount = Cast<u32>(maxImages),
|
||||
.stageFlags = vk::ShaderStageFlagBits::eAll,
|
||||
},
|
||||
//vk::DescriptorSetLayoutBinding{
|
||||
// vk::DescriptorSetLayoutBinding{
|
||||
// .binding = STORAGE_TEXTURE_BINDING_INDEX,
|
||||
// .descriptorType = vk::DescriptorType::eStorageImage,
|
||||
// .descriptorCount = Cast<u32>(storageTexturesCount),
|
||||
// .stageFlags = vk::ShaderStageFlagBits::eAll,
|
||||
//},
|
||||
// },
|
||||
};
|
||||
|
||||
vk::DescriptorBindingFlags bindingFlags =
|
||||
|
|
@ -133,13 +119,69 @@ RenderResourceManager::RenderResourceManager(const Device *device, u32 const max
|
|||
device->SetName(m_DescriptorSet, "Bindless Set");
|
||||
}
|
||||
|
||||
void
|
||||
systems::RenderResourceManager::Commit(concepts::HandleType auto &handle)
|
||||
RenderResourceManager::~RenderResourceManager()
|
||||
{
|
||||
using HandleType = decltype(handle)::Type;
|
||||
if constexpr (std::is_same_v<HandleType, Buffer>)
|
||||
|
||||
#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_DescriptorPool, nullptr);
|
||||
}
|
||||
|
||||
void
|
||||
RenderResourceManager::Write(const BufferHandle &handle, const usize offset, const usize size, const void *data) const
|
||||
{
|
||||
handle.Fetch()->Write(m_Device, offset, size, data);
|
||||
}
|
||||
|
||||
BufferHandle RenderResourceManager::CreateStorageBuffer(const usize size, const cstr name)
|
||||
{
|
||||
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())
|
||||
{
|
||||
const Buffer *buffer = handle.Fetch();
|
||||
WARN("Buffer is already committed");
|
||||
return;
|
||||
}
|
||||
|
||||
m_WriteInfos.emplace_back(vk::DescriptorBufferInfo{
|
||||
.buffer = buffer->m_Buffer,
|
||||
|
|
@ -154,13 +196,34 @@ systems::RenderResourceManager::Commit(concepts::HandleType auto &handle)
|
|||
.descriptorType = vk::DescriptorType::eStorageBuffer,
|
||||
.pBufferInfo = &m_WriteInfos.back().uBufferInfo,
|
||||
});
|
||||
}
|
||||
else if constexpr (std::is_same_v<HandleType, Image>)
|
||||
|
||||
buffer->SetCommitted(true);
|
||||
#if !defined(ASTER_NDEBUG)
|
||||
++m_CommitedBufferCount;
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
RenderResourceManager::Commit(const ImageHandle &handle)
|
||||
{
|
||||
const auto sampler = m_SamplerManager.Create({});
|
||||
Commit(handle, sampler);
|
||||
}
|
||||
|
||||
void
|
||||
RenderResourceManager::Commit(const ImageHandle &handle, const SamplerHandle &samplerHandle)
|
||||
{
|
||||
Image *image = handle.Fetch();
|
||||
if (image->IsCommitted())
|
||||
{
|
||||
const Image *image = handle.Fetch();
|
||||
WARN("Image is already committed");
|
||||
return;
|
||||
}
|
||||
|
||||
Sampler *sampler = samplerHandle.Fetch();
|
||||
|
||||
m_WriteInfos.emplace_back(vk::DescriptorImageInfo{
|
||||
.sampler = nullptr /* TODO Sampler */,
|
||||
.sampler = sampler->m_Sampler,
|
||||
.imageView = image->m_View,
|
||||
.imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal,
|
||||
});
|
||||
|
|
@ -169,14 +232,15 @@ systems::RenderResourceManager::Commit(concepts::HandleType auto &handle)
|
|||
.dstBinding = IMAGE_BINDING_INDEX,
|
||||
.dstArrayElement = handle.GetIndex(),
|
||||
.descriptorCount = 1,
|
||||
.descriptorType = vk::DescriptorType::eSampledImage,
|
||||
.descriptorType = vk::DescriptorType::eCombinedImageSampler,
|
||||
.pImageInfo = &m_WriteInfos.back().uImageInfo,
|
||||
});
|
||||
} else {
|
||||
static_assert(false && "Type is currently unsupported");
|
||||
}
|
||||
|
||||
m_WriteOwner.emplace_back(handle);
|
||||
image->SetCommitted(true);
|
||||
sampler->SetCommitted(true);
|
||||
#if !defined(ASTER_NDEBUG)
|
||||
++m_CommitedTextureCount;
|
||||
#endif
|
||||
}
|
||||
|
||||
RenderResourceManager::WriteInfo::WriteInfo(const vk::DescriptorBufferInfo &info)
|
||||
|
|
@ -193,3 +257,22 @@ RenderResourceManager::WriteInfo::WriteInfo(const vk::BufferView &info)
|
|||
: uBufferView{info}
|
||||
{
|
||||
}
|
||||
|
||||
SamplerHandle
|
||||
RenderResourceManager::CreateSampler(const SamplerCreateInfo &createInfo)
|
||||
{
|
||||
return m_SamplerManager.Create(createInfo);
|
||||
}
|
||||
|
||||
void
|
||||
RenderResourceManager::Update()
|
||||
{
|
||||
// Descriptor Updates
|
||||
if (!m_Writes.empty())
|
||||
{
|
||||
m_Device->m_Device.updateDescriptorSets(Cast<u32>(m_Writes.size()), m_Writes.data(), 0, nullptr);
|
||||
|
||||
m_Writes.clear();
|
||||
m_WriteInfos.clear();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,66 @@
|
|||
// =============================================
|
||||
// Aster: sampler_manager.cpp
|
||||
// Copyright (c) 2020-2025 Anish Bhobe
|
||||
// =============================================
|
||||
|
||||
#include "systems/sampler_manager.h"
|
||||
|
||||
#include "core/device.h"
|
||||
|
||||
using namespace systems;
|
||||
|
||||
Manager<Sampler> *Manager<Sampler>::m_Instance = nullptr;
|
||||
|
||||
usize
|
||||
HashSamplerCreateInfo(const vk::SamplerCreateInfo &createInfo)
|
||||
{
|
||||
usize hash = HashAny(createInfo.flags);
|
||||
hash = HashCombine(hash, HashAny(createInfo.magFilter));
|
||||
hash = HashCombine(hash, HashAny(createInfo.minFilter));
|
||||
hash = HashCombine(hash, HashAny(createInfo.mipmapMode));
|
||||
hash = HashCombine(hash, HashAny(createInfo.addressModeU));
|
||||
hash = HashCombine(hash, HashAny(createInfo.addressModeV));
|
||||
hash = HashCombine(hash, HashAny(createInfo.addressModeW));
|
||||
hash = HashCombine(hash, HashAny(Cast<usize>(createInfo.mipLodBias * 1000))); // Resolution of 10^-3
|
||||
hash = HashCombine(hash, HashAny(createInfo.anisotropyEnable));
|
||||
hash = HashCombine(hash,
|
||||
HashAny(Cast<usize>(createInfo.maxAnisotropy * 0x20))); // 32:1 Anisotropy is enough resolution
|
||||
hash = HashCombine(hash, HashAny(createInfo.compareEnable));
|
||||
hash = HashCombine(hash, HashAny(createInfo.compareOp));
|
||||
hash = HashCombine(hash, HashAny(Cast<usize>(createInfo.minLod * 1000))); // 0.001 resolution is enough.
|
||||
hash = HashCombine(hash,
|
||||
HashAny(Cast<usize>(createInfo.maxLod * 1000))); // 0.001 resolution is enough. (1 == NO Clamp)
|
||||
hash = HashCombine(hash, HashAny(createInfo.borderColor));
|
||||
hash = HashCombine(hash, HashAny(createInfo.unnormalizedCoordinates));
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
SamplerManager::SamplerManager(const Device *device, const u32 maxCount, const u8 typeId)
|
||||
: Manager{device, maxCount, typeId}
|
||||
{
|
||||
}
|
||||
|
||||
SamplerManager::~SamplerManager()
|
||||
{
|
||||
m_HashToSamplerIdx.clear();
|
||||
}
|
||||
|
||||
SamplerHandle
|
||||
SamplerManager::Create(const SamplerCreateInfo &createInfo)
|
||||
{
|
||||
const auto hash = HashSamplerCreateInfo(createInfo);
|
||||
|
||||
if (const auto iter = m_HashToSamplerIdx.find(hash); iter != m_HashToSamplerIdx.end())
|
||||
{
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
auto [handle, object] = Alloc();
|
||||
|
||||
object->Init(m_Device, createInfo, createInfo.m_Name ? createInfo.m_Name : nullptr);
|
||||
m_HashToSamplerIdx.emplace(hash, handle);
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
|
|
@ -20,6 +20,7 @@
|
|||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include "aster/systems/buffer_manager.h"
|
||||
#include "aster/systems/image_manager.h"
|
||||
#include "aster/systems/render_resource_manager.h"
|
||||
#include "frame.h"
|
||||
#include "stb_image.h"
|
||||
|
||||
|
|
@ -73,7 +74,7 @@ ImageFile::~ImageFile()
|
|||
}
|
||||
|
||||
vk::ShaderModule CreateShader(const Device *device, cstr shaderFile);
|
||||
Pipeline CreatePipeline(const Device *device, const Swapchain *swapchain);
|
||||
Pipeline CreatePipeline(const systems::RenderResourceManager *resourceManager, const Swapchain *swapchain);
|
||||
|
||||
struct Vertex
|
||||
{
|
||||
|
|
@ -106,17 +107,30 @@ main(int, char **)
|
|||
|
||||
Features enabledDeviceFeatures = {
|
||||
.m_Vulkan10Features = {.samplerAnisotropy = true},
|
||||
.m_Vulkan12Features = {.bufferDeviceAddress = true},
|
||||
.m_Vulkan12Features =
|
||||
{
|
||||
.descriptorIndexing = true,
|
||||
.shaderSampledImageArrayNonUniformIndexing = true,
|
||||
.shaderStorageBufferArrayNonUniformIndexing = true,
|
||||
.shaderStorageImageArrayNonUniformIndexing = true,
|
||||
.descriptorBindingUniformBufferUpdateAfterBind = true, // Not related to Bindless
|
||||
.descriptorBindingSampledImageUpdateAfterBind = true,
|
||||
.descriptorBindingStorageImageUpdateAfterBind = true,
|
||||
.descriptorBindingStorageBufferUpdateAfterBind = true,
|
||||
.descriptorBindingPartiallyBound = true,
|
||||
.runtimeDescriptorArray = true,
|
||||
.bufferDeviceAddress = true,
|
||||
.bufferDeviceAddressCaptureReplay = true,
|
||||
},
|
||||
.m_Vulkan13Features = {.synchronization2 = true, .dynamicRendering = true},
|
||||
};
|
||||
QueueAllocation queueAllocation = FindAppropriateQueueAllocation(&deviceToUse);
|
||||
Device device = {&context, &deviceToUse, &enabledDeviceFeatures, {queueAllocation}, "Primary Device"};
|
||||
vk::Queue commandQueue = device.GetQueue(queueAllocation.m_Family, 0);
|
||||
Swapchain swapchain = {&surface, &device, window.GetSize(), "Primary Chain"};
|
||||
Pipeline pipeline = CreatePipeline(&device, &swapchain);
|
||||
systems::RenderResourceManager renderResourceManager{&device, 12, 12, 1};
|
||||
|
||||
systems::BufferManager bufferManager{&device, 12, 0};
|
||||
systems::ImageManager imageManager{&device, 12, 1};
|
||||
Pipeline pipeline = CreatePipeline(&renderResourceManager, &swapchain);
|
||||
|
||||
Camera camera = {
|
||||
.m_Model = {1.0f},
|
||||
|
|
@ -125,36 +139,6 @@ main(int, char **)
|
|||
70_deg, Cast<f32>(swapchain.m_Extent.width) / Cast<f32>(swapchain.m_Extent.height), 0.1f, 100.0f),
|
||||
};
|
||||
|
||||
vk::DescriptorPool descriptorPool;
|
||||
vk::DescriptorSet descriptorSet;
|
||||
{
|
||||
vk::DescriptorSetLayout descriptorSetLayout = pipeline.m_SetLayouts.front();
|
||||
eastl::array poolSizes = {
|
||||
vk::DescriptorPoolSize{
|
||||
.type = vk::DescriptorType::eUniformBuffer,
|
||||
.descriptorCount = 1,
|
||||
},
|
||||
vk::DescriptorPoolSize{
|
||||
.type = vk::DescriptorType::eCombinedImageSampler,
|
||||
.descriptorCount = 1,
|
||||
},
|
||||
vk::DescriptorPoolSize{
|
||||
.type = vk::DescriptorType::eStorageBuffer,
|
||||
.descriptorCount = 1,
|
||||
},
|
||||
};
|
||||
vk::DescriptorPoolCreateInfo descriptorPoolCreateInfo = {
|
||||
.maxSets = 1, .poolSizeCount = Cast<u32>(poolSizes.size()), .pPoolSizes = poolSizes.data()};
|
||||
AbortIfFailed(device.m_Device.createDescriptorPool(&descriptorPoolCreateInfo, nullptr, &descriptorPool));
|
||||
|
||||
vk::DescriptorSetAllocateInfo descriptorSetAllocateInfo = {
|
||||
.descriptorPool = descriptorPool,
|
||||
.descriptorSetCount = 1,
|
||||
.pSetLayouts = &descriptorSetLayout,
|
||||
};
|
||||
AbortIfFailed(device.m_Device.allocateDescriptorSets(&descriptorSetAllocateInfo, &descriptorSet));
|
||||
}
|
||||
|
||||
vk::CommandPool copyPool;
|
||||
vk::CommandBuffer copyBuffer;
|
||||
{
|
||||
|
|
@ -222,15 +206,16 @@ main(int, char **)
|
|||
assert(loaded);
|
||||
INFO("Image {}x{} : {} channels", imageFile.m_Width, imageFile.m_Height, imageFile.m_NumChannels);
|
||||
|
||||
auto vbo = bufferManager.CreateStorageBuffer(vertices.size() * sizeof vertices[0], "Vertex Buffer").ToPointer();
|
||||
auto crate = imageManager
|
||||
auto vbo = renderResourceManager.CreateStorageBuffer(vertices.size() * sizeof vertices[0], "Vertex Buffer");
|
||||
renderResourceManager.Write(vbo, 0, vertices.size() * sizeof vertices[0], vertices.data());
|
||||
|
||||
auto crate = renderResourceManager
|
||||
.CreateTexture2D({
|
||||
.m_Format = vk::Format::eR8G8B8A8Srgb,
|
||||
.m_Extent = {imageFile.m_Width, imageFile.m_Height},
|
||||
.m_Name = "Crate Texture",
|
||||
})
|
||||
.ToPointer();
|
||||
vbo->Write(&device, 0, vertices.size() * sizeof vertices[0], vertices.data());
|
||||
|
||||
{
|
||||
StagingBuffer imageStaging;
|
||||
|
|
@ -333,70 +318,14 @@ main(int, char **)
|
|||
imageStaging.Destroy(&device);
|
||||
}
|
||||
|
||||
vk::Sampler sampler;
|
||||
{
|
||||
vk::SamplerCreateInfo samplerCreateInfo = {
|
||||
.magFilter = vk::Filter::eLinear,
|
||||
.minFilter = vk::Filter::eLinear,
|
||||
.mipmapMode = vk::SamplerMipmapMode::eLinear,
|
||||
.addressModeU = vk::SamplerAddressMode::eRepeat,
|
||||
.addressModeV = vk::SamplerAddressMode::eRepeat,
|
||||
.addressModeW = vk::SamplerAddressMode::eRepeat,
|
||||
.mipLodBias = 0.2f,
|
||||
.anisotropyEnable = true,
|
||||
.maxAnisotropy = 1.0f,
|
||||
.compareEnable = false,
|
||||
.minLod = 0,
|
||||
.maxLod = 4,
|
||||
.unnormalizedCoordinates = false,
|
||||
};
|
||||
AbortIfFailed(device.m_Device.createSampler(&samplerCreateInfo, nullptr, &sampler));
|
||||
}
|
||||
auto ubo = renderResourceManager.CreateStorageBuffer(sizeof camera, "Camera UBO");
|
||||
renderResourceManager.Write(ubo, 0, sizeof camera, &camera);
|
||||
|
||||
auto ubo = bufferManager.CreateUniformBuffer(sizeof camera, "Camera UBO").ToPointer();
|
||||
ubo->Write(&device, 0, sizeof camera, &camera);
|
||||
vk::DescriptorBufferInfo descriptorBufferInfo = {
|
||||
.buffer = ubo->m_Buffer,
|
||||
.offset = 0,
|
||||
.range = ubo->GetSize(),
|
||||
};
|
||||
vk::DescriptorImageInfo descriptorImageInfo = {
|
||||
.sampler = sampler,
|
||||
.imageView = crate->m_View,
|
||||
.imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal,
|
||||
};
|
||||
vk::DescriptorBufferInfo descriptorStorageBufferInfo = {
|
||||
.buffer = vbo->m_Buffer,
|
||||
.offset = 0,
|
||||
.range = vbo->GetSize(),
|
||||
};
|
||||
eastl::array writeDescriptors = {
|
||||
vk::WriteDescriptorSet{
|
||||
.dstSet = descriptorSet,
|
||||
.dstBinding = 0,
|
||||
.dstArrayElement = 0,
|
||||
.descriptorCount = 1,
|
||||
.descriptorType = vk::DescriptorType::eUniformBuffer,
|
||||
.pBufferInfo = &descriptorBufferInfo,
|
||||
},
|
||||
vk::WriteDescriptorSet{
|
||||
.dstSet = descriptorSet,
|
||||
.dstBinding = 1,
|
||||
.dstArrayElement = 0,
|
||||
.descriptorCount = 1,
|
||||
.descriptorType = vk::DescriptorType::eCombinedImageSampler,
|
||||
.pImageInfo = &descriptorImageInfo,
|
||||
},
|
||||
vk::WriteDescriptorSet{
|
||||
.dstSet = descriptorSet,
|
||||
.dstBinding = 2,
|
||||
.dstArrayElement = 0,
|
||||
.descriptorCount = 1,
|
||||
.descriptorType = vk::DescriptorType::eStorageBuffer,
|
||||
.pBufferInfo = &descriptorStorageBufferInfo,
|
||||
},
|
||||
};
|
||||
device.m_Device.updateDescriptorSets(Cast<u32>(writeDescriptors.size()), writeDescriptors.data(), 0, nullptr);
|
||||
renderResourceManager.Commit(ubo);
|
||||
renderResourceManager.Commit(vbo);
|
||||
renderResourceManager.Commit(crate);
|
||||
|
||||
renderResourceManager.Update();
|
||||
|
||||
// Persistent variables
|
||||
vk::Viewport viewport = {
|
||||
|
|
@ -462,13 +391,13 @@ main(int, char **)
|
|||
};
|
||||
|
||||
FrameManager frameManager = {&device, queueAllocation.m_Family, MAX_FRAMES_IN_FLIGHT};
|
||||
eastl::fixed_vector<Ref<Image>, MAX_FRAMES_IN_FLIGHT> depthImages;
|
||||
eastl::fixed_vector<systems::Ref<Image>, MAX_FRAMES_IN_FLIGHT> depthImages;
|
||||
|
||||
auto initDepthImages = [&imageManager, &depthImages, &frameManager] (const vk::Extent2D extent) {
|
||||
auto initDepthImages = [&depthImages, &frameManager, &renderResourceManager](const vk::Extent2D extent) {
|
||||
for (u32 i = 0; i < frameManager.m_FramesInFlight; ++i)
|
||||
{
|
||||
depthImages.push_back(
|
||||
imageManager.CreateDepthStencilImage({.m_Extent = extent, .m_Name = "Depth"}).ToPointer());
|
||||
renderResourceManager.CreateDepthStencilImage({.m_Extent = extent, .m_Name = "Depth"}).ToPointer());
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -480,6 +409,19 @@ main(int, char **)
|
|||
};
|
||||
swapchain.RegisterResizeCallback(recreateDepthBuffers);
|
||||
|
||||
struct PCB
|
||||
{
|
||||
systems::BufferHandle m_Camera;
|
||||
systems::BufferHandle m_VertexBuffer;
|
||||
systems::ImageHandle m_Texture;
|
||||
};
|
||||
|
||||
PCB pcb = {
|
||||
.m_Camera = std::move(ubo),
|
||||
.m_VertexBuffer = std::move(vbo),
|
||||
.m_Texture = std::move(crate),
|
||||
};
|
||||
|
||||
Time::Init();
|
||||
|
||||
INFO("Starting loop");
|
||||
|
|
@ -488,7 +430,7 @@ main(int, char **)
|
|||
Time::Update();
|
||||
|
||||
camera.m_Model *= rotate(mat4{1.0f}, Cast<f32>(45.0_deg * Time::m_Delta), vec3(0.0f, 1.0f, 0.0f));
|
||||
ubo->Write(&device, 0, sizeof camera, &camera);
|
||||
renderResourceManager.Write(pcb.m_Camera, 0, sizeof camera, &camera);
|
||||
|
||||
Frame *currentFrame = frameManager.GetNextFrame(&swapchain, &surface, window.GetSize());
|
||||
|
||||
|
|
@ -540,7 +482,9 @@ main(int, char **)
|
|||
cmd.setViewport(0, 1, &viewport);
|
||||
cmd.setScissor(0, 1, &scissor);
|
||||
cmd.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline.m_Pipeline);
|
||||
cmd.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipeline.m_Layout, 0, 1, &descriptorSet, 0, nullptr);
|
||||
cmd.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipeline.m_Layout, 0, 1,
|
||||
&renderResourceManager.GetDescriptorSet(), 0, nullptr);
|
||||
cmd.pushConstants(pipeline.m_Layout, vk::ShaderStageFlagBits::eAllGraphics, 0, 12, &pcb);
|
||||
cmd.draw(Cast<u32>(vertices.size()), 1, 0, 0);
|
||||
|
||||
cmd.endRendering();
|
||||
|
|
@ -565,17 +509,16 @@ main(int, char **)
|
|||
}
|
||||
|
||||
device.WaitIdle();
|
||||
device.m_Device.destroy(sampler, nullptr);
|
||||
device.m_Device.destroy(descriptorPool, nullptr);
|
||||
device.m_Device.destroy(copyPool, nullptr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Pipeline
|
||||
CreatePipeline(const Device *device, const Swapchain *swapchain)
|
||||
CreatePipeline(const systems::RenderResourceManager *resourceManager, const Swapchain *swapchain)
|
||||
{
|
||||
// Pipeline Setup
|
||||
auto *device = resourceManager->m_Device;
|
||||
auto vertexShaderModule = CreateShader(device, VERTEX_SHADER_FILE);
|
||||
auto fragmentShaderModule = CreateShader(device, FRAGMENT_SHADER_FILE);
|
||||
|
||||
|
|
@ -592,39 +535,18 @@ CreatePipeline(const Device *device, const Swapchain *swapchain)
|
|||
},
|
||||
}};
|
||||
|
||||
eastl::array descriptorSetLayoutBinding = {
|
||||
vk::DescriptorSetLayoutBinding{
|
||||
.binding = 0,
|
||||
.descriptorType = vk::DescriptorType::eUniformBuffer,
|
||||
.descriptorCount = 1,
|
||||
.stageFlags = vk::ShaderStageFlagBits::eVertex,
|
||||
},
|
||||
vk::DescriptorSetLayoutBinding{
|
||||
.binding = 1,
|
||||
.descriptorType = vk::DescriptorType::eCombinedImageSampler,
|
||||
.descriptorCount = 1,
|
||||
.stageFlags = vk::ShaderStageFlagBits::eFragment,
|
||||
},
|
||||
vk::DescriptorSetLayoutBinding{
|
||||
.binding = 2,
|
||||
.descriptorType = vk::DescriptorType::eStorageBuffer,
|
||||
.descriptorCount = 1,
|
||||
.stageFlags = vk::ShaderStageFlagBits::eVertex,
|
||||
},
|
||||
};
|
||||
vk::DescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo = {
|
||||
.bindingCount = Cast<u32>(descriptorSetLayoutBinding.size()),
|
||||
.pBindings = descriptorSetLayoutBinding.data(),
|
||||
};
|
||||
vk::DescriptorSetLayout descriptorSetLayout;
|
||||
AbortIfFailed(
|
||||
device->m_Device.createDescriptorSetLayout(&descriptorSetLayoutCreateInfo, nullptr, &descriptorSetLayout));
|
||||
auto descriptorSetLayout = resourceManager->GetDescriptorSetLayout();
|
||||
|
||||
vk::PushConstantRange pcr = {
|
||||
.stageFlags = vk::ShaderStageFlagBits::eAllGraphics,
|
||||
.offset = 0,
|
||||
.size = 12,
|
||||
};
|
||||
vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo = {
|
||||
.setLayoutCount = 1,
|
||||
.pSetLayouts = &descriptorSetLayout,
|
||||
.pushConstantRangeCount = 0,
|
||||
.pPushConstantRanges = nullptr,
|
||||
.pushConstantRangeCount = 1,
|
||||
.pPushConstantRanges = &pcr,
|
||||
};
|
||||
vk::PipelineLayout pipelineLayout;
|
||||
AbortIfFailed(device->m_Device.createPipelineLayout(&pipelineLayoutCreateInfo, nullptr, &pipelineLayout));
|
||||
|
|
@ -714,7 +636,7 @@ CreatePipeline(const Device *device, const Swapchain *swapchain)
|
|||
device->m_Device.destroy(vertexShaderModule, nullptr);
|
||||
device->m_Device.destroy(fragmentShaderModule, nullptr);
|
||||
|
||||
return {device, pipelineLayout, pipeline, {descriptorSetLayout}};
|
||||
return {device, pipelineLayout, pipeline, {}};
|
||||
}
|
||||
|
||||
vk::ShaderModule
|
||||
|
|
|
|||
|
|
@ -0,0 +1,31 @@
|
|||
|
||||
|
||||
struct VertexData
|
||||
{
|
||||
float4 Position;
|
||||
float2 TexCoord0;
|
||||
float2 _pad0;
|
||||
};
|
||||
|
||||
struct CameraData
|
||||
{
|
||||
float4x4 Model;
|
||||
float4x4 View;
|
||||
float4x4 Projection;
|
||||
};
|
||||
|
||||
struct Handle
|
||||
{
|
||||
uint value;
|
||||
|
||||
uint GetIndex()
|
||||
{
|
||||
return value & 0x0FFFFFFF;
|
||||
}
|
||||
};
|
||||
|
||||
[[vk::binding(0, 0)]] StructuredBuffer<VertexData> VertexDataBuffer[];
|
||||
[[vk::binding(0, 0)]] StructuredBuffer<CameraData> CameraDataBuffer[];
|
||||
|
||||
[[vk::binding(1, 0)]] Texture2D<float4> Textures[];
|
||||
[[vk::binding(1, 0)]] SamplerState Samplers[];
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
#include "bindless.hlsli"
|
||||
|
||||
struct FS_Input {
|
||||
float2 UV0 : TEXCOORD0;
|
||||
};
|
||||
|
|
@ -7,13 +9,19 @@ struct FS_Output
|
|||
float4 ColorTarget : SV_Target0;
|
||||
};
|
||||
|
||||
[[vk::binding(1, 0)]] Texture2D<float4> Texture;
|
||||
[[vk::binding(1, 0)]] SamplerState Sampler;
|
||||
struct PCB
|
||||
{
|
||||
Handle CameraBuffer;
|
||||
Handle VertexBuffer;
|
||||
Handle Texture;
|
||||
};
|
||||
|
||||
[[vk::push_constant]] PCB Block;
|
||||
|
||||
FS_Output main(FS_Input StageInput) {
|
||||
FS_Output output;
|
||||
|
||||
output.ColorTarget = float4(Texture.Sample(Sampler, StageInput.UV0).rgb, 1.0);
|
||||
output.ColorTarget = float4(Textures[Block.Texture.GetIndex()].Sample(Samplers[Block.Texture.GetIndex()], StageInput.UV0).rgb, 1.0);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
#include "bindless.hlsli"
|
||||
|
||||
struct VS_Input
|
||||
{
|
||||
uint VertexIndex : SV_VertexID;
|
||||
|
|
@ -9,26 +11,23 @@ struct VS_Output
|
|||
float4 VertexPosition : SV_Position;
|
||||
};
|
||||
|
||||
struct CameraData {
|
||||
float4x4 Model;
|
||||
float4x4 View;
|
||||
float4x4 Projection;
|
||||
struct PCB
|
||||
{
|
||||
Handle CameraBuffer;
|
||||
Handle VertexBuffer;
|
||||
Handle Texture;
|
||||
};
|
||||
|
||||
struct VertexData {
|
||||
float4 Position;
|
||||
float2 UV0;
|
||||
};
|
||||
|
||||
[[vk::binding(0, 0)]] ConstantBuffer<CameraData> Camera;
|
||||
[[vk::binding(2, 0)]] StructuredBuffer<VertexData> Vertices;
|
||||
[[vk::push_constant]] PCB Block;
|
||||
|
||||
VS_Output main(VS_Input StageInput) {
|
||||
VS_Output output;
|
||||
|
||||
output.UV0 = Vertices[StageInput.VertexIndex].UV0;
|
||||
CameraData Camera = CameraDataBuffer[Block.CameraBuffer.GetIndex()][0];
|
||||
|
||||
float4 position = Vertices[StageInput.VertexIndex].Position;
|
||||
output.UV0 = VertexDataBuffer[Block.VertexBuffer.GetIndex()][StageInput.VertexIndex].TexCoord0;
|
||||
|
||||
float4 position = VertexDataBuffer[Block.VertexBuffer.GetIndex()][StageInput.VertexIndex].Position;
|
||||
|
||||
output.VertexPosition = mul(Camera.Projection, mul(Camera.View, mul(Camera.Model, position)));
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue