RenderResourceManager handles images and bindless.
This commit is contained in:
parent
3a7bea902f
commit
396810d203
|
|
@ -18,4 +18,5 @@ INTERFACE
|
||||||
"surface.h"
|
"surface.h"
|
||||||
"size.h"
|
"size.h"
|
||||||
"type_traits.h"
|
"type_traits.h"
|
||||||
"window.h")
|
"window.h"
|
||||||
|
"sampler.h")
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ struct Buffer
|
||||||
};
|
};
|
||||||
|
|
||||||
template <>
|
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.
|
// Ensure that m_Size doesn't get used intrusively since it manages the state.
|
||||||
static_assert(offsetof(Buffer, m_Size_) > sizeof(usize));
|
static_assert(offsetof(Buffer, m_Size_) > sizeof(usize));
|
||||||
|
|
|
||||||
|
|
@ -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())); });
|
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 <>
|
template <>
|
||||||
constexpr bool concepts::GpuResource<Image> = true;
|
constexpr bool concepts::Resource<Image> = true;
|
||||||
|
|
||||||
struct Texture : Image
|
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
|
namespace concepts
|
||||||
{
|
{
|
||||||
|
template <typename THandle, typename TValue>
|
||||||
|
concept Fetches = requires(THandle h)
|
||||||
|
{
|
||||||
|
{ h.Fetch() } -> std::same_as<TValue*>;
|
||||||
|
};
|
||||||
|
|
||||||
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::convertible_to<void>;
|
||||||
|
|
@ -21,16 +27,24 @@ concept Committable = requires(T a, bool v) {
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
constexpr bool GpuResource = false;
|
constexpr bool Resource = false;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
concept RenderResource = GpuResource<T> and std::is_default_constructible_v<T> and std::is_trivially_copyable_v<T> and
|
constexpr bool Opaque = false;
|
||||||
DeviceDestructible<T> and Committable<T>;
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
constexpr bool IsHandle = false;
|
concept Consistent = (Resource<T> and !Opaque<T>) or (Opaque<T> and !Resource<T>);
|
||||||
|
|
||||||
template <typename THandle>
|
template <typename T>
|
||||||
concept HandleType = IsHandle<THandle> and RenderResource<typename THandle::Type>;
|
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
|
||||||
|
|
@ -7,4 +7,5 @@ INTERFACE
|
||||||
"manager.h"
|
"manager.h"
|
||||||
"buffer_manager.h"
|
"buffer_manager.h"
|
||||||
"image_manager.h"
|
"image_manager.h"
|
||||||
|
"sampler_manager.h"
|
||||||
"render_resource_manager.h")
|
"render_resource_manager.h")
|
||||||
|
|
|
||||||
|
|
@ -10,10 +10,13 @@
|
||||||
|
|
||||||
struct Device;
|
struct Device;
|
||||||
|
|
||||||
template <concepts::RenderResource T>
|
namespace systems
|
||||||
|
{
|
||||||
|
|
||||||
|
template <concepts::ShaderObject T>
|
||||||
class Handle;
|
class Handle;
|
||||||
|
|
||||||
template <concepts::RenderResource T>
|
template <concepts::ShaderObject T>
|
||||||
class Manager
|
class Manager
|
||||||
{
|
{
|
||||||
friend Handle<T>;
|
friend Handle<T>;
|
||||||
|
|
@ -35,7 +38,7 @@ class Manager
|
||||||
, m_Binding{binding}
|
, m_Binding{binding}
|
||||||
, m_Device{device}
|
, m_Device{device}
|
||||||
{
|
{
|
||||||
assert(!m_Instance);
|
assert(!m_Instance && "Attempting to initialize a second Manager");
|
||||||
assert(maxCount <= MAX_HANDLES);
|
assert(maxCount <= MAX_HANDLES);
|
||||||
|
|
||||||
m_Data = new Type[m_MaxCount];
|
m_Data = new Type[m_MaxCount];
|
||||||
|
|
@ -77,7 +80,7 @@ class Manager
|
||||||
static Manager *
|
static Manager *
|
||||||
Instance()
|
Instance()
|
||||||
{
|
{
|
||||||
assert(m_Instance);
|
assert(m_Instance && "Not initialized yet.");
|
||||||
return m_Instance;
|
return m_Instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -151,7 +154,7 @@ class Manager
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <concepts::RenderResource T>
|
template <concepts::ShaderObject T>
|
||||||
class Ref
|
class Ref
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
@ -173,14 +176,14 @@ class Ref
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Type *
|
Type *
|
||||||
Get()
|
Fetch()
|
||||||
{
|
{
|
||||||
assert(m_Pointer);
|
assert(m_Pointer);
|
||||||
return m_Pointer;
|
return m_Pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Type *
|
const Type *
|
||||||
Get() const
|
Fetch() const
|
||||||
{
|
{
|
||||||
assert(m_Pointer);
|
assert(m_Pointer);
|
||||||
return m_Pointer;
|
return m_Pointer;
|
||||||
|
|
@ -189,25 +192,35 @@ class Ref
|
||||||
Type *
|
Type *
|
||||||
operator->()
|
operator->()
|
||||||
{
|
{
|
||||||
return Get();
|
return Fetch();
|
||||||
}
|
}
|
||||||
|
|
||||||
const Type *
|
const Type *
|
||||||
operator->() const
|
operator->() const
|
||||||
{
|
{
|
||||||
return Get();
|
return Fetch();
|
||||||
}
|
}
|
||||||
|
|
||||||
Type &
|
Type &
|
||||||
operator*()
|
operator*()
|
||||||
{
|
{
|
||||||
return *Get();
|
return *Fetch();
|
||||||
}
|
}
|
||||||
|
|
||||||
const Type &
|
const Type &
|
||||||
operator*() const
|
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.
|
// The only constructor requires a valid construction.
|
||||||
|
|
@ -231,8 +244,13 @@ class Ref
|
||||||
~Ref() = default;
|
~Ref() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
class RawHandle
|
template <concepts::ShaderObject T>
|
||||||
|
class Handle
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
using Type = T;
|
||||||
|
using Manager = Manager<Type>;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
constexpr static u32 INVALID_HANDLE = MaxValue<u32>;
|
constexpr static u32 INVALID_HANDLE = MaxValue<u32>;
|
||||||
constexpr static u32 INDEX_MASK = 0x0FFFFFFF;
|
constexpr static u32 INDEX_MASK = 0x0FFFFFFF;
|
||||||
|
|
@ -240,17 +258,29 @@ class RawHandle
|
||||||
constexpr static u32 TYPE_OFFSET = GetMaskOffset(TYPE_MASK);
|
constexpr static u32 TYPE_OFFSET = GetMaskOffset(TYPE_MASK);
|
||||||
u32 m_Internal = INVALID_HANDLE;
|
u32 m_Internal = INVALID_HANDLE;
|
||||||
|
|
||||||
RawHandle(const u32 index, const u8 typeId)
|
// The only constructor requires a valid construction.
|
||||||
: m_Internal{(index & INDEX_MASK) | (typeId & TYPE_MASK)}
|
Handle(const u32 index, const u8 typeId)
|
||||||
|
: m_Internal{(index & INDEX_MASK) | ((typeId << TYPE_OFFSET) & TYPE_MASK)}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
AddRef();
|
||||||
}
|
}
|
||||||
|
|
||||||
explicit RawHandle(const u32 internal)
|
friend Manager;
|
||||||
: m_Internal{internal}
|
friend Ref<T>;
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
[[nodiscard]] Ref<T>
|
||||||
|
ToPointer()
|
||||||
|
{
|
||||||
|
return Ref{std::move(*this)};
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] Type *
|
||||||
|
Fetch() const
|
||||||
|
{
|
||||||
|
return Manager::Instance()->Fetch(GetIndex());
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] bool
|
[[nodiscard]] bool
|
||||||
IsValid() const
|
IsValid() const
|
||||||
|
|
@ -271,52 +301,21 @@ class RawHandle
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
operator==(const RawHandle &other) const
|
operator==(const Handle &other) const
|
||||||
{
|
{
|
||||||
return m_Internal == other.m_Internal;
|
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)
|
Handle(const Handle &other)
|
||||||
: RawHandle{other}
|
|
||||||
{
|
{
|
||||||
|
m_Internal = other.m_Internal;
|
||||||
AddRef();
|
AddRef();
|
||||||
}
|
}
|
||||||
|
|
||||||
Handle(Handle &&other) noexcept
|
Handle(Handle &&other) noexcept
|
||||||
: RawHandle{std::exchange(other.m_Internal, m_Internal)}
|
|
||||||
{
|
{
|
||||||
}
|
m_Internal = other.m_Internal;
|
||||||
|
other.m_Internal = INVALID_HANDLE;
|
||||||
[[nodiscard]] Ref<T>
|
|
||||||
ToPointer()
|
|
||||||
{
|
|
||||||
return Ref{std::move(*this)};
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] Type *
|
|
||||||
Fetch() const
|
|
||||||
{
|
|
||||||
return Manager::Instance()->Fetch(m_Internal);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Handle &
|
Handle &
|
||||||
|
|
@ -359,3 +358,5 @@ class Handle : public RawHandle
|
||||||
Manager::Instance()->Release(GetIndex());
|
Manager::Instance()->Release(GetIndex());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
} // namespace systems
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,9 +8,11 @@
|
||||||
#include "aster/aster.h"
|
#include "aster/aster.h"
|
||||||
#include "buffer_manager.h"
|
#include "buffer_manager.h"
|
||||||
#include "image_manager.h"
|
#include "image_manager.h"
|
||||||
|
#include "sampler_manager.h"
|
||||||
|
|
||||||
#include "EASTL/deque.h"
|
#include "EASTL/deque.h"
|
||||||
#include "EASTL/vector.h"
|
#include "EASTL/vector.h"
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
namespace systems
|
namespace systems
|
||||||
{
|
{
|
||||||
|
|
@ -30,122 +32,63 @@ class RenderResourceManager
|
||||||
|
|
||||||
using WriteCommand = vk::WriteDescriptorSet;
|
using WriteCommand = vk::WriteDescriptorSet;
|
||||||
|
|
||||||
union WriteOwner {
|
//using WriteOwner = std::variant<Handle<Buffer>, Handle<Image>>;
|
||||||
Handle<Buffer> uBufferHandle;
|
|
||||||
Handle<Image> uImageHandle;
|
|
||||||
|
|
||||||
explicit WriteOwner(const Handle<Buffer> &handle);
|
|
||||||
explicit WriteOwner(const Handle<Image> &handle);
|
|
||||||
|
|
||||||
WriteOwner(const WriteOwner &other)
|
|
||||||
{
|
|
||||||
switch (uRawHandle.GetType())
|
|
||||||
{
|
|
||||||
case BUFFER_BINDING_INDEX:
|
|
||||||
uBufferHandle = other.uBufferHandle;
|
|
||||||
break;
|
|
||||||
case IMAGE_BINDING_INDEX:
|
|
||||||
uImageHandle = other.uImageHandle;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ERROR("Invalid Handle type.") THEN_ABORT(-1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
WriteOwner(WriteOwner &&other) noexcept
|
|
||||||
{
|
|
||||||
switch (uRawHandle.GetType())
|
|
||||||
{
|
|
||||||
case BUFFER_BINDING_INDEX:
|
|
||||||
uBufferHandle = std::move(other.uBufferHandle);
|
|
||||||
break;
|
|
||||||
case IMAGE_BINDING_INDEX:
|
|
||||||
uImageHandle = std::move(other.uImageHandle);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ERROR("Invalid Handle type.") THEN_ABORT(-1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
WriteOwner &
|
|
||||||
operator=(const WriteOwner &other)
|
|
||||||
{
|
|
||||||
if (this == &other)
|
|
||||||
return *this;
|
|
||||||
|
|
||||||
switch (uRawHandle.GetType())
|
|
||||||
{
|
|
||||||
case BUFFER_BINDING_INDEX:
|
|
||||||
uBufferHandle = other.uBufferHandle;
|
|
||||||
break;
|
|
||||||
case IMAGE_BINDING_INDEX:
|
|
||||||
uImageHandle = other.uImageHandle;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ERROR("Invalid Handle type.") THEN_ABORT(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
WriteOwner &
|
|
||||||
operator=(WriteOwner &&other) noexcept
|
|
||||||
{
|
|
||||||
if (this == &other)
|
|
||||||
return *this;
|
|
||||||
|
|
||||||
switch (uRawHandle.GetType())
|
|
||||||
{
|
|
||||||
case BUFFER_BINDING_INDEX:
|
|
||||||
uBufferHandle = std::move(other.uBufferHandle);
|
|
||||||
break;
|
|
||||||
case IMAGE_BINDING_INDEX:
|
|
||||||
uImageHandle = std::move(other.uImageHandle);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ERROR("Invalid Handle type.") THEN_ABORT(-1);
|
|
||||||
}
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
~WriteOwner()
|
|
||||||
{
|
|
||||||
switch (uRawHandle.GetType())
|
|
||||||
{
|
|
||||||
case BUFFER_BINDING_INDEX:
|
|
||||||
uBufferHandle.~Handle();
|
|
||||||
return;
|
|
||||||
case IMAGE_BINDING_INDEX:
|
|
||||||
uImageHandle.~Handle();
|
|
||||||
return;
|
|
||||||
default:
|
|
||||||
ERROR("Invalid Handle type.") THEN_ABORT(-1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
RawHandle uRawHandle;
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
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;
|
BufferManager m_BufferManager;
|
||||||
ImageManager m_ImageManager;
|
ImageManager m_ImageManager;
|
||||||
|
SamplerManager m_SamplerManager;
|
||||||
|
|
||||||
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 = 0;
|
constexpr static u8 BUFFER_BINDING_INDEX = 0x0;
|
||||||
constexpr static u8 IMAGE_BINDING_INDEX = 1;
|
constexpr static u8 IMAGE_BINDING_INDEX = 0x1;
|
||||||
|
constexpr static u8 SAMPLER_TYPE_INDEX = 0xF;
|
||||||
|
|
||||||
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)
|
#if !defined(ASTER_NDEBUG)
|
||||||
usize m_CommitedBufferCount = 0;
|
usize m_CommitedBufferCount = 0;
|
||||||
|
|
@ -153,5 +96,4 @@ class RenderResourceManager
|
||||||
usize m_CommitedStorageTextureCount = 0;
|
usize m_CommitedStorageTextureCount = 0;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace systems
|
} // 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"
|
"buffer.cpp"
|
||||||
"image.cpp"
|
"image.cpp"
|
||||||
"surface.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"
|
"manager.cpp"
|
||||||
"buffer_manager.cpp"
|
"buffer_manager.cpp"
|
||||||
"image_manager.cpp"
|
"image_manager.cpp"
|
||||||
|
"sampler_manager.cpp"
|
||||||
"render_resource_manager.cpp")
|
"render_resource_manager.cpp")
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,10 @@
|
||||||
|
|
||||||
#include "systems/buffer_manager.h"
|
#include "systems/buffer_manager.h"
|
||||||
|
|
||||||
Manager<Buffer> *Manager<Buffer>::m_Instance = nullptr;
|
|
||||||
|
|
||||||
using namespace systems;
|
using namespace systems;
|
||||||
|
|
||||||
|
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)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -7,10 +7,10 @@
|
||||||
|
|
||||||
#include "core/device.h"
|
#include "core/device.h"
|
||||||
|
|
||||||
Manager<Image> *Manager<Image>::m_Instance = nullptr;
|
|
||||||
|
|
||||||
using namespace systems;
|
using namespace systems;
|
||||||
|
|
||||||
|
Manager<Image> *Manager<Image>::m_Instance = nullptr;
|
||||||
|
|
||||||
vk::ImageCreateInfo ToImageCreateInfo(const Texture2DCreateInfo &createInfo);
|
vk::ImageCreateInfo ToImageCreateInfo(const Texture2DCreateInfo &createInfo);
|
||||||
vk::ImageCreateInfo ToImageCreateInfo(const TextureCubeCreateInfo &createInfo);
|
vk::ImageCreateInfo ToImageCreateInfo(const TextureCubeCreateInfo &createInfo);
|
||||||
vk::ImageCreateInfo ToImageCreateInfo(const AttachmentCreateInfo &createInfo);
|
vk::ImageCreateInfo ToImageCreateInfo(const AttachmentCreateInfo &createInfo);
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,8 @@
|
||||||
|
|
||||||
#include "systems/render_resource_manager.h"
|
#include "systems/render_resource_manager.h"
|
||||||
|
|
||||||
#include "EASTL/array.h"
|
|
||||||
#include "core/device.h"
|
#include "core/device.h"
|
||||||
|
#include "EASTL/array.h"
|
||||||
|
|
||||||
#define AbortIfFailed(RESULT) \
|
#define AbortIfFailed(RESULT) \
|
||||||
do \
|
do \
|
||||||
|
|
@ -31,28 +31,14 @@
|
||||||
ERROR_IF(Failed(_checkResultValue_), MSG " Cause: {}", _checkResultValue_) THEN_ABORT(_checkResultValue_); \
|
ERROR_IF(Failed(_checkResultValue_), MSG " Cause: {}", _checkResultValue_) THEN_ABORT(_checkResultValue_); \
|
||||||
} while (false)
|
} while (false)
|
||||||
|
|
||||||
|
|
||||||
using namespace systems;
|
using namespace systems;
|
||||||
|
|
||||||
u32
|
RenderResourceManager::RenderResourceManager(const Device *device, u32 const maxBuffers, const u32 maxImages,
|
||||||
GetHandleInternal(concepts::HandleType auto &handle)
|
const u32 maxSamplers)
|
||||||
{
|
: m_Device{device}
|
||||||
return *Recast<u32 *>(&handle);
|
, m_BufferManager{device, maxBuffers, BUFFER_BINDING_INDEX}
|
||||||
}
|
|
||||||
|
|
||||||
RenderResourceManager::WriteOwner::WriteOwner(const Handle<Buffer> &handle)
|
|
||||||
: uBufferHandle(handle)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
RenderResourceManager::WriteOwner::WriteOwner(const Handle<Image> &handle)
|
|
||||||
: uImageHandle(handle)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
RenderResourceManager::RenderResourceManager(const Device *device, u32 const maxBuffers, const u32 maxImages)
|
|
||||||
: m_BufferManager{device, maxBuffers, BUFFER_BINDING_INDEX}
|
|
||||||
, m_ImageManager{device, maxImages, IMAGE_BINDING_INDEX}
|
, m_ImageManager{device, maxImages, IMAGE_BINDING_INDEX}
|
||||||
|
, m_SamplerManager{device, maxSamplers, SAMPLER_TYPE_INDEX}
|
||||||
{
|
{
|
||||||
eastl::array poolSizes = {
|
eastl::array poolSizes = {
|
||||||
vk::DescriptorPoolSize{
|
vk::DescriptorPoolSize{
|
||||||
|
|
@ -63,10 +49,10 @@ RenderResourceManager::RenderResourceManager(const Device *device, u32 const max
|
||||||
.type = vk::DescriptorType::eCombinedImageSampler,
|
.type = vk::DescriptorType::eCombinedImageSampler,
|
||||||
.descriptorCount = maxImages,
|
.descriptorCount = maxImages,
|
||||||
},
|
},
|
||||||
//vk::DescriptorPoolSize{
|
// vk::DescriptorPoolSize{
|
||||||
// .type = vk::DescriptorType::eStorageImage,
|
// .type = vk::DescriptorType::eStorageImage,
|
||||||
// .descriptorCount = storageTexturesCount,
|
// .descriptorCount = storageTexturesCount,
|
||||||
//},
|
// },
|
||||||
};
|
};
|
||||||
|
|
||||||
const vk::DescriptorPoolCreateInfo poolCreateInfo = {
|
const vk::DescriptorPoolCreateInfo poolCreateInfo = {
|
||||||
|
|
@ -90,12 +76,12 @@ RenderResourceManager::RenderResourceManager(const Device *device, u32 const max
|
||||||
.descriptorCount = Cast<u32>(maxImages),
|
.descriptorCount = Cast<u32>(maxImages),
|
||||||
.stageFlags = vk::ShaderStageFlagBits::eAll,
|
.stageFlags = vk::ShaderStageFlagBits::eAll,
|
||||||
},
|
},
|
||||||
//vk::DescriptorSetLayoutBinding{
|
// vk::DescriptorSetLayoutBinding{
|
||||||
// .binding = STORAGE_TEXTURE_BINDING_INDEX,
|
// .binding = STORAGE_TEXTURE_BINDING_INDEX,
|
||||||
// .descriptorType = vk::DescriptorType::eStorageImage,
|
// .descriptorType = vk::DescriptorType::eStorageImage,
|
||||||
// .descriptorCount = Cast<u32>(storageTexturesCount),
|
// .descriptorCount = Cast<u32>(storageTexturesCount),
|
||||||
// .stageFlags = vk::ShaderStageFlagBits::eAll,
|
// .stageFlags = vk::ShaderStageFlagBits::eAll,
|
||||||
//},
|
// },
|
||||||
};
|
};
|
||||||
|
|
||||||
vk::DescriptorBindingFlags bindingFlags =
|
vk::DescriptorBindingFlags bindingFlags =
|
||||||
|
|
@ -133,50 +119,128 @@ RenderResourceManager::RenderResourceManager(const Device *device, u32 const max
|
||||||
device->SetName(m_DescriptorSet, "Bindless Set");
|
device->SetName(m_DescriptorSet, "Bindless Set");
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
RenderResourceManager::~RenderResourceManager()
|
||||||
systems::RenderResourceManager::Commit(concepts::HandleType auto &handle)
|
|
||||||
{
|
{
|
||||||
using HandleType = decltype(handle)::Type;
|
|
||||||
if constexpr (std::is_same_v<HandleType, Buffer>)
|
|
||||||
{
|
|
||||||
const Buffer *buffer = handle.Fetch();
|
|
||||||
|
|
||||||
m_WriteInfos.emplace_back(vk::DescriptorBufferInfo{
|
#if !defined(ASTER_NDEBUG)
|
||||||
.buffer = buffer->m_Buffer,
|
WARN_IF(m_CommitedBufferCount > 0 || m_CommitedTextureCount > 0 || m_CommitedStorageTextureCount > 0,
|
||||||
.offset = 0,
|
"Resources alive: SSBO = {}, Textures = {}, RWTexture = {}", m_CommitedBufferCount, m_CommitedTextureCount,
|
||||||
.range = buffer->GetSize(),
|
m_CommitedStorageTextureCount);
|
||||||
});
|
#endif
|
||||||
m_Writes.push_back({
|
|
||||||
.dstSet = m_DescriptorSet,
|
|
||||||
.dstBinding = BUFFER_BINDING_INDEX,
|
|
||||||
.dstArrayElement = handle.GetIndex(),
|
|
||||||
.descriptorCount = 1,
|
|
||||||
.descriptorType = vk::DescriptorType::eStorageBuffer,
|
|
||||||
.pBufferInfo = &m_WriteInfos.back().uBufferInfo,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else if constexpr (std::is_same_v<HandleType, Image>)
|
|
||||||
{
|
|
||||||
const Image *image = handle.Fetch();
|
|
||||||
|
|
||||||
m_WriteInfos.emplace_back(vk::DescriptorImageInfo{
|
m_Device->m_Device.destroy(m_SetLayout, nullptr);
|
||||||
.sampler = nullptr /* TODO Sampler */,
|
m_Device->m_Device.destroy(m_DescriptorPool, nullptr);
|
||||||
.imageView = image->m_View,
|
}
|
||||||
.imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal,
|
|
||||||
});
|
void
|
||||||
m_Writes.push_back({
|
RenderResourceManager::Write(const BufferHandle &handle, const usize offset, const usize size, const void *data) const
|
||||||
.dstSet = m_DescriptorSet,
|
{
|
||||||
.dstBinding = IMAGE_BINDING_INDEX,
|
handle.Fetch()->Write(m_Device, offset, size, data);
|
||||||
.dstArrayElement = handle.GetIndex(),
|
}
|
||||||
.descriptorCount = 1,
|
|
||||||
.descriptorType = vk::DescriptorType::eSampledImage,
|
BufferHandle RenderResourceManager::CreateStorageBuffer(const usize size, const cstr name)
|
||||||
.pImageInfo = &m_WriteInfos.back().uImageInfo,
|
{
|
||||||
});
|
return m_BufferManager.CreateStorageBuffer(size, name);
|
||||||
} else {
|
}
|
||||||
static_assert(false && "Type is currently unsupported");
|
|
||||||
|
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_WriteOwner.emplace_back(handle);
|
m_WriteInfos.emplace_back(vk::DescriptorBufferInfo{
|
||||||
|
.buffer = buffer->m_Buffer,
|
||||||
|
.offset = 0,
|
||||||
|
.range = buffer->GetSize(),
|
||||||
|
});
|
||||||
|
m_Writes.push_back({
|
||||||
|
.dstSet = m_DescriptorSet,
|
||||||
|
.dstBinding = BUFFER_BINDING_INDEX,
|
||||||
|
.dstArrayElement = handle.GetIndex(),
|
||||||
|
.descriptorCount = 1,
|
||||||
|
.descriptorType = vk::DescriptorType::eStorageBuffer,
|
||||||
|
.pBufferInfo = &m_WriteInfos.back().uBufferInfo,
|
||||||
|
});
|
||||||
|
|
||||||
|
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())
|
||||||
|
{
|
||||||
|
WARN("Image is already committed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Sampler *sampler = samplerHandle.Fetch();
|
||||||
|
|
||||||
|
m_WriteInfos.emplace_back(vk::DescriptorImageInfo{
|
||||||
|
.sampler = sampler->m_Sampler,
|
||||||
|
.imageView = image->m_View,
|
||||||
|
.imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal,
|
||||||
|
});
|
||||||
|
m_Writes.push_back({
|
||||||
|
.dstSet = m_DescriptorSet,
|
||||||
|
.dstBinding = IMAGE_BINDING_INDEX,
|
||||||
|
.dstArrayElement = handle.GetIndex(),
|
||||||
|
.descriptorCount = 1,
|
||||||
|
.descriptorType = vk::DescriptorType::eCombinedImageSampler,
|
||||||
|
.pImageInfo = &m_WriteInfos.back().uImageInfo,
|
||||||
|
});
|
||||||
|
|
||||||
|
image->SetCommitted(true);
|
||||||
|
sampler->SetCommitted(true);
|
||||||
|
#if !defined(ASTER_NDEBUG)
|
||||||
|
++m_CommitedTextureCount;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
RenderResourceManager::WriteInfo::WriteInfo(const vk::DescriptorBufferInfo &info)
|
RenderResourceManager::WriteInfo::WriteInfo(const vk::DescriptorBufferInfo &info)
|
||||||
|
|
@ -193,3 +257,22 @@ RenderResourceManager::WriteInfo::WriteInfo(const vk::BufferView &info)
|
||||||
: uBufferView{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
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
#include "aster/systems/buffer_manager.h"
|
#include "aster/systems/buffer_manager.h"
|
||||||
#include "aster/systems/image_manager.h"
|
#include "aster/systems/image_manager.h"
|
||||||
|
#include "aster/systems/render_resource_manager.h"
|
||||||
#include "frame.h"
|
#include "frame.h"
|
||||||
#include "stb_image.h"
|
#include "stb_image.h"
|
||||||
|
|
||||||
|
|
@ -73,7 +74,7 @@ ImageFile::~ImageFile()
|
||||||
}
|
}
|
||||||
|
|
||||||
vk::ShaderModule CreateShader(const Device *device, cstr shaderFile);
|
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
|
struct Vertex
|
||||||
{
|
{
|
||||||
|
|
@ -106,17 +107,30 @@ main(int, char **)
|
||||||
|
|
||||||
Features enabledDeviceFeatures = {
|
Features enabledDeviceFeatures = {
|
||||||
.m_Vulkan10Features = {.samplerAnisotropy = true},
|
.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},
|
.m_Vulkan13Features = {.synchronization2 = true, .dynamicRendering = true},
|
||||||
};
|
};
|
||||||
QueueAllocation queueAllocation = FindAppropriateQueueAllocation(&deviceToUse);
|
QueueAllocation queueAllocation = FindAppropriateQueueAllocation(&deviceToUse);
|
||||||
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"};
|
||||||
Pipeline pipeline = CreatePipeline(&device, &swapchain);
|
systems::RenderResourceManager renderResourceManager{&device, 12, 12, 1};
|
||||||
|
|
||||||
systems::BufferManager bufferManager{&device, 12, 0};
|
Pipeline pipeline = CreatePipeline(&renderResourceManager, &swapchain);
|
||||||
systems::ImageManager imageManager{&device, 12, 1};
|
|
||||||
|
|
||||||
Camera camera = {
|
Camera camera = {
|
||||||
.m_Model = {1.0f},
|
.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),
|
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::CommandPool copyPool;
|
||||||
vk::CommandBuffer copyBuffer;
|
vk::CommandBuffer copyBuffer;
|
||||||
{
|
{
|
||||||
|
|
@ -222,15 +206,16 @@ 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 = bufferManager.CreateStorageBuffer(vertices.size() * sizeof vertices[0], "Vertex Buffer").ToPointer();
|
auto vbo = renderResourceManager.CreateStorageBuffer(vertices.size() * sizeof vertices[0], "Vertex Buffer");
|
||||||
auto crate = imageManager
|
renderResourceManager.Write(vbo, 0, vertices.size() * sizeof vertices[0], vertices.data());
|
||||||
|
|
||||||
|
auto crate = renderResourceManager
|
||||||
.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();
|
.ToPointer();
|
||||||
vbo->Write(&device, 0, vertices.size() * sizeof vertices[0], vertices.data());
|
|
||||||
|
|
||||||
{
|
{
|
||||||
StagingBuffer imageStaging;
|
StagingBuffer imageStaging;
|
||||||
|
|
@ -333,70 +318,14 @@ main(int, char **)
|
||||||
imageStaging.Destroy(&device);
|
imageStaging.Destroy(&device);
|
||||||
}
|
}
|
||||||
|
|
||||||
vk::Sampler sampler;
|
auto ubo = renderResourceManager.CreateStorageBuffer(sizeof camera, "Camera UBO");
|
||||||
{
|
renderResourceManager.Write(ubo, 0, sizeof camera, &camera);
|
||||||
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 = bufferManager.CreateUniformBuffer(sizeof camera, "Camera UBO").ToPointer();
|
renderResourceManager.Commit(ubo);
|
||||||
ubo->Write(&device, 0, sizeof camera, &camera);
|
renderResourceManager.Commit(vbo);
|
||||||
vk::DescriptorBufferInfo descriptorBufferInfo = {
|
renderResourceManager.Commit(crate);
|
||||||
.buffer = ubo->m_Buffer,
|
|
||||||
.offset = 0,
|
renderResourceManager.Update();
|
||||||
.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);
|
|
||||||
|
|
||||||
// Persistent variables
|
// Persistent variables
|
||||||
vk::Viewport viewport = {
|
vk::Viewport viewport = {
|
||||||
|
|
@ -462,13 +391,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<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)
|
for (u32 i = 0; i < frameManager.m_FramesInFlight; ++i)
|
||||||
{
|
{
|
||||||
depthImages.push_back(
|
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);
|
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();
|
Time::Init();
|
||||||
|
|
||||||
INFO("Starting loop");
|
INFO("Starting loop");
|
||||||
|
|
@ -488,7 +430,7 @@ main(int, char **)
|
||||||
Time::Update();
|
Time::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));
|
||||||
ubo->Write(&device, 0, sizeof camera, &camera);
|
renderResourceManager.Write(pcb.m_Camera, 0, sizeof camera, &camera);
|
||||||
|
|
||||||
Frame *currentFrame = frameManager.GetNextFrame(&swapchain, &surface, window.GetSize());
|
Frame *currentFrame = frameManager.GetNextFrame(&swapchain, &surface, window.GetSize());
|
||||||
|
|
||||||
|
|
@ -540,7 +482,9 @@ main(int, char **)
|
||||||
cmd.setViewport(0, 1, &viewport);
|
cmd.setViewport(0, 1, &viewport);
|
||||||
cmd.setScissor(0, 1, &scissor);
|
cmd.setScissor(0, 1, &scissor);
|
||||||
cmd.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline.m_Pipeline);
|
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.draw(Cast<u32>(vertices.size()), 1, 0, 0);
|
||||||
|
|
||||||
cmd.endRendering();
|
cmd.endRendering();
|
||||||
|
|
@ -565,17 +509,16 @@ main(int, char **)
|
||||||
}
|
}
|
||||||
|
|
||||||
device.WaitIdle();
|
device.WaitIdle();
|
||||||
device.m_Device.destroy(sampler, nullptr);
|
|
||||||
device.m_Device.destroy(descriptorPool, nullptr);
|
|
||||||
device.m_Device.destroy(copyPool, nullptr);
|
device.m_Device.destroy(copyPool, nullptr);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Pipeline
|
Pipeline
|
||||||
CreatePipeline(const Device *device, const Swapchain *swapchain)
|
CreatePipeline(const systems::RenderResourceManager *resourceManager, const Swapchain *swapchain)
|
||||||
{
|
{
|
||||||
// Pipeline Setup
|
// Pipeline Setup
|
||||||
|
auto *device = resourceManager->m_Device;
|
||||||
auto vertexShaderModule = CreateShader(device, VERTEX_SHADER_FILE);
|
auto vertexShaderModule = CreateShader(device, VERTEX_SHADER_FILE);
|
||||||
auto fragmentShaderModule = CreateShader(device, FRAGMENT_SHADER_FILE);
|
auto fragmentShaderModule = CreateShader(device, FRAGMENT_SHADER_FILE);
|
||||||
|
|
||||||
|
|
@ -592,39 +535,18 @@ CreatePipeline(const Device *device, const Swapchain *swapchain)
|
||||||
},
|
},
|
||||||
}};
|
}};
|
||||||
|
|
||||||
eastl::array descriptorSetLayoutBinding = {
|
auto descriptorSetLayout = resourceManager->GetDescriptorSetLayout();
|
||||||
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));
|
|
||||||
|
|
||||||
|
vk::PushConstantRange pcr = {
|
||||||
|
.stageFlags = vk::ShaderStageFlagBits::eAllGraphics,
|
||||||
|
.offset = 0,
|
||||||
|
.size = 12,
|
||||||
|
};
|
||||||
vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo = {
|
vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo = {
|
||||||
.setLayoutCount = 1,
|
.setLayoutCount = 1,
|
||||||
.pSetLayouts = &descriptorSetLayout,
|
.pSetLayouts = &descriptorSetLayout,
|
||||||
.pushConstantRangeCount = 0,
|
.pushConstantRangeCount = 1,
|
||||||
.pPushConstantRanges = nullptr,
|
.pPushConstantRanges = &pcr,
|
||||||
};
|
};
|
||||||
vk::PipelineLayout pipelineLayout;
|
vk::PipelineLayout pipelineLayout;
|
||||||
AbortIfFailed(device->m_Device.createPipelineLayout(&pipelineLayoutCreateInfo, nullptr, &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(vertexShaderModule, nullptr);
|
||||||
device->m_Device.destroy(fragmentShaderModule, nullptr);
|
device->m_Device.destroy(fragmentShaderModule, nullptr);
|
||||||
|
|
||||||
return {device, pipelineLayout, pipeline, {descriptorSetLayout}};
|
return {device, pipelineLayout, pipeline, {}};
|
||||||
}
|
}
|
||||||
|
|
||||||
vk::ShaderModule
|
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 {
|
struct FS_Input {
|
||||||
float2 UV0 : TEXCOORD0;
|
float2 UV0 : TEXCOORD0;
|
||||||
};
|
};
|
||||||
|
|
@ -7,13 +9,19 @@ struct FS_Output
|
||||||
float4 ColorTarget : SV_Target0;
|
float4 ColorTarget : SV_Target0;
|
||||||
};
|
};
|
||||||
|
|
||||||
[[vk::binding(1, 0)]] Texture2D<float4> Texture;
|
struct PCB
|
||||||
[[vk::binding(1, 0)]] SamplerState Sampler;
|
{
|
||||||
|
Handle CameraBuffer;
|
||||||
|
Handle VertexBuffer;
|
||||||
|
Handle Texture;
|
||||||
|
};
|
||||||
|
|
||||||
|
[[vk::push_constant]] PCB Block;
|
||||||
|
|
||||||
FS_Output main(FS_Input StageInput) {
|
FS_Output main(FS_Input StageInput) {
|
||||||
FS_Output output;
|
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;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
#include "bindless.hlsli"
|
||||||
|
|
||||||
struct VS_Input
|
struct VS_Input
|
||||||
{
|
{
|
||||||
uint VertexIndex : SV_VertexID;
|
uint VertexIndex : SV_VertexID;
|
||||||
|
|
@ -9,26 +11,23 @@ struct VS_Output
|
||||||
float4 VertexPosition : SV_Position;
|
float4 VertexPosition : SV_Position;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CameraData {
|
struct PCB
|
||||||
float4x4 Model;
|
{
|
||||||
float4x4 View;
|
Handle CameraBuffer;
|
||||||
float4x4 Projection;
|
Handle VertexBuffer;
|
||||||
|
Handle Texture;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct VertexData {
|
[[vk::push_constant]] PCB Block;
|
||||||
float4 Position;
|
|
||||||
float2 UV0;
|
|
||||||
};
|
|
||||||
|
|
||||||
[[vk::binding(0, 0)]] ConstantBuffer<CameraData> Camera;
|
|
||||||
[[vk::binding(2, 0)]] StructuredBuffer<VertexData> Vertices;
|
|
||||||
|
|
||||||
VS_Output main(VS_Input StageInput) {
|
VS_Output main(VS_Input StageInput) {
|
||||||
VS_Output output;
|
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)));
|
output.VertexPosition = mul(Camera.Projection, mul(Camera.View, mul(Camera.Model, position)));
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue