parent
afec1e3e32
commit
73c96dc56b
|
|
@ -15,6 +15,7 @@ INTERFACE
|
|||
"queue_allocation.h"
|
||||
"buffer.h"
|
||||
"image.h"
|
||||
"image_view.h"
|
||||
"surface.h"
|
||||
"size.h"
|
||||
"type_traits.h"
|
||||
|
|
|
|||
|
|
@ -26,7 +26,9 @@
|
|||
#if !defined(NDEBUG)
|
||||
#define VULKAN_HPP_ASSERT(expr) DEBUG_IF(!(expr), "Vulkan assert failed")
|
||||
#endif
|
||||
|
||||
#include "type_traits.h"
|
||||
#include "EASTL/intrusive_ptr.h"
|
||||
|
||||
#include <EASTL/fixed_string.h>
|
||||
#include <EASTL/string.h>
|
||||
|
|
@ -51,6 +53,7 @@ constexpr u32 ASTER_API_VERSION = VK_API_VERSION_1_3;
|
|||
#define Take(ELEMENT) eastl::exchange(ELEMENT, {})
|
||||
|
||||
#define TODO(MSG) assert(false && ("Unimplemented: " MSG))
|
||||
#define FIX(MSG) static_assert(false && ("Unimplemented: " MSG))
|
||||
|
||||
[[nodiscard]] inline bool
|
||||
Failed(const vk::Result result)
|
||||
|
|
@ -212,12 +215,5 @@ struct fmt::formatter<eastl::fixed_string<TType, TCount, TOverflow>> : nested_fo
|
|||
}
|
||||
};
|
||||
|
||||
namespace aster
|
||||
{
|
||||
template <typename TRef, typename TVal>
|
||||
TVal &
|
||||
Deref(TRef ref)
|
||||
{
|
||||
return ref.Deref();
|
||||
}
|
||||
}
|
||||
template <concepts::Manageable T>
|
||||
using Ref = eastl::intrusive_ptr<T>;
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include "global.h"
|
||||
|
||||
struct StorageTexture;
|
||||
struct Device;
|
||||
|
||||
[[nodiscard]] inline vk::Extent2D
|
||||
|
|
@ -46,6 +47,28 @@ struct Image
|
|||
u8 m_LayerCount = 0;
|
||||
u8 m_MipLevels = 0;
|
||||
|
||||
constexpr static u8 SAMPLED_BIT = 1 << 7;
|
||||
constexpr static u8 STORAGE_BIT = 1 << 6;
|
||||
constexpr static u8 CUBE_BIT = 1 << 5;
|
||||
|
||||
[[nodiscard]] bool
|
||||
IsSampled() const
|
||||
{
|
||||
return m_Flags_ & SAMPLED_BIT;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool
|
||||
IsStorage() const
|
||||
{
|
||||
return m_Flags_ & STORAGE_BIT;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool
|
||||
IsCube() const
|
||||
{
|
||||
return m_Flags_ & CUBE_BIT;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool
|
||||
IsValid() const
|
||||
{
|
||||
|
|
@ -83,48 +106,114 @@ struct Image
|
|||
}
|
||||
|
||||
void Destroy();
|
||||
|
||||
static bool
|
||||
Conforms(const Image &)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
namespace concepts
|
||||
{
|
||||
template <typename T>
|
||||
concept Image = std::derived_from<T, ::Image> and Manageable<T>;
|
||||
|
||||
template <typename T>
|
||||
concept ImageRef = Derefencable<T> and Image<DereferencesTo<T>>;
|
||||
|
||||
template <typename T>
|
||||
concept SampledImage = requires() {
|
||||
{ T::SAMPLED } -> std::convertible_to<bool>;
|
||||
} and T::SAMPLED and Image<T>;
|
||||
|
||||
template <typename T>
|
||||
concept SampledImageRef = Derefencable<T> and SampledImage<DereferencesTo<T>>;
|
||||
|
||||
template <typename T>
|
||||
concept ImageCube = requires() {
|
||||
{ T::CUBED } -> std::convertible_to<bool>;
|
||||
} and T::CUBED and Image<T>;
|
||||
|
||||
template <typename T>
|
||||
concept ImageCubeRef = Derefencable<T> and ImageCube<DereferencesTo<T>>;
|
||||
|
||||
template <typename T>
|
||||
concept StorageImage = requires() {
|
||||
{ T::STORAGE } -> std::convertible_to<bool>;
|
||||
} and T::STORAGE and Image<T>;
|
||||
|
||||
template <typename T>
|
||||
concept StorageImageRef = Derefencable<T> and StorageImage<DereferencesTo<T>>;
|
||||
|
||||
} // namespace concepts
|
||||
|
||||
struct Texture : Image
|
||||
{
|
||||
void Init(const Device *device, vk::Extent2D extent, vk::Format imageFormat, bool isMipMapped, cstr name = nullptr);
|
||||
constexpr static bool SAMPLED = true;
|
||||
|
||||
static bool
|
||||
Conforms(const Image &other)
|
||||
{
|
||||
return other.IsSampled();
|
||||
}
|
||||
};
|
||||
|
||||
static_assert(sizeof(Texture) == sizeof(Image));
|
||||
|
||||
struct TextureCube : Texture
|
||||
struct ImageCube : Image
|
||||
{
|
||||
void
|
||||
Init(const Device *device, u32 cubeSide, vk::Format imageFormat, bool isMipMapped = false, cstr name = nullptr);
|
||||
constexpr static bool CUBE = true;
|
||||
|
||||
static bool
|
||||
Conforms(const Image &other)
|
||||
{
|
||||
return other.IsCube();
|
||||
}
|
||||
};
|
||||
|
||||
static_assert(sizeof(TextureCube) == sizeof(Image));
|
||||
|
||||
struct AttachmentImage : Image
|
||||
struct TextureCube : Image
|
||||
{
|
||||
void Init(const Device *device, vk::Extent2D extent, vk::Format imageFormat, cstr name = nullptr);
|
||||
constexpr static bool SAMPLED = true;
|
||||
constexpr static bool CUBE = true;
|
||||
|
||||
static bool
|
||||
Conforms(const Image &other)
|
||||
{
|
||||
return other.IsSampled() && other.IsCube();
|
||||
}
|
||||
};
|
||||
|
||||
static_assert(sizeof(AttachmentImage) == sizeof(Image));
|
||||
|
||||
struct DepthImage : Image
|
||||
struct StorageImage : Image
|
||||
{
|
||||
void Init(const Device *device, vk::Extent2D extent, cstr name = nullptr);
|
||||
constexpr static bool STORAGE = true;
|
||||
|
||||
static bool
|
||||
Conforms(const Image &other)
|
||||
{
|
||||
return other.IsStorage();
|
||||
}
|
||||
};
|
||||
|
||||
static_assert(sizeof(DepthImage) == sizeof(Image));
|
||||
|
||||
struct StorageTexture : Texture
|
||||
struct StorageTexture : StorageImage
|
||||
{
|
||||
void Init(const Device *device, vk::Extent2D extent, vk::Format imageFormat, bool isSampled, cstr name = nullptr);
|
||||
constexpr static bool SAMPLED = true;
|
||||
constexpr static bool STORAGE = true;
|
||||
|
||||
static bool
|
||||
Conforms(const Image &other)
|
||||
{
|
||||
return other.IsStorage() && other.IsSampled();
|
||||
}
|
||||
};
|
||||
|
||||
static_assert(sizeof(StorageTexture) == sizeof(Image));
|
||||
|
||||
struct StorageTextureCube : StorageTexture
|
||||
struct StorageTextureCube : StorageImage
|
||||
{
|
||||
void Init(const Device *device, u32 cubeSide, vk::Format imageFormat, bool isSampled, bool isMipMapped = false,
|
||||
cstr name = nullptr);
|
||||
};
|
||||
constexpr static bool SAMPLED = true;
|
||||
constexpr static bool CUBE = true;
|
||||
constexpr static bool STORAGE = true;
|
||||
|
||||
static_assert(sizeof(StorageTextureCube) == sizeof(Image));
|
||||
static bool
|
||||
Conforms(const Image &other)
|
||||
{
|
||||
return other.IsStorage() && other.IsSampled() && other.IsCube();
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
// =============================================
|
||||
// Aster: image_view.h
|
||||
// Copyright (c) 2020-2025 Anish Bhobe
|
||||
// =============================================
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "global.h"
|
||||
#include "image.h"
|
||||
|
||||
template <concepts::Image TImage = Image>
|
||||
struct View
|
||||
{
|
||||
using ImageType = TImage;
|
||||
|
||||
Ref<ImageType> m_Image;
|
||||
vk::ImageView m_View = nullptr;
|
||||
vk::Extent3D m_Extent;
|
||||
std::atomic<u32> m_RefCount;
|
||||
u8 m_EmptyPadding_ = 0;
|
||||
u8 m_Flags_ = 0;
|
||||
u8 m_LayerCount = 0;
|
||||
u8 m_MipLevels = 0;
|
||||
};
|
||||
|
||||
using ImageView = View<>;
|
||||
|
|
@ -6,6 +6,7 @@
|
|||
#pragma once
|
||||
|
||||
struct Device;
|
||||
struct Image;
|
||||
|
||||
namespace concepts
|
||||
{
|
||||
|
|
@ -16,6 +17,14 @@ concept RefCounted = requires(T a) {
|
|||
{ a.IsReferenced() } -> std::convertible_to<bool>;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
concept Derefencable = requires(T a) {
|
||||
{ *a };
|
||||
};
|
||||
|
||||
template <Derefencable T>
|
||||
using DereferencesTo = std::remove_cvref_t<decltype(*std::declval<T>())>;
|
||||
|
||||
template <typename T>
|
||||
concept DeviceDestructible = requires(T a, Device *p) {
|
||||
{ a.Destroy(p) } -> std::same_as<void>;
|
||||
|
|
|
|||
|
|
@ -7,5 +7,8 @@ INTERFACE
|
|||
"manager.h"
|
||||
"buffer_manager.h"
|
||||
"image_manager.h"
|
||||
"image_view_manager.h"
|
||||
"sampler_manager.h"
|
||||
"render_resource_manager.h")
|
||||
"resource.h"
|
||||
"resource_manager.h"
|
||||
"commit_manager.h")
|
||||
|
|
|
|||
|
|
@ -5,20 +5,20 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "manager.h"
|
||||
|
||||
#include "aster/aster.h"
|
||||
#include "aster/core/buffer.h"
|
||||
#include "manager.h"
|
||||
|
||||
namespace systems
|
||||
{
|
||||
using BufferHandle = Manager<Buffer>::Handle;
|
||||
|
||||
class BufferManager final : public Manager<Buffer>
|
||||
{
|
||||
public:
|
||||
BufferManager(const Device *device, const u32 maxCount, const u8 binding);
|
||||
BufferManager(const Device *device, u32 maxCount);
|
||||
|
||||
[[nodiscard]] Handle CreateStorageBuffer(usize size, cstr name = nullptr);
|
||||
[[nodiscard]] Handle CreateUniformBuffer(usize size, cstr name = nullptr);
|
||||
[[nodiscard]] Handle CreateStagingBuffer(usize size, cstr name = nullptr);
|
||||
};
|
||||
} // namespace systems
|
||||
|
|
|
|||
|
|
@ -16,73 +16,12 @@
|
|||
#include "EASTL/intrusive_hash_map.h"
|
||||
#include "EASTL/bonus/fixed_ring_buffer.h"
|
||||
|
||||
#include "resource.h"
|
||||
|
||||
namespace systems
|
||||
{
|
||||
|
||||
class RenderResourceManager;
|
||||
|
||||
/**
|
||||
* CommitEntry manages the lifetime of the committed resource.
|
||||
* @tparam T Type of the committed resource.
|
||||
*/
|
||||
template <concepts::Manageable T>
|
||||
class CommitEntry
|
||||
{
|
||||
private:
|
||||
u32 m_Index;
|
||||
|
||||
explicit CommitEntry(const u32 index)
|
||||
: m_Index{index}
|
||||
{
|
||||
AddRef();
|
||||
}
|
||||
|
||||
friend class RenderResourceManager;
|
||||
|
||||
public:
|
||||
CommitEntry(const CommitEntry &other)
|
||||
: m_Index{other.m_Index}
|
||||
{
|
||||
AddRef();
|
||||
}
|
||||
|
||||
CommitEntry(CommitEntry &&other) noexcept
|
||||
: m_Index{other.m_Index}
|
||||
{
|
||||
AddRef();
|
||||
}
|
||||
|
||||
CommitEntry &
|
||||
operator=(const CommitEntry &other)
|
||||
{
|
||||
if (this == &other)
|
||||
return *this;
|
||||
m_Index = other.m_Index;
|
||||
AddRef();
|
||||
return *this;
|
||||
}
|
||||
|
||||
CommitEntry &
|
||||
operator=(CommitEntry &&other) noexcept
|
||||
{
|
||||
if (this == &other)
|
||||
return *this;
|
||||
m_Index = other.m_Index;
|
||||
AddRef();
|
||||
return *this;
|
||||
}
|
||||
|
||||
~CommitEntry()
|
||||
{
|
||||
Release();
|
||||
}
|
||||
|
||||
private:
|
||||
void AddRef() const; ///< Increases the refcount in the RenderResourceManager.
|
||||
void Release() const; ///< Decreases the refcount in the RenderResourceManager.
|
||||
};
|
||||
|
||||
class RenderResourceManager
|
||||
class CommitManager
|
||||
{
|
||||
private:
|
||||
template <concepts::Manageable T>
|
||||
|
|
@ -91,7 +30,7 @@ class RenderResourceManager
|
|||
using Type = T;
|
||||
using Manager = Manager<Type>;
|
||||
using Handle = typename Manager::Handle;
|
||||
using CommitE = CommitEntry<Type>;
|
||||
using Resource = ResId<Type>;
|
||||
|
||||
struct Entry : public eastl::intrusive_hash_node_key<Handle>
|
||||
{
|
||||
|
|
@ -173,7 +112,7 @@ class RenderResourceManager
|
|||
PIN_MEMORY(HandleMapper);
|
||||
|
||||
/// Returns a commit, and a bool signifying if it is a new commit.
|
||||
std::tuple<CommitE, bool>
|
||||
std::tuple<Resource, bool>
|
||||
Create(const Handle &object)
|
||||
{
|
||||
// Get-from freelist
|
||||
|
|
@ -184,7 +123,7 @@ class RenderResourceManager
|
|||
{
|
||||
it->AddRef();
|
||||
auto i = GetIndex(*it);
|
||||
return {CommitE{i}, false};
|
||||
return {Resource{i}, false};
|
||||
}
|
||||
|
||||
Entry &data = m_FreeList.Pop();
|
||||
|
|
@ -196,17 +135,23 @@ class RenderResourceManager
|
|||
|
||||
auto i = GetIndex(data);
|
||||
|
||||
return {CommitE{i}, true};
|
||||
return {Resource{i}, true};
|
||||
}
|
||||
|
||||
Handle
|
||||
GetHandle(const Resource &res)
|
||||
{
|
||||
return m_Data[res.m_Index].mKey;
|
||||
}
|
||||
|
||||
void
|
||||
AddRef(const CommitE &commit)
|
||||
AddRef(const Resource &commit)
|
||||
{
|
||||
m_Data.at(commit.m_Index).AddRef();
|
||||
}
|
||||
|
||||
void
|
||||
Release(const CommitE &commit)
|
||||
Release(const Resource &commit)
|
||||
{
|
||||
auto &entry = m_Data.at(commit.m_Index);
|
||||
entry.Release();
|
||||
|
|
@ -271,18 +216,58 @@ class RenderResourceManager
|
|||
public:
|
||||
const Device *m_Device;
|
||||
|
||||
RenderResourceManager(const Device *device, u32 const maxBuffers, const u32 maxImages,
|
||||
const SamplerHandle &defaultSampler);
|
||||
~RenderResourceManager();
|
||||
CommitManager(const Device *device, u32 maxBuffers, u32 maxImages, u32 maxStorageImages,
|
||||
Ref<Sampler> defaultSampler);
|
||||
~CommitManager();
|
||||
|
||||
PIN_MEMORY(RenderResourceManager);
|
||||
PIN_MEMORY(CommitManager);
|
||||
|
||||
CommitEntry<Buffer> Commit(const BufferHandle &buffer);
|
||||
CommitEntry<Image> Commit(const ImageHandle &handle);
|
||||
CommitEntry<Image> Commit(const ImageHandle &image, const SamplerHandle &sampler);
|
||||
// Commit Buffer
|
||||
ResId<Buffer> CommitBuffer(const Ref<Buffer> &buffer);
|
||||
|
||||
// Commit Storage Images
|
||||
ResId<StorageImage> CommitStorageImage(const concepts::StorageImageRef auto &image)
|
||||
{
|
||||
return CommitStorageImage(CastImage<StorageImage>(image));
|
||||
}
|
||||
ResId<StorageImage> CommitStorageImage(const Ref<StorageImage> &image);
|
||||
|
||||
// Sampled Images
|
||||
ResId<Texture>
|
||||
CommitTexture(const concepts::SampledImageRef auto &image, const Ref<Sampler> &sampler)
|
||||
{
|
||||
return CommitTexture(CastImage<Texture>(image), sampler);
|
||||
}
|
||||
|
||||
ResId<Texture>
|
||||
CommitTexture(const concepts::SampledImageRef auto &image)
|
||||
{
|
||||
return CommitTexture(CastImage<Texture>(image));
|
||||
}
|
||||
|
||||
ResId<Texture> CommitTexture(const Ref<Texture> &handle);
|
||||
ResId<Texture> CommitTexture(const Ref<Texture> &image, const Ref<Sampler> &sampler);
|
||||
|
||||
void Update();
|
||||
|
||||
Ref<Buffer>
|
||||
FetchHandle(const ResId<Buffer> &id)
|
||||
{
|
||||
return m_Buffers.GetHandle(id);
|
||||
}
|
||||
|
||||
Ref<Texture>
|
||||
FetchHandle(const ResId<Texture> &id)
|
||||
{
|
||||
return m_Images.GetHandle(id);
|
||||
}
|
||||
|
||||
Ref<StorageImage>
|
||||
FetchHandle(const ResId<StorageImage> &id)
|
||||
{
|
||||
return m_StorageImages.GetHandle(id);
|
||||
}
|
||||
|
||||
[[nodiscard]] const vk::DescriptorSetLayout &
|
||||
GetDescriptorSetLayout() const
|
||||
{
|
||||
|
|
@ -295,10 +280,10 @@ class RenderResourceManager
|
|||
return m_DescriptorSet;
|
||||
}
|
||||
|
||||
static RenderResourceManager *
|
||||
Instance()
|
||||
static CommitManager &Instance()
|
||||
{
|
||||
return m_Instance;
|
||||
assert(m_Instance);
|
||||
return *m_Instance;
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
@ -308,54 +293,68 @@ class RenderResourceManager
|
|||
|
||||
constexpr static u8 BUFFER_BINDING_INDEX = 0x0;
|
||||
constexpr static u8 IMAGE_BINDING_INDEX = 0x1;
|
||||
constexpr static u8 STORAGE_IMAGE_BINDING_INDEX = 0x2;
|
||||
|
||||
HandleMapper<Buffer> m_Buffers;
|
||||
HandleMapper<Image> m_Images;
|
||||
SamplerHandle m_DefaultSampler;
|
||||
HandleMapper<Texture> m_Images;
|
||||
HandleMapper<StorageImage> m_StorageImages;
|
||||
|
||||
Ref<Sampler> m_DefaultSampler;
|
||||
|
||||
eastl::vector<vk::WriteDescriptorSet> m_Writes;
|
||||
eastl::deque<WriteInfo> m_WriteInfos;
|
||||
// eastl::vector<WriteOwner> m_WriteOwner;
|
||||
|
||||
static RenderResourceManager *m_Instance;
|
||||
friend CommitEntry<Buffer>;
|
||||
friend CommitEntry<Image>;
|
||||
static CommitManager *m_Instance;
|
||||
friend ResId<Buffer>;
|
||||
friend ResId<Texture>;
|
||||
friend ResId<StorageImage>;
|
||||
|
||||
void
|
||||
AddRef(const CommitEntry<Buffer> &handle)
|
||||
AddRef(const ResId<Buffer> &handle)
|
||||
{
|
||||
m_Buffers.AddRef(handle);
|
||||
}
|
||||
void
|
||||
AddRef(const CommitEntry<Image> &handle)
|
||||
AddRef(const ResId<Texture> &handle)
|
||||
{
|
||||
m_Images.AddRef(handle);
|
||||
}
|
||||
void
|
||||
AddRef(const ResId<StorageImage> &handle)
|
||||
{
|
||||
m_StorageImages.AddRef(handle);
|
||||
}
|
||||
|
||||
void
|
||||
Release(const CommitEntry<Buffer> &handle)
|
||||
Release(const ResId<Buffer> &handle)
|
||||
{
|
||||
m_Buffers.Release(handle);
|
||||
}
|
||||
void
|
||||
Release(const CommitEntry<Image> &handle)
|
||||
Release(const ResId<Texture> &handle)
|
||||
{
|
||||
m_Images.Release(handle);
|
||||
}
|
||||
void
|
||||
Release(const ResId<StorageImage> &handle)
|
||||
{
|
||||
m_StorageImages.Release(handle);
|
||||
}
|
||||
};
|
||||
|
||||
template <concepts::Manageable T>
|
||||
void
|
||||
CommitEntry<T>::AddRef() const
|
||||
ResId<T>::AddRef() const
|
||||
{
|
||||
RenderResourceManager::Instance()->AddRef(*this);
|
||||
CommitManager::Instance().AddRef(*this);
|
||||
}
|
||||
|
||||
template <concepts::Manageable T>
|
||||
void
|
||||
CommitEntry<T>::Release() const
|
||||
ResId<T>::Release() const
|
||||
{
|
||||
RenderResourceManager::Instance()->Release(*this);
|
||||
CommitManager::Instance().Release(*this);
|
||||
}
|
||||
|
||||
} // namespace systems
|
||||
|
|
@ -5,13 +5,22 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "manager.h"
|
||||
|
||||
#include "aster/aster.h"
|
||||
#include "aster/core/image.h"
|
||||
#include "manager.h"
|
||||
|
||||
namespace systems
|
||||
{
|
||||
|
||||
template <std::derived_from<Image> TTo>
|
||||
static Ref<TTo>
|
||||
CastImage(const concepts::ImageRef auto &from)
|
||||
{
|
||||
assert(TTo::Conforms(*from.get()));
|
||||
return Recast<TTo *>(from.get());
|
||||
}
|
||||
|
||||
struct Texture2DCreateInfo
|
||||
{
|
||||
vk::Format m_Format = vk::Format::eUndefined;
|
||||
|
|
@ -45,16 +54,30 @@ struct DepthStencilImageCreateInfo
|
|||
cstr m_Name = nullptr;
|
||||
};
|
||||
|
||||
using ImageHandle = Manager<Image>::Handle;
|
||||
|
||||
class ImageManager final : public Manager<Image>
|
||||
{
|
||||
public:
|
||||
ImageManager(const Device *device, const u32 maxCount, const u8 binding);
|
||||
ImageManager(const Device *device, const u32 maxCount);
|
||||
|
||||
[[nodiscard]] Handle CreateTexture2D(const Texture2DCreateInfo &createInfo);
|
||||
[[nodiscard]] Handle CreateTextureCube(const TextureCubeCreateInfo &createInfo);
|
||||
[[nodiscard]] Handle CreateAttachment(const AttachmentCreateInfo &createInfo);
|
||||
[[nodiscard]] Handle CreateDepthStencilImage(const DepthStencilImageCreateInfo &createInfo);
|
||||
template <concepts::Image T>
|
||||
[[nodiscard]] Ref<T>
|
||||
CreateTexture2D(const Texture2DCreateInfo &createInfo)
|
||||
{
|
||||
auto handle = CreateTexture2D(createInfo);
|
||||
return CastImage<T>(handle);
|
||||
}
|
||||
|
||||
template <concepts::Image T>
|
||||
[[nodiscard]] Ref<T>
|
||||
CreateTextureCube(const TextureCubeCreateInfo &createInfo)
|
||||
{
|
||||
auto handle = CreateTextureCube(createInfo);
|
||||
return CastImage<T>(handle);
|
||||
}
|
||||
|
||||
[[nodiscard]] Ref<Image> CreateTexture2D(const Texture2DCreateInfo &createInfo);
|
||||
[[nodiscard]] Ref<ImageCube> CreateTextureCube(const TextureCubeCreateInfo &createInfo);
|
||||
[[nodiscard]] Ref<Image> CreateAttachment(const AttachmentCreateInfo &createInfo);
|
||||
[[nodiscard]] Ref<Image> CreateDepthStencilImage(const DepthStencilImageCreateInfo &createInfo);
|
||||
};
|
||||
} // namespace systems
|
||||
|
|
|
|||
|
|
@ -0,0 +1,32 @@
|
|||
// =============================================
|
||||
// Aster: image_manager.h
|
||||
// Copyright (c) 2020-2024 Anish Bhobe
|
||||
// =============================================
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "manager.h"
|
||||
|
||||
#include "aster/aster.h"
|
||||
#include "aster/core/image_view.h"
|
||||
|
||||
namespace systems
|
||||
{
|
||||
//
|
||||
//template <std::derived_from<Image> TTo>
|
||||
//static Ref<TTo>
|
||||
//CastView(const concepts::ImageRef auto &from)
|
||||
//{
|
||||
// assert(TTo::Conforms(*from.get()));
|
||||
// return Recast<TTo *>(from.get());
|
||||
//}
|
||||
|
||||
class ImageViewManager final : public Manager<ImageView>
|
||||
{
|
||||
public:
|
||||
ImageViewManager(const Device *device, const u32 maxCount);
|
||||
|
||||
|
||||
};
|
||||
|
||||
} // namespace systems
|
||||
|
|
@ -21,28 +21,22 @@ class Manager
|
|||
{
|
||||
public:
|
||||
using Type = T;
|
||||
using Handle = eastl::intrusive_ptr<Type>;
|
||||
using Handle = Ref<T>;
|
||||
|
||||
/**
|
||||
* Constructor for the Manager class template.
|
||||
* @param device Device with which resources are created.
|
||||
* @param maxCount Max number of resources that can be created (maxCount <= Handle::INDEX_MASK)
|
||||
* @param binding The shader binding at which this manager will bind its resources.
|
||||
*/
|
||||
explicit Manager(const Device *device, const u32 maxCount, const u8 binding)
|
||||
explicit Manager(const Device *device, const u32 maxCount)
|
||||
: m_Data{maxCount}
|
||||
, m_Binding{binding}
|
||||
, m_Device{device}
|
||||
{
|
||||
assert(!m_Instance && "Attempting to initialize a second Manager");
|
||||
|
||||
u32 i = 0;
|
||||
for (auto& element : m_Data)
|
||||
{
|
||||
*Recast<u32 *>(&element) = ++i;
|
||||
}
|
||||
|
||||
m_Instance = this;
|
||||
}
|
||||
|
||||
virtual ~Manager()
|
||||
|
|
@ -61,8 +55,6 @@ class Manager
|
|||
|
||||
m_FreeHead = 0;
|
||||
m_Device = nullptr;
|
||||
|
||||
m_Instance = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -85,9 +77,6 @@ class Manager
|
|||
private:
|
||||
eastl::vector<Type> m_Data; // Data also keeps the freelist during 'not use'.
|
||||
u32 m_FreeHead = 0;
|
||||
u8 m_Binding = 0;
|
||||
|
||||
static Manager *m_Instance;
|
||||
|
||||
protected:
|
||||
const Device *m_Device;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,92 @@
|
|||
// =============================================
|
||||
// Aster: resource.h
|
||||
// Copyright (c) 2020-2024 Anish Bhobe
|
||||
// =============================================
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <EASTL/intrusive_ptr.h>
|
||||
|
||||
namespace systems
|
||||
{
|
||||
|
||||
/**
|
||||
* ResId manages the lifetime of the committed resource.
|
||||
* @tparam T Type of the committed resource.
|
||||
*/
|
||||
template <concepts::Manageable T>
|
||||
class ResId
|
||||
{
|
||||
public:
|
||||
constexpr static u32 INVALID = MaxValue<u32>;
|
||||
|
||||
private:
|
||||
u32 m_Index;
|
||||
|
||||
explicit ResId(const u32 index)
|
||||
: m_Index{index}
|
||||
{
|
||||
AddRef();
|
||||
}
|
||||
|
||||
friend class CommitManager;
|
||||
|
||||
public:
|
||||
static ResId
|
||||
Null()
|
||||
{
|
||||
return ResId{INVALID};
|
||||
}
|
||||
|
||||
ResId(const ResId &other)
|
||||
: m_Index{other.m_Index}
|
||||
{
|
||||
AddRef();
|
||||
}
|
||||
|
||||
ResId(ResId &&other) noexcept
|
||||
: m_Index{other.m_Index}
|
||||
{
|
||||
AddRef();
|
||||
}
|
||||
|
||||
ResId &
|
||||
operator=(const ResId &other)
|
||||
{
|
||||
if (this == &other)
|
||||
return *this;
|
||||
m_Index = other.m_Index;
|
||||
AddRef();
|
||||
return *this;
|
||||
}
|
||||
|
||||
ResId &
|
||||
operator=(ResId &&other) noexcept
|
||||
{
|
||||
if (this == &other)
|
||||
return *this;
|
||||
m_Index = other.m_Index;
|
||||
AddRef();
|
||||
return *this;
|
||||
}
|
||||
|
||||
~ResId()
|
||||
{
|
||||
Release();
|
||||
}
|
||||
|
||||
private:
|
||||
void AddRef() const; ///< Increases the refcount in the CommitManager.
|
||||
void Release() const; ///< Decreases the refcount in the CommitManager.
|
||||
};
|
||||
|
||||
struct NullId
|
||||
{
|
||||
template <concepts::Manageable T>
|
||||
operator ResId<T>()
|
||||
{
|
||||
return ResId<T>::Null();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace systems
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
// =============================================
|
||||
// Aster: resource_manager.h
|
||||
// Copyright (c) 2020-2024 Anish Bhobe
|
||||
// =============================================
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "aster/aster.h"
|
||||
|
||||
#include "buffer_manager.h"
|
||||
#include "image_manager.h"
|
||||
#include "sampler_manager.h"
|
||||
|
||||
namespace systems
|
||||
{
|
||||
class ResourceManager
|
||||
{
|
||||
BufferManager m_Buffers;
|
||||
ImageManager m_Images;
|
||||
SamplerManager m_Samplers;
|
||||
|
||||
public:
|
||||
ResourceManager(const Device *device, u32 maxBufferCount, u32 maxImageCount, u32 maxSamplerCount)
|
||||
: m_Buffers{device, maxBufferCount}
|
||||
, m_Images{device, maxImageCount}
|
||||
, m_Samplers{device, maxSamplerCount}
|
||||
{
|
||||
}
|
||||
|
||||
BufferManager &
|
||||
Buffers()
|
||||
{
|
||||
return m_Buffers;
|
||||
}
|
||||
|
||||
ImageManager &
|
||||
Images()
|
||||
{
|
||||
return m_Images;
|
||||
}
|
||||
|
||||
SamplerManager &
|
||||
Samplers()
|
||||
{
|
||||
return m_Samplers;
|
||||
}
|
||||
|
||||
~ResourceManager() = default;
|
||||
|
||||
PIN_MEMORY(ResourceManager);
|
||||
};
|
||||
} // namespace systems
|
||||
|
|
@ -5,37 +5,88 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "EASTL/vector_map.h"
|
||||
#include "manager.h"
|
||||
#include "EASTL/hash_map.h"
|
||||
|
||||
#include "aster/aster.h"
|
||||
#include "aster/core/sampler.h"
|
||||
#include "manager.h"
|
||||
|
||||
#include "EASTL/vector_map.h"
|
||||
|
||||
template <>
|
||||
struct eastl::hash<vk::SamplerCreateInfo>
|
||||
{
|
||||
usize
|
||||
operator()(const vk::SamplerCreateInfo &createInfo) const noexcept
|
||||
{
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
namespace systems
|
||||
{
|
||||
using SamplerHandle = Manager<Sampler>::Handle;
|
||||
|
||||
struct SamplerCreateInfo : vk::SamplerCreateInfo
|
||||
struct SamplerCreateInfo
|
||||
{
|
||||
cstr m_Name = nullptr;
|
||||
vk::SamplerCreateFlags m_Flags = {};
|
||||
vk::Filter m_MagFilter = vk::Filter::eLinear;
|
||||
vk::Filter m_MinFilter = vk::Filter::eLinear;
|
||||
vk::SamplerMipmapMode m_MipmapMode = vk::SamplerMipmapMode::eLinear;
|
||||
vk::SamplerAddressMode m_AddressModeU = vk::SamplerAddressMode::eRepeat;
|
||||
vk::SamplerAddressMode m_AddressModeV = vk::SamplerAddressMode::eRepeat;
|
||||
vk::SamplerAddressMode m_AddressModeW = vk::SamplerAddressMode::eRepeat;
|
||||
vk::BorderColor m_BorderColor = vk::BorderColor::eFloatOpaqueBlack;
|
||||
vk::CompareOp m_CompareOp = vk::CompareOp::eNever;
|
||||
f32 m_MipLodBias = 0.0f;
|
||||
f32 m_MaxAnisotropy = 16.0f;
|
||||
f32 m_MinLod = 0;
|
||||
f32 m_MaxLod = VK_LOD_CLAMP_NONE;
|
||||
bool m_AnisotropyEnable = true;
|
||||
bool m_CompareEnable = false;
|
||||
bool m_NormalizedCoordinates = true;
|
||||
|
||||
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,
|
||||
}
|
||||
explicit operator vk::SamplerCreateInfo() const
|
||||
{
|
||||
return {
|
||||
.flags = m_Flags,
|
||||
.magFilter = m_MagFilter,
|
||||
.minFilter = m_MinFilter,
|
||||
.mipmapMode = m_MipmapMode,
|
||||
.addressModeU = m_AddressModeU,
|
||||
.addressModeV = m_AddressModeV,
|
||||
.addressModeW = m_AddressModeW,
|
||||
.mipLodBias = m_MipLodBias,
|
||||
.anisotropyEnable = m_AnisotropyEnable,
|
||||
.maxAnisotropy = m_MaxAnisotropy,
|
||||
.compareEnable = m_CompareEnable,
|
||||
.compareOp = m_CompareOp,
|
||||
.minLod = m_MinLod,
|
||||
.maxLod = m_MaxLod,
|
||||
.borderColor = m_BorderColor,
|
||||
.unnormalizedCoordinates = !m_NormalizedCoordinates,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -46,12 +97,12 @@ struct SamplerCreateInfo : vk::SamplerCreateInfo
|
|||
*/
|
||||
class SamplerManager final : public Manager<Sampler>
|
||||
{
|
||||
eastl::vector_map<usize, Handle> m_HashToSamplerIdx;
|
||||
eastl::hash_map<vk::SamplerCreateInfo, Handle> m_HashToSamplerIdx;
|
||||
|
||||
public:
|
||||
SamplerManager(const Device *device, const u32 maxCount, const u8 typeId);
|
||||
SamplerManager(const Device *device, const u32 maxCount);
|
||||
~SamplerManager() override;
|
||||
|
||||
SamplerHandle Create(const SamplerCreateInfo &createInfo);
|
||||
Ref<Sampler> CreateSampler(const SamplerCreateInfo &createInfo);
|
||||
};
|
||||
} // namespace systems
|
||||
|
|
|
|||
|
|
@ -3,4 +3,6 @@
|
|||
cmake_minimum_required(VERSION 3.13)
|
||||
|
||||
target_sources(aster_core
|
||||
INTERFACE "logger.h" "intrusive_slist.h")
|
||||
INTERFACE
|
||||
"logger.h"
|
||||
"intrusive_slist.h")
|
||||
|
|
|
|||
|
|
@ -17,407 +17,407 @@ Image::Destroy()
|
|||
vmaDestroyImage(m_Device->m_Allocator, Take(m_Image), m_Allocation);
|
||||
m_Flags_ = 0;
|
||||
}
|
||||
|
||||
void
|
||||
Texture::Init(const Device *device, const vk::Extent2D extent, vk::Format imageFormat, const bool isMipMapped,
|
||||
const cstr name)
|
||||
{
|
||||
WARN_IF(!IsPowerOfTwo(extent.width) || !IsPowerOfTwo(extent.width), "Image {2} is {0}x{1} (Non Power of Two)",
|
||||
extent.width, extent.height, name ? name : "<unnamed>");
|
||||
|
||||
const u8 mipLevels = isMipMapped ? 1 + Cast<u8>(floor(log2(eastl::max(extent.width, extent.height)))) : 1;
|
||||
|
||||
auto usage = vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eTransferDst;
|
||||
if (isMipMapped)
|
||||
{
|
||||
usage |= vk::ImageUsageFlagBits::eTransferSrc;
|
||||
}
|
||||
|
||||
vk::ImageCreateInfo imageCreateInfo = {
|
||||
.imageType = vk::ImageType::e2D,
|
||||
.format = imageFormat,
|
||||
.extent = ToExtent3D(extent, 1),
|
||||
.mipLevels = mipLevels,
|
||||
.arrayLayers = 1,
|
||||
.samples = vk::SampleCountFlagBits::e1,
|
||||
.tiling = vk::ImageTiling::eOptimal,
|
||||
.usage = usage,
|
||||
.sharingMode = vk::SharingMode::eExclusive,
|
||||
.initialLayout = vk::ImageLayout::eUndefined,
|
||||
};
|
||||
constexpr VmaAllocationCreateInfo allocationCreateInfo = {
|
||||
.flags = {},
|
||||
.usage = VMA_MEMORY_USAGE_AUTO,
|
||||
};
|
||||
|
||||
VkImage image;
|
||||
VmaAllocation allocation;
|
||||
auto result = Cast<vk::Result>(vmaCreateImage(device->m_Allocator, Recast<VkImageCreateInfo *>(&imageCreateInfo),
|
||||
&allocationCreateInfo, &image, &allocation, nullptr));
|
||||
ERROR_IF(Failed(result), "Could not allocate image {}. Cause: {}", name, result) THEN_ABORT(result);
|
||||
|
||||
vk::ImageView view;
|
||||
vk::ImageViewCreateInfo imageViewCreateInfo = {
|
||||
.image = image,
|
||||
.viewType = vk::ImageViewType::e2D,
|
||||
.format = imageFormat,
|
||||
.components = {},
|
||||
.subresourceRange =
|
||||
{
|
||||
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||
.baseMipLevel = 0,
|
||||
.levelCount = mipLevels,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = 1,
|
||||
},
|
||||
};
|
||||
result = device->m_Device.createImageView(&imageViewCreateInfo, nullptr, &view);
|
||||
ERROR_IF(Failed(result), "Could not create image view {}. Cause: {}", name, result) THEN_ABORT(result);
|
||||
|
||||
m_Device = device;
|
||||
m_Image = image;
|
||||
m_View = view;
|
||||
m_Allocation = allocation;
|
||||
m_Extent = imageCreateInfo.extent;
|
||||
m_LayerCount = 1;
|
||||
m_MipLevels = mipLevels;
|
||||
|
||||
device->SetName(m_Image, name);
|
||||
}
|
||||
|
||||
/*
|
||||
Cube map Faces info.
|
||||
|
||||
TODO: Correct this based on the actual layout for upside down viewport.
|
||||
|
||||
| Axis | Layer | Up |
|
||||
|:----:|:-----:|:--:|
|
||||
| +x | 0 | -y |
|
||||
| -x | 1 | -y |
|
||||
| +y | 2 | +z |
|
||||
| -y | 3 | -z |
|
||||
| +z | 4 | -y |
|
||||
| -z | 5 | -y |
|
||||
|
||||
Remember, we use upside down viewport.
|
||||
|
||||
*/
|
||||
|
||||
void
|
||||
TextureCube::Init(const Device *device, u32 cubeSide, vk::Format imageFormat, bool isMipMapped, cstr name)
|
||||
{
|
||||
WARN_IF(!IsPowerOfTwo(cubeSide), "Image Cube {1} has side {0}x{0} (Non Power of Two)", cubeSide,
|
||||
name ? name : "<unnamed>");
|
||||
|
||||
const u8 mipLevels = isMipMapped ? 1 + Cast<u8>(floor(log2(cubeSide))) : 1;
|
||||
|
||||
auto usage = vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eTransferDst;
|
||||
if (isMipMapped)
|
||||
{
|
||||
usage |= vk::ImageUsageFlagBits::eTransferSrc;
|
||||
}
|
||||
|
||||
const vk::Extent3D extent = {.width = cubeSide, .height = cubeSide, .depth = 1};
|
||||
|
||||
vk::ImageCreateInfo imageCreateInfo = {
|
||||
.flags = vk::ImageCreateFlagBits::eCubeCompatible,
|
||||
.imageType = vk::ImageType::e2D,
|
||||
.format = imageFormat,
|
||||
.extent = extent,
|
||||
.mipLevels = mipLevels,
|
||||
.arrayLayers = 6,
|
||||
.samples = vk::SampleCountFlagBits::e1,
|
||||
.tiling = vk::ImageTiling::eOptimal,
|
||||
.usage = usage,
|
||||
.sharingMode = vk::SharingMode::eExclusive,
|
||||
.initialLayout = vk::ImageLayout::eUndefined,
|
||||
};
|
||||
constexpr VmaAllocationCreateInfo allocationCreateInfo = {
|
||||
.flags = {},
|
||||
.usage = VMA_MEMORY_USAGE_AUTO,
|
||||
};
|
||||
|
||||
VkImage image;
|
||||
VmaAllocation allocation;
|
||||
auto result = Cast<vk::Result>(vmaCreateImage(device->m_Allocator, Recast<VkImageCreateInfo *>(&imageCreateInfo),
|
||||
&allocationCreateInfo, &image, &allocation, nullptr));
|
||||
ERROR_IF(Failed(result), "Could not allocate image {}. Cause: {}", name, result) THEN_ABORT(result);
|
||||
|
||||
vk::ImageView view;
|
||||
vk::ImageViewCreateInfo imageViewCreateInfo = {
|
||||
.image = image,
|
||||
.viewType = vk::ImageViewType::eCube,
|
||||
.format = imageFormat,
|
||||
.components = {},
|
||||
.subresourceRange =
|
||||
{
|
||||
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||
.baseMipLevel = 0,
|
||||
.levelCount = mipLevels,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = 6,
|
||||
},
|
||||
};
|
||||
result = device->m_Device.createImageView(&imageViewCreateInfo, nullptr, &view);
|
||||
ERROR_IF(Failed(result), "Could not create image view {}. Cause: {}", name, result) THEN_ABORT(result);
|
||||
|
||||
m_Device = device;
|
||||
m_Image = image;
|
||||
m_View = view;
|
||||
m_Allocation = allocation;
|
||||
m_Extent = extent;
|
||||
m_MipLevels = mipLevels;
|
||||
m_LayerCount = 6;
|
||||
|
||||
device->SetName(m_Image, name);
|
||||
}
|
||||
|
||||
void
|
||||
AttachmentImage::Init(const Device *device, vk::Extent2D extent, vk::Format imageFormat, cstr name)
|
||||
{
|
||||
vk::ImageCreateInfo imageCreateInfo = {
|
||||
.imageType = vk::ImageType::e2D,
|
||||
.format = imageFormat,
|
||||
.extent = ToExtent3D(extent, 1),
|
||||
.mipLevels = 1,
|
||||
.arrayLayers = 1,
|
||||
.samples = vk::SampleCountFlagBits::e1,
|
||||
.tiling = vk::ImageTiling::eOptimal,
|
||||
.usage = vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eTransferSrc,
|
||||
.sharingMode = vk::SharingMode::eExclusive,
|
||||
.initialLayout = vk::ImageLayout::eUndefined,
|
||||
};
|
||||
constexpr VmaAllocationCreateInfo allocationCreateInfo = {
|
||||
.flags = VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT,
|
||||
.usage = VMA_MEMORY_USAGE_AUTO,
|
||||
};
|
||||
|
||||
VkImage image;
|
||||
VmaAllocation allocation;
|
||||
auto result = Cast<vk::Result>(vmaCreateImage(device->m_Allocator, Recast<VkImageCreateInfo *>(&imageCreateInfo),
|
||||
&allocationCreateInfo, &image, &allocation, nullptr));
|
||||
ERROR_IF(Failed(result), "Could not allocate depth buffer. Cause: {}", result) THEN_ABORT(result);
|
||||
|
||||
vk::ImageView view;
|
||||
vk::ImageViewCreateInfo imageViewCreateInfo = {
|
||||
.image = image,
|
||||
.viewType = vk::ImageViewType::e2D,
|
||||
.format = imageFormat,
|
||||
.components = {},
|
||||
.subresourceRange =
|
||||
{
|
||||
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||
.baseMipLevel = 0,
|
||||
.levelCount = 1,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = 1,
|
||||
},
|
||||
};
|
||||
result = device->m_Device.createImageView(&imageViewCreateInfo, nullptr, &view);
|
||||
ERROR_IF(Failed(result), "Could not create attachment image view {}. Cause: {}", name, result) THEN_ABORT(result);
|
||||
|
||||
m_Device = device;
|
||||
m_Image = image;
|
||||
m_View = view;
|
||||
m_Allocation = allocation;
|
||||
m_Extent = imageCreateInfo.extent;
|
||||
m_MipLevels = 1;
|
||||
m_LayerCount = 1;
|
||||
|
||||
device->SetName(m_Image, name);
|
||||
}
|
||||
|
||||
void
|
||||
DepthImage::Init(const Device *device, vk::Extent2D extent, cstr name)
|
||||
{
|
||||
constexpr vk::Format imageFormat = vk::Format::eD24UnormS8Uint;
|
||||
vk::ImageCreateInfo imageCreateInfo = {
|
||||
.imageType = vk::ImageType::e2D,
|
||||
.format = imageFormat,
|
||||
.extent = ToExtent3D(extent, 1),
|
||||
.mipLevels = 1,
|
||||
.arrayLayers = 1,
|
||||
.samples = vk::SampleCountFlagBits::e1,
|
||||
.tiling = vk::ImageTiling::eOptimal,
|
||||
.usage = vk::ImageUsageFlagBits::eDepthStencilAttachment,
|
||||
.sharingMode = vk::SharingMode::eExclusive,
|
||||
.initialLayout = vk::ImageLayout::eUndefined,
|
||||
};
|
||||
constexpr VmaAllocationCreateInfo allocationCreateInfo = {
|
||||
.flags = VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT,
|
||||
.usage = VMA_MEMORY_USAGE_AUTO,
|
||||
};
|
||||
|
||||
VkImage image;
|
||||
VmaAllocation allocation;
|
||||
auto result = Cast<vk::Result>(vmaCreateImage(device->m_Allocator, Recast<VkImageCreateInfo *>(&imageCreateInfo),
|
||||
&allocationCreateInfo, &image, &allocation, nullptr));
|
||||
ERROR_IF(Failed(result), "Could not allocate depth buffer. Cause: {}", result) THEN_ABORT(result);
|
||||
|
||||
vk::ImageView view;
|
||||
vk::ImageViewCreateInfo imageViewCreateInfo = {
|
||||
.image = image,
|
||||
.viewType = vk::ImageViewType::e2D,
|
||||
.format = imageFormat,
|
||||
.components = {},
|
||||
.subresourceRange =
|
||||
{
|
||||
.aspectMask = vk::ImageAspectFlagBits::eDepth,
|
||||
.baseMipLevel = 0,
|
||||
.levelCount = 1,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = 1,
|
||||
},
|
||||
};
|
||||
result = device->m_Device.createImageView(&imageViewCreateInfo, nullptr, &view);
|
||||
ERROR_IF(Failed(result), "Could not create depth image view {}. Cause: {}", name, result) THEN_ABORT(result);
|
||||
|
||||
m_Device = device;
|
||||
m_Image = image;
|
||||
m_View = view;
|
||||
m_Allocation = allocation;
|
||||
m_Extent = imageCreateInfo.extent;
|
||||
m_MipLevels = 1;
|
||||
m_LayerCount = 1;
|
||||
|
||||
device->SetName(m_Image, name);
|
||||
}
|
||||
|
||||
void
|
||||
StorageTexture::Init(const Device *device, vk::Extent2D extent, const vk::Format imageFormat, const bool isSampled,
|
||||
cstr name)
|
||||
{
|
||||
// Reasoning:
|
||||
// Transfer Src and Dst to copy to and from the buffer since Storage will often be loaded with info, and read for
|
||||
// results.
|
||||
auto usage =
|
||||
vk::ImageUsageFlagBits::eStorage | vk::ImageUsageFlagBits::eTransferSrc | vk::ImageUsageFlagBits::eTransferDst;
|
||||
if (isSampled)
|
||||
{
|
||||
WARN_IF(!IsPowerOfTwo(extent.width) || !IsPowerOfTwo(extent.width), "Image {2} is {0}x{1} (Non Power of Two)",
|
||||
extent.width, extent.height, name ? name : "<unnamed>");
|
||||
usage |= vk::ImageUsageFlagBits::eSampled;
|
||||
}
|
||||
|
||||
vk::ImageCreateInfo imageCreateInfo = {
|
||||
.imageType = vk::ImageType::e2D,
|
||||
.format = imageFormat,
|
||||
.extent = ToExtent3D(extent, 1),
|
||||
.mipLevels = 1,
|
||||
.arrayLayers = 1,
|
||||
.samples = vk::SampleCountFlagBits::e1,
|
||||
.tiling = vk::ImageTiling::eOptimal,
|
||||
.usage = usage,
|
||||
.sharingMode = vk::SharingMode::eExclusive,
|
||||
.initialLayout = vk::ImageLayout::eUndefined,
|
||||
};
|
||||
constexpr VmaAllocationCreateInfo allocationCreateInfo = {
|
||||
.flags = {},
|
||||
.usage = VMA_MEMORY_USAGE_AUTO,
|
||||
};
|
||||
|
||||
VkImage image;
|
||||
VmaAllocation allocation;
|
||||
auto result = Cast<vk::Result>(vmaCreateImage(device->m_Allocator, Recast<VkImageCreateInfo *>(&imageCreateInfo),
|
||||
&allocationCreateInfo, &image, &allocation, nullptr));
|
||||
ERROR_IF(Failed(result), "Could not allocate image {}. Cause: {}", name, result) THEN_ABORT(result);
|
||||
|
||||
vk::ImageView view;
|
||||
const vk::ImageViewCreateInfo imageViewCreateInfo = {
|
||||
.image = image,
|
||||
.viewType = vk::ImageViewType::e2D,
|
||||
.format = imageFormat,
|
||||
.components = {},
|
||||
.subresourceRange =
|
||||
{
|
||||
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||
.baseMipLevel = 0,
|
||||
.levelCount = 1,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = 1,
|
||||
},
|
||||
};
|
||||
result = device->m_Device.createImageView(&imageViewCreateInfo, nullptr, &view);
|
||||
ERROR_IF(Failed(result), "Could not create image view {}. Cause: {}", name, result) THEN_ABORT(result);
|
||||
|
||||
m_Device = device;
|
||||
m_Image = image;
|
||||
m_View = view;
|
||||
m_Allocation = allocation;
|
||||
m_Extent = imageCreateInfo.extent;
|
||||
m_MipLevels = 1;
|
||||
m_LayerCount = 1;
|
||||
|
||||
device->SetName(m_Image, name);
|
||||
}
|
||||
|
||||
void
|
||||
StorageTextureCube::Init(const Device *device, u32 cubeSide, vk::Format imageFormat, bool isSampled, bool isMipMapped,
|
||||
cstr name)
|
||||
{
|
||||
// Reasoning:
|
||||
// Transfer Src and Dst to copy to and from the buffer since Storage will often be loaded with info, and read for
|
||||
// results.
|
||||
auto usage =
|
||||
vk::ImageUsageFlagBits::eStorage | vk::ImageUsageFlagBits::eTransferSrc | vk::ImageUsageFlagBits::eTransferDst;
|
||||
if (isSampled)
|
||||
{
|
||||
WARN_IF(!IsPowerOfTwo(cubeSide), "Image {1} is {0}x{0} (Non Power of Two)", cubeSide,
|
||||
name ? name : "<unnamed>");
|
||||
usage |= vk::ImageUsageFlagBits::eSampled;
|
||||
}
|
||||
|
||||
const u8 mipLevels = isMipMapped ? 1 + Cast<u8>(floor(log2(cubeSide))) : 1;
|
||||
|
||||
vk::ImageCreateInfo imageCreateInfo = {
|
||||
.flags = vk::ImageCreateFlagBits::eCubeCompatible,
|
||||
.imageType = vk::ImageType::e2D,
|
||||
.format = imageFormat,
|
||||
.extent = {cubeSide, cubeSide, 1},
|
||||
.mipLevels = mipLevels,
|
||||
.arrayLayers = 6,
|
||||
.samples = vk::SampleCountFlagBits::e1,
|
||||
.tiling = vk::ImageTiling::eOptimal,
|
||||
.usage = usage,
|
||||
.sharingMode = vk::SharingMode::eExclusive,
|
||||
.initialLayout = vk::ImageLayout::eUndefined,
|
||||
};
|
||||
constexpr VmaAllocationCreateInfo allocationCreateInfo = {
|
||||
.flags = {},
|
||||
.usage = VMA_MEMORY_USAGE_AUTO,
|
||||
};
|
||||
|
||||
VkImage image;
|
||||
VmaAllocation allocation;
|
||||
auto result = Cast<vk::Result>(vmaCreateImage(device->m_Allocator, Recast<VkImageCreateInfo *>(&imageCreateInfo),
|
||||
&allocationCreateInfo, &image, &allocation, nullptr));
|
||||
ERROR_IF(Failed(result), "Could not allocate image {}. Cause: {}", name, result) THEN_ABORT(result);
|
||||
|
||||
vk::ImageView view;
|
||||
const vk::ImageViewCreateInfo imageViewCreateInfo = {
|
||||
.image = image,
|
||||
.viewType = vk::ImageViewType::eCube,
|
||||
.format = imageFormat,
|
||||
.components = {},
|
||||
.subresourceRange =
|
||||
{
|
||||
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||
.baseMipLevel = 0,
|
||||
.levelCount = mipLevels,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = 6,
|
||||
},
|
||||
};
|
||||
result = device->m_Device.createImageView(&imageViewCreateInfo, nullptr, &view);
|
||||
ERROR_IF(Failed(result), "Could not create image view {}. Cause: {}", name, result) THEN_ABORT(result);
|
||||
|
||||
m_Device = device;
|
||||
m_Image = image;
|
||||
m_View = view;
|
||||
m_Allocation = allocation;
|
||||
m_Extent = imageCreateInfo.extent;
|
||||
m_MipLevels = mipLevels;
|
||||
m_LayerCount = 6;
|
||||
|
||||
device->SetName(m_Image, name);
|
||||
}
|
||||
//
|
||||
//void
|
||||
//Texture::Init(const Device *device, const vk::Extent2D extent, vk::Format imageFormat, const bool isMipMapped,
|
||||
// const cstr name)
|
||||
//{
|
||||
// WARN_IF(!IsPowerOfTwo(extent.width) || !IsPowerOfTwo(extent.width), "Image {2} is {0}x{1} (Non Power of Two)",
|
||||
// extent.width, extent.height, name ? name : "<unnamed>");
|
||||
//
|
||||
// const u8 mipLevels = isMipMapped ? 1 + Cast<u8>(floor(log2(eastl::max(extent.width, extent.height)))) : 1;
|
||||
//
|
||||
// auto usage = vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eTransferDst;
|
||||
// if (isMipMapped)
|
||||
// {
|
||||
// usage |= vk::ImageUsageFlagBits::eTransferSrc;
|
||||
// }
|
||||
//
|
||||
// vk::ImageCreateInfo imageCreateInfo = {
|
||||
// .imageType = vk::ImageType::e2D,
|
||||
// .format = imageFormat,
|
||||
// .extent = ToExtent3D(extent, 1),
|
||||
// .mipLevels = mipLevels,
|
||||
// .arrayLayers = 1,
|
||||
// .samples = vk::SampleCountFlagBits::e1,
|
||||
// .tiling = vk::ImageTiling::eOptimal,
|
||||
// .usage = usage,
|
||||
// .sharingMode = vk::SharingMode::eExclusive,
|
||||
// .initialLayout = vk::ImageLayout::eUndefined,
|
||||
// };
|
||||
// constexpr VmaAllocationCreateInfo allocationCreateInfo = {
|
||||
// .flags = {},
|
||||
// .usage = VMA_MEMORY_USAGE_AUTO,
|
||||
// };
|
||||
//
|
||||
// VkImage image;
|
||||
// VmaAllocation allocation;
|
||||
// auto result = Cast<vk::Result>(vmaCreateImage(device->m_Allocator, Recast<VkImageCreateInfo *>(&imageCreateInfo),
|
||||
// &allocationCreateInfo, &image, &allocation, nullptr));
|
||||
// ERROR_IF(Failed(result), "Could not allocate image {}. Cause: {}", name, result) THEN_ABORT(result);
|
||||
//
|
||||
// vk::ImageView view;
|
||||
// vk::ImageViewCreateInfo imageViewCreateInfo = {
|
||||
// .image = image,
|
||||
// .viewType = vk::ImageViewType::e2D,
|
||||
// .format = imageFormat,
|
||||
// .components = {},
|
||||
// .subresourceRange =
|
||||
// {
|
||||
// .aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||
// .baseMipLevel = 0,
|
||||
// .levelCount = mipLevels,
|
||||
// .baseArrayLayer = 0,
|
||||
// .layerCount = 1,
|
||||
// },
|
||||
// };
|
||||
// result = device->m_Device.createImageView(&imageViewCreateInfo, nullptr, &view);
|
||||
// ERROR_IF(Failed(result), "Could not create image view {}. Cause: {}", name, result) THEN_ABORT(result);
|
||||
//
|
||||
// m_Device = device;
|
||||
// m_Image = image;
|
||||
// m_View = view;
|
||||
// m_Allocation = allocation;
|
||||
// m_Extent = imageCreateInfo.extent;
|
||||
// m_LayerCount = 1;
|
||||
// m_MipLevels = mipLevels;
|
||||
//
|
||||
// device->SetName(m_Image, name);
|
||||
//}
|
||||
//
|
||||
///*
|
||||
//Cube map Faces info.
|
||||
//
|
||||
//TODO: Correct this based on the actual layout for upside down viewport.
|
||||
//
|
||||
//| Axis | Layer | Up |
|
||||
//|:----:|:-----:|:--:|
|
||||
//| +x | 0 | -y |
|
||||
//| -x | 1 | -y |
|
||||
//| +y | 2 | +z |
|
||||
//| -y | 3 | -z |
|
||||
//| +z | 4 | -y |
|
||||
//| -z | 5 | -y |
|
||||
//
|
||||
//Remember, we use upside down viewport.
|
||||
//
|
||||
//*/
|
||||
//
|
||||
//void
|
||||
//TextureCube::Init(const Device *device, u32 cubeSide, vk::Format imageFormat, bool isMipMapped, cstr name)
|
||||
//{
|
||||
// WARN_IF(!IsPowerOfTwo(cubeSide), "Image Cube {1} has side {0}x{0} (Non Power of Two)", cubeSide,
|
||||
// name ? name : "<unnamed>");
|
||||
//
|
||||
// const u8 mipLevels = isMipMapped ? 1 + Cast<u8>(floor(log2(cubeSide))) : 1;
|
||||
//
|
||||
// auto usage = vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eTransferDst;
|
||||
// if (isMipMapped)
|
||||
// {
|
||||
// usage |= vk::ImageUsageFlagBits::eTransferSrc;
|
||||
// }
|
||||
//
|
||||
// const vk::Extent3D extent = {.width = cubeSide, .height = cubeSide, .depth = 1};
|
||||
//
|
||||
// vk::ImageCreateInfo imageCreateInfo = {
|
||||
// .flags = vk::ImageCreateFlagBits::eCubeCompatible,
|
||||
// .imageType = vk::ImageType::e2D,
|
||||
// .format = imageFormat,
|
||||
// .extent = extent,
|
||||
// .mipLevels = mipLevels,
|
||||
// .arrayLayers = 6,
|
||||
// .samples = vk::SampleCountFlagBits::e1,
|
||||
// .tiling = vk::ImageTiling::eOptimal,
|
||||
// .usage = usage,
|
||||
// .sharingMode = vk::SharingMode::eExclusive,
|
||||
// .initialLayout = vk::ImageLayout::eUndefined,
|
||||
// };
|
||||
// constexpr VmaAllocationCreateInfo allocationCreateInfo = {
|
||||
// .flags = {},
|
||||
// .usage = VMA_MEMORY_USAGE_AUTO,
|
||||
// };
|
||||
//
|
||||
// VkImage image;
|
||||
// VmaAllocation allocation;
|
||||
// auto result = Cast<vk::Result>(vmaCreateImage(device->m_Allocator, Recast<VkImageCreateInfo *>(&imageCreateInfo),
|
||||
// &allocationCreateInfo, &image, &allocation, nullptr));
|
||||
// ERROR_IF(Failed(result), "Could not allocate image {}. Cause: {}", name, result) THEN_ABORT(result);
|
||||
//
|
||||
// vk::ImageView view;
|
||||
// vk::ImageViewCreateInfo imageViewCreateInfo = {
|
||||
// .image = image,
|
||||
// .viewType = vk::ImageViewType::eCube,
|
||||
// .format = imageFormat,
|
||||
// .components = {},
|
||||
// .subresourceRange =
|
||||
// {
|
||||
// .aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||
// .baseMipLevel = 0,
|
||||
// .levelCount = mipLevels,
|
||||
// .baseArrayLayer = 0,
|
||||
// .layerCount = 6,
|
||||
// },
|
||||
// };
|
||||
// result = device->m_Device.createImageView(&imageViewCreateInfo, nullptr, &view);
|
||||
// ERROR_IF(Failed(result), "Could not create image view {}. Cause: {}", name, result) THEN_ABORT(result);
|
||||
//
|
||||
// m_Device = device;
|
||||
// m_Image = image;
|
||||
// m_View = view;
|
||||
// m_Allocation = allocation;
|
||||
// m_Extent = extent;
|
||||
// m_MipLevels = mipLevels;
|
||||
// m_LayerCount = 6;
|
||||
//
|
||||
// device->SetName(m_Image, name);
|
||||
//}
|
||||
//
|
||||
//void
|
||||
//AttachmentImage::Init(const Device *device, vk::Extent2D extent, vk::Format imageFormat, cstr name)
|
||||
//{
|
||||
// vk::ImageCreateInfo imageCreateInfo = {
|
||||
// .imageType = vk::ImageType::e2D,
|
||||
// .format = imageFormat,
|
||||
// .extent = ToExtent3D(extent, 1),
|
||||
// .mipLevels = 1,
|
||||
// .arrayLayers = 1,
|
||||
// .samples = vk::SampleCountFlagBits::e1,
|
||||
// .tiling = vk::ImageTiling::eOptimal,
|
||||
// .usage = vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eTransferSrc,
|
||||
// .sharingMode = vk::SharingMode::eExclusive,
|
||||
// .initialLayout = vk::ImageLayout::eUndefined,
|
||||
// };
|
||||
// constexpr VmaAllocationCreateInfo allocationCreateInfo = {
|
||||
// .flags = VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT,
|
||||
// .usage = VMA_MEMORY_USAGE_AUTO,
|
||||
// };
|
||||
//
|
||||
// VkImage image;
|
||||
// VmaAllocation allocation;
|
||||
// auto result = Cast<vk::Result>(vmaCreateImage(device->m_Allocator, Recast<VkImageCreateInfo *>(&imageCreateInfo),
|
||||
// &allocationCreateInfo, &image, &allocation, nullptr));
|
||||
// ERROR_IF(Failed(result), "Could not allocate depth buffer. Cause: {}", result) THEN_ABORT(result);
|
||||
//
|
||||
// vk::ImageView view;
|
||||
// vk::ImageViewCreateInfo imageViewCreateInfo = {
|
||||
// .image = image,
|
||||
// .viewType = vk::ImageViewType::e2D,
|
||||
// .format = imageFormat,
|
||||
// .components = {},
|
||||
// .subresourceRange =
|
||||
// {
|
||||
// .aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||
// .baseMipLevel = 0,
|
||||
// .levelCount = 1,
|
||||
// .baseArrayLayer = 0,
|
||||
// .layerCount = 1,
|
||||
// },
|
||||
// };
|
||||
// result = device->m_Device.createImageView(&imageViewCreateInfo, nullptr, &view);
|
||||
// ERROR_IF(Failed(result), "Could not create attachment image view {}. Cause: {}", name, result) THEN_ABORT(result);
|
||||
//
|
||||
// m_Device = device;
|
||||
// m_Image = image;
|
||||
// m_View = view;
|
||||
// m_Allocation = allocation;
|
||||
// m_Extent = imageCreateInfo.extent;
|
||||
// m_MipLevels = 1;
|
||||
// m_LayerCount = 1;
|
||||
//
|
||||
// device->SetName(m_Image, name);
|
||||
//}
|
||||
//
|
||||
//void
|
||||
//DepthImage::Init(const Device *device, vk::Extent2D extent, cstr name)
|
||||
//{
|
||||
// constexpr vk::Format imageFormat = vk::Format::eD24UnormS8Uint;
|
||||
// vk::ImageCreateInfo imageCreateInfo = {
|
||||
// .imageType = vk::ImageType::e2D,
|
||||
// .format = imageFormat,
|
||||
// .extent = ToExtent3D(extent, 1),
|
||||
// .mipLevels = 1,
|
||||
// .arrayLayers = 1,
|
||||
// .samples = vk::SampleCountFlagBits::e1,
|
||||
// .tiling = vk::ImageTiling::eOptimal,
|
||||
// .usage = vk::ImageUsageFlagBits::eDepthStencilAttachment,
|
||||
// .sharingMode = vk::SharingMode::eExclusive,
|
||||
// .initialLayout = vk::ImageLayout::eUndefined,
|
||||
// };
|
||||
// constexpr VmaAllocationCreateInfo allocationCreateInfo = {
|
||||
// .flags = VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT,
|
||||
// .usage = VMA_MEMORY_USAGE_AUTO,
|
||||
// };
|
||||
//
|
||||
// VkImage image;
|
||||
// VmaAllocation allocation;
|
||||
// auto result = Cast<vk::Result>(vmaCreateImage(device->m_Allocator, Recast<VkImageCreateInfo *>(&imageCreateInfo),
|
||||
// &allocationCreateInfo, &image, &allocation, nullptr));
|
||||
// ERROR_IF(Failed(result), "Could not allocate depth buffer. Cause: {}", result) THEN_ABORT(result);
|
||||
//
|
||||
// vk::ImageView view;
|
||||
// vk::ImageViewCreateInfo imageViewCreateInfo = {
|
||||
// .image = image,
|
||||
// .viewType = vk::ImageViewType::e2D,
|
||||
// .format = imageFormat,
|
||||
// .components = {},
|
||||
// .subresourceRange =
|
||||
// {
|
||||
// .aspectMask = vk::ImageAspectFlagBits::eDepth,
|
||||
// .baseMipLevel = 0,
|
||||
// .levelCount = 1,
|
||||
// .baseArrayLayer = 0,
|
||||
// .layerCount = 1,
|
||||
// },
|
||||
// };
|
||||
// result = device->m_Device.createImageView(&imageViewCreateInfo, nullptr, &view);
|
||||
// ERROR_IF(Failed(result), "Could not create depth image view {}. Cause: {}", name, result) THEN_ABORT(result);
|
||||
//
|
||||
// m_Device = device;
|
||||
// m_Image = image;
|
||||
// m_View = view;
|
||||
// m_Allocation = allocation;
|
||||
// m_Extent = imageCreateInfo.extent;
|
||||
// m_MipLevels = 1;
|
||||
// m_LayerCount = 1;
|
||||
//
|
||||
// device->SetName(m_Image, name);
|
||||
//}
|
||||
//
|
||||
//void
|
||||
//StorageTexture::Init(const Device *device, vk::Extent2D extent, const vk::Format imageFormat, const bool isSampled,
|
||||
// cstr name)
|
||||
//{
|
||||
// // Reasoning:
|
||||
// // Transfer Src and Dst to copy to and from the buffer since Storage will often be loaded with info, and read for
|
||||
// // results.
|
||||
// auto usage =
|
||||
// vk::ImageUsageFlagBits::eStorage | vk::ImageUsageFlagBits::eTransferSrc | vk::ImageUsageFlagBits::eTransferDst;
|
||||
// if (isSampled)
|
||||
// {
|
||||
// WARN_IF(!IsPowerOfTwo(extent.width) || !IsPowerOfTwo(extent.width), "Image {2} is {0}x{1} (Non Power of Two)",
|
||||
// extent.width, extent.height, name ? name : "<unnamed>");
|
||||
// usage |= vk::ImageUsageFlagBits::eSampled;
|
||||
// }
|
||||
//
|
||||
// vk::ImageCreateInfo imageCreateInfo = {
|
||||
// .imageType = vk::ImageType::e2D,
|
||||
// .format = imageFormat,
|
||||
// .extent = ToExtent3D(extent, 1),
|
||||
// .mipLevels = 1,
|
||||
// .arrayLayers = 1,
|
||||
// .samples = vk::SampleCountFlagBits::e1,
|
||||
// .tiling = vk::ImageTiling::eOptimal,
|
||||
// .usage = usage,
|
||||
// .sharingMode = vk::SharingMode::eExclusive,
|
||||
// .initialLayout = vk::ImageLayout::eUndefined,
|
||||
// };
|
||||
// constexpr VmaAllocationCreateInfo allocationCreateInfo = {
|
||||
// .flags = {},
|
||||
// .usage = VMA_MEMORY_USAGE_AUTO,
|
||||
// };
|
||||
//
|
||||
// VkImage image;
|
||||
// VmaAllocation allocation;
|
||||
// auto result = Cast<vk::Result>(vmaCreateImage(device->m_Allocator, Recast<VkImageCreateInfo *>(&imageCreateInfo),
|
||||
// &allocationCreateInfo, &image, &allocation, nullptr));
|
||||
// ERROR_IF(Failed(result), "Could not allocate image {}. Cause: {}", name, result) THEN_ABORT(result);
|
||||
//
|
||||
// vk::ImageView view;
|
||||
// const vk::ImageViewCreateInfo imageViewCreateInfo = {
|
||||
// .image = image,
|
||||
// .viewType = vk::ImageViewType::e2D,
|
||||
// .format = imageFormat,
|
||||
// .components = {},
|
||||
// .subresourceRange =
|
||||
// {
|
||||
// .aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||
// .baseMipLevel = 0,
|
||||
// .levelCount = 1,
|
||||
// .baseArrayLayer = 0,
|
||||
// .layerCount = 1,
|
||||
// },
|
||||
// };
|
||||
// result = device->m_Device.createImageView(&imageViewCreateInfo, nullptr, &view);
|
||||
// ERROR_IF(Failed(result), "Could not create image view {}. Cause: {}", name, result) THEN_ABORT(result);
|
||||
//
|
||||
// m_Device = device;
|
||||
// m_Image = image;
|
||||
// m_View = view;
|
||||
// m_Allocation = allocation;
|
||||
// m_Extent = imageCreateInfo.extent;
|
||||
// m_MipLevels = 1;
|
||||
// m_LayerCount = 1;
|
||||
//
|
||||
// device->SetName(m_Image, name);
|
||||
//}
|
||||
//
|
||||
//void
|
||||
//StorageTextureCube::Init(const Device *device, u32 cubeSide, vk::Format imageFormat, bool isSampled, bool isMipMapped,
|
||||
// cstr name)
|
||||
//{
|
||||
// // Reasoning:
|
||||
// // Transfer Src and Dst to copy to and from the buffer since Storage will often be loaded with info, and read for
|
||||
// // results.
|
||||
// auto usage =
|
||||
// vk::ImageUsageFlagBits::eStorage | vk::ImageUsageFlagBits::eTransferSrc | vk::ImageUsageFlagBits::eTransferDst;
|
||||
// if (isSampled)
|
||||
// {
|
||||
// WARN_IF(!IsPowerOfTwo(cubeSide), "Image {1} is {0}x{0} (Non Power of Two)", cubeSide,
|
||||
// name ? name : "<unnamed>");
|
||||
// usage |= vk::ImageUsageFlagBits::eSampled;
|
||||
// }
|
||||
//
|
||||
// const u8 mipLevels = isMipMapped ? 1 + Cast<u8>(floor(log2(cubeSide))) : 1;
|
||||
//
|
||||
// vk::ImageCreateInfo imageCreateInfo = {
|
||||
// .flags = vk::ImageCreateFlagBits::eCubeCompatible,
|
||||
// .imageType = vk::ImageType::e2D,
|
||||
// .format = imageFormat,
|
||||
// .extent = {cubeSide, cubeSide, 1},
|
||||
// .mipLevels = mipLevels,
|
||||
// .arrayLayers = 6,
|
||||
// .samples = vk::SampleCountFlagBits::e1,
|
||||
// .tiling = vk::ImageTiling::eOptimal,
|
||||
// .usage = usage,
|
||||
// .sharingMode = vk::SharingMode::eExclusive,
|
||||
// .initialLayout = vk::ImageLayout::eUndefined,
|
||||
// };
|
||||
// constexpr VmaAllocationCreateInfo allocationCreateInfo = {
|
||||
// .flags = {},
|
||||
// .usage = VMA_MEMORY_USAGE_AUTO,
|
||||
// };
|
||||
//
|
||||
// VkImage image;
|
||||
// VmaAllocation allocation;
|
||||
// auto result = Cast<vk::Result>(vmaCreateImage(device->m_Allocator, Recast<VkImageCreateInfo *>(&imageCreateInfo),
|
||||
// &allocationCreateInfo, &image, &allocation, nullptr));
|
||||
// ERROR_IF(Failed(result), "Could not allocate image {}. Cause: {}", name, result) THEN_ABORT(result);
|
||||
//
|
||||
// vk::ImageView view;
|
||||
// const vk::ImageViewCreateInfo imageViewCreateInfo = {
|
||||
// .image = image,
|
||||
// .viewType = vk::ImageViewType::eCube,
|
||||
// .format = imageFormat,
|
||||
// .components = {},
|
||||
// .subresourceRange =
|
||||
// {
|
||||
// .aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||
// .baseMipLevel = 0,
|
||||
// .levelCount = mipLevels,
|
||||
// .baseArrayLayer = 0,
|
||||
// .layerCount = 6,
|
||||
// },
|
||||
// };
|
||||
// result = device->m_Device.createImageView(&imageViewCreateInfo, nullptr, &view);
|
||||
// ERROR_IF(Failed(result), "Could not create image view {}. Cause: {}", name, result) THEN_ABORT(result);
|
||||
//
|
||||
// m_Device = device;
|
||||
// m_Image = image;
|
||||
// m_View = view;
|
||||
// m_Allocation = allocation;
|
||||
// m_Extent = imageCreateInfo.extent;
|
||||
// m_MipLevels = mipLevels;
|
||||
// m_LayerCount = 6;
|
||||
//
|
||||
// device->SetName(m_Image, name);
|
||||
//}
|
||||
|
|
|
|||
|
|
@ -8,4 +8,4 @@ PRIVATE
|
|||
"buffer_manager.cpp"
|
||||
"image_manager.cpp"
|
||||
"sampler_manager.cpp"
|
||||
"render_resource_manager.cpp")
|
||||
"commit_manager.cpp")
|
||||
|
|
|
|||
|
|
@ -7,17 +7,16 @@
|
|||
|
||||
using namespace systems;
|
||||
|
||||
Manager<Buffer> *Manager<Buffer>::m_Instance = nullptr;
|
||||
|
||||
BufferHandle
|
||||
Ref<Buffer>
|
||||
BufferManager::CreateStorageBuffer(const usize size, const cstr name)
|
||||
{
|
||||
auto object = Alloc();
|
||||
|
||||
// TODO: Storage and Index buffer are set.
|
||||
// This is hacky and should be improved.
|
||||
constexpr vk::BufferUsageFlags usage = vk::BufferUsageFlagBits::eStorageBuffer | vk::BufferUsageFlagBits::eIndexBuffer |
|
||||
vk::BufferUsageFlagBits::eShaderDeviceAddress;
|
||||
constexpr vk::BufferUsageFlags usage = vk::BufferUsageFlagBits::eStorageBuffer |
|
||||
vk::BufferUsageFlagBits::eIndexBuffer |
|
||||
vk::BufferUsageFlagBits::eShaderDeviceAddress;
|
||||
constexpr VmaAllocationCreateFlags createFlags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT |
|
||||
VMA_ALLOCATION_CREATE_HOST_ACCESS_ALLOW_TRANSFER_INSTEAD_BIT |
|
||||
VMA_ALLOCATION_CREATE_MAPPED_BIT;
|
||||
|
|
@ -27,7 +26,7 @@ BufferManager::CreateStorageBuffer(const usize size, const cstr name)
|
|||
return object;
|
||||
}
|
||||
|
||||
Manager<Buffer>::Handle
|
||||
Ref<Buffer>
|
||||
BufferManager::CreateUniformBuffer(const usize size, const cstr name)
|
||||
{
|
||||
auto object = Alloc();
|
||||
|
|
@ -42,7 +41,21 @@ BufferManager::CreateUniformBuffer(const usize size, const cstr name)
|
|||
return object;
|
||||
}
|
||||
|
||||
BufferManager::BufferManager(const Device *device, const u32 maxCount, const u8 binding)
|
||||
: Manager{device, maxCount, binding}
|
||||
Manager<Buffer>::Handle
|
||||
BufferManager::CreateStagingBuffer(const usize size, const cstr name)
|
||||
{
|
||||
auto object = Alloc();
|
||||
|
||||
constexpr vk::BufferUsageFlags usage = vk::BufferUsageFlagBits::eTransferSrc;
|
||||
constexpr VmaAllocationCreateFlags createFlags =
|
||||
VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT;
|
||||
constexpr VmaMemoryUsage memoryUsage = VMA_MEMORY_USAGE_AUTO;
|
||||
object->Allocate(m_Device, size, usage, createFlags, memoryUsage, name);
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
BufferManager::BufferManager(const Device *device, const u32 maxCount)
|
||||
: Manager{device, maxCount}
|
||||
{
|
||||
}
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
// Copyright (c) 2020-2025 Anish Bhobe
|
||||
// =============================================
|
||||
|
||||
#include "systems/render_resource_manager.h"
|
||||
#include "systems/commit_manager.h"
|
||||
|
||||
#include "EASTL/array.h"
|
||||
#include "core/device.h"
|
||||
|
|
@ -33,14 +33,15 @@
|
|||
|
||||
using namespace systems;
|
||||
|
||||
RenderResourceManager *RenderResourceManager::m_Instance = nullptr;
|
||||
CommitManager *CommitManager::m_Instance = nullptr;
|
||||
|
||||
RenderResourceManager::RenderResourceManager(const Device *device, u32 const maxBuffers, const u32 maxImages,
|
||||
const SamplerHandle &defaultSampler)
|
||||
CommitManager::CommitManager(const Device *device, u32 const maxBuffers, const u32 maxImages, const u32 maxStorageImages,
|
||||
Ref<Sampler> defaultSampler)
|
||||
: m_Device{device}
|
||||
, m_Buffers{maxBuffers}
|
||||
, m_Images{maxImages}
|
||||
, m_DefaultSampler{defaultSampler}
|
||||
, m_StorageImages{maxStorageImages}
|
||||
, m_DefaultSampler{std::move(defaultSampler)}
|
||||
{
|
||||
assert(!m_Instance);
|
||||
|
||||
|
|
@ -80,12 +81,12 @@ RenderResourceManager::RenderResourceManager(const Device *device, u32 const max
|
|||
.descriptorCount = Cast<u32>(maxImages),
|
||||
.stageFlags = vk::ShaderStageFlagBits::eAll,
|
||||
},
|
||||
// vk::DescriptorSetLayoutBinding{
|
||||
// .binding = STORAGE_TEXTURE_BINDING_INDEX,
|
||||
// .descriptorType = vk::DescriptorType::eStorageImage,
|
||||
// .descriptorCount = Cast<u32>(storageTexturesCount),
|
||||
// .stageFlags = vk::ShaderStageFlagBits::eAll,
|
||||
// },
|
||||
vk::DescriptorSetLayoutBinding{
|
||||
.binding = STORAGE_IMAGE_BINDING_INDEX,
|
||||
.descriptorType = vk::DescriptorType::eStorageImage,
|
||||
.descriptorCount = Cast<u32>(maxStorageImages),
|
||||
.stageFlags = vk::ShaderStageFlagBits::eAll,
|
||||
},
|
||||
};
|
||||
|
||||
vk::DescriptorBindingFlags bindingFlags =
|
||||
|
|
@ -125,7 +126,7 @@ RenderResourceManager::RenderResourceManager(const Device *device, u32 const max
|
|||
m_Instance = this;
|
||||
}
|
||||
|
||||
RenderResourceManager::~RenderResourceManager()
|
||||
CommitManager::~CommitManager()
|
||||
{
|
||||
m_Device->m_Device.destroy(m_SetLayout, nullptr);
|
||||
m_Device->m_Device.destroy(m_DescriptorPool, nullptr);
|
||||
|
|
@ -148,8 +149,8 @@ RenderResourceManager::~RenderResourceManager()
|
|||
#endif
|
||||
}
|
||||
|
||||
CommitEntry<Buffer>
|
||||
RenderResourceManager::Commit(const BufferHandle &buffer)
|
||||
ResId<Buffer>
|
||||
CommitManager::CommitBuffer(const Ref<Buffer> &buffer)
|
||||
{
|
||||
auto [commit, isNew] = m_Buffers.Create(buffer);
|
||||
|
||||
|
|
@ -173,14 +174,38 @@ RenderResourceManager::Commit(const BufferHandle &buffer)
|
|||
return commit;
|
||||
}
|
||||
|
||||
CommitEntry<Image>
|
||||
RenderResourceManager::Commit(const ImageHandle &handle)
|
||||
ResId<StorageImage>
|
||||
CommitManager::CommitStorageImage(const Ref<StorageImage> &image)
|
||||
{
|
||||
return Commit(handle, m_DefaultSampler);
|
||||
auto [commit, isNew] = m_StorageImages.Create(image);
|
||||
if (!isNew)
|
||||
return commit;
|
||||
|
||||
m_WriteInfos.emplace_back(vk::DescriptorImageInfo{
|
||||
.sampler = nullptr,
|
||||
.imageView = image->m_View,
|
||||
.imageLayout = vk::ImageLayout::eGeneral,
|
||||
});
|
||||
m_Writes.push_back({
|
||||
.dstSet = m_DescriptorSet,
|
||||
.dstBinding = STORAGE_IMAGE_BINDING_INDEX,
|
||||
.dstArrayElement = commit.m_Index,
|
||||
.descriptorCount = 1,
|
||||
.descriptorType = vk::DescriptorType::eStorageImage,
|
||||
.pImageInfo = &m_WriteInfos.back().uImageInfo,
|
||||
});
|
||||
|
||||
return commit;
|
||||
}
|
||||
|
||||
CommitEntry<Image>
|
||||
RenderResourceManager::Commit(const ImageHandle &image, const SamplerHandle &sampler)
|
||||
ResId<Texture>
|
||||
CommitManager::CommitTexture(const Ref<Texture> &handle)
|
||||
{
|
||||
return CommitTexture(handle, m_DefaultSampler);
|
||||
}
|
||||
|
||||
ResId<Texture>
|
||||
CommitManager::CommitTexture(const Ref<Texture> &image, const Ref<Sampler> &sampler)
|
||||
{
|
||||
auto [commit, isNew] = m_Images.Create(image);
|
||||
if (!isNew)
|
||||
|
|
@ -203,23 +228,23 @@ RenderResourceManager::Commit(const ImageHandle &image, const SamplerHandle &sam
|
|||
return commit;
|
||||
}
|
||||
|
||||
RenderResourceManager::WriteInfo::WriteInfo(const vk::DescriptorBufferInfo &info)
|
||||
CommitManager::WriteInfo::WriteInfo(const vk::DescriptorBufferInfo &info)
|
||||
: uBufferInfo{info}
|
||||
{
|
||||
}
|
||||
|
||||
RenderResourceManager::WriteInfo::WriteInfo(const vk::DescriptorImageInfo &info)
|
||||
CommitManager::WriteInfo::WriteInfo(const vk::DescriptorImageInfo &info)
|
||||
: uImageInfo{info}
|
||||
{
|
||||
}
|
||||
|
||||
RenderResourceManager::WriteInfo::WriteInfo(const vk::BufferView &info)
|
||||
CommitManager::WriteInfo::WriteInfo(const vk::BufferView &info)
|
||||
: uBufferView{info}
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
RenderResourceManager::Update()
|
||||
CommitManager::Update()
|
||||
{
|
||||
// Descriptor Updates
|
||||
if (!m_Writes.empty())
|
||||
|
|
@ -9,8 +9,6 @@
|
|||
|
||||
using namespace systems;
|
||||
|
||||
Manager<Image> *Manager<Image>::m_Instance = nullptr;
|
||||
|
||||
vk::ImageCreateInfo ToImageCreateInfo(const Texture2DCreateInfo &createInfo);
|
||||
vk::ImageCreateInfo ToImageCreateInfo(const TextureCubeCreateInfo &createInfo);
|
||||
vk::ImageCreateInfo ToImageCreateInfo(const AttachmentCreateInfo &createInfo);
|
||||
|
|
@ -27,7 +25,7 @@ constexpr vk::ImageUsageFlags COLOR_ATTACHMENT =
|
|||
constexpr vk::ImageUsageFlags DEPTH_STENCIL_ATTACHMENT = vk::ImageUsageFlagBits::eDepthStencilAttachment;
|
||||
} // namespace usage_flags
|
||||
|
||||
ImageHandle
|
||||
Ref<Image>
|
||||
ImageManager::CreateTexture2D(const Texture2DCreateInfo &createInfo)
|
||||
{
|
||||
constexpr VmaAllocationCreateInfo allocationCreateInfo = {
|
||||
|
|
@ -68,13 +66,18 @@ ImageManager::CreateTexture2D(const Texture2DCreateInfo &createInfo)
|
|||
object->m_Extent = imageCreateInfo.extent;
|
||||
object->m_LayerCount = Cast<u8>(imageCreateInfo.arrayLayers);
|
||||
object->m_MipLevels = Cast<u8>(imageCreateInfo.mipLevels);
|
||||
object->m_Flags_ = {};
|
||||
if (createInfo.m_IsSampled)
|
||||
object->m_Flags_ |= Image::SAMPLED_BIT;
|
||||
if (createInfo.m_IsStorage)
|
||||
object->m_Flags_ |= Image::STORAGE_BIT;
|
||||
|
||||
m_Device->SetName(object->m_Image, createInfo.m_Name);
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
ImageHandle
|
||||
Ref<ImageCube>
|
||||
ImageManager::CreateTextureCube(const TextureCubeCreateInfo &createInfo)
|
||||
{
|
||||
constexpr VmaAllocationCreateInfo allocationCreateInfo = {
|
||||
|
|
@ -115,13 +118,18 @@ ImageManager::CreateTextureCube(const TextureCubeCreateInfo &createInfo)
|
|||
object->m_Extent = imageCreateInfo.extent;
|
||||
object->m_LayerCount = Cast<u8>(imageCreateInfo.arrayLayers);
|
||||
object->m_MipLevels = Cast<u8>(imageCreateInfo.mipLevels);
|
||||
object->m_Flags_ = Image::CUBE_BIT;
|
||||
if (createInfo.m_IsSampled)
|
||||
object->m_Flags_ |= Image::SAMPLED_BIT;
|
||||
if (createInfo.m_IsStorage)
|
||||
object->m_Flags_ |= Image::STORAGE_BIT;
|
||||
|
||||
m_Device->SetName(object->m_Image, createInfo.m_Name);
|
||||
|
||||
return object;
|
||||
return CastImage<ImageCube>(object);
|
||||
}
|
||||
|
||||
ImageHandle
|
||||
Ref<Image>
|
||||
ImageManager::CreateAttachment(const AttachmentCreateInfo &createInfo)
|
||||
{
|
||||
constexpr VmaAllocationCreateInfo allocationCreateInfo = {
|
||||
|
|
@ -168,7 +176,7 @@ ImageManager::CreateAttachment(const AttachmentCreateInfo &createInfo)
|
|||
return object;
|
||||
}
|
||||
|
||||
ImageHandle
|
||||
Ref<Image>
|
||||
ImageManager::CreateDepthStencilImage(const DepthStencilImageCreateInfo &createInfo)
|
||||
{
|
||||
constexpr VmaAllocationCreateInfo allocationCreateInfo = {
|
||||
|
|
@ -306,7 +314,7 @@ ToImageCreateInfo(const DepthStencilImageCreateInfo &createInfo)
|
|||
};
|
||||
}
|
||||
|
||||
ImageManager::ImageManager(const Device *device, const u32 maxCount, const u8 binding)
|
||||
: Manager{device, maxCount, binding}
|
||||
ImageManager::ImageManager(const Device *device, const u32 maxCount)
|
||||
: Manager{device, maxCount}
|
||||
{
|
||||
}
|
||||
|
|
@ -9,35 +9,8 @@
|
|||
|
||||
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(const Device *device, const u32 maxCount)
|
||||
: Manager{device, maxCount}
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -46,21 +19,20 @@ SamplerManager::~SamplerManager()
|
|||
m_HashToSamplerIdx.clear();
|
||||
}
|
||||
|
||||
SamplerHandle
|
||||
SamplerManager::Create(const SamplerCreateInfo &createInfo)
|
||||
Ref<Sampler>
|
||||
SamplerManager::CreateSampler(const SamplerCreateInfo &createInfo)
|
||||
{
|
||||
const auto hash = HashSamplerCreateInfo(createInfo);
|
||||
auto vkCreateInfo = Cast<vk::SamplerCreateInfo>(createInfo);
|
||||
|
||||
if (const auto iter = m_HashToSamplerIdx.find(hash); iter != m_HashToSamplerIdx.end())
|
||||
if (const auto iter = m_HashToSamplerIdx.find(vkCreateInfo); iter != m_HashToSamplerIdx.end())
|
||||
{
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
auto object = Alloc();
|
||||
|
||||
object->Init(m_Device, createInfo, createInfo.m_Name ? createInfo.m_Name : nullptr);
|
||||
m_HashToSamplerIdx.emplace(hash, object);
|
||||
object->Init(m_Device, vkCreateInfo, createInfo.m_Name ? createInfo.m_Name : nullptr);
|
||||
m_HashToSamplerIdx.emplace(vkCreateInfo, object);
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@
|
|||
|
||||
#include <imgui.h>
|
||||
|
||||
struct AttachmentImage;
|
||||
struct Device;
|
||||
struct Context;
|
||||
struct Window;
|
||||
|
|
|
|||
|
|
@ -20,7 +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 "aster/systems/commit_manager.h"
|
||||
#include "frame.h"
|
||||
#include "stb_image.h"
|
||||
|
||||
|
|
@ -74,7 +74,7 @@ ImageFile::~ImageFile()
|
|||
}
|
||||
|
||||
vk::ShaderModule CreateShader(const Device *device, cstr shaderFile);
|
||||
Pipeline CreatePipeline(const systems::RenderResourceManager *resourceManager, const Swapchain *swapchain);
|
||||
Pipeline CreatePipeline(const systems::CommitManager *resourceManager, const Swapchain *swapchain);
|
||||
|
||||
struct Vertex
|
||||
{
|
||||
|
|
@ -129,13 +129,13 @@ main(int, char **)
|
|||
vk::Queue commandQueue = device.GetQueue(queueAllocation.m_Family, 0);
|
||||
Swapchain swapchain = {&surface, &device, window.GetSize(), "Primary Chain"};
|
||||
|
||||
systems::BufferManager bufferManager{&device, 12, 0};
|
||||
systems::ImageManager imageManager{&device, 12, 1};
|
||||
systems::SamplerManager samplerManager{&device, 1, 0xF};
|
||||
systems::BufferManager bufferManager{&device, 12};
|
||||
systems::ImageManager imageManager{&device, 12};
|
||||
systems::SamplerManager samplerManager{&device, 1};
|
||||
|
||||
systems::RenderResourceManager renderResourceManager{&device, 12, 12, samplerManager.Create({})};
|
||||
systems::CommitManager commitManager{&device, 12, 12, 12, samplerManager.CreateSampler({})};
|
||||
|
||||
Pipeline pipeline = CreatePipeline(&renderResourceManager, &swapchain);
|
||||
Pipeline pipeline = CreatePipeline(&commitManager, &swapchain);
|
||||
|
||||
Camera camera = {
|
||||
.m_Model = {1.0f},
|
||||
|
|
@ -389,7 +389,7 @@ main(int, char **)
|
|||
};
|
||||
|
||||
FrameManager frameManager = {&device, queueAllocation.m_Family, MAX_FRAMES_IN_FLIGHT};
|
||||
eastl::fixed_vector<systems::ImageHandle, MAX_FRAMES_IN_FLIGHT> depthImages;
|
||||
eastl::fixed_vector<Ref<Image>, MAX_FRAMES_IN_FLIGHT> depthImages;
|
||||
|
||||
auto initDepthImages = [&depthImages, &frameManager, &imageManager](const vk::Extent2D extent) {
|
||||
for (u32 i = 0; i < frameManager.m_FramesInFlight; ++i)
|
||||
|
|
@ -409,15 +409,15 @@ main(int, char **)
|
|||
|
||||
struct PCB
|
||||
{
|
||||
systems::CommitEntry<Buffer> m_Camera;
|
||||
systems::CommitEntry<Buffer> m_VertexBuffer;
|
||||
systems::CommitEntry<Image> m_Texture;
|
||||
systems::ResId<Buffer> m_Camera;
|
||||
systems::ResId<Buffer> m_VertexBuffer;
|
||||
systems::ResId<Texture> m_Texture;
|
||||
};
|
||||
|
||||
PCB pcb = {
|
||||
.m_Camera = renderResourceManager.Commit(ubo),
|
||||
.m_VertexBuffer = renderResourceManager.Commit(vbo),
|
||||
.m_Texture = renderResourceManager.Commit(crate),
|
||||
.m_Camera = commitManager.CommitBuffer(ubo),
|
||||
.m_VertexBuffer = commitManager.CommitBuffer(vbo),
|
||||
.m_Texture = commitManager.CommitTexture(systems::CastImage<Texture>(crate)),
|
||||
};
|
||||
|
||||
Time::Init();
|
||||
|
|
@ -426,7 +426,7 @@ main(int, char **)
|
|||
while (window.Poll())
|
||||
{
|
||||
Time::Update();
|
||||
renderResourceManager.Update();
|
||||
commitManager.Update();
|
||||
|
||||
camera.m_Model *= rotate(mat4{1.0f}, Cast<f32>(45.0_deg * Time::m_Delta), vec3(0.0f, 1.0f, 0.0f));
|
||||
ubo->Write(0, sizeof camera, &camera);
|
||||
|
|
@ -482,7 +482,7 @@ main(int, char **)
|
|||
cmd.setScissor(0, 1, &scissor);
|
||||
cmd.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline.m_Pipeline);
|
||||
cmd.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipeline.m_Layout, 0, 1,
|
||||
&renderResourceManager.GetDescriptorSet(), 0, nullptr);
|
||||
&commitManager.GetDescriptorSet(), 0, nullptr);
|
||||
cmd.pushConstants(pipeline.m_Layout, vk::ShaderStageFlagBits::eAllGraphics, 0, 12, &pcb);
|
||||
cmd.draw(Cast<u32>(vertices.size()), 1, 0, 0);
|
||||
|
||||
|
|
@ -514,7 +514,7 @@ main(int, char **)
|
|||
}
|
||||
|
||||
Pipeline
|
||||
CreatePipeline(const systems::RenderResourceManager *resourceManager, const Swapchain *swapchain)
|
||||
CreatePipeline(const systems::CommitManager *resourceManager, const Swapchain *swapchain)
|
||||
{
|
||||
// Pipeline Setup
|
||||
auto *device = resourceManager->m_Device;
|
||||
|
|
|
|||
|
|
@ -12,12 +12,11 @@ add_executable(model_render "model_render.cpp"
|
|||
"asset_loader.h"
|
||||
"light_manager.cpp"
|
||||
"light_manager.h"
|
||||
"gpu_resource_manager.cpp"
|
||||
"gpu_resource_manager.h"
|
||||
"nodes.cpp"
|
||||
"nodes.h"
|
||||
"ibl_helpers.cpp"
|
||||
"ibl_helpers.h")
|
||||
"ibl_helpers.h"
|
||||
"tiny_gltf_setup.cpp")
|
||||
|
||||
add_shader(model_render "shader/model.vs.hlsl")
|
||||
add_shader(model_render "shader/model.ps.hlsl")
|
||||
|
|
|
|||
|
|
@ -3,26 +3,25 @@
|
|||
// Copyright (c) 2020-2024 Anish Bhobe
|
||||
// =============================================
|
||||
|
||||
#define TINYGLTF_NOEXCEPTION
|
||||
#define JSON_NOEXCEPTION
|
||||
|
||||
#define TINYGLTF_IMPLEMENTATION
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||
|
||||
#include "aster/core/buffer.h"
|
||||
#include "aster/core/device.h"
|
||||
#include "aster/core/image.h"
|
||||
|
||||
#include "gpu_resource_manager.h"
|
||||
#include "helpers.h"
|
||||
#include "asset_loader.h"
|
||||
#include "helpers.h"
|
||||
|
||||
#include "aster/systems/commit_manager.h"
|
||||
#include "aster/systems/resource_manager.h"
|
||||
|
||||
#include <EASTL/fixed_vector.h>
|
||||
#include <EASTL/hash_map.h>
|
||||
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
#include <tiny_gltf.h>
|
||||
#include <stb_image.h>
|
||||
|
||||
#if defined(LoadImage)
|
||||
#undef LoadImage
|
||||
|
|
@ -54,12 +53,9 @@ VectorToVec3(const std::vector<double> &vec)
|
|||
return {vec[0], vec[1], vec[2]};
|
||||
}
|
||||
|
||||
void
|
||||
AssetLoader::LoadHdrImage(Texture *texture, cstr path, cstr name) const
|
||||
Ref<Texture>
|
||||
AssetLoader::LoadHdrImage(cstr path, cstr name) const
|
||||
{
|
||||
const Device *pDevice = m_ResourceManager->m_Device;
|
||||
ERROR_IF(texture->IsValid(), "Expected invalid image.") THEN_ABORT(-1);
|
||||
|
||||
i32 x, y, nChannels;
|
||||
f32 *data = stbi_loadf(path, &x, &y, &nChannels, 4);
|
||||
assert(nChannels == 3);
|
||||
|
|
@ -69,11 +65,20 @@ AssetLoader::LoadHdrImage(Texture *texture, cstr path, cstr name) const
|
|||
u32 width = Cast<u32>(x);
|
||||
u32 height = Cast<u32>(y);
|
||||
|
||||
auto texture = m_ResourceManager->Images().CreateTexture2D<Texture>({
|
||||
.m_Format = vk::Format::eR32G32B32A32Sfloat,
|
||||
.m_Extent = {width, height},
|
||||
.m_Name = path,
|
||||
.m_IsSampled = true,
|
||||
.m_IsMipMapped = false,
|
||||
.m_IsStorage = false,
|
||||
});
|
||||
|
||||
auto *pDevice = m_CommitManager->m_Device;
|
||||
|
||||
StagingBuffer stagingBuffer;
|
||||
texture->Init(m_ResourceManager->m_Device, {width, height}, vk::Format::eR32G32B32A32Sfloat, false, path);
|
||||
assert(texture->IsValid());
|
||||
stagingBuffer.Init(m_ResourceManager->m_Device, (sizeof *data) * x * y * 4, "HDR Staging Buffer");
|
||||
stagingBuffer.Write(m_ResourceManager->m_Device, 0, stagingBuffer.GetSize(), data);
|
||||
stagingBuffer.Init(pDevice, (sizeof *data) * x * y * 4, "HDR Staging Buffer");
|
||||
stagingBuffer.Write(0, stagingBuffer.m_Size, data);
|
||||
|
||||
stbi_image_free(data);
|
||||
|
||||
|
|
@ -189,11 +194,13 @@ AssetLoader::LoadHdrImage(Texture *texture, cstr path, cstr name) const
|
|||
|
||||
AbortIfFailed(pDevice->m_Device.resetCommandPool(m_CommandPool, {}));
|
||||
|
||||
stagingBuffer.Destroy(pDevice);
|
||||
stagingBuffer.Destroy();
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
void
|
||||
GenerateMipMaps(vk::CommandBuffer commandBuffer, Texture *texture, vk::ImageLayout initialLayout,
|
||||
GenerateMipMaps(vk::CommandBuffer commandBuffer, const Ref<Texture> &texture, vk::ImageLayout initialLayout,
|
||||
vk::ImageLayout finalLayout, vk::PipelineStageFlags2 prevStage, vk::PipelineStageFlags2 finalStage)
|
||||
{
|
||||
#if !defined(ASTER_NDEBUG)
|
||||
|
|
@ -362,8 +369,8 @@ GenerateMipMaps(vk::CommandBuffer commandBuffer, Texture *texture, vk::ImageLayo
|
|||
#endif
|
||||
}
|
||||
|
||||
TextureHandle
|
||||
AssetLoader::LoadImageToGpu(StagingBuffer *stagingBuffer, tinygltf::Image *image, bool isSrgb) const
|
||||
std::tuple<systems::ResId<Texture>, Ref<Buffer>>
|
||||
AssetLoader::LoadImageToGpu(tinygltf::Image* image, bool isSrgb) const
|
||||
{
|
||||
assert(image->component == 4);
|
||||
assert(image->height > 0 && image->width > 0);
|
||||
|
|
@ -373,13 +380,17 @@ AssetLoader::LoadImageToGpu(StagingBuffer *stagingBuffer, tinygltf::Image *image
|
|||
|
||||
vk::Format imageFormat = isSrgb ? vk::Format::eR8G8B8A8Srgb : vk::Format::eR8G8B8A8Unorm;
|
||||
|
||||
Texture texture;
|
||||
|
||||
usize byteSize = image->image.size();
|
||||
texture.Init(m_ResourceManager->m_Device, {.width = width, .height = height}, imageFormat, true,
|
||||
image->name.data());
|
||||
stagingBuffer->Init(m_ResourceManager->m_Device, byteSize);
|
||||
stagingBuffer->Write(m_ResourceManager->m_Device, 0, byteSize, image->image.data());
|
||||
auto texture = m_ResourceManager->Images().CreateTexture2D<Texture>({
|
||||
.m_Format = imageFormat,
|
||||
.m_Extent = {width, height},
|
||||
.m_Name = image->name.c_str(),
|
||||
.m_IsSampled = true,
|
||||
.m_IsMipMapped = true,
|
||||
.m_IsStorage = false,
|
||||
});
|
||||
auto stagingBuffer = m_ResourceManager->Buffers().CreateStagingBuffer(byteSize);
|
||||
stagingBuffer->Write(0, byteSize, image->image.data());
|
||||
|
||||
#if !defined(ASTER_NDEBUG)
|
||||
StackString<128> loadActionName = "Load: ";
|
||||
|
|
@ -402,7 +413,7 @@ AssetLoader::LoadImageToGpu(StagingBuffer *stagingBuffer, tinygltf::Image *image
|
|||
.newLayout = vk::ImageLayout::eTransferDstOptimal,
|
||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.image = texture.m_Image,
|
||||
.image = texture->m_Image,
|
||||
.subresourceRange =
|
||||
{
|
||||
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||
|
|
@ -426,7 +437,7 @@ AssetLoader::LoadImageToGpu(StagingBuffer *stagingBuffer, tinygltf::Image *image
|
|||
.newLayout = vk::ImageLayout::eTransferSrcOptimal,
|
||||
.srcQueueFamilyIndex = m_TransferQueueIndex,
|
||||
.dstQueueFamilyIndex = m_GraphicsQueueIndex,
|
||||
.image = texture.m_Image,
|
||||
.image = texture->m_Image,
|
||||
.subresourceRange =
|
||||
{
|
||||
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||
|
|
@ -455,11 +466,11 @@ AssetLoader::LoadImageToGpu(StagingBuffer *stagingBuffer, tinygltf::Image *image
|
|||
.layerCount = 1,
|
||||
},
|
||||
.imageOffset = {},
|
||||
.imageExtent = texture.m_Extent,
|
||||
.imageExtent = texture->m_Extent,
|
||||
};
|
||||
vk::CopyBufferToImageInfo2 stagingCopyInfo = {
|
||||
.srcBuffer = stagingBuffer->m_Buffer,
|
||||
.dstImage = texture.m_Image,
|
||||
.dstImage = texture->m_Image,
|
||||
.dstImageLayout = vk::ImageLayout::eTransferDstOptimal,
|
||||
.regionCount = 1,
|
||||
.pRegions = &imageCopy,
|
||||
|
|
@ -471,14 +482,14 @@ AssetLoader::LoadImageToGpu(StagingBuffer *stagingBuffer, tinygltf::Image *image
|
|||
m_CommandBuffer.copyBufferToImage2(&stagingCopyInfo);
|
||||
m_CommandBuffer.pipelineBarrier2(&postStagingDependency);
|
||||
|
||||
GenerateMipMaps(m_CommandBuffer, &texture, vk::ImageLayout::eTransferSrcOptimal,
|
||||
GenerateMipMaps(m_CommandBuffer, texture, vk::ImageLayout::eTransferSrcOptimal,
|
||||
vk::ImageLayout::eShaderReadOnlyOptimal);
|
||||
|
||||
#if !defined(ASTER_NDEBUG)
|
||||
m_CommandBuffer.endDebugUtilsLabelEXT();
|
||||
#endif
|
||||
|
||||
return m_ResourceManager->CommitTexture(&texture);
|
||||
return {m_CommitManager->CommitTexture(texture), stagingBuffer};
|
||||
}
|
||||
|
||||
Model
|
||||
|
|
@ -488,7 +499,7 @@ AssetLoader::LoadModelToGpu(cstr path, cstr name)
|
|||
tinygltf::Model model;
|
||||
tinygltf::TinyGLTF loader;
|
||||
|
||||
const Device *pDevice = m_ResourceManager->m_Device;
|
||||
const Device *pDevice = m_CommitManager->m_Device;
|
||||
|
||||
const auto fsPath = fs::absolute(path);
|
||||
const auto ext = fsPath.extension();
|
||||
|
|
@ -525,30 +536,28 @@ AssetLoader::LoadModelToGpu(cstr path, cstr name)
|
|||
m_CommandBuffer.beginDebugUtilsLabelEXT(&debugLabel);
|
||||
#endif
|
||||
|
||||
eastl::vector<StagingBuffer> stagingBuffers;
|
||||
eastl::vector<Ref<Buffer>> stagingBuffers;
|
||||
|
||||
eastl::hash_map<i32, TextureHandle> textureHandleMap;
|
||||
eastl::hash_map<i32, systems::ResId<Texture>> textureHandleMap;
|
||||
|
||||
eastl::vector<Material> materials;
|
||||
StorageBuffer materialsBuffer;
|
||||
BufferHandle materialsHandle;
|
||||
systems::ResId<Buffer> materialsHandle = systems::ResId<Buffer>::Null();
|
||||
|
||||
if (!model.materials.empty())
|
||||
{
|
||||
auto getTextureHandle = [this, &textureHandleMap, &stagingBuffers, &model](i32 index,
|
||||
bool isSrgb) -> TextureHandle {
|
||||
auto getTextureHandle = [this, &textureHandleMap, &stagingBuffers,
|
||||
&model](i32 index, const bool isSrgb) -> systems::ResId<Texture> {
|
||||
if (index < 0)
|
||||
{
|
||||
return {};
|
||||
return systems::NullId{};
|
||||
}
|
||||
const auto iter = textureHandleMap.find(index);
|
||||
if (iter != textureHandleMap.end())
|
||||
if (const auto iter = textureHandleMap.find(index); iter != textureHandleMap.end())
|
||||
{
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
auto *image = &model.images[index];
|
||||
TextureHandle handle = LoadImageToGpu(&stagingBuffers.push_back(), image, isSrgb);
|
||||
auto [handle , staging] = LoadImageToGpu(image, isSrgb);
|
||||
textureHandleMap.emplace(index, handle);
|
||||
return handle;
|
||||
};
|
||||
|
|
@ -571,15 +580,15 @@ AssetLoader::LoadModelToGpu(cstr path, cstr name)
|
|||
}
|
||||
|
||||
usize materialsByteSize = materials.size() * sizeof materials[0];
|
||||
materialsBuffer.Init(pDevice, materialsByteSize, false, name);
|
||||
materialsHandle = m_ResourceManager->Commit(&materialsBuffer);
|
||||
auto materialsBuffer = m_ResourceManager->Buffers().CreateStorageBuffer(materialsByteSize, name);
|
||||
materialsHandle = m_CommitManager->CommitBuffer(materialsBuffer);
|
||||
|
||||
StagingBuffer &materialStaging = stagingBuffers.push_back();
|
||||
materialStaging.Init(pDevice, materialsByteSize);
|
||||
materialStaging.Write(pDevice, 0, materialsByteSize, materials.data());
|
||||
auto materialStaging = m_ResourceManager->Buffers().CreateStagingBuffer(materialsByteSize);
|
||||
materialStaging->Write(0, materialsByteSize, materials.data());
|
||||
stagingBuffers.emplace_back(std::move(materialStaging));
|
||||
|
||||
vk::BufferCopy bufferCopy = {.srcOffset = 0, .dstOffset = 0, .size = materialsByteSize};
|
||||
m_CommandBuffer.copyBuffer(materialStaging.m_Buffer, materialsBuffer.m_Buffer, 1, &bufferCopy);
|
||||
m_CommandBuffer.copyBuffer(materialStaging->m_Buffer, materialsBuffer->m_Buffer, 1, &bufferCopy);
|
||||
}
|
||||
|
||||
// TODO: Mesh reordering based on nodes AND OR meshoptimizer
|
||||
|
|
@ -862,38 +871,39 @@ AssetLoader::LoadModelToGpu(cstr path, cstr name)
|
|||
|
||||
nodes.Update();
|
||||
|
||||
StorageBuffer nodeBuffer;
|
||||
nodeBuffer.Init(pDevice, nodes.GetGlobalTransformByteSize(), true);
|
||||
nodeBuffer.Write(pDevice, 0, nodes.GetGlobalTransformByteSize(), nodes.GetGlobalTransformPtr());
|
||||
BufferHandle nodeHandle = m_ResourceManager->Commit(&nodeBuffer);
|
||||
auto nodeBuffer = m_ResourceManager->Buffers().CreateStorageBuffer(nodes.GetGlobalTransformByteSize());
|
||||
nodeBuffer->Write(0, nodes.GetGlobalTransformByteSize(), nodes.GetGlobalTransformPtr());
|
||||
systems::ResId<Buffer> nodeHandle = m_CommitManager->CommitBuffer(nodeBuffer);
|
||||
|
||||
#pragma region Staging / Transfer / Uploads
|
||||
BufferHandle positionBufferHandle;
|
||||
BufferHandle vertexDataHandle;
|
||||
IndexBuffer indexBuffer;
|
||||
systems::ResId<Buffer> positionBufferHandle = systems::ResId<Buffer>::Null();
|
||||
systems::ResId<Buffer> vertexDataHandle = systems::ResId<Buffer>::Null();
|
||||
Ref<Buffer> indexBuffer;
|
||||
|
||||
{
|
||||
auto uploadBufferData = [cmd = this->m_CommandBuffer, &stagingBuffers, pDevice](const Buffer *buffer,
|
||||
const void *data) {
|
||||
vk::BufferCopy bufferCopy = {.srcOffset = 0, .dstOffset = 0, .size = buffer->GetSize()};
|
||||
StagingBuffer &stagingBuffer = stagingBuffers.push_back();
|
||||
stagingBuffer.Init(pDevice, bufferCopy.size);
|
||||
stagingBuffer.Write(pDevice, 0, bufferCopy.size, data);
|
||||
cmd.copyBuffer(stagingBuffer.m_Buffer, buffer->m_Buffer, 1, &bufferCopy);
|
||||
auto uploadBufferData = [cmd = this->m_CommandBuffer, &stagingBuffers, resMan = this->m_ResourceManager,
|
||||
pDevice](const Ref<Buffer> &buffer, const void *data) {
|
||||
const vk::BufferCopy bufferCopy = {.srcOffset = 0, .dstOffset = 0, .size = buffer->m_Size};
|
||||
auto stagingBuffer = resMan->Buffers().CreateStagingBuffer(bufferCopy.size);
|
||||
stagingBuffer->Write(0, bufferCopy.size, data);
|
||||
cmd.copyBuffer(stagingBuffer->m_Buffer, buffer->m_Buffer, 1, &bufferCopy);
|
||||
stagingBuffers.emplace_back(std::move(stagingBuffer));
|
||||
};
|
||||
|
||||
StorageBuffer positionBuffer;
|
||||
positionBuffer.Init(pDevice, vertexPositions.size() * sizeof vertexPositions[0], false);
|
||||
positionBufferHandle = m_ResourceManager->Commit(&positionBuffer);
|
||||
uploadBufferData(&positionBuffer, vertexPositions.data());
|
||||
auto positionBuffer =
|
||||
m_ResourceManager->Buffers().CreateStorageBuffer(vertexPositions.size() * sizeof vertexPositions[0]);
|
||||
positionBufferHandle = m_CommitManager->CommitBuffer(positionBuffer);
|
||||
uploadBufferData(positionBuffer, vertexPositions.data());
|
||||
|
||||
StorageBuffer vertexDataBuffer;
|
||||
vertexDataBuffer.Init(pDevice, vertexData.size() * sizeof vertexData[0], false);
|
||||
vertexDataHandle = m_ResourceManager->Commit(&vertexDataBuffer);
|
||||
uploadBufferData(&vertexDataBuffer, vertexData.data());
|
||||
auto vertexDataBuffer =
|
||||
m_ResourceManager->Buffers().CreateStorageBuffer(vertexData.size() * sizeof vertexData[0]);
|
||||
vertexDataHandle = m_CommitManager->CommitBuffer(vertexDataBuffer);
|
||||
uploadBufferData(vertexDataBuffer, vertexData.data());
|
||||
|
||||
indexBuffer.Init(pDevice, indices.size() * sizeof indices[0]);
|
||||
uploadBufferData(&indexBuffer, indices.data());
|
||||
// TODO: Index buffer needs to be separated.
|
||||
indexBuffer =
|
||||
m_ResourceManager->Buffers().CreateStorageBuffer(indices.size() * sizeof indices[0], "Index Buffer");
|
||||
uploadBufferData(indexBuffer, indices.data());
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
|
@ -919,11 +929,6 @@ AssetLoader::LoadModelToGpu(cstr path, cstr name)
|
|||
|
||||
AbortIfFailed(pDevice->m_Device.resetCommandPool(m_CommandPool, {}));
|
||||
|
||||
for (auto &buffer : stagingBuffers)
|
||||
{
|
||||
buffer.Destroy(pDevice);
|
||||
}
|
||||
|
||||
Model::ModelHandles handles = {
|
||||
.m_VertexPositionHandle = positionBufferHandle,
|
||||
.m_VertexDataHandle = vertexDataHandle,
|
||||
|
|
@ -931,7 +936,7 @@ AssetLoader::LoadModelToGpu(cstr path, cstr name)
|
|||
.m_NodeHandle = nodeHandle,
|
||||
};
|
||||
|
||||
eastl::vector<TextureHandle> textureHandles;
|
||||
eastl::vector<systems::ResId<Texture>> textureHandles;
|
||||
textureHandles.reserve(textureHandleMap.size());
|
||||
|
||||
for (auto &[key, val] : textureHandleMap)
|
||||
|
|
@ -940,44 +945,23 @@ AssetLoader::LoadModelToGpu(cstr path, cstr name)
|
|||
}
|
||||
|
||||
return Model{
|
||||
m_ResourceManager, std::move(textureHandles), std::move(nodes), handles, indexBuffer, meshPrimitives,
|
||||
m_CommitManager, textureHandles, std::move(nodes), nodeBuffer, handles, indexBuffer, meshPrimitives,
|
||||
};
|
||||
}
|
||||
|
||||
Model::Model(GpuResourceManager *resourceManager, eastl::vector<TextureHandle> &&textureHandles, Nodes &&nodes,
|
||||
const ModelHandles &handles, const IndexBuffer &indexBuffer,
|
||||
Model::Model(systems::CommitManager *resourceManager, eastl::vector<systems::ResId<Texture>> &textureHandles,
|
||||
Nodes &&nodes, Ref<Buffer> nodeBuffer, ModelHandles &handles, Ref<Buffer> indexBuffer,
|
||||
const eastl::vector<MeshPrimitive> &meshPrimitives)
|
||||
: m_ResourceManager(resourceManager)
|
||||
, m_TextureHandles(std::move(textureHandles))
|
||||
, m_Nodes(std::move(nodes))
|
||||
, m_Handles(handles)
|
||||
, m_IndexBuffer(indexBuffer)
|
||||
, m_Handles(std::move(handles))
|
||||
, m_NodeBuffer(std::move(nodeBuffer))
|
||||
, m_IndexBuffer(std::move(indexBuffer))
|
||||
, m_MeshPrimitives(meshPrimitives)
|
||||
{
|
||||
}
|
||||
|
||||
Model::Model(Model &&other) noexcept
|
||||
: m_ResourceManager(Take(other.m_ResourceManager))
|
||||
, m_TextureHandles(std::move(other.m_TextureHandles))
|
||||
, m_Handles(other.m_Handles)
|
||||
, m_IndexBuffer(other.m_IndexBuffer)
|
||||
, m_MeshPrimitives(std::move(other.m_MeshPrimitives))
|
||||
{
|
||||
}
|
||||
|
||||
Model &
|
||||
Model::operator=(Model &&other) noexcept
|
||||
{
|
||||
if (this == &other)
|
||||
return *this;
|
||||
m_ResourceManager = Take(other.m_ResourceManager);
|
||||
m_TextureHandles = std::move(other.m_TextureHandles);
|
||||
m_Handles = other.m_Handles;
|
||||
m_IndexBuffer = other.m_IndexBuffer;
|
||||
m_MeshPrimitives = std::move(other.m_MeshPrimitives);
|
||||
return *this;
|
||||
}
|
||||
|
||||
const mat4 &
|
||||
Model::GetModelTransform() const
|
||||
{
|
||||
|
|
@ -990,42 +974,24 @@ Model::SetModelTransform(const mat4 &transform)
|
|||
m_Nodes.Set(0, transform);
|
||||
}
|
||||
|
||||
Model::~Model()
|
||||
{
|
||||
if (!m_ResourceManager)
|
||||
return;
|
||||
|
||||
m_IndexBuffer.Destroy(m_ResourceManager->m_Device);
|
||||
|
||||
m_ResourceManager->Release(m_Handles.m_VertexDataHandle);
|
||||
m_ResourceManager->Release(m_Handles.m_NodeHandle);
|
||||
m_ResourceManager->Release(m_Handles.m_VertexPositionHandle);
|
||||
m_ResourceManager->Release(m_Handles.m_MaterialsHandle);
|
||||
|
||||
for (const TextureHandle &handle : m_TextureHandles)
|
||||
{
|
||||
m_ResourceManager->Release(handle);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Model::Update()
|
||||
{
|
||||
if (m_Nodes.Update())
|
||||
{
|
||||
m_ResourceManager->Write(m_Handles.m_NodeHandle, 0, m_Nodes.GetGlobalTransformByteSize(),
|
||||
m_Nodes.GetGlobalTransformPtr());
|
||||
m_NodeBuffer->Write(0, m_Nodes.GetGlobalTransformByteSize(), m_Nodes.GetGlobalTransformPtr());
|
||||
}
|
||||
}
|
||||
|
||||
AssetLoader::AssetLoader(GpuResourceManager *resourceManager, vk::Queue transferQueue, u32 transferQueueIndex,
|
||||
u32 graphicsQueueIndex)
|
||||
AssetLoader::AssetLoader(systems::ResourceManager *resourceManager, systems::CommitManager *commitManager,
|
||||
vk::Queue transferQueue, u32 transferQueueIndex, u32 graphicsQueueIndex)
|
||||
: m_ResourceManager(resourceManager)
|
||||
, m_CommitManager(commitManager)
|
||||
, m_TransferQueue(transferQueue)
|
||||
, m_TransferQueueIndex(transferQueueIndex)
|
||||
, m_GraphicsQueueIndex(graphicsQueueIndex)
|
||||
{
|
||||
const Device *pDevice = resourceManager->m_Device;
|
||||
const Device *pDevice = commitManager->m_Device;
|
||||
const vk::CommandPoolCreateInfo poolCreateInfo = {
|
||||
.flags = vk::CommandPoolCreateFlagBits::eTransient,
|
||||
.queueFamilyIndex = transferQueueIndex,
|
||||
|
|
@ -1047,15 +1013,16 @@ AssetLoader::AssetLoader(GpuResourceManager *resourceManager, vk::Queue transfer
|
|||
|
||||
AssetLoader::~AssetLoader()
|
||||
{
|
||||
if (m_ResourceManager)
|
||||
if (m_CommitManager && m_CommandPool)
|
||||
{
|
||||
m_ResourceManager->m_Device->m_Device.destroy(m_CommandPool, nullptr);
|
||||
m_CommitManager->m_Device->m_Device.destroy(m_CommandPool, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
AssetLoader::AssetLoader(AssetLoader &&other) noexcept
|
||||
: m_ResourceManager(Take(other.m_ResourceManager))
|
||||
, m_CommandPool(other.m_CommandPool)
|
||||
, m_CommitManager(Take(other.m_CommitManager))
|
||||
, m_CommandPool(Take(other.m_CommandPool))
|
||||
, m_CommandBuffer(other.m_CommandBuffer)
|
||||
, m_TransferQueue(other.m_TransferQueue)
|
||||
, m_TransferQueueIndex(other.m_TransferQueueIndex)
|
||||
|
|
@ -1069,7 +1036,8 @@ AssetLoader::operator=(AssetLoader &&other) noexcept
|
|||
if (this == &other)
|
||||
return *this;
|
||||
m_ResourceManager = Take(other.m_ResourceManager);
|
||||
m_CommandPool = other.m_CommandPool;
|
||||
m_CommitManager = Take(other.m_CommitManager);
|
||||
m_CommandPool = Take(other.m_CommandPool);
|
||||
m_CommandBuffer = other.m_CommandBuffer;
|
||||
m_TransferQueue = other.m_TransferQueue;
|
||||
m_TransferQueueIndex = other.m_TransferQueueIndex;
|
||||
|
|
|
|||
|
|
@ -9,8 +9,19 @@
|
|||
|
||||
#include "aster/core/buffer.h"
|
||||
|
||||
#include "gpu_resource_manager.h"
|
||||
#include "nodes.h"
|
||||
#include "tiny_gltf.h"
|
||||
#include "aster/systems/image_manager.h"
|
||||
#include "aster/systems/resource.h"
|
||||
|
||||
namespace systems
|
||||
{
|
||||
class ResourceManager;
|
||||
class SamplerManager;
|
||||
class BufferManager;
|
||||
class ImageManager;
|
||||
class CommitManager;
|
||||
}
|
||||
|
||||
namespace tinygltf
|
||||
{
|
||||
|
|
@ -18,7 +29,6 @@ struct Image;
|
|||
}
|
||||
|
||||
struct Image;
|
||||
struct TextureHandle;
|
||||
struct Texture;
|
||||
|
||||
constexpr auto GLTF_ASCII_FILE_EXTENSION = ".gltf";
|
||||
|
|
@ -39,11 +49,11 @@ struct Material
|
|||
vec3 m_EmissionFactor; // 12 28
|
||||
f32 m_MetalFactor; // 04 32
|
||||
f32 m_RoughFactor; // 04 36
|
||||
TextureHandle m_AlbedoTex; // 04 40
|
||||
TextureHandle m_NormalTex; // 04 44
|
||||
TextureHandle m_MetalRoughTex; // 04 48
|
||||
TextureHandle m_OcclusionTex; // 04 52
|
||||
TextureHandle m_EmissionTex; // 04 56
|
||||
systems::ResId<Texture> m_AlbedoTex; // 04 40
|
||||
systems::ResId<Texture> m_NormalTex; // 04 44
|
||||
systems::ResId<Texture> m_MetalRoughTex; // 04 48
|
||||
systems::ResId<Texture> m_OcclusionTex; // 04 52
|
||||
systems::ResId<Texture> m_EmissionTex; // 04 56
|
||||
};
|
||||
|
||||
struct VertexData
|
||||
|
|
@ -56,33 +66,33 @@ struct VertexData
|
|||
|
||||
struct Model
|
||||
{
|
||||
GpuResourceManager *m_ResourceManager;
|
||||
systems::CommitManager *m_ResourceManager;
|
||||
|
||||
eastl::vector<TextureHandle> m_TextureHandles;
|
||||
eastl::vector<systems::ResId<Texture>> m_TextureHandles;
|
||||
Nodes m_Nodes;
|
||||
|
||||
struct ModelHandles
|
||||
{
|
||||
BufferHandle m_VertexPositionHandle;
|
||||
BufferHandle m_VertexDataHandle;
|
||||
BufferHandle m_MaterialsHandle;
|
||||
BufferHandle m_NodeHandle;
|
||||
systems::ResId<Buffer> m_VertexPositionHandle;
|
||||
systems::ResId<Buffer> m_VertexDataHandle;
|
||||
systems::ResId<Buffer> m_MaterialsHandle;
|
||||
systems::ResId<Buffer> m_NodeHandle;
|
||||
} m_Handles;
|
||||
|
||||
IndexBuffer m_IndexBuffer;
|
||||
Ref<Buffer> m_NodeBuffer;
|
||||
Ref<Buffer> m_IndexBuffer;
|
||||
eastl::vector<MeshPrimitive> m_MeshPrimitives;
|
||||
|
||||
[[nodiscard]] const mat4 &GetModelTransform() const;
|
||||
void SetModelTransform(const mat4 &transform);
|
||||
void Update();
|
||||
|
||||
Model(GpuResourceManager *resourceManager, eastl::vector<TextureHandle> &&textureHandles, Nodes &&nodes,
|
||||
const ModelHandles &handles, const IndexBuffer &indexBuffer,
|
||||
const eastl::vector<MeshPrimitive> &meshPrimitives);
|
||||
~Model();
|
||||
Model(systems::CommitManager *resourceManager, eastl::vector<systems::ResId<Texture>> &textureHandles, Nodes &&nodes, Ref<Buffer> nodeBuffer,
|
||||
ModelHandles &handles, Ref<Buffer> indexBuffer, const eastl::vector<MeshPrimitive> &meshPrimitives);
|
||||
~Model() = default;
|
||||
|
||||
Model(Model &&other) noexcept;
|
||||
Model &operator=(Model &&other) noexcept;
|
||||
Model(Model &&other) noexcept = default;
|
||||
Model &operator=(Model &&other) noexcept = default;
|
||||
|
||||
Model(const Model &) = delete;
|
||||
const Model &operator=(const Model &) = delete;
|
||||
|
|
@ -90,15 +100,17 @@ struct Model
|
|||
|
||||
struct AssetLoader
|
||||
{
|
||||
GpuResourceManager *m_ResourceManager;
|
||||
systems::ResourceManager *m_ResourceManager;
|
||||
systems::CommitManager *m_CommitManager;
|
||||
|
||||
vk::CommandPool m_CommandPool;
|
||||
vk::CommandBuffer m_CommandBuffer;
|
||||
vk::Queue m_TransferQueue;
|
||||
u32 m_TransferQueueIndex;
|
||||
u32 m_GraphicsQueueIndex;
|
||||
|
||||
void LoadHdrImage(Texture *texture, cstr path, cstr name = nullptr) const;
|
||||
TextureHandle LoadImageToGpu(StagingBuffer *stagingBuffer, tinygltf::Image *image, bool isSrgb) const;
|
||||
Ref<Texture> LoadHdrImage(cstr path, cstr name = nullptr) const;
|
||||
std::tuple<systems::ResId<Texture>, Ref<Buffer>> LoadImageToGpu(tinygltf::Image *image, bool isSrgb) const;
|
||||
Model LoadModelToGpu(cstr path, cstr name = nullptr);
|
||||
|
||||
constexpr static auto ANormal = "NORMAL";
|
||||
|
|
@ -110,7 +122,8 @@ struct AssetLoader
|
|||
constexpr static auto AJoints0 = "JOINTS_0";
|
||||
constexpr static auto AWeights0 = "WEIGHTS_0";
|
||||
|
||||
AssetLoader(GpuResourceManager *resourceManager, vk::Queue transferQueue, u32 transferQueueIndex,
|
||||
AssetLoader(systems::ResourceManager *resourceManager, systems::CommitManager *commitManager,
|
||||
vk::Queue transferQueue, u32 transferQueueIndex,
|
||||
u32 graphicsQueueIndex);
|
||||
~AssetLoader();
|
||||
|
||||
|
|
@ -120,7 +133,18 @@ struct AssetLoader
|
|||
DISALLOW_COPY_AND_ASSIGN(AssetLoader);
|
||||
};
|
||||
|
||||
void GenerateMipMaps(vk::CommandBuffer commandBuffer, Texture *texture, vk::ImageLayout initialLayout,
|
||||
void
|
||||
GenerateMipMaps(vk::CommandBuffer commandBuffer, const Ref<Texture> &texture, vk::ImageLayout initialLayout,
|
||||
vk::ImageLayout finalLayout, vk::PipelineStageFlags2 prevStage, vk::PipelineStageFlags2 finalStage);
|
||||
|
||||
|
||||
void GenerateMipMaps(vk::CommandBuffer commandBuffer, concepts::SampledImageRef auto& texture, vk::ImageLayout initialLayout,
|
||||
vk::ImageLayout finalLayout,
|
||||
vk::PipelineStageFlags2 prevStage = vk::PipelineStageFlagBits2::eAllCommands,
|
||||
vk::PipelineStageFlags2 finalStage = vk::PipelineStageFlagBits2::eAllCommands);
|
||||
vk::PipelineStageFlags2 finalStage = vk::PipelineStageFlagBits2::eAllCommands)
|
||||
{
|
||||
GenerateMipMaps(commandBuffer, systems::CastImage<Texture>(texture), initialLayout, finalLayout, prevStage,
|
||||
finalStage);
|
||||
}
|
||||
|
||||
static_assert(concepts::SampledImageRef<Ref<Texture>>);
|
||||
|
|
@ -1,688 +0,0 @@
|
|||
// =============================================
|
||||
// Aster: gpu_resource_manager.cpp
|
||||
// Copyright (c) 2020-2024 Anish Bhobe
|
||||
// =============================================
|
||||
|
||||
#include "gpu_resource_manager.h"
|
||||
|
||||
#include "helpers.h"
|
||||
|
||||
#include "aster/core/buffer.h"
|
||||
#include "aster/core/device.h"
|
||||
#include "aster/core/image.h"
|
||||
|
||||
#include <EASTL/array.h>
|
||||
|
||||
void
|
||||
TextureManager::Init(const u32 maxCapacity)
|
||||
{
|
||||
m_MaxCapacity = maxCapacity;
|
||||
m_FreeHead = GpuResourceHandle::INVALID_HANDLE;
|
||||
}
|
||||
|
||||
TextureHandle
|
||||
TextureManager::Commit(Texture *texture)
|
||||
{
|
||||
ERROR_IF(!texture || !texture->IsValid(), "Texture must be valid for committal")
|
||||
THEN_ABORT(-1);
|
||||
|
||||
if (m_FreeHead != GpuResourceHandle::INVALID_HANDLE)
|
||||
{
|
||||
const u32 index = m_FreeHead;
|
||||
|
||||
Texture *allocatedTexture = &m_Textures[index];
|
||||
|
||||
assert(!allocatedTexture->IsValid());
|
||||
m_FreeHead = *Recast<u32 *>(allocatedTexture);
|
||||
|
||||
// Ensure it is copyable.
|
||||
static_assert(std::is_trivially_copyable_v<Texture>);
|
||||
*allocatedTexture = *texture;
|
||||
|
||||
// Take ownership of the texture.
|
||||
texture->m_Flags_ &= ~Texture::OWNED_BIT;
|
||||
|
||||
return {index};
|
||||
}
|
||||
|
||||
const u32 index = Cast<u32>(m_Textures.size());
|
||||
if (index < m_MaxCapacity)
|
||||
{
|
||||
Texture *allocatedTexture = &m_Textures.push_back();
|
||||
|
||||
// Ensure it is copyable.
|
||||
static_assert(std::is_trivially_copyable_v<Texture>);
|
||||
*allocatedTexture = *texture;
|
||||
|
||||
texture->m_Flags_ &= ~Texture::OWNED_BIT;
|
||||
|
||||
return {index};
|
||||
}
|
||||
|
||||
ERROR("Out of Buffers") THEN_ABORT(-1);
|
||||
}
|
||||
|
||||
Texture *
|
||||
TextureManager::Fetch(const TextureHandle handle)
|
||||
{
|
||||
assert(!handle.IsInvalid());
|
||||
|
||||
return &m_Textures[handle.m_Index];
|
||||
}
|
||||
|
||||
void
|
||||
TextureManager::Release(const Device *device, const TextureHandle handle)
|
||||
{
|
||||
assert(!handle.IsInvalid());
|
||||
|
||||
Texture *allocatedTexture = &m_Textures[handle.m_Index];
|
||||
allocatedTexture->Destroy(device);
|
||||
|
||||
assert(!allocatedTexture->IsValid());
|
||||
*Recast<u32 *>(allocatedTexture) = m_FreeHead;
|
||||
|
||||
m_FreeHead = handle.m_Index;
|
||||
}
|
||||
|
||||
void
|
||||
TextureManager::Destroy(const Device *device)
|
||||
{
|
||||
for (auto &texture : m_Textures)
|
||||
{
|
||||
texture.Destroy(device);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
BufferManager::Init(const u32 maxCapacity)
|
||||
{
|
||||
m_MaxCapacity = maxCapacity;
|
||||
m_FreeHead = GpuResourceHandle::INVALID_HANDLE;
|
||||
}
|
||||
|
||||
BufferHandle
|
||||
BufferManager::Commit(StorageBuffer *buffer)
|
||||
{
|
||||
ERROR_IF(!buffer || !buffer->IsValid() || !buffer->IsOwned(), "Buffer must be valid and owned for commital")
|
||||
THEN_ABORT(-1);
|
||||
|
||||
if (m_FreeHead != GpuResourceHandle::INVALID_HANDLE)
|
||||
{
|
||||
const u32 index = m_FreeHead;
|
||||
|
||||
StorageBuffer *allocatedBuffer = &m_Buffers[index];
|
||||
|
||||
assert(!allocatedBuffer->IsValid());
|
||||
m_FreeHead = *Recast<u32 *>(allocatedBuffer);
|
||||
|
||||
// Ensure it is copyable.
|
||||
static_assert(std::is_trivially_copyable_v<StorageBuffer>);
|
||||
*allocatedBuffer = *buffer;
|
||||
|
||||
// Take ownership of the buffer.
|
||||
buffer->m_Size_ &= ~StorageBuffer::OWNED_BIT;
|
||||
|
||||
return {index};
|
||||
}
|
||||
|
||||
const u32 index = Cast<u32>(m_Buffers.size());
|
||||
if (index < m_MaxCapacity)
|
||||
{
|
||||
StorageBuffer *allocatedBuffer = &m_Buffers.push_back();
|
||||
|
||||
// Ensure it is copyable.
|
||||
static_assert(std::is_trivially_copyable_v<StorageBuffer>);
|
||||
*allocatedBuffer = *buffer;
|
||||
|
||||
buffer->m_Size_ &= ~StorageBuffer::OWNED_BIT;
|
||||
|
||||
return {index};
|
||||
}
|
||||
|
||||
ERROR("Out of Buffers") THEN_ABORT(-1);
|
||||
}
|
||||
|
||||
StorageBuffer *
|
||||
BufferManager::Fetch(const BufferHandle handle)
|
||||
{
|
||||
assert(!handle.IsInvalid());
|
||||
|
||||
return &m_Buffers[handle.m_Index];
|
||||
}
|
||||
|
||||
void
|
||||
BufferManager::Release(const Device *device, const BufferHandle handle)
|
||||
{
|
||||
assert(!handle.IsInvalid());
|
||||
|
||||
StorageBuffer *allocatedBuffer = &m_Buffers[handle.m_Index];
|
||||
allocatedBuffer->Destroy(device);
|
||||
|
||||
assert(!allocatedBuffer->IsValid());
|
||||
*Recast<u32 *>(allocatedBuffer) = m_FreeHead;
|
||||
|
||||
m_FreeHead = handle.m_Index;
|
||||
}
|
||||
|
||||
void
|
||||
BufferManager::Destroy(const Device *device)
|
||||
{
|
||||
for (auto &buffer : m_Buffers)
|
||||
{
|
||||
buffer.Destroy(device);
|
||||
}
|
||||
}
|
||||
|
||||
StorageTextureHandle
|
||||
StorageTextureManager::Commit(StorageTexture *texture)
|
||||
{
|
||||
const TextureHandle tx = TextureManager::Commit(texture);
|
||||
return {tx.m_Index};
|
||||
}
|
||||
|
||||
StorageTexture *
|
||||
StorageTextureManager::Fetch(const StorageTextureHandle handle)
|
||||
{
|
||||
assert(!handle.IsInvalid());
|
||||
|
||||
return Recast<StorageTexture *>(&m_Textures[handle.m_Index]);
|
||||
}
|
||||
|
||||
void
|
||||
StorageTextureManager::Release(const Device *device, const StorageTextureHandle handle)
|
||||
{
|
||||
TextureManager::Release(device, {handle.m_Index});
|
||||
}
|
||||
|
||||
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 * 0x10))); // 16: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;
|
||||
}
|
||||
|
||||
void
|
||||
SamplerManager::Init(usize size)
|
||||
{
|
||||
m_Samplers.reserve(size);
|
||||
m_SamplerHashes.reserve(size);
|
||||
}
|
||||
|
||||
SamplerHandle
|
||||
SamplerManager::Create(const Device *device, const vk::SamplerCreateInfo *createInfo)
|
||||
{
|
||||
const usize hash = HashSamplerCreateInfo(createInfo);
|
||||
|
||||
for (u32 index = 0; usize samplerHash : m_SamplerHashes)
|
||||
{
|
||||
if (samplerHash == hash)
|
||||
{
|
||||
return {index};
|
||||
}
|
||||
++index;
|
||||
}
|
||||
|
||||
vk::Sampler sampler;
|
||||
AbortIfFailed(device->m_Device.createSampler(createInfo, nullptr, &sampler));
|
||||
const u32 index = Cast<u32>(m_SamplerHashes.size());
|
||||
m_SamplerHashes.push_back(hash);
|
||||
m_Samplers.push_back(sampler);
|
||||
return {index};
|
||||
}
|
||||
|
||||
vk::Sampler
|
||||
SamplerManager::Fetch(const SamplerHandle handle)
|
||||
{
|
||||
assert(!handle.IsInvalid());
|
||||
|
||||
return m_Samplers[handle.m_Index];
|
||||
}
|
||||
|
||||
void
|
||||
SamplerManager::Destroy(const Device *device)
|
||||
{
|
||||
for (const auto &sampler : m_Samplers)
|
||||
{
|
||||
device->m_Device.destroy(sampler, nullptr);
|
||||
}
|
||||
m_Samplers.clear();
|
||||
m_SamplerHashes.clear();
|
||||
}
|
||||
|
||||
GpuResourceManager::WriteInfo::WriteInfo(vk::DescriptorBufferInfo info)
|
||||
: uBufferInfo(info)
|
||||
{
|
||||
}
|
||||
|
||||
GpuResourceManager::WriteInfo::WriteInfo(vk::DescriptorImageInfo info)
|
||||
: uImageInfo(info)
|
||||
{
|
||||
}
|
||||
|
||||
GpuResourceManager::WriteInfo::WriteInfo(vk::BufferView info)
|
||||
: uBufferView(info)
|
||||
{
|
||||
}
|
||||
|
||||
BufferHandle
|
||||
GpuResourceManager::Commit(StorageBuffer *storageBuffer)
|
||||
{
|
||||
const BufferHandle handle = m_BufferManager.Commit(storageBuffer);
|
||||
|
||||
m_WriteInfos.emplace_back(vk::DescriptorBufferInfo{
|
||||
.buffer = storageBuffer->m_Buffer,
|
||||
.offset = 0,
|
||||
.range = storageBuffer->GetSize(),
|
||||
});
|
||||
|
||||
m_Writes.push_back({
|
||||
.dstSet = m_DescriptorSet,
|
||||
.dstBinding = BUFFER_BINDING_INDEX,
|
||||
.dstArrayElement = handle.m_Index,
|
||||
.descriptorCount = 1,
|
||||
.descriptorType = vk::DescriptorType::eStorageBuffer,
|
||||
.pBufferInfo = &m_WriteInfos.back().uBufferInfo,
|
||||
});
|
||||
|
||||
m_WriteOwner.emplace_back(HandleType::eBuffer, handle.m_Index);
|
||||
|
||||
#if !defined(ASTER_NDEBUG)
|
||||
++m_CommitedBufferCount;
|
||||
#endif
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
void
|
||||
GpuResourceManager::Write(const BufferHandle handle, const usize offset, const usize size, const void *data)
|
||||
{
|
||||
m_BufferManager.Fetch(handle)->Write(m_Device, offset, size, data);
|
||||
}
|
||||
|
||||
void
|
||||
GpuResourceManager::EraseWrites(u32 handleIndex, HandleType handleType)
|
||||
{
|
||||
auto writeIter = m_Writes.begin();
|
||||
auto ownerIter = m_WriteOwner.begin();
|
||||
const auto ownerEnd = m_WriteOwner.end();
|
||||
|
||||
while (ownerIter != ownerEnd)
|
||||
{
|
||||
if (ownerIter->first == handleType && ownerIter->second == handleIndex)
|
||||
{
|
||||
*writeIter = m_Writes.back();
|
||||
*ownerIter = m_WriteOwner.back();
|
||||
m_Writes.pop_back();
|
||||
m_WriteOwner.pop_back();
|
||||
return;
|
||||
}
|
||||
|
||||
++ownerIter;
|
||||
++writeIter;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GpuResourceManager::Release(BufferHandle handle)
|
||||
{
|
||||
if (handle.IsInvalid())
|
||||
return;
|
||||
|
||||
EraseWrites(handle.m_Index, HandleType::eBuffer);
|
||||
|
||||
m_BufferManager.Release(m_Device, handle);
|
||||
|
||||
#if !defined(ASTER_NDEBUG)
|
||||
--m_CommitedBufferCount;
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
GpuResourceManager::Release(StorageBuffer *storageBuffer, const BufferHandle handle)
|
||||
{
|
||||
assert(storageBuffer);
|
||||
assert(!storageBuffer->IsValid());
|
||||
|
||||
StorageBuffer *internal = m_BufferManager.Fetch(handle);
|
||||
*storageBuffer = *internal;
|
||||
internal->m_Size_ &= ~StorageBuffer::OWNED_BIT;
|
||||
|
||||
Release(handle);
|
||||
}
|
||||
|
||||
void
|
||||
GpuResourceManager::Release(TextureHandle handle)
|
||||
{
|
||||
if (handle.IsInvalid())
|
||||
return;
|
||||
|
||||
EraseWrites(handle.m_Index, HandleType::eTexture);
|
||||
|
||||
m_TextureManager.Release(m_Device, handle);
|
||||
|
||||
#if !defined(ASTER_NDEBUG)
|
||||
--m_CommitedTextureCount;
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
GpuResourceManager::Release(Texture *texture, TextureHandle handle)
|
||||
{
|
||||
assert(texture);
|
||||
assert(!texture->IsValid());
|
||||
|
||||
Texture *internal = m_TextureManager.Fetch(handle);
|
||||
*texture = *internal;
|
||||
internal->m_Flags_ &= ~Texture::OWNED_BIT;
|
||||
|
||||
Release(handle);
|
||||
}
|
||||
|
||||
TextureHandle
|
||||
GpuResourceManager::CommitTexture(Texture *texture, const SamplerHandle sampler)
|
||||
{
|
||||
TextureHandle handle = m_TextureManager.Commit(texture);
|
||||
|
||||
const vk::Sampler samplerImpl = sampler.IsInvalid() ? m_DefaultSampler : m_SamplerManager.Fetch(sampler);
|
||||
|
||||
m_WriteInfos.emplace_back(vk::DescriptorImageInfo{
|
||||
.sampler = samplerImpl,
|
||||
.imageView = texture->m_View,
|
||||
.imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal,
|
||||
});
|
||||
|
||||
m_Writes.push_back({
|
||||
.dstSet = m_DescriptorSet,
|
||||
.dstBinding = TEXTURE_BINDING_INDEX,
|
||||
.dstArrayElement = handle.m_Index,
|
||||
.descriptorCount = 1,
|
||||
.descriptorType = vk::DescriptorType::eCombinedImageSampler,
|
||||
.pImageInfo = &m_WriteInfos.back().uImageInfo,
|
||||
});
|
||||
|
||||
m_WriteOwner.emplace_back(HandleType::eTexture, handle.m_Index);
|
||||
|
||||
#if !defined(ASTER_NDEBUG)
|
||||
++m_CommitedTextureCount;
|
||||
#endif
|
||||
|
||||
return {handle};
|
||||
}
|
||||
|
||||
StorageTextureHandle
|
||||
GpuResourceManager::CommitStorageTexture(StorageTexture *storageTexture, SamplerHandle sampler)
|
||||
{
|
||||
StorageTextureHandle handle = m_StorageTextureManager.Commit(storageTexture);
|
||||
|
||||
vk::Sampler samplerImpl = sampler.IsInvalid() ? m_DefaultSampler : m_SamplerManager.Fetch(sampler);
|
||||
|
||||
m_WriteInfos.emplace_back(vk::DescriptorImageInfo{
|
||||
.sampler = samplerImpl,
|
||||
.imageView = storageTexture->m_View,
|
||||
.imageLayout = vk::ImageLayout::eGeneral,
|
||||
});
|
||||
|
||||
m_Writes.push_back({
|
||||
.dstSet = m_DescriptorSet,
|
||||
.dstBinding = STORAGE_TEXTURE_BINDING_INDEX,
|
||||
.dstArrayElement = handle.m_Index,
|
||||
.descriptorCount = 1,
|
||||
.descriptorType = vk::DescriptorType::eStorageImage,
|
||||
.pImageInfo = &m_WriteInfos.back().uImageInfo,
|
||||
});
|
||||
|
||||
m_WriteOwner.emplace_back(HandleType::eStorageTexture, handle.m_Index);
|
||||
|
||||
#if !defined(ASTER_NDEBUG)
|
||||
++m_CommitedStorageTextureCount;
|
||||
#endif
|
||||
|
||||
return {handle};
|
||||
}
|
||||
|
||||
void
|
||||
GpuResourceManager::Release(StorageTextureHandle handle)
|
||||
{
|
||||
if (handle.IsInvalid())
|
||||
return;
|
||||
|
||||
EraseWrites(handle.m_Index, HandleType::eTexture);
|
||||
|
||||
m_StorageTextureManager.Release(m_Device, handle);
|
||||
|
||||
#if !defined(ASTER_NDEBUG)
|
||||
--m_CommitedStorageTextureCount;
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
GpuResourceManager::Release(StorageTexture *texture, const StorageTextureHandle handle)
|
||||
{
|
||||
assert(texture);
|
||||
assert(!texture->IsValid());
|
||||
|
||||
StorageTexture *internal = m_StorageTextureManager.Fetch(handle);
|
||||
*texture = *internal;
|
||||
internal->m_Flags_ &= ~StorageTexture::OWNED_BIT;
|
||||
|
||||
Release(handle);
|
||||
}
|
||||
|
||||
void
|
||||
GpuResourceManager::Update()
|
||||
{
|
||||
if (m_Writes.empty() || m_WriteInfos.empty())
|
||||
return;
|
||||
|
||||
m_Device->m_Device.updateDescriptorSets(Cast<u32>(m_Writes.size()), m_Writes.data(), 0, nullptr);
|
||||
|
||||
m_Writes.clear();
|
||||
m_WriteInfos.clear();
|
||||
m_WriteOwner.clear();
|
||||
}
|
||||
|
||||
GpuResourceManager::GpuResourceManager(Device *device, u16 maxSize)
|
||||
: m_Device(device)
|
||||
{
|
||||
vk::PhysicalDeviceProperties properties;
|
||||
m_Device->m_PhysicalDevice.getProperties(&properties);
|
||||
|
||||
u32 buffersCount = eastl::min(properties.limits.maxPerStageDescriptorStorageBuffers - 1024, Cast<u32>(maxSize));
|
||||
u32 texturesCount = eastl::min(properties.limits.maxPerStageDescriptorSampledImages - 1024, Cast<u32>(maxSize));
|
||||
u32 storageTexturesCount =
|
||||
eastl::min(properties.limits.maxPerStageDescriptorStorageImages - 1024, Cast<u32>(maxSize));
|
||||
|
||||
INFO("Max Buffer Count: {}", buffersCount);
|
||||
INFO("Max Texture Count: {}", texturesCount);
|
||||
INFO("Max Storage Texture Count: {}", storageTexturesCount);
|
||||
|
||||
m_BufferManager.Init(buffersCount);
|
||||
m_TextureManager.Init(texturesCount);
|
||||
m_StorageTextureManager.Init(storageTexturesCount);
|
||||
m_SamplerManager.Init(storageTexturesCount);
|
||||
|
||||
m_DefaultSamplerCreateInfo = {
|
||||
.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 = properties.limits.maxSamplerAnisotropy,
|
||||
.compareEnable = false,
|
||||
.minLod = 0,
|
||||
.maxLod = VK_LOD_CLAMP_NONE,
|
||||
.borderColor = vk::BorderColor::eFloatOpaqueBlack,
|
||||
.unnormalizedCoordinates = false,
|
||||
};
|
||||
|
||||
m_DefaultSampler = m_SamplerManager.Fetch(m_SamplerManager.Create(device, &m_DefaultSamplerCreateInfo));
|
||||
|
||||
eastl::array poolSizes = {
|
||||
vk::DescriptorPoolSize{
|
||||
.type = vk::DescriptorType::eStorageBuffer,
|
||||
.descriptorCount = buffersCount,
|
||||
},
|
||||
vk::DescriptorPoolSize{
|
||||
.type = vk::DescriptorType::eCombinedImageSampler,
|
||||
.descriptorCount = texturesCount,
|
||||
},
|
||||
vk::DescriptorPoolSize{
|
||||
.type = vk::DescriptorType::eStorageImage,
|
||||
.descriptorCount = storageTexturesCount,
|
||||
},
|
||||
};
|
||||
|
||||
const vk::DescriptorPoolCreateInfo poolCreateInfo = {
|
||||
.flags = vk::DescriptorPoolCreateFlagBits::eUpdateAfterBind,
|
||||
.maxSets = 1,
|
||||
.poolSizeCount = Cast<u32>(poolSizes.size()),
|
||||
.pPoolSizes = poolSizes.data(),
|
||||
};
|
||||
AbortIfFailed(device->m_Device.createDescriptorPool(&poolCreateInfo, nullptr, &m_DescriptorPool));
|
||||
|
||||
vk::DescriptorBindingFlags bindingFlags =
|
||||
vk::DescriptorBindingFlagBits::ePartiallyBound | vk::DescriptorBindingFlagBits::eUpdateAfterBind;
|
||||
eastl::array layoutBindingFlags = {
|
||||
bindingFlags,
|
||||
bindingFlags,
|
||||
bindingFlags,
|
||||
};
|
||||
|
||||
vk::DescriptorSetLayoutBindingFlagsCreateInfo bindingFlagsCreateInfo = {
|
||||
.bindingCount = Cast<u32>(layoutBindingFlags.size()),
|
||||
.pBindingFlags = layoutBindingFlags.data(),
|
||||
};
|
||||
|
||||
eastl::array descriptorLayoutBindings = {
|
||||
vk::DescriptorSetLayoutBinding{
|
||||
.binding = BUFFER_BINDING_INDEX,
|
||||
.descriptorType = vk::DescriptorType::eStorageBuffer,
|
||||
.descriptorCount = Cast<u32>(buffersCount),
|
||||
.stageFlags = vk::ShaderStageFlagBits::eAll,
|
||||
},
|
||||
vk::DescriptorSetLayoutBinding{
|
||||
.binding = TEXTURE_BINDING_INDEX,
|
||||
.descriptorType = vk::DescriptorType::eCombinedImageSampler,
|
||||
.descriptorCount = Cast<u32>(texturesCount),
|
||||
.stageFlags = vk::ShaderStageFlagBits::eAll,
|
||||
},
|
||||
vk::DescriptorSetLayoutBinding{
|
||||
.binding = STORAGE_TEXTURE_BINDING_INDEX,
|
||||
.descriptorType = vk::DescriptorType::eStorageImage,
|
||||
.descriptorCount = Cast<u32>(storageTexturesCount),
|
||||
.stageFlags = vk::ShaderStageFlagBits::eAll,
|
||||
},
|
||||
};
|
||||
static_assert(layoutBindingFlags.size() == descriptorLayoutBindings.size());
|
||||
const vk::DescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo = {
|
||||
.pNext = &bindingFlagsCreateInfo,
|
||||
.flags = vk::DescriptorSetLayoutCreateFlagBits::eUpdateAfterBindPool,
|
||||
.bindingCount = Cast<u32>(descriptorLayoutBindings.size()),
|
||||
.pBindings = descriptorLayoutBindings.data(),
|
||||
};
|
||||
AbortIfFailed(device->m_Device.createDescriptorSetLayout(&descriptorSetLayoutCreateInfo, nullptr, &m_SetLayout));
|
||||
|
||||
// One descriptor is enough. Updating it at any time is safe. (Update until submit, data held when pending)
|
||||
// https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_descriptor_indexing.html
|
||||
// https://github.com/KhronosGroup/Vulkan-Guide/blob/main/chapters/extensions/VK_EXT_descriptor_indexing.adoc
|
||||
const vk::DescriptorSetAllocateInfo descriptorSetAllocateInfo = {
|
||||
.descriptorPool = m_DescriptorPool,
|
||||
.descriptorSetCount = 1,
|
||||
.pSetLayouts = &m_SetLayout,
|
||||
};
|
||||
AbortIfFailed(device->m_Device.allocateDescriptorSets(&descriptorSetAllocateInfo, &m_DescriptorSet));
|
||||
|
||||
m_Device->SetName(m_SetLayout, "Bindless Layout");
|
||||
m_Device->SetName(m_DescriptorPool, "Bindless Pool");
|
||||
m_Device->SetName(m_DescriptorSet, "Bindless Set");
|
||||
}
|
||||
|
||||
GpuResourceManager::~GpuResourceManager()
|
||||
{
|
||||
#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_BufferManager.Destroy(m_Device);
|
||||
m_TextureManager.Destroy(m_Device);
|
||||
m_StorageTextureManager.Destroy(m_Device);
|
||||
m_SamplerManager.Destroy(m_Device);
|
||||
m_Device->m_Device.destroy(m_DescriptorPool, nullptr);
|
||||
m_Device->m_Device.destroy(m_SetLayout, nullptr);
|
||||
}
|
||||
|
||||
GpuResourceManager::GpuResourceManager(GpuResourceManager &&other) noexcept
|
||||
: m_WriteInfos(std::move(other.m_WriteInfos))
|
||||
, m_Writes(std::move(other.m_Writes))
|
||||
, m_WriteOwner(std::move(other.m_WriteOwner))
|
||||
, m_BufferManager(std::move(other.m_BufferManager))
|
||||
, m_TextureManager(std::move(other.m_TextureManager))
|
||||
, m_StorageTextureManager(std::move(other.m_StorageTextureManager))
|
||||
, m_SamplerManager(std::move(other.m_SamplerManager))
|
||||
, m_Device(Take(other.m_Device))
|
||||
, m_DescriptorPool(other.m_DescriptorPool)
|
||||
, m_SetLayout(other.m_SetLayout)
|
||||
, m_DescriptorSet(other.m_DescriptorSet)
|
||||
#if !defined(ASTER_NDEBUG)
|
||||
, m_CommitedBufferCount(other.m_CommitedBufferCount)
|
||||
, m_CommitedTextureCount(other.m_CommitedTextureCount)
|
||||
, m_CommitedStorageTextureCount(other.m_CommitedStorageTextureCount)
|
||||
#endif
|
||||
{
|
||||
assert(!other.m_Device);
|
||||
}
|
||||
|
||||
GpuResourceManager &
|
||||
GpuResourceManager::operator=(GpuResourceManager &&other) noexcept
|
||||
{
|
||||
if (this == &other)
|
||||
return *this;
|
||||
m_WriteInfos = std::move(other.m_WriteInfos);
|
||||
m_Writes = std::move(other.m_Writes);
|
||||
m_WriteOwner = std::move(other.m_WriteOwner);
|
||||
m_BufferManager = std::move(other.m_BufferManager);
|
||||
m_TextureManager = std::move(other.m_TextureManager);
|
||||
m_StorageTextureManager = std::move(other.m_StorageTextureManager);
|
||||
m_SamplerManager = std::move(other.m_SamplerManager);
|
||||
m_Device = Take(other.m_Device); // Ensure taken.
|
||||
m_DescriptorPool = other.m_DescriptorPool;
|
||||
m_SetLayout = other.m_SetLayout;
|
||||
m_DescriptorSet = other.m_DescriptorSet;
|
||||
#if !defined(ASTER_NDEBUG)
|
||||
m_CommitedBufferCount = other.m_CommitedBufferCount;
|
||||
m_CommitedTextureCount = other.m_CommitedTextureCount;
|
||||
m_CommitedStorageTextureCount = other.m_CommitedStorageTextureCount;
|
||||
#endif
|
||||
|
||||
assert(!other.m_Device);
|
||||
return *this;
|
||||
}
|
||||
|
||||
SamplerHandle
|
||||
GpuResourceManager::CreateSampler(const vk::SamplerCreateInfo *samplerCreateInfo)
|
||||
{
|
||||
return m_SamplerManager.Create(m_Device, samplerCreateInfo);
|
||||
}
|
||||
|
|
@ -1,175 +0,0 @@
|
|||
// =============================================
|
||||
// Aster: gpu_resource_manager.h
|
||||
// Copyright (c) 2020-2024 Anish Bhobe
|
||||
// =============================================
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "aster/aster.h"
|
||||
|
||||
#include <EASTL/deque.h>
|
||||
#include <EASTL/vector_map.h>
|
||||
|
||||
struct Device;
|
||||
struct Texture;
|
||||
struct StorageTexture;
|
||||
struct StorageBuffer;
|
||||
|
||||
struct GpuResourceHandle
|
||||
{
|
||||
constexpr static u32 INVALID_HANDLE = MaxValue<u32>;
|
||||
u32 m_Index = INVALID_HANDLE; // Default = invalid
|
||||
|
||||
[[nodiscard]] bool
|
||||
IsInvalid() const
|
||||
{
|
||||
return m_Index == INVALID_HANDLE;
|
||||
}
|
||||
};
|
||||
|
||||
struct BufferHandle : GpuResourceHandle
|
||||
{
|
||||
};
|
||||
|
||||
struct TextureHandle : GpuResourceHandle
|
||||
{
|
||||
};
|
||||
|
||||
struct StorageTextureHandle : GpuResourceHandle
|
||||
{
|
||||
};
|
||||
|
||||
struct SamplerHandle : GpuResourceHandle
|
||||
{
|
||||
};
|
||||
|
||||
struct TextureManager
|
||||
{
|
||||
eastl::vector<Texture> m_Textures;
|
||||
u32 m_MaxCapacity;
|
||||
u32 m_FreeHead;
|
||||
|
||||
void Init(u32 maxCapacity);
|
||||
TextureHandle Commit(Texture *texture);
|
||||
Texture *Fetch(TextureHandle handle);
|
||||
void Release(const Device *device, TextureHandle handle);
|
||||
void Destroy(const Device *device);
|
||||
};
|
||||
|
||||
struct BufferManager
|
||||
{
|
||||
eastl::vector<StorageBuffer> m_Buffers;
|
||||
u32 m_MaxCapacity;
|
||||
u32 m_FreeHead;
|
||||
|
||||
void Init(u32 maxCapacity);
|
||||
BufferHandle Commit(StorageBuffer *buffer);
|
||||
StorageBuffer *Fetch(BufferHandle handle);
|
||||
void Release(const Device *device, BufferHandle handle);
|
||||
void Destroy(const Device *device);
|
||||
};
|
||||
|
||||
struct StorageTextureManager : TextureManager
|
||||
{
|
||||
StorageTextureHandle Commit(StorageTexture *texture);
|
||||
StorageTexture *Fetch(StorageTextureHandle handle);
|
||||
void Release(const Device *device, StorageTextureHandle handle);
|
||||
};
|
||||
|
||||
struct SamplerManager
|
||||
{
|
||||
// There can only be so many samplers.
|
||||
eastl::vector<vk::Sampler> m_Samplers;
|
||||
eastl::vector<usize> m_SamplerHashes;
|
||||
|
||||
void Init(usize size);
|
||||
SamplerHandle Create(const Device *device, const vk::SamplerCreateInfo *createInfo);
|
||||
vk::Sampler Fetch(SamplerHandle handle);
|
||||
void Destroy(const Device *device);
|
||||
};
|
||||
|
||||
struct GpuResourceManager
|
||||
{
|
||||
private:
|
||||
union WriteInfo {
|
||||
vk::DescriptorBufferInfo uBufferInfo;
|
||||
vk::DescriptorImageInfo uImageInfo;
|
||||
vk::BufferView uBufferView;
|
||||
|
||||
WriteInfo()
|
||||
{
|
||||
}
|
||||
|
||||
explicit WriteInfo(vk::DescriptorBufferInfo info);
|
||||
explicit WriteInfo(vk::DescriptorImageInfo info);
|
||||
explicit WriteInfo(vk::BufferView info);
|
||||
};
|
||||
|
||||
enum class HandleType
|
||||
{
|
||||
eBuffer,
|
||||
eTexture,
|
||||
eStorageTexture,
|
||||
};
|
||||
|
||||
using WriteOwner = eastl::pair<HandleType, u32>;
|
||||
|
||||
eastl::deque<WriteInfo> m_WriteInfos;
|
||||
eastl::vector<vk::WriteDescriptorSet> m_Writes;
|
||||
eastl::vector<WriteOwner> m_WriteOwner;
|
||||
|
||||
vk::Sampler m_DefaultSampler;
|
||||
|
||||
BufferManager m_BufferManager;
|
||||
TextureManager m_TextureManager;
|
||||
StorageTextureManager m_StorageTextureManager;
|
||||
SamplerManager m_SamplerManager;
|
||||
|
||||
void EraseWrites(u32 handleIndex, HandleType handleType);
|
||||
|
||||
public:
|
||||
Device *m_Device;
|
||||
|
||||
constexpr static u32 BUFFER_BINDING_INDEX = 0;
|
||||
constexpr static u32 TEXTURE_BINDING_INDEX = 1;
|
||||
constexpr static u32 STORAGE_TEXTURE_BINDING_INDEX = 2;
|
||||
|
||||
vk::SamplerCreateInfo m_DefaultSamplerCreateInfo;
|
||||
|
||||
vk::DescriptorPool m_DescriptorPool;
|
||||
vk::DescriptorSetLayout m_SetLayout;
|
||||
vk::DescriptorSet m_DescriptorSet;
|
||||
|
||||
BufferHandle Commit(StorageBuffer *storageBuffer); // Commit to GPU and take Ownership
|
||||
void Write(BufferHandle handle, usize offset, usize size, const void *data); // Write to buffer
|
||||
void Release(BufferHandle handle); // Release and Destroy
|
||||
void Release(StorageBuffer *storageBuffer, BufferHandle handle); // Release and Return
|
||||
|
||||
TextureHandle CommitTexture(Texture *texture, SamplerHandle sampler = {}); // Commit to GPU and take Ownership
|
||||
void Release(TextureHandle handle); // Release and Destroy
|
||||
void Release(Texture *texture, TextureHandle handle); // Release and Return
|
||||
|
||||
StorageTextureHandle
|
||||
CommitStorageTexture(StorageTexture *storageTexture, SamplerHandle sampler = {}); // Commit to GPU and take Ownership
|
||||
void Release(StorageTextureHandle handle); // Release and Destroy
|
||||
void Release(StorageTexture *texture, StorageTextureHandle handle); // Release and Return
|
||||
|
||||
SamplerHandle CreateSampler(const vk::SamplerCreateInfo *samplerCreateInfo);
|
||||
|
||||
void Update(); // Update all the descriptors required.
|
||||
|
||||
// Ctor/Dtor
|
||||
GpuResourceManager(Device *device, u16 maxSize);
|
||||
~GpuResourceManager();
|
||||
|
||||
GpuResourceManager(GpuResourceManager &&other) noexcept;
|
||||
GpuResourceManager &operator=(GpuResourceManager &&other) noexcept;
|
||||
|
||||
#if !defined(ASTER_NDEBUG)
|
||||
usize m_CommitedBufferCount = 0;
|
||||
usize m_CommitedTextureCount = 0;
|
||||
usize m_CommitedStorageTextureCount = 0;
|
||||
#endif
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(GpuResourceManager);
|
||||
};
|
||||
|
|
@ -9,10 +9,12 @@
|
|||
#include "aster/core/image.h"
|
||||
|
||||
#include "asset_loader.h"
|
||||
#include "gpu_resource_manager.h"
|
||||
#include "helpers.h"
|
||||
#include "pipeline_utils.h"
|
||||
|
||||
#include "aster/systems/commit_manager.h"
|
||||
#include "aster/systems/resource_manager.h"
|
||||
|
||||
#include <EASTL/fixed_vector.h>
|
||||
#include <EASTL/tuple.h>
|
||||
|
||||
|
|
@ -21,70 +23,86 @@ constexpr cstr DIFFUSE_IRRADIANCE_SHADER_FILE = "shader/diffuse_irradiance.cs.hl
|
|||
constexpr cstr PREFILTER_SHADER_FILE = "shader/prefilter.cs.hlsl.spv";
|
||||
constexpr cstr BRDF_LUT_SHADER_FILE = "shader/brdf_lut.cs.hlsl.spv";
|
||||
|
||||
void
|
||||
Environment::Destroy(GpuResourceManager *resourceManager)
|
||||
{
|
||||
resourceManager->Release(Take(m_Skybox));
|
||||
resourceManager->Release(Take(m_Diffuse));
|
||||
resourceManager->Release(Take(m_Prefilter));
|
||||
resourceManager->Release(Take(m_BrdfLut));
|
||||
}
|
||||
|
||||
Environment
|
||||
CreateCubeFromHdrEnv(AssetLoader *assetLoader, vk::Queue computeQueue, const u32 cubeSide, TextureHandle hdrEnv,
|
||||
const cstr name)
|
||||
CreateCubeFromHdrEnv(AssetLoader *assetLoader, vk::Queue computeQueue, const u32 cubeSide,
|
||||
systems::ResId<Texture> hdrEnv, const cstr name)
|
||||
{
|
||||
GpuResourceManager *resMan = assetLoader->m_ResourceManager;
|
||||
const Device *pDevice = resMan->m_Device;
|
||||
systems::ResourceManager *resourceManager = assetLoader->m_ResourceManager;
|
||||
systems::CommitManager *commitManager = assetLoader->m_CommitManager;
|
||||
const Device *pDevice = commitManager->m_Device;
|
||||
|
||||
vk::SamplerCreateInfo brdfLutSamplerCreateInfo = resMan->m_DefaultSamplerCreateInfo;
|
||||
brdfLutSamplerCreateInfo.addressModeU = vk::SamplerAddressMode::eClampToEdge;
|
||||
brdfLutSamplerCreateInfo.addressModeV = vk::SamplerAddressMode::eClampToEdge;
|
||||
brdfLutSamplerCreateInfo.addressModeW = vk::SamplerAddressMode::eClampToEdge;
|
||||
auto skybox = resourceManager->Images().CreateTextureCube<StorageTexture>({
|
||||
.m_Format = vk::Format::eR16G16B16A16Sfloat,
|
||||
.m_Side = cubeSide,
|
||||
.m_Name = "Skybox",
|
||||
.m_IsSampled = true,
|
||||
.m_IsMipMapped = true,
|
||||
.m_IsStorage = true,
|
||||
});
|
||||
|
||||
StorageTextureCube skybox;
|
||||
StorageTextureCube diffuseIrradiance;
|
||||
StorageTextureCube prefilterCube;
|
||||
StorageTexture brdfLut;
|
||||
SamplerHandle brdfLutSampler;
|
||||
auto skyboxHandle = commitManager->CommitTexture(skybox);
|
||||
auto skyboxStorageHandle = commitManager->CommitStorageImage(skybox);
|
||||
|
||||
skybox.Init(pDevice, cubeSide, vk::Format::eR16G16B16A16Sfloat, true, true, "Skybox");
|
||||
TextureHandle skyboxHandle = resMan->CommitTexture(&skybox);
|
||||
StorageTextureHandle skyboxStorageHandle = resMan->CommitStorageTexture(&skybox);
|
||||
auto diffuseIrradiance = resourceManager->Images().CreateTextureCube<StorageTexture>({
|
||||
.m_Format = vk::Format::eR16G16B16A16Sfloat,
|
||||
.m_Side = 64,
|
||||
.m_Name = "Diffuse Irradiance",
|
||||
.m_IsSampled = true,
|
||||
.m_IsMipMapped = false,
|
||||
.m_IsStorage = true,
|
||||
});
|
||||
auto diffuseIrradianceHandle = commitManager->CommitTexture(diffuseIrradiance);
|
||||
auto diffuseIrradianceStorageHandle = commitManager->CommitStorageImage(diffuseIrradiance);
|
||||
|
||||
diffuseIrradiance.Init(pDevice, 64, vk::Format::eR16G16B16A16Sfloat, true, false, "Diffuse Irradiance");
|
||||
TextureHandle diffuseIrradianceHandle = resMan->CommitTexture(&diffuseIrradiance);
|
||||
StorageTextureHandle diffuseIrradianceStorageHandle = resMan->CommitStorageTexture(&diffuseIrradiance);
|
||||
|
||||
prefilterCube.Init(pDevice, cubeSide, vk::Format::eR16G16B16A16Sfloat, true, true, "Prefilter");
|
||||
TextureHandle prefilterHandle = resMan->CommitTexture(&prefilterCube); // This stores the original view for us.
|
||||
auto prefilterCube = resourceManager->Images().CreateTextureCube<StorageTextureCube>({
|
||||
.m_Format = vk::Format::eR16G16B16A16Sfloat,
|
||||
.m_Side = cubeSide,
|
||||
.m_Name = "Prefilter",
|
||||
.m_IsSampled = true,
|
||||
.m_IsMipMapped = true,
|
||||
.m_IsStorage = true,
|
||||
});
|
||||
auto prefilterHandle = commitManager->CommitTexture(prefilterCube); // This stores the original view for us.
|
||||
constexpr u32 prefilterMipCountMax = 6;
|
||||
eastl::array<StorageTextureHandle, prefilterMipCountMax> prefilterStorageHandles;
|
||||
eastl::fixed_vector<systems::ResId<StorageImage>, prefilterMipCountMax> prefilterStorageHandles;
|
||||
// All non-owning copies.
|
||||
for (u32 mipLevel = 0; auto &tex : prefilterStorageHandles)
|
||||
for (u32 mipLevel = 0; mipLevel < prefilterMipCountMax; ++mipLevel)
|
||||
{
|
||||
vk::ImageViewCreateInfo imageViewCreateInfo = {
|
||||
.image = prefilterCube.m_Image,
|
||||
.image = prefilterCube->m_Image,
|
||||
.viewType = vk::ImageViewType::eCube,
|
||||
.format = vk::Format::eR16G16B16A16Sfloat,
|
||||
.components = vk::ComponentMapping{},
|
||||
.subresourceRange =
|
||||
{
|
||||
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||
.baseMipLevel = mipLevel++,
|
||||
.baseMipLevel = mipLevel,
|
||||
.levelCount = 1,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = 6,
|
||||
},
|
||||
};
|
||||
AbortIfFailed(pDevice->m_Device.createImageView(&imageViewCreateInfo, nullptr, &prefilterCube.m_View));
|
||||
tex = resMan->CommitStorageTexture(&prefilterCube);
|
||||
AbortIfFailed(pDevice->m_Device.createImageView(&imageViewCreateInfo, nullptr, &prefilterCube->m_View));
|
||||
// TODO: FIXME: This is an issue. This needs copying but we don't do that anymore.
|
||||
// The views need to be separated from the images.
|
||||
TODO("This is bad");
|
||||
prefilterStorageHandles.push_back(commitManager->CommitStorageImage(prefilterCube));
|
||||
}
|
||||
|
||||
brdfLut.Init(pDevice, {512, 512}, vk::Format::eR16G16Sfloat, true, "BRDF LUT");
|
||||
brdfLutSampler = resMan->CreateSampler(&brdfLutSamplerCreateInfo);
|
||||
TextureHandle brdfLutHandle = resMan->CommitTexture(&brdfLut, brdfLutSampler);
|
||||
StorageTextureHandle brdfLutStorageHandle = resMan->CommitStorageTexture(&brdfLut);
|
||||
auto brdfLut = resourceManager->Images().CreateTexture2D<StorageTexture>({.m_Format = vk::Format::eR16G16Sfloat,
|
||||
.m_Extent = {512, 512},
|
||||
.m_Name = "BRDF LUT",
|
||||
.m_IsSampled = true,
|
||||
.m_IsMipMapped = true,
|
||||
.m_IsStorage = true});
|
||||
|
||||
auto brdfLutSampler = resourceManager->Samplers().CreateSampler({
|
||||
.m_AddressModeU = vk::SamplerAddressMode::eClampToEdge,
|
||||
.m_AddressModeV = vk::SamplerAddressMode::eClampToEdge,
|
||||
.m_AddressModeW = vk::SamplerAddressMode::eClampToEdge,
|
||||
});
|
||||
auto brdfLutHandle = commitManager->CommitTexture(brdfLut, brdfLutSampler);
|
||||
auto brdfLutStorageHandle = commitManager->CommitStorageImage(brdfLut);
|
||||
|
||||
#pragma region Dependencies and Copies
|
||||
vk::ImageSubresourceRange cubeSubresRange = {
|
||||
|
|
@ -114,10 +132,10 @@ CreateCubeFromHdrEnv(AssetLoader *assetLoader, vk::Queue computeQueue, const u32
|
|||
.subresourceRange = cubeSubresRange,
|
||||
};
|
||||
eastl::fixed_vector<vk::ImageMemoryBarrier2, 4> readyToWriteBarriers(4, readyToWriteBarrierTemplate);
|
||||
readyToWriteBarriers[0].image = skybox.m_Image;
|
||||
readyToWriteBarriers[1].image = diffuseIrradiance.m_Image;
|
||||
readyToWriteBarriers[2].image = prefilterCube.m_Image;
|
||||
readyToWriteBarriers[3].image = brdfLut.m_Image;
|
||||
readyToWriteBarriers[0].image = skybox->m_Image;
|
||||
readyToWriteBarriers[1].image = diffuseIrradiance->m_Image;
|
||||
readyToWriteBarriers[2].image = prefilterCube->m_Image;
|
||||
readyToWriteBarriers[3].image = brdfLut->m_Image;
|
||||
readyToWriteBarriers[3].subresourceRange = lutSubresRange;
|
||||
|
||||
vk::DependencyInfo readyToWriteDependency = {
|
||||
|
|
@ -136,16 +154,16 @@ CreateCubeFromHdrEnv(AssetLoader *assetLoader, vk::Queue computeQueue, const u32
|
|||
.subresourceRange = cubeSubresRange,
|
||||
};
|
||||
auto skyboxToSampleBarrier = readyToSampleBarrierTemplate;
|
||||
skyboxToSampleBarrier.image = skybox.m_Image;
|
||||
skyboxToSampleBarrier.image = skybox->m_Image;
|
||||
|
||||
auto diffIrrToSampleBarrier = readyToSampleBarrierTemplate;
|
||||
diffIrrToSampleBarrier.image = diffuseIrradiance.m_Image;
|
||||
diffIrrToSampleBarrier.image = diffuseIrradiance->m_Image;
|
||||
|
||||
auto prefilterToSampleBarrier = readyToSampleBarrierTemplate;
|
||||
prefilterToSampleBarrier.image = prefilterCube.m_Image;
|
||||
prefilterToSampleBarrier.image = prefilterCube->m_Image;
|
||||
|
||||
auto brdfToSampleBarrier = readyToSampleBarrierTemplate;
|
||||
prefilterToSampleBarrier.image = brdfLut.m_Image;
|
||||
prefilterToSampleBarrier.image = brdfLut->m_Image;
|
||||
prefilterToSampleBarrier.subresourceRange = lutSubresRange;
|
||||
|
||||
vk::DependencyInfo skyboxToSampleDependency = {
|
||||
|
|
@ -169,27 +187,27 @@ CreateCubeFromHdrEnv(AssetLoader *assetLoader, vk::Queue computeQueue, const u32
|
|||
|
||||
struct SkyboxPushConstants
|
||||
{
|
||||
TextureHandle m_HdrEnvHandle;
|
||||
StorageTextureHandle m_OutputTexture;
|
||||
systems::ResId<Texture> m_HdrEnvHandle;
|
||||
systems::ResId<StorageImage> m_OutputTexture;
|
||||
u32 m_CubeSide;
|
||||
};
|
||||
struct DiffuseIrradiancePushConstants
|
||||
{
|
||||
TextureHandle m_SkyboxHandle;
|
||||
StorageTextureHandle m_OutputTexture;
|
||||
systems::ResId<Texture> m_SkyboxHandle;
|
||||
systems::ResId<StorageImage> m_OutputTexture;
|
||||
u32 m_CubeSide;
|
||||
};
|
||||
struct PrefilterPushConstants
|
||||
{
|
||||
TextureHandle m_SkyboxHandle;
|
||||
StorageTextureHandle m_OutputTexture;
|
||||
systems::ResId<Texture> m_SkyboxHandle;
|
||||
systems::ResId<StorageImage> m_OutputTexture;
|
||||
u32 m_CubeSide;
|
||||
f32 m_Roughness;
|
||||
u32 m_EnvSide;
|
||||
};
|
||||
struct BrdfLutPushConstants
|
||||
{
|
||||
StorageTextureHandle m_OutputTexture;
|
||||
systems::ResId<StorageImage> m_OutputTexture;
|
||||
};
|
||||
|
||||
#pragma region Pipeline Creation etc
|
||||
|
|
@ -197,14 +215,15 @@ CreateCubeFromHdrEnv(AssetLoader *assetLoader, vk::Queue computeQueue, const u32
|
|||
vk::PushConstantRange pcr = {
|
||||
.stageFlags = vk::ShaderStageFlagBits::eCompute,
|
||||
.offset = 0,
|
||||
.size = Cast<u32>(eastl::max(eastl::max(sizeof(SkyboxPushConstants), sizeof(BrdfLutPushConstants)),
|
||||
eastl::max(sizeof(DiffuseIrradiancePushConstants), sizeof(PrefilterPushConstants)))),
|
||||
.size =
|
||||
Cast<u32>(eastl::max(eastl::max(sizeof(SkyboxPushConstants), sizeof(BrdfLutPushConstants)),
|
||||
eastl::max(sizeof(DiffuseIrradiancePushConstants), sizeof(PrefilterPushConstants)))),
|
||||
};
|
||||
|
||||
vk::PipelineLayout pipelineLayout;
|
||||
const vk::PipelineLayoutCreateInfo layoutCreateInfo = {
|
||||
.setLayoutCount = 1,
|
||||
.pSetLayouts = &resMan->m_SetLayout,
|
||||
.pSetLayouts = &commitManager->GetDescriptorSetLayout(),
|
||||
.pushConstantRangeCount = 1,
|
||||
.pPushConstantRanges = &pcr,
|
||||
};
|
||||
|
|
@ -254,9 +273,9 @@ CreateCubeFromHdrEnv(AssetLoader *assetLoader, vk::Queue computeQueue, const u32
|
|||
};
|
||||
|
||||
eastl::array<vk::Pipeline, computePipelineCreateInfo.size()> pipelines;
|
||||
AbortIfFailed(pDevice->m_Device.createComputePipelines(pDevice->m_PipelineCache, Cast<u32>(computePipelineCreateInfo.size()),
|
||||
computePipelineCreateInfo.data(), nullptr,
|
||||
pipelines.data()));
|
||||
AbortIfFailed(
|
||||
pDevice->m_Device.createComputePipelines(pDevice->m_PipelineCache, Cast<u32>(computePipelineCreateInfo.size()),
|
||||
computePipelineCreateInfo.data(), nullptr, pipelines.data()));
|
||||
|
||||
vk::Pipeline eqRectToCubePipeline = pipelines[0];
|
||||
vk::Pipeline diffuseIrradiancePipeline = pipelines[1];
|
||||
|
|
@ -278,17 +297,18 @@ CreateCubeFromHdrEnv(AssetLoader *assetLoader, vk::Queue computeQueue, const u32
|
|||
DiffuseIrradiancePushConstants diffuseIrradiancePushConstants = {
|
||||
.m_SkyboxHandle = skyboxHandle,
|
||||
.m_OutputTexture = diffuseIrradianceStorageHandle,
|
||||
.m_CubeSide = diffuseIrradiance.m_Extent.width,
|
||||
.m_CubeSide = diffuseIrradiance->m_Extent.width,
|
||||
};
|
||||
PrefilterPushConstants prefilterPushConstants = {
|
||||
.m_SkyboxHandle = skyboxHandle,
|
||||
.m_OutputTexture = systems::NullId{},
|
||||
.m_EnvSide = cubeSide,
|
||||
};
|
||||
BrdfLutPushConstants brdfLutPushConstants = {
|
||||
.m_OutputTexture = brdfLutStorageHandle,
|
||||
};
|
||||
|
||||
resMan->Update();
|
||||
commitManager->Update();
|
||||
|
||||
auto cmd = assetLoader->m_CommandBuffer;
|
||||
constexpr vk::CommandBufferBeginInfo beginInfo = {.flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit};
|
||||
|
|
@ -306,26 +326,27 @@ CreateCubeFromHdrEnv(AssetLoader *assetLoader, vk::Queue computeQueue, const u32
|
|||
|
||||
cmd.pipelineBarrier2(&readyToWriteDependency);
|
||||
|
||||
cmd.bindDescriptorSets(vk::PipelineBindPoint::eCompute, pipelineLayout, 0, 1, &resMan->m_DescriptorSet, 0, nullptr);
|
||||
cmd.bindDescriptorSets(vk::PipelineBindPoint::eCompute, pipelineLayout, 0, 1, &commitManager->GetDescriptorSet(), 0,
|
||||
nullptr);
|
||||
cmd.bindPipeline(vk::PipelineBindPoint::eCompute, eqRectToCubePipeline);
|
||||
cmd.pushConstants(pipelineLayout, vk::ShaderStageFlagBits::eCompute, 0, sizeof skyboxPushConstant,
|
||||
&skyboxPushConstant);
|
||||
assert(skybox.m_Extent.width % 16 == 0 && skybox.m_Extent.height % 16 == 0);
|
||||
cmd.dispatch(skybox.m_Extent.width / 16, skybox.m_Extent.height / 16, 6);
|
||||
assert(skybox->m_Extent.width % 16 == 0 && skybox->m_Extent.height % 16 == 0);
|
||||
cmd.dispatch(skybox->m_Extent.width / 16, skybox->m_Extent.height / 16, 6);
|
||||
|
||||
GenerateMipMaps(cmd, &skybox, vk::ImageLayout::eGeneral, vk::ImageLayout::eGeneral,
|
||||
GenerateMipMaps(cmd, skybox, vk::ImageLayout::eGeneral, vk::ImageLayout::eGeneral,
|
||||
vk::PipelineStageFlagBits2::eComputeShader, vk::PipelineStageFlagBits2::eComputeShader);
|
||||
|
||||
cmd.bindPipeline(vk::PipelineBindPoint::eCompute, diffuseIrradiancePipeline);
|
||||
cmd.pushConstants(pipelineLayout, vk::ShaderStageFlagBits::eCompute, 0, sizeof skyboxPushConstant,
|
||||
&diffuseIrradiancePushConstants);
|
||||
assert(diffuseIrradiance.m_Extent.width % 16 == 0 && diffuseIrradiance.m_Extent.height % 16 == 0);
|
||||
cmd.dispatch(diffuseIrradiance.m_Extent.width / 16, diffuseIrradiance.m_Extent.width / 16, 6);
|
||||
assert(diffuseIrradiance->m_Extent.width % 16 == 0 && diffuseIrradiance->m_Extent.height % 16 == 0);
|
||||
cmd.dispatch(diffuseIrradiance->m_Extent.width / 16, diffuseIrradiance->m_Extent.width / 16, 6);
|
||||
|
||||
cmd.pipelineBarrier2(&diffIrrToSampleDependency);
|
||||
|
||||
cmd.bindPipeline(vk::PipelineBindPoint::eCompute, prefilterPipeline);
|
||||
u32 mipSize = prefilterCube.m_Extent.width;
|
||||
u32 mipSize = prefilterCube->m_Extent.width;
|
||||
assert(mipSize % 16 == 0);
|
||||
for (u32 mipCount = 0; auto &tex : prefilterStorageHandles)
|
||||
{
|
||||
|
|
@ -347,8 +368,8 @@ CreateCubeFromHdrEnv(AssetLoader *assetLoader, vk::Queue computeQueue, const u32
|
|||
cmd.bindPipeline(vk::PipelineBindPoint::eCompute, brdfLutPipeline);
|
||||
cmd.pushConstants(pipelineLayout, vk::ShaderStageFlagBits::eCompute, 0, sizeof brdfLutPushConstants,
|
||||
&brdfLutPushConstants);
|
||||
assert(brdfLut.m_Extent.width % 16 == 0 && brdfLut.m_Extent.height % 16 == 0);
|
||||
cmd.dispatch(brdfLut.m_Extent.width / 16, brdfLut.m_Extent.height / 16, 1);
|
||||
assert(brdfLut->m_Extent.width % 16 == 0 && brdfLut->m_Extent.height % 16 == 0);
|
||||
cmd.dispatch(brdfLut->m_Extent.width / 16, brdfLut->m_Extent.height / 16, 1);
|
||||
|
||||
#if !defined(ASTER_NDEBUG)
|
||||
cmd.endDebugUtilsLabelEXT();
|
||||
|
|
@ -373,13 +394,10 @@ CreateCubeFromHdrEnv(AssetLoader *assetLoader, vk::Queue computeQueue, const u32
|
|||
AbortIfFailed(pDevice->m_Device.resetCommandPool(assetLoader->m_CommandPool, {}));
|
||||
|
||||
skybox = {};
|
||||
resMan->Release(skyboxStorageHandle);
|
||||
resMan->Release(diffuseIrradianceStorageHandle);
|
||||
resMan->Release(brdfLutStorageHandle);
|
||||
for (auto &texHandles : prefilterStorageHandles)
|
||||
for (auto &_ : prefilterStorageHandles)
|
||||
{
|
||||
StorageTextureCube st;
|
||||
resMan->Release(&st, texHandles);
|
||||
// TODO: This needs fixing
|
||||
pDevice->m_Device.destroy(st.m_View, nullptr);
|
||||
}
|
||||
for (auto &pipeline : pipelines)
|
||||
|
|
|
|||
|
|
@ -6,7 +6,8 @@
|
|||
#pragma once
|
||||
|
||||
#include "aster/aster.h"
|
||||
#include "gpu_resource_manager.h"
|
||||
#include "aster/systems/resource.h"
|
||||
#include "aster/core/image.h"
|
||||
|
||||
struct Pipeline;
|
||||
struct Texture;
|
||||
|
|
@ -15,14 +16,11 @@ struct AssetLoader;
|
|||
|
||||
struct Environment
|
||||
{
|
||||
TextureHandle m_Skybox;
|
||||
TextureHandle m_Diffuse;
|
||||
TextureHandle m_Prefilter;
|
||||
TextureHandle m_BrdfLut;
|
||||
|
||||
void Destroy(GpuResourceManager *resourceManager);
|
||||
systems::ResId<Texture> m_Skybox;
|
||||
systems::ResId<Texture> m_Diffuse;
|
||||
systems::ResId<Texture> m_Prefilter;
|
||||
systems::ResId<Texture> m_BrdfLut;
|
||||
};
|
||||
|
||||
Environment
|
||||
CreateCubeFromHdrEnv(AssetLoader *assetLoader, vk::Queue computeQueue, u32 cubeSide, TextureHandle hdrEnv,
|
||||
cstr name = nullptr);
|
||||
Environment CreateCubeFromHdrEnv(AssetLoader *assetLoader, vk::Queue computeQueue, u32 cubeSide, systems::ResId<Texture> hdrEnv,
|
||||
cstr name = nullptr);
|
||||
|
|
@ -6,30 +6,11 @@
|
|||
#include "light_manager.h"
|
||||
|
||||
#include "aster/core/buffer.h"
|
||||
#include "aster/systems/resource.h"
|
||||
#include "aster/systems/resource_manager.h"
|
||||
#include "aster/systems/commit_manager.h"
|
||||
#include "glm/ext/matrix_transform.hpp"
|
||||
|
||||
struct Light
|
||||
{
|
||||
union {
|
||||
vec3 um_Position;
|
||||
vec3 um_Direction;
|
||||
};
|
||||
f32 m_Range; // < 0.0 for invalid
|
||||
u32 m_Color_; // LSB is used for flags. (R G B Flags)
|
||||
f32 m_Intensity;
|
||||
|
||||
constexpr static u32 MAX_GEN = 0x40;
|
||||
constexpr static u32 GEN_MASK = MAX_GEN - 1;
|
||||
|
||||
constexpr static u32 TYPE_MASK = 0xC0;
|
||||
constexpr static u32 TYPE_INVALID = 0x0;
|
||||
constexpr static u32 TYPE_DIRECTIONAL = 1 << 6;
|
||||
constexpr static u32 TYPE_POINT = 2 << 6;
|
||||
constexpr static u32 TYPE_SPOT = 3 << 6; // Currently Unused
|
||||
|
||||
constexpr static u32 COLOR_MASK = ~(GEN_MASK | TYPE_MASK);
|
||||
};
|
||||
|
||||
// Static Checks
|
||||
|
||||
// Ensure layouts are exact.
|
||||
|
|
@ -74,29 +55,25 @@ ToColor32(const vec3 &col)
|
|||
return r << 24 | g << 16 | b << 8 | a;
|
||||
}
|
||||
|
||||
LightManager::LightManager(GpuResourceManager *resourceManager)
|
||||
LightManager::LightManager(systems::ResourceManager *resourceManager, systems::CommitManager *commitManager)
|
||||
: m_ResourceManager{resourceManager}
|
||||
, m_CommitManager{commitManager}
|
||||
, m_DirectionalLightCount{}
|
||||
, m_PointLightCount{}
|
||||
, m_MetaInfo{}
|
||||
, m_MetaInfo{.m_LightBuffer = systems::ResId<Buffer>::Null() }
|
||||
, m_GpuBufferCapacity_{0}
|
||||
{
|
||||
}
|
||||
|
||||
LightManager::~LightManager()
|
||||
{
|
||||
m_ResourceManager->Release(m_MetaInfo.m_LightBuffer);
|
||||
}
|
||||
|
||||
LightManager::LightManager(LightManager &&other) noexcept
|
||||
: m_ResourceManager(other.m_ResourceManager)
|
||||
, m_CommitManager(other.m_CommitManager)
|
||||
, m_Lights(std::move(other.m_Lights))
|
||||
, m_DirectionalLightCount(other.m_DirectionalLightCount)
|
||||
, m_PointLightCount(other.m_PointLightCount)
|
||||
, m_MetaInfo(other.m_MetaInfo)
|
||||
, m_MetaInfo(std::move(other.m_MetaInfo))
|
||||
, m_GpuBufferCapacity_(other.m_GpuBufferCapacity_)
|
||||
{
|
||||
other.m_MetaInfo.m_LightBuffer = {};
|
||||
}
|
||||
|
||||
LightManager &
|
||||
|
|
@ -108,8 +85,7 @@ LightManager::operator=(LightManager &&other) noexcept
|
|||
m_Lights = std::move(other.m_Lights);
|
||||
m_DirectionalLightCount = other.m_DirectionalLightCount;
|
||||
m_PointLightCount = other.m_PointLightCount;
|
||||
m_MetaInfo = other.m_MetaInfo;
|
||||
other.m_MetaInfo.m_LightBuffer = {};
|
||||
m_MetaInfo = std::move(other.m_MetaInfo);
|
||||
m_GpuBufferCapacity_ = other.m_GpuBufferCapacity_;
|
||||
return *this;
|
||||
}
|
||||
|
|
@ -234,16 +210,15 @@ LightManager::Update()
|
|||
const u16 requiredBufferCapacity = eastl::min(Cast<u16>(m_Lights.capacity()), MAX_LIGHTS);
|
||||
if ((m_GpuBufferCapacity_ & CAPACITY_MASK) < requiredBufferCapacity)
|
||||
{
|
||||
StorageBuffer newBuffer;
|
||||
newBuffer.Init(m_ResourceManager->m_Device, requiredBufferCapacity * sizeof m_Lights[0], true, "Light Buffer");
|
||||
auto newBuffer = m_ResourceManager->Buffers().CreateStorageBuffer(requiredBufferCapacity * sizeof m_Lights[0], "Light Buffer");
|
||||
m_GpuBufferCapacity_ = requiredBufferCapacity | UPDATE_REQUIRED_BIT;
|
||||
|
||||
m_ResourceManager->Release(m_MetaInfo.m_LightBuffer);
|
||||
m_MetaInfo.m_LightBuffer = m_ResourceManager->Commit(&newBuffer);
|
||||
m_MetaInfo.m_LightBuffer = m_CommitManager->CommitBuffer(newBuffer);
|
||||
}
|
||||
if (m_GpuBufferCapacity_ & UPDATE_REQUIRED_BIT)
|
||||
{
|
||||
m_ResourceManager->Write(m_MetaInfo.m_LightBuffer, 0, m_Lights.size() * sizeof m_Lights[0], m_Lights.data());
|
||||
const auto ref = m_CommitManager->FetchHandle(m_MetaInfo.m_LightBuffer);
|
||||
ref->Write(0, m_Lights.size() * sizeof m_Lights[0], m_Lights.data());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,16 @@
|
|||
#include "aster/aster.h"
|
||||
|
||||
// TODO: Separate files so you only import handles.
|
||||
#include "gpu_resource_manager.h"
|
||||
#include "aster/systems/resource.h"
|
||||
#include "aster/core/buffer.h"
|
||||
|
||||
#include <EASTL/vector.h>
|
||||
|
||||
namespace systems
|
||||
{
|
||||
class ResourceManager;
|
||||
class CommitManager;
|
||||
} // namespace systems
|
||||
|
||||
struct DirectionalLight
|
||||
{
|
||||
|
|
@ -33,7 +42,27 @@ struct LightHandle
|
|||
u16 m_Index;
|
||||
};
|
||||
|
||||
struct Light;
|
||||
struct Light
|
||||
{
|
||||
union {
|
||||
vec3 um_Position;
|
||||
vec3 um_Direction;
|
||||
};
|
||||
f32 m_Range; // < 0.0 for invalid
|
||||
u32 m_Color_; // LSB is used for flags. (R G B Flags)
|
||||
f32 m_Intensity;
|
||||
|
||||
constexpr static u32 MAX_GEN = 0x40;
|
||||
constexpr static u32 GEN_MASK = MAX_GEN - 1;
|
||||
|
||||
constexpr static u32 TYPE_MASK = 0xC0;
|
||||
constexpr static u32 TYPE_INVALID = 0x0;
|
||||
constexpr static u32 TYPE_DIRECTIONAL = 1 << 6;
|
||||
constexpr static u32 TYPE_POINT = 2 << 6;
|
||||
constexpr static u32 TYPE_SPOT = 3 << 6; // Currently Unused
|
||||
|
||||
constexpr static u32 COLOR_MASK = ~(GEN_MASK | TYPE_MASK);
|
||||
};
|
||||
|
||||
struct LightManager
|
||||
{
|
||||
|
|
@ -44,14 +73,15 @@ struct LightManager
|
|||
// We can use that with Offset = 0, and point light at further offsets.
|
||||
// This way we don't need to move point lights often.
|
||||
|
||||
BufferHandle m_LightBuffer; // 04 04
|
||||
u16 m_PointLightMaxCount; // 02 06
|
||||
u16 m_PointLightOffset; // 02 08
|
||||
u16 m_DirectionalLightMaxCount; // 02 10
|
||||
u16 m_UnusedPadding0 = 0; // 02 12
|
||||
systems::ResId<Buffer> m_LightBuffer; // 04 04
|
||||
u16 m_PointLightMaxCount; // 02 06
|
||||
u16 m_PointLightOffset; // 02 08
|
||||
u16 m_DirectionalLightMaxCount; // 02 10
|
||||
u16 m_UnusedPadding0 = 0; // 02 12
|
||||
};
|
||||
|
||||
GpuResourceManager *m_ResourceManager;
|
||||
systems::ResourceManager *m_ResourceManager;
|
||||
systems::CommitManager *m_CommitManager;
|
||||
eastl::vector<Light> m_Lights;
|
||||
|
||||
// We don't need a Directional Light free list. We will just brute force iterate.
|
||||
|
|
@ -73,9 +103,9 @@ struct LightManager
|
|||
void Update();
|
||||
void RemoveLight(LightHandle handle);
|
||||
|
||||
explicit LightManager(GpuResourceManager *resourceManager);
|
||||
~LightManager();
|
||||
~LightManager() = default;
|
||||
|
||||
LightManager(systems::ResourceManager *resourceManager, systems::CommitManager *commitManager);
|
||||
LightManager(LightManager &&other) noexcept;
|
||||
LightManager &operator=(LightManager &&other) noexcept;
|
||||
|
||||
|
|
|
|||
|
|
@ -15,18 +15,19 @@
|
|||
#include "aster/core/swapchain.h"
|
||||
#include "aster/core/window.h"
|
||||
|
||||
#include "asset_loader.h"
|
||||
#include "frame.h"
|
||||
#include "helpers.h"
|
||||
#include "light_manager.h"
|
||||
|
||||
#include "asset_loader.h"
|
||||
#include "gpu_resource_manager.h"
|
||||
#include "aster/systems/buffer_manager.h"
|
||||
#include "gui.h"
|
||||
#include "ibl_helpers.h"
|
||||
#include "pipeline_utils.h"
|
||||
|
||||
#include <EASTL/array.h>
|
||||
#include <stb_image.h>
|
||||
#include <aster/systems/commit_manager.h>
|
||||
#include <aster/systems/resource_manager.h>
|
||||
#include <tiny_gltf.h>
|
||||
#include <filesystem>
|
||||
|
||||
|
|
@ -176,24 +177,24 @@ main(int, char **)
|
|||
{queueAllocation}, pipelineCacheData, "Primary Device"};
|
||||
vk::Queue graphicsQueue = device.GetQueue(queueAllocation.m_Family, 0);
|
||||
Swapchain swapchain = {&surface, &device, window.GetSize(), "Primary Chain"};
|
||||
GpuResourceManager resourceManager = {&device, 1000};
|
||||
|
||||
AssetLoader assetLoader = {&resourceManager, graphicsQueue, queueAllocation.m_Family, queueAllocation.m_Family};
|
||||
LightManager lightManager = LightManager{&resourceManager};
|
||||
systems::ResourceManager resourceManager = {&device, 1000, 1000, 10};
|
||||
systems::CommitManager commitManager = {&device, 1000, 1000, 1000, resourceManager.Samplers().CreateSampler({})};
|
||||
|
||||
AssetLoader assetLoader = {&resourceManager, &commitManager, graphicsQueue, queueAllocation.m_Family,
|
||||
queueAllocation.m_Family};
|
||||
LightManager lightManager = LightManager{&resourceManager, &commitManager};
|
||||
|
||||
Model model = assetLoader.LoadModelToGpu(MODEL_FILE);
|
||||
Texture environmentHdri;
|
||||
assetLoader.LoadHdrImage(&environmentHdri, BACKDROP_FILE);
|
||||
auto envHdriHandle = resourceManager.CommitTexture(&environmentHdri);
|
||||
auto environmentHdri = assetLoader.LoadHdrImage(BACKDROP_FILE);
|
||||
auto envHdriHandle = commitManager.CommitTexture(environmentHdri);
|
||||
|
||||
auto environment = CreateCubeFromHdrEnv(&assetLoader, graphicsQueue, 512, envHdriHandle, "Cube Env");
|
||||
|
||||
resourceManager.Release(envHdriHandle);
|
||||
|
||||
vk::Format attachmentFormat = vk::Format::eR8G8B8A8Srgb;
|
||||
|
||||
Pipeline pipeline = CreatePipeline(&device, attachmentFormat, &resourceManager);
|
||||
Pipeline backGroundPipeline = CreateBackgroundPipeline(&device, attachmentFormat, &resourceManager);
|
||||
Pipeline pipeline = CreatePipeline(&device, attachmentFormat, &commitManager);
|
||||
Pipeline backGroundPipeline = CreateBackgroundPipeline(&device, attachmentFormat, &commitManager);
|
||||
|
||||
lightManager.AddPoint(vec3{-5.0f, -5.0f, 5.0f}, vec3{1.0f}, 30.0f, 16.0f);
|
||||
lightManager.AddPoint(vec3{5.0f, -5.0f, 5.0f}, vec3{1.0f}, 30.0f, 16.0f);
|
||||
|
|
@ -242,19 +243,18 @@ main(int, char **)
|
|||
memcpy(data + lightOffset, &environment, sizeof environment);
|
||||
memcpy(data + lightOffset + sizeof environment, &lightManager.m_MetaInfo, sizeof lightManager.m_MetaInfo);
|
||||
|
||||
UniformBuffer ubo;
|
||||
ubo.Init(&device, uboSize, "Desc1 UBO");
|
||||
ubo.Write(&device, 0, ubo.GetSize(), data);
|
||||
auto ubo = resourceManager.Buffers().CreateUniformBuffer(uboSize, "Desc1 UBO");
|
||||
ubo->Write(0, ubo->m_Size, data);
|
||||
|
||||
delete[] data;
|
||||
|
||||
vk::DescriptorBufferInfo cameraBufferInfo = {
|
||||
.buffer = ubo.m_Buffer,
|
||||
.buffer = ubo->m_Buffer,
|
||||
.offset = 0,
|
||||
.range = cameraSize,
|
||||
};
|
||||
vk::DescriptorBufferInfo lightingBufferInfo = {
|
||||
.buffer = ubo.m_Buffer,
|
||||
.buffer = ubo->m_Buffer,
|
||||
.offset = lightOffset,
|
||||
.range = lightingSize,
|
||||
};
|
||||
|
|
@ -278,7 +278,7 @@ main(int, char **)
|
|||
};
|
||||
device.m_Device.updateDescriptorSets(Cast<u32>(writeDescriptors.size()), writeDescriptors.data(), 0, nullptr);
|
||||
|
||||
resourceManager.Update();
|
||||
commitManager.Update();
|
||||
|
||||
// Persistent variables
|
||||
vk::Viewport viewport = {
|
||||
|
|
@ -383,22 +383,23 @@ main(int, char **)
|
|||
};
|
||||
|
||||
FrameManager frameManager = {&device, queueAllocation.m_Family, MAX_FRAMES_IN_FLIGHT};
|
||||
eastl::fixed_vector<DepthImage, MAX_FRAMES_IN_FLIGHT> depthImages(frameManager.m_FramesInFlight);
|
||||
eastl::fixed_vector<AttachmentImage, MAX_FRAMES_IN_FLIGHT> attachmentImages(frameManager.m_FramesInFlight);
|
||||
eastl::fixed_vector<Ref<Image>, MAX_FRAMES_IN_FLIGHT> depthImages;
|
||||
eastl::fixed_vector<Ref<Image>, MAX_FRAMES_IN_FLIGHT> attachmentImages;
|
||||
|
||||
for (u32 index = 0; index < frameManager.m_FramesInFlight; ++index)
|
||||
{
|
||||
auto depthIter = depthImages.begin();
|
||||
auto attachmentIter = attachmentImages.begin();
|
||||
for (u32 index = 0; index < frameManager.m_FramesInFlight; ++index)
|
||||
{
|
||||
auto name = fmt::format("Depth Frame{}", index);
|
||||
depthIter->Init(&device, internalResolution, name.c_str());
|
||||
auto name = fmt::format("Depth Frame{}", index);
|
||||
depthImages.emplace_back(resourceManager.Images().CreateDepthStencilImage({
|
||||
.m_Extent = internalResolution,
|
||||
.m_Name = name.c_str(),
|
||||
}));
|
||||
|
||||
name = fmt::format("Attachment0 Frame{}", index);
|
||||
attachmentIter->Init(&device, internalResolution, attachmentFormat, name.c_str());
|
||||
|
||||
++depthIter;
|
||||
++attachmentIter;
|
||||
}
|
||||
name = fmt::format("Attachment0 Frame{}", index);
|
||||
attachmentImages.emplace_back(resourceManager.Images().CreateAttachment({
|
||||
.m_Format = attachmentFormat,
|
||||
.m_Extent = internalResolution,
|
||||
.m_Name = name.c_str(),
|
||||
}));
|
||||
}
|
||||
|
||||
gui::Init(&context, &device, &window, swapchain.m_Format, Cast<u32>(swapchain.m_ImageViews.size()),
|
||||
|
|
@ -410,10 +411,10 @@ main(int, char **)
|
|||
bool showPrefilter = false;
|
||||
bool useSpecular = true;
|
||||
|
||||
constexpr u32 USE_DIFFUSE_BIT = 1;
|
||||
constexpr u32 USE_SPECULAR_BIT = 1 << 1;
|
||||
constexpr u32 SHOW_DIFFUSE_BIT = 1 << 2;
|
||||
constexpr u32 SHOW_PREFILTER_BIT = 1 << 3;
|
||||
constexpr static u32 USE_DIFFUSE_BIT = 1;
|
||||
constexpr static u32 USE_SPECULAR_BIT = 1 << 1;
|
||||
constexpr static u32 SHOW_DIFFUSE_BIT = 1 << 2;
|
||||
constexpr static u32 SHOW_PREFILTER_BIT = 1 << 3;
|
||||
|
||||
i32 height = Cast<i32>(internalResolution.height);
|
||||
f32 camPitch = glm::degrees(cameraController.m_Pitch);
|
||||
|
|
@ -513,7 +514,7 @@ main(int, char **)
|
|||
}
|
||||
model.Update();
|
||||
cameraController.m_Camera.CalculateInverses();
|
||||
ubo.Write(&device, 0, sizeof cameraController.m_Camera, &cameraController.m_Camera);
|
||||
ubo->Write(0, sizeof cameraController.m_Camera, &cameraController.m_Camera);
|
||||
|
||||
Frame *currentFrame = frameManager.GetNextFrame(&swapchain, &surface, window.GetSize());
|
||||
|
||||
|
|
@ -522,19 +523,24 @@ main(int, char **)
|
|||
vk::ImageView currentSwapchainImageView = swapchain.m_ImageViews[imageIndex];
|
||||
vk::CommandBuffer cmd = currentFrame->m_CommandBuffer;
|
||||
|
||||
DepthImage *currentDepthImage = &depthImages[currentFrame->m_FrameIdx];
|
||||
AttachmentImage *currentAttachment = &attachmentImages[currentFrame->m_FrameIdx];
|
||||
auto& currentDepthImage = depthImages[currentFrame->m_FrameIdx];
|
||||
auto& currentAttachment = attachmentImages[currentFrame->m_FrameIdx];
|
||||
|
||||
if (currentAttachment->m_Extent.width != internalResolution.width ||
|
||||
currentAttachment->m_Extent.height != internalResolution.height)
|
||||
{
|
||||
auto name = fmt::format("Depth Frame{}", currentFrame->m_FrameIdx);
|
||||
currentDepthImage->Destroy(&device);
|
||||
currentDepthImage->Init(&device, internalResolution, name.c_str());
|
||||
currentDepthImage = resourceManager.Images().CreateDepthStencilImage({
|
||||
.m_Extent = internalResolution,
|
||||
.m_Name = name.c_str(),
|
||||
});
|
||||
|
||||
name = fmt::format("Attachment0 Frame{}", currentFrame->m_FrameIdx);
|
||||
currentAttachment->Destroy(&device);
|
||||
currentAttachment->Init(&device, internalResolution, attachmentFormat, name.c_str());
|
||||
currentAttachment = resourceManager.Images().CreateAttachment({
|
||||
.m_Format = attachmentFormat,
|
||||
.m_Extent = internalResolution,
|
||||
.m_Name = name.c_str(),
|
||||
});
|
||||
}
|
||||
|
||||
vk::ImageView currentDepthImageView = currentDepthImage->m_View;
|
||||
|
|
@ -586,12 +592,12 @@ main(int, char **)
|
|||
cmd.setViewport(0, 1, &viewport);
|
||||
cmd.setScissor(0, 1, &scissor);
|
||||
cmd.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipeline.m_Layout, 0, 1,
|
||||
&resourceManager.m_DescriptorSet, 0, nullptr);
|
||||
&commitManager.GetDescriptorSet(), 0, nullptr);
|
||||
|
||||
cmd.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipeline.m_Layout, 1, 1, &perFrameDescriptor, 0,
|
||||
nullptr);
|
||||
|
||||
cmd.bindIndexBuffer(model.m_IndexBuffer.m_Buffer, 0, vk::IndexType::eUint32);
|
||||
cmd.bindIndexBuffer(model.m_IndexBuffer->m_Buffer, 0, vk::IndexType::eUint32);
|
||||
|
||||
cmd.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline.m_Pipeline);
|
||||
|
||||
|
|
@ -693,22 +699,11 @@ main(int, char **)
|
|||
|
||||
device.WaitIdle();
|
||||
|
||||
environment.Destroy(&resourceManager);
|
||||
|
||||
pipelineCacheData = device.DumpPipelineCache();
|
||||
ERROR_IF(!WriteFileBytes(PIPELINE_CACHE_FILE, pipelineCacheData), "Pipeline Cache incorrectly written");
|
||||
|
||||
gui::Destroy(&device);
|
||||
|
||||
for (auto &depthImage : depthImages)
|
||||
{
|
||||
depthImage.Destroy(&device);
|
||||
}
|
||||
for (auto &attachmentImage : attachmentImages)
|
||||
{
|
||||
attachmentImage.Destroy(&device);
|
||||
}
|
||||
ubo.Destroy(&device);
|
||||
device.m_Device.destroy(descriptorPool, nullptr);
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -8,13 +8,14 @@
|
|||
#include "aster/core/device.h"
|
||||
#include "aster/core/pipeline.h"
|
||||
|
||||
#include "gpu_resource_manager.h"
|
||||
#include "helpers.h"
|
||||
|
||||
#include "aster/systems/commit_manager.h"
|
||||
|
||||
#include <EASTL/array.h>
|
||||
|
||||
Pipeline
|
||||
CreatePipeline(const Device *device, vk::Format attachmentFormat, const GpuResourceManager *resourceManager)
|
||||
CreatePipeline(const Device *device, vk::Format attachmentFormat, const systems::CommitManager *commitManager)
|
||||
{
|
||||
// Pipeline Setup
|
||||
auto vertexShaderModule = CreateShader(device, VERTEX_SHADER_FILE);
|
||||
|
|
@ -35,7 +36,7 @@ CreatePipeline(const Device *device, vk::Format attachmentFormat, const GpuResou
|
|||
|
||||
eastl::vector<vk::DescriptorSetLayout> descriptorSetLayouts;
|
||||
|
||||
descriptorSetLayouts.push_back(resourceManager->m_SetLayout);
|
||||
descriptorSetLayouts.push_back(commitManager->GetDescriptorSetLayout());
|
||||
|
||||
{
|
||||
eastl::array descriptorSetLayoutBindings = {
|
||||
|
|
@ -175,7 +176,7 @@ CreatePipeline(const Device *device, vk::Format attachmentFormat, const GpuResou
|
|||
}
|
||||
|
||||
Pipeline
|
||||
CreateBackgroundPipeline(const Device *device, vk::Format attachmentFormat, const GpuResourceManager *resourceManager)
|
||||
CreateBackgroundPipeline(const Device *device, vk::Format attachmentFormat, const systems::CommitManager *commitManager)
|
||||
{
|
||||
// Pipeline Setup
|
||||
auto vertexShaderModule = CreateShader(device, BACKGROUND_VERTEX_SHADER_FILE);
|
||||
|
|
@ -196,7 +197,7 @@ CreateBackgroundPipeline(const Device *device, vk::Format attachmentFormat, cons
|
|||
|
||||
eastl::vector<vk::DescriptorSetLayout> descriptorSetLayouts;
|
||||
|
||||
descriptorSetLayouts.push_back(resourceManager->m_SetLayout);
|
||||
descriptorSetLayouts.push_back(commitManager->GetDescriptorSetLayout());
|
||||
|
||||
{
|
||||
eastl::array descriptorSetLayoutBindings = {
|
||||
|
|
|
|||
|
|
@ -7,6 +7,11 @@
|
|||
|
||||
#include "aster/aster.h"
|
||||
|
||||
namespace systems
|
||||
{
|
||||
class CommitManager;
|
||||
}
|
||||
|
||||
struct GpuResourceManager;
|
||||
struct Swapchain;
|
||||
struct Device;
|
||||
|
|
@ -19,6 +24,6 @@ constexpr auto BACKGROUND_VERTEX_SHADER_FILE = "shader/background.vs.hlsl.spv";
|
|||
constexpr auto BACKGROUND_FRAGMENT_SHADER_FILE = "shader/background.ps.hlsl.spv";
|
||||
|
||||
vk::ShaderModule CreateShader(const Device *device, cstr shaderFile);
|
||||
Pipeline CreatePipeline(const Device *device, vk::Format attachmentFormat, const GpuResourceManager *resourceManager);
|
||||
Pipeline CreatePipeline(const Device *device, vk::Format attachmentFormat, const systems::CommitManager *resourceManager);
|
||||
Pipeline
|
||||
CreateBackgroundPipeline(const Device *device, vk::Format attachmentFormat, const GpuResourceManager *resourceManager);
|
||||
CreateBackgroundPipeline(const Device *device, vk::Format attachmentFormat, const systems::CommitManager *resourceManager);
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
|
||||
|
||||
#define TINYGLTF_NOEXCEPTION
|
||||
#define JSON_NOEXCEPTION
|
||||
|
||||
#define TINYGLTF_IMPLEMENTATION
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||
|
||||
#include <tiny_gltf.h>
|
||||
|
|
@ -5,5 +5,5 @@ cmake_minimum_required(VERSION 3.13)
|
|||
add_subdirectory("00_util")
|
||||
add_subdirectory("01_triangle")
|
||||
add_subdirectory("02_box")
|
||||
# add_subdirectory("03_model_render")
|
||||
add_subdirectory("03_model_render")
|
||||
# add_subdirectory("04_scenes")
|
||||
|
|
|
|||
Loading…
Reference in New Issue