From 396810d2038dbe5575a526254deaf7f6841a789c Mon Sep 17 00:00:00 2001 From: Anish Bhobe Date: Sun, 2 Mar 2025 19:19:43 +0100 Subject: [PATCH] RenderResourceManager handles images and bindless. --- aster/include/aster/core/CMakeLists.txt | 3 +- aster/include/aster/core/buffer.h | 2 +- aster/include/aster/core/global.h | 10 + aster/include/aster/core/image.h | 2 +- aster/include/aster/core/sampler.h | 46 ++++ aster/include/aster/core/type_traits.h | 26 +- aster/include/aster/systems/CMakeLists.txt | 1 + aster/include/aster/systems/manager.h | 107 ++++----- .../aster/systems/render_resource_manager.h | 148 ++++-------- aster/include/aster/systems/sampler_manager.h | 57 +++++ aster/src/aster/core/CMakeLists.txt | 3 +- aster/src/aster/core/sampler.cpp | 24 ++ aster/src/aster/systems/CMakeLists.txt | 1 + aster/src/aster/systems/buffer_manager.cpp | 4 +- aster/src/aster/systems/image_manager.cpp | 4 +- .../aster/systems/render_resource_manager.cpp | 223 ++++++++++++------ aster/src/aster/systems/sampler_manager.cpp | 66 ++++++ samples/02_box/box.cpp | 200 +++++----------- samples/02_box/shader/bindless.hlsli | 31 +++ samples/02_box/shader/box.ps.hlsl | 14 +- samples/02_box/shader/box.vs.hlsl | 25 +- 21 files changed, 602 insertions(+), 395 deletions(-) create mode 100644 aster/include/aster/core/sampler.h create mode 100644 aster/include/aster/systems/sampler_manager.h create mode 100644 aster/src/aster/core/sampler.cpp create mode 100644 aster/src/aster/systems/sampler_manager.cpp create mode 100644 samples/02_box/shader/bindless.hlsli diff --git a/aster/include/aster/core/CMakeLists.txt b/aster/include/aster/core/CMakeLists.txt index 968c60c..9153d89 100644 --- a/aster/include/aster/core/CMakeLists.txt +++ b/aster/include/aster/core/CMakeLists.txt @@ -18,4 +18,5 @@ INTERFACE "surface.h" "size.h" "type_traits.h" - "window.h") + "window.h" + "sampler.h") diff --git a/aster/include/aster/core/buffer.h b/aster/include/aster/core/buffer.h index e4f65ed..5d88958 100644 --- a/aster/include/aster/core/buffer.h +++ b/aster/include/aster/core/buffer.h @@ -47,7 +47,7 @@ struct Buffer }; template <> -constexpr bool concepts::GpuResource = true; +constexpr bool concepts::Resource = true; // Ensure that m_Size doesn't get used intrusively since it manages the state. static_assert(offsetof(Buffer, m_Size_) > sizeof(usize)); diff --git a/aster/include/aster/core/global.h b/aster/include/aster/core/global.h index a79c575..fbdff20 100644 --- a/aster/include/aster/core/global.h +++ b/aster/include/aster/core/global.h @@ -211,3 +211,13 @@ struct fmt::formatter> : nested_fo return write_padded(ctx, [this, str](auto out) { return v10::format_to(out, "{}", nested(str.c_str())); }); } }; + +namespace aster +{ +template +TVal & +Deref(TRef ref) +{ + return ref.Deref(); +} +} diff --git a/aster/include/aster/core/image.h b/aster/include/aster/core/image.h index c4e0b49..bdd6c14 100644 --- a/aster/include/aster/core/image.h +++ b/aster/include/aster/core/image.h @@ -60,7 +60,7 @@ struct Image }; template <> -constexpr bool concepts::GpuResource = true; +constexpr bool concepts::Resource = true; struct Texture : Image { diff --git a/aster/include/aster/core/sampler.h b/aster/include/aster/core/sampler.h new file mode 100644 index 0000000..4dfeff1 --- /dev/null +++ b/aster/include/aster/core/sampler.h @@ -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 = 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; +} diff --git a/aster/include/aster/core/type_traits.h b/aster/include/aster/core/type_traits.h index 59abf85..caddf03 100644 --- a/aster/include/aster/core/type_traits.h +++ b/aster/include/aster/core/type_traits.h @@ -9,6 +9,12 @@ struct Device; namespace concepts { +template +concept Fetches = requires(THandle h) +{ + { h.Fetch() } -> std::same_as; +}; + template concept DeviceDestructible = requires(T a, Device *p) { { a.Destroy(p) } -> std::convertible_to; @@ -21,16 +27,24 @@ concept Committable = requires(T a, bool v) { }; template -constexpr bool GpuResource = false; +constexpr bool Resource = false; template -concept RenderResource = GpuResource and std::is_default_constructible_v and std::is_trivially_copyable_v and - DeviceDestructible and Committable; +constexpr bool Opaque = false; template -constexpr bool IsHandle = false; +concept Consistent = (Resource and !Opaque) or (Opaque and !Resource); -template -concept HandleType = IsHandle and RenderResource; +template +concept Manageable = std::is_default_constructible_v and std::is_trivially_copyable_v and DeviceDestructible; + +template +concept ShaderObject = Consistent and Manageable and Committable; + +template +concept ShaderResource = ShaderObject and Resource; + +template +concept ShaderOpaque = ShaderObject and Opaque; } // namespace concepts \ No newline at end of file diff --git a/aster/include/aster/systems/CMakeLists.txt b/aster/include/aster/systems/CMakeLists.txt index 38a40e7..58b60b1 100644 --- a/aster/include/aster/systems/CMakeLists.txt +++ b/aster/include/aster/systems/CMakeLists.txt @@ -7,4 +7,5 @@ INTERFACE "manager.h" "buffer_manager.h" "image_manager.h" + "sampler_manager.h" "render_resource_manager.h") diff --git a/aster/include/aster/systems/manager.h b/aster/include/aster/systems/manager.h index 3abd077..9594966 100644 --- a/aster/include/aster/systems/manager.h +++ b/aster/include/aster/systems/manager.h @@ -10,10 +10,13 @@ struct Device; -template +namespace systems +{ + +template class Handle; -template +template class Manager { friend Handle; @@ -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 +template 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 +class Handle { + public: + using Type = T; + using Manager = Manager; + protected: constexpr static u32 INVALID_HANDLE = MaxValue; 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; public: + [[nodiscard]] Ref + 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 -class Handle : public RawHandle -{ - public: - using Type = T; - using Manager = Manager; - - protected: - // The only constructor requires a valid construction. - Handle(const u32 index, const u8 typeId) - : RawHandle{index, typeId} - { - AddRef(); - } - - friend Manager; - friend Ref; - - 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 - 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 + diff --git a/aster/include/aster/systems/render_resource_manager.h b/aster/include/aster/systems/render_resource_manager.h index 753ad3f..1a487b6 100644 --- a/aster/include/aster/systems/render_resource_manager.h +++ b/aster/include/aster/systems/render_resource_manager.h @@ -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 namespace systems { @@ -30,122 +32,63 @@ class RenderResourceManager using WriteCommand = vk::WriteDescriptorSet; - union WriteOwner { - Handle uBufferHandle; - Handle uImageHandle; - - explicit WriteOwner(const Handle &handle); - explicit WriteOwner(const Handle &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>; 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 m_Writes; eastl::deque m_WriteInfos; - eastl::vector m_WriteOwner; + // eastl::vector m_WriteOwner; #if !defined(ASTER_NDEBUG) usize m_CommitedBufferCount = 0; @@ -153,5 +96,4 @@ class RenderResourceManager usize m_CommitedStorageTextureCount = 0; #endif }; - } // namespace systems \ No newline at end of file diff --git a/aster/include/aster/systems/sampler_manager.h b/aster/include/aster/systems/sampler_manager.h new file mode 100644 index 0000000..0a75d77 --- /dev/null +++ b/aster/include/aster/systems/sampler_manager.h @@ -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; + +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 +{ + eastl::vector_map m_HashToSamplerIdx; + + public: + SamplerManager(const Device *device, const u32 maxCount, const u8 typeId); + ~SamplerManager() override; + + SamplerHandle Create(const SamplerCreateInfo &createInfo); +}; +} // namespace systems diff --git a/aster/src/aster/core/CMakeLists.txt b/aster/src/aster/core/CMakeLists.txt index 0710bdc..0b6059d 100644 --- a/aster/src/aster/core/CMakeLists.txt +++ b/aster/src/aster/core/CMakeLists.txt @@ -13,4 +13,5 @@ PRIVATE "buffer.cpp" "image.cpp" "surface.cpp" - "window.cpp") + "window.cpp" + "sampler.cpp") diff --git a/aster/src/aster/core/sampler.cpp b/aster/src/aster/core/sampler.cpp new file mode 100644 index 0000000..f656c42 --- /dev/null +++ b/aster/src/aster/core/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 : "") THEN_ABORT(-1); +} \ No newline at end of file diff --git a/aster/src/aster/systems/CMakeLists.txt b/aster/src/aster/systems/CMakeLists.txt index 1b1215b..519d315 100644 --- a/aster/src/aster/systems/CMakeLists.txt +++ b/aster/src/aster/systems/CMakeLists.txt @@ -7,4 +7,5 @@ PRIVATE "manager.cpp" "buffer_manager.cpp" "image_manager.cpp" +"sampler_manager.cpp" "render_resource_manager.cpp") diff --git a/aster/src/aster/systems/buffer_manager.cpp b/aster/src/aster/systems/buffer_manager.cpp index 580f004..5013de3 100644 --- a/aster/src/aster/systems/buffer_manager.cpp +++ b/aster/src/aster/systems/buffer_manager.cpp @@ -5,10 +5,10 @@ #include "systems/buffer_manager.h" -Manager *Manager::m_Instance = nullptr; - using namespace systems; +Manager *Manager::m_Instance = nullptr; + BufferHandle BufferManager::CreateStorageBuffer(const usize size, const cstr name) { diff --git a/aster/src/aster/systems/image_manager.cpp b/aster/src/aster/systems/image_manager.cpp index adfe232..4a0e3d1 100644 --- a/aster/src/aster/systems/image_manager.cpp +++ b/aster/src/aster/systems/image_manager.cpp @@ -7,10 +7,10 @@ #include "core/device.h" -Manager *Manager::m_Instance = nullptr; - using namespace systems; +Manager *Manager::m_Instance = nullptr; + vk::ImageCreateInfo ToImageCreateInfo(const Texture2DCreateInfo &createInfo); vk::ImageCreateInfo ToImageCreateInfo(const TextureCubeCreateInfo &createInfo); vk::ImageCreateInfo ToImageCreateInfo(const AttachmentCreateInfo &createInfo); diff --git a/aster/src/aster/systems/render_resource_manager.cpp b/aster/src/aster/systems/render_resource_manager.cpp index 1534470..3862f51 100644 --- a/aster/src/aster/systems/render_resource_manager.cpp +++ b/aster/src/aster/systems/render_resource_manager.cpp @@ -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(&handle); -} - -RenderResourceManager::WriteOwner::WriteOwner(const Handle &handle) - : uBufferHandle(handle) -{ -} - -RenderResourceManager::WriteOwner::WriteOwner(const Handle &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{ - // .type = vk::DescriptorType::eStorageImage, - // .descriptorCount = storageTexturesCount, - //}, + // 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(maxImages), .stageFlags = vk::ShaderStageFlagBits::eAll, }, - //vk::DescriptorSetLayoutBinding{ - // .binding = STORAGE_TEXTURE_BINDING_INDEX, - // .descriptorType = vk::DescriptorType::eStorageImage, - // .descriptorCount = Cast(storageTexturesCount), - // .stageFlags = vk::ShaderStageFlagBits::eAll, - //}, + // vk::DescriptorSetLayoutBinding{ + // .binding = STORAGE_TEXTURE_BINDING_INDEX, + // .descriptorType = vk::DescriptorType::eStorageImage, + // .descriptorCount = Cast(storageTexturesCount), + // .stageFlags = vk::ShaderStageFlagBits::eAll, + // }, }; vk::DescriptorBindingFlags bindingFlags = @@ -133,50 +119,128 @@ 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) - { - const Buffer *buffer = handle.Fetch(); - m_WriteInfos.emplace_back(vk::DescriptorBufferInfo{ - .buffer = buffer->m_Buffer, - .offset = 0, - .range = buffer->GetSize(), - }); - m_Writes.push_back({ - .dstSet = m_DescriptorSet, - .dstBinding = BUFFER_BINDING_INDEX, - .dstArrayElement = handle.GetIndex(), - .descriptorCount = 1, - .descriptorType = vk::DescriptorType::eStorageBuffer, - .pBufferInfo = &m_WriteInfos.back().uBufferInfo, - }); - } - else if constexpr (std::is_same_v) - { - const Image *image = handle.Fetch(); +#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_WriteInfos.emplace_back(vk::DescriptorImageInfo{ - .sampler = nullptr /* TODO Sampler */, - .imageView = image->m_View, - .imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal, - }); - m_Writes.push_back({ - .dstSet = m_DescriptorSet, - .dstBinding = IMAGE_BINDING_INDEX, - .dstArrayElement = handle.GetIndex(), - .descriptorCount = 1, - .descriptorType = vk::DescriptorType::eSampledImage, - .pImageInfo = &m_WriteInfos.back().uImageInfo, - }); - } else { - static_assert(false && "Type is currently unsupported"); + m_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()) + { + 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) @@ -192,4 +256,23 @@ RenderResourceManager::WriteInfo::WriteInfo(const vk::DescriptorImageInfo &info) RenderResourceManager::WriteInfo::WriteInfo(const vk::BufferView &info) : uBufferView{info} { -} \ No newline at end of file +} + +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(m_Writes.size()), m_Writes.data(), 0, nullptr); + + m_Writes.clear(); + m_WriteInfos.clear(); + } +} diff --git a/aster/src/aster/systems/sampler_manager.cpp b/aster/src/aster/systems/sampler_manager.cpp new file mode 100644 index 0000000..0d27449 --- /dev/null +++ b/aster/src/aster/systems/sampler_manager.cpp @@ -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 *Manager::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(createInfo.mipLodBias * 1000))); // Resolution of 10^-3 + hash = HashCombine(hash, HashAny(createInfo.anisotropyEnable)); + hash = HashCombine(hash, + HashAny(Cast(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(createInfo.minLod * 1000))); // 0.001 resolution is enough. + hash = HashCombine(hash, + HashAny(Cast(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; +} + diff --git a/samples/02_box/box.cpp b/samples/02_box/box.cpp index f26a436..a620743 100644 --- a/samples/02_box/box.cpp +++ b/samples/02_box/box.cpp @@ -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(swapchain.m_Extent.width) / Cast(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(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(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, MAX_FRAMES_IN_FLIGHT> depthImages; + eastl::fixed_vector, 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(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(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(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 diff --git a/samples/02_box/shader/bindless.hlsli b/samples/02_box/shader/bindless.hlsli new file mode 100644 index 0000000..db1cc68 --- /dev/null +++ b/samples/02_box/shader/bindless.hlsli @@ -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 VertexDataBuffer[]; +[[vk::binding(0, 0)]] StructuredBuffer CameraDataBuffer[]; + +[[vk::binding(1, 0)]] Texture2D Textures[]; +[[vk::binding(1, 0)]] SamplerState Samplers[]; diff --git a/samples/02_box/shader/box.ps.hlsl b/samples/02_box/shader/box.ps.hlsl index 562c878..262dfbb 100644 --- a/samples/02_box/shader/box.ps.hlsl +++ b/samples/02_box/shader/box.ps.hlsl @@ -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 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; } \ No newline at end of file diff --git a/samples/02_box/shader/box.vs.hlsl b/samples/02_box/shader/box.vs.hlsl index 4d96c75..c1c168e 100644 --- a/samples/02_box/shader/box.vs.hlsl +++ b/samples/02_box/shader/box.vs.hlsl @@ -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 Camera; -[[vk::binding(2, 0)]] StructuredBuffer Vertices; +[[vk::push_constant]] PCB Block; VS_Output main(VS_Input StageInput) { VS_Output output; + + CameraData Camera = CameraDataBuffer[Block.CameraBuffer.GetIndex()][0]; - output.UV0 = Vertices[StageInput.VertexIndex].UV0; + output.UV0 = VertexDataBuffer[Block.VertexBuffer.GetIndex()][StageInput.VertexIndex].TexCoord0; - float4 position = Vertices[StageInput.VertexIndex].Position; + float4 position = VertexDataBuffer[Block.VertexBuffer.GetIndex()][StageInput.VertexIndex].Position; output.VertexPosition = mul(Camera.Projection, mul(Camera.View, mul(Camera.Model, position)));