Compare commits
8 Commits
16bb54273c
...
3a7bea902f
| Author | SHA1 | Date |
|---|---|---|
|
|
3a7bea902f | |
|
|
88d8a2acc2 | |
|
|
9ca5751a78 | |
|
|
15df13730d | |
|
|
dfdbd52087 | |
|
|
300fa7449c | |
|
|
058a6512ea | |
|
|
8d2c04ea19 |
|
|
@ -4,3 +4,4 @@ build/
|
||||||
.vs/
|
.vs/
|
||||||
.direnv/
|
.direnv/
|
||||||
.ccls-cache/
|
.ccls-cache/
|
||||||
|
*.user
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ set(CMAKE_CXX_EXTENSIONS OFF)
|
||||||
|
|
||||||
if (MSVC)
|
if (MSVC)
|
||||||
set(CMAKE_CXX_FLAGS "/W4 /GR- ${MSVC_FLAGS}")
|
set(CMAKE_CXX_FLAGS "/W4 /GR- ${MSVC_FLAGS}")
|
||||||
|
set(CMAKE_CXX_FLAGS_RELEASE "/O3")
|
||||||
add_compile_definitions(_HAS_EXCEPTIONS=0)
|
add_compile_definitions(_HAS_EXCEPTIONS=0)
|
||||||
add_compile_definitions(_CRT_SECURE_NO_WARNINGS)
|
add_compile_definitions(_CRT_SECURE_NO_WARNINGS)
|
||||||
add_compile_definitions(${MSVC_DEFINES})
|
add_compile_definitions(${MSVC_DEFINES})
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
cmake_minimum_required(VERSION 3.13)
|
cmake_minimum_required(VERSION 3.13)
|
||||||
|
|
||||||
add_subdirectory("core")
|
add_subdirectory("core")
|
||||||
|
add_subdirectory("systems")
|
||||||
add_subdirectory("util")
|
add_subdirectory("util")
|
||||||
|
|
||||||
target_sources(aster_core
|
target_sources(aster_core
|
||||||
|
|
|
||||||
|
|
@ -17,4 +17,5 @@ INTERFACE
|
||||||
"image.h"
|
"image.h"
|
||||||
"surface.h"
|
"surface.h"
|
||||||
"size.h"
|
"size.h"
|
||||||
|
"type_traits.h"
|
||||||
"window.h")
|
"window.h")
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,8 @@ struct Buffer
|
||||||
[[nodiscard]] bool IsValid() const;
|
[[nodiscard]] bool IsValid() const;
|
||||||
[[nodiscard]] bool IsMapped() const;
|
[[nodiscard]] bool IsMapped() const;
|
||||||
[[nodiscard]] bool IsOwned() const;
|
[[nodiscard]] bool IsOwned() const;
|
||||||
|
[[nodiscard]] bool IsCommitted() const;
|
||||||
|
void SetCommitted(bool committed);
|
||||||
|
|
||||||
void Destroy(const Device *device);
|
void Destroy(const Device *device);
|
||||||
void Write(const Device *device, usize offset, usize size, const void *data);
|
void Write(const Device *device, usize offset, usize size, const void *data);
|
||||||
|
|
@ -40,9 +42,13 @@ struct Buffer
|
||||||
|
|
||||||
constexpr static usize VALID_BUFFER_BIT = Cast<usize>(1llu << 63);
|
constexpr static usize VALID_BUFFER_BIT = Cast<usize>(1llu << 63);
|
||||||
constexpr static usize OWNED_BIT = 1llu << 62;
|
constexpr static usize OWNED_BIT = 1llu << 62;
|
||||||
constexpr static usize SIZE_MASK = ~(VALID_BUFFER_BIT | OWNED_BIT);
|
constexpr static usize COMMITTED_BIT = 1llu << 61;
|
||||||
|
constexpr static usize SIZE_MASK = ~(VALID_BUFFER_BIT | OWNED_BIT | COMMITTED_BIT);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
constexpr bool concepts::GpuResource<Buffer> = true;
|
||||||
|
|
||||||
// Ensure that m_Size doesn't get used intrusively since it manages the state.
|
// Ensure that m_Size doesn't get used intrusively since it manages the state.
|
||||||
static_assert(offsetof(Buffer, m_Size_) > sizeof(usize));
|
static_assert(offsetof(Buffer, m_Size_) > sizeof(usize));
|
||||||
|
|
||||||
|
|
@ -113,3 +119,15 @@ Buffer::IsOwned() const
|
||||||
{
|
{
|
||||||
return m_Size_ & OWNED_BIT;
|
return m_Size_ & OWNED_BIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool
|
||||||
|
Buffer::IsCommitted() const
|
||||||
|
{
|
||||||
|
return m_Size_ & COMMITTED_BIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void
|
||||||
|
Buffer::SetCommitted(const bool committed)
|
||||||
|
{
|
||||||
|
m_Size_ = committed ? (m_Size_ | COMMITTED_BIT) : (m_Size_ & ~COMMITTED_BIT);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,8 @@
|
||||||
#if !defined(NDEBUG)
|
#if !defined(NDEBUG)
|
||||||
#define VULKAN_HPP_ASSERT(expr) DEBUG_IF(!(expr), "Vulkan assert failed")
|
#define VULKAN_HPP_ASSERT(expr) DEBUG_IF(!(expr), "Vulkan assert failed")
|
||||||
#endif
|
#endif
|
||||||
|
#include "type_traits.h"
|
||||||
|
|
||||||
#include <EASTL/fixed_string.h>
|
#include <EASTL/fixed_string.h>
|
||||||
#include <EASTL/string.h>
|
#include <EASTL/string.h>
|
||||||
#include <vk_mem_alloc.h>
|
#include <vk_mem_alloc.h>
|
||||||
|
|
@ -40,6 +42,12 @@ constexpr u32 ASTER_API_VERSION = VK_API_VERSION_1_3;
|
||||||
CLASS_NAME(const CLASS_NAME &other) = delete; \
|
CLASS_NAME(const CLASS_NAME &other) = delete; \
|
||||||
CLASS_NAME &operator=(const CLASS_NAME &other) = delete
|
CLASS_NAME &operator=(const CLASS_NAME &other) = delete
|
||||||
|
|
||||||
|
#define PIN_MEMORY(CLASS_NAME) \
|
||||||
|
CLASS_NAME(const CLASS_NAME &other) = delete; \
|
||||||
|
CLASS_NAME(CLASS_NAME &&other) noexcept = delete; \
|
||||||
|
CLASS_NAME &operator=(const CLASS_NAME &other) = delete; \
|
||||||
|
CLASS_NAME &operator=(CLASS_NAME &&other) noexcept = delete
|
||||||
|
|
||||||
#define Take(ELEMENT) eastl::exchange(ELEMENT, {})
|
#define Take(ELEMENT) eastl::exchange(ELEMENT, {})
|
||||||
|
|
||||||
#define TODO(MSG) assert(false && ("Unimplemented: " MSG))
|
#define TODO(MSG) assert(false && ("Unimplemented: " MSG))
|
||||||
|
|
@ -169,6 +177,18 @@ ClosestPowerOfTwo(const u32 val)
|
||||||
return (smallerPo2 + largerPo2 <= (val << 1)) ? largerPo2 : smallerPo2;
|
return (smallerPo2 + largerPo2 <= (val << 1)) ? largerPo2 : smallerPo2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] constexpr u32
|
||||||
|
GetMaskOffset(u32 val)
|
||||||
|
{
|
||||||
|
u32 count = 0;
|
||||||
|
while ((val & 1) == 0)
|
||||||
|
{
|
||||||
|
count++;
|
||||||
|
val = val >> 1;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
struct fmt::formatter<vk::Result> : nested_formatter<std::string>
|
struct fmt::formatter<vk::Result> : nested_formatter<std::string>
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -49,13 +49,19 @@ struct Image
|
||||||
[[nodiscard]] bool IsValid() const;
|
[[nodiscard]] bool IsValid() const;
|
||||||
[[nodiscard]] bool IsOwned() const;
|
[[nodiscard]] bool IsOwned() const;
|
||||||
[[nodiscard]] u32 GetMipLevels() const;
|
[[nodiscard]] u32 GetMipLevels() const;
|
||||||
|
[[nodiscard]] bool IsCommitted() const;
|
||||||
|
void SetCommitted(bool committed);
|
||||||
|
|
||||||
void Destroy(const Device *device);
|
void Destroy(const Device *device);
|
||||||
|
|
||||||
constexpr static u8 VALID_BIT = 1u << 7;
|
constexpr static u8 VALID_BIT = 1u << 7;
|
||||||
constexpr static u8 OWNED_BIT = 1u << 6;
|
constexpr static u8 OWNED_BIT = 1u << 6;
|
||||||
|
constexpr static u8 COMMITTED_BIT = 1u << 5;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
constexpr bool concepts::GpuResource<Image> = true;
|
||||||
|
|
||||||
struct Texture : Image
|
struct Texture : Image
|
||||||
{
|
{
|
||||||
void Init(const Device *device, vk::Extent2D extent, vk::Format imageFormat, bool isMipMapped, cstr name = nullptr);
|
void Init(const Device *device, vk::Extent2D extent, vk::Format imageFormat, bool isMipMapped, cstr name = nullptr);
|
||||||
|
|
@ -117,3 +123,15 @@ Image::GetMipLevels() const
|
||||||
{
|
{
|
||||||
return m_MipLevels;
|
return m_MipLevels;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool
|
||||||
|
Image::IsCommitted() const
|
||||||
|
{
|
||||||
|
return m_Flags_ & COMMITTED_BIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void
|
||||||
|
Image::SetCommitted(const bool committed)
|
||||||
|
{
|
||||||
|
m_Flags_ = committed ? (m_Flags_ | COMMITTED_BIT) : (m_Flags_ & ~COMMITTED_BIT);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
// =============================================
|
||||||
|
// Aster: type_traits.h
|
||||||
|
// Copyright (c) 2020-2024 Anish Bhobe
|
||||||
|
// =============================================
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
struct Device;
|
||||||
|
|
||||||
|
namespace concepts
|
||||||
|
{
|
||||||
|
template <typename T>
|
||||||
|
concept DeviceDestructible = requires(T a, Device *p) {
|
||||||
|
{ a.Destroy(p) } -> std::convertible_to<void>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
concept Committable = requires(T a, bool v) {
|
||||||
|
{ a.IsCommitted() } -> std::convertible_to<bool>;
|
||||||
|
{ a.SetCommitted(v) } -> std::convertible_to<void>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
constexpr bool GpuResource = false;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
concept RenderResource = GpuResource<T> and std::is_default_constructible_v<T> and std::is_trivially_copyable_v<T> and
|
||||||
|
DeviceDestructible<T> and Committable<T>;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
constexpr bool IsHandle = false;
|
||||||
|
|
||||||
|
template <typename THandle>
|
||||||
|
concept HandleType = IsHandle<THandle> and RenderResource<typename THandle::Type>;
|
||||||
|
|
||||||
|
} // namespace concepts
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
# CMakeList.txt ; CMake project for Aster Util Headers
|
||||||
|
|
||||||
|
cmake_minimum_required(VERSION 3.13)
|
||||||
|
|
||||||
|
target_sources(aster_core
|
||||||
|
INTERFACE
|
||||||
|
"manager.h"
|
||||||
|
"buffer_manager.h"
|
||||||
|
"image_manager.h"
|
||||||
|
"render_resource_manager.h")
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
// =============================================
|
||||||
|
// Aster: buffer_manager.h
|
||||||
|
// Copyright (c) 2020-2024 Anish Bhobe
|
||||||
|
// =============================================
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "aster/aster.h"
|
||||||
|
#include "aster/core/buffer.h"
|
||||||
|
#include "manager.h"
|
||||||
|
|
||||||
|
namespace systems
|
||||||
|
{
|
||||||
|
using BufferHandle = Handle<Buffer>;
|
||||||
|
|
||||||
|
class BufferManager final : public Manager<Buffer>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
BufferManager(const Device *device, const u32 maxCount, const u8 binding);
|
||||||
|
|
||||||
|
[[nodiscard]] Handle CreateStorageBuffer(usize size, cstr name = nullptr);
|
||||||
|
[[nodiscard]] Handle CreateUniformBuffer(usize size, cstr name = nullptr);
|
||||||
|
};
|
||||||
|
} // namespace systems
|
||||||
|
|
@ -0,0 +1,60 @@
|
||||||
|
// =============================================
|
||||||
|
// Aster: image_manager.h
|
||||||
|
// Copyright (c) 2020-2024 Anish Bhobe
|
||||||
|
// =============================================
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "aster/aster.h"
|
||||||
|
#include "aster/core/image.h"
|
||||||
|
#include "manager.h"
|
||||||
|
|
||||||
|
namespace systems
|
||||||
|
{
|
||||||
|
|
||||||
|
struct Texture2DCreateInfo
|
||||||
|
{
|
||||||
|
vk::Format m_Format = vk::Format::eUndefined;
|
||||||
|
vk::Extent2D m_Extent = {};
|
||||||
|
cstr m_Name = nullptr;
|
||||||
|
bool m_IsSampled = true;
|
||||||
|
bool m_IsMipMapped = false;
|
||||||
|
bool m_IsStorage = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TextureCubeCreateInfo
|
||||||
|
{
|
||||||
|
vk::Format m_Format = vk::Format::eUndefined;
|
||||||
|
u32 m_Side = 0;
|
||||||
|
cstr m_Name = nullptr;
|
||||||
|
bool m_IsSampled = true;
|
||||||
|
bool m_IsMipMapped = false;
|
||||||
|
bool m_IsStorage = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AttachmentCreateInfo
|
||||||
|
{
|
||||||
|
vk::Format m_Format = vk::Format::eUndefined;
|
||||||
|
vk::Extent2D m_Extent = {};
|
||||||
|
cstr m_Name = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DepthStencilImageCreateInfo
|
||||||
|
{
|
||||||
|
vk::Extent2D m_Extent = {};
|
||||||
|
cstr m_Name = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
using ImageHandle = Handle<Image>;
|
||||||
|
|
||||||
|
class ImageManager final : public Manager<Image>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ImageManager(const Device *device, const u32 maxCount, const u8 binding);
|
||||||
|
|
||||||
|
[[nodiscard]] Handle CreateTexture2D(const Texture2DCreateInfo &createInfo);
|
||||||
|
[[nodiscard]] Handle CreateTextureCube(const TextureCubeCreateInfo &createInfo);
|
||||||
|
[[nodiscard]] Handle CreateAttachment(const AttachmentCreateInfo &createInfo);
|
||||||
|
[[nodiscard]] Handle CreateDepthStencilImage(const DepthStencilImageCreateInfo &createInfo);
|
||||||
|
};
|
||||||
|
} // namespace systems
|
||||||
|
|
@ -0,0 +1,361 @@
|
||||||
|
// =============================================
|
||||||
|
// Aster: manager.h
|
||||||
|
// Copyright (c) 2020-2024 Anish Bhobe
|
||||||
|
// =============================================
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "aster/aster.h"
|
||||||
|
#include "aster/core/type_traits.h"
|
||||||
|
|
||||||
|
struct Device;
|
||||||
|
|
||||||
|
template <concepts::RenderResource T>
|
||||||
|
class Handle;
|
||||||
|
|
||||||
|
template <concepts::RenderResource T>
|
||||||
|
class Manager
|
||||||
|
{
|
||||||
|
friend Handle<T>;
|
||||||
|
|
||||||
|
public:
|
||||||
|
using Type = T;
|
||||||
|
using Handle = Handle<Type>;
|
||||||
|
static_assert(sizeof(Handle) == sizeof(u32));
|
||||||
|
constexpr static u32 MAX_HANDLES = Handle::INDEX_MASK + 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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)
|
||||||
|
: m_MaxCount{maxCount}
|
||||||
|
, m_Binding{binding}
|
||||||
|
, m_Device{device}
|
||||||
|
{
|
||||||
|
assert(!m_Instance);
|
||||||
|
assert(maxCount <= MAX_HANDLES);
|
||||||
|
|
||||||
|
m_Data = new Type[m_MaxCount];
|
||||||
|
m_RefCount = new std::atomic<u32>[m_MaxCount];
|
||||||
|
|
||||||
|
for (u32 i = 0; i < m_MaxCount; ++i)
|
||||||
|
{
|
||||||
|
*Recast<u32 *>(&m_Data[i]) = (i + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_Instance = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~Manager()
|
||||||
|
{
|
||||||
|
if (!m_Data)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (u32 i = 0; i < m_MaxCount; ++i)
|
||||||
|
{
|
||||||
|
m_Data[i].Destroy(m_Device);
|
||||||
|
}
|
||||||
|
|
||||||
|
delete[] m_Data;
|
||||||
|
delete[] m_RefCount;
|
||||||
|
m_Data = nullptr;
|
||||||
|
m_RefCount = nullptr;
|
||||||
|
m_MaxCount = 0;
|
||||||
|
m_FreeHead = 0;
|
||||||
|
m_Device = nullptr;
|
||||||
|
|
||||||
|
m_Instance = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @warning only to be used internally.
|
||||||
|
* @return The only constructed instance of this manager.
|
||||||
|
*/
|
||||||
|
static Manager *
|
||||||
|
Instance()
|
||||||
|
{
|
||||||
|
assert(m_Instance);
|
||||||
|
return m_Instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
PIN_MEMORY(Manager);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Type *m_Data = nullptr; // Data also keeps the freelist during 'not use'.
|
||||||
|
std::atomic<u32> *m_RefCount = nullptr; // Associated reference count for each of the instances in Data.
|
||||||
|
u32 m_MaxCount = 0; // Max number of resources supported.
|
||||||
|
u32 m_FreeHead = 0;
|
||||||
|
u8 m_Binding = 0;
|
||||||
|
|
||||||
|
static Manager *m_Instance;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User is expected to type-check.
|
||||||
|
* @param index Actual index of the resource in the m_Data array. Not type checked.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
AddRef(const u32 index)
|
||||||
|
{
|
||||||
|
assert(index < m_MaxCount);
|
||||||
|
++m_RefCount[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User is expected to type-check.
|
||||||
|
* @param index Actual index of the resource in the m_Data array. Not type checked.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
Release(const u32 index)
|
||||||
|
{
|
||||||
|
assert(index < m_MaxCount);
|
||||||
|
const u32 rc = --m_RefCount[index];
|
||||||
|
assert(rc != MaxValue<u32>);
|
||||||
|
if (rc == 0)
|
||||||
|
{
|
||||||
|
// TODO: Don't destroy here. Separate out to a cleanup routine.
|
||||||
|
m_Data[index].Destroy(m_Device);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User is expected to type-check.
|
||||||
|
* @param index Actual index of the resource in the m_Data array. Not type checked.
|
||||||
|
* @return Pointer to the resource at the index.
|
||||||
|
*/
|
||||||
|
Type *
|
||||||
|
Fetch(const u32 index)
|
||||||
|
{
|
||||||
|
assert(index < m_MaxCount);
|
||||||
|
return &m_Data[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
const Device *m_Device;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal Method to Allocate a resource on the manager.
|
||||||
|
* @return [Handle, Type*] Where Type* is available to initialize the resource.
|
||||||
|
*/
|
||||||
|
[[nodiscard]] std::pair<Handle, Type *>
|
||||||
|
Alloc()
|
||||||
|
{
|
||||||
|
ERROR_IF(m_FreeHead >= m_MaxCount, "Max buffers allocated.") THEN_ABORT(-1);
|
||||||
|
|
||||||
|
const auto index = m_FreeHead;
|
||||||
|
Type *pAlloc = &m_Data[index];
|
||||||
|
m_FreeHead = *Recast<u32 *>(pAlloc);
|
||||||
|
return {Handle{index, m_Binding}, pAlloc};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <concepts::RenderResource T>
|
||||||
|
class Ref
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using Type = T;
|
||||||
|
using Handle = Handle<Type>;
|
||||||
|
using Manager = Manager<Type>;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Handle m_Handle;
|
||||||
|
Type *m_Pointer = nullptr;
|
||||||
|
|
||||||
|
friend Handle;
|
||||||
|
|
||||||
|
void
|
||||||
|
InitPtr()
|
||||||
|
{
|
||||||
|
m_Pointer = m_Handle.Fetch();
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
Type *
|
||||||
|
Get()
|
||||||
|
{
|
||||||
|
assert(m_Pointer);
|
||||||
|
return m_Pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Type *
|
||||||
|
Get() const
|
||||||
|
{
|
||||||
|
assert(m_Pointer);
|
||||||
|
return m_Pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
Type *
|
||||||
|
operator->()
|
||||||
|
{
|
||||||
|
return Get();
|
||||||
|
}
|
||||||
|
|
||||||
|
const Type *
|
||||||
|
operator->() const
|
||||||
|
{
|
||||||
|
return Get();
|
||||||
|
}
|
||||||
|
|
||||||
|
Type &
|
||||||
|
operator*()
|
||||||
|
{
|
||||||
|
return *Get();
|
||||||
|
}
|
||||||
|
|
||||||
|
const Type &
|
||||||
|
operator*() const
|
||||||
|
{
|
||||||
|
return Get();
|
||||||
|
}
|
||||||
|
|
||||||
|
// The only constructor requires a valid construction.
|
||||||
|
explicit Ref(Handle &&handle)
|
||||||
|
: m_Handle{std::forward<Handle>(handle)}
|
||||||
|
{
|
||||||
|
InitPtr();
|
||||||
|
}
|
||||||
|
|
||||||
|
// The only constructor requires a valid construction.
|
||||||
|
explicit Ref(const Handle &&handle)
|
||||||
|
: m_Handle{handle}
|
||||||
|
{
|
||||||
|
InitPtr();
|
||||||
|
}
|
||||||
|
|
||||||
|
Ref(const Ref &other) = default;
|
||||||
|
Ref(Ref &&other) noexcept = default;
|
||||||
|
Ref &operator=(const Ref &other) = default;
|
||||||
|
Ref &operator=(Ref &&other) noexcept = default;
|
||||||
|
~Ref() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
class RawHandle
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
constexpr static u32 INVALID_HANDLE = MaxValue<u32>;
|
||||||
|
constexpr static u32 INDEX_MASK = 0x0FFFFFFF;
|
||||||
|
constexpr static u32 TYPE_MASK = ~INDEX_MASK;
|
||||||
|
constexpr static u32 TYPE_OFFSET = GetMaskOffset(TYPE_MASK);
|
||||||
|
u32 m_Internal = INVALID_HANDLE;
|
||||||
|
|
||||||
|
RawHandle(const u32 index, const u8 typeId)
|
||||||
|
: m_Internal{(index & INDEX_MASK) | (typeId & TYPE_MASK)}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit RawHandle(const u32 internal)
|
||||||
|
: m_Internal{internal}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
[[nodiscard]] bool
|
||||||
|
IsValid() const
|
||||||
|
{
|
||||||
|
return m_Internal != INVALID_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] u32
|
||||||
|
GetIndex() const
|
||||||
|
{
|
||||||
|
return m_Internal & INDEX_MASK;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] u32
|
||||||
|
GetType() const
|
||||||
|
{
|
||||||
|
return (m_Internal & TYPE_MASK) >> TYPE_OFFSET;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
operator==(const RawHandle &other) const
|
||||||
|
{
|
||||||
|
return m_Internal == other.m_Internal;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <concepts::RenderResource T>
|
||||||
|
class Handle : public RawHandle
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using Type = T;
|
||||||
|
using Manager = Manager<Type>;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// The only constructor requires a valid construction.
|
||||||
|
Handle(const u32 index, const u8 typeId)
|
||||||
|
: RawHandle{index, typeId}
|
||||||
|
{
|
||||||
|
AddRef();
|
||||||
|
}
|
||||||
|
|
||||||
|
friend Manager;
|
||||||
|
friend Ref<T>;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Handle(const Handle &other)
|
||||||
|
: RawHandle{other}
|
||||||
|
{
|
||||||
|
AddRef();
|
||||||
|
}
|
||||||
|
|
||||||
|
Handle(Handle &&other) noexcept
|
||||||
|
: RawHandle{std::exchange(other.m_Internal, m_Internal)}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] Ref<T>
|
||||||
|
ToPointer()
|
||||||
|
{
|
||||||
|
return Ref{std::move(*this)};
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] Type *
|
||||||
|
Fetch() const
|
||||||
|
{
|
||||||
|
return Manager::Instance()->Fetch(m_Internal);
|
||||||
|
}
|
||||||
|
|
||||||
|
Handle &
|
||||||
|
operator=(const Handle &other)
|
||||||
|
{
|
||||||
|
if (this == &other)
|
||||||
|
return *this;
|
||||||
|
m_Internal = other.m_Internal;
|
||||||
|
AddRef();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Handle &
|
||||||
|
operator=(Handle &&other) noexcept
|
||||||
|
{
|
||||||
|
if (this == &other)
|
||||||
|
return *this;
|
||||||
|
std::swap(m_Internal, other.m_Internal);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
~Handle()
|
||||||
|
{
|
||||||
|
if (m_Internal != INVALID_HANDLE)
|
||||||
|
{
|
||||||
|
Release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void
|
||||||
|
AddRef()
|
||||||
|
{
|
||||||
|
Manager::Instance()->AddRef(GetIndex());
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Release()
|
||||||
|
{
|
||||||
|
Manager::Instance()->Release(GetIndex());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,157 @@
|
||||||
|
// =============================================
|
||||||
|
// Aster: render_resource_manager.h
|
||||||
|
// Copyright (c) 2020-2024 Anish Bhobe
|
||||||
|
// =============================================
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "aster/aster.h"
|
||||||
|
#include "buffer_manager.h"
|
||||||
|
#include "image_manager.h"
|
||||||
|
|
||||||
|
#include "EASTL/deque.h"
|
||||||
|
#include "EASTL/vector.h"
|
||||||
|
|
||||||
|
namespace systems
|
||||||
|
{
|
||||||
|
|
||||||
|
class RenderResourceManager
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
union WriteInfo {
|
||||||
|
vk::DescriptorBufferInfo uBufferInfo;
|
||||||
|
vk::DescriptorImageInfo uImageInfo;
|
||||||
|
vk::BufferView uBufferView;
|
||||||
|
|
||||||
|
explicit WriteInfo(const vk::DescriptorBufferInfo &info);
|
||||||
|
explicit WriteInfo(const vk::DescriptorImageInfo &info);
|
||||||
|
explicit WriteInfo(const vk::BufferView &info);
|
||||||
|
};
|
||||||
|
|
||||||
|
using WriteCommand = vk::WriteDescriptorSet;
|
||||||
|
|
||||||
|
union WriteOwner {
|
||||||
|
Handle<Buffer> uBufferHandle;
|
||||||
|
Handle<Image> uImageHandle;
|
||||||
|
|
||||||
|
explicit WriteOwner(const Handle<Buffer> &handle);
|
||||||
|
explicit WriteOwner(const Handle<Image> &handle);
|
||||||
|
|
||||||
|
WriteOwner(const WriteOwner &other)
|
||||||
|
{
|
||||||
|
switch (uRawHandle.GetType())
|
||||||
|
{
|
||||||
|
case BUFFER_BINDING_INDEX:
|
||||||
|
uBufferHandle = other.uBufferHandle;
|
||||||
|
break;
|
||||||
|
case IMAGE_BINDING_INDEX:
|
||||||
|
uImageHandle = other.uImageHandle;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ERROR("Invalid Handle type.") THEN_ABORT(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WriteOwner(WriteOwner &&other) noexcept
|
||||||
|
{
|
||||||
|
switch (uRawHandle.GetType())
|
||||||
|
{
|
||||||
|
case BUFFER_BINDING_INDEX:
|
||||||
|
uBufferHandle = std::move(other.uBufferHandle);
|
||||||
|
break;
|
||||||
|
case IMAGE_BINDING_INDEX:
|
||||||
|
uImageHandle = std::move(other.uImageHandle);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ERROR("Invalid Handle type.") THEN_ABORT(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WriteOwner &
|
||||||
|
operator=(const WriteOwner &other)
|
||||||
|
{
|
||||||
|
if (this == &other)
|
||||||
|
return *this;
|
||||||
|
|
||||||
|
switch (uRawHandle.GetType())
|
||||||
|
{
|
||||||
|
case BUFFER_BINDING_INDEX:
|
||||||
|
uBufferHandle = other.uBufferHandle;
|
||||||
|
break;
|
||||||
|
case IMAGE_BINDING_INDEX:
|
||||||
|
uImageHandle = other.uImageHandle;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ERROR("Invalid Handle type.") THEN_ABORT(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
WriteOwner &
|
||||||
|
operator=(WriteOwner &&other) noexcept
|
||||||
|
{
|
||||||
|
if (this == &other)
|
||||||
|
return *this;
|
||||||
|
|
||||||
|
switch (uRawHandle.GetType())
|
||||||
|
{
|
||||||
|
case BUFFER_BINDING_INDEX:
|
||||||
|
uBufferHandle = std::move(other.uBufferHandle);
|
||||||
|
break;
|
||||||
|
case IMAGE_BINDING_INDEX:
|
||||||
|
uImageHandle = std::move(other.uImageHandle);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ERROR("Invalid Handle type.") THEN_ABORT(-1);
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
~WriteOwner()
|
||||||
|
{
|
||||||
|
switch (uRawHandle.GetType())
|
||||||
|
{
|
||||||
|
case BUFFER_BINDING_INDEX:
|
||||||
|
uBufferHandle.~Handle();
|
||||||
|
return;
|
||||||
|
case IMAGE_BINDING_INDEX:
|
||||||
|
uImageHandle.~Handle();
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
ERROR("Invalid Handle type.") THEN_ABORT(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
RawHandle uRawHandle;
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
RenderResourceManager(const Device *device, u32 maxBuffers, u32 maxImages);
|
||||||
|
|
||||||
|
void Commit(concepts::HandleType auto &handle);
|
||||||
|
|
||||||
|
private:
|
||||||
|
BufferManager m_BufferManager;
|
||||||
|
ImageManager m_ImageManager;
|
||||||
|
|
||||||
|
vk::DescriptorPool m_DescriptorPool;
|
||||||
|
vk::DescriptorSetLayout m_SetLayout;
|
||||||
|
vk::DescriptorSet m_DescriptorSet;
|
||||||
|
|
||||||
|
constexpr static u8 BUFFER_BINDING_INDEX = 0;
|
||||||
|
constexpr static u8 IMAGE_BINDING_INDEX = 1;
|
||||||
|
|
||||||
|
eastl::vector<vk::WriteDescriptorSet> m_Writes;
|
||||||
|
eastl::deque<WriteInfo> m_WriteInfos;
|
||||||
|
eastl::vector<WriteOwner> m_WriteOwner;
|
||||||
|
|
||||||
|
#if !defined(ASTER_NDEBUG)
|
||||||
|
usize m_CommitedBufferCount = 0;
|
||||||
|
usize m_CommitedTextureCount = 0;
|
||||||
|
usize m_CommitedStorageTextureCount = 0;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace systems
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "core/constants.h"
|
#include "aster/core/constants.h"
|
||||||
#include <debugbreak.h>
|
#include <debugbreak.h>
|
||||||
#include <fmt/core.h>
|
#include <fmt/core.h>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,4 +3,5 @@
|
||||||
cmake_minimum_required(VERSION 3.13)
|
cmake_minimum_required(VERSION 3.13)
|
||||||
|
|
||||||
add_subdirectory("core")
|
add_subdirectory("core")
|
||||||
|
add_subdirectory("systems")
|
||||||
add_subdirectory("util")
|
add_subdirectory("util")
|
||||||
|
|
@ -44,7 +44,8 @@ Buffer::Allocate(const Device *device, usize size, vk::BufferUsageFlags bufferUs
|
||||||
vk::MemoryPropertyFlags memoryPropertyFlags;
|
vk::MemoryPropertyFlags memoryPropertyFlags;
|
||||||
vmaGetAllocationMemoryProperties(device->m_Allocator, allocation,
|
vmaGetAllocationMemoryProperties(device->m_Allocator, allocation,
|
||||||
Recast<VkMemoryPropertyFlags *>(&memoryPropertyFlags));
|
Recast<VkMemoryPropertyFlags *>(&memoryPropertyFlags));
|
||||||
bool hostAccessible = Cast<bool>(memoryPropertyFlags & vk::MemoryPropertyFlagBits::eHostVisible);
|
// TODO: Actually track Host Access
|
||||||
|
// bool hostAccessible = Cast<bool>(memoryPropertyFlags & vk::MemoryPropertyFlagBits::eHostVisible);
|
||||||
|
|
||||||
m_Buffer = buffer;
|
m_Buffer = buffer;
|
||||||
m_Size_ = size | VALID_BUFFER_BIT | OWNED_BIT;
|
m_Size_ = size | VALID_BUFFER_BIT | OWNED_BIT;
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ struct MemorySize
|
||||||
m_Kilobytes = totalKb % 1024;
|
m_Kilobytes = totalKb % 1024;
|
||||||
const usize totalMb = m_Megabytes + totalKb / 1024;
|
const usize totalMb = m_Megabytes + totalKb / 1024;
|
||||||
m_Megabytes = totalMb % 1024;
|
m_Megabytes = totalMb % 1024;
|
||||||
m_Gigabytes += totalMb / 1024;
|
m_Gigabytes += Cast<u16>(totalMb / 1024);
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
@ -56,8 +56,7 @@ struct fmt::formatter<MemorySize>
|
||||||
// return format_to(ctx.out(), "({}, {})", foo.a, foo.b); // --== KEY LINE ==--
|
// return format_to(ctx.out(), "({}, {})", foo.a, foo.b); // --== KEY LINE ==--
|
||||||
if (mem.m_Gigabytes > 0)
|
if (mem.m_Gigabytes > 0)
|
||||||
{
|
{
|
||||||
return v10::format_to(ctx.out(), "{}.{} GB", mem.m_Gigabytes,
|
return v10::format_to(ctx.out(), "{}.{} GB", mem.m_Gigabytes, Cast<u16>(mem.m_Megabytes / 1024.0));
|
||||||
Cast<u16>(mem.m_Megabytes / 1024.0));
|
|
||||||
}
|
}
|
||||||
if (mem.m_Megabytes > 0)
|
if (mem.m_Megabytes > 0)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -109,7 +109,7 @@ Remember, we use upside down viewport.
|
||||||
void
|
void
|
||||||
TextureCube::Init(const Device *device, u32 cubeSide, vk::Format imageFormat, bool isMipMapped, cstr name)
|
TextureCube::Init(const Device *device, u32 cubeSide, vk::Format imageFormat, bool isMipMapped, cstr name)
|
||||||
{
|
{
|
||||||
WARN_IF(!IsPowerOfTwo(cubeSide), "Image {1} is {0}x{0} (Non Power of Two)", cubeSide, name ? name : "<unnamed>");
|
WARN_IF(!IsPowerOfTwo(cubeSide), "Image Cube {1} has side {0}x{0} (Non Power of Two)", cubeSide, name ? name : "<unnamed>");
|
||||||
|
|
||||||
const u8 mipLevels = isMipMapped ? 1 + Cast<u8>(floor(log2(cubeSide))) : 1;
|
const u8 mipLevels = isMipMapped ? 1 + Cast<u8>(floor(log2(cubeSide))) : 1;
|
||||||
|
|
||||||
|
|
@ -119,7 +119,7 @@ TextureCube::Init(const Device *device, u32 cubeSide, vk::Format imageFormat, bo
|
||||||
usage |= vk::ImageUsageFlagBits::eTransferSrc;
|
usage |= vk::ImageUsageFlagBits::eTransferSrc;
|
||||||
}
|
}
|
||||||
|
|
||||||
vk::Extent3D extent = {.width = cubeSide, .height = cubeSide, .depth = 1};
|
const vk::Extent3D extent = {.width = cubeSide, .height = cubeSide, .depth = 1};
|
||||||
|
|
||||||
vk::ImageCreateInfo imageCreateInfo = {
|
vk::ImageCreateInfo imageCreateInfo = {
|
||||||
.flags = vk::ImageCreateFlagBits::eCubeCompatible,
|
.flags = vk::ImageCreateFlagBits::eCubeCompatible,
|
||||||
|
|
@ -216,7 +216,7 @@ AttachmentImage::Init(const Device *device, vk::Extent2D extent, vk::Format imag
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
result = device->m_Device.createImageView(&imageViewCreateInfo, nullptr, &view);
|
result = device->m_Device.createImageView(&imageViewCreateInfo, nullptr, &view);
|
||||||
ERROR_IF(Failed(result), "Could not create depth image view {}. Cause: {}", name, result) THEN_ABORT(result);
|
ERROR_IF(Failed(result), "Could not create attachment image view {}. Cause: {}", name, result) THEN_ABORT(result);
|
||||||
|
|
||||||
m_Image = image;
|
m_Image = image;
|
||||||
m_View = view;
|
m_View = view;
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@
|
||||||
|
|
||||||
Surface::Surface(Context *context, const Window *window, cstr name)
|
Surface::Surface(Context *context, const Window *window, cstr name)
|
||||||
: m_Context(context)
|
: m_Context(context)
|
||||||
|
, m_Name(name)
|
||||||
{
|
{
|
||||||
VkSurfaceKHR surface;
|
VkSurfaceKHR surface;
|
||||||
auto result = Cast<vk::Result>(
|
auto result = Cast<vk::Result>(
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
# CMakeList.txt ; CMake project for Aster Util Headers
|
||||||
|
|
||||||
|
cmake_minimum_required(VERSION 3.13)
|
||||||
|
|
||||||
|
target_sources(aster_core
|
||||||
|
PRIVATE
|
||||||
|
"manager.cpp"
|
||||||
|
"buffer_manager.cpp"
|
||||||
|
"image_manager.cpp"
|
||||||
|
"render_resource_manager.cpp")
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
// =============================================
|
||||||
|
// Aster: buffer_manager.cpp
|
||||||
|
// Copyright (c) 2020-2025 Anish Bhobe
|
||||||
|
// =============================================
|
||||||
|
|
||||||
|
#include "systems/buffer_manager.h"
|
||||||
|
|
||||||
|
Manager<Buffer> *Manager<Buffer>::m_Instance = nullptr;
|
||||||
|
|
||||||
|
using namespace systems;
|
||||||
|
|
||||||
|
BufferHandle
|
||||||
|
BufferManager::CreateStorageBuffer(const usize size, const cstr name)
|
||||||
|
{
|
||||||
|
auto [handle, 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 VmaAllocationCreateFlags createFlags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT |
|
||||||
|
VMA_ALLOCATION_CREATE_HOST_ACCESS_ALLOW_TRANSFER_INSTEAD_BIT |
|
||||||
|
VMA_ALLOCATION_CREATE_MAPPED_BIT;
|
||||||
|
constexpr VmaMemoryUsage memoryUsage = VMA_MEMORY_USAGE_AUTO;
|
||||||
|
object->Allocate(m_Device, size, usage, createFlags, memoryUsage, name);
|
||||||
|
|
||||||
|
return std::move(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
Manager<Buffer>::Handle
|
||||||
|
BufferManager::CreateUniformBuffer(const usize size, const cstr name)
|
||||||
|
{
|
||||||
|
auto [handle, object] = Alloc();
|
||||||
|
|
||||||
|
constexpr vk::BufferUsageFlags usage = vk::BufferUsageFlagBits::eUniformBuffer;
|
||||||
|
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;
|
||||||
|
constexpr VmaMemoryUsage memoryUsage = VMA_MEMORY_USAGE_AUTO;
|
||||||
|
object->Allocate(m_Device, size, usage, createFlags, memoryUsage, name);
|
||||||
|
|
||||||
|
return std::move(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
BufferManager::BufferManager(const Device *device, const u32 maxCount, const u8 binding)
|
||||||
|
: Manager{device, maxCount, binding}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,316 @@
|
||||||
|
// =============================================
|
||||||
|
// Aster: buffer_manager.cpp
|
||||||
|
// Copyright (c) 2020-2025 Anish Bhobe
|
||||||
|
// =============================================
|
||||||
|
|
||||||
|
#include "systems/image_manager.h"
|
||||||
|
|
||||||
|
#include "core/device.h"
|
||||||
|
|
||||||
|
Manager<Image> *Manager<Image>::m_Instance = nullptr;
|
||||||
|
|
||||||
|
using namespace systems;
|
||||||
|
|
||||||
|
vk::ImageCreateInfo ToImageCreateInfo(const Texture2DCreateInfo &createInfo);
|
||||||
|
vk::ImageCreateInfo ToImageCreateInfo(const TextureCubeCreateInfo &createInfo);
|
||||||
|
vk::ImageCreateInfo ToImageCreateInfo(const AttachmentCreateInfo &createInfo);
|
||||||
|
vk::ImageCreateInfo ToImageCreateInfo(const DepthStencilImageCreateInfo &createInfo);
|
||||||
|
|
||||||
|
namespace usage_flags
|
||||||
|
{
|
||||||
|
constexpr vk::ImageUsageFlags MIPMAP = vk::ImageUsageFlagBits::eTransferSrc | vk::ImageUsageFlagBits::eTransferDst;
|
||||||
|
constexpr vk::ImageUsageFlags SAMPLE = vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eTransferDst;
|
||||||
|
constexpr vk::ImageUsageFlags STORAGE =
|
||||||
|
vk::ImageUsageFlagBits::eStorage | vk::ImageUsageFlagBits::eTransferDst | vk::ImageUsageFlagBits::eTransferSrc;
|
||||||
|
constexpr vk::ImageUsageFlags COLOR_ATTACHMENT =
|
||||||
|
vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eTransferSrc;
|
||||||
|
constexpr vk::ImageUsageFlags DEPTH_STENCIL_ATTACHMENT = vk::ImageUsageFlagBits::eDepthStencilAttachment;
|
||||||
|
} // namespace usage_flags
|
||||||
|
|
||||||
|
ImageHandle
|
||||||
|
ImageManager::CreateTexture2D(const Texture2DCreateInfo &createInfo)
|
||||||
|
{
|
||||||
|
constexpr VmaAllocationCreateInfo allocationCreateInfo = {
|
||||||
|
.flags = {},
|
||||||
|
.usage = VMA_MEMORY_USAGE_AUTO,
|
||||||
|
};
|
||||||
|
|
||||||
|
VkImage image;
|
||||||
|
VmaAllocation allocation;
|
||||||
|
vk::ImageCreateInfo imageCreateInfo = ToImageCreateInfo(createInfo);
|
||||||
|
auto result = Cast<vk::Result>(vmaCreateImage(m_Device->m_Allocator, Recast<VkImageCreateInfo *>(&imageCreateInfo),
|
||||||
|
&allocationCreateInfo, &image, &allocation, nullptr));
|
||||||
|
ERROR_IF(Failed(result), "Could not allocate image {}. Cause: {}", createInfo.m_Name, result) THEN_ABORT(result);
|
||||||
|
|
||||||
|
vk::ImageView view;
|
||||||
|
const vk::ImageViewCreateInfo imageViewCreateInfo = {
|
||||||
|
.image = image,
|
||||||
|
.viewType = vk::ImageViewType::e2D,
|
||||||
|
.format = imageCreateInfo.format,
|
||||||
|
.components = {},
|
||||||
|
.subresourceRange =
|
||||||
|
{
|
||||||
|
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||||
|
.baseMipLevel = 0,
|
||||||
|
.levelCount = imageCreateInfo.mipLevels,
|
||||||
|
.baseArrayLayer = 0,
|
||||||
|
.layerCount = imageCreateInfo.arrayLayers,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
result = m_Device->m_Device.createImageView(&imageViewCreateInfo, nullptr, &view);
|
||||||
|
ERROR_IF(Failed(result), "Could not create image view {}. Cause: {}", createInfo.m_Name, result)
|
||||||
|
THEN_ABORT(result);
|
||||||
|
|
||||||
|
auto [handle, object] = Alloc();
|
||||||
|
object->m_Image = image;
|
||||||
|
object->m_View = view;
|
||||||
|
object->m_Allocation = allocation;
|
||||||
|
object->m_Extent = imageCreateInfo.extent;
|
||||||
|
object->m_Flags_ = Image::OWNED_BIT | Image::VALID_BIT;
|
||||||
|
object->m_LayerCount = Cast<u8>(imageCreateInfo.arrayLayers);
|
||||||
|
object->m_MipLevels = Cast<u8>(imageCreateInfo.mipLevels);
|
||||||
|
|
||||||
|
m_Device->SetName(object->m_Image, createInfo.m_Name);
|
||||||
|
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImageHandle
|
||||||
|
ImageManager::CreateTextureCube(const TextureCubeCreateInfo &createInfo)
|
||||||
|
{
|
||||||
|
constexpr VmaAllocationCreateInfo allocationCreateInfo = {
|
||||||
|
.flags = {},
|
||||||
|
.usage = VMA_MEMORY_USAGE_AUTO,
|
||||||
|
};
|
||||||
|
|
||||||
|
VkImage image;
|
||||||
|
VmaAllocation allocation;
|
||||||
|
vk::ImageCreateInfo imageCreateInfo = ToImageCreateInfo(createInfo);
|
||||||
|
auto result = Cast<vk::Result>(vmaCreateImage(m_Device->m_Allocator, Recast<VkImageCreateInfo *>(&imageCreateInfo),
|
||||||
|
&allocationCreateInfo, &image, &allocation, nullptr));
|
||||||
|
ERROR_IF(Failed(result), "Could not allocate image {}. Cause: {}", createInfo.m_Name, result) THEN_ABORT(result);
|
||||||
|
|
||||||
|
vk::ImageView view;
|
||||||
|
const vk::ImageViewCreateInfo imageViewCreateInfo = {
|
||||||
|
.image = image,
|
||||||
|
.viewType = vk::ImageViewType::eCube,
|
||||||
|
.format = imageCreateInfo.format,
|
||||||
|
.components = {},
|
||||||
|
.subresourceRange =
|
||||||
|
{
|
||||||
|
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||||
|
.baseMipLevel = 0,
|
||||||
|
.levelCount = imageCreateInfo.mipLevels,
|
||||||
|
.baseArrayLayer = 0,
|
||||||
|
.layerCount = imageCreateInfo.arrayLayers,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
result = m_Device->m_Device.createImageView(&imageViewCreateInfo, nullptr, &view);
|
||||||
|
ERROR_IF(Failed(result), "Could not create image view {}. Cause: {}", createInfo.m_Name, result)
|
||||||
|
THEN_ABORT(result);
|
||||||
|
|
||||||
|
auto [handle, object] = Alloc();
|
||||||
|
object->m_Image = image;
|
||||||
|
object->m_View = view;
|
||||||
|
object->m_Allocation = allocation;
|
||||||
|
object->m_Extent = imageCreateInfo.extent;
|
||||||
|
object->m_Flags_ = Image::OWNED_BIT | Image::VALID_BIT;
|
||||||
|
object->m_LayerCount = Cast<u8>(imageCreateInfo.arrayLayers);
|
||||||
|
object->m_MipLevels = Cast<u8>(imageCreateInfo.mipLevels);
|
||||||
|
|
||||||
|
m_Device->SetName(object->m_Image, createInfo.m_Name);
|
||||||
|
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImageHandle
|
||||||
|
ImageManager::CreateAttachment(const AttachmentCreateInfo &createInfo)
|
||||||
|
{
|
||||||
|
constexpr VmaAllocationCreateInfo allocationCreateInfo = {
|
||||||
|
.flags = VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT,
|
||||||
|
.usage = VMA_MEMORY_USAGE_AUTO,
|
||||||
|
};
|
||||||
|
|
||||||
|
VkImage image;
|
||||||
|
VmaAllocation allocation;
|
||||||
|
vk::ImageCreateInfo imageCreateInfo = ToImageCreateInfo(createInfo);
|
||||||
|
auto result = Cast<vk::Result>(vmaCreateImage(m_Device->m_Allocator, Recast<VkImageCreateInfo *>(&imageCreateInfo),
|
||||||
|
&allocationCreateInfo, &image, &allocation, nullptr));
|
||||||
|
ERROR_IF(Failed(result), "Could not allocate image {}. Cause: {}", createInfo.m_Name, result) THEN_ABORT(result);
|
||||||
|
|
||||||
|
vk::ImageView view;
|
||||||
|
const vk::ImageViewCreateInfo imageViewCreateInfo = {
|
||||||
|
.image = image,
|
||||||
|
.viewType = vk::ImageViewType::e2D,
|
||||||
|
.format = imageCreateInfo.format,
|
||||||
|
.components = {},
|
||||||
|
.subresourceRange =
|
||||||
|
{
|
||||||
|
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||||
|
.baseMipLevel = 0,
|
||||||
|
.levelCount = imageCreateInfo.mipLevels,
|
||||||
|
.baseArrayLayer = 0,
|
||||||
|
.layerCount = imageCreateInfo.arrayLayers,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
result = m_Device->m_Device.createImageView(&imageViewCreateInfo, nullptr, &view);
|
||||||
|
ERROR_IF(Failed(result), "Could not create image view {}. Cause: {}", createInfo.m_Name, result)
|
||||||
|
THEN_ABORT(result);
|
||||||
|
|
||||||
|
auto [handle, object] = Alloc();
|
||||||
|
object->m_Image = image;
|
||||||
|
object->m_View = view;
|
||||||
|
object->m_Allocation = allocation;
|
||||||
|
object->m_Extent = imageCreateInfo.extent;
|
||||||
|
object->m_Flags_ = Image::OWNED_BIT | Image::VALID_BIT;
|
||||||
|
object->m_LayerCount = Cast<u8>(imageCreateInfo.arrayLayers);
|
||||||
|
object->m_MipLevels = Cast<u8>(imageCreateInfo.mipLevels);
|
||||||
|
|
||||||
|
m_Device->SetName(object->m_Image, createInfo.m_Name);
|
||||||
|
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImageHandle
|
||||||
|
ImageManager::CreateDepthStencilImage(const DepthStencilImageCreateInfo &createInfo)
|
||||||
|
{
|
||||||
|
constexpr VmaAllocationCreateInfo allocationCreateInfo = {
|
||||||
|
.flags = VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT,
|
||||||
|
.usage = VMA_MEMORY_USAGE_AUTO,
|
||||||
|
};
|
||||||
|
|
||||||
|
VkImage image;
|
||||||
|
VmaAllocation allocation;
|
||||||
|
vk::ImageCreateInfo imageCreateInfo = ToImageCreateInfo(createInfo);
|
||||||
|
auto result = Cast<vk::Result>(vmaCreateImage(m_Device->m_Allocator, Recast<VkImageCreateInfo *>(&imageCreateInfo),
|
||||||
|
&allocationCreateInfo, &image, &allocation, nullptr));
|
||||||
|
ERROR_IF(Failed(result), "Could not allocate image {}. Cause: {}", createInfo.m_Name, result) THEN_ABORT(result);
|
||||||
|
|
||||||
|
vk::ImageView view;
|
||||||
|
const vk::ImageViewCreateInfo imageViewCreateInfo = {
|
||||||
|
.image = image,
|
||||||
|
.viewType = vk::ImageViewType::e2D,
|
||||||
|
.format = imageCreateInfo.format,
|
||||||
|
.components = {},
|
||||||
|
.subresourceRange =
|
||||||
|
{
|
||||||
|
.aspectMask = vk::ImageAspectFlagBits::eDepth | vk::ImageAspectFlagBits::eStencil,
|
||||||
|
.baseMipLevel = 0,
|
||||||
|
.levelCount = imageCreateInfo.mipLevels,
|
||||||
|
.baseArrayLayer = 0,
|
||||||
|
.layerCount = imageCreateInfo.arrayLayers,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
result = m_Device->m_Device.createImageView(&imageViewCreateInfo, nullptr, &view);
|
||||||
|
ERROR_IF(Failed(result), "Could not create image view {}. Cause: {}", createInfo.m_Name, result)
|
||||||
|
THEN_ABORT(result);
|
||||||
|
|
||||||
|
auto [handle, object] = Alloc();
|
||||||
|
object->m_Image = image;
|
||||||
|
object->m_View = view;
|
||||||
|
object->m_Allocation = allocation;
|
||||||
|
object->m_Extent = imageCreateInfo.extent;
|
||||||
|
object->m_Flags_ = Image::OWNED_BIT | Image::VALID_BIT;
|
||||||
|
object->m_LayerCount = Cast<u8>(imageCreateInfo.arrayLayers);
|
||||||
|
object->m_MipLevels = Cast<u8>(imageCreateInfo.mipLevels);
|
||||||
|
|
||||||
|
m_Device->SetName(object->m_Image, createInfo.m_Name);
|
||||||
|
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
vk::ImageCreateInfo
|
||||||
|
ToImageCreateInfo(const Texture2DCreateInfo &createInfo)
|
||||||
|
{
|
||||||
|
auto &[format, extent, name, isSampled, isMipMapped, isStorage] = createInfo;
|
||||||
|
|
||||||
|
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::ImageUsageFlags{};
|
||||||
|
if (isSampled)
|
||||||
|
usage |= usage_flags::SAMPLE;
|
||||||
|
if (isMipMapped)
|
||||||
|
usage |= usage_flags::MIPMAP;
|
||||||
|
if (isStorage)
|
||||||
|
usage |= usage_flags::STORAGE;
|
||||||
|
|
||||||
|
return {
|
||||||
|
.imageType = vk::ImageType::e2D,
|
||||||
|
.format = format,
|
||||||
|
.extent = ToExtent3D(extent, 1),
|
||||||
|
.mipLevels = mipLevels,
|
||||||
|
.arrayLayers = 1,
|
||||||
|
.usage = usage,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
vk::ImageCreateInfo
|
||||||
|
ToImageCreateInfo(const TextureCubeCreateInfo &createInfo)
|
||||||
|
{
|
||||||
|
auto &[format, side, name, isSampled, isMipMapped, isStorage] = createInfo;
|
||||||
|
|
||||||
|
WARN_IF(!IsPowerOfTwo(side), "ImageCube {1} is {0}x{0} (Non Power of Two)", side, name ? name : "<unnamed>");
|
||||||
|
|
||||||
|
const u8 mipLevels = isMipMapped ? 1 + Cast<u8>(floor(log2(side))) : 1;
|
||||||
|
|
||||||
|
auto usage = vk::ImageUsageFlags{};
|
||||||
|
if (isSampled)
|
||||||
|
usage |= usage_flags::SAMPLE;
|
||||||
|
if (isMipMapped)
|
||||||
|
usage |= usage_flags::MIPMAP;
|
||||||
|
if (isStorage)
|
||||||
|
usage |= usage_flags::STORAGE;
|
||||||
|
|
||||||
|
return {
|
||||||
|
.flags = vk::ImageCreateFlagBits::eCubeCompatible,
|
||||||
|
.imageType = vk::ImageType::e2D,
|
||||||
|
.format = format,
|
||||||
|
.extent = {side, side, 1},
|
||||||
|
.mipLevels = mipLevels,
|
||||||
|
.arrayLayers = 6,
|
||||||
|
.usage = usage,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
vk::ImageCreateInfo
|
||||||
|
ToImageCreateInfo(const AttachmentCreateInfo &createInfo)
|
||||||
|
{
|
||||||
|
auto &[format, extent, name] = createInfo;
|
||||||
|
|
||||||
|
constexpr auto usage = usage_flags::COLOR_ATTACHMENT;
|
||||||
|
|
||||||
|
return {
|
||||||
|
.imageType = vk::ImageType::e2D,
|
||||||
|
.format = format,
|
||||||
|
.extent = ToExtent3D(extent, 1),
|
||||||
|
.mipLevels = 1,
|
||||||
|
.arrayLayers = 1,
|
||||||
|
.usage = usage,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
vk::ImageCreateInfo
|
||||||
|
ToImageCreateInfo(const DepthStencilImageCreateInfo &createInfo)
|
||||||
|
{
|
||||||
|
auto &[extent, name] = createInfo;
|
||||||
|
|
||||||
|
constexpr vk::Format format = vk::Format::eD24UnormS8Uint;
|
||||||
|
constexpr auto usage = usage_flags::DEPTH_STENCIL_ATTACHMENT;
|
||||||
|
|
||||||
|
return {
|
||||||
|
.imageType = vk::ImageType::e2D,
|
||||||
|
.format = format,
|
||||||
|
.extent = ToExtent3D(extent, 1),
|
||||||
|
.mipLevels = 1,
|
||||||
|
.arrayLayers = 1,
|
||||||
|
.usage = usage,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
ImageManager::ImageManager(const Device *device, const u32 maxCount, const u8 binding)
|
||||||
|
: Manager{device, maxCount, binding}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
// =============================================
|
||||||
|
// Aster: manager.cpp
|
||||||
|
// Copyright (c) 2020-2025 Anish Bhobe
|
||||||
|
// =============================================
|
||||||
|
|
||||||
|
#include "systems/manager.h"
|
||||||
|
|
@ -0,0 +1,195 @@
|
||||||
|
// =============================================
|
||||||
|
// Aster: render_resource_manager.cpp
|
||||||
|
// Copyright (c) 2020-2025 Anish Bhobe
|
||||||
|
// =============================================
|
||||||
|
|
||||||
|
#include "systems/render_resource_manager.h"
|
||||||
|
|
||||||
|
#include "EASTL/array.h"
|
||||||
|
#include "core/device.h"
|
||||||
|
|
||||||
|
#define AbortIfFailed(RESULT) \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
|
vk::Result _checkResultValue_; \
|
||||||
|
ERROR_IF(Failed(_checkResultValue_ = Cast<vk::Result>(RESULT)), "Cause: {}", _checkResultValue_) \
|
||||||
|
THEN_ABORT(_checkResultValue_); \
|
||||||
|
} while (false)
|
||||||
|
|
||||||
|
#define AbortIfFailedMV(RESULT, MSG, EXTRA) \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
|
vk::Result _checkResultValue_; \
|
||||||
|
ERROR_IF(Failed(_checkResultValue_ = Cast<vk::Result>(RESULT)), MSG " Cause: {}", EXTRA, _checkResultValue_) \
|
||||||
|
THEN_ABORT(_checkResultValue_); \
|
||||||
|
} while (false)
|
||||||
|
|
||||||
|
#define AbortIfFailedM(RESULT, MSG) \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
|
auto _checkResultValue_ = Cast<vk::Result>(RESULT); \
|
||||||
|
ERROR_IF(Failed(_checkResultValue_), MSG " Cause: {}", _checkResultValue_) THEN_ABORT(_checkResultValue_); \
|
||||||
|
} while (false)
|
||||||
|
|
||||||
|
|
||||||
|
using namespace systems;
|
||||||
|
|
||||||
|
u32
|
||||||
|
GetHandleInternal(concepts::HandleType auto &handle)
|
||||||
|
{
|
||||||
|
return *Recast<u32 *>(&handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderResourceManager::WriteOwner::WriteOwner(const Handle<Buffer> &handle)
|
||||||
|
: uBufferHandle(handle)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderResourceManager::WriteOwner::WriteOwner(const Handle<Image> &handle)
|
||||||
|
: uImageHandle(handle)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderResourceManager::RenderResourceManager(const Device *device, u32 const maxBuffers, const u32 maxImages)
|
||||||
|
: m_BufferManager{device, maxBuffers, BUFFER_BINDING_INDEX}
|
||||||
|
, m_ImageManager{device, maxImages, IMAGE_BINDING_INDEX}
|
||||||
|
{
|
||||||
|
eastl::array poolSizes = {
|
||||||
|
vk::DescriptorPoolSize{
|
||||||
|
.type = vk::DescriptorType::eStorageBuffer,
|
||||||
|
.descriptorCount = maxBuffers,
|
||||||
|
},
|
||||||
|
vk::DescriptorPoolSize{
|
||||||
|
.type = vk::DescriptorType::eCombinedImageSampler,
|
||||||
|
.descriptorCount = maxImages,
|
||||||
|
},
|
||||||
|
//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));
|
||||||
|
|
||||||
|
eastl::array descriptorLayoutBindings = {
|
||||||
|
vk::DescriptorSetLayoutBinding{
|
||||||
|
.binding = BUFFER_BINDING_INDEX,
|
||||||
|
.descriptorType = vk::DescriptorType::eStorageBuffer,
|
||||||
|
.descriptorCount = Cast<u32>(maxBuffers),
|
||||||
|
.stageFlags = vk::ShaderStageFlagBits::eAll,
|
||||||
|
},
|
||||||
|
vk::DescriptorSetLayoutBinding{
|
||||||
|
.binding = IMAGE_BINDING_INDEX,
|
||||||
|
.descriptorType = vk::DescriptorType::eCombinedImageSampler,
|
||||||
|
.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::DescriptorBindingFlags bindingFlags =
|
||||||
|
vk::DescriptorBindingFlagBits::ePartiallyBound | vk::DescriptorBindingFlagBits::eUpdateAfterBind;
|
||||||
|
|
||||||
|
eastl::array<vk::DescriptorBindingFlags, decltype(descriptorLayoutBindings)::count> layoutBindingFlags;
|
||||||
|
layoutBindingFlags.fill(bindingFlags);
|
||||||
|
|
||||||
|
vk::DescriptorSetLayoutBindingFlagsCreateInfo bindingFlagsCreateInfo = {
|
||||||
|
.bindingCount = Cast<u32>(layoutBindingFlags.size()),
|
||||||
|
.pBindingFlags = layoutBindingFlags.data(),
|
||||||
|
};
|
||||||
|
|
||||||
|
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));
|
||||||
|
|
||||||
|
device->SetName(m_SetLayout, "Bindless Layout");
|
||||||
|
device->SetName(m_DescriptorPool, "Bindless Pool");
|
||||||
|
device->SetName(m_DescriptorSet, "Bindless Set");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
systems::RenderResourceManager::Commit(concepts::HandleType auto &handle)
|
||||||
|
{
|
||||||
|
using HandleType = decltype(handle)::Type;
|
||||||
|
if constexpr (std::is_same_v<HandleType, Buffer>)
|
||||||
|
{
|
||||||
|
const Buffer *buffer = handle.Fetch();
|
||||||
|
|
||||||
|
m_WriteInfos.emplace_back(vk::DescriptorBufferInfo{
|
||||||
|
.buffer = buffer->m_Buffer,
|
||||||
|
.offset = 0,
|
||||||
|
.range = buffer->GetSize(),
|
||||||
|
});
|
||||||
|
m_Writes.push_back({
|
||||||
|
.dstSet = m_DescriptorSet,
|
||||||
|
.dstBinding = BUFFER_BINDING_INDEX,
|
||||||
|
.dstArrayElement = handle.GetIndex(),
|
||||||
|
.descriptorCount = 1,
|
||||||
|
.descriptorType = vk::DescriptorType::eStorageBuffer,
|
||||||
|
.pBufferInfo = &m_WriteInfos.back().uBufferInfo,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else if constexpr (std::is_same_v<HandleType, Image>)
|
||||||
|
{
|
||||||
|
const Image *image = handle.Fetch();
|
||||||
|
|
||||||
|
m_WriteInfos.emplace_back(vk::DescriptorImageInfo{
|
||||||
|
.sampler = nullptr /* TODO Sampler */,
|
||||||
|
.imageView = image->m_View,
|
||||||
|
.imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal,
|
||||||
|
});
|
||||||
|
m_Writes.push_back({
|
||||||
|
.dstSet = m_DescriptorSet,
|
||||||
|
.dstBinding = IMAGE_BINDING_INDEX,
|
||||||
|
.dstArrayElement = handle.GetIndex(),
|
||||||
|
.descriptorCount = 1,
|
||||||
|
.descriptorType = vk::DescriptorType::eSampledImage,
|
||||||
|
.pImageInfo = &m_WriteInfos.back().uImageInfo,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
static_assert(false && "Type is currently unsupported");
|
||||||
|
}
|
||||||
|
|
||||||
|
m_WriteOwner.emplace_back(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderResourceManager::WriteInfo::WriteInfo(const vk::DescriptorBufferInfo &info)
|
||||||
|
: uBufferInfo{info}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderResourceManager::WriteInfo::WriteInfo(const vk::DescriptorImageInfo &info)
|
||||||
|
: uImageInfo{info}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderResourceManager::WriteInfo::WriteInfo(const vk::BufferView &info)
|
||||||
|
: uBufferView{info}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
@ -10,9 +10,9 @@
|
||||||
#include "aster/core/context.h"
|
#include "aster/core/context.h"
|
||||||
#include "aster/core/device.h"
|
#include "aster/core/device.h"
|
||||||
#include "aster/core/physical_device.h"
|
#include "aster/core/physical_device.h"
|
||||||
#include "aster/core/window.h"
|
|
||||||
#include "aster/core/pipeline.h"
|
#include "aster/core/pipeline.h"
|
||||||
#include "aster/core/swapchain.h"
|
#include "aster/core/swapchain.h"
|
||||||
|
#include "aster/core/window.h"
|
||||||
|
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
|
|
||||||
|
|
@ -83,7 +83,10 @@ main(int, char **)
|
||||||
|
|
||||||
INFO("Using {} as the primary device.", deviceToUse.m_DeviceProperties.deviceName.data());
|
INFO("Using {} as the primary device.", deviceToUse.m_DeviceProperties.deviceName.data());
|
||||||
|
|
||||||
Features enabledDeviceFeatures = {.m_Vulkan13Features = {.dynamicRendering = true}};
|
Features enabledDeviceFeatures = {
|
||||||
|
.m_Vulkan12Features = {.bufferDeviceAddress = true},
|
||||||
|
.m_Vulkan13Features = {.synchronization2 = true, .dynamicRendering = true},
|
||||||
|
};
|
||||||
QueueAllocation queueAllocation = FindAppropriateQueueAllocation(&deviceToUse);
|
QueueAllocation queueAllocation = FindAppropriateQueueAllocation(&deviceToUse);
|
||||||
Device device = {&context, &deviceToUse, &enabledDeviceFeatures, {queueAllocation}, "Primary Device"};
|
Device device = {&context, &deviceToUse, &enabledDeviceFeatures, {queueAllocation}, "Primary Device"};
|
||||||
vk::Queue commandQueue = device.GetQueue(queueAllocation.m_Family, 0);
|
vk::Queue commandQueue = device.GetQueue(queueAllocation.m_Family, 0);
|
||||||
|
|
@ -176,24 +179,40 @@ main(int, char **)
|
||||||
.baseArrayLayer = 0,
|
.baseArrayLayer = 0,
|
||||||
.layerCount = 1,
|
.layerCount = 1,
|
||||||
};
|
};
|
||||||
vk::ImageMemoryBarrier topOfThePipeBarrier = {
|
vk::ImageMemoryBarrier2 topOfThePipeBarrier = {
|
||||||
|
.srcStageMask = vk::PipelineStageFlagBits2::eColorAttachmentOutput,
|
||||||
|
.srcAccessMask = vk::AccessFlagBits2::eNone,
|
||||||
|
.dstStageMask = vk::PipelineStageFlagBits2::eColorAttachmentOutput,
|
||||||
|
.dstAccessMask = vk::AccessFlagBits2::eColorAttachmentWrite,
|
||||||
.oldLayout = vk::ImageLayout::eUndefined,
|
.oldLayout = vk::ImageLayout::eUndefined,
|
||||||
.newLayout = vk::ImageLayout::eColorAttachmentOptimal,
|
.newLayout = vk::ImageLayout::eColorAttachmentOptimal,
|
||||||
.srcQueueFamilyIndex = queueAllocation.m_Family,
|
.srcQueueFamilyIndex = queueAllocation.m_Family,
|
||||||
.dstQueueFamilyIndex = queueAllocation.m_Family,
|
.dstQueueFamilyIndex = queueAllocation.m_Family,
|
||||||
.subresourceRange = subresourceRange,
|
.subresourceRange = subresourceRange,
|
||||||
};
|
};
|
||||||
vk::ImageMemoryBarrier renderToPresentBarrier = {
|
vk::DependencyInfo topOfThePipeDependency = {
|
||||||
|
.imageMemoryBarrierCount = 1,
|
||||||
|
.pImageMemoryBarriers = &topOfThePipeBarrier,
|
||||||
|
};
|
||||||
|
vk::ImageMemoryBarrier2 renderToPresentBarrier = {
|
||||||
|
.srcStageMask = vk::PipelineStageFlagBits2::eColorAttachmentOutput,
|
||||||
|
.srcAccessMask = vk::AccessFlagBits2::eColorAttachmentWrite,
|
||||||
|
.dstStageMask = vk::PipelineStageFlagBits2::eBottomOfPipe,
|
||||||
|
.dstAccessMask = vk::AccessFlagBits2::eNone,
|
||||||
.oldLayout = vk::ImageLayout::eColorAttachmentOptimal,
|
.oldLayout = vk::ImageLayout::eColorAttachmentOptimal,
|
||||||
.newLayout = vk::ImageLayout::ePresentSrcKHR,
|
.newLayout = vk::ImageLayout::ePresentSrcKHR,
|
||||||
.srcQueueFamilyIndex = queueAllocation.m_Family,
|
.srcQueueFamilyIndex = queueAllocation.m_Family,
|
||||||
.dstQueueFamilyIndex = queueAllocation.m_Family,
|
.dstQueueFamilyIndex = queueAllocation.m_Family,
|
||||||
.subresourceRange = subresourceRange,
|
.subresourceRange = subresourceRange,
|
||||||
};
|
};
|
||||||
|
vk::DependencyInfo renderToPresentDependency = {
|
||||||
|
.imageMemoryBarrierCount = 1,
|
||||||
|
.pImageMemoryBarriers = &renderToPresentBarrier,
|
||||||
|
};
|
||||||
|
|
||||||
// Frames
|
// Frames
|
||||||
eastl::fixed_vector<Frame, MAX_FRAMES_IN_FLIGHT> frames;
|
eastl::fixed_vector<Frame, MAX_FRAMES_IN_FLIGHT> frames;
|
||||||
for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i)
|
for (u32 i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i)
|
||||||
{
|
{
|
||||||
frames.emplace_back(&device, queueAllocation.m_Family, i);
|
frames.emplace_back(&device, queueAllocation.m_Family, i);
|
||||||
}
|
}
|
||||||
|
|
@ -250,8 +269,7 @@ main(int, char **)
|
||||||
ERROR_IF(Failed(result), "Command buffer begin failed. Cause: {}", result)
|
ERROR_IF(Failed(result), "Command buffer begin failed. Cause: {}", result)
|
||||||
THEN_ABORT(result);
|
THEN_ABORT(result);
|
||||||
|
|
||||||
cmd.pipelineBarrier(vk::PipelineStageFlagBits::eTopOfPipe, vk::PipelineStageFlagBits::eColorAttachmentOutput,
|
cmd.pipelineBarrier2(&topOfThePipeDependency);
|
||||||
{}, 0, nullptr, 0, nullptr, 1, &topOfThePipeBarrier);
|
|
||||||
|
|
||||||
// Render
|
// Render
|
||||||
vk::RenderingAttachmentInfo attachmentInfo = {
|
vk::RenderingAttachmentInfo attachmentInfo = {
|
||||||
|
|
@ -260,7 +278,7 @@ main(int, char **)
|
||||||
.resolveMode = vk::ResolveModeFlagBits::eNone,
|
.resolveMode = vk::ResolveModeFlagBits::eNone,
|
||||||
.loadOp = vk::AttachmentLoadOp::eClear,
|
.loadOp = vk::AttachmentLoadOp::eClear,
|
||||||
.storeOp = vk::AttachmentStoreOp::eStore,
|
.storeOp = vk::AttachmentStoreOp::eStore,
|
||||||
.clearValue = vk::ClearColorValue{0.0f, 0.0f, 0.0f, 1.0f},
|
.clearValue = vk::ClearColorValue{0.0f, 0.0f, 0.0f, 0.0f},
|
||||||
};
|
};
|
||||||
|
|
||||||
vk::RenderingInfo renderingInfo = {
|
vk::RenderingInfo renderingInfo = {
|
||||||
|
|
@ -281,8 +299,7 @@ main(int, char **)
|
||||||
|
|
||||||
cmd.endRendering();
|
cmd.endRendering();
|
||||||
|
|
||||||
cmd.pipelineBarrier(vk::PipelineStageFlagBits::eColorAttachmentOutput, vk::PipelineStageFlagBits::eBottomOfPipe,
|
cmd.pipelineBarrier2(&renderToPresentDependency);
|
||||||
{}, 0, nullptr, 0, nullptr, 1, &renderToPresentBarrier);
|
|
||||||
|
|
||||||
result = cmd.end();
|
result = cmd.end();
|
||||||
ERROR_IF(Failed(result), "Command buffer end failed. Cause: {}", result)
|
ERROR_IF(Failed(result), "Command buffer end failed. Cause: {}", result)
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,8 @@ cmake_minimum_required(VERSION 3.13)
|
||||||
add_executable(box "box.cpp" "stb_image.h")
|
add_executable(box "box.cpp" "stb_image.h")
|
||||||
add_shader(box "shader/box.vert.glsl")
|
add_shader(box "shader/box.vert.glsl")
|
||||||
add_shader(box "shader/box.frag.glsl")
|
add_shader(box "shader/box.frag.glsl")
|
||||||
|
add_shader(box "shader/box.vs.hlsl")
|
||||||
|
add_shader(box "shader/box.ps.hlsl")
|
||||||
|
|
||||||
target_link_libraries(box PRIVATE aster_core)
|
target_link_libraries(box PRIVATE aster_core)
|
||||||
target_link_libraries(box PRIVATE util_helper)
|
target_link_libraries(box PRIVATE util_helper)
|
||||||
|
|
|
||||||
|
|
@ -9,23 +9,25 @@
|
||||||
#include "aster/core/constants.h"
|
#include "aster/core/constants.h"
|
||||||
#include "aster/core/context.h"
|
#include "aster/core/context.h"
|
||||||
#include "aster/core/device.h"
|
#include "aster/core/device.h"
|
||||||
|
#include "aster/core/image.h"
|
||||||
#include "aster/core/physical_device.h"
|
#include "aster/core/physical_device.h"
|
||||||
#include "aster/core/pipeline.h"
|
#include "aster/core/pipeline.h"
|
||||||
#include "aster/core/swapchain.h"
|
#include "aster/core/swapchain.h"
|
||||||
#include "aster/core/window.h"
|
#include "aster/core/window.h"
|
||||||
#include "aster/core/image.h"
|
|
||||||
|
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
|
|
||||||
#define STB_IMAGE_IMPLEMENTATION
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
|
#include "aster/systems/buffer_manager.h"
|
||||||
|
#include "aster/systems/image_manager.h"
|
||||||
#include "frame.h"
|
#include "frame.h"
|
||||||
#include "stb_image.h"
|
#include "stb_image.h"
|
||||||
|
|
||||||
#include <EASTL/array.h>
|
#include <EASTL/array.h>
|
||||||
|
|
||||||
constexpr u32 MAX_FRAMES_IN_FLIGHT = 3;
|
constexpr u32 MAX_FRAMES_IN_FLIGHT = 3;
|
||||||
constexpr auto VERTEX_SHADER_FILE = "shader/box.vert.glsl.spv";
|
constexpr auto VERTEX_SHADER_FILE = "shader/box.vs.hlsl.spv";
|
||||||
constexpr auto FRAGMENT_SHADER_FILE = "shader/box.frag.glsl.spv";
|
constexpr auto FRAGMENT_SHADER_FILE = "shader/box.ps.hlsl.spv";
|
||||||
|
|
||||||
struct ImageFile
|
struct ImageFile
|
||||||
{
|
{
|
||||||
|
|
@ -76,32 +78,9 @@ Pipeline CreatePipeline(const Device *device, const Swapchain *swapchain);
|
||||||
struct Vertex
|
struct Vertex
|
||||||
{
|
{
|
||||||
vec3 m_Position;
|
vec3 m_Position;
|
||||||
|
f32 m_PositionW = 1.0;
|
||||||
vec2 m_TexCoord0;
|
vec2 m_TexCoord0;
|
||||||
|
vec2 m_Padding0_ = {0.0f, 0.0f};
|
||||||
constexpr static vk::VertexInputBindingDescription
|
|
||||||
GetBinding(const u32 binding)
|
|
||||||
{
|
|
||||||
return {.binding = binding, .stride = sizeof(Vertex), .inputRate = vk::VertexInputRate::eVertex};
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr static eastl::array<vk::VertexInputAttributeDescription, 2>
|
|
||||||
GetAttributes(const u32 binding)
|
|
||||||
{
|
|
||||||
return {
|
|
||||||
vk::VertexInputAttributeDescription{
|
|
||||||
.location = 0,
|
|
||||||
.binding = binding,
|
|
||||||
.format = vk::Format::eR32G32B32Sfloat,
|
|
||||||
.offset = offsetof(Vertex, m_Position),
|
|
||||||
},
|
|
||||||
vk::VertexInputAttributeDescription{
|
|
||||||
.location = 1,
|
|
||||||
.binding = binding,
|
|
||||||
.format = vk::Format::eR32G32Sfloat,
|
|
||||||
.offset = offsetof(Vertex, m_TexCoord0),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Camera
|
struct Camera
|
||||||
|
|
@ -127,7 +106,8 @@ main(int, char **)
|
||||||
|
|
||||||
Features enabledDeviceFeatures = {
|
Features enabledDeviceFeatures = {
|
||||||
.m_Vulkan10Features = {.samplerAnisotropy = true},
|
.m_Vulkan10Features = {.samplerAnisotropy = true},
|
||||||
.m_Vulkan13Features = {.dynamicRendering = true},
|
.m_Vulkan12Features = {.bufferDeviceAddress = true},
|
||||||
|
.m_Vulkan13Features = {.synchronization2 = true, .dynamicRendering = true},
|
||||||
};
|
};
|
||||||
QueueAllocation queueAllocation = FindAppropriateQueueAllocation(&deviceToUse);
|
QueueAllocation queueAllocation = FindAppropriateQueueAllocation(&deviceToUse);
|
||||||
Device device = {&context, &deviceToUse, &enabledDeviceFeatures, {queueAllocation}, "Primary Device"};
|
Device device = {&context, &deviceToUse, &enabledDeviceFeatures, {queueAllocation}, "Primary Device"};
|
||||||
|
|
@ -135,6 +115,9 @@ main(int, char **)
|
||||||
Swapchain swapchain = {&surface, &device, window.GetSize(), "Primary Chain"};
|
Swapchain swapchain = {&surface, &device, window.GetSize(), "Primary Chain"};
|
||||||
Pipeline pipeline = CreatePipeline(&device, &swapchain);
|
Pipeline pipeline = CreatePipeline(&device, &swapchain);
|
||||||
|
|
||||||
|
systems::BufferManager bufferManager{&device, 12, 0};
|
||||||
|
systems::ImageManager imageManager{&device, 12, 1};
|
||||||
|
|
||||||
Camera camera = {
|
Camera camera = {
|
||||||
.m_Model = {1.0f},
|
.m_Model = {1.0f},
|
||||||
.m_View = glm::lookAt(vec3(0.0f, 2.0f, 2.0f), vec3(0.0f), vec3(0.0f, 1.0f, 0.0f)),
|
.m_View = glm::lookAt(vec3(0.0f, 2.0f, 2.0f), vec3(0.0f), vec3(0.0f, 1.0f, 0.0f)),
|
||||||
|
|
@ -155,6 +138,10 @@ main(int, char **)
|
||||||
.type = vk::DescriptorType::eCombinedImageSampler,
|
.type = vk::DescriptorType::eCombinedImageSampler,
|
||||||
.descriptorCount = 1,
|
.descriptorCount = 1,
|
||||||
},
|
},
|
||||||
|
vk::DescriptorPoolSize{
|
||||||
|
.type = vk::DescriptorType::eStorageBuffer,
|
||||||
|
.descriptorCount = 1,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
vk::DescriptorPoolCreateInfo descriptorPoolCreateInfo = {
|
vk::DescriptorPoolCreateInfo descriptorPoolCreateInfo = {
|
||||||
.maxSets = 1, .poolSizeCount = Cast<u32>(poolSizes.size()), .pPoolSizes = poolSizes.data()};
|
.maxSets = 1, .poolSizeCount = Cast<u32>(poolSizes.size()), .pPoolSizes = poolSizes.data()};
|
||||||
|
|
@ -235,24 +222,32 @@ main(int, char **)
|
||||||
assert(loaded);
|
assert(loaded);
|
||||||
INFO("Image {}x{} : {} channels", imageFile.m_Width, imageFile.m_Height, imageFile.m_NumChannels);
|
INFO("Image {}x{} : {} channels", imageFile.m_Width, imageFile.m_Height, imageFile.m_NumChannels);
|
||||||
|
|
||||||
VertexBuffer vbo;
|
auto vbo = bufferManager.CreateStorageBuffer(vertices.size() * sizeof vertices[0], "Vertex Buffer").ToPointer();
|
||||||
Texture crate;
|
auto crate = imageManager
|
||||||
vbo.Init(&device, vertices.size() * sizeof vertices[0], "VBO");
|
.CreateTexture2D({
|
||||||
crate.Init(&device, {imageFile.m_Width, imageFile.m_Height}, vk::Format::eR8G8B8A8Srgb, false, "Crate Texture");
|
.m_Format = vk::Format::eR8G8B8A8Srgb,
|
||||||
|
.m_Extent = {imageFile.m_Width, imageFile.m_Height},
|
||||||
|
.m_Name = "Crate Texture",
|
||||||
|
})
|
||||||
|
.ToPointer();
|
||||||
|
vbo->Write(&device, 0, vertices.size() * sizeof vertices[0], vertices.data());
|
||||||
|
|
||||||
{
|
{
|
||||||
StagingBuffer vertexStaging, imageStaging;
|
StagingBuffer imageStaging;
|
||||||
vertexStaging.Init(&device, vertices.size() * sizeof vertices[0], "Vertex Staging");
|
|
||||||
vertexStaging.Write(&device, 0, vertices.size() * sizeof vertices[0], vertices.data());
|
|
||||||
|
|
||||||
imageStaging.Init(&device, imageFile.GetSize(), "Image Staging");
|
imageStaging.Init(&device, imageFile.GetSize(), "Image Staging");
|
||||||
imageStaging.Write(&device, 0, imageFile.GetSize(), imageFile.m_Data);
|
imageStaging.Write(&device, 0, imageFile.GetSize(), imageFile.m_Data);
|
||||||
|
|
||||||
vk::ImageMemoryBarrier imageReadyToWrite = {
|
vk::ImageMemoryBarrier2 imageReadyToWrite = {
|
||||||
|
.srcStageMask = vk::PipelineStageFlagBits2::eTransfer,
|
||||||
|
.srcAccessMask = vk::AccessFlagBits2::eNone,
|
||||||
|
.dstStageMask = vk::PipelineStageFlagBits2::eTransfer,
|
||||||
|
.dstAccessMask = vk::AccessFlagBits2::eTransferWrite,
|
||||||
.oldLayout = vk::ImageLayout::eUndefined,
|
.oldLayout = vk::ImageLayout::eUndefined,
|
||||||
.newLayout = vk::ImageLayout::eTransferDstOptimal,
|
.newLayout = vk::ImageLayout::eTransferDstOptimal,
|
||||||
.srcQueueFamilyIndex = queueAllocation.m_Family,
|
.srcQueueFamilyIndex = queueAllocation.m_Family,
|
||||||
.dstQueueFamilyIndex = queueAllocation.m_Family,
|
.dstQueueFamilyIndex = queueAllocation.m_Family,
|
||||||
.image = crate.m_Image,
|
.image = crate->m_Image,
|
||||||
.subresourceRange =
|
.subresourceRange =
|
||||||
{
|
{
|
||||||
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||||
|
|
@ -262,13 +257,21 @@ main(int, char **)
|
||||||
.layerCount = 1,
|
.layerCount = 1,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
vk::DependencyInfo imageReadyToWriteDependency = {
|
||||||
|
.imageMemoryBarrierCount = 1,
|
||||||
|
.pImageMemoryBarriers = &imageReadyToWrite,
|
||||||
|
};
|
||||||
|
|
||||||
vk::ImageMemoryBarrier imageReadyToRead = {
|
vk::ImageMemoryBarrier2 imageReadyToRead = {
|
||||||
|
.srcStageMask = vk::PipelineStageFlagBits2::eTransfer,
|
||||||
|
.srcAccessMask = vk::AccessFlagBits2::eTransferWrite,
|
||||||
|
.dstStageMask = vk::PipelineStageFlagBits2::eFragmentShader,
|
||||||
|
.dstAccessMask = vk::AccessFlagBits2::eShaderRead,
|
||||||
.oldLayout = vk::ImageLayout::eTransferDstOptimal,
|
.oldLayout = vk::ImageLayout::eTransferDstOptimal,
|
||||||
.newLayout = vk::ImageLayout::eShaderReadOnlyOptimal,
|
.newLayout = vk::ImageLayout::eShaderReadOnlyOptimal,
|
||||||
.srcQueueFamilyIndex = queueAllocation.m_Family,
|
.srcQueueFamilyIndex = queueAllocation.m_Family,
|
||||||
.dstQueueFamilyIndex = queueAllocation.m_Family,
|
.dstQueueFamilyIndex = queueAllocation.m_Family,
|
||||||
.image = crate.m_Image,
|
.image = crate->m_Image,
|
||||||
.subresourceRange =
|
.subresourceRange =
|
||||||
{
|
{
|
||||||
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||||
|
|
@ -278,6 +281,10 @@ main(int, char **)
|
||||||
.layerCount = 1,
|
.layerCount = 1,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
vk::DependencyInfo imageReadyToReadDependency = {
|
||||||
|
.imageMemoryBarrierCount = 1,
|
||||||
|
.pImageMemoryBarriers = &imageReadyToRead,
|
||||||
|
};
|
||||||
|
|
||||||
vk::Fence fence;
|
vk::Fence fence;
|
||||||
vk::FenceCreateInfo fenceCreateInfo = {};
|
vk::FenceCreateInfo fenceCreateInfo = {};
|
||||||
|
|
@ -285,11 +292,8 @@ main(int, char **)
|
||||||
|
|
||||||
vk::CommandBufferBeginInfo beginInfo = {.flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit};
|
vk::CommandBufferBeginInfo beginInfo = {.flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit};
|
||||||
AbortIfFailed(copyBuffer.begin(&beginInfo));
|
AbortIfFailed(copyBuffer.begin(&beginInfo));
|
||||||
copyBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eHost, vk::PipelineStageFlagBits::eTransfer, {}, 0,
|
|
||||||
nullptr, 0, nullptr, 1, &imageReadyToWrite);
|
|
||||||
|
|
||||||
vk::BufferCopy bufferCopy = {.srcOffset = 0, .dstOffset = 0, .size = vertexStaging.GetSize()};
|
copyBuffer.pipelineBarrier2(&imageReadyToWriteDependency);
|
||||||
copyBuffer.copyBuffer(vertexStaging.m_Buffer, vbo.m_Buffer, 1, &bufferCopy);
|
|
||||||
|
|
||||||
vk::BufferImageCopy imageCopy = {
|
vk::BufferImageCopy imageCopy = {
|
||||||
.bufferOffset = 0,
|
.bufferOffset = 0,
|
||||||
|
|
@ -305,11 +309,10 @@ main(int, char **)
|
||||||
.imageOffset = {},
|
.imageOffset = {},
|
||||||
.imageExtent = {imageFile.m_Width, imageFile.m_Height, 1},
|
.imageExtent = {imageFile.m_Width, imageFile.m_Height, 1},
|
||||||
};
|
};
|
||||||
copyBuffer.copyBufferToImage(imageStaging.m_Buffer, crate.m_Image, vk::ImageLayout::eTransferDstOptimal, 1,
|
copyBuffer.copyBufferToImage(imageStaging.m_Buffer, crate->m_Image, vk::ImageLayout::eTransferDstOptimal, 1,
|
||||||
&imageCopy);
|
&imageCopy);
|
||||||
|
|
||||||
copyBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eFragmentShader, {},
|
copyBuffer.pipelineBarrier2(&imageReadyToReadDependency);
|
||||||
0, nullptr, 0, nullptr, 1, &imageReadyToRead);
|
|
||||||
|
|
||||||
AbortIfFailed(copyBuffer.end());
|
AbortIfFailed(copyBuffer.end());
|
||||||
|
|
||||||
|
|
@ -327,7 +330,6 @@ main(int, char **)
|
||||||
AbortIfFailedM(device.m_Device.resetCommandPool(copyPool, {}), "Couldn't reset command pool.");
|
AbortIfFailedM(device.m_Device.resetCommandPool(copyPool, {}), "Couldn't reset command pool.");
|
||||||
|
|
||||||
device.m_Device.destroy(fence, nullptr);
|
device.m_Device.destroy(fence, nullptr);
|
||||||
vertexStaging.Destroy(&device);
|
|
||||||
imageStaging.Destroy(&device);
|
imageStaging.Destroy(&device);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -351,19 +353,23 @@ main(int, char **)
|
||||||
AbortIfFailed(device.m_Device.createSampler(&samplerCreateInfo, nullptr, &sampler));
|
AbortIfFailed(device.m_Device.createSampler(&samplerCreateInfo, nullptr, &sampler));
|
||||||
}
|
}
|
||||||
|
|
||||||
UniformBuffer ubo;
|
auto ubo = bufferManager.CreateUniformBuffer(sizeof camera, "Camera UBO").ToPointer();
|
||||||
ubo.Init(&device, sizeof camera, "Camera UBO");
|
ubo->Write(&device, 0, sizeof camera, &camera);
|
||||||
ubo.Write(&device, 0, sizeof camera, &camera);
|
|
||||||
vk::DescriptorBufferInfo descriptorBufferInfo = {
|
vk::DescriptorBufferInfo descriptorBufferInfo = {
|
||||||
.buffer = ubo.m_Buffer,
|
.buffer = ubo->m_Buffer,
|
||||||
.offset = 0,
|
.offset = 0,
|
||||||
.range = ubo.GetSize(),
|
.range = ubo->GetSize(),
|
||||||
};
|
};
|
||||||
vk::DescriptorImageInfo descriptorImageInfo = {
|
vk::DescriptorImageInfo descriptorImageInfo = {
|
||||||
.sampler = sampler,
|
.sampler = sampler,
|
||||||
.imageView = crate.m_View,
|
.imageView = crate->m_View,
|
||||||
.imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal,
|
.imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal,
|
||||||
};
|
};
|
||||||
|
vk::DescriptorBufferInfo descriptorStorageBufferInfo = {
|
||||||
|
.buffer = vbo->m_Buffer,
|
||||||
|
.offset = 0,
|
||||||
|
.range = vbo->GetSize(),
|
||||||
|
};
|
||||||
eastl::array writeDescriptors = {
|
eastl::array writeDescriptors = {
|
||||||
vk::WriteDescriptorSet{
|
vk::WriteDescriptorSet{
|
||||||
.dstSet = descriptorSet,
|
.dstSet = descriptorSet,
|
||||||
|
|
@ -381,6 +387,14 @@ main(int, char **)
|
||||||
.descriptorType = vk::DescriptorType::eCombinedImageSampler,
|
.descriptorType = vk::DescriptorType::eCombinedImageSampler,
|
||||||
.pImageInfo = &descriptorImageInfo,
|
.pImageInfo = &descriptorImageInfo,
|
||||||
},
|
},
|
||||||
|
vk::WriteDescriptorSet{
|
||||||
|
.dstSet = descriptorSet,
|
||||||
|
.dstBinding = 2,
|
||||||
|
.dstArrayElement = 0,
|
||||||
|
.descriptorCount = 1,
|
||||||
|
.descriptorType = vk::DescriptorType::eStorageBuffer,
|
||||||
|
.pBufferInfo = &descriptorStorageBufferInfo,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
device.m_Device.updateDescriptorSets(Cast<u32>(writeDescriptors.size()), writeDescriptors.data(), 0, nullptr);
|
device.m_Device.updateDescriptorSets(Cast<u32>(writeDescriptors.size()), writeDescriptors.data(), 0, nullptr);
|
||||||
|
|
||||||
|
|
@ -414,35 +428,56 @@ main(int, char **)
|
||||||
.baseArrayLayer = 0,
|
.baseArrayLayer = 0,
|
||||||
.layerCount = 1,
|
.layerCount = 1,
|
||||||
};
|
};
|
||||||
vk::ImageMemoryBarrier topOfThePipeBarrier = {
|
vk::ImageMemoryBarrier2 topOfThePipeBarrier = {
|
||||||
|
// For Color Attachment output ref:
|
||||||
|
// https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/7193#issuecomment-1875960974
|
||||||
|
.srcStageMask = vk::PipelineStageFlagBits2::eColorAttachmentOutput,
|
||||||
|
.srcAccessMask = vk::AccessFlagBits2::eNone,
|
||||||
|
.dstStageMask = vk::PipelineStageFlagBits2::eColorAttachmentOutput,
|
||||||
|
.dstAccessMask = vk::AccessFlagBits2::eColorAttachmentWrite,
|
||||||
.oldLayout = vk::ImageLayout::eUndefined,
|
.oldLayout = vk::ImageLayout::eUndefined,
|
||||||
.newLayout = vk::ImageLayout::eColorAttachmentOptimal,
|
.newLayout = vk::ImageLayout::eColorAttachmentOptimal,
|
||||||
.srcQueueFamilyIndex = queueAllocation.m_Family,
|
.srcQueueFamilyIndex = queueAllocation.m_Family,
|
||||||
.dstQueueFamilyIndex = queueAllocation.m_Family,
|
.dstQueueFamilyIndex = queueAllocation.m_Family,
|
||||||
.subresourceRange = subresourceRange,
|
.subresourceRange = subresourceRange,
|
||||||
};
|
};
|
||||||
vk::ImageMemoryBarrier renderToPresentBarrier = {
|
vk::DependencyInfo topOfThePipeDependency = {
|
||||||
|
.imageMemoryBarrierCount = 1,
|
||||||
|
.pImageMemoryBarriers = &topOfThePipeBarrier,
|
||||||
|
};
|
||||||
|
vk::ImageMemoryBarrier2 renderToPresentBarrier = {
|
||||||
|
.srcStageMask = vk::PipelineStageFlagBits2::eColorAttachmentOutput,
|
||||||
|
.srcAccessMask = vk::AccessFlagBits2::eColorAttachmentWrite,
|
||||||
|
.dstStageMask = vk::PipelineStageFlagBits2::eBottomOfPipe,
|
||||||
|
.dstAccessMask = vk::AccessFlagBits2::eNone,
|
||||||
.oldLayout = vk::ImageLayout::eColorAttachmentOptimal,
|
.oldLayout = vk::ImageLayout::eColorAttachmentOptimal,
|
||||||
.newLayout = vk::ImageLayout::ePresentSrcKHR,
|
.newLayout = vk::ImageLayout::ePresentSrcKHR,
|
||||||
.srcQueueFamilyIndex = queueAllocation.m_Family,
|
.srcQueueFamilyIndex = queueAllocation.m_Family,
|
||||||
.dstQueueFamilyIndex = queueAllocation.m_Family,
|
.dstQueueFamilyIndex = queueAllocation.m_Family,
|
||||||
.subresourceRange = subresourceRange,
|
.subresourceRange = subresourceRange,
|
||||||
};
|
};
|
||||||
|
vk::DependencyInfo renderToPresentDependency = {
|
||||||
|
.imageMemoryBarrierCount = 1,
|
||||||
|
.pImageMemoryBarriers = &renderToPresentBarrier,
|
||||||
|
};
|
||||||
|
|
||||||
FrameManager frameManager = {&device, queueAllocation.m_Family, MAX_FRAMES_IN_FLIGHT};
|
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<Ref<Image>, MAX_FRAMES_IN_FLIGHT> depthImages;
|
||||||
for (auto &depthImage : depthImages)
|
|
||||||
{
|
|
||||||
depthImage.Init(&device, swapchain.m_Extent, "Depth");
|
|
||||||
}
|
|
||||||
|
|
||||||
auto recreateDepthBuffers = [&device, &depthImages](vk::Extent2D extent) {
|
auto initDepthImages = [&imageManager, &depthImages, &frameManager] (const vk::Extent2D extent) {
|
||||||
for (auto &depthImage : depthImages)
|
for (u32 i = 0; i < frameManager.m_FramesInFlight; ++i)
|
||||||
{
|
{
|
||||||
depthImage.Destroy(&device);
|
depthImages.push_back(
|
||||||
depthImage.Init(&device, extent, "Depth");
|
imageManager.CreateDepthStencilImage({.m_Extent = extent, .m_Name = "Depth"}).ToPointer());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
initDepthImages(swapchain.m_Extent);
|
||||||
|
|
||||||
|
auto recreateDepthBuffers = [&depthImages, &initDepthImages](const vk::Extent2D extent) {
|
||||||
|
depthImages.clear();
|
||||||
|
initDepthImages(extent);
|
||||||
|
};
|
||||||
swapchain.RegisterResizeCallback(recreateDepthBuffers);
|
swapchain.RegisterResizeCallback(recreateDepthBuffers);
|
||||||
|
|
||||||
Time::Init();
|
Time::Init();
|
||||||
|
|
@ -453,7 +488,7 @@ main(int, char **)
|
||||||
Time::Update();
|
Time::Update();
|
||||||
|
|
||||||
camera.m_Model *= rotate(mat4{1.0f}, Cast<f32>(45.0_deg * Time::m_Delta), vec3(0.0f, 1.0f, 0.0f));
|
camera.m_Model *= rotate(mat4{1.0f}, Cast<f32>(45.0_deg * Time::m_Delta), vec3(0.0f, 1.0f, 0.0f));
|
||||||
ubo.Write(&device, 0, sizeof camera, &camera);
|
ubo->Write(&device, 0, sizeof camera, &camera);
|
||||||
|
|
||||||
Frame *currentFrame = frameManager.GetNextFrame(&swapchain, &surface, window.GetSize());
|
Frame *currentFrame = frameManager.GetNextFrame(&swapchain, &surface, window.GetSize());
|
||||||
|
|
||||||
|
|
@ -461,7 +496,7 @@ main(int, char **)
|
||||||
vk::ImageView currentImageView = swapchain.m_ImageViews[imageIndex];
|
vk::ImageView currentImageView = swapchain.m_ImageViews[imageIndex];
|
||||||
vk::Image currentImage = swapchain.m_Images[imageIndex];
|
vk::Image currentImage = swapchain.m_Images[imageIndex];
|
||||||
vk::CommandBuffer cmd = currentFrame->m_CommandBuffer;
|
vk::CommandBuffer cmd = currentFrame->m_CommandBuffer;
|
||||||
vk::ImageView currentDepthImageView = depthImages[currentFrame->m_FrameIdx].m_View;
|
vk::ImageView currentDepthImageView = depthImages[currentFrame->m_FrameIdx]->m_View;
|
||||||
|
|
||||||
topOfThePipeBarrier.image = currentImage;
|
topOfThePipeBarrier.image = currentImage;
|
||||||
renderToPresentBarrier.image = currentImage;
|
renderToPresentBarrier.image = currentImage;
|
||||||
|
|
@ -469,8 +504,7 @@ main(int, char **)
|
||||||
vk::CommandBufferBeginInfo beginInfo = {.flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit};
|
vk::CommandBufferBeginInfo beginInfo = {.flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit};
|
||||||
AbortIfFailed(cmd.begin(&beginInfo));
|
AbortIfFailed(cmd.begin(&beginInfo));
|
||||||
|
|
||||||
cmd.pipelineBarrier(vk::PipelineStageFlagBits::eTopOfPipe, vk::PipelineStageFlagBits::eColorAttachmentOutput,
|
cmd.pipelineBarrier2(&topOfThePipeDependency);
|
||||||
{}, 0, nullptr, 0, nullptr, 1, &topOfThePipeBarrier);
|
|
||||||
|
|
||||||
// Render
|
// Render
|
||||||
eastl::array attachmentInfos = {
|
eastl::array attachmentInfos = {
|
||||||
|
|
@ -480,7 +514,7 @@ main(int, char **)
|
||||||
.resolveMode = vk::ResolveModeFlagBits::eNone,
|
.resolveMode = vk::ResolveModeFlagBits::eNone,
|
||||||
.loadOp = vk::AttachmentLoadOp::eClear,
|
.loadOp = vk::AttachmentLoadOp::eClear,
|
||||||
.storeOp = vk::AttachmentStoreOp::eStore,
|
.storeOp = vk::AttachmentStoreOp::eStore,
|
||||||
.clearValue = vk::ClearColorValue{0.0f, 0.0f, 0.0f, 1.0f},
|
.clearValue = vk::ClearColorValue{0.0f, 0.0f, 0.0f, 0.0f},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -507,14 +541,11 @@ main(int, char **)
|
||||||
cmd.setScissor(0, 1, &scissor);
|
cmd.setScissor(0, 1, &scissor);
|
||||||
cmd.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline.m_Pipeline);
|
cmd.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline.m_Pipeline);
|
||||||
cmd.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipeline.m_Layout, 0, 1, &descriptorSet, 0, nullptr);
|
cmd.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipeline.m_Layout, 0, 1, &descriptorSet, 0, nullptr);
|
||||||
usize offsets = 0;
|
|
||||||
cmd.bindVertexBuffers(0, 1, &vbo.m_Buffer, &offsets);
|
|
||||||
cmd.draw(Cast<u32>(vertices.size()), 1, 0, 0);
|
cmd.draw(Cast<u32>(vertices.size()), 1, 0, 0);
|
||||||
|
|
||||||
cmd.endRendering();
|
cmd.endRendering();
|
||||||
|
|
||||||
cmd.pipelineBarrier(vk::PipelineStageFlagBits::eColorAttachmentOutput, vk::PipelineStageFlagBits::eBottomOfPipe,
|
cmd.pipelineBarrier2(&renderToPresentDependency);
|
||||||
{}, 0, nullptr, 0, nullptr, 1, &renderToPresentBarrier);
|
|
||||||
|
|
||||||
AbortIfFailed(cmd.end());
|
AbortIfFailed(cmd.end());
|
||||||
|
|
||||||
|
|
@ -534,17 +565,9 @@ main(int, char **)
|
||||||
}
|
}
|
||||||
|
|
||||||
device.WaitIdle();
|
device.WaitIdle();
|
||||||
|
|
||||||
for (auto &depthImage : depthImages)
|
|
||||||
{
|
|
||||||
depthImage.Destroy(&device);
|
|
||||||
}
|
|
||||||
device.m_Device.destroy(sampler, nullptr);
|
device.m_Device.destroy(sampler, nullptr);
|
||||||
ubo.Destroy(&device);
|
|
||||||
device.m_Device.destroy(descriptorPool, nullptr);
|
device.m_Device.destroy(descriptorPool, nullptr);
|
||||||
device.m_Device.destroy(copyPool, nullptr);
|
device.m_Device.destroy(copyPool, nullptr);
|
||||||
crate.Destroy(&device);
|
|
||||||
vbo.Destroy(&device);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -582,6 +605,12 @@ CreatePipeline(const Device *device, const Swapchain *swapchain)
|
||||||
.descriptorCount = 1,
|
.descriptorCount = 1,
|
||||||
.stageFlags = vk::ShaderStageFlagBits::eFragment,
|
.stageFlags = vk::ShaderStageFlagBits::eFragment,
|
||||||
},
|
},
|
||||||
|
vk::DescriptorSetLayoutBinding{
|
||||||
|
.binding = 2,
|
||||||
|
.descriptorType = vk::DescriptorType::eStorageBuffer,
|
||||||
|
.descriptorCount = 1,
|
||||||
|
.stageFlags = vk::ShaderStageFlagBits::eVertex,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
vk::DescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo = {
|
vk::DescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo = {
|
||||||
.bindingCount = Cast<u32>(descriptorSetLayoutBinding.size()),
|
.bindingCount = Cast<u32>(descriptorSetLayoutBinding.size()),
|
||||||
|
|
@ -601,15 +630,7 @@ CreatePipeline(const Device *device, const Swapchain *swapchain)
|
||||||
AbortIfFailed(device->m_Device.createPipelineLayout(&pipelineLayoutCreateInfo, nullptr, &pipelineLayout));
|
AbortIfFailed(device->m_Device.createPipelineLayout(&pipelineLayoutCreateInfo, nullptr, &pipelineLayout));
|
||||||
device->SetName(pipelineLayout, "Box Layout");
|
device->SetName(pipelineLayout, "Box Layout");
|
||||||
|
|
||||||
vk::VertexInputBindingDescription inputBindingDescription = Vertex::GetBinding(0);
|
vk::PipelineVertexInputStateCreateInfo vertexInputStateCreateInfo = {};
|
||||||
auto inputAttributeDescription = Vertex::GetAttributes(0);
|
|
||||||
|
|
||||||
vk::PipelineVertexInputStateCreateInfo vertexInputStateCreateInfo = {
|
|
||||||
.vertexBindingDescriptionCount = 1,
|
|
||||||
.pVertexBindingDescriptions = &inputBindingDescription,
|
|
||||||
.vertexAttributeDescriptionCount = Cast<u32>(inputAttributeDescription.size()),
|
|
||||||
.pVertexAttributeDescriptions = inputAttributeDescription.data(),
|
|
||||||
};
|
|
||||||
vk::PipelineInputAssemblyStateCreateInfo inputAssemblyStateCreateInfo = {
|
vk::PipelineInputAssemblyStateCreateInfo inputAssemblyStateCreateInfo = {
|
||||||
.topology = vk::PrimitiveTopology::eTriangleList,
|
.topology = vk::PrimitiveTopology::eTriangleList,
|
||||||
.primitiveRestartEnable = false,
|
.primitiveRestartEnable = false,
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
struct FS_Input {
|
||||||
|
float2 UV0 : TEXCOORD0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FS_Output
|
||||||
|
{
|
||||||
|
float4 ColorTarget : SV_Target0;
|
||||||
|
};
|
||||||
|
|
||||||
|
[[vk::binding(1, 0)]] Texture2D<float4> Texture;
|
||||||
|
[[vk::binding(1, 0)]] SamplerState Sampler;
|
||||||
|
|
||||||
|
FS_Output main(FS_Input StageInput) {
|
||||||
|
FS_Output output;
|
||||||
|
|
||||||
|
output.ColorTarget = float4(Texture.Sample(Sampler, StageInput.UV0).rgb, 1.0);
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
struct VS_Input
|
||||||
|
{
|
||||||
|
uint VertexIndex : SV_VertexID;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VS_Output
|
||||||
|
{
|
||||||
|
float2 UV0 : TEXCOORD0;
|
||||||
|
float4 VertexPosition : SV_Position;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CameraData {
|
||||||
|
float4x4 Model;
|
||||||
|
float4x4 View;
|
||||||
|
float4x4 Projection;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VertexData {
|
||||||
|
float4 Position;
|
||||||
|
float2 UV0;
|
||||||
|
};
|
||||||
|
|
||||||
|
[[vk::binding(0, 0)]] ConstantBuffer<CameraData> Camera;
|
||||||
|
[[vk::binding(2, 0)]] StructuredBuffer<VertexData> Vertices;
|
||||||
|
|
||||||
|
VS_Output main(VS_Input StageInput) {
|
||||||
|
VS_Output output;
|
||||||
|
|
||||||
|
output.UV0 = Vertices[StageInput.VertexIndex].UV0;
|
||||||
|
|
||||||
|
float4 position = Vertices[StageInput.VertexIndex].Position;
|
||||||
|
|
||||||
|
output.VertexPosition = mul(Camera.Projection, mul(Camera.View, mul(Camera.Model, position)));
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
@ -10,7 +10,7 @@ add_executable(model_render "model_render.cpp"
|
||||||
"pipeline_utils.h"
|
"pipeline_utils.h"
|
||||||
"asset_loader.cpp"
|
"asset_loader.cpp"
|
||||||
"asset_loader.h"
|
"asset_loader.h"
|
||||||
"light_manager.cpp "
|
"light_manager.cpp"
|
||||||
"light_manager.h"
|
"light_manager.h"
|
||||||
"gpu_resource_manager.cpp"
|
"gpu_resource_manager.cpp"
|
||||||
"gpu_resource_manager.h"
|
"gpu_resource_manager.h"
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ TextureManager::Init(const u32 maxCapacity)
|
||||||
TextureHandle
|
TextureHandle
|
||||||
TextureManager::Commit(Texture *texture)
|
TextureManager::Commit(Texture *texture)
|
||||||
{
|
{
|
||||||
ERROR_IF(!texture || !texture->IsValid(), "Texture must be valid for commital")
|
ERROR_IF(!texture || !texture->IsValid(), "Texture must be valid for committal")
|
||||||
THEN_ABORT(-1);
|
THEN_ABORT(-1);
|
||||||
|
|
||||||
if (m_FreeHead != GpuResourceHandle::INVALID_HANDLE)
|
if (m_FreeHead != GpuResourceHandle::INVALID_HANDLE)
|
||||||
|
|
|
||||||
|
|
@ -197,8 +197,8 @@ CreateCubeFromHdrEnv(AssetLoader *assetLoader, vk::Queue computeQueue, const u32
|
||||||
vk::PushConstantRange pcr = {
|
vk::PushConstantRange pcr = {
|
||||||
.stageFlags = vk::ShaderStageFlagBits::eCompute,
|
.stageFlags = vk::ShaderStageFlagBits::eCompute,
|
||||||
.offset = 0,
|
.offset = 0,
|
||||||
.size = eastl::max(eastl::max(sizeof(SkyboxPushConstants), sizeof(BrdfLutPushConstants)),
|
.size = Cast<u32>(eastl::max(eastl::max(sizeof(SkyboxPushConstants), sizeof(BrdfLutPushConstants)),
|
||||||
eastl::max(sizeof(DiffuseIrradiancePushConstants), sizeof(PrefilterPushConstants))),
|
eastl::max(sizeof(DiffuseIrradiancePushConstants), sizeof(PrefilterPushConstants)))),
|
||||||
};
|
};
|
||||||
|
|
||||||
vk::PipelineLayout pipelineLayout;
|
vk::PipelineLayout pipelineLayout;
|
||||||
|
|
@ -254,7 +254,7 @@ CreateCubeFromHdrEnv(AssetLoader *assetLoader, vk::Queue computeQueue, const u32
|
||||||
};
|
};
|
||||||
|
|
||||||
eastl::array<vk::Pipeline, computePipelineCreateInfo.size()> pipelines;
|
eastl::array<vk::Pipeline, computePipelineCreateInfo.size()> pipelines;
|
||||||
AbortIfFailed(pDevice->m_Device.createComputePipelines(pDevice->m_PipelineCache, computePipelineCreateInfo.size(),
|
AbortIfFailed(pDevice->m_Device.createComputePipelines(pDevice->m_PipelineCache, Cast<u32>(computePipelineCreateInfo.size()),
|
||||||
computePipelineCreateInfo.data(), nullptr,
|
computePipelineCreateInfo.data(), nullptr,
|
||||||
pipelines.data()));
|
pipelines.data()));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,7 @@ struct LightManager
|
||||||
// Using lower bit. Capacity can be directly a multiple of 2
|
// Using lower bit. Capacity can be directly a multiple of 2
|
||||||
// Thus, range is up to MaxValue<u16>
|
// Thus, range is up to MaxValue<u16>
|
||||||
constexpr static u16 UPDATE_REQUIRED_BIT = 1;
|
constexpr static u16 UPDATE_REQUIRED_BIT = 1;
|
||||||
constexpr static u16 CAPACITY_MASK = ~(UPDATE_REQUIRED_BIT);
|
constexpr static u16 CAPACITY_MASK = Cast<u16>(~UPDATE_REQUIRED_BIT);
|
||||||
|
|
||||||
LightHandle AddDirectional(const vec3 &direction, const vec3 &color, f32 intensity);
|
LightHandle AddDirectional(const vec3 &direction, const vec3 &color, f32 intensity);
|
||||||
LightHandle AddPoint(const vec3 &position, const vec3 &color, f32 radius, f32 intensity);
|
LightHandle AddPoint(const vec3 &position, const vec3 &color, f32 radius, f32 intensity);
|
||||||
|
|
|
||||||
|
|
@ -197,8 +197,8 @@ CreateEnvironment(AssetLoader *assetLoader, vk::Queue computeQueue, const u32 cu
|
||||||
vk::PushConstantRange pcr = {
|
vk::PushConstantRange pcr = {
|
||||||
.stageFlags = vk::ShaderStageFlagBits::eCompute,
|
.stageFlags = vk::ShaderStageFlagBits::eCompute,
|
||||||
.offset = 0,
|
.offset = 0,
|
||||||
.size = eastl::max(eastl::max(sizeof(SkyboxPushConstants), sizeof(BrdfLutPushConstants)),
|
.size = Cast<u32>(eastl::max(eastl::max(sizeof(SkyboxPushConstants), sizeof(BrdfLutPushConstants)),
|
||||||
eastl::max(sizeof(DiffuseIrradiancePushConstants), sizeof(PrefilterPushConstants))),
|
eastl::max(sizeof(DiffuseIrradiancePushConstants), sizeof(PrefilterPushConstants)))),
|
||||||
};
|
};
|
||||||
|
|
||||||
vk::PipelineLayout pipelineLayout;
|
vk::PipelineLayout pipelineLayout;
|
||||||
|
|
@ -254,7 +254,7 @@ CreateEnvironment(AssetLoader *assetLoader, vk::Queue computeQueue, const u32 cu
|
||||||
};
|
};
|
||||||
|
|
||||||
eastl::array<vk::Pipeline, computePipelineCreateInfo.size()> pipelines;
|
eastl::array<vk::Pipeline, computePipelineCreateInfo.size()> pipelines;
|
||||||
AbortIfFailed(pDevice->m_Device.createComputePipelines(pDevice->m_PipelineCache, computePipelineCreateInfo.size(),
|
AbortIfFailed(pDevice->m_Device.createComputePipelines(pDevice->m_PipelineCache, Cast<u32>(computePipelineCreateInfo.size()),
|
||||||
computePipelineCreateInfo.data(), nullptr,
|
computePipelineCreateInfo.data(), nullptr,
|
||||||
pipelines.data()));
|
pipelines.data()));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,7 @@ struct LightManager
|
||||||
// Using lower bit. Capacity can be directly a multiple of 2
|
// Using lower bit. Capacity can be directly a multiple of 2
|
||||||
// Thus, range is up to MaxValue<u16>
|
// Thus, range is up to MaxValue<u16>
|
||||||
constexpr static u16 UPDATE_REQUIRED_BIT = 1;
|
constexpr static u16 UPDATE_REQUIRED_BIT = 1;
|
||||||
constexpr static u16 CAPACITY_MASK = ~(UPDATE_REQUIRED_BIT);
|
constexpr static u16 CAPACITY_MASK = Cast<u16>(~UPDATE_REQUIRED_BIT);
|
||||||
|
|
||||||
LightHandle AddDirectional(const vec3 &direction, const vec3 &color, f32 intensity);
|
LightHandle AddDirectional(const vec3 &direction, const vec3 &color, f32 intensity);
|
||||||
LightHandle AddPoint(const vec3 &position, const vec3 &color, f32 radius, f32 intensity);
|
LightHandle AddPoint(const vec3 &position, const vec3 &color, f32 radius, f32 intensity);
|
||||||
|
|
|
||||||
|
|
@ -5,11 +5,11 @@
|
||||||
|
|
||||||
#include "aster/core/context.h"
|
#include "aster/core/context.h"
|
||||||
#include "aster/core/device.h"
|
#include "aster/core/device.h"
|
||||||
|
#include "aster/core/image.h"
|
||||||
#include "aster/core/physical_device.h"
|
#include "aster/core/physical_device.h"
|
||||||
|
#include "aster/core/pipeline.h"
|
||||||
#include "aster/core/swapchain.h"
|
#include "aster/core/swapchain.h"
|
||||||
#include "aster/core/window.h"
|
#include "aster/core/window.h"
|
||||||
#include "aster/core/image.h"
|
|
||||||
#include "aster/core/pipeline.h"
|
|
||||||
|
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
#include "render_resource_manager.h"
|
#include "render_resource_manager.h"
|
||||||
|
|
@ -93,7 +93,7 @@ main(int, char *[])
|
||||||
Device device = {&context, &deviceToUse, &enabledDeviceFeatures,
|
Device device = {&context, &deviceToUse, &enabledDeviceFeatures,
|
||||||
{queueAllocation}, pipelineCacheData, "Primary Device"};
|
{queueAllocation}, pipelineCacheData, "Primary Device"};
|
||||||
vk::Queue graphicsQueue = device.GetQueue(queueAllocation.m_Family, 0);
|
vk::Queue graphicsQueue = device.GetQueue(queueAllocation.m_Family, 0);
|
||||||
Swapchain swapchain = {&surface, &device, window.GetSize(),"Primary Chain"};
|
Swapchain swapchain = {&surface, &device, window.GetSize(), "Primary Chain"};
|
||||||
|
|
||||||
RenderResourceManager resourceManager = {&device, 1024};
|
RenderResourceManager resourceManager = {&device, 1024};
|
||||||
EcsRegistry registry;
|
EcsRegistry registry;
|
||||||
|
|
@ -114,7 +114,7 @@ main(int, char *[])
|
||||||
|
|
||||||
eastl::vector<Model> models;
|
eastl::vector<Model> models;
|
||||||
models.emplace_back(assetLoader.LoadModelToGpu(MODEL_FILE, "Main Model"));
|
models.emplace_back(assetLoader.LoadModelToGpu(MODEL_FILE, "Main Model"));
|
||||||
//registry.get<CDynamicTransform>(model.m_RootEntity).m_Position = vec3(2 * i, 0, 2 * j);
|
// registry.get<CDynamicTransform>(model.m_RootEntity).m_Position = vec3(2 * i, 0, 2 * j);
|
||||||
|
|
||||||
UniformBuffer ubo;
|
UniformBuffer ubo;
|
||||||
constexpr usize uboLightManagerOffset = sizeof cameraController.m_Camera;
|
constexpr usize uboLightManagerOffset = sizeof cameraController.m_Camera;
|
||||||
|
|
@ -350,12 +350,13 @@ main(int, char *[])
|
||||||
{
|
{
|
||||||
Time::Update();
|
Time::Update();
|
||||||
|
|
||||||
//u32 index = 0;
|
// u32 index = 0;
|
||||||
//for (auto [entity, dynTrans] : rootModel.each())
|
// for (auto [entity, dynTrans] : rootModel.each())
|
||||||
//{
|
//{
|
||||||
// dynTrans.m_Rotation =
|
// dynTrans.m_Rotation =
|
||||||
// glm::rotate(dynTrans.m_Rotation, Cast<f32>(30_deg * (++index) * Time::m_Delta), vec3{0.0f, 1.0f, 0.0f});
|
// glm::rotate(dynTrans.m_Rotation, Cast<f32>(30_deg * (++index) * Time::m_Delta), vec3{0.0f, 1.0f,
|
||||||
//}
|
// 0.0f});
|
||||||
|
// }
|
||||||
|
|
||||||
Frame *currentFrame = frameManager.GetNextFrame(&swapchain, &surface, window.GetSize());
|
Frame *currentFrame = frameManager.GetNextFrame(&swapchain, &surface, window.GetSize());
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -315,7 +315,7 @@ VirtualizedBufferPool::InitIndex(const Device *device, usize bufferMaxSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
VirtualizedBufferPool::UpdateToGpu(const Device *device)
|
VirtualizedBufferPool::UpdateToGpu(const Device *)
|
||||||
{
|
{
|
||||||
// Unrequired until adding the non-ReBAR support.
|
// Unrequired until adding the non-ReBAR support.
|
||||||
}
|
}
|
||||||
|
|
|
||||||
2
vcpkg
2
vcpkg
|
|
@ -1 +1 @@
|
||||||
Subproject commit b27651341123a59f7187b42ef2bc476284afb310
|
Subproject commit 0ca64b4e1c70fa6d9f53b369b8f3f0843797c20c
|
||||||
Loading…
Reference in New Issue