Model Render updated.
This commit is contained in:
parent
befa36c7f1
commit
4f71df797c
|
|
@ -12,6 +12,7 @@ function(add_shader TARGET SHADER)
|
||||||
|
|
||||||
set(current-shader-path ${CMAKE_CURRENT_SOURCE_DIR}/${SHADER})
|
set(current-shader-path ${CMAKE_CURRENT_SOURCE_DIR}/${SHADER})
|
||||||
set(current-output-path ${CMAKE_CURRENT_BINARY_DIR}/${SHADER}.spv)
|
set(current-output-path ${CMAKE_CURRENT_BINARY_DIR}/${SHADER}.spv)
|
||||||
|
set(current-copy-path ${CMAKE_CURRENT_BINARY_DIR}/${SHADER})
|
||||||
|
|
||||||
get_filename_component(current-output-dir ${current-output-path} DIRECTORY)
|
get_filename_component(current-output-dir ${current-output-path} DIRECTORY)
|
||||||
file(MAKE_DIRECTORY ${current-output-dir})
|
file(MAKE_DIRECTORY ${current-output-dir})
|
||||||
|
|
@ -39,12 +40,19 @@ function(add_shader TARGET SHADER)
|
||||||
VERBATIM)
|
VERBATIM)
|
||||||
elseif (${shader-ext} STREQUAL ".slang")
|
elseif (${shader-ext} STREQUAL ".slang")
|
||||||
message("Marked as slang file. ${current-output-path}")
|
message("Marked as slang file. ${current-output-path}")
|
||||||
|
# add_custom_command(
|
||||||
|
# OUTPUT ${current-output-path}
|
||||||
|
# COMMAND ${slangc_exe} -target spirv -o ${current-output-path} ${current-shader-path}
|
||||||
|
# DEPENDS ${current-shader-path}
|
||||||
|
# IMPLICIT_DEPENDS CXX ${current-shader-path}
|
||||||
|
# VERBATIM)
|
||||||
add_custom_command(
|
add_custom_command(
|
||||||
OUTPUT ${current-output-path}
|
TARGET ${TARGET} POST_BUILD
|
||||||
COMMAND ${slangc_exe} -target spirv -o ${current-output-path} ${current-shader-path}
|
# OUTPUT ${current-copy-path}
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy ${current-shader-path} ${CMAKE_CURRENT_BINARY_DIR}/${SHADER}
|
||||||
DEPENDS ${current-shader-path}
|
DEPENDS ${current-shader-path}
|
||||||
IMPLICIT_DEPENDS CXX ${current-shader-path}
|
IMPLICIT_DEPENDS CXX ${current-shader-path}
|
||||||
VERBATIM)
|
COMMENT "Copying ${SHADER}")
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
# Make sure our build depends on this output.
|
# Make sure our build depends on this output.
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ using f128 = long double;
|
||||||
using b8 = bool;
|
using b8 = bool;
|
||||||
using b32 = u32;
|
using b32 = u32;
|
||||||
using usize = size_t;
|
using usize = size_t;
|
||||||
|
using isize = intptr_t;
|
||||||
using uptr = uintptr_t;
|
using uptr = uintptr_t;
|
||||||
using cstr = const char *;
|
using cstr = const char *;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -81,6 +81,7 @@ struct PhysicalDevice final
|
||||||
eastl::vector<vk::PresentModeKHR> m_PresentModes;
|
eastl::vector<vk::PresentModeKHR> m_PresentModes;
|
||||||
eastl::vector<QueueFamilyInfo> m_QueueFamilies;
|
eastl::vector<QueueFamilyInfo> m_QueueFamilies;
|
||||||
|
|
||||||
|
PhysicalDevice() = default;
|
||||||
PhysicalDevice(vk::SurfaceKHR surface, vk::PhysicalDevice physicalDevice);
|
PhysicalDevice(vk::SurfaceKHR surface, vk::PhysicalDevice physicalDevice);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,23 +13,31 @@ struct Device;
|
||||||
|
|
||||||
struct Pipeline
|
struct Pipeline
|
||||||
{
|
{
|
||||||
const Device *m_Device;
|
enum class Kind
|
||||||
|
{
|
||||||
|
eGraphics,
|
||||||
|
eCompute,
|
||||||
|
};
|
||||||
|
|
||||||
|
const Device *m_Device = nullptr;
|
||||||
vk::PipelineLayout m_Layout;
|
vk::PipelineLayout m_Layout;
|
||||||
vk::Pipeline m_Pipeline;
|
vk::Pipeline m_Pipeline = nullptr;
|
||||||
eastl::vector<vk::DescriptorSetLayout> m_SetLayouts;
|
eastl::vector<vk::DescriptorSetLayout> m_SetLayouts;
|
||||||
|
Kind m_Kind;
|
||||||
|
|
||||||
Pipeline() = default;
|
Pipeline() = default;
|
||||||
Pipeline(const Device *device, vk::PipelineLayout layout, vk::Pipeline pipeline,
|
Pipeline(const Device *device, vk::PipelineLayout layout, vk::Pipeline pipeline,
|
||||||
eastl::vector<vk::DescriptorSetLayout> &&setLayouts);
|
eastl::vector<vk::DescriptorSetLayout> &&setLayouts, Kind kind);
|
||||||
~Pipeline();
|
~Pipeline();
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(Pipeline);
|
DISALLOW_COPY_AND_ASSIGN(Pipeline);
|
||||||
|
|
||||||
Pipeline(Pipeline &&other) noexcept
|
Pipeline(Pipeline &&other) noexcept
|
||||||
: m_Device{other.m_Device},
|
: m_Device{other.m_Device}
|
||||||
m_Layout{Take(other.m_Layout)},
|
, m_Layout{Take(other.m_Layout)}
|
||||||
m_Pipeline{Take(other.m_Pipeline)},
|
, m_Pipeline{Take(other.m_Pipeline)}
|
||||||
m_SetLayouts{std::move(other.m_SetLayouts)}
|
, m_SetLayouts{std::move(other.m_SetLayouts)}
|
||||||
|
, m_Kind{other.m_Kind}
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -38,10 +46,12 @@ struct Pipeline
|
||||||
{
|
{
|
||||||
if (this == &other)
|
if (this == &other)
|
||||||
return *this;
|
return *this;
|
||||||
m_Device = other.m_Device;
|
using eastl::swap;
|
||||||
m_Layout = Take(other.m_Layout);
|
swap(m_Device, other.m_Device);
|
||||||
m_Pipeline = Take(other.m_Pipeline);
|
swap(m_Layout, other.m_Layout);
|
||||||
m_SetLayouts = std::move(other.m_SetLayouts);
|
swap(m_Pipeline, other.m_Pipeline);
|
||||||
|
swap(m_SetLayouts, other.m_SetLayouts);
|
||||||
|
swap(m_Kind, other.m_Kind);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "EASTL/span.h"
|
||||||
#include "context.h"
|
#include "context.h"
|
||||||
|
|
||||||
#include <aster/aster.h>
|
#include <aster/aster.h>
|
||||||
|
|
@ -30,10 +31,10 @@ struct Frame;
|
||||||
|
|
||||||
namespace _internal
|
namespace _internal
|
||||||
{
|
{
|
||||||
|
class ComputeContextPool;
|
||||||
class GraphicsContextPool;
|
class GraphicsContextPool;
|
||||||
class TransferContextPool;
|
class TransferContextPool;
|
||||||
class ContextPool;
|
class ContextPool;
|
||||||
class OrderlessTransferContextPool;
|
|
||||||
} // namespace _internal
|
} // namespace _internal
|
||||||
|
|
||||||
#define DEPRECATE_RAW_CALLS
|
#define DEPRECATE_RAW_CALLS
|
||||||
|
|
@ -46,7 +47,6 @@ class Context
|
||||||
|
|
||||||
friend Device;
|
friend Device;
|
||||||
friend _internal::ContextPool;
|
friend _internal::ContextPool;
|
||||||
friend _internal::OrderlessTransferContextPool;
|
|
||||||
|
|
||||||
explicit Context(_internal::ContextPool &pool, const vk::CommandBuffer cmd)
|
explicit Context(_internal::ContextPool &pool, const vk::CommandBuffer cmd)
|
||||||
: m_Pool{&pool}
|
: m_Pool{&pool}
|
||||||
|
|
@ -66,8 +66,24 @@ class Context
|
||||||
|
|
||||||
void Begin();
|
void Begin();
|
||||||
void End();
|
void End();
|
||||||
|
|
||||||
|
void BeginDebugRegion(cstr name, vec4 color = {});
|
||||||
|
void EndDebugRegion();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Inline the no-op if not debug.
|
||||||
|
#if defined(ASTER_NDEBUG)
|
||||||
|
inline void
|
||||||
|
Context::BeginDebugRegion(cstr name, vec4 color)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void
|
||||||
|
Context::EndDebugRegion()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
class TransferContext : public Context
|
class TransferContext : public Context
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
|
|
@ -79,14 +95,19 @@ class TransferContext : public Context
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
void UploadBuffer(const Ref<Buffer> &buffer, usize size, const void *data);
|
||||||
struct ImageData
|
|
||||||
{
|
|
||||||
void *m_Data;
|
|
||||||
usize m_NumBytes;
|
|
||||||
};
|
|
||||||
|
|
||||||
void UploadTexture(const Ref<Image> &image, const ImageData &data);
|
public:
|
||||||
|
void UploadTexture(const Ref<Image> &image, const eastl::span<u8> &data);
|
||||||
|
|
||||||
|
void
|
||||||
|
UploadBuffer(const Ref<Buffer> &buffer, const std::ranges::range auto &data)
|
||||||
|
{
|
||||||
|
const auto span = eastl::span{data.begin(), data.end()};
|
||||||
|
UploadBuffer(buffer, span.size_bytes(), span.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
DEPRECATE_RAW_CALLS void Blit(const vk::BlitImageInfo2 &mipBlitInfo);
|
||||||
|
|
||||||
TransferContext(TransferContext &&other) noexcept;
|
TransferContext(TransferContext &&other) noexcept;
|
||||||
TransferContext &operator=(TransferContext &&other) noexcept;
|
TransferContext &operator=(TransferContext &&other) noexcept;
|
||||||
|
|
@ -96,38 +117,79 @@ class TransferContext : public Context
|
||||||
DISALLOW_COPY_AND_ASSIGN(TransferContext);
|
DISALLOW_COPY_AND_ASSIGN(TransferContext);
|
||||||
};
|
};
|
||||||
|
|
||||||
class GraphicsContext : public Context
|
class ComputeContext : public TransferContext
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
friend Device;
|
||||||
|
friend _internal::ComputeContextPool;
|
||||||
|
|
||||||
|
const Pipeline *m_PipelineInUse;
|
||||||
|
|
||||||
|
explicit ComputeContext(_internal::ContextPool &pool, const vk::CommandBuffer cmd)
|
||||||
|
: TransferContext{pool, cmd}
|
||||||
|
, m_PipelineInUse{nullptr}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void PushConstantBlock(usize offset, usize size, const void *data);
|
||||||
|
|
||||||
|
void Dispatch(const Pipeline &pipeline, u32 x, u32 y, u32 z, usize size, void *data);
|
||||||
|
|
||||||
|
public:
|
||||||
|
void BindPipeline(const Pipeline &pipeline);
|
||||||
|
void
|
||||||
|
PushConstantBlock(const auto &block)
|
||||||
|
{
|
||||||
|
if constexpr (sizeof block > 128)
|
||||||
|
WARN("Vulkan only guarantees 128 bytes of Push Constants. Size of PCB is {}", sizeof block);
|
||||||
|
PushConstantBlock(0, sizeof block, &block);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PushConstantBlock(const usize offset, const auto &block)
|
||||||
|
{
|
||||||
|
if (offset + sizeof block > 128)
|
||||||
|
WARN("Vulkan only guarantees 128 bytes of Push Constants. Size of PCB is {}, at offset {}", sizeof block,
|
||||||
|
offset);
|
||||||
|
PushConstantBlock(offset, sizeof block, &block);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Dispatch(const Pipeline &pipeline, const u32 x, const u32 y, const u32 z, auto &pushConstantBlock)
|
||||||
|
{
|
||||||
|
if constexpr (sizeof pushConstantBlock > 128)
|
||||||
|
WARN("Vulkan only guarantees 128 bytes of Push Constants. Size of PCB is {}", sizeof pushConstantBlock);
|
||||||
|
Dispatch(pipeline, x, y, z, sizeof pushConstantBlock, &pushConstantBlock);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class GraphicsContext : public ComputeContext
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
friend Device;
|
friend Device;
|
||||||
friend _internal::GraphicsContextPool;
|
friend _internal::GraphicsContextPool;
|
||||||
|
|
||||||
const Pipeline *m_PipelineInUse;
|
|
||||||
|
|
||||||
explicit GraphicsContext(_internal::ContextPool &pool, const vk::CommandBuffer cmd)
|
explicit GraphicsContext(_internal::ContextPool &pool, const vk::CommandBuffer cmd)
|
||||||
: Context{pool, cmd}
|
: ComputeContext{pool, cmd}
|
||||||
, m_PipelineInUse{nullptr}
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DEPRECATE_RAW_CALLS void SetViewport(const vk::Viewport &viewport);
|
DEPRECATE_RAW_CALLS void SetViewport(const vk::Viewport &viewport);
|
||||||
void BindVertexBuffer(const Ref<VertexBuffer> &vertexBuffer);
|
void BindVertexBuffer(const Ref<VertexBuffer> &vertexBuffer);
|
||||||
void BindPipeline(const Pipeline &pipeline);
|
void BindIndexBuffer(const Ref<IndexBuffer> &indexBuffer);
|
||||||
void
|
|
||||||
PushConstantBlock(auto &block)
|
|
||||||
{
|
|
||||||
if constexpr (sizeof(block) > 128)
|
|
||||||
{
|
|
||||||
WARN("Vulkan only guarantees 128 bytes of Push Constants. Size of PCB is {}", sizeof block);
|
|
||||||
}
|
|
||||||
m_Cmd.pushConstants(m_PipelineInUse->m_Layout, vk::ShaderStageFlagBits::eAll, 0, sizeof block, &block);
|
|
||||||
}
|
|
||||||
void Draw(usize vertexCount);
|
void Draw(usize vertexCount);
|
||||||
void DrawIndexed(usize indexCount);
|
void DrawIndexed(usize indexCount);
|
||||||
|
void DrawIndexed(usize indexCount, usize firstIndex, usize firstVertex);
|
||||||
|
|
||||||
DEPRECATE_RAW_CALLS void BeginRendering(const vk::RenderingInfo &renderingInfo);
|
DEPRECATE_RAW_CALLS void BeginRendering(const vk::RenderingInfo &renderingInfo);
|
||||||
void EndRendering();
|
void EndRendering();
|
||||||
|
|
||||||
|
DEPRECATE_RAW_CALLS vk::CommandBuffer
|
||||||
|
GetCommandBuffer() const
|
||||||
|
{
|
||||||
|
return m_Cmd;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace _internal
|
namespace _internal
|
||||||
|
|
@ -215,14 +277,33 @@ class TransferContextPool : public ContextPool
|
||||||
DISALLOW_COPY_AND_ASSIGN(TransferContextPool);
|
DISALLOW_COPY_AND_ASSIGN(TransferContextPool);
|
||||||
};
|
};
|
||||||
|
|
||||||
class GraphicsContextPool : public TransferContextPool
|
class ComputeContextPool : public TransferContextPool
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ComputeContext CreateComputeContext();
|
||||||
|
|
||||||
|
ComputeContextPool() = default;
|
||||||
|
ComputeContextPool(Device &device, const u32 queueFamilyIndex, const ManagedBy managedBy)
|
||||||
|
: TransferContextPool{device, queueFamilyIndex, managedBy}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ComputeContextPool(ComputeContextPool &&other) noexcept = default;
|
||||||
|
ComputeContextPool &operator=(ComputeContextPool &&other) noexcept = default;
|
||||||
|
|
||||||
|
~ComputeContextPool() = default;
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(ComputeContextPool);
|
||||||
|
};
|
||||||
|
|
||||||
|
class GraphicsContextPool : public ComputeContextPool
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
GraphicsContext CreateGraphicsContext();
|
GraphicsContext CreateGraphicsContext();
|
||||||
|
|
||||||
GraphicsContextPool() = default;
|
GraphicsContextPool() = default;
|
||||||
GraphicsContextPool(Device &device, const u32 queueFamilyIndex, const ManagedBy managedBy)
|
GraphicsContextPool(Device &device, const u32 queueFamilyIndex, const ManagedBy managedBy)
|
||||||
: TransferContextPool{device, queueFamilyIndex, managedBy}
|
: ComputeContextPool{device, queueFamilyIndex, managedBy}
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -234,35 +315,38 @@ class GraphicsContextPool : public TransferContextPool
|
||||||
DISALLOW_COPY_AND_ASSIGN(GraphicsContextPool);
|
DISALLOW_COPY_AND_ASSIGN(GraphicsContextPool);
|
||||||
};
|
};
|
||||||
|
|
||||||
class OrderlessTransferContextPool
|
template <std::derived_from<ContextPool> TContextPool>
|
||||||
|
class OrderlessContextPool
|
||||||
{
|
{
|
||||||
struct TransferContextEntry : eastl::intrusive_list_node
|
using ContextPoolType = TContextPool;
|
||||||
|
|
||||||
|
struct ContextListEntry : eastl::intrusive_list_node
|
||||||
{
|
{
|
||||||
TransferContextPool m_Pool;
|
ContextPoolType m_Pool;
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Contains(const _internal::ContextPool &other) const
|
Contains(const ContextPool &other) const
|
||||||
{
|
{
|
||||||
return m_Pool == other;
|
return m_Pool == other;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
using TransferContextList = eastl::intrusive_list<TransferContextEntry>;
|
using ContextListType = eastl::intrusive_list<ContextListEntry>;
|
||||||
|
|
||||||
Device *m_Device;
|
Device *m_Device;
|
||||||
memory::memory_pool<> m_TransferContextMemoryPool;
|
memory::memory_pool<> m_ContextPoolEntryMemory;
|
||||||
TransferContextList m_FreeTransferContexts;
|
ContextListType m_FreeContextPools;
|
||||||
TransferContextList m_TransferContexts;
|
ContextListType m_UsedContextPools;
|
||||||
u32 m_QueueFamilyIndex;
|
u32 m_QueueFamilyIndex;
|
||||||
|
|
||||||
constexpr static usize ENTRY_SIZE = sizeof(TransferContextEntry);
|
constexpr static usize ENTRY_SIZE = sizeof(ContextListEntry);
|
||||||
constexpr static usize ENTRIES_PER_BLOCK = 5;
|
constexpr static usize ENTRIES_PER_BLOCK = 5;
|
||||||
constexpr static usize BLOCK_SIZE = ENTRIES_PER_BLOCK * ENTRY_SIZE;
|
constexpr static usize BLOCK_SIZE = ENTRIES_PER_BLOCK * ENTRY_SIZE;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
OrderlessTransferContextPool()
|
OrderlessContextPool()
|
||||||
: m_Device{nullptr}
|
: m_Device{nullptr}
|
||||||
, m_TransferContextMemoryPool{ENTRY_SIZE, BLOCK_SIZE}
|
, m_ContextPoolEntryMemory{ENTRY_SIZE, BLOCK_SIZE}
|
||||||
, m_QueueFamilyIndex{0}
|
, m_QueueFamilyIndex{0}
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
@ -276,81 +360,109 @@ class OrderlessTransferContextPool
|
||||||
|
|
||||||
TransferContext
|
TransferContext
|
||||||
CreateTransferContext()
|
CreateTransferContext()
|
||||||
|
requires std::derived_from<TContextPool, TransferContextPool>
|
||||||
{
|
{
|
||||||
if (!m_FreeTransferContexts.empty())
|
if (!m_FreeContextPools.empty())
|
||||||
{
|
{
|
||||||
TransferContextEntry &entry = m_FreeTransferContexts.back();
|
ContextListEntry &entry = m_FreeContextPools.back();
|
||||||
m_FreeTransferContexts.pop_back();
|
m_FreeContextPools.pop_back();
|
||||||
m_TransferContexts.push_back(entry);
|
m_UsedContextPools.push_back(entry);
|
||||||
|
|
||||||
return entry.m_Pool.CreateTransferContext();
|
return entry.m_Pool.CreateTransferContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
TransferContextEntry &entry = *static_cast<TransferContextEntry *>(m_TransferContextMemoryPool.allocate_node());
|
ContextListEntry &entry = *static_cast<ContextListEntry *>(m_ContextPoolEntryMemory.allocate_node());
|
||||||
auto pool = TransferContextPool{*m_Device, m_QueueFamilyIndex, ContextPool::ManagedBy::eDevice};
|
auto pool = ContextPoolType{*m_Device, m_QueueFamilyIndex, ContextPool::ManagedBy::eDevice};
|
||||||
pool.m_ResetCallback = [this](ContextPool &resetPool) { this->ReleasePool(resetPool); };
|
pool.m_ResetCallback = [this](ContextPool &resetPool) { this->ReleasePool(resetPool); };
|
||||||
new (&entry) TransferContextEntry{
|
new (&entry) ContextListEntry{
|
||||||
.m_Pool = eastl::move(pool),
|
.m_Pool = eastl::move(pool),
|
||||||
};
|
};
|
||||||
m_TransferContexts.push_back(entry);
|
m_UsedContextPools.push_back(entry);
|
||||||
|
|
||||||
return entry.m_Pool.CreateTransferContext();
|
return entry.m_Pool.CreateTransferContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ComputeContext
|
||||||
|
CreateComputeContext()
|
||||||
|
requires std::derived_from<TContextPool, ComputeContextPool>
|
||||||
|
{
|
||||||
|
if (!m_FreeContextPools.empty())
|
||||||
|
{
|
||||||
|
ContextListEntry &entry = m_FreeContextPools.back();
|
||||||
|
m_FreeContextPools.pop_back();
|
||||||
|
m_UsedContextPools.push_back(entry);
|
||||||
|
|
||||||
|
return entry.m_Pool.CreateComputeContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
ContextListEntry &entry = *static_cast<ContextListEntry *>(m_ContextPoolEntryMemory.allocate_node());
|
||||||
|
auto pool = ContextPoolType{*m_Device, m_QueueFamilyIndex, ContextPool::ManagedBy::eDevice};
|
||||||
|
pool.m_ResetCallback = [this](ContextPool &resetPool) { this->ReleasePool(resetPool); };
|
||||||
|
new (&entry) ContextListEntry{
|
||||||
|
.m_Pool = eastl::move(pool),
|
||||||
|
};
|
||||||
|
m_UsedContextPools.push_back(entry);
|
||||||
|
|
||||||
|
return entry.m_Pool.CreateComputeContext();
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ReleasePool(ContextPool &pool)
|
ReleasePool(ContextPool &pool)
|
||||||
{
|
{
|
||||||
auto const found = eastl::find_if(m_TransferContexts.begin(), m_TransferContexts.end(),
|
auto const found = eastl::find_if(m_UsedContextPools.begin(), m_UsedContextPools.end(),
|
||||||
[&pool](const TransferContextEntry &v) { return v.Contains(pool); });
|
[&pool](const ContextListEntry &v) { return v.Contains(pool); });
|
||||||
auto &v = *found;
|
auto &v = *found;
|
||||||
TransferContextList::remove(v);
|
ContextListType::remove(v);
|
||||||
|
|
||||||
pool.Reset();
|
pool.Reset();
|
||||||
|
|
||||||
m_FreeTransferContexts.push_back(v);
|
m_FreeContextPools.push_back(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
OrderlessTransferContextPool(OrderlessTransferContextPool &&other) noexcept
|
OrderlessContextPool(OrderlessContextPool &&other) noexcept
|
||||||
: m_Device{other.m_Device}
|
: m_Device{other.m_Device}
|
||||||
, m_TransferContextMemoryPool{std::move(other.m_TransferContextMemoryPool)}
|
, m_ContextPoolEntryMemory{std::move(other.m_ContextPoolEntryMemory)}
|
||||||
, m_FreeTransferContexts{other.m_FreeTransferContexts}
|
, m_FreeContextPools{other.m_FreeContextPools}
|
||||||
, m_TransferContexts{other.m_TransferContexts}
|
, m_UsedContextPools{other.m_UsedContextPools}
|
||||||
, m_QueueFamilyIndex{other.m_QueueFamilyIndex}
|
, m_QueueFamilyIndex{other.m_QueueFamilyIndex}
|
||||||
{
|
{
|
||||||
other.m_FreeTransferContexts.clear();
|
other.m_FreeContextPools.clear();
|
||||||
other.m_TransferContexts.clear();
|
other.m_UsedContextPools.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
OrderlessTransferContextPool &
|
OrderlessContextPool &
|
||||||
operator=(OrderlessTransferContextPool &&other) noexcept
|
operator=(OrderlessContextPool &&other) noexcept
|
||||||
{
|
{
|
||||||
if (this == &other)
|
if (this == &other)
|
||||||
return *this;
|
return *this;
|
||||||
m_Device = other.m_Device;
|
m_Device = other.m_Device;
|
||||||
m_TransferContextMemoryPool = std::move(other.m_TransferContextMemoryPool);
|
m_ContextPoolEntryMemory = std::move(other.m_ContextPoolEntryMemory);
|
||||||
m_FreeTransferContexts = other.m_FreeTransferContexts;
|
m_FreeContextPools = other.m_FreeContextPools;
|
||||||
other.m_FreeTransferContexts.clear();
|
other.m_FreeContextPools.clear();
|
||||||
m_TransferContexts = other.m_TransferContexts;
|
m_UsedContextPools = other.m_UsedContextPools;
|
||||||
other.m_TransferContexts.clear();
|
other.m_UsedContextPools.clear();
|
||||||
m_QueueFamilyIndex = other.m_QueueFamilyIndex;
|
m_QueueFamilyIndex = other.m_QueueFamilyIndex;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
~OrderlessTransferContextPool()
|
~OrderlessContextPool()
|
||||||
{
|
{
|
||||||
for (auto &entry : m_FreeTransferContexts)
|
for (auto &entry : m_FreeContextPools)
|
||||||
{
|
{
|
||||||
entry.m_Pool.~TransferContextPool();
|
entry.m_Pool.~ContextPoolType();
|
||||||
}
|
}
|
||||||
for (auto &entry : m_TransferContexts)
|
for (auto &entry : m_UsedContextPools)
|
||||||
{
|
{
|
||||||
entry.m_Pool.~TransferContextPool();
|
entry.m_Pool.~ContextPoolType();
|
||||||
}
|
}
|
||||||
// The allocations will 'wink' away.
|
// The allocations will 'wink' away.
|
||||||
}
|
}
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(OrderlessTransferContextPool);
|
DISALLOW_COPY_AND_ASSIGN(OrderlessContextPool);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using OrderlessTransferContextPool = OrderlessContextPool<TransferContextPool>;
|
||||||
|
using OrderlessComputeContextPool = OrderlessContextPool<ComputeContextPool>;
|
||||||
|
|
||||||
} // namespace _internal
|
} // namespace _internal
|
||||||
} // namespace systems
|
} // namespace systems
|
||||||
|
|
@ -294,8 +294,42 @@ struct ShaderInfo
|
||||||
|
|
||||||
struct GraphicsPipelineCreateInfo
|
struct GraphicsPipelineCreateInfo
|
||||||
{
|
{
|
||||||
|
enum class DepthTest
|
||||||
|
{
|
||||||
|
eEnabled,
|
||||||
|
eReadOnly,
|
||||||
|
eDisabled,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class CompareOp
|
||||||
|
{
|
||||||
|
eNever = 0x0,
|
||||||
|
eLessThan = 0x1,
|
||||||
|
eEqualTo = 0x2,
|
||||||
|
eGreaterThan = 0x4,
|
||||||
|
eLessThanOrEqualTo = eLessThan | eEqualTo,
|
||||||
|
eGreaterThanOrEqualTo = eGreaterThan | eEqualTo,
|
||||||
|
eNotEqualTo = eLessThan | eGreaterThan,
|
||||||
|
eAlways = eLessThan | eEqualTo | eGreaterThan,
|
||||||
|
};
|
||||||
|
|
||||||
eastl::fixed_vector<VertexInput, 4, false> m_VertexInputs;
|
eastl::fixed_vector<VertexInput, 4, false> m_VertexInputs;
|
||||||
eastl::fixed_vector<ShaderInfo, 4, false> m_Shaders;
|
eastl::fixed_vector<ShaderInfo, 4, false> m_Shaders;
|
||||||
|
|
||||||
|
DepthTest m_DepthTest = DepthTest::eEnabled;
|
||||||
|
CompareOp m_DepthOp = CompareOp::eLessThan;
|
||||||
|
|
||||||
|
cstr m_Name;
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend Device;
|
||||||
|
[[nodiscard]] vk::PipelineDepthStencilStateCreateInfo GetDepthStencilStateCreateInfo() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ComputePipelineCreateInfo
|
||||||
|
{
|
||||||
|
ShaderInfo m_Shader;
|
||||||
|
cstr m_Name;
|
||||||
};
|
};
|
||||||
|
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
|
|
@ -402,6 +436,7 @@ class Device final
|
||||||
u32 m_ComputeQueueFamily;
|
u32 m_ComputeQueueFamily;
|
||||||
|
|
||||||
_internal::OrderlessTransferContextPool m_TransferContextPool;
|
_internal::OrderlessTransferContextPool m_TransferContextPool;
|
||||||
|
_internal::OrderlessComputeContextPool m_ComputeContextPool;
|
||||||
|
|
||||||
std::array<Frame, MAX_FRAMES_IN_FLIGHT> m_Frames;
|
std::array<Frame, MAX_FRAMES_IN_FLIGHT> m_Frames;
|
||||||
u32 m_CurrentFrameIdx = 0;
|
u32 m_CurrentFrameIdx = 0;
|
||||||
|
|
@ -416,6 +451,7 @@ class Device final
|
||||||
// ----------------------------------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
[[nodiscard]] Ref<StorageBuffer> CreateStorageBuffer(usize size, cstr name = nullptr);
|
[[nodiscard]] Ref<StorageBuffer> CreateStorageBuffer(usize size, cstr name = nullptr);
|
||||||
|
[[nodiscard]] Ref<IndexBuffer> CreateIndexBuffer(usize size, cstr name = nullptr);
|
||||||
[[nodiscard]] Ref<UniformBuffer> CreateUniformBuffer(usize size, cstr name = nullptr);
|
[[nodiscard]] Ref<UniformBuffer> CreateUniformBuffer(usize size, cstr name = nullptr);
|
||||||
[[nodiscard]] Ref<StagingBuffer> CreateStagingBuffer(usize size, cstr name = nullptr);
|
[[nodiscard]] Ref<StagingBuffer> CreateStagingBuffer(usize size, cstr name = nullptr);
|
||||||
[[nodiscard]] Ref<VertexBuffer> CreateVertexBuffer(usize size, cstr name = nullptr);
|
[[nodiscard]] Ref<VertexBuffer> CreateVertexBuffer(usize size, cstr name = nullptr);
|
||||||
|
|
@ -464,7 +500,7 @@ class Device final
|
||||||
[[nodiscard]] Ref<T>
|
[[nodiscard]] Ref<T>
|
||||||
CreateTexture2DWithView(const Texture2DCreateInfo &createInfo)
|
CreateTexture2DWithView(const Texture2DCreateInfo &createInfo)
|
||||||
{
|
{
|
||||||
auto handle = CreateTexture2D(createInfo);
|
auto handle = CreateTexture2DWithView(createInfo);
|
||||||
return CastView<T>(handle);
|
return CastView<T>(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -472,7 +508,7 @@ class Device final
|
||||||
[[nodiscard]] Ref<T>
|
[[nodiscard]] Ref<T>
|
||||||
CreateTextureCubeWithView(const TextureCubeCreateInfo &createInfo)
|
CreateTextureCubeWithView(const TextureCubeCreateInfo &createInfo)
|
||||||
{
|
{
|
||||||
auto handle = CreateTextureCube(createInfo);
|
auto handle = CreateTextureCubeWithView(createInfo);
|
||||||
return CastView<T>(handle);
|
return CastView<T>(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -503,12 +539,16 @@ class Device final
|
||||||
PipelineCreationError
|
PipelineCreationError
|
||||||
CreateShaders(eastl::fixed_vector<vk::PipelineShaderStageCreateInfo, ShaderTypeCount, false> &shadersOut,
|
CreateShaders(eastl::fixed_vector<vk::PipelineShaderStageCreateInfo, ShaderTypeCount, false> &shadersOut,
|
||||||
Slang::ComPtr<slang::IComponentType> &program, const std::span<const ShaderInfo> &shaders);
|
Slang::ComPtr<slang::IComponentType> &program, const std::span<const ShaderInfo> &shaders);
|
||||||
|
systems::PipelineCreationError
|
||||||
|
CreateShader(vk::PipelineShaderStageCreateInfo &shadersOut, Slang::ComPtr<slang::IComponentType> &program,
|
||||||
|
const ShaderInfo &shaders);
|
||||||
PipelineCreationError
|
PipelineCreationError
|
||||||
CreatePipelineLayout(vk::PipelineLayout &pipelineLayout, const Slang::ComPtr<slang::IComponentType> &program);
|
CreatePipelineLayout(vk::PipelineLayout &pipelineLayout, const Slang::ComPtr<slang::IComponentType> &program);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Pipelines, unlike the other resources, are not ref-counted.
|
// Pipelines, unlike the other resources, are not ref-counted.
|
||||||
PipelineCreationError CreatePipeline(Pipeline &pipeline, const GraphicsPipelineCreateInfo &createInfo);
|
PipelineCreationError CreatePipeline(Pipeline &pipeline, const GraphicsPipelineCreateInfo &createInfo);
|
||||||
|
PipelineCreationError CreateComputePipeline(Pipeline &pipeline, const ComputePipelineCreateInfo &createInfo);
|
||||||
|
|
||||||
//
|
//
|
||||||
// Frames
|
// Frames
|
||||||
|
|
@ -522,6 +562,12 @@ class Device final
|
||||||
return {m_Swapchain.m_Extent.width, m_Swapchain.m_Extent.height};
|
return {m_Swapchain.m_Extent.width, m_Swapchain.m_Extent.height};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
RegisterResizeCallback(Swapchain::FnResizeCallback &&callback)
|
||||||
|
{
|
||||||
|
m_Swapchain.RegisterResizeCallback(eastl::forward<Swapchain::FnResizeCallback>(callback));
|
||||||
|
}
|
||||||
|
|
||||||
void Present(Frame &frame, GraphicsContext &graphicsContext);
|
void Present(Frame &frame, GraphicsContext &graphicsContext);
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
@ -532,6 +578,7 @@ class Device final
|
||||||
friend TransferContext;
|
friend TransferContext;
|
||||||
|
|
||||||
TransferContext CreateTransferContext();
|
TransferContext CreateTransferContext();
|
||||||
|
ComputeContext CreateComputeContext();
|
||||||
Receipt Submit(Context &context);
|
Receipt Submit(Context &context);
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ CastBuffer(const Ref<TFrom> &from)
|
||||||
{
|
{
|
||||||
if constexpr (not concepts::BufferInto<TFrom, TTo>)
|
if constexpr (not concepts::BufferInto<TFrom, TTo>)
|
||||||
assert(TTo::FLAGS & from->m_Flags);
|
assert(TTo::FLAGS & from->m_Flags);
|
||||||
return std::reinterpret_pointer_cast<TTo>(from);
|
return eastl::reinterpret_pointer_cast<TTo>(from);
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
|
|
@ -75,7 +75,7 @@ class ResId
|
||||||
|
|
||||||
private:
|
private:
|
||||||
IdType m_Index;
|
IdType m_Index;
|
||||||
u32 m_Padding; //< Slang DescriptorHandle are a pair of u32. TODO: Use as validation.
|
u32 m_Padding = 0; //< Slang DescriptorHandle are a pair of u32. TODO: Use as validation.
|
||||||
|
|
||||||
explicit ResId(const IdType index)
|
explicit ResId(const IdType index)
|
||||||
: m_Index{index}
|
: m_Index{index}
|
||||||
|
|
|
||||||
|
|
@ -7,17 +7,21 @@
|
||||||
|
|
||||||
#include "core/device.h"
|
#include "core/device.h"
|
||||||
|
|
||||||
Pipeline::Pipeline(const Device *device, vk::PipelineLayout layout, vk::Pipeline pipeline,
|
Pipeline::Pipeline(const Device *device, const vk::PipelineLayout layout, const vk::Pipeline pipeline,
|
||||||
eastl::vector<vk::DescriptorSetLayout> &&setLayouts)
|
eastl::vector<vk::DescriptorSetLayout> &&setLayouts, const Kind kind)
|
||||||
: m_Device(device)
|
: m_Device{device}
|
||||||
, m_Layout(layout)
|
, m_Layout{layout}
|
||||||
, m_Pipeline(pipeline)
|
, m_Pipeline{pipeline}
|
||||||
, m_SetLayouts(std::move(setLayouts))
|
, m_SetLayouts{std::move(setLayouts)}
|
||||||
|
, m_Kind{kind}
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Pipeline::~Pipeline()
|
Pipeline::~Pipeline()
|
||||||
{
|
{
|
||||||
|
if (!m_Device || !m_Pipeline)
|
||||||
|
return;
|
||||||
|
|
||||||
for (const auto setLayout : m_SetLayouts)
|
for (const auto setLayout : m_SetLayouts)
|
||||||
{
|
{
|
||||||
m_Device->m_Device.destroy(setLayout, nullptr);
|
m_Device->m_Device.destroy(setLayout, nullptr);
|
||||||
|
|
|
||||||
|
|
@ -166,6 +166,25 @@ systems::Context::Begin()
|
||||||
ERROR_IF(Failed(result), "Could not begin context") THEN_ABORT(result);
|
ERROR_IF(Failed(result), "Could not begin context") THEN_ABORT(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Release versions inline 'no-op'.
|
||||||
|
#if !defined(ASTER_NDEBUG)
|
||||||
|
void
|
||||||
|
systems::Context::BeginDebugRegion(const cstr name, const vec4 color)
|
||||||
|
{
|
||||||
|
const vk::DebugUtilsLabelEXT label = {
|
||||||
|
.pLabelName = name,
|
||||||
|
.color = std::array{color.r, color.g, color.b, color.a},
|
||||||
|
};
|
||||||
|
m_Cmd.beginDebugUtilsLabelEXT(&label);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
systems::Context::EndDebugRegion()
|
||||||
|
{
|
||||||
|
m_Cmd.endDebugUtilsLabelEXT();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void
|
void
|
||||||
systems::Context::End()
|
systems::Context::End()
|
||||||
{
|
{
|
||||||
|
|
@ -173,6 +192,42 @@ systems::Context::End()
|
||||||
ERROR_IF(Failed(result), "Could not end context") THEN_ABORT(result);
|
ERROR_IF(Failed(result), "Could not end context") THEN_ABORT(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
systems::ComputeContext::Dispatch(const Pipeline &pipeline, u32 x, u32 y, u32 z, usize size, void *data)
|
||||||
|
{
|
||||||
|
BindPipeline(pipeline);
|
||||||
|
PushConstantBlock(0, size, data);
|
||||||
|
|
||||||
|
m_Cmd.dispatch(x, y, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
systems::ComputeContext::BindPipeline(const Pipeline &pipeline)
|
||||||
|
{
|
||||||
|
vk::PipelineBindPoint bindPoint = vk::PipelineBindPoint::eGraphics;
|
||||||
|
switch (pipeline.m_Kind)
|
||||||
|
{
|
||||||
|
case Pipeline::Kind::eGraphics:
|
||||||
|
bindPoint = vk::PipelineBindPoint::eGraphics;
|
||||||
|
break;
|
||||||
|
case Pipeline::Kind::eCompute:
|
||||||
|
bindPoint = vk::PipelineBindPoint::eCompute;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
UNREACHABLE("No additional bind points");
|
||||||
|
}
|
||||||
|
m_Cmd.bindPipeline(bindPoint, pipeline.m_Pipeline);
|
||||||
|
|
||||||
|
// TODO: Maybe find a smarter place to host this.
|
||||||
|
if (CommitManager::IsInit())
|
||||||
|
{
|
||||||
|
m_Cmd.bindDescriptorSets(bindPoint, pipeline.m_Layout, 0, 1, &CommitManager::Instance().GetDescriptorSet(), 0,
|
||||||
|
nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_PipelineInUse = &pipeline;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
systems::GraphicsContext::SetViewport(const vk::Viewport &viewport)
|
systems::GraphicsContext::SetViewport(const vk::Viewport &viewport)
|
||||||
{
|
{
|
||||||
|
|
@ -187,18 +242,9 @@ systems::GraphicsContext::BindVertexBuffer(const Ref<VertexBuffer> &vertexBuffer
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
systems::GraphicsContext::BindPipeline(const Pipeline &pipeline)
|
systems::GraphicsContext::BindIndexBuffer(const Ref<IndexBuffer> &indexBuffer)
|
||||||
{
|
{
|
||||||
m_Cmd.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline.m_Pipeline);
|
m_Cmd.bindIndexBuffer(indexBuffer->m_Buffer, 0, vk::IndexType::eUint32);
|
||||||
|
|
||||||
// TODO: Maybe find a smarter place to host this.
|
|
||||||
if (CommitManager::IsInit())
|
|
||||||
{
|
|
||||||
m_Cmd.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipeline.m_Layout, 0, 1,
|
|
||||||
&CommitManager::Instance().GetDescriptorSet(), 0, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_PipelineInUse = &pipeline;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -213,6 +259,12 @@ systems::GraphicsContext::DrawIndexed(usize indexCount)
|
||||||
m_Cmd.drawIndexed(static_cast<u32>(indexCount), 1, 0, 0, 0);
|
m_Cmd.drawIndexed(static_cast<u32>(indexCount), 1, 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
systems::GraphicsContext::DrawIndexed(const usize indexCount, const usize firstIndex, const usize firstVertex)
|
||||||
|
{
|
||||||
|
m_Cmd.drawIndexed(static_cast<u32>(indexCount), 1, static_cast<u32>(firstIndex), static_cast<i32>(firstVertex), 0);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
systems::GraphicsContext::BeginRendering(const vk::RenderingInfo &renderingInfo)
|
systems::GraphicsContext::BeginRendering(const vk::RenderingInfo &renderingInfo)
|
||||||
{
|
{
|
||||||
|
|
@ -227,18 +279,18 @@ systems::GraphicsContext::EndRendering()
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
systems::TransferContext::UploadTexture(const Ref<Image> &image, const ImageData &data)
|
systems::TransferContext::UploadTexture(const Ref<Image> &image, const eastl::span<u8> &data)
|
||||||
{
|
{
|
||||||
ERROR_IF(not(image and image->IsValid()), "Invalid image");
|
ERROR_IF(not(image and image->IsValid()), "Invalid image");
|
||||||
|
|
||||||
auto [w, h, d] = image->m_Extent;
|
auto [w, h, d] = image->m_Extent;
|
||||||
auto formatSize = GetFormatSize(image->m_Format);
|
auto formatSize = GetFormatSize(image->m_Format);
|
||||||
auto expectedByteSize = static_cast<u64>(w) * static_cast<u64>(h) * static_cast<u64>(d) * formatSize;
|
auto expectedByteSize = static_cast<u64>(w) * static_cast<u64>(h) * static_cast<u64>(d) * formatSize;
|
||||||
ERROR_IF(expectedByteSize != data.m_NumBytes, "Mismatch in data size {} vs image size {} ({}x{}x{}x{})",
|
ERROR_IF(expectedByteSize != data.size_bytes(), "Mismatch in data size {} vs image size {} ({}x{}x{}x{})",
|
||||||
data.m_NumBytes, expectedByteSize, w, h, d, formatSize);
|
data.size_bytes(), expectedByteSize, w, h, d, formatSize);
|
||||||
|
|
||||||
const Ref<StagingBuffer> stagingBuffer = m_Pool->GetDevice().CreateStagingBuffer(data.m_NumBytes);
|
const Ref<StagingBuffer> stagingBuffer = m_Pool->GetDevice().CreateStagingBuffer(data.size_bytes());
|
||||||
stagingBuffer->Write(0, data.m_NumBytes, data.m_Data);
|
stagingBuffer->Write(0, data.size_bytes(), data.data());
|
||||||
|
|
||||||
const vk::BufferImageCopy bufferImageCopy = {
|
const vk::BufferImageCopy bufferImageCopy = {
|
||||||
.bufferOffset = 0,
|
.bufferOffset = 0,
|
||||||
|
|
@ -261,6 +313,31 @@ systems::TransferContext::UploadTexture(const Ref<Image> &image, const ImageData
|
||||||
KeepAlive(image);
|
KeepAlive(image);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
systems::TransferContext::UploadBuffer(const Ref<Buffer> &buffer, usize size, const void *data)
|
||||||
|
{
|
||||||
|
ERROR_IF(not(buffer and buffer->IsValid()), "Invalid buffer");
|
||||||
|
|
||||||
|
auto expectedByteSize = buffer->m_Size;
|
||||||
|
ERROR_IF(expectedByteSize != size, "Mismatch in data size {} vs buffer size {}", size, expectedByteSize);
|
||||||
|
|
||||||
|
const Ref<StagingBuffer> stagingBuffer = m_Pool->GetDevice().CreateStagingBuffer(size);
|
||||||
|
stagingBuffer->Write(0, size, data);
|
||||||
|
|
||||||
|
const vk::BufferCopy bufferCopy = {.srcOffset = 0, .dstOffset = 0, .size = expectedByteSize};
|
||||||
|
|
||||||
|
m_Cmd.copyBuffer(stagingBuffer->m_Buffer, buffer->m_Buffer, 1, &bufferCopy);
|
||||||
|
|
||||||
|
KeepAlive(stagingBuffer);
|
||||||
|
KeepAlive(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
systems::TransferContext::Blit(const vk::BlitImageInfo2 &mipBlitInfo)
|
||||||
|
{
|
||||||
|
m_Cmd.blitImage2(&mipBlitInfo);
|
||||||
|
}
|
||||||
|
|
||||||
systems::TransferContext::TransferContext(TransferContext &&other) noexcept
|
systems::TransferContext::TransferContext(TransferContext &&other) noexcept
|
||||||
: Context{std::move(other)}
|
: Context{std::move(other)}
|
||||||
{
|
{
|
||||||
|
|
@ -275,6 +352,26 @@ systems::TransferContext::operator=(TransferContext &&other) noexcept
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
systems::ComputeContext::PushConstantBlock(const usize offset, const usize size, const void *data)
|
||||||
|
{
|
||||||
|
assert(m_PipelineInUse);
|
||||||
|
|
||||||
|
vk::ShaderStageFlags stage;
|
||||||
|
switch (m_PipelineInUse->m_Kind)
|
||||||
|
{
|
||||||
|
case Pipeline::Kind::eGraphics:
|
||||||
|
stage = vk::ShaderStageFlagBits::eAll;
|
||||||
|
break;
|
||||||
|
case Pipeline::Kind::eCompute:
|
||||||
|
stage = vk::ShaderStageFlagBits::eCompute;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_Cmd.pushConstants(m_PipelineInUse->m_Layout, stage, static_cast<u32>(offset),
|
||||||
|
static_cast<u32>(size), data);
|
||||||
|
}
|
||||||
|
|
||||||
using namespace systems::_internal;
|
using namespace systems::_internal;
|
||||||
|
|
||||||
ContextPool::ContextPool(Device &device, const u32 queueFamilyIndex, const ManagedBy managedBy)
|
ContextPool::ContextPool(Device &device, const u32 queueFamilyIndex, const ManagedBy managedBy)
|
||||||
|
|
@ -367,6 +464,8 @@ ContextPool::AllocateCommandBuffer()
|
||||||
};
|
};
|
||||||
vk::CommandBuffer &cmd = m_CommandBuffers.emplace_back();
|
vk::CommandBuffer &cmd = m_CommandBuffers.emplace_back();
|
||||||
AbortIfFailed(m_Device->m_Device->allocateCommandBuffers(&allocateInfo, &cmd));
|
AbortIfFailed(m_Device->m_Device->allocateCommandBuffers(&allocateInfo, &cmd));
|
||||||
|
++m_BuffersAllocated;
|
||||||
|
|
||||||
return cmd;
|
return cmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -395,6 +494,12 @@ TransferContextPool::CreateTransferContext()
|
||||||
return TransferContext{*this, AllocateCommandBuffer()};
|
return TransferContext{*this, AllocateCommandBuffer()};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
systems::ComputeContext
|
||||||
|
ComputeContextPool::CreateComputeContext()
|
||||||
|
{
|
||||||
|
return ComputeContext{*this, AllocateCommandBuffer()};
|
||||||
|
}
|
||||||
|
|
||||||
systems::GraphicsContext
|
systems::GraphicsContext
|
||||||
GraphicsContextPool::CreateGraphicsContext()
|
GraphicsContextPool::CreateGraphicsContext()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -17,10 +17,65 @@
|
||||||
#include <EASTL/vector_map.h>
|
#include <EASTL/vector_map.h>
|
||||||
#include <fmt/ranges.h>
|
#include <fmt/ranges.h>
|
||||||
|
|
||||||
|
#if defined(DOMAIN)
|
||||||
|
#undef DOMAIN
|
||||||
|
#endif
|
||||||
|
|
||||||
static constexpr QueueSupportFlags REQUIRED_QUEUE_SUPPORT =
|
static constexpr QueueSupportFlags REQUIRED_QUEUE_SUPPORT =
|
||||||
QueueSupportFlags{} | QueueSupportFlagBits::eGraphics | QueueSupportFlagBits::eCompute |
|
QueueSupportFlags{} | QueueSupportFlagBits::eGraphics | QueueSupportFlagBits::eCompute |
|
||||||
QueueSupportFlagBits::ePresent | QueueSupportFlagBits::eTransfer;
|
QueueSupportFlagBits::ePresent | QueueSupportFlagBits::eTransfer;
|
||||||
|
|
||||||
|
vk::CompareOp
|
||||||
|
DepthOpToVulkan(systems::GraphicsPipelineCreateInfo::CompareOp depthOp)
|
||||||
|
{
|
||||||
|
switch (depthOp)
|
||||||
|
{
|
||||||
|
case systems::GraphicsPipelineCreateInfo::CompareOp::eNever:
|
||||||
|
return vk::CompareOp::eNever;
|
||||||
|
case systems::GraphicsPipelineCreateInfo::CompareOp::eLessThan:
|
||||||
|
return vk::CompareOp::eLess;
|
||||||
|
case systems::GraphicsPipelineCreateInfo::CompareOp::eEqualTo:
|
||||||
|
return vk::CompareOp::eEqual;
|
||||||
|
case systems::GraphicsPipelineCreateInfo::CompareOp::eGreaterThan:
|
||||||
|
return vk::CompareOp::eGreater;
|
||||||
|
case systems::GraphicsPipelineCreateInfo::CompareOp::eLessThanOrEqualTo:
|
||||||
|
return vk::CompareOp::eLessOrEqual;
|
||||||
|
case systems::GraphicsPipelineCreateInfo::CompareOp::eGreaterThanOrEqualTo:
|
||||||
|
return vk::CompareOp::eGreaterOrEqual;
|
||||||
|
case systems::GraphicsPipelineCreateInfo::CompareOp::eNotEqualTo:
|
||||||
|
return vk::CompareOp::eNotEqual;
|
||||||
|
case systems::GraphicsPipelineCreateInfo::CompareOp::eAlways:
|
||||||
|
return vk::CompareOp::eAlways;
|
||||||
|
}
|
||||||
|
return vk::CompareOp::eAlways;
|
||||||
|
}
|
||||||
|
|
||||||
|
vk::PipelineDepthStencilStateCreateInfo
|
||||||
|
systems::GraphicsPipelineCreateInfo::GetDepthStencilStateCreateInfo() const
|
||||||
|
{
|
||||||
|
bool depthEnabled = false;
|
||||||
|
bool depthWriteEnabled = false;
|
||||||
|
|
||||||
|
switch (m_DepthTest)
|
||||||
|
{
|
||||||
|
case DepthTest::eEnabled:
|
||||||
|
depthEnabled = true;
|
||||||
|
depthWriteEnabled = true;
|
||||||
|
break;
|
||||||
|
case DepthTest::eReadOnly:
|
||||||
|
depthEnabled = true;
|
||||||
|
break;
|
||||||
|
case DepthTest::eDisabled:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
.depthTestEnable = depthEnabled,
|
||||||
|
.depthWriteEnable = depthWriteEnabled,
|
||||||
|
.depthCompareOp = DepthOpToVulkan(m_DepthOp),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
PhysicalDevice
|
PhysicalDevice
|
||||||
systems::DefaultPhysicalDeviceSelector(const PhysicalDevices &physicalDevices)
|
systems::DefaultPhysicalDeviceSelector(const PhysicalDevices &physicalDevices)
|
||||||
{
|
{
|
||||||
|
|
@ -66,6 +121,21 @@ systems::Device::CreateStorageBuffer(const usize size, const cstr name)
|
||||||
return eastl::make_shared<StorageBuffer>(Buffer{&m_Device, size, usage, createFlags, memoryUsage, name});
|
return eastl::make_shared<StorageBuffer>(Buffer{&m_Device, size, usage, createFlags, memoryUsage, name});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ref<IndexBuffer>
|
||||||
|
systems::Device::CreateIndexBuffer(usize size, cstr name)
|
||||||
|
{
|
||||||
|
// TODO: Storage and Index buffer are set.
|
||||||
|
// This is hacky and should be improved.
|
||||||
|
constexpr vk::BufferUsageFlags usage = vk::BufferUsageFlagBits::eIndexBuffer |
|
||||||
|
vk::BufferUsageFlagBits::eShaderDeviceAddress |
|
||||||
|
vk::BufferUsageFlagBits::eTransferDst;
|
||||||
|
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;
|
||||||
|
return eastl::make_shared<IndexBuffer>(Buffer{&m_Device, size, usage, createFlags, memoryUsage, name});
|
||||||
|
}
|
||||||
|
|
||||||
Ref<UniformBuffer>
|
Ref<UniformBuffer>
|
||||||
systems::Device::CreateUniformBuffer(const usize size, const cstr name)
|
systems::Device::CreateUniformBuffer(const usize size, const cstr name)
|
||||||
{
|
{
|
||||||
|
|
@ -447,6 +517,8 @@ systems::Device::CreatePipeline(Pipeline &pipelineOut, const GraphicsPipelineCre
|
||||||
{
|
{
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
if (createInfo.m_Name)
|
||||||
|
SetName(pipelineLayout, createInfo.m_Name);
|
||||||
|
|
||||||
eastl::fixed_vector<vk::VertexInputBindingDescription, 4, false> inputBindingDescriptions;
|
eastl::fixed_vector<vk::VertexInputBindingDescription, 4, false> inputBindingDescriptions;
|
||||||
eastl::fixed_vector<vk::VertexInputAttributeDescription, 4, false> inputAttributeDescriptions;
|
eastl::fixed_vector<vk::VertexInputAttributeDescription, 4, false> inputAttributeDescriptions;
|
||||||
|
|
@ -499,11 +571,7 @@ systems::Device::CreatePipeline(Pipeline &pipelineOut, const GraphicsPipelineCre
|
||||||
.rasterizationSamples = vk::SampleCountFlagBits::e1,
|
.rasterizationSamples = vk::SampleCountFlagBits::e1,
|
||||||
.sampleShadingEnable = false,
|
.sampleShadingEnable = false,
|
||||||
};
|
};
|
||||||
vk::PipelineDepthStencilStateCreateInfo depthStencilStateCreateInfo = {
|
vk::PipelineDepthStencilStateCreateInfo depthStencilStateCreateInfo = createInfo.GetDepthStencilStateCreateInfo();
|
||||||
.depthTestEnable = true,
|
|
||||||
.depthWriteEnable = true,
|
|
||||||
.depthCompareOp = vk::CompareOp::eLess,
|
|
||||||
};
|
|
||||||
vk::PipelineColorBlendAttachmentState colorBlendAttachmentState = {
|
vk::PipelineColorBlendAttachmentState colorBlendAttachmentState = {
|
||||||
.blendEnable = false,
|
.blendEnable = false,
|
||||||
.srcColorBlendFactor = vk::BlendFactor::eSrcColor,
|
.srcColorBlendFactor = vk::BlendFactor::eSrcColor,
|
||||||
|
|
@ -554,17 +622,64 @@ systems::Device::CreatePipeline(Pipeline &pipelineOut, const GraphicsPipelineCre
|
||||||
.layout = pipelineLayout,
|
.layout = pipelineLayout,
|
||||||
};
|
};
|
||||||
vk::Pipeline pipeline;
|
vk::Pipeline pipeline;
|
||||||
auto vresult = m_Device->createGraphicsPipelines(nullptr, 1, &pipelineCreateInfo, nullptr, &pipeline);
|
if (auto result = m_Device->createGraphicsPipelines(nullptr, 1, &pipelineCreateInfo, nullptr, &pipeline);
|
||||||
ERROR_IF(Failed(vresult), "Could not create a graphics pipeline. Cause: {}", vresult)
|
Failed(result))
|
||||||
THEN_ABORT(vresult);
|
{
|
||||||
SetName(pipeline, "Triangle Pipeline");
|
ERROR("Could not create a graphics pipeline. Cause: {}", result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
if (createInfo.m_Name)
|
||||||
|
SetName(pipeline, createInfo.m_Name);
|
||||||
|
|
||||||
for (auto &shader : shaders)
|
for (auto &shader : shaders)
|
||||||
{
|
{
|
||||||
m_Device->destroy(shader.module, nullptr);
|
m_Device->destroy(shader.module, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
pipelineOut = {&m_Device, pipelineLayout, pipeline, {}};
|
pipelineOut = {&m_Device, pipelineLayout, pipeline, {}, Pipeline::Kind::eGraphics};
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
systems::PipelineCreationError
|
||||||
|
systems::Device::CreateComputePipeline(Pipeline &pipelineOut, const ComputePipelineCreateInfo &createInfo)
|
||||||
|
{
|
||||||
|
eastl::fixed_vector<vk::PipelineShaderStageCreateInfo, ShaderTypeCount, false> shaders;
|
||||||
|
Slang::ComPtr<slang::IComponentType> program;
|
||||||
|
if (auto shaderResult = CreateShaders(shaders, program, {&createInfo.m_Shader, 1}); shaderResult)
|
||||||
|
{
|
||||||
|
return shaderResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
vk::PipelineLayout pipelineLayout;
|
||||||
|
if (auto result = CreatePipelineLayout(pipelineLayout, program))
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
if (createInfo.m_Name)
|
||||||
|
SetName(pipelineLayout, createInfo.m_Name);
|
||||||
|
|
||||||
|
vk::ComputePipelineCreateInfo pipelineCreateInfo = {
|
||||||
|
.stage = shaders[0],
|
||||||
|
.layout = pipelineLayout,
|
||||||
|
};
|
||||||
|
|
||||||
|
vk::Pipeline pipeline;
|
||||||
|
if (auto result = m_Device->createComputePipelines(nullptr, 1, &pipelineCreateInfo, nullptr, &pipeline);
|
||||||
|
Failed(result))
|
||||||
|
{
|
||||||
|
ERROR("Could not create a graphics pipeline. Cause: {}", result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (createInfo.m_Name)
|
||||||
|
SetName(pipeline, createInfo.m_Name);
|
||||||
|
|
||||||
|
for (auto &shader : shaders)
|
||||||
|
{
|
||||||
|
m_Device->destroy(shader.module, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
pipelineOut = Pipeline{&m_Device, pipelineLayout, pipeline, {}, Pipeline::Kind::eCompute};
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -607,11 +722,12 @@ systems::Device::CreateShaders(
|
||||||
{
|
{
|
||||||
ComPtr<slang::IModule> shaderModule;
|
ComPtr<slang::IModule> shaderModule;
|
||||||
shaderModule = m_SlangSession->loadModule(shaderInfo.m_ShaderFile.data(), shaderDiagnostics.writeRef());
|
shaderModule = m_SlangSession->loadModule(shaderInfo.m_ShaderFile.data(), shaderDiagnostics.writeRef());
|
||||||
if (shaderDiagnostics)
|
if (!shaderModule)
|
||||||
{
|
{
|
||||||
ERROR("{}", static_cast<cstr>(shaderDiagnostics->getBufferPointer()));
|
ERROR("{}", static_cast<cstr>(shaderDiagnostics->getBufferPointer()));
|
||||||
return SLANG_FAIL;
|
return SLANG_FAIL;
|
||||||
}
|
}
|
||||||
|
WARN_IF(shaderDiagnostics, "{}", static_cast<cstr>(shaderDiagnostics->getBufferPointer()));
|
||||||
|
|
||||||
components.push_back(shaderModule);
|
components.push_back(shaderModule);
|
||||||
|
|
||||||
|
|
@ -620,12 +736,21 @@ systems::Device::CreateShaders(
|
||||||
ComPtr<slang::IEntryPoint> actualEntryPoint;
|
ComPtr<slang::IEntryPoint> actualEntryPoint;
|
||||||
auto slangResult = shaderModule->findEntryPointByName(entryPointName.data(), actualEntryPoint.writeRef());
|
auto slangResult = shaderModule->findEntryPointByName(entryPointName.data(), actualEntryPoint.writeRef());
|
||||||
|
|
||||||
|
if (slangResult < 0)
|
||||||
|
{
|
||||||
|
ERROR("Could not find entry point '{}' in '{}'. Cause: {}", entryPointName, shaderInfo.m_ShaderFile,
|
||||||
|
slangResult);
|
||||||
|
return slangResult;
|
||||||
|
}
|
||||||
|
|
||||||
slang::ProgramLayout *entryProgramLayout = actualEntryPoint->getLayout(0, shaderDiagnostics.writeRef());
|
slang::ProgramLayout *entryProgramLayout = actualEntryPoint->getLayout(0, shaderDiagnostics.writeRef());
|
||||||
if (shaderDiagnostics)
|
if (!entryProgramLayout)
|
||||||
{
|
{
|
||||||
ERROR("{}", static_cast<cstr>(shaderDiagnostics->getBufferPointer()));
|
ERROR("{}", static_cast<cstr>(shaderDiagnostics->getBufferPointer()));
|
||||||
return SLANG_FAIL;
|
return SLANG_FAIL;
|
||||||
}
|
}
|
||||||
|
WARN_IF(shaderDiagnostics, "{}", static_cast<cstr>(shaderDiagnostics->getBufferPointer()));
|
||||||
|
|
||||||
switch (entryProgramLayout->getEntryPointByIndex(0)->getStage())
|
switch (entryProgramLayout->getEntryPointByIndex(0)->getStage())
|
||||||
{
|
{
|
||||||
MARK_FOUND_AND_VALIDATE_UNIQUE(vertexFound, VERTEX);
|
MARK_FOUND_AND_VALIDATE_UNIQUE(vertexFound, VERTEX);
|
||||||
|
|
@ -647,13 +772,6 @@ systems::Device::CreateShaders(
|
||||||
ERROR("Invalid Stage.") THEN_ABORT(-1);
|
ERROR("Invalid Stage.") THEN_ABORT(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (slangResult < 0)
|
|
||||||
{
|
|
||||||
ERROR("Could not find entry point '{}' in '{}'. Cause: {}", entryPointName, shaderInfo.m_ShaderFile,
|
|
||||||
slangResult);
|
|
||||||
return slangResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
components.push_back(actualEntryPoint);
|
components.push_back(actualEntryPoint);
|
||||||
++entryPointCount;
|
++entryPointCount;
|
||||||
}
|
}
|
||||||
|
|
@ -697,6 +815,7 @@ systems::Device::CreateShaders(
|
||||||
ERROR("{}", static_cast<cstr>(shaderDiagnostics->getBufferPointer()));
|
ERROR("{}", static_cast<cstr>(shaderDiagnostics->getBufferPointer()));
|
||||||
return slangResult;
|
return slangResult;
|
||||||
}
|
}
|
||||||
|
WARN_IF(shaderDiagnostics, "{}", static_cast<cstr>(shaderDiagnostics->getBufferPointer()));
|
||||||
|
|
||||||
vk::Result result = vk::Result::eSuccess;
|
vk::Result result = vk::Result::eSuccess;
|
||||||
for (u32 entryPoint = 0; entryPoint < entryPointCount; ++entryPoint)
|
for (u32 entryPoint = 0; entryPoint < entryPointCount; ++entryPoint)
|
||||||
|
|
@ -710,6 +829,7 @@ systems::Device::CreateShaders(
|
||||||
ERROR("{}", static_cast<cstr>(shaderDiagnostics->getBufferPointer()));
|
ERROR("{}", static_cast<cstr>(shaderDiagnostics->getBufferPointer()));
|
||||||
return slangResult;
|
return slangResult;
|
||||||
}
|
}
|
||||||
|
WARN_IF(shaderDiagnostics, "{}", static_cast<cstr>(shaderDiagnostics->getBufferPointer()));
|
||||||
|
|
||||||
if (auto progLayout = program->getLayout(0))
|
if (auto progLayout = program->getLayout(0))
|
||||||
{
|
{
|
||||||
|
|
@ -789,12 +909,13 @@ systems::Device::CreatePipelineLayout(vk::PipelineLayout &pipelineLayout,
|
||||||
|
|
||||||
ComPtr<slang::IBlob> layoutDiagnostics;
|
ComPtr<slang::IBlob> layoutDiagnostics;
|
||||||
slang::ProgramLayout *layout = program->getLayout(0, layoutDiagnostics.writeRef());
|
slang::ProgramLayout *layout = program->getLayout(0, layoutDiagnostics.writeRef());
|
||||||
if (layoutDiagnostics)
|
if (!layout)
|
||||||
{
|
{
|
||||||
ERROR_IF(!layout, "{}", static_cast<cstr>(layoutDiagnostics->getBufferPointer()));
|
ERROR("{}", static_cast<cstr>(layoutDiagnostics->getBufferPointer()));
|
||||||
return SLANG_FAIL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WARN_IF(layoutDiagnostics, "{}", static_cast<cstr>(layoutDiagnostics->getBufferPointer()));
|
||||||
|
|
||||||
vk::DescriptorSetLayout setLayout = {};
|
vk::DescriptorSetLayout setLayout = {};
|
||||||
if (m_CommitManager)
|
if (m_CommitManager)
|
||||||
setLayout = m_CommitManager->GetDescriptorSetLayout();
|
setLayout = m_CommitManager->GetDescriptorSetLayout();
|
||||||
|
|
@ -940,6 +1061,7 @@ systems::Device::Device(const DeviceCreateInfo &createInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
m_TransferContextPool.Init(*this, m_TransferQueueFamily);
|
m_TransferContextPool.Init(*this, m_TransferQueueFamily);
|
||||||
|
m_ComputeContextPool.Init(*this, m_ComputeQueueFamily);
|
||||||
|
|
||||||
constexpr SlangGlobalSessionDesc globalSessionDesc = {};
|
constexpr SlangGlobalSessionDesc globalSessionDesc = {};
|
||||||
auto result = slang::createGlobalSession(&globalSessionDesc, m_GlobalSlangSession.writeRef());
|
auto result = slang::createGlobalSession(&globalSessionDesc, m_GlobalSlangSession.writeRef());
|
||||||
|
|
@ -957,15 +1079,12 @@ systems::Device::Device(const DeviceCreateInfo &createInfo)
|
||||||
.name = slang::CompilerOptionName::GLSLForceScalarLayout,
|
.name = slang::CompilerOptionName::GLSLForceScalarLayout,
|
||||||
.value = slang::CompilerOptionValue{.kind = slang::CompilerOptionValueKind::Int, .intValue0 = 1},
|
.value = slang::CompilerOptionValue{.kind = slang::CompilerOptionValueKind::Int, .intValue0 = 1},
|
||||||
};
|
};
|
||||||
std::array compilerOptions = {
|
eastl::array compilerOptions = {useOriginalEntrypointNames, bindlessSpaceIndex, scalarLayout};
|
||||||
useOriginalEntrypointNames,
|
slang::PreprocessorMacroDesc fancyFlag = {"_DEBUG", "1"};
|
||||||
bindlessSpaceIndex,
|
|
||||||
scalarLayout,
|
|
||||||
};
|
|
||||||
|
|
||||||
const slang::TargetDesc spirvTargetDesc = {
|
const slang::TargetDesc spirvTargetDesc = {
|
||||||
.format = SLANG_SPIRV,
|
.format = SLANG_SPIRV,
|
||||||
.profile = m_GlobalSlangSession->findProfile("glsl_450"),
|
.profile = m_GlobalSlangSession->findProfile("sm_6_6"),
|
||||||
.compilerOptionEntries = compilerOptions.data(),
|
.compilerOptionEntries = compilerOptions.data(),
|
||||||
.compilerOptionEntryCount = static_cast<u32>(compilerOptions.size()),
|
.compilerOptionEntryCount = static_cast<u32>(compilerOptions.size()),
|
||||||
};
|
};
|
||||||
|
|
@ -974,6 +1093,12 @@ systems::Device::Device(const DeviceCreateInfo &createInfo)
|
||||||
.targetCount = 1,
|
.targetCount = 1,
|
||||||
.searchPaths = createInfo.m_ShaderSearchPaths.data(),
|
.searchPaths = createInfo.m_ShaderSearchPaths.data(),
|
||||||
.searchPathCount = static_cast<u32>(createInfo.m_ShaderSearchPaths.size()),
|
.searchPathCount = static_cast<u32>(createInfo.m_ShaderSearchPaths.size()),
|
||||||
|
.preprocessorMacros = &fancyFlag,
|
||||||
|
#if !defined(ASTER_NDEBUG)
|
||||||
|
.preprocessorMacroCount = 1,
|
||||||
|
#else
|
||||||
|
.preprocessorMacroCount = 0,
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
result = m_GlobalSlangSession->createSession(sessionDesc, m_SlangSession.writeRef());
|
result = m_GlobalSlangSession->createSession(sessionDesc, m_SlangSession.writeRef());
|
||||||
ERROR_IF(result < 0, "Could not create a slang session.") THEN_ABORT(result);
|
ERROR_IF(result < 0, "Could not create a slang session.") THEN_ABORT(result);
|
||||||
|
|
@ -1003,6 +1128,9 @@ systems::Device::~Device()
|
||||||
systems::Frame &
|
systems::Frame &
|
||||||
systems::Device::GetNextFrame()
|
systems::Device::GetNextFrame()
|
||||||
{
|
{
|
||||||
|
if (m_CommitManager)
|
||||||
|
m_CommitManager->Update();
|
||||||
|
|
||||||
Frame ¤tFrame = m_Frames[m_CurrentFrameIdx];
|
Frame ¤tFrame = m_Frames[m_CurrentFrameIdx];
|
||||||
u32 frameIndex = m_CurrentFrameIdx;
|
u32 frameIndex = m_CurrentFrameIdx;
|
||||||
|
|
||||||
|
|
@ -1083,6 +1211,12 @@ systems::Device::CreateTransferContext()
|
||||||
return m_TransferContextPool.CreateTransferContext();
|
return m_TransferContextPool.CreateTransferContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
systems::ComputeContext
|
||||||
|
systems::Device::CreateComputeContext()
|
||||||
|
{
|
||||||
|
return m_ComputeContextPool.CreateComputeContext();
|
||||||
|
}
|
||||||
|
|
||||||
systems::Receipt
|
systems::Receipt
|
||||||
systems::Device::Submit(Context &context)
|
systems::Device::Submit(Context &context)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,10 @@
|
||||||
|
|
||||||
#include "gui.h"
|
#include "gui.h"
|
||||||
|
|
||||||
#include "aster/core/instance.h"
|
|
||||||
#include "aster/core/device.h"
|
#include "aster/core/device.h"
|
||||||
|
#include "aster/core/instance.h"
|
||||||
#include "aster/core/window.h"
|
#include "aster/core/window.h"
|
||||||
|
#include "aster/systems/device.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
|
|
||||||
#include <imgui_impl_glfw.h>
|
#include <imgui_impl_glfw.h>
|
||||||
|
|
@ -25,6 +26,72 @@ VulkanAssert(VkResult result)
|
||||||
AbortIfFailed(result);
|
AbortIfFailed(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Init(systems::Device &device, Window &window)
|
||||||
|
{
|
||||||
|
g_AttachmentFormat = device.m_Swapchain.m_Format;
|
||||||
|
|
||||||
|
eastl::vector<vk::DescriptorPoolSize> poolSizes = {
|
||||||
|
{vk::DescriptorType::eSampler, 1000},
|
||||||
|
{vk::DescriptorType::eCombinedImageSampler, 1000},
|
||||||
|
{vk::DescriptorType::eSampledImage, 1000},
|
||||||
|
{vk::DescriptorType::eStorageImage, 1000},
|
||||||
|
{vk::DescriptorType::eUniformTexelBuffer, 1000},
|
||||||
|
{vk::DescriptorType::eStorageTexelBuffer, 1000},
|
||||||
|
{vk::DescriptorType::eUniformBuffer, 1000},
|
||||||
|
{vk::DescriptorType::eStorageBuffer, 1000},
|
||||||
|
{vk::DescriptorType::eUniformBufferDynamic, 1000},
|
||||||
|
{vk::DescriptorType::eStorageBufferDynamic, 1000},
|
||||||
|
{vk::DescriptorType::eInputAttachment, 1000},
|
||||||
|
};
|
||||||
|
|
||||||
|
const vk::DescriptorPoolCreateInfo descriptorPoolCreateInfo = {
|
||||||
|
.flags = vk::DescriptorPoolCreateFlagBits::eFreeDescriptorSet,
|
||||||
|
.maxSets = 1000,
|
||||||
|
.poolSizeCount = static_cast<u32>(poolSizes.size()),
|
||||||
|
.pPoolSizes = poolSizes.data(),
|
||||||
|
};
|
||||||
|
|
||||||
|
AbortIfFailed(device.m_Device->createDescriptorPool(&descriptorPoolCreateInfo, nullptr, &g_DescriptorPool));
|
||||||
|
|
||||||
|
IMGUI_CHECKVERSION();
|
||||||
|
CreateContext();
|
||||||
|
ImGuiIO &io = GetIO();
|
||||||
|
(void)io;
|
||||||
|
// io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
|
||||||
|
// io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Viewports bad
|
||||||
|
|
||||||
|
StyleColorsDark();
|
||||||
|
|
||||||
|
ImGui_ImplGlfw_InitForVulkan(window.m_Window, true);
|
||||||
|
|
||||||
|
vk::PipelineRenderingCreateInfo renderingCreateInfo = {
|
||||||
|
.colorAttachmentCount = 1,
|
||||||
|
.pColorAttachmentFormats = &g_AttachmentFormat,
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: Switch this into being managed by Device.
|
||||||
|
// m_Instance etc should private.
|
||||||
|
ImGui_ImplVulkan_InitInfo imguiVulkanInitInfo = {
|
||||||
|
.Instance = device.m_Instance.m_Instance,
|
||||||
|
.PhysicalDevice = device.m_Device.m_PhysicalDevice,
|
||||||
|
.Device = device.m_Device.m_Device,
|
||||||
|
.QueueFamily = device.m_PrimaryQueueFamily,
|
||||||
|
.Queue = device.m_PrimaryQueue,
|
||||||
|
.DescriptorPool = g_DescriptorPool,
|
||||||
|
.MinImageCount = static_cast<u32>(device.m_Swapchain.m_Images.size()),
|
||||||
|
.ImageCount = static_cast<u32>(device.m_Swapchain.m_Images.size()),
|
||||||
|
.PipelineCache = nullptr,
|
||||||
|
.UseDynamicRendering = true,
|
||||||
|
.PipelineRenderingCreateInfo = renderingCreateInfo,
|
||||||
|
.Allocator = nullptr,
|
||||||
|
.CheckVkResultFn = VulkanAssert,
|
||||||
|
};
|
||||||
|
ImGui_ImplVulkan_Init(&imguiVulkanInitInfo);
|
||||||
|
|
||||||
|
ImGui_ImplVulkan_CreateFontsTexture();
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Init(const Instance *context, const Device *device, const Window *window, vk::Format attachmentFormat,
|
Init(const Instance *context, const Device *device, const Window *window, vk::Format attachmentFormat,
|
||||||
const u32 imageCount, const u32 queueFamily, const vk::Queue queue)
|
const u32 imageCount, const u32 queueFamily, const vk::Queue queue)
|
||||||
|
|
@ -90,10 +157,19 @@ Init(const Instance *context, const Device *device, const Window *window, vk::Fo
|
||||||
ImGui_ImplVulkan_CreateFontsTexture();
|
ImGui_ImplVulkan_CreateFontsTexture();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Destroy(const systems::Device &device)
|
||||||
|
{
|
||||||
|
ImGui_ImplVulkan_Shutdown();
|
||||||
|
ImGui_ImplGlfw_Shutdown();
|
||||||
|
DestroyContext();
|
||||||
|
|
||||||
|
device.m_Device->destroy(Take(g_DescriptorPool), nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Destroy(const Device *device)
|
Destroy(const Device *device)
|
||||||
{
|
{
|
||||||
|
|
||||||
ImGui_ImplVulkan_Shutdown();
|
ImGui_ImplVulkan_Shutdown();
|
||||||
ImGui_ImplGlfw_Shutdown();
|
ImGui_ImplGlfw_Shutdown();
|
||||||
DestroyContext();
|
DestroyContext();
|
||||||
|
|
@ -200,6 +276,36 @@ Draw(const vk::CommandBuffer commandBuffer, const vk::Extent2D extent, const vk:
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Draw(systems::Frame &frame, systems::GraphicsContext &context)
|
||||||
|
{
|
||||||
|
context.BeginDebugRegion("UI Pass", {0.9f, 0.9f, 1.0f, 1.0f});
|
||||||
|
|
||||||
|
vk::RenderingAttachmentInfo attachmentInfo = {
|
||||||
|
.imageView = frame.m_SwapchainImageView,
|
||||||
|
.imageLayout = vk::ImageLayout::eColorAttachmentOptimal,
|
||||||
|
.resolveMode = vk::ResolveModeFlagBits::eNone,
|
||||||
|
.loadOp = vk::AttachmentLoadOp::eLoad,
|
||||||
|
.storeOp = vk::AttachmentStoreOp::eStore,
|
||||||
|
.clearValue = vk::ClearColorValue{0.0f, 0.0f, 0.0f, 1.0f},
|
||||||
|
};
|
||||||
|
|
||||||
|
const vk::RenderingInfo renderingInfo = {
|
||||||
|
.renderArea = {.extent = frame.m_SwapchainSize},
|
||||||
|
.layerCount = 1,
|
||||||
|
.colorAttachmentCount = 1,
|
||||||
|
.pColorAttachments = &attachmentInfo,
|
||||||
|
.pDepthAttachment = nullptr,
|
||||||
|
};
|
||||||
|
|
||||||
|
context.BeginRendering(renderingInfo);
|
||||||
|
|
||||||
|
ImGui_ImplVulkan_RenderDrawData(GetDrawData(), context.GetCommandBuffer());
|
||||||
|
|
||||||
|
context.EndRendering();
|
||||||
|
context.EndDebugRegion();
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
PushDisable()
|
PushDisable()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "aster/aster.h"
|
#include "aster/aster.h"
|
||||||
|
#include "aster/core/device.h"
|
||||||
|
|
||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
|
|
||||||
|
|
@ -14,17 +15,27 @@ struct Instance;
|
||||||
struct Window;
|
struct Window;
|
||||||
struct Swapchain;
|
struct Swapchain;
|
||||||
|
|
||||||
|
namespace systems
|
||||||
|
{
|
||||||
|
class Device;
|
||||||
|
class GraphicsContext;
|
||||||
|
struct Frame;
|
||||||
|
}
|
||||||
|
|
||||||
// ReSharper disable once CppInconsistentNaming
|
// ReSharper disable once CppInconsistentNaming
|
||||||
namespace ImGui
|
namespace ImGui
|
||||||
{
|
{
|
||||||
|
void Init(systems::Device &device, Window &window);
|
||||||
void Init(const Instance *context, const Device *device, const Window *window, vk::Format attachmentFormat,
|
void Init(const Instance *context, const Device *device, const Window *window, vk::Format attachmentFormat,
|
||||||
u32 imageCount, u32 queueFamily, vk::Queue queue);
|
u32 imageCount, u32 queueFamily, vk::Queue queue);
|
||||||
|
void Destroy(const systems::Device &device);
|
||||||
void Destroy(const Device *device);
|
void Destroy(const Device *device);
|
||||||
|
|
||||||
void Recreate();
|
void Recreate();
|
||||||
void StartBuild();
|
void StartBuild();
|
||||||
void EndBuild();
|
void EndBuild();
|
||||||
void Draw(vk::CommandBuffer commandBuffer, vk::Extent2D extent, vk::ImageView view);
|
void Draw(vk::CommandBuffer commandBuffer, vk::Extent2D extent, vk::ImageView view);
|
||||||
|
void Draw(systems::Frame &frame, systems::GraphicsContext &context);
|
||||||
|
|
||||||
void PushDisable();
|
void PushDisable();
|
||||||
void PopDisable();
|
void PopDisable();
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,12 @@ struct ImageFile
|
||||||
|
|
||||||
bool Load(cstr fileName);
|
bool Load(cstr fileName);
|
||||||
[[nodiscard]] usize GetSize() const;
|
[[nodiscard]] usize GetSize() const;
|
||||||
|
|
||||||
|
operator eastl::span<u8>() const
|
||||||
|
{
|
||||||
|
return {static_cast<u8*>(m_Data), GetSize()};
|
||||||
|
}
|
||||||
|
|
||||||
~ImageFile();
|
~ImageFile();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -251,7 +257,7 @@ main(int, char **)
|
||||||
|
|
||||||
context.Dependency(imageReadyToWriteDependency);
|
context.Dependency(imageReadyToWriteDependency);
|
||||||
|
|
||||||
context.UploadTexture(crate->m_Image, {.m_Data = imageFile.m_Data, .m_NumBytes = imageFile.GetSize()});
|
context.UploadTexture(crate->m_Image, imageFile);
|
||||||
|
|
||||||
context.Dependency(imageReadyToReadDependency);
|
context.Dependency(imageReadyToReadDependency);
|
||||||
|
|
||||||
|
|
@ -347,12 +353,11 @@ main(int, char **)
|
||||||
while (window.Poll())
|
while (window.Poll())
|
||||||
{
|
{
|
||||||
Time::Update();
|
Time::Update();
|
||||||
commitManager.Update();
|
|
||||||
|
|
||||||
camera.m_Model *= rotate(mat4{1.0f}, static_cast<f32>(45.0_deg * Time::m_Delta), vec3(0.0f, 1.0f, 0.0f));
|
camera.m_Model *= rotate(mat4{1.0f}, static_cast<f32>(45.0_deg * Time::m_Delta), vec3(0.0f, 1.0f, 0.0f));
|
||||||
ubo->Write(0, sizeof camera, &camera);
|
ubo->Write(0, sizeof camera, &camera);
|
||||||
|
|
||||||
auto& currentFrame = device.GetNextFrame();
|
auto ¤tFrame = device.GetNextFrame();
|
||||||
|
|
||||||
prevSwapchainSize = swapchainSize;
|
prevSwapchainSize = swapchainSize;
|
||||||
swapchainSize = currentFrame.m_SwapchainSize;
|
swapchainSize = currentFrame.m_SwapchainSize;
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,14 @@ add_shader(model_render "shader/diffuse_irradiance.cs.hlsl")
|
||||||
add_shader(model_render "shader/prefilter.cs.hlsl")
|
add_shader(model_render "shader/prefilter.cs.hlsl")
|
||||||
add_shader(model_render "shader/brdf_lut.cs.hlsl")
|
add_shader(model_render "shader/brdf_lut.cs.hlsl")
|
||||||
|
|
||||||
|
add_shader(model_render "shader/slang/background.slang")
|
||||||
|
add_shader(model_render "shader/slang/bindless.slang")
|
||||||
|
add_shader(model_render "shader/slang/common_structs.slang")
|
||||||
|
add_shader(model_render "shader/slang/environment.slang")
|
||||||
|
add_shader(model_render "shader/slang/eqrect_to_cube.slang")
|
||||||
|
add_shader(model_render "shader/slang/ibl_common.slang")
|
||||||
|
add_shader(model_render "shader/slang/model.slang")
|
||||||
|
|
||||||
target_link_libraries(model_render PRIVATE aster_core)
|
target_link_libraries(model_render PRIVATE aster_core)
|
||||||
target_link_libraries(model_render PRIVATE util_helper)
|
target_link_libraries(model_render PRIVATE util_helper)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
|
|
||||||
#include "aster/systems/commit_manager.h"
|
#include "aster/systems/commit_manager.h"
|
||||||
#include "aster/systems/resource_manager.h"
|
#include "aster/systems/device.h"
|
||||||
|
|
||||||
#include <EASTL/fixed_vector.h>
|
#include <EASTL/fixed_vector.h>
|
||||||
#include <EASTL/hash_map.h>
|
#include <EASTL/hash_map.h>
|
||||||
|
|
@ -37,10 +37,20 @@ VectorToVec4(const std::vector<double> &vec)
|
||||||
return vec4{0.0f};
|
return vec4{0.0f};
|
||||||
}
|
}
|
||||||
assert(vec.size() == 4);
|
assert(vec.size() == 4);
|
||||||
|
|
||||||
return {vec[0], vec[1], vec[2], vec[3]};
|
return {vec[0], vec[1], vec[2], vec[3]};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vec4
|
||||||
|
VectorToVec4(const std::vector<double> &vec, float w)
|
||||||
|
{
|
||||||
|
if (vec.empty())
|
||||||
|
{
|
||||||
|
return vec4{0.0f};
|
||||||
|
}
|
||||||
|
assert(vec.size() == 3);
|
||||||
|
return {vec[0], vec[1], vec[2], w};
|
||||||
|
}
|
||||||
|
|
||||||
vec3
|
vec3
|
||||||
VectorToVec3(const std::vector<double> &vec)
|
VectorToVec3(const std::vector<double> &vec)
|
||||||
{
|
{
|
||||||
|
|
@ -65,7 +75,7 @@ AssetLoader::LoadHdrImage(cstr path, cstr name) const
|
||||||
u32 width = static_cast<u32>(x);
|
u32 width = static_cast<u32>(x);
|
||||||
u32 height = static_cast<u32>(y);
|
u32 height = static_cast<u32>(y);
|
||||||
|
|
||||||
auto texture = m_ResourceManager->CombinedImageViews().CreateTexture2D<TextureView>({
|
auto texture = m_Device->CreateTexture2DWithView({
|
||||||
.m_Format = vk::Format::eR32G32B32A32Sfloat,
|
.m_Format = vk::Format::eR32G32B32A32Sfloat,
|
||||||
.m_Extent = {width, height},
|
.m_Extent = {width, height},
|
||||||
.m_Name = path,
|
.m_Name = path,
|
||||||
|
|
@ -74,36 +84,7 @@ AssetLoader::LoadHdrImage(cstr path, cstr name) const
|
||||||
.m_IsStorage = false,
|
.m_IsStorage = false,
|
||||||
});
|
});
|
||||||
|
|
||||||
auto *pDevice = m_CommitManager->m_Device;
|
|
||||||
|
|
||||||
auto stagingBuffer =
|
|
||||||
m_ResourceManager->Buffers().CreateStagingBuffer((sizeof *data) * x * y * 4, "HDR Staging Buffer");
|
|
||||||
stagingBuffer->Write(0, stagingBuffer->m_Size, data);
|
|
||||||
|
|
||||||
stbi_image_free(data);
|
|
||||||
|
|
||||||
#pragma region Setup Copy/Sync primitives
|
#pragma region Setup Copy/Sync primitives
|
||||||
vk::BufferImageCopy2 copyRegion = {
|
|
||||||
.bufferOffset = 0,
|
|
||||||
.bufferRowLength = width,
|
|
||||||
.bufferImageHeight = height,
|
|
||||||
.imageSubresource =
|
|
||||||
{
|
|
||||||
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
|
||||||
.mipLevel = 0,
|
|
||||||
.baseArrayLayer = 0,
|
|
||||||
.layerCount = 1,
|
|
||||||
},
|
|
||||||
.imageOffset = {0, 0, 0},
|
|
||||||
.imageExtent = texture->m_Extent,
|
|
||||||
};
|
|
||||||
vk::CopyBufferToImageInfo2 stagingInfo = {
|
|
||||||
.srcBuffer = stagingBuffer->m_Buffer,
|
|
||||||
.dstImage = texture->GetImage(),
|
|
||||||
.dstImageLayout = vk::ImageLayout::eTransferDstOptimal,
|
|
||||||
.regionCount = 1,
|
|
||||||
.pRegions = ©Region,
|
|
||||||
};
|
|
||||||
vk::ImageMemoryBarrier2 readyToStageBarrier = {
|
vk::ImageMemoryBarrier2 readyToStageBarrier = {
|
||||||
.srcStageMask = vk::PipelineStageFlagBits2::eAllCommands,
|
.srcStageMask = vk::PipelineStageFlagBits2::eAllCommands,
|
||||||
.srcAccessMask = vk::AccessFlagBits2::eNone,
|
.srcAccessMask = vk::AccessFlagBits2::eNone,
|
||||||
|
|
@ -136,8 +117,8 @@ AssetLoader::LoadHdrImage(cstr path, cstr name) const
|
||||||
.dstAccessMask = vk::AccessFlagBits2::eShaderRead,
|
.dstAccessMask = vk::AccessFlagBits2::eShaderRead,
|
||||||
.oldLayout = vk::ImageLayout::eTransferDstOptimal,
|
.oldLayout = vk::ImageLayout::eTransferDstOptimal,
|
||||||
.newLayout = vk::ImageLayout::eShaderReadOnlyOptimal,
|
.newLayout = vk::ImageLayout::eShaderReadOnlyOptimal,
|
||||||
.srcQueueFamilyIndex = m_TransferQueueIndex,
|
.srcQueueFamilyIndex = m_Device->m_TransferQueueFamily,
|
||||||
.dstQueueFamilyIndex = m_GraphicsQueueIndex,
|
.dstQueueFamilyIndex = m_Device->m_PrimaryQueueFamily,
|
||||||
.image = texture->GetImage(),
|
.image = texture->GetImage(),
|
||||||
.subresourceRange =
|
.subresourceRange =
|
||||||
{
|
{
|
||||||
|
|
@ -156,49 +137,31 @@ AssetLoader::LoadHdrImage(cstr path, cstr name) const
|
||||||
};
|
};
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
|
|
||||||
AbortIfFailed(m_CommandBuffer.begin(&OneTimeCmdBeginInfo));
|
auto context = m_Device->CreateTransferContext();
|
||||||
|
context.Begin();
|
||||||
|
|
||||||
#if !defined(ASTER_NDEBUG)
|
|
||||||
StackString<128> loadActionName = "Load: ";
|
StackString<128> loadActionName = "Load: ";
|
||||||
loadActionName += name ? name : path;
|
loadActionName += name ? name : path;
|
||||||
vk::DebugUtilsLabelEXT debugLabel = {
|
context.BeginDebugRegion(loadActionName.c_str());
|
||||||
.pLabelName = loadActionName.c_str(),
|
|
||||||
.color = std::array{1.0f, 1.0f, 1.0f, 1.0f},
|
|
||||||
};
|
|
||||||
m_CommandBuffer.beginDebugUtilsLabelEXT(&debugLabel);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
m_CommandBuffer.pipelineBarrier2(&readyToStageDependency);
|
context.Dependency(readyToStageDependency);
|
||||||
m_CommandBuffer.copyBufferToImage2(&stagingInfo);
|
context.UploadTexture(texture->m_Image, {reinterpret_cast<u8 *>(data), (sizeof *data) * x * y * 4});
|
||||||
m_CommandBuffer.pipelineBarrier2(&postStagingDependency);
|
context.Dependency(postStagingDependency);
|
||||||
|
|
||||||
#if !defined(ASTER_NDEBUG)
|
context.EndDebugRegion();
|
||||||
m_CommandBuffer.endDebugUtilsLabelEXT();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
AbortIfFailed(m_CommandBuffer.end());
|
context.End();
|
||||||
|
|
||||||
vk::SubmitInfo submitInfo = {
|
auto rcpt = m_Device->Submit(context);
|
||||||
.waitSemaphoreCount = 0,
|
stbi_image_free(data);
|
||||||
.pWaitDstStageMask = nullptr,
|
|
||||||
.commandBufferCount = 1,
|
|
||||||
.pCommandBuffers = &m_CommandBuffer,
|
|
||||||
};
|
|
||||||
|
|
||||||
vk::Fence fence;
|
m_Device->WaitOn(rcpt);
|
||||||
vk::FenceCreateInfo fenceCreateInfo = {};
|
|
||||||
AbortIfFailed(pDevice->m_Device.createFence(&fenceCreateInfo, nullptr, &fence));
|
|
||||||
AbortIfFailed(m_TransferQueue.submit(1, &submitInfo, fence));
|
|
||||||
AbortIfFailed(pDevice->m_Device.waitForFences(1, &fence, true, MaxValue<u32>));
|
|
||||||
pDevice->m_Device.destroy(fence, nullptr);
|
|
||||||
|
|
||||||
AbortIfFailed(pDevice->m_Device.resetCommandPool(m_CommandPool, {}));
|
|
||||||
|
|
||||||
return texture;
|
return texture;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
GenerateMipMaps(vk::CommandBuffer commandBuffer, const Ref<Texture> &texture, vk::ImageLayout initialLayout,
|
GenerateMipMaps(systems::TransferContext &context, const Ref<Texture> &texture, vk::ImageLayout initialLayout,
|
||||||
vk::ImageLayout finalLayout, vk::PipelineStageFlags2 prevStage, vk::PipelineStageFlags2 finalStage)
|
vk::ImageLayout finalLayout, vk::PipelineStageFlags2 prevStage, vk::PipelineStageFlags2 finalStage)
|
||||||
{
|
{
|
||||||
#if !defined(ASTER_NDEBUG)
|
#if !defined(ASTER_NDEBUG)
|
||||||
|
|
@ -206,7 +169,7 @@ GenerateMipMaps(vk::CommandBuffer commandBuffer, const Ref<Texture> &texture, vk
|
||||||
.pLabelName = "Generate Mipmap",
|
.pLabelName = "Generate Mipmap",
|
||||||
.color = std::array{0.9f, 0.9f, 0.9f, 1.0f},
|
.color = std::array{0.9f, 0.9f, 0.9f, 1.0f},
|
||||||
};
|
};
|
||||||
commandBuffer.beginDebugUtilsLabelEXT(&label);
|
context.BeginDebugRegion("Generate MipMap", {0.9, 0.9, 0.9, 1.0});
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
vk::ImageMemoryBarrier2 imageStartBarrier = {
|
vk::ImageMemoryBarrier2 imageStartBarrier = {
|
||||||
|
|
@ -329,7 +292,7 @@ GenerateMipMaps(vk::CommandBuffer commandBuffer, const Ref<Texture> &texture, vk
|
||||||
|
|
||||||
// Mip Mapping
|
// Mip Mapping
|
||||||
|
|
||||||
commandBuffer.pipelineBarrier2(&imageStartDependency);
|
context.Dependency(imageStartDependency);
|
||||||
|
|
||||||
i32 prevMipWidth = static_cast<i32>(texture->m_Extent.width);
|
i32 prevMipWidth = static_cast<i32>(texture->m_Extent.width);
|
||||||
i32 prevMipHeight = static_cast<i32>(texture->m_Extent.height);
|
i32 prevMipHeight = static_cast<i32>(texture->m_Extent.height);
|
||||||
|
|
@ -354,21 +317,21 @@ GenerateMipMaps(vk::CommandBuffer commandBuffer, const Ref<Texture> &texture, vk
|
||||||
|
|
||||||
nextMipBarrier.subresourceRange.baseMipLevel = currentMipLevel;
|
nextMipBarrier.subresourceRange.baseMipLevel = currentMipLevel;
|
||||||
|
|
||||||
commandBuffer.blitImage2(&mipBlitInfo);
|
context.Blit(mipBlitInfo);
|
||||||
commandBuffer.pipelineBarrier2(&interMipDependency);
|
context.Dependency(interMipDependency);
|
||||||
|
|
||||||
prevMipHeight = currentMipHeight;
|
prevMipHeight = currentMipHeight;
|
||||||
prevMipWidth = currentMipWidth;
|
prevMipWidth = currentMipWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
commandBuffer.pipelineBarrier2(&imageReadyDependency);
|
context.Dependency(imageReadyDependency);
|
||||||
#if !defined(ASTER_NDEBUG)
|
#if !defined(ASTER_NDEBUG)
|
||||||
commandBuffer.endDebugUtilsLabelEXT();
|
context.EndDebugRegion();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
std::tuple<systems::ResId<TextureView>, Ref<StagingBuffer>>
|
systems::ResId<TextureView>
|
||||||
AssetLoader::LoadImageToGpu(tinygltf::Image *image, bool isSrgb, cstr name) const
|
AssetLoader::LoadImageToGpu(systems::TransferContext &context, tinygltf::Image *image, bool isSrgb, cstr name) const
|
||||||
{
|
{
|
||||||
// TODO(Something not loading properly).
|
// TODO(Something not loading properly).
|
||||||
|
|
||||||
|
|
@ -381,14 +344,12 @@ AssetLoader::LoadImageToGpu(tinygltf::Image *image, bool isSrgb, cstr name) cons
|
||||||
auto assignedName = nullptr;
|
auto assignedName = nullptr;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
u32 height = static_cast<u32>(image->height);
|
u32 height = static_cast<u32>(image->height);
|
||||||
u32 width = static_cast<u32>(image->width);
|
u32 width = static_cast<u32>(image->width);
|
||||||
|
|
||||||
vk::Format imageFormat = isSrgb ? vk::Format::eR8G8B8A8Srgb : vk::Format::eR8G8B8A8Unorm;
|
vk::Format imageFormat = isSrgb ? vk::Format::eR8G8B8A8Srgb : vk::Format::eR8G8B8A8Unorm;
|
||||||
|
|
||||||
usize byteSize = image->image.size();
|
auto texture = m_Device->CreateTexture2D<Texture>({
|
||||||
auto texture = m_ResourceManager->Images().CreateTexture2D<Texture>({
|
|
||||||
.m_Format = imageFormat,
|
.m_Format = imageFormat,
|
||||||
.m_Extent = {width, height},
|
.m_Extent = {width, height},
|
||||||
.m_Name = assignedName,
|
.m_Name = assignedName,
|
||||||
|
|
@ -397,18 +358,9 @@ AssetLoader::LoadImageToGpu(tinygltf::Image *image, bool isSrgb, cstr name) cons
|
||||||
.m_IsStorage = false,
|
.m_IsStorage = false,
|
||||||
});
|
});
|
||||||
|
|
||||||
auto stagingBuffer = m_ResourceManager->Buffers().CreateStagingBuffer(byteSize);
|
|
||||||
stagingBuffer->Write(0, byteSize, image->image.data());
|
|
||||||
|
|
||||||
#if !defined(ASTER_NDEBUG)
|
|
||||||
StackString<128> loadActionName = "Load: ";
|
StackString<128> loadActionName = "Load: ";
|
||||||
loadActionName += assignedName;
|
loadActionName += assignedName;
|
||||||
vk::DebugUtilsLabelEXT debugLabel = {
|
context.BeginDebugRegion(loadActionName.c_str());
|
||||||
.pLabelName = loadActionName.c_str(),
|
|
||||||
.color = std::array{1.0f, 1.0f, 1.0f, 1.0f},
|
|
||||||
};
|
|
||||||
m_CommandBuffer.beginDebugUtilsLabelEXT(&debugLabel);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#pragma region Barriers and Blits
|
#pragma region Barriers and Blits
|
||||||
|
|
||||||
|
|
@ -445,8 +397,8 @@ AssetLoader::LoadImageToGpu(tinygltf::Image *image, bool isSrgb, cstr name) cons
|
||||||
.dstAccessMask = vk::AccessFlagBits2::eTransferRead,
|
.dstAccessMask = vk::AccessFlagBits2::eTransferRead,
|
||||||
.oldLayout = vk::ImageLayout::eTransferDstOptimal,
|
.oldLayout = vk::ImageLayout::eTransferDstOptimal,
|
||||||
.newLayout = vk::ImageLayout::eTransferSrcOptimal,
|
.newLayout = vk::ImageLayout::eTransferSrcOptimal,
|
||||||
.srcQueueFamilyIndex = m_TransferQueueIndex,
|
.srcQueueFamilyIndex = m_Device->m_TransferQueueFamily,
|
||||||
.dstQueueFamilyIndex = m_GraphicsQueueIndex,
|
.dstQueueFamilyIndex = m_Device->m_PrimaryQueueFamily,
|
||||||
.image = texture->m_Image,
|
.image = texture->m_Image,
|
||||||
.subresourceRange =
|
.subresourceRange =
|
||||||
{
|
{
|
||||||
|
|
@ -463,45 +415,22 @@ AssetLoader::LoadImageToGpu(tinygltf::Image *image, bool isSrgb, cstr name) cons
|
||||||
.pImageMemoryBarriers = &postStagingBarrier,
|
.pImageMemoryBarriers = &postStagingBarrier,
|
||||||
};
|
};
|
||||||
|
|
||||||
vk::BufferImageCopy2 imageCopy = {
|
|
||||||
.bufferOffset = 0,
|
|
||||||
.bufferRowLength = static_cast<u32>(image->width),
|
|
||||||
.bufferImageHeight = static_cast<u32>(image->height),
|
|
||||||
.imageSubresource =
|
|
||||||
{
|
|
||||||
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
|
||||||
.mipLevel = 0,
|
|
||||||
.baseArrayLayer = 0,
|
|
||||||
.layerCount = 1,
|
|
||||||
},
|
|
||||||
.imageOffset = {},
|
|
||||||
.imageExtent = texture->m_Extent,
|
|
||||||
};
|
|
||||||
vk::CopyBufferToImageInfo2 stagingCopyInfo = {
|
|
||||||
.srcBuffer = stagingBuffer->m_Buffer,
|
|
||||||
.dstImage = texture->m_Image,
|
|
||||||
.dstImageLayout = vk::ImageLayout::eTransferDstOptimal,
|
|
||||||
.regionCount = 1,
|
|
||||||
.pRegions = &imageCopy,
|
|
||||||
};
|
|
||||||
|
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
|
|
||||||
m_CommandBuffer.pipelineBarrier2(&imageStartDependency);
|
context.Dependency(imageStartDependency);
|
||||||
m_CommandBuffer.copyBufferToImage2(&stagingCopyInfo);
|
context.UploadTexture(texture, {image->image.data(), image->image.size()});
|
||||||
m_CommandBuffer.pipelineBarrier2(&postStagingDependency);
|
context.Dependency(postStagingDependency);
|
||||||
|
|
||||||
GenerateMipMaps(m_CommandBuffer, texture, vk::ImageLayout::eTransferSrcOptimal,
|
GenerateMipMaps(context, texture, vk::ImageLayout::eTransferSrcOptimal, vk::ImageLayout::eShaderReadOnlyOptimal);
|
||||||
vk::ImageLayout::eShaderReadOnlyOptimal);
|
|
||||||
|
|
||||||
#if !defined(ASTER_NDEBUG)
|
#if !defined(ASTER_NDEBUG)
|
||||||
m_CommandBuffer.endDebugUtilsLabelEXT();
|
context.EndDebugRegion();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
auto textureView = m_ResourceManager->Views().CreateView<TextureView>(
|
auto textureView = m_Device->CreateView<TextureView>(
|
||||||
{.m_Image = texture, .m_Name = image->name.data(), .m_AspectMask = vk::ImageAspectFlagBits::eColor});
|
{.m_Image = texture, .m_Name = image->name.data(), .m_AspectMask = vk::ImageAspectFlagBits::eColor});
|
||||||
|
|
||||||
return {m_CommitManager->CommitTexture(textureView), stagingBuffer};
|
return m_Device->m_CommitManager->CommitTexture(textureView);
|
||||||
}
|
}
|
||||||
|
|
||||||
Model
|
Model
|
||||||
|
|
@ -511,8 +440,6 @@ AssetLoader::LoadModelToGpu(cstr path, cstr name)
|
||||||
tinygltf::Model model;
|
tinygltf::Model model;
|
||||||
tinygltf::TinyGLTF loader;
|
tinygltf::TinyGLTF loader;
|
||||||
|
|
||||||
const Device *pDevice = m_CommitManager->m_Device;
|
|
||||||
|
|
||||||
const auto fsPath = fs::absolute(path);
|
const auto fsPath = fs::absolute(path);
|
||||||
const auto ext = fsPath.extension();
|
const auto ext = fsPath.extension();
|
||||||
if (ext == GLTF_ASCII_FILE_EXTENSION)
|
if (ext == GLTF_ASCII_FILE_EXTENSION)
|
||||||
|
|
@ -536,19 +463,13 @@ AssetLoader::LoadModelToGpu(cstr path, cstr name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AbortIfFailed(m_CommandBuffer.begin(&OneTimeCmdBeginInfo));
|
auto context = m_Device->CreateTransferContext();
|
||||||
|
|
||||||
|
context.Begin();
|
||||||
|
|
||||||
#if !defined(ASTER_NDEBUG)
|
|
||||||
StackString<128> loadActionName = "Load: ";
|
StackString<128> loadActionName = "Load: ";
|
||||||
loadActionName += name ? name : path;
|
loadActionName += name ? name : path;
|
||||||
vk::DebugUtilsLabelEXT debugLabel = {
|
context.BeginDebugRegion(loadActionName.c_str());
|
||||||
.pLabelName = loadActionName.c_str(),
|
|
||||||
.color = std::array{1.0f, 1.0f, 1.0f, 1.0f},
|
|
||||||
};
|
|
||||||
m_CommandBuffer.beginDebugUtilsLabelEXT(&debugLabel);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
eastl::vector<Ref<StagingBuffer>> stagingBuffers;
|
|
||||||
|
|
||||||
eastl::hash_map<i32, systems::ResId<TextureView>> textureHandleMap;
|
eastl::hash_map<i32, systems::ResId<TextureView>> textureHandleMap;
|
||||||
|
|
||||||
|
|
@ -558,7 +479,7 @@ AssetLoader::LoadModelToGpu(cstr path, cstr name)
|
||||||
if (!model.materials.empty())
|
if (!model.materials.empty())
|
||||||
{
|
{
|
||||||
// TODO("Something broken on load here.");
|
// TODO("Something broken on load here.");
|
||||||
auto getTextureHandle = [this, &textureHandleMap, &stagingBuffers,
|
auto getTextureHandle = [this, &context, &textureHandleMap,
|
||||||
&model](i32 index, const bool isSrgb) -> systems::ResId<TextureView> {
|
&model](i32 index, const bool isSrgb) -> systems::ResId<TextureView> {
|
||||||
if (index < 0)
|
if (index < 0)
|
||||||
{
|
{
|
||||||
|
|
@ -571,9 +492,8 @@ AssetLoader::LoadModelToGpu(cstr path, cstr name)
|
||||||
|
|
||||||
const auto &texture = model.textures[index];
|
const auto &texture = model.textures[index];
|
||||||
auto *image = &model.images[texture.source];
|
auto *image = &model.images[texture.source];
|
||||||
auto [handle, staging] = LoadImageToGpu(image, isSrgb, texture.name.empty() ? nullptr : texture.name.c_str());
|
auto handle = LoadImageToGpu(context, image, isSrgb, texture.name.empty() ? nullptr : texture.name.c_str());
|
||||||
textureHandleMap.emplace(index, handle);
|
textureHandleMap.emplace(index, handle);
|
||||||
stagingBuffers.emplace_back(std::move(staging));
|
|
||||||
return handle;
|
return handle;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -582,29 +502,23 @@ AssetLoader::LoadModelToGpu(cstr path, cstr name)
|
||||||
{
|
{
|
||||||
materials.push_back({
|
materials.push_back({
|
||||||
.m_AlbedoFactor = VectorToVec4(material.pbrMetallicRoughness.baseColorFactor),
|
.m_AlbedoFactor = VectorToVec4(material.pbrMetallicRoughness.baseColorFactor),
|
||||||
.m_EmissionFactor = VectorToVec3(material.emissiveFactor),
|
.m_EmissionFactor = VectorToVec4(material.emissiveFactor, 0.0f),
|
||||||
.m_MetalFactor = static_cast<f32>(material.pbrMetallicRoughness.metallicFactor),
|
|
||||||
.m_RoughFactor = static_cast<f32>(material.pbrMetallicRoughness.roughnessFactor),
|
|
||||||
.m_AlbedoTex = getTextureHandle(material.pbrMetallicRoughness.baseColorTexture.index, true),
|
.m_AlbedoTex = getTextureHandle(material.pbrMetallicRoughness.baseColorTexture.index, true),
|
||||||
.m_NormalTex = getTextureHandle(material.normalTexture.index, false),
|
.m_NormalTex = getTextureHandle(material.normalTexture.index, false),
|
||||||
.m_MetalRoughTex =
|
.m_MetalRoughTex =
|
||||||
getTextureHandle(material.pbrMetallicRoughness.metallicRoughnessTexture.index, false),
|
getTextureHandle(material.pbrMetallicRoughness.metallicRoughnessTexture.index, false),
|
||||||
.m_OcclusionTex = getTextureHandle(material.occlusionTexture.index, false),
|
.m_OcclusionTex = getTextureHandle(material.occlusionTexture.index, false),
|
||||||
.m_EmissionTex = getTextureHandle(material.emissiveTexture.index, true),
|
.m_EmissionTex = getTextureHandle(material.emissiveTexture.index, true),
|
||||||
|
.m_MetalFactor = static_cast<f32>(material.pbrMetallicRoughness.metallicFactor),
|
||||||
|
.m_RoughFactor = static_cast<f32>(material.pbrMetallicRoughness.roughnessFactor),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
usize materialsByteSize = materials.size() * sizeof materials[0];
|
usize materialsByteSize = materials.size() * sizeof materials[0];
|
||||||
auto materialsBuffer = m_ResourceManager->Buffers().CreateStorageBuffer(materialsByteSize, name);
|
auto materialsBuffer = m_Device->CreateStorageBuffer(materialsByteSize, name);
|
||||||
materialsHandle = m_CommitManager->CommitBuffer(materialsBuffer);
|
materialsHandle = m_Device->m_CommitManager->CommitBuffer(materialsBuffer);
|
||||||
|
|
||||||
auto materialStaging = m_ResourceManager->Buffers().CreateStagingBuffer(materialsByteSize);
|
context.UploadBuffer(materialsBuffer, materials);
|
||||||
materialStaging->Write(0, materialsByteSize, materials.data());
|
|
||||||
|
|
||||||
vk::BufferCopy bufferCopy = {.srcOffset = 0, .dstOffset = 0, .size = materialsByteSize};
|
|
||||||
m_CommandBuffer.copyBuffer(materialStaging->m_Buffer, materialsBuffer->m_Buffer, 1, &bufferCopy);
|
|
||||||
|
|
||||||
stagingBuffers.emplace_back(std::move(materialStaging));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Mesh reordering based on nodes AND OR meshoptimizer
|
// TODO: Mesh reordering based on nodes AND OR meshoptimizer
|
||||||
|
|
@ -887,63 +801,37 @@ AssetLoader::LoadModelToGpu(cstr path, cstr name)
|
||||||
|
|
||||||
nodes.Update();
|
nodes.Update();
|
||||||
|
|
||||||
auto nodeBuffer = m_ResourceManager->Buffers().CreateStorageBuffer(nodes.GetGlobalTransformByteSize());
|
auto nodeBuffer = m_Device->CreateStorageBuffer(nodes.GetGlobalTransformByteSize());
|
||||||
nodeBuffer->Write(0, nodes.GetGlobalTransformByteSize(), nodes.GetGlobalTransformPtr());
|
nodeBuffer->Write(0, nodes.GetGlobalTransformByteSize(), nodes.GetGlobalTransformPtr());
|
||||||
systems::ResId<Buffer> nodeHandle = m_CommitManager->CommitBuffer(nodeBuffer);
|
systems::ResId<Buffer> nodeHandle = m_Device->m_CommitManager->CommitBuffer(nodeBuffer);
|
||||||
|
|
||||||
#pragma region Staging / Transfer / Uploads
|
#pragma region Staging / Transfer / Uploads
|
||||||
systems::ResId<Buffer> positionBufferHandle = systems::ResId<Buffer>::Null();
|
systems::ResId<Buffer> positionBufferHandle = systems::ResId<Buffer>::Null();
|
||||||
systems::ResId<Buffer> vertexDataHandle = systems::ResId<Buffer>::Null();
|
systems::ResId<Buffer> vertexDataHandle = systems::ResId<Buffer>::Null();
|
||||||
Ref<Buffer> indexBuffer;
|
Ref<IndexBuffer> indexBuffer;
|
||||||
|
|
||||||
{
|
auto positionBuffer = m_Device->CreateStorageBuffer(vertexPositions.size() * sizeof vertexPositions[0]);
|
||||||
auto uploadBufferData = [cmd = this->m_CommandBuffer, &stagingBuffers, resMan = this->m_ResourceManager,
|
positionBufferHandle = m_Device->m_CommitManager->CommitBuffer(positionBuffer);
|
||||||
pDevice](const Ref<Buffer> &buffer, const void *data) {
|
context.UploadBuffer(positionBuffer, vertexPositions);
|
||||||
const vk::BufferCopy bufferCopy = {.srcOffset = 0, .dstOffset = 0, .size = buffer->m_Size};
|
|
||||||
auto stagingBuffer = resMan->Buffers().CreateStagingBuffer(bufferCopy.size);
|
|
||||||
stagingBuffer->Write(0, bufferCopy.size, data);
|
|
||||||
cmd.copyBuffer(stagingBuffer->m_Buffer, buffer->m_Buffer, 1, &bufferCopy);
|
|
||||||
stagingBuffers.emplace_back(std::move(stagingBuffer));
|
|
||||||
};
|
|
||||||
|
|
||||||
auto positionBuffer =
|
auto vertexDataBuffer = m_Device->CreateStorageBuffer(vertexData.size() * sizeof vertexData[0]);
|
||||||
m_ResourceManager->Buffers().CreateStorageBuffer(vertexPositions.size() * sizeof vertexPositions[0]);
|
vertexDataHandle = m_Device->m_CommitManager->CommitBuffer(vertexDataBuffer);
|
||||||
positionBufferHandle = m_CommitManager->CommitBuffer(positionBuffer);
|
context.UploadBuffer(vertexDataBuffer, vertexData);
|
||||||
uploadBufferData(positionBuffer, vertexPositions.data());
|
|
||||||
|
|
||||||
auto vertexDataBuffer =
|
|
||||||
m_ResourceManager->Buffers().CreateStorageBuffer(vertexData.size() * sizeof vertexData[0]);
|
|
||||||
vertexDataHandle = m_CommitManager->CommitBuffer(vertexDataBuffer);
|
|
||||||
uploadBufferData(vertexDataBuffer, vertexData.data());
|
|
||||||
|
|
||||||
// TODO: Index buffer needs to be separated.
|
// TODO: Index buffer needs to be separated.
|
||||||
indexBuffer =
|
indexBuffer = systems::CastBuffer<IndexBuffer>(
|
||||||
m_ResourceManager->Buffers().CreateStorageBuffer(indices.size() * sizeof indices[0], "Index Buffer");
|
m_Device->CreateIndexBuffer(indices.size() * sizeof indices[0], "Index Buffer"));
|
||||||
uploadBufferData(indexBuffer, indices.data());
|
context.UploadBuffer(indexBuffer, indices);
|
||||||
}
|
|
||||||
|
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
|
|
||||||
#if !defined(ASTER_NDEBUG)
|
#if !defined(ASTER_NDEBUG)
|
||||||
m_CommandBuffer.endDebugUtilsLabelEXT();
|
context.EndDebugRegion();
|
||||||
#endif
|
#endif
|
||||||
AbortIfFailed(m_CommandBuffer.end());
|
context.End();
|
||||||
|
|
||||||
vk::SubmitInfo submitInfo = {
|
auto rcpt = m_Device->Submit(context);
|
||||||
.waitSemaphoreCount = 0,
|
m_Device->WaitOn(rcpt);
|
||||||
.pWaitDstStageMask = nullptr,
|
|
||||||
.commandBufferCount = 1,
|
|
||||||
.pCommandBuffers = &m_CommandBuffer,
|
|
||||||
};
|
|
||||||
|
|
||||||
vk::Fence fence;
|
|
||||||
vk::FenceCreateInfo fenceCreateInfo = {};
|
|
||||||
AbortIfFailed(pDevice->m_Device.createFence(&fenceCreateInfo, nullptr, &fence));
|
|
||||||
AbortIfFailed(m_TransferQueue.submit(1, &submitInfo, fence));
|
|
||||||
AbortIfFailed(pDevice->m_Device.waitForFences(1, &fence, true, MaxValue<u32>));
|
|
||||||
pDevice->m_Device.destroy(fence, nullptr);
|
|
||||||
|
|
||||||
AbortIfFailed(pDevice->m_Device.resetCommandPool(m_CommandPool, {}));
|
|
||||||
|
|
||||||
Model::ModelHandles handles = {
|
Model::ModelHandles handles = {
|
||||||
.m_VertexPositionHandle = positionBufferHandle,
|
.m_VertexPositionHandle = positionBufferHandle,
|
||||||
|
|
@ -961,15 +849,13 @@ AssetLoader::LoadModelToGpu(cstr path, cstr name)
|
||||||
}
|
}
|
||||||
|
|
||||||
return Model{
|
return Model{
|
||||||
m_CommitManager, textureHandles, std::move(nodes), nodeBuffer, handles, indexBuffer, meshPrimitives,
|
textureHandles, std::move(nodes), nodeBuffer, handles, indexBuffer, meshPrimitives,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
Model::Model(systems::CommitManager *resourceManager, eastl::vector<systems::ResId<TextureView>> &textureHandles,
|
Model::Model(eastl::vector<systems::ResId<TextureView>> &textureHandles, Nodes &&nodes, Ref<Buffer> nodeBuffer,
|
||||||
Nodes &&nodes, Ref<Buffer> nodeBuffer, ModelHandles &handles, Ref<Buffer> indexBuffer,
|
ModelHandles &handles, Ref<IndexBuffer> indexBuffer, const eastl::vector<MeshPrimitive> &meshPrimitives)
|
||||||
const eastl::vector<MeshPrimitive> &meshPrimitives)
|
: m_TextureHandles(std::move(textureHandles))
|
||||||
: m_ResourceManager(resourceManager)
|
|
||||||
, m_TextureHandles(std::move(textureHandles))
|
|
||||||
, m_Nodes(std::move(nodes))
|
, m_Nodes(std::move(nodes))
|
||||||
, m_Handles(std::move(handles))
|
, m_Handles(std::move(handles))
|
||||||
, m_NodeBuffer(std::move(nodeBuffer))
|
, m_NodeBuffer(std::move(nodeBuffer))
|
||||||
|
|
@ -999,64 +885,7 @@ Model::Update()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AssetLoader::AssetLoader(systems::ResourceManager *resourceManager, systems::CommitManager *commitManager,
|
AssetLoader::AssetLoader(systems::Device &device)
|
||||||
vk::Queue transferQueue, u32 transferQueueIndex, u32 graphicsQueueIndex)
|
: m_Device{&device}
|
||||||
: m_ResourceManager(resourceManager)
|
|
||||||
, m_CommitManager(commitManager)
|
|
||||||
, m_TransferQueue(transferQueue)
|
|
||||||
, m_TransferQueueIndex(transferQueueIndex)
|
|
||||||
, m_GraphicsQueueIndex(graphicsQueueIndex)
|
|
||||||
{
|
|
||||||
const Device *pDevice = commitManager->m_Device;
|
|
||||||
const vk::CommandPoolCreateInfo poolCreateInfo = {
|
|
||||||
.flags = vk::CommandPoolCreateFlagBits::eTransient,
|
|
||||||
.queueFamilyIndex = transferQueueIndex,
|
|
||||||
};
|
|
||||||
AbortIfFailedM(pDevice->m_Device.createCommandPool(&poolCreateInfo, nullptr, &m_CommandPool),
|
|
||||||
"Transfer command pool creation failed.");
|
|
||||||
|
|
||||||
pDevice->SetName(m_CommandPool, "Asset Loader Command Pool");
|
|
||||||
|
|
||||||
const vk::CommandBufferAllocateInfo commandBufferAllocateInfo = {
|
|
||||||
.commandPool = m_CommandPool,
|
|
||||||
.level = vk::CommandBufferLevel::ePrimary,
|
|
||||||
.commandBufferCount = 1,
|
|
||||||
};
|
|
||||||
AbortIfFailed(pDevice->m_Device.allocateCommandBuffers(&commandBufferAllocateInfo, &m_CommandBuffer));
|
|
||||||
|
|
||||||
pDevice->SetName(m_CommandBuffer, "Asset Loader Command Buffer");
|
|
||||||
}
|
|
||||||
|
|
||||||
AssetLoader::~AssetLoader()
|
|
||||||
{
|
|
||||||
if (m_CommitManager && m_CommandPool)
|
|
||||||
{
|
|
||||||
m_CommitManager->m_Device->m_Device.destroy(m_CommandPool, nullptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
AssetLoader::AssetLoader(AssetLoader &&other) noexcept
|
|
||||||
: m_ResourceManager(Take(other.m_ResourceManager))
|
|
||||||
, m_CommitManager(Take(other.m_CommitManager))
|
|
||||||
, m_CommandPool(Take(other.m_CommandPool))
|
|
||||||
, m_CommandBuffer(other.m_CommandBuffer)
|
|
||||||
, m_TransferQueue(other.m_TransferQueue)
|
|
||||||
, m_TransferQueueIndex(other.m_TransferQueueIndex)
|
|
||||||
, m_GraphicsQueueIndex(other.m_GraphicsQueueIndex)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
AssetLoader &
|
|
||||||
AssetLoader::operator=(AssetLoader &&other) noexcept
|
|
||||||
{
|
|
||||||
if (this == &other)
|
|
||||||
return *this;
|
|
||||||
m_ResourceManager = Take(other.m_ResourceManager);
|
|
||||||
m_CommitManager = Take(other.m_CommitManager);
|
|
||||||
m_CommandPool = Take(other.m_CommandPool);
|
|
||||||
m_CommandBuffer = other.m_CommandBuffer;
|
|
||||||
m_TransferQueue = other.m_TransferQueue;
|
|
||||||
m_TransferQueueIndex = other.m_TransferQueueIndex;
|
|
||||||
m_GraphicsQueueIndex = other.m_GraphicsQueueIndex;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
@ -9,14 +9,18 @@
|
||||||
|
|
||||||
#include "aster/core/buffer.h"
|
#include "aster/core/buffer.h"
|
||||||
|
|
||||||
#include "aster/systems/image_manager.h"
|
|
||||||
#include "aster/systems/resource.h"
|
#include "aster/systems/resource.h"
|
||||||
#include "aster/systems/view_manager.h"
|
|
||||||
#include "nodes.h"
|
#include "nodes.h"
|
||||||
#include "tiny_gltf.h"
|
#include "tiny_gltf.h"
|
||||||
|
|
||||||
namespace systems
|
namespace systems
|
||||||
{
|
{
|
||||||
|
class TransferContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace systems
|
||||||
|
{
|
||||||
|
class Device;
|
||||||
class ResourceManager;
|
class ResourceManager;
|
||||||
class SamplerManager;
|
class SamplerManager;
|
||||||
class BufferManager;
|
class BufferManager;
|
||||||
|
|
@ -47,14 +51,14 @@ struct MeshPrimitive
|
||||||
struct Material
|
struct Material
|
||||||
{
|
{
|
||||||
vec4 m_AlbedoFactor; // 16 16
|
vec4 m_AlbedoFactor; // 16 16
|
||||||
vec3 m_EmissionFactor; // 12 28
|
vec4 m_EmissionFactor; // 16 32
|
||||||
f32 m_MetalFactor; // 04 32
|
systems::ResId<TextureView> m_AlbedoTex; // 08 40
|
||||||
f32 m_RoughFactor; // 04 36
|
systems::ResId<TextureView> m_NormalTex; // 08 48
|
||||||
systems::ResId<TextureView> m_AlbedoTex; // 04 40
|
systems::ResId<TextureView> m_MetalRoughTex; // 08 56
|
||||||
systems::ResId<TextureView> m_NormalTex; // 04 44
|
systems::ResId<TextureView> m_OcclusionTex; // 08 64
|
||||||
systems::ResId<TextureView> m_MetalRoughTex; // 04 48
|
systems::ResId<TextureView> m_EmissionTex; // 08 72
|
||||||
systems::ResId<TextureView> m_OcclusionTex; // 04 52
|
f32 m_MetalFactor; // 04 76
|
||||||
systems::ResId<TextureView> m_EmissionTex; // 04 56
|
f32 m_RoughFactor; // 04 80
|
||||||
};
|
};
|
||||||
|
|
||||||
struct VertexData
|
struct VertexData
|
||||||
|
|
@ -67,8 +71,6 @@ struct VertexData
|
||||||
|
|
||||||
struct Model
|
struct Model
|
||||||
{
|
{
|
||||||
systems::CommitManager *m_ResourceManager;
|
|
||||||
|
|
||||||
eastl::vector<systems::ResId<TextureView>> m_TextureHandles;
|
eastl::vector<systems::ResId<TextureView>> m_TextureHandles;
|
||||||
Nodes m_Nodes;
|
Nodes m_Nodes;
|
||||||
|
|
||||||
|
|
@ -81,15 +83,15 @@ struct Model
|
||||||
} m_Handles;
|
} m_Handles;
|
||||||
|
|
||||||
Ref<Buffer> m_NodeBuffer;
|
Ref<Buffer> m_NodeBuffer;
|
||||||
Ref<Buffer> m_IndexBuffer;
|
Ref<IndexBuffer> m_IndexBuffer;
|
||||||
eastl::vector<MeshPrimitive> m_MeshPrimitives;
|
eastl::vector<MeshPrimitive> m_MeshPrimitives;
|
||||||
|
|
||||||
[[nodiscard]] const mat4 &GetModelTransform() const;
|
[[nodiscard]] const mat4 &GetModelTransform() const;
|
||||||
void SetModelTransform(const mat4 &transform);
|
void SetModelTransform(const mat4 &transform);
|
||||||
void Update();
|
void Update();
|
||||||
|
|
||||||
Model(systems::CommitManager *resourceManager, eastl::vector<systems::ResId<TextureView>> &textureHandles,
|
Model(eastl::vector<systems::ResId<TextureView>> &textureHandles,
|
||||||
Nodes &&nodes, Ref<Buffer> nodeBuffer, ModelHandles &handles, Ref<Buffer> indexBuffer,
|
Nodes &&nodes, Ref<Buffer> nodeBuffer, ModelHandles &handles, Ref<IndexBuffer> indexBuffer,
|
||||||
const eastl::vector<MeshPrimitive> &meshPrimitives);
|
const eastl::vector<MeshPrimitive> &meshPrimitives);
|
||||||
~Model() = default;
|
~Model() = default;
|
||||||
|
|
||||||
|
|
@ -102,14 +104,7 @@ struct Model
|
||||||
|
|
||||||
struct AssetLoader
|
struct AssetLoader
|
||||||
{
|
{
|
||||||
systems::ResourceManager *m_ResourceManager;
|
systems::Device *m_Device;
|
||||||
systems::CommitManager *m_CommitManager;
|
|
||||||
|
|
||||||
vk::CommandPool m_CommandPool;
|
|
||||||
vk::CommandBuffer m_CommandBuffer;
|
|
||||||
vk::Queue m_TransferQueue;
|
|
||||||
u32 m_TransferQueueIndex;
|
|
||||||
u32 m_GraphicsQueueIndex;
|
|
||||||
|
|
||||||
Ref<TextureView> LoadHdrImage(cstr path, cstr name = nullptr) const;
|
Ref<TextureView> LoadHdrImage(cstr path, cstr name = nullptr) const;
|
||||||
Model LoadModelToGpu(cstr path, cstr name = nullptr);
|
Model LoadModelToGpu(cstr path, cstr name = nullptr);
|
||||||
|
|
@ -123,40 +118,33 @@ struct AssetLoader
|
||||||
constexpr static auto AJoints0 = "JOINTS_0";
|
constexpr static auto AJoints0 = "JOINTS_0";
|
||||||
constexpr static auto AWeights0 = "WEIGHTS_0";
|
constexpr static auto AWeights0 = "WEIGHTS_0";
|
||||||
|
|
||||||
AssetLoader(systems::ResourceManager *resourceManager, systems::CommitManager *commitManager,
|
explicit AssetLoader(systems::Device &device);
|
||||||
vk::Queue transferQueue, u32 transferQueueIndex, u32 graphicsQueueIndex);
|
|
||||||
~AssetLoader();
|
|
||||||
|
|
||||||
AssetLoader(AssetLoader &&other) noexcept;
|
private:
|
||||||
AssetLoader &operator=(AssetLoader &&other) noexcept;
|
systems::ResId<TextureView>
|
||||||
|
LoadImageToGpu(systems::TransferContext &context, tinygltf::Image *image, bool isSrgb, cstr name = nullptr) const;
|
||||||
DISALLOW_COPY_AND_ASSIGN(AssetLoader);
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::tuple<systems::ResId<TextureView>, Ref<StagingBuffer>>
|
|
||||||
LoadImageToGpu(tinygltf::Image *image, bool isSrgb, cstr name = nullptr) const;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
GenerateMipMaps(vk::CommandBuffer commandBuffer, const Ref<Texture> &textureView, vk::ImageLayout initialLayout,
|
GenerateMipMaps(systems::TransferContext &context, const Ref<Texture> &textureView, vk::ImageLayout initialLayout,
|
||||||
vk::ImageLayout finalLayout, vk::PipelineStageFlags2 prevStage, vk::PipelineStageFlags2 finalStage);
|
vk::ImageLayout finalLayout, vk::PipelineStageFlags2 prevStage, vk::PipelineStageFlags2 finalStage);
|
||||||
|
|
||||||
void
|
void
|
||||||
GenerateMipMaps(vk::CommandBuffer commandBuffer, concepts::ImageRefTo<Texture> auto &texture, vk::ImageLayout initialLayout,
|
GenerateMipMaps(systems::TransferContext &context, concepts::ImageRefTo<Texture> auto &texture,
|
||||||
vk::ImageLayout finalLayout,
|
|
||||||
vk::PipelineStageFlags2 prevStage = vk::PipelineStageFlagBits2::eAllCommands,
|
|
||||||
vk::PipelineStageFlags2 finalStage = vk::PipelineStageFlagBits2::eAllCommands)
|
|
||||||
{
|
|
||||||
GenerateMipMaps(commandBuffer, systems::CastImage<Texture>(texture), initialLayout, finalLayout, prevStage,
|
|
||||||
finalStage);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
GenerateMipMaps(vk::CommandBuffer commandBuffer, concepts::ViewRefTo<Texture> auto &texture,
|
|
||||||
vk::ImageLayout initialLayout, vk::ImageLayout finalLayout,
|
vk::ImageLayout initialLayout, vk::ImageLayout finalLayout,
|
||||||
vk::PipelineStageFlags2 prevStage = vk::PipelineStageFlagBits2::eAllCommands,
|
vk::PipelineStageFlags2 prevStage = vk::PipelineStageFlagBits2::eAllCommands,
|
||||||
vk::PipelineStageFlags2 finalStage = vk::PipelineStageFlagBits2::eAllCommands)
|
vk::PipelineStageFlags2 finalStage = vk::PipelineStageFlagBits2::eAllCommands)
|
||||||
{
|
{
|
||||||
GenerateMipMaps(commandBuffer, systems::CastImage<Texture>(texture->m_Image), initialLayout, finalLayout, prevStage,
|
GenerateMipMaps(context, systems::CastImage<Texture>(texture), initialLayout, finalLayout, prevStage,
|
||||||
|
finalStage);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
GenerateMipMaps(systems::TransferContext &context, concepts::ViewRefTo<Texture> auto &texture,
|
||||||
|
vk::ImageLayout initialLayout, vk::ImageLayout finalLayout,
|
||||||
|
vk::PipelineStageFlags2 prevStage = vk::PipelineStageFlagBits2::eAllCommands,
|
||||||
|
vk::PipelineStageFlags2 finalStage = vk::PipelineStageFlagBits2::eAllCommands)
|
||||||
|
{
|
||||||
|
GenerateMipMaps(context, systems::CastImage<Texture>(texture->m_Image), initialLayout, finalLayout, prevStage,
|
||||||
finalStage);
|
finalStage);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,25 +13,24 @@
|
||||||
#include "pipeline_utils.h"
|
#include "pipeline_utils.h"
|
||||||
|
|
||||||
#include "aster/systems/commit_manager.h"
|
#include "aster/systems/commit_manager.h"
|
||||||
#include "aster/systems/resource_manager.h"
|
#include "aster/systems/device.h"
|
||||||
|
|
||||||
#include <EASTL/fixed_vector.h>
|
#include <EASTL/fixed_vector.h>
|
||||||
#include <EASTL/tuple.h>
|
#include <EASTL/tuple.h>
|
||||||
|
|
||||||
constexpr auto EQUIRECT_TO_CUBE_SHADER_FILE = "shader/eqrect_to_cube.cs.hlsl.spv";
|
constexpr auto EQUIRECT_TO_CUBE_SHADER_FILE = "eqrect_to_cube";
|
||||||
constexpr auto DIFFUSE_IRRADIANCE_SHADER_FILE = "shader/diffuse_irradiance.cs.hlsl.spv";
|
constexpr auto ENVIRONMENT_SHADER_FILE = "environment";
|
||||||
constexpr auto PREFILTER_SHADER_FILE = "shader/prefilter.cs.hlsl.spv";
|
constexpr auto DIFFUSE_IRRADIANCE_ENTRY = "diffuseIrradiance";
|
||||||
constexpr auto BRDF_LUT_SHADER_FILE = "shader/brdf_lut.cs.hlsl.spv";
|
constexpr auto PREFILTER_ENTRY = "prefilter";
|
||||||
|
constexpr auto BRDF_LUT_ENTRY = "brdfLut";
|
||||||
|
|
||||||
Environment
|
Environment
|
||||||
CreateCubeFromHdrEnv(AssetLoader *assetLoader, vk::Queue computeQueue, const u32 cubeSide,
|
CreateCubeFromHdrEnv(AssetLoader &assetLoader, const u32 cubeSide, systems::ResId<TextureView> hdrEnv)
|
||||||
systems::ResId<TextureView> hdrEnv, const cstr name)
|
|
||||||
{
|
{
|
||||||
systems::ResourceManager *resourceManager = assetLoader->m_ResourceManager;
|
systems::Device &device = *assetLoader.m_Device;
|
||||||
systems::CommitManager *commitManager = assetLoader->m_CommitManager;
|
auto *commitManager = device.m_CommitManager.get();
|
||||||
const Device *pDevice = commitManager->m_Device;
|
|
||||||
|
|
||||||
auto skybox = resourceManager->CombinedImageViews().CreateTextureCube<StorageTextureCubeView>({
|
auto skybox = device.CreateTextureCubeWithView<StorageTextureCubeView>({
|
||||||
.m_Format = vk::Format::eR16G16B16A16Sfloat,
|
.m_Format = vk::Format::eR16G16B16A16Sfloat,
|
||||||
.m_Side = cubeSide,
|
.m_Side = cubeSide,
|
||||||
.m_Name = "Skybox",
|
.m_Name = "Skybox",
|
||||||
|
|
@ -43,7 +42,7 @@ CreateCubeFromHdrEnv(AssetLoader *assetLoader, vk::Queue computeQueue, const u32
|
||||||
auto skyboxHandle = commitManager->CommitTexture(skybox);
|
auto skyboxHandle = commitManager->CommitTexture(skybox);
|
||||||
auto skyboxStorageHandle = commitManager->CommitStorageImage(skybox);
|
auto skyboxStorageHandle = commitManager->CommitStorageImage(skybox);
|
||||||
|
|
||||||
auto diffuseIrradiance = resourceManager->CombinedImageViews().CreateTextureCube<StorageTextureCubeView>({
|
auto diffuseIrradiance = device.CreateTextureCubeWithView<StorageTextureCubeView>({
|
||||||
.m_Format = vk::Format::eR16G16B16A16Sfloat,
|
.m_Format = vk::Format::eR16G16B16A16Sfloat,
|
||||||
.m_Side = 64,
|
.m_Side = 64,
|
||||||
.m_Name = "Diffuse Irradiance",
|
.m_Name = "Diffuse Irradiance",
|
||||||
|
|
@ -54,7 +53,7 @@ CreateCubeFromHdrEnv(AssetLoader *assetLoader, vk::Queue computeQueue, const u32
|
||||||
auto diffuseIrradianceHandle = commitManager->CommitTexture(diffuseIrradiance);
|
auto diffuseIrradianceHandle = commitManager->CommitTexture(diffuseIrradiance);
|
||||||
auto diffuseIrradianceStorageHandle = commitManager->CommitStorageImage(diffuseIrradiance);
|
auto diffuseIrradianceStorageHandle = commitManager->CommitStorageImage(diffuseIrradiance);
|
||||||
|
|
||||||
auto prefilterCube = resourceManager->CombinedImageViews().CreateTextureCube<StorageTextureCubeView>({
|
auto prefilterCube = device.CreateTextureCubeWithView<StorageTextureCubeView>({
|
||||||
.m_Format = vk::Format::eR16G16B16A16Sfloat,
|
.m_Format = vk::Format::eR16G16B16A16Sfloat,
|
||||||
.m_Side = cubeSide,
|
.m_Side = cubeSide,
|
||||||
.m_Name = "Prefilter",
|
.m_Name = "Prefilter",
|
||||||
|
|
@ -68,7 +67,7 @@ CreateCubeFromHdrEnv(AssetLoader *assetLoader, vk::Queue computeQueue, const u32
|
||||||
// All non-owning copies.
|
// All non-owning copies.
|
||||||
for (u8 mipLevel = 0; mipLevel < prefilterMipCountMax; ++mipLevel)
|
for (u8 mipLevel = 0; mipLevel < prefilterMipCountMax; ++mipLevel)
|
||||||
{
|
{
|
||||||
auto view = resourceManager->Views().CreateView<StorageTextureCubeView>({
|
auto view = device.CreateView<StorageTextureCubeView>({
|
||||||
.m_Image = systems::CastImage<StorageTextureCube>(prefilterCube->m_Image),
|
.m_Image = systems::CastImage<StorageTextureCube>(prefilterCube->m_Image),
|
||||||
.m_ViewType = vk::ImageViewType::eCube,
|
.m_ViewType = vk::ImageViewType::eCube,
|
||||||
.m_AspectMask = vk::ImageAspectFlagBits::eColor,
|
.m_AspectMask = vk::ImageAspectFlagBits::eColor,
|
||||||
|
|
@ -80,7 +79,7 @@ CreateCubeFromHdrEnv(AssetLoader *assetLoader, vk::Queue computeQueue, const u32
|
||||||
prefilterStorageHandles.push_back(commitManager->CommitStorageImage(view));
|
prefilterStorageHandles.push_back(commitManager->CommitStorageImage(view));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto brdfLut = resourceManager->CombinedImageViews().CreateTexture2D<StorageTextureView>({
|
auto brdfLut = device.CreateTexture2DWithView<StorageTextureView>({
|
||||||
.m_Format = vk::Format::eR16G16Sfloat,
|
.m_Format = vk::Format::eR16G16Sfloat,
|
||||||
.m_Extent = {512, 512},
|
.m_Extent = {512, 512},
|
||||||
.m_Name = "BRDF LUT",
|
.m_Name = "BRDF LUT",
|
||||||
|
|
@ -89,7 +88,7 @@ CreateCubeFromHdrEnv(AssetLoader *assetLoader, vk::Queue computeQueue, const u32
|
||||||
.m_IsStorage = true,
|
.m_IsStorage = true,
|
||||||
});
|
});
|
||||||
|
|
||||||
auto brdfLutSampler = resourceManager->Samplers().CreateSampler({
|
auto brdfLutSampler = device.CreateSampler({
|
||||||
.m_AddressModeU = vk::SamplerAddressMode::eClampToEdge,
|
.m_AddressModeU = vk::SamplerAddressMode::eClampToEdge,
|
||||||
.m_AddressModeV = vk::SamplerAddressMode::eClampToEdge,
|
.m_AddressModeV = vk::SamplerAddressMode::eClampToEdge,
|
||||||
.m_AddressModeW = vk::SamplerAddressMode::eClampToEdge,
|
.m_AddressModeW = vk::SamplerAddressMode::eClampToEdge,
|
||||||
|
|
@ -205,79 +204,119 @@ CreateCubeFromHdrEnv(AssetLoader *assetLoader, vk::Queue computeQueue, const u32
|
||||||
|
|
||||||
#pragma region Pipeline Creation etc
|
#pragma region Pipeline Creation etc
|
||||||
|
|
||||||
vk::PushConstantRange pcr = {
|
// vk::PushConstantRange pcr = {
|
||||||
.stageFlags = vk::ShaderStageFlagBits::eCompute,
|
// .stageFlags = vk::ShaderStageFlagBits::eCompute,
|
||||||
.offset = 0,
|
// .offset = 0,
|
||||||
.size =
|
// .size = static_cast<u32>(
|
||||||
static_cast<u32>(eastl::max(eastl::max(sizeof(SkyboxPushConstants), sizeof(BrdfLutPushConstants)),
|
// 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;
|
||||||
const vk::PipelineLayoutCreateInfo layoutCreateInfo = {
|
// const vk::PipelineLayoutCreateInfo layoutCreateInfo = {
|
||||||
.setLayoutCount = 1,
|
// .setLayoutCount = 1,
|
||||||
.pSetLayouts = &commitManager->GetDescriptorSetLayout(),
|
// .pSetLayouts = &commitManager->GetDescriptorSetLayout(),
|
||||||
.pushConstantRangeCount = 1,
|
// .pushConstantRangeCount = 1,
|
||||||
.pPushConstantRanges = &pcr,
|
// .pPushConstantRanges = &pcr,
|
||||||
};
|
// };
|
||||||
AbortIfFailed(pDevice->m_Device.createPipelineLayout(&layoutCreateInfo, nullptr, &pipelineLayout));
|
// AbortIfFailed(device.m_Device->createPipelineLayout(&layoutCreateInfo, nullptr, &pipelineLayout));
|
||||||
|
|
||||||
const auto eqRectToCubeShader = CreateShader(pDevice, EQUIRECT_TO_CUBE_SHADER_FILE);
|
// const auto eqRectToCubeShader = CreateShader(pDevice, EQUIRECT_TO_CUBE_SHADER_FILE);
|
||||||
const auto diffuseRadianceShader = CreateShader(pDevice, DIFFUSE_IRRADIANCE_SHADER_FILE);
|
// const auto diffuseRadianceShader = CreateShader(pDevice, DIFFUSE_IRRADIANCE_SHADER_FILE);
|
||||||
const auto prefilterShader = CreateShader(pDevice, PREFILTER_SHADER_FILE);
|
// const auto prefilterShader = CreateShader(pDevice, PREFILTER_SHADER_FILE);
|
||||||
const auto brdfLutShader = CreateShader(pDevice, BRDF_LUT_SHADER_FILE);
|
// const auto brdfLutShader = CreateShader(pDevice, BRDF_LUT_SHADER_FILE);
|
||||||
eastl::array computePipelineCreateInfo = {
|
// eastl::array computePipelineCreateInfo = {
|
||||||
vk::ComputePipelineCreateInfo{
|
// vk::ComputePipelineCreateInfo{
|
||||||
.stage =
|
// .stage =
|
||||||
{
|
// {
|
||||||
.stage = vk::ShaderStageFlagBits::eCompute,
|
// .stage = vk::ShaderStageFlagBits::eCompute,
|
||||||
.module = eqRectToCubeShader,
|
// .module = eqRectToCubeShader,
|
||||||
.pName = "main",
|
// .pName = "main",
|
||||||
},
|
// },
|
||||||
.layout = pipelineLayout,
|
// .layout = pipelineLayout,
|
||||||
},
|
// },
|
||||||
vk::ComputePipelineCreateInfo{
|
// vk::ComputePipelineCreateInfo{
|
||||||
.stage =
|
// .stage =
|
||||||
{
|
// {
|
||||||
.stage = vk::ShaderStageFlagBits::eCompute,
|
// .stage = vk::ShaderStageFlagBits::eCompute,
|
||||||
.module = diffuseRadianceShader,
|
// .module = diffuseRadianceShader,
|
||||||
.pName = "main",
|
// .pName = "main",
|
||||||
},
|
// },
|
||||||
.layout = pipelineLayout,
|
// .layout = pipelineLayout,
|
||||||
},
|
// },
|
||||||
vk::ComputePipelineCreateInfo{
|
// vk::ComputePipelineCreateInfo{
|
||||||
.stage =
|
// .stage =
|
||||||
{
|
// {
|
||||||
.stage = vk::ShaderStageFlagBits::eCompute,
|
// .stage = vk::ShaderStageFlagBits::eCompute,
|
||||||
.module = prefilterShader,
|
// .module = prefilterShader,
|
||||||
.pName = "main",
|
// .pName = "main",
|
||||||
},
|
// },
|
||||||
.layout = pipelineLayout,
|
// .layout = pipelineLayout,
|
||||||
},
|
// },
|
||||||
vk::ComputePipelineCreateInfo{
|
// vk::ComputePipelineCreateInfo{
|
||||||
.stage =
|
// .stage =
|
||||||
{
|
// {
|
||||||
.stage = vk::ShaderStageFlagBits::eCompute,
|
// .stage = vk::ShaderStageFlagBits::eCompute,
|
||||||
.module = brdfLutShader,
|
// .module = brdfLutShader,
|
||||||
.pName = "main",
|
// .pName = "main",
|
||||||
},
|
// },
|
||||||
.layout = pipelineLayout,
|
// .layout = pipelineLayout,
|
||||||
},
|
// },
|
||||||
};
|
// };
|
||||||
|
|
||||||
eastl::array<vk::Pipeline, computePipelineCreateInfo.size()> pipelines;
|
// eastl::array<vk::Pipeline, computePipelineCreateInfo.size()> pipelines;
|
||||||
AbortIfFailed(
|
// AbortIfFailed(pDevice->m_Device.createComputePipelines(
|
||||||
pDevice->m_Device.createComputePipelines(pDevice->m_PipelineCache, static_cast<u32>(computePipelineCreateInfo.size()),
|
// pDevice->m_PipelineCache, static_cast<u32>(computePipelineCreateInfo.size()),
|
||||||
computePipelineCreateInfo.data(), nullptr, pipelines.data()));
|
// computePipelineCreateInfo.data(), nullptr, pipelines.data()));
|
||||||
|
|
||||||
vk::Pipeline eqRectToCubePipeline = pipelines[0];
|
// vk::Pipeline eqRectToCubePipeline = pipelines[0];
|
||||||
vk::Pipeline diffuseIrradiancePipeline = pipelines[1];
|
// vk::Pipeline diffuseIrradiancePipeline = pipelines[1];
|
||||||
vk::Pipeline prefilterPipeline = pipelines[2];
|
// vk::Pipeline prefilterPipeline = pipelines[2];
|
||||||
vk::Pipeline brdfLutPipeline = pipelines[3];
|
// vk::Pipeline brdfLutPipeline = pipelines[3];
|
||||||
|
|
||||||
for (auto &createInfos : computePipelineCreateInfo)
|
Pipeline eqRectToCubePipeline;
|
||||||
|
|
||||||
|
if (auto result =
|
||||||
|
device.CreateComputePipeline(eqRectToCubePipeline, {
|
||||||
|
.m_Shader =
|
||||||
{
|
{
|
||||||
pDevice->m_Device.destroy(createInfos.stage.module, nullptr);
|
.m_ShaderFile = EQUIRECT_TO_CUBE_SHADER_FILE,
|
||||||
|
.m_EntryPoints = {"main"},
|
||||||
|
},
|
||||||
|
.m_Name = "EqRect -> Cubemap",
|
||||||
|
}))
|
||||||
|
{
|
||||||
|
ERROR("EqRect -> Cubemap Pipeline Creation failed. Cause: {}", result.What()) THEN_ABORT(result.Value());
|
||||||
|
}
|
||||||
|
|
||||||
|
Pipeline diffuseIrradiancePipeline;
|
||||||
|
|
||||||
|
if (auto result = device.CreateComputePipeline(
|
||||||
|
diffuseIrradiancePipeline,
|
||||||
|
{{.m_ShaderFile = ENVIRONMENT_SHADER_FILE, .m_EntryPoints = {DIFFUSE_IRRADIANCE_ENTRY}},
|
||||||
|
"DiffuseIrradiance"}))
|
||||||
|
{
|
||||||
|
ERROR("Diffuse Irradiance compute pipeline creation failed. Cause: {}", result.What())
|
||||||
|
THEN_ABORT(result.Value());
|
||||||
|
}
|
||||||
|
|
||||||
|
Pipeline prefilterPipeline;
|
||||||
|
|
||||||
|
if (auto result = device.CreateComputePipeline(
|
||||||
|
prefilterPipeline,
|
||||||
|
{{.m_ShaderFile = ENVIRONMENT_SHADER_FILE, .m_EntryPoints = {PREFILTER_ENTRY}}, "Prefilter"}))
|
||||||
|
{
|
||||||
|
ERROR("Prefilter compute pipeline creation failed. Cause: {}", result.What())
|
||||||
|
THEN_ABORT(result.Value());
|
||||||
|
}
|
||||||
|
|
||||||
|
Pipeline brdfLutPipeline;
|
||||||
|
|
||||||
|
if (auto result = device.CreateComputePipeline(
|
||||||
|
brdfLutPipeline, {{.m_ShaderFile = ENVIRONMENT_SHADER_FILE, .m_EntryPoints = {BRDF_LUT_ENTRY}}, "BRDF"}))
|
||||||
|
{
|
||||||
|
ERROR("BRDF LUT compute pipeline creation failed. Cause: {}", result.What())
|
||||||
|
THEN_ABORT(result.Value());
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
|
|
@ -303,42 +342,27 @@ CreateCubeFromHdrEnv(AssetLoader *assetLoader, vk::Queue computeQueue, const u32
|
||||||
|
|
||||||
commitManager->Update();
|
commitManager->Update();
|
||||||
|
|
||||||
auto cmd = assetLoader->m_CommandBuffer;
|
auto context = assetLoader.m_Device->CreateComputeContext();
|
||||||
constexpr vk::CommandBufferBeginInfo beginInfo = {.flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit};
|
|
||||||
AbortIfFailed(cmd.begin(&beginInfo));
|
|
||||||
|
|
||||||
#if !defined(ASTER_NDEBUG)
|
context.Begin();
|
||||||
StackString<128> labelName = "Eqrect -> Cubemap: ";
|
|
||||||
labelName += name ? name : "<unknown env>";
|
|
||||||
vk::DebugUtilsLabelEXT label = {
|
|
||||||
.pLabelName = labelName.c_str(),
|
|
||||||
.color = std::array{1.0f, 1.0f, 1.0f, 1.0f},
|
|
||||||
};
|
|
||||||
cmd.beginDebugUtilsLabelEXT(&label);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
cmd.pipelineBarrier2(&readyToWriteDependency);
|
context.BeginDebugRegion("Eqrect -> Cubemap");
|
||||||
|
|
||||||
|
context.Dependency(readyToWriteDependency);
|
||||||
|
|
||||||
cmd.bindDescriptorSets(vk::PipelineBindPoint::eCompute, pipelineLayout, 0, 1, &commitManager->GetDescriptorSet(), 0,
|
|
||||||
nullptr);
|
|
||||||
cmd.bindPipeline(vk::PipelineBindPoint::eCompute, eqRectToCubePipeline);
|
|
||||||
cmd.pushConstants(pipelineLayout, vk::ShaderStageFlagBits::eCompute, 0, sizeof skyboxPushConstant,
|
|
||||||
&skyboxPushConstant);
|
|
||||||
assert(skybox->m_Extent.width % 16 == 0 && skybox->m_Extent.height % 16 == 0);
|
assert(skybox->m_Extent.width % 16 == 0 && skybox->m_Extent.height % 16 == 0);
|
||||||
cmd.dispatch(skybox->m_Extent.width / 16, skybox->m_Extent.height / 16, 6);
|
context.Dispatch(eqRectToCubePipeline, skybox->m_Extent.width / 16, skybox->m_Extent.height / 16, 6,
|
||||||
|
skyboxPushConstant);
|
||||||
|
|
||||||
GenerateMipMaps(cmd, skybox, vk::ImageLayout::eGeneral, vk::ImageLayout::eGeneral,
|
GenerateMipMaps(context, skybox, vk::ImageLayout::eGeneral, vk::ImageLayout::eGeneral,
|
||||||
vk::PipelineStageFlagBits2::eComputeShader, vk::PipelineStageFlagBits2::eComputeShader);
|
vk::PipelineStageFlagBits2::eComputeShader, vk::PipelineStageFlagBits2::eComputeShader);
|
||||||
|
|
||||||
cmd.bindPipeline(vk::PipelineBindPoint::eCompute, diffuseIrradiancePipeline);
|
|
||||||
cmd.pushConstants(pipelineLayout, vk::ShaderStageFlagBits::eCompute, 0, sizeof skyboxPushConstant,
|
|
||||||
&diffuseIrradiancePushConstants);
|
|
||||||
assert(diffuseIrradiance->m_Extent.width % 16 == 0 && diffuseIrradiance->m_Extent.height % 16 == 0);
|
assert(diffuseIrradiance->m_Extent.width % 16 == 0 && diffuseIrradiance->m_Extent.height % 16 == 0);
|
||||||
cmd.dispatch(diffuseIrradiance->m_Extent.width / 16, diffuseIrradiance->m_Extent.width / 16, 6);
|
context.Dispatch(diffuseIrradiancePipeline, diffuseIrradiance->m_Extent.width / 16,
|
||||||
|
diffuseIrradiance->m_Extent.width / 16, 6, diffuseIrradiancePushConstants);
|
||||||
|
|
||||||
cmd.pipelineBarrier2(&diffIrrToSampleDependency);
|
context.Dependency(diffIrrToSampleDependency);
|
||||||
|
|
||||||
cmd.bindPipeline(vk::PipelineBindPoint::eCompute, prefilterPipeline);
|
|
||||||
u32 mipSize = prefilterCube->m_Extent.width;
|
u32 mipSize = prefilterCube->m_Extent.width;
|
||||||
assert(mipSize % 16 == 0);
|
assert(mipSize % 16 == 0);
|
||||||
for (u32 mipCount = 0; auto &tex : prefilterStorageHandles)
|
for (u32 mipCount = 0; auto &tex : prefilterStorageHandles)
|
||||||
|
|
@ -346,52 +370,27 @@ CreateCubeFromHdrEnv(AssetLoader *assetLoader, vk::Queue computeQueue, const u32
|
||||||
prefilterPushConstants.m_OutputTexture = tex;
|
prefilterPushConstants.m_OutputTexture = tex;
|
||||||
prefilterPushConstants.m_CubeSide = mipSize;
|
prefilterPushConstants.m_CubeSide = mipSize;
|
||||||
prefilterPushConstants.m_Roughness = static_cast<f32>(mipCount) / static_cast<f32>(prefilterMipCountMax - 1);
|
prefilterPushConstants.m_Roughness = static_cast<f32>(mipCount) / static_cast<f32>(prefilterMipCountMax - 1);
|
||||||
cmd.pushConstants(pipelineLayout, vk::ShaderStageFlagBits::eCompute, 0, sizeof prefilterPushConstants,
|
|
||||||
&prefilterPushConstants);
|
|
||||||
u32 groupCount = eastl::max(mipSize / 16u, 1u);
|
u32 groupCount = eastl::max(mipSize / 16u, 1u);
|
||||||
cmd.dispatch(groupCount, groupCount, 6);
|
context.Dispatch(prefilterPipeline, groupCount, groupCount, 6, prefilterPushConstants);
|
||||||
|
|
||||||
++mipCount;
|
++mipCount;
|
||||||
mipSize = mipSize >> 1;
|
mipSize = mipSize >> 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.pipelineBarrier2(&skyboxToSampleDependency);
|
context.Dependency(skyboxToSampleDependency);
|
||||||
cmd.pipelineBarrier2(&prefilterToSampleDependency);
|
context.Dependency(prefilterToSampleDependency);
|
||||||
|
|
||||||
cmd.bindPipeline(vk::PipelineBindPoint::eCompute, brdfLutPipeline);
|
|
||||||
cmd.pushConstants(pipelineLayout, vk::ShaderStageFlagBits::eCompute, 0, sizeof brdfLutPushConstants,
|
|
||||||
&brdfLutPushConstants);
|
|
||||||
assert(brdfLut->m_Extent.width % 16 == 0 && brdfLut->m_Extent.height % 16 == 0);
|
assert(brdfLut->m_Extent.width % 16 == 0 && brdfLut->m_Extent.height % 16 == 0);
|
||||||
cmd.dispatch(brdfLut->m_Extent.width / 16, brdfLut->m_Extent.height / 16, 1);
|
context.Dispatch(brdfLutPipeline, brdfLut->m_Extent.width / 16, brdfLut->m_Extent.height / 16, 1,
|
||||||
|
brdfLutPushConstants);
|
||||||
|
|
||||||
#if !defined(ASTER_NDEBUG)
|
context.EndDebugRegion();
|
||||||
cmd.endDebugUtilsLabelEXT();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
AbortIfFailed(cmd.end());
|
context.End();
|
||||||
|
|
||||||
vk::SubmitInfo submitInfo = {
|
auto receipt = device.Submit(context);
|
||||||
.waitSemaphoreCount = 0,
|
device.WaitOn(receipt);
|
||||||
.pWaitDstStageMask = nullptr,
|
|
||||||
.commandBufferCount = 1,
|
|
||||||
.pCommandBuffers = &cmd,
|
|
||||||
};
|
|
||||||
|
|
||||||
vk::Fence fence;
|
|
||||||
vk::FenceCreateInfo fenceCreateInfo = {};
|
|
||||||
AbortIfFailed(pDevice->m_Device.createFence(&fenceCreateInfo, nullptr, &fence));
|
|
||||||
AbortIfFailed(computeQueue.submit(1, &submitInfo, fence));
|
|
||||||
AbortIfFailed(pDevice->m_Device.waitForFences(1, &fence, true, MaxValue<u32>));
|
|
||||||
pDevice->m_Device.destroy(fence, nullptr);
|
|
||||||
|
|
||||||
AbortIfFailed(pDevice->m_Device.resetCommandPool(assetLoader->m_CommandPool, {}));
|
|
||||||
|
|
||||||
skybox = {};
|
|
||||||
for (auto &pipeline : pipelines)
|
|
||||||
{
|
|
||||||
pDevice->m_Device.destroy(pipeline, nullptr);
|
|
||||||
}
|
|
||||||
pDevice->m_Device.destroy(pipelineLayout, nullptr);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
.m_Skybox = skyboxHandle,
|
.m_Skybox = skyboxHandle,
|
||||||
|
|
|
||||||
|
|
@ -23,5 +23,4 @@ struct Environment
|
||||||
systems::ResId<TextureView> m_BrdfLut;
|
systems::ResId<TextureView> m_BrdfLut;
|
||||||
};
|
};
|
||||||
|
|
||||||
Environment CreateCubeFromHdrEnv(AssetLoader *assetLoader, vk::Queue computeQueue, u32 cubeSide,
|
Environment CreateCubeFromHdrEnv(AssetLoader &assetLoader, u32 cubeSide, systems::ResId<TextureView> hdrEnv);
|
||||||
systems::ResId<TextureView> hdrEnv, cstr name = nullptr);
|
|
||||||
|
|
@ -7,8 +7,8 @@
|
||||||
|
|
||||||
#include "aster/core/buffer.h"
|
#include "aster/core/buffer.h"
|
||||||
#include "aster/systems/commit_manager.h"
|
#include "aster/systems/commit_manager.h"
|
||||||
|
#include "aster/systems/device.h"
|
||||||
#include "aster/systems/resource.h"
|
#include "aster/systems/resource.h"
|
||||||
#include "aster/systems/resource_manager.h"
|
|
||||||
#include "glm/ext/matrix_transform.hpp"
|
#include "glm/ext/matrix_transform.hpp"
|
||||||
|
|
||||||
// Static Checks
|
// Static Checks
|
||||||
|
|
@ -55,9 +55,8 @@ ToColor32(const vec3 &col)
|
||||||
return r << 24 | g << 16 | b << 8 | a;
|
return r << 24 | g << 16 | b << 8 | a;
|
||||||
}
|
}
|
||||||
|
|
||||||
LightManager::LightManager(systems::ResourceManager *resourceManager, systems::CommitManager *commitManager)
|
LightManager::LightManager(systems::Device &device)
|
||||||
: m_ResourceManager{resourceManager}
|
: m_Device{&device}
|
||||||
, m_CommitManager{commitManager}
|
|
||||||
, m_DirectionalLightCount{}
|
, m_DirectionalLightCount{}
|
||||||
, m_PointLightCount{}
|
, m_PointLightCount{}
|
||||||
, m_MetaInfo{.m_LightBuffer = systems::NullId()}
|
, m_MetaInfo{.m_LightBuffer = systems::NullId()}
|
||||||
|
|
@ -66,8 +65,7 @@ LightManager::LightManager(systems::ResourceManager *resourceManager, systems::C
|
||||||
}
|
}
|
||||||
|
|
||||||
LightManager::LightManager(LightManager &&other) noexcept
|
LightManager::LightManager(LightManager &&other) noexcept
|
||||||
: m_ResourceManager(other.m_ResourceManager)
|
: m_Device{Take(other.m_Device)}
|
||||||
, m_CommitManager(other.m_CommitManager)
|
|
||||||
, m_Lights(std::move(other.m_Lights))
|
, m_Lights(std::move(other.m_Lights))
|
||||||
, m_DirectionalLightCount(other.m_DirectionalLightCount)
|
, m_DirectionalLightCount(other.m_DirectionalLightCount)
|
||||||
, m_PointLightCount(other.m_PointLightCount)
|
, m_PointLightCount(other.m_PointLightCount)
|
||||||
|
|
@ -81,7 +79,7 @@ LightManager::operator=(LightManager &&other) noexcept
|
||||||
{
|
{
|
||||||
if (this == &other)
|
if (this == &other)
|
||||||
return *this;
|
return *this;
|
||||||
m_ResourceManager = other.m_ResourceManager;
|
m_Device = Take(other.m_Device);
|
||||||
m_Lights = std::move(other.m_Lights);
|
m_Lights = std::move(other.m_Lights);
|
||||||
m_DirectionalLightCount = other.m_DirectionalLightCount;
|
m_DirectionalLightCount = other.m_DirectionalLightCount;
|
||||||
m_PointLightCount = other.m_PointLightCount;
|
m_PointLightCount = other.m_PointLightCount;
|
||||||
|
|
@ -210,15 +208,14 @@ LightManager::Update()
|
||||||
const u16 requiredBufferCapacity = eastl::min(static_cast<u16>(m_Lights.capacity()), MAX_LIGHTS);
|
const u16 requiredBufferCapacity = eastl::min(static_cast<u16>(m_Lights.capacity()), MAX_LIGHTS);
|
||||||
if ((m_GpuBufferCapacity_ & CAPACITY_MASK) < requiredBufferCapacity)
|
if ((m_GpuBufferCapacity_ & CAPACITY_MASK) < requiredBufferCapacity)
|
||||||
{
|
{
|
||||||
auto newBuffer = m_ResourceManager->Buffers().CreateStorageBuffer(requiredBufferCapacity * sizeof m_Lights[0],
|
auto newBuffer = m_Device->CreateStorageBuffer(requiredBufferCapacity * sizeof m_Lights[0], "Light Buffer");
|
||||||
"Light Buffer");
|
|
||||||
m_GpuBufferCapacity_ = requiredBufferCapacity | UPDATE_REQUIRED_BIT;
|
m_GpuBufferCapacity_ = requiredBufferCapacity | UPDATE_REQUIRED_BIT;
|
||||||
|
|
||||||
m_MetaInfo.m_LightBuffer = m_CommitManager->CommitBuffer(newBuffer);
|
m_MetaInfo.m_LightBuffer = m_Device->m_CommitManager->CommitBuffer(newBuffer);
|
||||||
}
|
}
|
||||||
if (m_GpuBufferCapacity_ & UPDATE_REQUIRED_BIT)
|
if (m_GpuBufferCapacity_ & UPDATE_REQUIRED_BIT)
|
||||||
{
|
{
|
||||||
const auto ref = m_CommitManager->FetchHandle(m_MetaInfo.m_LightBuffer);
|
const auto ref = m_Device->m_CommitManager->FetchHandle(m_MetaInfo.m_LightBuffer);
|
||||||
ref->Write(0, m_Lights.size() * sizeof m_Lights[0], m_Lights.data());
|
ref->Write(0, m_Lights.size() * sizeof m_Lights[0], m_Lights.data());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,11 @@
|
||||||
|
|
||||||
#include <EASTL/vector.h>
|
#include <EASTL/vector.h>
|
||||||
|
|
||||||
|
namespace systems
|
||||||
|
{
|
||||||
|
class Device;
|
||||||
|
}
|
||||||
|
|
||||||
namespace systems
|
namespace systems
|
||||||
{
|
{
|
||||||
class ResourceManager;
|
class ResourceManager;
|
||||||
|
|
@ -52,6 +57,8 @@ struct Light
|
||||||
f32 m_Range; // < 0.0 for invalid
|
f32 m_Range; // < 0.0 for invalid
|
||||||
u32 m_Color_; // LSB is used for flags. (R G B Flags)
|
u32 m_Color_; // LSB is used for flags. (R G B Flags)
|
||||||
f32 m_Intensity;
|
f32 m_Intensity;
|
||||||
|
u32 m_Pad0;
|
||||||
|
u32 m_Pad1;
|
||||||
|
|
||||||
constexpr static u32 MAX_GEN = 0x40;
|
constexpr static u32 MAX_GEN = 0x40;
|
||||||
constexpr static u32 GEN_MASK = MAX_GEN - 1;
|
constexpr static u32 GEN_MASK = MAX_GEN - 1;
|
||||||
|
|
@ -82,8 +89,7 @@ struct LightManager
|
||||||
u16 m_UnusedPadding0 = 0; // 02 12
|
u16 m_UnusedPadding0 = 0; // 02 12
|
||||||
};
|
};
|
||||||
|
|
||||||
systems::ResourceManager *m_ResourceManager;
|
systems::Device *m_Device;
|
||||||
systems::CommitManager *m_CommitManager;
|
|
||||||
eastl::vector<Light> m_Lights;
|
eastl::vector<Light> m_Lights;
|
||||||
|
|
||||||
// We don't need a Directional Light free list. We will just brute force iterate.
|
// We don't need a Directional Light free list. We will just brute force iterate.
|
||||||
|
|
@ -107,7 +113,7 @@ struct LightManager
|
||||||
|
|
||||||
~LightManager() = default;
|
~LightManager() = default;
|
||||||
|
|
||||||
LightManager(systems::ResourceManager *resourceManager, systems::CommitManager *commitManager);
|
LightManager(systems::Device &device);
|
||||||
LightManager(LightManager &&other) noexcept;
|
LightManager(LightManager &&other) noexcept;
|
||||||
LightManager &operator=(LightManager &&other) noexcept;
|
LightManager &operator=(LightManager &&other) noexcept;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,9 @@
|
||||||
|
|
||||||
#include "aster/core/buffer.h"
|
#include "aster/core/buffer.h"
|
||||||
#include "aster/core/constants.h"
|
#include "aster/core/constants.h"
|
||||||
#include "aster/core/instance.h"
|
|
||||||
#include "aster/core/device.h"
|
#include "aster/core/device.h"
|
||||||
#include "aster/core/image.h"
|
#include "aster/core/image.h"
|
||||||
|
#include "aster/core/instance.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"
|
||||||
|
|
@ -20,21 +20,24 @@
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
#include "light_manager.h"
|
#include "light_manager.h"
|
||||||
|
|
||||||
#include "aster/systems/buffer_manager.h"
|
#include "aster/util/files.h"
|
||||||
#include "gui.h"
|
#include "gui.h"
|
||||||
#include "ibl_helpers.h"
|
#include "ibl_helpers.h"
|
||||||
#include "pipeline_utils.h"
|
#include "pipeline_utils.h"
|
||||||
|
|
||||||
#include <EASTL/array.h>
|
#include <EASTL/array.h>
|
||||||
#include <aster/systems/commit_manager.h>
|
#include <aster/systems/commit_manager.h>
|
||||||
#include <aster/systems/resource_manager.h>
|
#include <aster/systems/device.h>
|
||||||
#include <tiny_gltf.h>
|
#include <tiny_gltf.h>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
|
||||||
constexpr u32 MAX_FRAMES_IN_FLIGHT = 3;
|
|
||||||
constexpr auto PIPELINE_CACHE_FILE = "PipelineCacheData.bin";
|
constexpr auto PIPELINE_CACHE_FILE = "PipelineCacheData.bin";
|
||||||
constexpr auto MODEL_FILE = "model/Sponza/Sponza.gltf";
|
constexpr auto MODEL_FILE = "model/DamagedHelmet.glb";
|
||||||
constexpr auto BACKDROP_FILE = "image/photo_studio_loft_hall_4k.hdr";
|
constexpr auto BACKDROP_FILE = "image/photo_studio_loft_hall_4k.hdr";
|
||||||
|
|
||||||
|
constexpr auto MODEL_SHADER_FILE = "model";
|
||||||
|
constexpr auto BACKGROUND_SHADER_FILE = "background";
|
||||||
|
|
||||||
constexpr u32 INIT_WIDTH = 1280;
|
constexpr u32 INIT_WIDTH = 1280;
|
||||||
constexpr u32 INIT_HEIGHT = 720;
|
constexpr u32 INIT_HEIGHT = 720;
|
||||||
|
|
||||||
|
|
@ -136,18 +139,9 @@ main(int, char **)
|
||||||
MIN_LOG_LEVEL(Logger::LogType::eInfo);
|
MIN_LOG_LEVEL(Logger::LogType::eInfo);
|
||||||
|
|
||||||
Window window = {"ModelRender (Aster)", {INIT_WIDTH, INIT_HEIGHT}};
|
Window window = {"ModelRender (Aster)", {INIT_WIDTH, INIT_HEIGHT}};
|
||||||
Instance context = {"ModelRender", VERSION};
|
|
||||||
Surface surface = {&context, &window, "Primary Surface"};
|
|
||||||
|
|
||||||
PhysicalDevices physicalDevices = {&surface, &context};
|
|
||||||
PhysicalDevice deviceToUse = FindSuitableDevice(physicalDevices);
|
|
||||||
|
|
||||||
usize physicalDeviceOffsetAlignment = deviceToUse.m_DeviceProperties.limits.minUniformBufferOffsetAlignment;
|
|
||||||
|
|
||||||
INFO("Using {} as the primary device.", deviceToUse.m_DeviceProperties.deviceName.data());
|
|
||||||
|
|
||||||
Features enabledDeviceFeatures = {
|
Features enabledDeviceFeatures = {
|
||||||
.m_Vulkan10Features = {.samplerAnisotropy = true},
|
.m_Vulkan10Features = {.samplerAnisotropy = true, .shaderInt16 = true},
|
||||||
.m_Vulkan12Features =
|
.m_Vulkan12Features =
|
||||||
{
|
{
|
||||||
.descriptorIndexing = true,
|
.descriptorIndexing = true,
|
||||||
|
|
@ -160,6 +154,7 @@ main(int, char **)
|
||||||
.descriptorBindingStorageBufferUpdateAfterBind = true,
|
.descriptorBindingStorageBufferUpdateAfterBind = true,
|
||||||
.descriptorBindingPartiallyBound = true,
|
.descriptorBindingPartiallyBound = true,
|
||||||
.runtimeDescriptorArray = true,
|
.runtimeDescriptorArray = true,
|
||||||
|
.timelineSemaphore = true,
|
||||||
.bufferDeviceAddress = true,
|
.bufferDeviceAddress = true,
|
||||||
.bufferDeviceAddressCaptureReplay = true,
|
.bufferDeviceAddressCaptureReplay = true,
|
||||||
},
|
},
|
||||||
|
|
@ -171,31 +166,52 @@ main(int, char **)
|
||||||
};
|
};
|
||||||
|
|
||||||
auto pipelineCacheData = ReadFileBytes(PIPELINE_CACHE_FILE, false);
|
auto pipelineCacheData = ReadFileBytes(PIPELINE_CACHE_FILE, false);
|
||||||
|
systems::Device device{{
|
||||||
|
.m_Window = window,
|
||||||
|
.m_Features = enabledDeviceFeatures,
|
||||||
|
.m_AppName = "ModelRender",
|
||||||
|
.m_AppVersion = VERSION,
|
||||||
|
.m_PipelineCacheData = pipelineCacheData,
|
||||||
|
.m_ShaderSearchPaths = {"shader/slang/"},
|
||||||
|
}};
|
||||||
|
|
||||||
QueueAllocation queueAllocation = FindAppropriateQueueAllocation(&deviceToUse);
|
AssetLoader assetLoader{device};
|
||||||
Device device = {&context, &deviceToUse, &enabledDeviceFeatures,
|
LightManager lightManager{device};
|
||||||
{queueAllocation}, pipelineCacheData, "Primary Device"};
|
|
||||||
vk::Queue graphicsQueue = device.GetQueue(queueAllocation.m_Family, 0);
|
|
||||||
Swapchain swapchain = {&surface, &device, window.GetSize(), "Primary Chain"};
|
|
||||||
|
|
||||||
auto resourceManager = systems::ResourceManager{&device};
|
|
||||||
systems::CommitManager commitManager = {&device, 1000, 1000, 1000,
|
|
||||||
resourceManager.Samplers().CreateSampler({.m_Name = "Default Sampler"})};
|
|
||||||
|
|
||||||
AssetLoader assetLoader = {&resourceManager, &commitManager, graphicsQueue, queueAllocation.m_Family,
|
|
||||||
queueAllocation.m_Family};
|
|
||||||
auto lightManager = LightManager{&resourceManager, &commitManager};
|
|
||||||
|
|
||||||
Model model = assetLoader.LoadModelToGpu(MODEL_FILE);
|
Model model = assetLoader.LoadModelToGpu(MODEL_FILE);
|
||||||
auto environmentHdri = assetLoader.LoadHdrImage(BACKDROP_FILE);
|
auto environmentHdri = assetLoader.LoadHdrImage(BACKDROP_FILE);
|
||||||
auto envHdriHandle = commitManager.CommitTexture(environmentHdri);
|
auto envHdriHandle = device.m_CommitManager->CommitTexture(environmentHdri);
|
||||||
|
|
||||||
auto environment = CreateCubeFromHdrEnv(&assetLoader, graphicsQueue, 512, envHdriHandle, "Cube Env");
|
auto environment = CreateCubeFromHdrEnv(assetLoader, 512, envHdriHandle);
|
||||||
|
|
||||||
auto attachmentFormat = vk::Format::eR8G8B8A8Srgb;
|
auto attachmentFormat = device.m_Swapchain.m_Format;
|
||||||
|
|
||||||
Pipeline pipeline = CreatePipeline(&device, attachmentFormat, &commitManager);
|
Pipeline pipeline;
|
||||||
Pipeline backGroundPipeline = CreateBackgroundPipeline(&device, attachmentFormat, &commitManager);
|
if (auto result = device.CreatePipeline(pipeline, {
|
||||||
|
.m_Shaders = {{
|
||||||
|
.m_ShaderFile = MODEL_SHADER_FILE,
|
||||||
|
.m_EntryPoints = {"vsmain", "fsmain"},
|
||||||
|
}},
|
||||||
|
.m_Name = "Primary",
|
||||||
|
}))
|
||||||
|
{
|
||||||
|
ERROR("Could not create model pipeline. Cause: {}", result.What()) THEN_ABORT(result.Value());
|
||||||
|
}
|
||||||
|
|
||||||
|
Pipeline backgroundPipeline;
|
||||||
|
if (auto result = device.CreatePipeline(
|
||||||
|
backgroundPipeline, {
|
||||||
|
.m_Shaders = {{
|
||||||
|
.m_ShaderFile = BACKGROUND_SHADER_FILE,
|
||||||
|
.m_EntryPoints = {"vsmain", "fsmain"},
|
||||||
|
}},
|
||||||
|
.m_DepthTest = systems::GraphicsPipelineCreateInfo::DepthTest::eReadOnly,
|
||||||
|
.m_DepthOp = systems::GraphicsPipelineCreateInfo::CompareOp::eLessThanOrEqualTo,
|
||||||
|
.m_Name = "Background",
|
||||||
|
}))
|
||||||
|
{
|
||||||
|
ERROR("Could not create background pipeline. Cause: {}", result.What()) THEN_ABORT(result.Value());
|
||||||
|
}
|
||||||
|
|
||||||
lightManager.AddPoint(vec3{-5.0f, -5.0f, 5.0f}, vec3{1.0f}, 30.0f, 16.0f);
|
lightManager.AddPoint(vec3{-5.0f, -5.0f, 5.0f}, vec3{1.0f}, 30.0f, 16.0f);
|
||||||
lightManager.AddPoint(vec3{5.0f, -5.0f, 5.0f}, vec3{1.0f}, 30.0f, 16.0f);
|
lightManager.AddPoint(vec3{5.0f, -5.0f, 5.0f}, vec3{1.0f}, 30.0f, 16.0f);
|
||||||
|
|
@ -204,82 +220,21 @@ main(int, char **)
|
||||||
|
|
||||||
lightManager.Update();
|
lightManager.Update();
|
||||||
|
|
||||||
vk::DescriptorPool descriptorPool;
|
|
||||||
vk::DescriptorSet perFrameDescriptor;
|
|
||||||
|
|
||||||
{
|
|
||||||
vk::DescriptorSetLayout descriptorSetLayout = pipeline.m_SetLayouts[1];
|
|
||||||
eastl::array poolSizes = {
|
|
||||||
vk::DescriptorPoolSize{
|
|
||||||
.type = vk::DescriptorType::eUniformBuffer,
|
|
||||||
.descriptorCount = 3,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
vk::DescriptorPoolCreateInfo descriptorPoolCreateInfo = {
|
|
||||||
.maxSets = 1, .poolSizeCount = static_cast<u32>(poolSizes.size()), .pPoolSizes = poolSizes.data()};
|
|
||||||
AbortIfFailed(device.m_Device.createDescriptorPool(&descriptorPoolCreateInfo, nullptr, &descriptorPool));
|
|
||||||
|
|
||||||
vk::DescriptorSetAllocateInfo descriptorSetAllocateInfo = {
|
|
||||||
.descriptorPool = descriptorPool,
|
|
||||||
.descriptorSetCount = 1,
|
|
||||||
.pSetLayouts = &descriptorSetLayout,
|
|
||||||
};
|
|
||||||
AbortIfFailed(device.m_Device.allocateDescriptorSets(&descriptorSetAllocateInfo, &perFrameDescriptor));
|
|
||||||
}
|
|
||||||
|
|
||||||
vk::Extent2D internalResolution = {1920, 1080};
|
vk::Extent2D internalResolution = {1920, 1080};
|
||||||
|
|
||||||
|
auto swapchainSize = device.GetSwapchainSize();
|
||||||
|
|
||||||
CameraController cameraController = {vec3{0.0f, 0.0f, 2.0f}, vec3{0.0f}, 70_deg,
|
CameraController cameraController = {vec3{0.0f, 0.0f, 2.0f}, vec3{0.0f}, 70_deg,
|
||||||
static_cast<f32>(swapchain.m_Extent.width) / static_cast<f32>(swapchain.m_Extent.height)};
|
static_cast<f32>(swapchainSize.m_Width) /
|
||||||
|
static_cast<f32>(swapchainSize.m_Height)};
|
||||||
|
|
||||||
usize uboSize = 0;
|
auto cameraBuffer = device.CreateStorageBuffer(sizeof cameraController.m_Camera, "Camera Info");
|
||||||
usize cameraSize = sizeof cameraController.m_Camera;
|
auto cameraBufferId = device.m_CommitManager->CommitBuffer(cameraBuffer);
|
||||||
uboSize += ClosestMultiple(cameraSize, physicalDeviceOffsetAlignment);
|
auto lightManagerBuffer =
|
||||||
usize lightOffset = uboSize;
|
device.CreateStorageBuffer(sizeof environment + sizeof lightManager.m_MetaInfo, "Light Info");
|
||||||
usize lightingSize = sizeof environment + sizeof lightManager.m_MetaInfo;
|
auto lightsBufferId = device.m_CommitManager->CommitBuffer(lightManagerBuffer);
|
||||||
uboSize += ClosestMultiple(lightingSize, physicalDeviceOffsetAlignment);
|
lightManagerBuffer->Write(0, sizeof environment, &environment);
|
||||||
|
lightManagerBuffer->Write(sizeof environment, sizeof lightManager.m_MetaInfo, &lightManager.m_MetaInfo);
|
||||||
auto data = new u8[uboSize];
|
|
||||||
memcpy(data, &cameraController.m_Camera, cameraSize);
|
|
||||||
memcpy(data + lightOffset, &environment, sizeof environment);
|
|
||||||
memcpy(data + lightOffset + sizeof environment, &lightManager.m_MetaInfo, sizeof lightManager.m_MetaInfo);
|
|
||||||
|
|
||||||
auto ubo = resourceManager.Buffers().CreateUniformBuffer(uboSize, "Desc1 UBO");
|
|
||||||
ubo->Write(0, ubo->m_Size, data);
|
|
||||||
|
|
||||||
delete[] data;
|
|
||||||
|
|
||||||
vk::DescriptorBufferInfo cameraBufferInfo = {
|
|
||||||
.buffer = ubo->m_Buffer,
|
|
||||||
.offset = 0,
|
|
||||||
.range = cameraSize,
|
|
||||||
};
|
|
||||||
vk::DescriptorBufferInfo lightingBufferInfo = {
|
|
||||||
.buffer = ubo->m_Buffer,
|
|
||||||
.offset = lightOffset,
|
|
||||||
.range = lightingSize,
|
|
||||||
};
|
|
||||||
eastl::array writeDescriptors = {
|
|
||||||
vk::WriteDescriptorSet{
|
|
||||||
.dstSet = perFrameDescriptor,
|
|
||||||
.dstBinding = 0,
|
|
||||||
.dstArrayElement = 0,
|
|
||||||
.descriptorCount = 1,
|
|
||||||
.descriptorType = vk::DescriptorType::eUniformBuffer,
|
|
||||||
.pBufferInfo = &cameraBufferInfo,
|
|
||||||
},
|
|
||||||
vk::WriteDescriptorSet{
|
|
||||||
.dstSet = perFrameDescriptor,
|
|
||||||
.dstBinding = 1,
|
|
||||||
.dstArrayElement = 0,
|
|
||||||
.descriptorCount = 1,
|
|
||||||
.descriptorType = vk::DescriptorType::eUniformBuffer,
|
|
||||||
.pBufferInfo = &lightingBufferInfo,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
device.m_Device.updateDescriptorSets(static_cast<u32>(writeDescriptors.size()), writeDescriptors.data(), 0, nullptr);
|
|
||||||
|
|
||||||
commitManager.Update();
|
|
||||||
|
|
||||||
// Persistent variables
|
// Persistent variables
|
||||||
vk::Viewport viewport = {
|
vk::Viewport viewport = {
|
||||||
|
|
@ -304,7 +259,7 @@ main(int, char **)
|
||||||
.layerCount = 1,
|
.layerCount = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
vk::ImageMemoryBarrier2 preRenderBarrier = {
|
vk::ImageMemoryBarrier2 attachmentPreRenderBarrier = {
|
||||||
.srcStageMask = vk::PipelineStageFlagBits2::eTransfer,
|
.srcStageMask = vk::PipelineStageFlagBits2::eTransfer,
|
||||||
.srcAccessMask = vk::AccessFlagBits2::eTransferRead,
|
.srcAccessMask = vk::AccessFlagBits2::eTransferRead,
|
||||||
.dstStageMask = vk::PipelineStageFlagBits2::eColorAttachmentOutput,
|
.dstStageMask = vk::PipelineStageFlagBits2::eColorAttachmentOutput,
|
||||||
|
|
@ -315,12 +270,8 @@ main(int, char **)
|
||||||
.dstQueueFamilyIndex = vk::QueueFamilyIgnored,
|
.dstQueueFamilyIndex = vk::QueueFamilyIgnored,
|
||||||
.subresourceRange = subresourceRange,
|
.subresourceRange = subresourceRange,
|
||||||
};
|
};
|
||||||
vk::DependencyInfo preRenderDependencies = {
|
|
||||||
.imageMemoryBarrierCount = 1,
|
|
||||||
.pImageMemoryBarriers = &preRenderBarrier,
|
|
||||||
};
|
|
||||||
|
|
||||||
vk::ImageMemoryBarrier2 renderToBlitBarrier = {
|
vk::ImageMemoryBarrier2 attachmentRenderToBlitBarrier = {
|
||||||
.srcStageMask = vk::PipelineStageFlagBits2::eColorAttachmentOutput,
|
.srcStageMask = vk::PipelineStageFlagBits2::eColorAttachmentOutput,
|
||||||
.srcAccessMask = vk::AccessFlagBits2::eColorAttachmentWrite,
|
.srcAccessMask = vk::AccessFlagBits2::eColorAttachmentWrite,
|
||||||
.dstStageMask = vk::PipelineStageFlagBits2::eBlit,
|
.dstStageMask = vk::PipelineStageFlagBits2::eBlit,
|
||||||
|
|
@ -331,29 +282,24 @@ main(int, char **)
|
||||||
.dstQueueFamilyIndex = vk::QueueFamilyIgnored,
|
.dstQueueFamilyIndex = vk::QueueFamilyIgnored,
|
||||||
.subresourceRange = subresourceRange,
|
.subresourceRange = subresourceRange,
|
||||||
};
|
};
|
||||||
vk::ImageMemoryBarrier2 acquireToTransferDstBarrier = {
|
|
||||||
.srcStageMask = vk::PipelineStageFlagBits2::eTransfer,
|
// Dependency from Acquire to Blit
|
||||||
|
vk::ImageMemoryBarrier2 swapchainPreBlitBarrier = {
|
||||||
|
.srcStageMask = vk::PipelineStageFlagBits2::eColorAttachmentOutput,
|
||||||
.srcAccessMask = vk::AccessFlagBits2::eNone,
|
.srcAccessMask = vk::AccessFlagBits2::eNone,
|
||||||
.dstStageMask = vk::PipelineStageFlagBits2::eBlit,
|
.dstStageMask = vk::PipelineStageFlagBits2::eBlit,
|
||||||
.dstAccessMask = vk::AccessFlagBits2::eTransferWrite,
|
.dstAccessMask = vk::AccessFlagBits2::eTransferRead | vk::AccessFlagBits2::eTransferWrite,
|
||||||
.oldLayout = vk::ImageLayout::eUndefined,
|
.oldLayout = vk::ImageLayout::eUndefined,
|
||||||
.newLayout = vk::ImageLayout::eTransferDstOptimal,
|
.newLayout = vk::ImageLayout::eTransferDstOptimal,
|
||||||
.srcQueueFamilyIndex = vk::QueueFamilyIgnored,
|
.srcQueueFamilyIndex = vk::QueueFamilyIgnored,
|
||||||
.dstQueueFamilyIndex = vk::QueueFamilyIgnored,
|
.dstQueueFamilyIndex = vk::QueueFamilyIgnored,
|
||||||
.subresourceRange = subresourceRange,
|
.subresourceRange = subresourceRange,
|
||||||
};
|
};
|
||||||
eastl::array postRenderBarriers = {
|
|
||||||
renderToBlitBarrier,
|
|
||||||
acquireToTransferDstBarrier,
|
|
||||||
};
|
|
||||||
vk::DependencyInfo postRenderDependencies = {
|
|
||||||
.imageMemoryBarrierCount = static_cast<u32>(postRenderBarriers.size()),
|
|
||||||
.pImageMemoryBarriers = postRenderBarriers.data(),
|
|
||||||
};
|
|
||||||
|
|
||||||
vk::ImageMemoryBarrier2 transferDstToGuiRenderBarrier = {
|
// Execution dependency between blit and GUI render.
|
||||||
|
vk::ImageMemoryBarrier2 swapchainBlitToGuiBarrier = {
|
||||||
.srcStageMask = vk::PipelineStageFlagBits2::eTransfer,
|
.srcStageMask = vk::PipelineStageFlagBits2::eTransfer,
|
||||||
.srcAccessMask = vk::AccessFlagBits2::eTransferWrite | vk::AccessFlagBits2::eTransferRead,
|
.srcAccessMask = vk::AccessFlagBits2::eTransferWrite,
|
||||||
.dstStageMask = vk::PipelineStageFlagBits2::eColorAttachmentOutput,
|
.dstStageMask = vk::PipelineStageFlagBits2::eColorAttachmentOutput,
|
||||||
.dstAccessMask = vk::AccessFlagBits2::eColorAttachmentRead,
|
.dstAccessMask = vk::AccessFlagBits2::eColorAttachmentRead,
|
||||||
.oldLayout = vk::ImageLayout::eTransferDstOptimal,
|
.oldLayout = vk::ImageLayout::eTransferDstOptimal,
|
||||||
|
|
@ -362,12 +308,8 @@ main(int, char **)
|
||||||
.dstQueueFamilyIndex = vk::QueueFamilyIgnored,
|
.dstQueueFamilyIndex = vk::QueueFamilyIgnored,
|
||||||
.subresourceRange = subresourceRange,
|
.subresourceRange = subresourceRange,
|
||||||
};
|
};
|
||||||
vk::DependencyInfo preGuiDependencies = {
|
|
||||||
.imageMemoryBarrierCount = 1,
|
|
||||||
.pImageMemoryBarriers = &transferDstToGuiRenderBarrier,
|
|
||||||
};
|
|
||||||
|
|
||||||
vk::ImageMemoryBarrier2 prePresentBarrier = {
|
vk::ImageMemoryBarrier2 swapchainPrePresentBarrier = {
|
||||||
.srcStageMask = vk::PipelineStageFlagBits2::eColorAttachmentOutput,
|
.srcStageMask = vk::PipelineStageFlagBits2::eColorAttachmentOutput,
|
||||||
.srcAccessMask = vk::AccessFlagBits2::eColorAttachmentWrite,
|
.srcAccessMask = vk::AccessFlagBits2::eColorAttachmentWrite,
|
||||||
.dstStageMask = vk::PipelineStageFlagBits2::eBottomOfPipe,
|
.dstStageMask = vk::PipelineStageFlagBits2::eBottomOfPipe,
|
||||||
|
|
@ -378,33 +320,34 @@ main(int, char **)
|
||||||
.dstQueueFamilyIndex = vk::QueueFamilyIgnored,
|
.dstQueueFamilyIndex = vk::QueueFamilyIgnored,
|
||||||
.subresourceRange = subresourceRange,
|
.subresourceRange = subresourceRange,
|
||||||
};
|
};
|
||||||
vk::DependencyInfo prePresentDependencies = {
|
|
||||||
.imageMemoryBarrierCount = 1,
|
auto primeBarriers = [](const eastl::span<vk::ImageMemoryBarrier2> &barriers, const vk::Image image) {
|
||||||
.pImageMemoryBarriers = &prePresentBarrier,
|
for (auto &bar : barriers)
|
||||||
|
{
|
||||||
|
bar.image = image;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
FrameManager frameManager = {&device, queueAllocation.m_Family, MAX_FRAMES_IN_FLIGHT};
|
|
||||||
eastl::fixed_vector<Ref<ImageView>, MAX_FRAMES_IN_FLIGHT> depthImages;
|
eastl::fixed_vector<Ref<ImageView>, MAX_FRAMES_IN_FLIGHT> depthImages;
|
||||||
eastl::fixed_vector<Ref<ImageView>, MAX_FRAMES_IN_FLIGHT> attachmentImages;
|
eastl::fixed_vector<Ref<ImageView>, MAX_FRAMES_IN_FLIGHT> attachmentImages;
|
||||||
|
|
||||||
for (u32 index = 0; index < frameManager.m_FramesInFlight; ++index)
|
for (u32 index = 0; index < MAX_FRAMES_IN_FLIGHT; ++index)
|
||||||
{
|
{
|
||||||
auto name = fmt::format("Depth Frame{}", index);
|
auto name = fmt::format("Depth Frame{}", index);
|
||||||
depthImages.emplace_back(resourceManager.CombinedImageViews().CreateDepthStencilImage({
|
depthImages.emplace_back(device.CreateDepthStencilImageWithView({
|
||||||
.m_Extent = internalResolution,
|
.m_Extent = internalResolution,
|
||||||
.m_Name = name.c_str(),
|
.m_Name = name.c_str(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
name = fmt::format("Attachment0 Frame{}", index);
|
name = fmt::format("Attachment0 Frame{}", index);
|
||||||
attachmentImages.emplace_back(resourceManager.CombinedImageViews().CreateAttachment({
|
attachmentImages.emplace_back(device.CreateAttachmentWithView({
|
||||||
.m_Format = attachmentFormat,
|
.m_Format = attachmentFormat,
|
||||||
.m_Extent = internalResolution,
|
.m_Extent = internalResolution,
|
||||||
.m_Name = name.c_str(),
|
.m_Name = name.c_str(),
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
gui::Init(&context, &device, &window, swapchain.m_Format, static_cast<u32>(swapchain.m_ImageViews.size()),
|
gui::Init(device, window);
|
||||||
queueAllocation.m_Family, graphicsQueue);
|
|
||||||
bool rotating = false;
|
bool rotating = false;
|
||||||
bool lockToScreen = true;
|
bool lockToScreen = true;
|
||||||
bool showDiffuse = false;
|
bool showDiffuse = false;
|
||||||
|
|
@ -423,7 +366,7 @@ main(int, char **)
|
||||||
vec3 camPosition = cameraController.m_Camera.m_Position;
|
vec3 camPosition = cameraController.m_Camera.m_Position;
|
||||||
vk::Extent2D inputResolution = internalResolution;
|
vk::Extent2D inputResolution = internalResolution;
|
||||||
|
|
||||||
swapchain.RegisterResizeCallback([&cameraController](vk::Extent2D extent) {
|
device.RegisterResizeCallback([&cameraController](vk::Extent2D extent) {
|
||||||
cameraController.SetAspectRatio(static_cast<f32>(extent.width) / static_cast<f32>(extent.height));
|
cameraController.SetAspectRatio(static_cast<f32>(extent.width) / static_cast<f32>(extent.height));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -433,12 +376,11 @@ main(int, char **)
|
||||||
while (window.Poll())
|
while (window.Poll())
|
||||||
{
|
{
|
||||||
Time::Update();
|
Time::Update();
|
||||||
commitManager.Update();
|
|
||||||
|
|
||||||
gui::StartBuild();
|
gui::StartBuild();
|
||||||
|
|
||||||
gui::Begin("Settings");
|
gui::Begin("Settings");
|
||||||
gui::Text("Window Resolution: %ux%u", swapchain.m_Extent.width, swapchain.m_Extent.height);
|
gui::Text("Window Resolution: %ux%u", swapchainSize.m_Width, swapchainSize.m_Height);
|
||||||
gui::Text("Render Resolution: %ux%u", internalResolution.width, internalResolution.height);
|
gui::Text("Render Resolution: %ux%u", internalResolution.width, internalResolution.height);
|
||||||
gui::Checkbox("Lock Resolution to Window", &lockToScreen);
|
gui::Checkbox("Lock Resolution to Window", &lockToScreen);
|
||||||
if (!lockToScreen)
|
if (!lockToScreen)
|
||||||
|
|
@ -449,7 +391,8 @@ main(int, char **)
|
||||||
}
|
}
|
||||||
|
|
||||||
inputResolution.height = height;
|
inputResolution.height = height;
|
||||||
inputResolution.width = static_cast<i32>(cameraController.m_AspectRatio * static_cast<f32>(inputResolution.height));
|
inputResolution.width =
|
||||||
|
static_cast<i32>(cameraController.m_AspectRatio * static_cast<f32>(inputResolution.height));
|
||||||
|
|
||||||
if (gui::Button("Change Resolution"))
|
if (gui::Button("Change Resolution"))
|
||||||
{
|
{
|
||||||
|
|
@ -466,10 +409,10 @@ main(int, char **)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (swapchain.m_Extent.width != internalResolution.width ||
|
if (swapchainSize.m_Width != internalResolution.width ||
|
||||||
swapchain.m_Extent.height != internalResolution.height)
|
swapchainSize.m_Height != internalResolution.height)
|
||||||
{
|
{
|
||||||
internalResolution = swapchain.m_Extent;
|
internalResolution = swapchainSize;
|
||||||
viewport.width = static_cast<f32>(internalResolution.width);
|
viewport.width = static_cast<f32>(internalResolution.width);
|
||||||
viewport.height = -static_cast<f32>(internalResolution.height);
|
viewport.height = -static_cast<f32>(internalResolution.height);
|
||||||
viewport.y = static_cast<f32>(internalResolution.height);
|
viewport.y = static_cast<f32>(internalResolution.height);
|
||||||
|
|
@ -516,49 +459,51 @@ main(int, char **)
|
||||||
}
|
}
|
||||||
model.Update();
|
model.Update();
|
||||||
cameraController.m_Camera.CalculateInverses();
|
cameraController.m_Camera.CalculateInverses();
|
||||||
ubo->Write(0, sizeof cameraController.m_Camera, &cameraController.m_Camera);
|
cameraBuffer->Write(0, sizeof cameraController.m_Camera, &cameraController.m_Camera);
|
||||||
|
|
||||||
Frame *currentFrame = frameManager.GetNextFrame(&swapchain, &surface, window.GetSize());
|
auto ¤tFrame = device.GetNextFrame();
|
||||||
|
|
||||||
u32 imageIndex = currentFrame->m_ImageIdx;
|
auto context = currentFrame.CreateGraphicsContext();
|
||||||
vk::Image currentSwapchainImage = swapchain.m_Images[imageIndex];
|
|
||||||
vk::ImageView currentSwapchainImageView = swapchain.m_ImageViews[imageIndex];
|
|
||||||
vk::CommandBuffer cmd = currentFrame->m_CommandBuffer;
|
|
||||||
|
|
||||||
auto ¤tDepthImage = depthImages[currentFrame->m_FrameIdx];
|
auto ¤tDepthImage = depthImages[currentFrame.m_FrameIdx];
|
||||||
auto ¤tAttachment = attachmentImages[currentFrame->m_FrameIdx];
|
auto ¤tAttachment = attachmentImages[currentFrame.m_FrameIdx];
|
||||||
|
|
||||||
if (currentAttachment->m_Extent.width != internalResolution.width ||
|
if (currentAttachment->m_Extent.width != internalResolution.width ||
|
||||||
currentAttachment->m_Extent.height != internalResolution.height)
|
currentAttachment->m_Extent.height != internalResolution.height)
|
||||||
{
|
{
|
||||||
auto name = fmt::format("Depth Frame{}", currentFrame->m_FrameIdx);
|
auto name = fmt::format("Depth Frame{}", currentFrame.m_FrameIdx);
|
||||||
currentDepthImage = resourceManager.CombinedImageViews().CreateDepthStencilImage({
|
currentDepthImage = device.CreateDepthStencilImageWithView({
|
||||||
.m_Extent = internalResolution,
|
.m_Extent = internalResolution,
|
||||||
.m_Name = name.c_str(),
|
.m_Name = name.c_str(),
|
||||||
});
|
});
|
||||||
|
|
||||||
name = fmt::format("Attachment0 Frame{}", currentFrame->m_FrameIdx);
|
name = fmt::format("Attachment0 Frame{}", currentFrame.m_FrameIdx);
|
||||||
currentAttachment = resourceManager.CombinedImageViews().CreateAttachment({
|
currentAttachment = device.CreateAttachmentWithView({
|
||||||
.m_Format = attachmentFormat,
|
.m_Format = attachmentFormat,
|
||||||
.m_Extent = internalResolution,
|
.m_Extent = internalResolution,
|
||||||
.m_Name = name.c_str(),
|
.m_Name = name.c_str(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vk::Image currentSwapchainImage = currentFrame.m_SwapchainImage;
|
||||||
|
|
||||||
vk::ImageView currentDepthImageView = currentDepthImage->m_View;
|
vk::ImageView currentDepthImageView = currentDepthImage->m_View;
|
||||||
vk::Image currentImage = currentAttachment->m_Image->m_Image;
|
vk::Image currentImage = currentAttachment->m_Image->m_Image;
|
||||||
vk::ImageView currentImageView = currentAttachment->m_View;
|
vk::ImageView currentImageView = currentAttachment->m_View;
|
||||||
|
|
||||||
preRenderBarrier.image = currentImage;
|
attachmentPreRenderBarrier.image = currentImage;
|
||||||
postRenderBarriers[0].image = currentImage;
|
attachmentRenderToBlitBarrier.image = currentImage;
|
||||||
postRenderBarriers[1].image = currentSwapchainImage;
|
swapchainPreBlitBarrier.image = currentSwapchainImage;
|
||||||
transferDstToGuiRenderBarrier.image = currentSwapchainImage;
|
swapchainBlitToGuiBarrier.image = currentSwapchainImage;
|
||||||
prePresentBarrier.image = currentSwapchainImage;
|
swapchainPrePresentBarrier.image = currentSwapchainImage;
|
||||||
|
|
||||||
vk::CommandBufferBeginInfo beginInfo = {.flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit};
|
context.Begin();
|
||||||
AbortIfFailed(cmd.begin(&beginInfo));
|
|
||||||
|
|
||||||
cmd.pipelineBarrier2(&preRenderDependencies);
|
eastl::array firstBarriers = {attachmentPreRenderBarrier, swapchainPreBlitBarrier};
|
||||||
|
context.Dependency({
|
||||||
|
.imageMemoryBarrierCount = static_cast<u32>(firstBarriers.size()),
|
||||||
|
.pImageMemoryBarriers = firstBarriers.data(),
|
||||||
|
});
|
||||||
|
|
||||||
// Render
|
// Render
|
||||||
eastl::array attachmentInfos = {
|
eastl::array attachmentInfos = {
|
||||||
|
|
@ -589,19 +534,13 @@ main(int, char **)
|
||||||
.pDepthAttachment = &depthAttachment,
|
.pDepthAttachment = &depthAttachment,
|
||||||
};
|
};
|
||||||
|
|
||||||
cmd.beginRendering(&renderingInfo);
|
context.BeginRendering(renderingInfo);
|
||||||
|
|
||||||
cmd.setViewport(0, 1, &viewport);
|
context.SetViewport(viewport);
|
||||||
cmd.setScissor(0, 1, &scissor);
|
|
||||||
cmd.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipeline.m_Layout, 0, 1,
|
|
||||||
&commitManager.GetDescriptorSet(), 0, nullptr);
|
|
||||||
|
|
||||||
cmd.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipeline.m_Layout, 1, 1, &perFrameDescriptor, 0,
|
context.BindIndexBuffer(model.m_IndexBuffer);
|
||||||
nullptr);
|
|
||||||
|
|
||||||
cmd.bindIndexBuffer(model.m_IndexBuffer->m_Buffer, 0, vk::IndexType::eUint32);
|
context.BindPipeline(pipeline);
|
||||||
|
|
||||||
cmd.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline.m_Pipeline);
|
|
||||||
|
|
||||||
u32 flags = 0;
|
u32 flags = 0;
|
||||||
if (useSpecular)
|
if (useSpecular)
|
||||||
|
|
@ -622,32 +561,33 @@ main(int, char **)
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 pcbOffset = 0;
|
u32 pcbOffset = 0;
|
||||||
cmd.pushConstants(pipeline.m_Layout, vk::ShaderStageFlagBits::eAll, pcbOffset, sizeof model.m_Handles,
|
context.PushConstantBlock(model.m_Handles);
|
||||||
&model.m_Handles);
|
|
||||||
pcbOffset += sizeof model.m_Handles;
|
pcbOffset += sizeof model.m_Handles;
|
||||||
cmd.pushConstants(pipeline.m_Layout, vk::ShaderStageFlagBits::eAll, pcbOffset, sizeof flags, &flags);
|
context.PushConstantBlock(pcbOffset, cameraBufferId);
|
||||||
|
pcbOffset += sizeof cameraBufferId;
|
||||||
|
context.PushConstantBlock(pcbOffset, lightsBufferId);
|
||||||
|
pcbOffset += sizeof lightsBufferId;
|
||||||
|
context.PushConstantBlock(pcbOffset, flags);
|
||||||
pcbOffset += sizeof flags;
|
pcbOffset += sizeof flags;
|
||||||
|
|
||||||
for (auto &prim : model.m_MeshPrimitives)
|
for (auto &prim : model.m_MeshPrimitives)
|
||||||
{
|
{
|
||||||
u32 innerPcbOffset = pcbOffset;
|
u32 innerPcbOffset = pcbOffset;
|
||||||
cmd.pushConstants(pipeline.m_Layout, vk::ShaderStageFlagBits::eAll, innerPcbOffset,
|
context.PushConstantBlock(innerPcbOffset, prim.m_MaterialIdx);
|
||||||
sizeof prim.m_MaterialIdx, &prim.m_MaterialIdx);
|
|
||||||
innerPcbOffset += sizeof prim.m_MaterialIdx;
|
innerPcbOffset += sizeof prim.m_MaterialIdx;
|
||||||
cmd.pushConstants(pipeline.m_Layout, vk::ShaderStageFlagBits::eAll, innerPcbOffset,
|
context.PushConstantBlock(innerPcbOffset, prim.m_TransformIdx);
|
||||||
sizeof prim.m_TransformIdx, &prim.m_TransformIdx);
|
|
||||||
innerPcbOffset += sizeof prim.m_TransformIdx;
|
innerPcbOffset += sizeof prim.m_TransformIdx;
|
||||||
cmd.drawIndexed(prim.m_IndexCount, 1, prim.m_FirstIndex, static_cast<i32>(prim.m_VertexOffset), 0);
|
context.DrawIndexed(prim.m_IndexCount, prim.m_FirstIndex, prim.m_VertexOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.bindPipeline(vk::PipelineBindPoint::eGraphics, backGroundPipeline.m_Pipeline);
|
context.BindPipeline(backgroundPipeline);
|
||||||
cmd.draw(3, 1, 0, 0);
|
context.Draw(3);
|
||||||
|
|
||||||
cmd.endRendering();
|
context.EndRendering();
|
||||||
|
|
||||||
cmd.pipelineBarrier2(&postRenderDependencies);
|
context.Dependency({.imageMemoryBarrierCount = 1, .pImageMemoryBarriers = &attachmentRenderToBlitBarrier});
|
||||||
|
|
||||||
vk::ImageBlit blitRegion = {
|
vk::ImageBlit2 blitRegion = {
|
||||||
.srcSubresource =
|
.srcSubresource =
|
||||||
{
|
{
|
||||||
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||||
|
|
@ -670,33 +610,31 @@ main(int, char **)
|
||||||
.dstOffsets =
|
.dstOffsets =
|
||||||
std::array{
|
std::array{
|
||||||
vk::Offset3D{0, 0, 0},
|
vk::Offset3D{0, 0, 0},
|
||||||
vk::Offset3D{static_cast<i32>(swapchain.m_Extent.width), static_cast<i32>(swapchain.m_Extent.height), 1},
|
vk::Offset3D{static_cast<i32>(swapchainSize.m_Width), static_cast<i32>(swapchainSize.m_Height), 1},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
cmd.blitImage(currentImage, postRenderBarriers[0].newLayout, currentSwapchainImage,
|
|
||||||
postRenderBarriers[1].newLayout, 1, &blitRegion, vk::Filter::eLinear);
|
|
||||||
|
|
||||||
cmd.pipelineBarrier2(&preGuiDependencies);
|
vk::BlitImageInfo2 blit = {
|
||||||
|
.srcImage = currentImage,
|
||||||
gui::Draw(cmd, swapchain.m_Extent, currentSwapchainImageView);
|
.srcImageLayout = vk::ImageLayout::eTransferSrcOptimal,
|
||||||
|
.dstImage = currentSwapchainImage,
|
||||||
cmd.pipelineBarrier2(&prePresentDependencies);
|
.dstImageLayout = vk::ImageLayout::eTransferDstOptimal,
|
||||||
|
.regionCount = 1,
|
||||||
AbortIfFailed(cmd.end());
|
.pRegions = &blitRegion,
|
||||||
|
.filter = vk::Filter::eLinear,
|
||||||
vk::PipelineStageFlags waitDstStage = vk::PipelineStageFlagBits::eTransfer;
|
|
||||||
vk::SubmitInfo submitInfo = {
|
|
||||||
.waitSemaphoreCount = 1,
|
|
||||||
.pWaitSemaphores = ¤tFrame->m_ImageAcquireSem,
|
|
||||||
.pWaitDstStageMask = &waitDstStage,
|
|
||||||
.commandBufferCount = 1,
|
|
||||||
.pCommandBuffers = &cmd,
|
|
||||||
.signalSemaphoreCount = 1,
|
|
||||||
.pSignalSemaphores = ¤tFrame->m_RenderFinishSem,
|
|
||||||
};
|
};
|
||||||
AbortIfFailed(graphicsQueue.submit(1, &submitInfo, currentFrame->m_FrameAvailableFence));
|
|
||||||
|
|
||||||
currentFrame->Present(graphicsQueue, &swapchain, &surface, window.GetSize());
|
context.Blit(blit);
|
||||||
|
|
||||||
|
context.Dependency({.imageMemoryBarrierCount = 1, .pImageMemoryBarriers = &swapchainBlitToGuiBarrier});
|
||||||
|
|
||||||
|
gui::Draw(currentFrame, context);
|
||||||
|
|
||||||
|
context.Dependency({.imageMemoryBarrierCount = 1, .pImageMemoryBarriers = &swapchainPrePresentBarrier});
|
||||||
|
|
||||||
|
context.End();
|
||||||
|
|
||||||
|
device.Present(currentFrame, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
device.WaitIdle();
|
device.WaitIdle();
|
||||||
|
|
@ -704,9 +642,7 @@ main(int, char **)
|
||||||
pipelineCacheData = device.DumpPipelineCache();
|
pipelineCacheData = device.DumpPipelineCache();
|
||||||
ERROR_IF(!WriteFileBytes(PIPELINE_CACHE_FILE, pipelineCacheData), "Pipeline Cache incorrectly written");
|
ERROR_IF(!WriteFileBytes(PIPELINE_CACHE_FILE, pipelineCacheData), "Pipeline Cache incorrectly written");
|
||||||
|
|
||||||
gui::Destroy(&device);
|
gui::Destroy(device);
|
||||||
|
|
||||||
device.m_Device.destroy(descriptorPool, nullptr);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -11,6 +11,7 @@
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
|
|
||||||
#include "aster/systems/commit_manager.h"
|
#include "aster/systems/commit_manager.h"
|
||||||
|
#include "aster/util/files.h"
|
||||||
|
|
||||||
#include <EASTL/array.h>
|
#include <EASTL/array.h>
|
||||||
|
|
||||||
|
|
@ -172,7 +173,7 @@ CreatePipeline(const Device *device, vk::Format attachmentFormat, const systems:
|
||||||
device->m_Device.destroy(vertexShaderModule, nullptr);
|
device->m_Device.destroy(vertexShaderModule, nullptr);
|
||||||
device->m_Device.destroy(fragmentShaderModule, nullptr);
|
device->m_Device.destroy(fragmentShaderModule, nullptr);
|
||||||
|
|
||||||
return {device, pipelineLayout, pipeline, std::move(descriptorSetLayouts)};
|
return {device, pipelineLayout, pipeline, std::move(descriptorSetLayouts), Pipeline::Kind::eGraphics};
|
||||||
}
|
}
|
||||||
|
|
||||||
Pipeline
|
Pipeline
|
||||||
|
|
@ -333,7 +334,7 @@ CreateBackgroundPipeline(const Device *device, vk::Format attachmentFormat, cons
|
||||||
device->m_Device.destroy(vertexShaderModule, nullptr);
|
device->m_Device.destroy(vertexShaderModule, nullptr);
|
||||||
device->m_Device.destroy(fragmentShaderModule, nullptr);
|
device->m_Device.destroy(fragmentShaderModule, nullptr);
|
||||||
|
|
||||||
return {device, pipelineLayout, pipeline, std::move(descriptorSetLayouts)};
|
return {device, pipelineLayout, pipeline, std::move(descriptorSetLayouts), Pipeline::Kind::eGraphics};
|
||||||
}
|
}
|
||||||
|
|
||||||
vk::ShaderModule
|
vk::ShaderModule
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,57 @@
|
||||||
|
import bindless;
|
||||||
|
import ibl_common;
|
||||||
|
import common_structs;
|
||||||
|
|
||||||
|
const static float3 trianglePoints[] = {
|
||||||
|
float3(-1.0f, -1.0f, 1.0f),
|
||||||
|
float3(3.0f, -1.0f, 1.0f),
|
||||||
|
float3(-1.0f, 3.0f, 1.0f),
|
||||||
|
};
|
||||||
|
|
||||||
|
[vk::push_constant]
|
||||||
|
uniform Block pcb;
|
||||||
|
|
||||||
|
struct VS_Output
|
||||||
|
{
|
||||||
|
float4 vertexPosition : SV_Position;
|
||||||
|
float3 worldPosition : World_Position;
|
||||||
|
};
|
||||||
|
|
||||||
|
[shader("vertex")]
|
||||||
|
VS_Output vsmain(
|
||||||
|
uint vertexId : SV_VertexID
|
||||||
|
)
|
||||||
|
{
|
||||||
|
VS_Output stageOutput;
|
||||||
|
stageOutput.vertexPosition = float4(trianglePoints[vertexId], 1.0f);
|
||||||
|
|
||||||
|
float4 clipSpace = mul(float4(trianglePoints[vertexId], 1.0f), pcb.camera[0].invProj);
|
||||||
|
float4 worldSpace = mul(clipSpace / clipSpace.wwww, pcb.camera[0].invView);
|
||||||
|
stageOutput.worldPosition = worldSpace.xyz;
|
||||||
|
|
||||||
|
return stageOutput;
|
||||||
|
}
|
||||||
|
|
||||||
|
[shader("fragment")]
|
||||||
|
float4 fsmain(float3 worldPosition: World_Position) : SV_Target0
|
||||||
|
{
|
||||||
|
float3 direction = normalize(worldPosition - pcb.camera[0].position.xyz);
|
||||||
|
#ifndef _DEBUG
|
||||||
|
float4 color = pcb.lights[0].environment.Sample(direction);
|
||||||
|
#else
|
||||||
|
float4 color;
|
||||||
|
if (pcb.showDiffuse)
|
||||||
|
{
|
||||||
|
color = pcb.lights[0].diffuseIrradiance.Sample(direction);
|
||||||
|
}
|
||||||
|
else if (pcb.showPrefilter)
|
||||||
|
{
|
||||||
|
color = pcb.lights[0].prefilter.Sample(direction);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
color = pcb.lights[0].environment.Sample(direction);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return float4(Uncharted2Tonemap(color.rgb), color.a);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
[vk::binding(0, 0)] __DynamicResource<__DynamicResourceKind.General> gBuffers[];
|
||||||
|
[vk::binding(1, 0)] __DynamicResource<__DynamicResourceKind.Sampler> gSamplers[];
|
||||||
|
[vk::binding(2, 0)] __DynamicResource<__DynamicResourceKind.General> gStorageTextures[];
|
||||||
|
|
||||||
|
bool IsValid<T>(DescriptorHandle<T> handle) where T : IOpaqueDescriptor
|
||||||
|
{
|
||||||
|
var handleVal = (uint2)handle;
|
||||||
|
return handleVal.x != 0xFFFFFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
export T getDescriptorFromHandle<T>(DescriptorHandle<T> handle) where T : IOpaqueDescriptor
|
||||||
|
{
|
||||||
|
__target_switch
|
||||||
|
{
|
||||||
|
case spirv:
|
||||||
|
switch (T.kind) {
|
||||||
|
case DescriptorKind.Buffer:
|
||||||
|
return gBuffers[((uint2)handle).x].asOpaqueDescriptor<T>();
|
||||||
|
case DescriptorKind.CombinedTextureSampler:
|
||||||
|
return gSamplers[((uint2)handle).x].asOpaqueDescriptor<T>();
|
||||||
|
case DescriptorKind.Texture:
|
||||||
|
return gStorageTextures[((uint2)handle).x].asOpaqueDescriptor<T>();
|
||||||
|
default:
|
||||||
|
return defaultGetDescriptorFromHandle(handle);
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return defaultGetDescriptorFromHandle(handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,136 @@
|
||||||
|
static const float HALF_PI = 1.57079633f;
|
||||||
|
static const float PI = 3.14159265f;
|
||||||
|
static const float TAU = 6.28318530f;
|
||||||
|
|
||||||
|
struct VertexData
|
||||||
|
{
|
||||||
|
float4 normal;
|
||||||
|
float2 uv0;
|
||||||
|
float2 uv1;
|
||||||
|
float4 color0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TransformData
|
||||||
|
{
|
||||||
|
float4x4 transform;
|
||||||
|
float4x4 normalTransform;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MaterialData
|
||||||
|
{
|
||||||
|
float4 albedoFactor;
|
||||||
|
float4 emissionFactor;
|
||||||
|
Sampler2D.Handle albedoTex;
|
||||||
|
Sampler2D.Handle normalTex;
|
||||||
|
Sampler2D.Handle metalRoughTex;
|
||||||
|
Sampler2D.Handle occlusionTex;
|
||||||
|
Sampler2D.Handle emissionTex;
|
||||||
|
float metalFactor;
|
||||||
|
float roughFactor;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PointLight
|
||||||
|
{
|
||||||
|
float3 Position; // 12
|
||||||
|
float Range; // 16
|
||||||
|
uint Color; // 20
|
||||||
|
float Intensity; // 24
|
||||||
|
uint pad0;
|
||||||
|
uint pad1;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DirectionalLight
|
||||||
|
{
|
||||||
|
float3 Direction;
|
||||||
|
float Validity_;
|
||||||
|
uint Color;
|
||||||
|
float Intensity;
|
||||||
|
uint pad0;
|
||||||
|
uint pad1;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CameraData
|
||||||
|
{
|
||||||
|
float4x4 view; // 64
|
||||||
|
float4x4 proj; // 128
|
||||||
|
float4x4 invView; // 192
|
||||||
|
float4x4 invProj; // 256
|
||||||
|
float4 position; // 272
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Indexer
|
||||||
|
{
|
||||||
|
uint16_t count;
|
||||||
|
uint16_t offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Lighting
|
||||||
|
{
|
||||||
|
SamplerCube.Handle environment; // 8
|
||||||
|
SamplerCube.Handle diffuseIrradiance; // 16
|
||||||
|
SamplerCube.Handle prefilter; // 24
|
||||||
|
Sampler2D<float2>.Handle brdfLUT; // 32
|
||||||
|
ByteAddressBuffer.Handle lights; // 40
|
||||||
|
Indexer pointLightIndexer; // 44
|
||||||
|
Indexer dirLightIndexer; // 48
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Block
|
||||||
|
{
|
||||||
|
static const uint USE_DIFFUSE_BIT = 1;
|
||||||
|
static const uint USE_SPECULAR_BIT = 2;
|
||||||
|
static const uint SHOW_DIFFUSE_BIT = 4;
|
||||||
|
static const uint SHOW_PREFILTER_BIT = 8;
|
||||||
|
|
||||||
|
StructuredBuffer<float4>.Handle vertexBuffer; // 8
|
||||||
|
StructuredBuffer<VertexData>.Handle vertexData; // 16
|
||||||
|
StructuredBuffer<MaterialData>.Handle materialBuffer; // 24
|
||||||
|
StructuredBuffer<TransformData>.Handle nodeBuffer; // 32
|
||||||
|
StructuredBuffer<CameraData>.Handle camera; // 40
|
||||||
|
StructuredBuffer<Lighting>.Handle lights; // 48
|
||||||
|
|
||||||
|
uint debugFlags; // 52
|
||||||
|
|
||||||
|
int materialIdx; // 56
|
||||||
|
uint nodeIdx; // 60
|
||||||
|
|
||||||
|
property ignoreDiffuse : bool
|
||||||
|
{
|
||||||
|
get {
|
||||||
|
return (debugFlags & USE_DIFFUSE_BIT) == 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
property ignoreSpecular : bool
|
||||||
|
{
|
||||||
|
get {
|
||||||
|
return (debugFlags & USE_SPECULAR_BIT) == 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
property showDiffuse : bool
|
||||||
|
{
|
||||||
|
get {
|
||||||
|
return (debugFlags & SHOW_DIFFUSE_BIT) != 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
property showPrefilter : bool
|
||||||
|
{
|
||||||
|
get {
|
||||||
|
return (debugFlags & SHOW_PREFILTER_BIT) != 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
float3 Uncharted2Tonemap(float3 color)
|
||||||
|
{
|
||||||
|
float A = 0.15f;
|
||||||
|
float B = 0.50f;
|
||||||
|
float C = 0.10f;
|
||||||
|
float D = 0.20f;
|
||||||
|
float E = 0.02f;
|
||||||
|
float F = 0.30f;
|
||||||
|
float W = 11.2f;
|
||||||
|
return ((color * (A * color + C * B) + D * E) / (color * (A * color + B) + D * F)) - E / F;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,114 @@
|
||||||
|
import bindless;
|
||||||
|
import common_structs;
|
||||||
|
import ibl_common;
|
||||||
|
|
||||||
|
/*
|
||||||
|
| Axis | Layer | Up |
|
||||||
|
|:----:|:-----:|:--:|
|
||||||
|
| +x | 0 | -y |
|
||||||
|
| -x | 1 | -y |
|
||||||
|
| +y | 2 | +z |
|
||||||
|
| -y | 3 | -z |
|
||||||
|
| -z | 4 | -y |
|
||||||
|
| +z | 5 | -y |
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct DiffuseBlock {
|
||||||
|
SamplerCube<float4>.Handle skybox;
|
||||||
|
RWTexture2DArray<float4>.Handle outputTexture;
|
||||||
|
uint cubeSide;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
[shader("compute")]
|
||||||
|
[numthreads(16, 16, 1)]
|
||||||
|
void diffuseIrradiance(
|
||||||
|
uint3 GlobalInvocationID: SV_DispatchThreadID,
|
||||||
|
uniform DiffuseBlock diffusePcb,
|
||||||
|
)
|
||||||
|
{
|
||||||
|
float3 Forward, Up, Right;
|
||||||
|
|
||||||
|
Forward = GetCubeDir(GlobalInvocationID, diffusePcb.cubeSide);
|
||||||
|
Up = abs(Forward.y) < 1.0f ? float3(0.0f, 1.0f, 0.0f) : float3(1.0f, 0.0f, 0.0f); // 0.01f offset to
|
||||||
|
Right = normalize(cross(Up, Forward));
|
||||||
|
Up = normalize(cross(Forward, Right));
|
||||||
|
|
||||||
|
float3 Irradiance = 0.0f.xxx;
|
||||||
|
float3 IrrDirr = 0.0f.xxx;
|
||||||
|
float SampleStep = 0.005f;
|
||||||
|
float SampleCount = 0.0f;
|
||||||
|
|
||||||
|
for (float Azimuth = 0.0f; Azimuth < TAU; Azimuth += SampleStep)
|
||||||
|
{
|
||||||
|
for (float Zenith = 0.0f; Zenith < HALF_PI; Zenith += SampleStep)
|
||||||
|
{
|
||||||
|
float3 DirectionTanSpace = float3(sin(Zenith) * cos(Azimuth), sin(Zenith) * sin(Azimuth), cos(Zenith));
|
||||||
|
float3 DirectionWorld = DirectionTanSpace.x * Right + DirectionTanSpace.y * Up + DirectionTanSpace.z * Forward;
|
||||||
|
|
||||||
|
Irradiance += diffusePcb.skybox.SampleLevel(DirectionWorld, 0).xyz * (cos(Zenith) * sin(Zenith));
|
||||||
|
SampleCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
diffusePcb.outputTexture[GlobalInvocationID.xyz] = PI * float4(Irradiance * (1.0f / SampleCount), 1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct PrefilterBlock {
|
||||||
|
SamplerCube<float4>.Handle skybox;
|
||||||
|
RWTexture2DArray<float4>.Handle outputTexture;
|
||||||
|
uint cubeSide;
|
||||||
|
float roughness;
|
||||||
|
uint envRes;
|
||||||
|
};
|
||||||
|
|
||||||
|
[shader("compute")]
|
||||||
|
[numthreads(16, 16, 1)]
|
||||||
|
void prefilter(uint3 GlobalInvocationID: SV_DispatchThreadID, uniform PrefilterBlock prefilterPcb)
|
||||||
|
{
|
||||||
|
float3 Normal = GetCubeDir(GlobalInvocationID, prefilterPcb.cubeSide);
|
||||||
|
float3 ViewDir = Normal;
|
||||||
|
|
||||||
|
const uint SAMPLE_COUNT = 2048u;
|
||||||
|
float TotalWeight = 0.0f;
|
||||||
|
float3 PrefilterColor = 0.0f.xxx;
|
||||||
|
for (uint i = 0u; i < SAMPLE_COUNT; ++i)
|
||||||
|
{
|
||||||
|
float2 Xi = Hammersley(i, SAMPLE_COUNT);
|
||||||
|
float3 Halfway = ImportanceSampleGGX(Xi, Normal, prefilterPcb.roughness);
|
||||||
|
float3 LightDir = normalize(2.0 * dot(ViewDir, Halfway) * Halfway - ViewDir);
|
||||||
|
|
||||||
|
float NdotH = max(dot(Normal, Halfway), 0.0f);
|
||||||
|
|
||||||
|
float MipLevel = GetSampleMipLevel(NdotH, NdotH /* N = V :: NdotH = HdotV */, SAMPLE_COUNT, prefilterPcb.roughness, prefilterPcb.envRes);
|
||||||
|
|
||||||
|
float NdotL = max(dot(Normal, LightDir), 0.0);
|
||||||
|
if (NdotL > 0.0)
|
||||||
|
{
|
||||||
|
PrefilterColor += prefilterPcb.skybox.SampleLevel(LightDir, MipLevel).rgb * NdotL;
|
||||||
|
TotalWeight += NdotL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PrefilterColor = PrefilterColor / TotalWeight;
|
||||||
|
|
||||||
|
prefilterPcb.outputTexture[GlobalInvocationID] = float4(PrefilterColor, 1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct BrdfBlock {
|
||||||
|
RWTexture2D<float2>.Handle outputTexture;
|
||||||
|
};
|
||||||
|
|
||||||
|
[shader("compute")]
|
||||||
|
[numthreads(16, 16, 1)]
|
||||||
|
void brdfLut(
|
||||||
|
uint3 GlobalInvocationID: SV_DispatchThreadID,
|
||||||
|
uniform BrdfBlock brdfPcb)
|
||||||
|
{
|
||||||
|
float Width, Height;
|
||||||
|
brdfPcb.outputTexture.GetDimensions(Width, Height);
|
||||||
|
|
||||||
|
float2 UV = GlobalInvocationID.xy / float2(Width, Height);
|
||||||
|
|
||||||
|
float2 IntegratedBRDF = IntegrateBRDF(UV.x, UV.y);
|
||||||
|
brdfPcb.outputTexture[GlobalInvocationID.xy] = IntegratedBRDF;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
import bindless;
|
||||||
|
import ibl_common;
|
||||||
|
|
||||||
|
float2 SampleSphericalMap(float3 v)
|
||||||
|
{
|
||||||
|
const float2 InvTan = float2(0.1591f, 0.3183f); // (1/2PI, 1/PI)
|
||||||
|
float2 UV = float2(atan2(-v.x, v.z), asin(-v.y)); // (-PI, -PI/2) to (PI, PI/2)
|
||||||
|
UV *= InvTan; // (-1/2, -1/2) to (1/2, 1/2)
|
||||||
|
UV += 0.5f.xx; // (0, 0) to (1, 1)
|
||||||
|
return UV;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Block {
|
||||||
|
Sampler2D<float4>.Handle hdrEnv;
|
||||||
|
RWTexture2DArray<float4>.Handle outputTexture;
|
||||||
|
uint cubeSide;
|
||||||
|
};
|
||||||
|
|
||||||
|
[shader("compute")]
|
||||||
|
[numthreads(16, 16, 1)]
|
||||||
|
void main(
|
||||||
|
uint3 GlobalInvocationID: SV_DispatchThreadID,
|
||||||
|
uniform Block pcb
|
||||||
|
)
|
||||||
|
{
|
||||||
|
float3 LocalDir = GetCubeDir(GlobalInvocationID, pcb.cubeSide);
|
||||||
|
|
||||||
|
float2 UV = SampleSphericalMap(LocalDir);
|
||||||
|
|
||||||
|
pcb.outputTexture[GlobalInvocationID.xyz] = pcb.hdrEnv.SampleLevel(UV, 0);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,151 @@
|
||||||
|
import common_structs;
|
||||||
|
|
||||||
|
float3 GetCubeDir(uint3 GlobalInvocationID, float SideLength)
|
||||||
|
{
|
||||||
|
float2 FaceUV = float2(GlobalInvocationID.xy) / SideLength; // (0, SideLength) -> (0, 1)
|
||||||
|
FaceUV = 2.0f * FaceUV - 1.0f; // (0, 1) -> (-1, 1)
|
||||||
|
|
||||||
|
switch (GlobalInvocationID.z)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return normalize(float3(1.0f, -FaceUV.y, -FaceUV.x)); // Face +X; x = 1, y = -v, z = -u
|
||||||
|
case 1:
|
||||||
|
return normalize(float3(-1.0f, -FaceUV.y, FaceUV.x)); // Face -X; x = -1, y = -v, z = u
|
||||||
|
case 2:
|
||||||
|
return normalize(float3(FaceUV.x, 1.0f, FaceUV.y)); // Face +Y; x = u, y = 1, z = v
|
||||||
|
case 3:
|
||||||
|
return normalize(float3(FaceUV.x, -1.0f, -FaceUV.y)); // Face -Y; x=u, y=-1, z=-v
|
||||||
|
case 4:
|
||||||
|
return normalize(float3(FaceUV.x, -FaceUV.y, 1.0f)); // Face +Z; x=u,y=-v, z=1
|
||||||
|
case 5:
|
||||||
|
return normalize(float3(-FaceUV.x, -FaceUV.y, -1.0f)); // Face -Z; x=u,y=-v, z=-1
|
||||||
|
default:
|
||||||
|
// Never reach here.
|
||||||
|
return 0.0f.xxx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float RadicalInverse_VdC(uint Bits)
|
||||||
|
{
|
||||||
|
Bits = (Bits << 16u) | (Bits >> 16u);
|
||||||
|
Bits = ((Bits & 0x55555555u) << 1u) | ((Bits & 0xAAAAAAAAu) >> 1u);
|
||||||
|
Bits = ((Bits & 0x33333333u) << 2u) | ((Bits & 0xCCCCCCCCu) >> 2u);
|
||||||
|
Bits = ((Bits & 0x0F0F0F0Fu) << 4u) | ((Bits & 0xF0F0F0F0u) >> 4u);
|
||||||
|
Bits = ((Bits & 0x00FF00FFu) << 8u) | ((Bits & 0xFF00FF00u) >> 8u);
|
||||||
|
return float(Bits) * 2.3283064365386963e-10; // / 0x100000000
|
||||||
|
}
|
||||||
|
|
||||||
|
float2 Hammersley(uint SampleIndex, uint SampleCount)
|
||||||
|
{
|
||||||
|
return float2(float(SampleIndex) / float(SampleCount), RadicalInverse_VdC(SampleIndex));
|
||||||
|
}
|
||||||
|
|
||||||
|
float3 ImportanceSampleGGX(float2 Xi, float3 Normal, float Roughness)
|
||||||
|
{
|
||||||
|
float A = Roughness * Roughness;
|
||||||
|
|
||||||
|
float Phi = 2.0f * PI * Xi.x;
|
||||||
|
float CosTheta = sqrt((1.0f - Xi.y) / (1.0f + (A * A - 1.0f) * Xi.y));
|
||||||
|
float SinTheta = sqrt(1.0f - CosTheta * CosTheta);
|
||||||
|
|
||||||
|
// from spherical coordinates to cartesian coordinates
|
||||||
|
float3 H;
|
||||||
|
H.x = cos(Phi) * SinTheta;
|
||||||
|
H.y = sin(Phi) * SinTheta;
|
||||||
|
H.z = CosTheta;
|
||||||
|
|
||||||
|
// from tangent-space vector to world-space sample vector
|
||||||
|
float3 Up = abs(Normal.z) < 0.999f ? float3(0.0f, 0.0f, 1.0f) : float3(1.0f, 0.0f, 0.0f);
|
||||||
|
float3 Tangent = normalize(cross(Up, Normal));
|
||||||
|
float3 Bitangent = cross(Normal, Tangent);
|
||||||
|
|
||||||
|
float3 SampleVec = Tangent * H.x + Bitangent * H.y + Normal * H.z;
|
||||||
|
return normalize(SampleVec);
|
||||||
|
}
|
||||||
|
|
||||||
|
float TrowbridgeReitzGGX(float NdotH, float Roughness)
|
||||||
|
{
|
||||||
|
float NdotH = max(NdotH, 0.0f);
|
||||||
|
|
||||||
|
float Coeff = Roughness * Roughness;
|
||||||
|
float Alpha2 = Coeff * Coeff;
|
||||||
|
float NdotH2 = NdotH * NdotH;
|
||||||
|
|
||||||
|
float Numerator = Alpha2;
|
||||||
|
float Denominator = NdotH2 * (Alpha2 - 1.0f) + 1.0f;
|
||||||
|
Denominator = PI * Denominator * Denominator;
|
||||||
|
|
||||||
|
return Numerator / Denominator;
|
||||||
|
}
|
||||||
|
|
||||||
|
float GetSampleMipLevel(float NdotH, float HdotV, float SampleCount, float roughness, float envRes)
|
||||||
|
{
|
||||||
|
float D = TrowbridgeReitzGGX(NdotH, roughness);
|
||||||
|
float Pdf = (D * NdotH / (4.0f * HdotV)) + 0.0001f;
|
||||||
|
|
||||||
|
float SurfAreaTexel = 4.0f * PI / (6.0f * envRes * envRes);
|
||||||
|
float SurfAreaSample = 1.0f / (SampleCount * Pdf + 0.0001f);
|
||||||
|
|
||||||
|
return roughness == 0.0f ? 0.0f : 0.5f * log2(SurfAreaSample / SurfAreaTexel);
|
||||||
|
}
|
||||||
|
|
||||||
|
float GeometrySchlickGGX(float NdotV, float Roughness)
|
||||||
|
{
|
||||||
|
float R = Roughness;
|
||||||
|
// (Rough + 1)^2 / 8 for Punctual Lights
|
||||||
|
// Rough^2 / 2 for IBL
|
||||||
|
float K = (R * R) / 2.0;
|
||||||
|
|
||||||
|
float Numerator = NdotV;
|
||||||
|
float Denominator = NdotV * (1.0f - K) + K;
|
||||||
|
|
||||||
|
return Numerator / Denominator;
|
||||||
|
}
|
||||||
|
|
||||||
|
float GeometrySmith(float NdotV, float NdotL, float Roughness)
|
||||||
|
{
|
||||||
|
float GGX1 = GeometrySchlickGGX(NdotV, Roughness);
|
||||||
|
float GGX2 = GeometrySchlickGGX(NdotL, Roughness);
|
||||||
|
|
||||||
|
return GGX1 * GGX2;
|
||||||
|
}
|
||||||
|
|
||||||
|
float2 IntegrateBRDF(float NdotV, float Roughness)
|
||||||
|
{
|
||||||
|
float3 ViewDir;
|
||||||
|
ViewDir.x = sqrt(1.0f - NdotV * NdotV);
|
||||||
|
ViewDir.y = 0.0f;
|
||||||
|
ViewDir.z = NdotV;
|
||||||
|
|
||||||
|
float A = 0.0f;
|
||||||
|
float B = 0.0f;
|
||||||
|
|
||||||
|
float3 Normal = float3(0.0f, 0.0f, 1.0f);
|
||||||
|
|
||||||
|
const uint SAMPLE_COUNT = 1024u;
|
||||||
|
|
||||||
|
for (uint i = 0u; i < SAMPLE_COUNT; ++i)
|
||||||
|
{
|
||||||
|
float2 Xi = Hammersley(i, SAMPLE_COUNT);
|
||||||
|
float3 Halfway = ImportanceSampleGGX(Xi, Normal, Roughness);
|
||||||
|
float3 LightDir = normalize(2.0f * dot(ViewDir, Halfway) * Halfway - ViewDir);
|
||||||
|
|
||||||
|
float NdotL = max(LightDir.z, 0.0f);
|
||||||
|
float NdotH = max(Halfway.z, 0.0f);
|
||||||
|
float VdotH = max(dot(ViewDir, Halfway), 0.0f);
|
||||||
|
|
||||||
|
if (NdotL > 0.0f)
|
||||||
|
{
|
||||||
|
float G = GeometrySmith(NdotV, NdotL, Roughness);
|
||||||
|
float G_Vis = (G * VdotH) / max((NdotH * NdotV), 0.0001f);
|
||||||
|
float Fc = pow(1.0f - VdotH, 5.0f);
|
||||||
|
|
||||||
|
A += (1.0f - Fc) * G_Vis;
|
||||||
|
B += Fc * G_Vis;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
A /= float(SAMPLE_COUNT);
|
||||||
|
B /= float(SAMPLE_COUNT);
|
||||||
|
|
||||||
|
return float2(A, B);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,377 @@
|
||||||
|
import bindless;
|
||||||
|
import ibl_common;
|
||||||
|
import common_structs;
|
||||||
|
|
||||||
|
struct ModelHandles
|
||||||
|
{
|
||||||
|
StructuredBuffer<float4>.Handle vertexBuffer; // 8
|
||||||
|
StructuredBuffer<VertexData>.Handle vertexData; // 16
|
||||||
|
StructuredBuffer<MaterialData>.Handle materialBuffer; // 24
|
||||||
|
StructuredBuffer<TransformData>.Handle nodeBuffer; // 32
|
||||||
|
};
|
||||||
|
|
||||||
|
[vk::push_constant]
|
||||||
|
uniform Block pcb;
|
||||||
|
|
||||||
|
struct VS_Input
|
||||||
|
{
|
||||||
|
uint vertexId : SV_VertexID;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VS_Output
|
||||||
|
{
|
||||||
|
float4 worldPosition : POSITION;
|
||||||
|
float4 worldNormal : NORMAL;
|
||||||
|
float4 vertexColor : COLOR0;
|
||||||
|
float2 uv0 : TEXCOORD0;
|
||||||
|
float4 vertexPosition : SV_Position;
|
||||||
|
};
|
||||||
|
|
||||||
|
float2 GetUV(uint vertexId)
|
||||||
|
{
|
||||||
|
return pcb.vertexData[vertexId].uv0.xy;
|
||||||
|
}
|
||||||
|
|
||||||
|
float4 GetPosition(uint vertexId)
|
||||||
|
{
|
||||||
|
return float4(pcb.vertexBuffer[vertexId].xyz, 1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
float4 GetNormal(uint vertexId)
|
||||||
|
{
|
||||||
|
return pcb.vertexData[vertexId].normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
float4 GetColor(uint vertexId)
|
||||||
|
{
|
||||||
|
return pcb.vertexData[vertexId].color0;
|
||||||
|
}
|
||||||
|
|
||||||
|
float4x4 GetNodeTransform(uint nodeIdx)
|
||||||
|
{
|
||||||
|
return pcb.nodeBuffer[nodeIdx].transform;
|
||||||
|
}
|
||||||
|
|
||||||
|
float4x4 GetNormalTransform(uint nodeIdx)
|
||||||
|
{
|
||||||
|
return pcb.nodeBuffer[nodeIdx].normalTransform;
|
||||||
|
}
|
||||||
|
|
||||||
|
[shader("vertex")]
|
||||||
|
VS_Output vsmain(VS_Input stageInput)
|
||||||
|
{
|
||||||
|
VS_Output stageOutput;
|
||||||
|
|
||||||
|
float4 worldPosition = mul(GetPosition(stageInput.vertexId), GetNodeTransform(pcb.nodeIdx));
|
||||||
|
float4 clipSpace = mul(worldPosition, pcb.camera[0].view);
|
||||||
|
|
||||||
|
stageOutput.vertexPosition = mul(clipSpace, pcb.camera[0].proj);
|
||||||
|
stageOutput.worldPosition = worldPosition;
|
||||||
|
stageOutput.uv0 = GetUV(stageInput.vertexId);
|
||||||
|
stageOutput.vertexColor = GetColor(stageInput.vertexId);
|
||||||
|
|
||||||
|
stageOutput.worldNormal = mul(GetNormal(stageInput.vertexId), GetNormalTransform(pcb.nodeIdx));
|
||||||
|
return stageOutput;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct FS_Input
|
||||||
|
{
|
||||||
|
float4 InPosition : POSITION;
|
||||||
|
float4 InNormal : NORMAL;
|
||||||
|
float4 InColor : COLOR0;
|
||||||
|
float2 InUV0 : TEXCOORD0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FS_Output
|
||||||
|
{
|
||||||
|
float4 ColorTarget : SV_Target0;
|
||||||
|
};
|
||||||
|
|
||||||
|
float4 GetAlbedo(float2 uv, float4 color)
|
||||||
|
{
|
||||||
|
float4 albedoFactor = pcb.materialBuffer[NonUniformResourceIndex(pcb.materialIdx)].albedoFactor;
|
||||||
|
var albedoTex = pcb.materialBuffer[NonUniformResourceIndex(pcb.materialIdx)].albedoTex;
|
||||||
|
|
||||||
|
return albedoFactor * color * (IsValid(albedoTex) ? albedoTex.Sample(uv) : 1.0f.xxxx);
|
||||||
|
}
|
||||||
|
|
||||||
|
float GetOcclusion(float2 uv)
|
||||||
|
{
|
||||||
|
var occlusionTex = pcb.materialBuffer[NonUniformResourceIndex(pcb.materialIdx)].occlusionTex;
|
||||||
|
|
||||||
|
return IsValid(occlusionTex) ? occlusionTex.Sample(uv).r : 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
float3 GetEmissive(float2 uv)
|
||||||
|
{
|
||||||
|
float3 emissionFactor = pcb.materialBuffer[NonUniformResourceIndex(pcb.materialIdx)].emissionFactor.rgb;
|
||||||
|
var emissionTex = pcb.materialBuffer[NonUniformResourceIndex(pcb.materialIdx)].emissionTex;
|
||||||
|
|
||||||
|
return emissionFactor * (IsValid(emissionTex) ? emissionTex.Sample(uv).rgb : 1.0f.xxx);
|
||||||
|
}
|
||||||
|
|
||||||
|
float3 GetNormal(float3 position, float3 normal, float2 uv)
|
||||||
|
{
|
||||||
|
float3 N = normalize(normal);
|
||||||
|
|
||||||
|
var normalTex = pcb.materialBuffer[NonUniformResourceIndex(pcb.materialIdx)].normalTex;
|
||||||
|
if (!IsValid(normalTex))
|
||||||
|
{
|
||||||
|
return N;
|
||||||
|
}
|
||||||
|
|
||||||
|
float3 tangentSpaceNormal = normalTex.Sample(uv).xyz * 2.0f - 1.0f;
|
||||||
|
|
||||||
|
float3 q1 = ddx(position);
|
||||||
|
float3 q2 = ddy(position);
|
||||||
|
float2 st1 = ddx(uv);
|
||||||
|
float2 st2 = ddy(uv);
|
||||||
|
|
||||||
|
float3 T = normalize(q1 * st2.y - q2 * st1.y).xyz;
|
||||||
|
float3 B = -normalize(cross(N, T));
|
||||||
|
float3x3 TBN = float3x3(T, B, N); // Construction is Row by Row.
|
||||||
|
|
||||||
|
return normalize(mul(tangentSpaceNormal, TBN)); // Post multiple to avoid transpose.
|
||||||
|
}
|
||||||
|
|
||||||
|
float2 GetMetalRough(float2 uv)
|
||||||
|
{
|
||||||
|
var material = pcb.materialBuffer[NonUniformResourceIndex(pcb.materialIdx)];
|
||||||
|
float2 metalRough = float2(material.metalFactor, material.roughFactor);
|
||||||
|
var metalRoughTex = pcb.materialBuffer[NonUniformResourceIndex(pcb.materialIdx)].metalRoughTex;
|
||||||
|
|
||||||
|
return metalRough * (IsValid(metalRoughTex) ? metalRoughTex.Sample(uv).bg : 1.0f.xx); // Metal is B, Rough is G.
|
||||||
|
}
|
||||||
|
|
||||||
|
float3 SampleIrradiance(float3 direction)
|
||||||
|
{
|
||||||
|
var diffuseIrradiance = pcb.lights[0].diffuseIrradiance;
|
||||||
|
if (IsValid(diffuseIrradiance))
|
||||||
|
{
|
||||||
|
return diffuseIrradiance.Sample(direction).rgb;
|
||||||
|
}
|
||||||
|
return 0.04f.xxx;
|
||||||
|
}
|
||||||
|
|
||||||
|
float3 SamplePrefiltered(float3 direction, float roughness)
|
||||||
|
{
|
||||||
|
var prefilter = pcb.lights[0].prefilter;
|
||||||
|
if (!IsValid(prefilter))
|
||||||
|
return 0.0f.xxx;
|
||||||
|
|
||||||
|
const float MAX_MIP_LEVEL = 5.0f;
|
||||||
|
float mip = MAX_MIP_LEVEL * roughness;
|
||||||
|
|
||||||
|
return prefilter.SampleLevel(direction, mip).rgb;
|
||||||
|
}
|
||||||
|
|
||||||
|
float2 SampleBrdfLut(float nDotV, float roughness)
|
||||||
|
{
|
||||||
|
var brdfLut = pcb.lights[0].brdfLUT;
|
||||||
|
if (IsValid(brdfLut))
|
||||||
|
{
|
||||||
|
return brdfLut.Sample(float2(nDotV, roughness));
|
||||||
|
}
|
||||||
|
return 0.0f.xx;
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://en.wikipedia.org/wiki/Schlick%27s_approximation
|
||||||
|
float3 FresnelSchlick(float cosine, float3 F_0)
|
||||||
|
{
|
||||||
|
return F_0 + (1.0f - F_0) * pow(clamp(1.0f - cosine, 0.0f, 1.0f), 5.0f); // Clamp to avoid artifacts.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sebastian Lagarde
|
||||||
|
float3 FresnelSchlickRoughness(float cosine, float3 F_0, float Roughness)
|
||||||
|
{
|
||||||
|
return F_0 + (max((1.0f - Roughness).xxx, F_0) - F_0) * pow(clamp(1.0f - cosine, 0.0f, 1.0f), 5.0f); // Clamp to avoid artifacts.
|
||||||
|
}
|
||||||
|
|
||||||
|
float3 GetPBRContrib(float3 Albedo, float3 LightColor, float3 ViewDir, float3 Normal, float Metallic, float Roughness, float3 F_0, float3 LightDir, float LightDistance)
|
||||||
|
{
|
||||||
|
float Attenuation = 1.0f / (LightDistance * LightDistance); // TODO: Controlled Attenuation
|
||||||
|
float3 Halfway = normalize(ViewDir + LightDir);
|
||||||
|
|
||||||
|
// If the dot is negative, then it we just us 0.
|
||||||
|
// Light from the back is irrelevant.
|
||||||
|
float CosineFactor = max(dot(Halfway, ViewDir), 0.0f);
|
||||||
|
float NdotV = max(dot(Normal, ViewDir), 0.0f);
|
||||||
|
float NdotL = max(dot(Normal, LightDir), 0.0f);
|
||||||
|
float NdotH = max(dot(Normal, Halfway), 0.0f);
|
||||||
|
|
||||||
|
float3 Radiance = LightColor * Attenuation;
|
||||||
|
|
||||||
|
float NormalDistribution = TrowbridgeReitzGGX(NdotH, Roughness);
|
||||||
|
float Geometry = GeometrySmith(NdotV, NdotL, Roughness);
|
||||||
|
float3 Fresnel = FresnelSchlickRoughness(CosineFactor, F_0, Roughness);
|
||||||
|
|
||||||
|
float3 Numerator = (NormalDistribution * Geometry) * Fresnel;
|
||||||
|
float Denominator = 4.0f * NdotV * NdotL;
|
||||||
|
float3 Specular = Numerator / (Denominator + 0.00001f);
|
||||||
|
|
||||||
|
float3 K_Specular = Fresnel;
|
||||||
|
float3 K_Diffuse = 1.0f.xxx - K_Specular;
|
||||||
|
|
||||||
|
K_Diffuse *= 1.0f - Metallic;
|
||||||
|
|
||||||
|
return NdotL * Radiance * (K_Diffuse * Albedo / PI + Specular);
|
||||||
|
}
|
||||||
|
|
||||||
|
float3 GetPointLightInfluence(float3 Albedo, float2 MetalRough, float3 Position, float3 Normal)
|
||||||
|
{
|
||||||
|
var lightData = pcb.lights[0];
|
||||||
|
var pointLightBuffer = (StructuredBuffer<PointLight>.Handle)lightData.lights;
|
||||||
|
|
||||||
|
if (!IsValid(pointLightBuffer))
|
||||||
|
return 0.0f.xxx;
|
||||||
|
|
||||||
|
uint offset = lightData.pointLightIndexer.offset;
|
||||||
|
uint count = lightData.pointLightIndexer.count;
|
||||||
|
|
||||||
|
float3 ViewDir = normalize(pcb.camera[0].position.xyz - Position);
|
||||||
|
|
||||||
|
float Metallic = MetalRough.r;
|
||||||
|
float Roughness = MetalRough.g;
|
||||||
|
|
||||||
|
// Dielectric F_0 based on LearnOpenGL.
|
||||||
|
// TODO: Cite
|
||||||
|
float3 F_0 = 0.04f.xxx;
|
||||||
|
F_0 = lerp(F_0, Albedo, Metallic);
|
||||||
|
|
||||||
|
float3 Contrib = 0.0f;
|
||||||
|
for (uint i = 0; i < count; ++i)
|
||||||
|
{
|
||||||
|
PointLight Light = pointLightBuffer[i + offset];
|
||||||
|
|
||||||
|
if (Light.Range < 0.0f)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
float3 LightDir = Light.Position - Position;
|
||||||
|
float LightDistance = length(LightDir);
|
||||||
|
|
||||||
|
if (LightDistance > Light.Range)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
LightDir /= LightDistance; // Normalization
|
||||||
|
|
||||||
|
// Color Unpack
|
||||||
|
float R = (Light.Color & 0xFF000000) >> 24;
|
||||||
|
float G = (Light.Color & 0x00FF0000) >> 16;
|
||||||
|
float B = (Light.Color & 0x0000FF00) >> 8;
|
||||||
|
|
||||||
|
float3 LightColor = Light.Intensity * float3(R, G, B) * 0.00392156862f; // 0.00392156862 = 1/255
|
||||||
|
|
||||||
|
Contrib += GetPBRContrib(Albedo, LightColor, ViewDir, Normal, Metallic, Roughness, F_0, LightDir, LightDistance);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Contrib;
|
||||||
|
}
|
||||||
|
|
||||||
|
float3 GetDirectionalLightInfluence(float3 Albedo, float2 MetalRough, float3 Position, float3 Normal)
|
||||||
|
{
|
||||||
|
var lightData = pcb.lights[0];
|
||||||
|
var dirLightBuffer = (StructuredBuffer<DirectionalLight>.Handle)lightData.lights;
|
||||||
|
|
||||||
|
if (!IsValid(dirLightBuffer))
|
||||||
|
return 0.0f.xxx;
|
||||||
|
|
||||||
|
uint count = lightData.dirLightIndexer.count;
|
||||||
|
|
||||||
|
float3 ViewDir = normalize(pcb.camera[0].position.xyz - Position);
|
||||||
|
|
||||||
|
float Metallic = MetalRough.r;
|
||||||
|
float Roughness = MetalRough.g;
|
||||||
|
|
||||||
|
// Dielectric F_0 based on LearnOpenGL.
|
||||||
|
// TODO: Cite
|
||||||
|
float3 F_0 = 0.04f.xxx;
|
||||||
|
F_0 = lerp(F_0, Albedo, Metallic);
|
||||||
|
|
||||||
|
float3 Contrib = 0.0f;
|
||||||
|
for (uint i = 0; i < count; ++i)
|
||||||
|
{
|
||||||
|
DirectionalLight Light = dirLightBuffer[i];
|
||||||
|
|
||||||
|
if (Light.Validity_ < 0.0f)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
float3 LightDir = -normalize(float3(Light.Direction));
|
||||||
|
|
||||||
|
// Color Unpack
|
||||||
|
float R = (Light.Color & 0xFF000000) >> 24;
|
||||||
|
float G = (Light.Color & 0x00FF0000) >> 16;
|
||||||
|
float B = (Light.Color & 0x0000FF00) >> 8;
|
||||||
|
|
||||||
|
float3 LightColor = Light.Intensity * float3(R, G, B) * 0.00392156862f; // 0.00392156862 = 1/255
|
||||||
|
|
||||||
|
Contrib += GetPBRContrib(Albedo, LightColor, ViewDir, Normal, Metallic, Roughness, F_0, LightDir, 1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Contrib;
|
||||||
|
}
|
||||||
|
|
||||||
|
float3 GetAmbientInfluence(float3 Albedo, float2 MetalRough, float3 Position, float3 Normal, float Occlusion)
|
||||||
|
{
|
||||||
|
float3 ViewDir = normalize(pcb.camera[0].position.xyz - Position);
|
||||||
|
float CosineFactor = max(dot(Normal, ViewDir), 0.0f); // Normal instead of Halfway since there's no halfway in ambient.
|
||||||
|
|
||||||
|
float Metal = MetalRough.r;
|
||||||
|
float Roughness = MetalRough.g;
|
||||||
|
|
||||||
|
float3 F_0 = 0.04f.xxx;
|
||||||
|
F_0 = lerp(F_0, Albedo, MetalRough.r);
|
||||||
|
float3 K_Specular = FresnelSchlickRoughness(CosineFactor, F_0, Roughness);
|
||||||
|
float3 K_Diffuse = 1.0f.xxx - K_Specular;
|
||||||
|
|
||||||
|
K_Diffuse *= 1.0f - Metal; // Metals don't have diffuse/refractions.
|
||||||
|
|
||||||
|
float3 ReflectionDir = reflect(-ViewDir, Normal);
|
||||||
|
|
||||||
|
float NdotV = max(dot(Normal, ViewDir), 0.0f);
|
||||||
|
float3 PrefilteredColor = SamplePrefiltered(ReflectionDir, Roughness).rgb;
|
||||||
|
float2 EnvBRDF = SampleBrdfLut(NdotV, Roughness);
|
||||||
|
float3 Specular = PrefilteredColor * (K_Specular * EnvBRDF.x + EnvBRDF.y);
|
||||||
|
|
||||||
|
float3 DiffuseIrradiance = Albedo * SampleIrradiance(Normal);
|
||||||
|
#if defined(_DEBUG)
|
||||||
|
if (pcb.ignoreDiffuse) {
|
||||||
|
DiffuseIrradiance = 0.0f.xxx;
|
||||||
|
}
|
||||||
|
if (pcb.ignoreSpecular) {
|
||||||
|
Specular = 0.0f.xxx;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return (K_Diffuse * DiffuseIrradiance + Specular) * Occlusion;
|
||||||
|
}
|
||||||
|
|
||||||
|
[shader("fragment")]
|
||||||
|
FS_Output fsmain(FS_Input StageInput)
|
||||||
|
{
|
||||||
|
FS_Output Output;
|
||||||
|
|
||||||
|
// TODO: This should be invalid on the CPU side.
|
||||||
|
if (pcb.materialIdx < 0)
|
||||||
|
{
|
||||||
|
Output.ColorTarget = float4(1.0f, 0.0f, 1.0f, 1.0f);
|
||||||
|
return Output;
|
||||||
|
}
|
||||||
|
|
||||||
|
float3 Position = StageInput.InPosition.xyz;
|
||||||
|
float3 Normal = GetNormal(Position, StageInput.InNormal.xyz, StageInput.InUV0);
|
||||||
|
|
||||||
|
float4 AlbedoAlpha = GetAlbedo(StageInput.InUV0, StageInput.InColor);
|
||||||
|
float3 Albedo = AlbedoAlpha.rgb;
|
||||||
|
float Alpha = AlbedoAlpha.a;
|
||||||
|
float2 MetalRough = GetMetalRough(StageInput.InUV0);
|
||||||
|
float3 Emission = GetEmissive(StageInput.InUV0);
|
||||||
|
float Occlusion = GetOcclusion(StageInput.InUV0);
|
||||||
|
|
||||||
|
float3 DirectionalLightLum = GetDirectionalLightInfluence(Albedo, MetalRough, Position, Normal);
|
||||||
|
float3 PointLighLum = GetPointLightInfluence(Albedo, MetalRough, Position, Normal);
|
||||||
|
float3 AmbientLum = GetAmbientInfluence(Albedo, MetalRough, Position, Normal, Occlusion);
|
||||||
|
float3 Color = DirectionalLightLum + /*PointLighLum +*/ AmbientLum;
|
||||||
|
|
||||||
|
Output.ColorTarget = float4(Uncharted2Tonemap(Color + Emission), Alpha);
|
||||||
|
return Output;
|
||||||
|
}
|
||||||
|
|
@ -5,5 +5,5 @@ cmake_minimum_required(VERSION 3.13)
|
||||||
add_subdirectory("00_util")
|
add_subdirectory("00_util")
|
||||||
add_subdirectory("01_triangle")
|
add_subdirectory("01_triangle")
|
||||||
add_subdirectory("02_box")
|
add_subdirectory("02_box")
|
||||||
# add_subdirectory("03_model_render")
|
add_subdirectory("03_model_render")
|
||||||
# add_subdirectory("04_scenes")
|
# add_subdirectory("04_scenes")
|
||||||
|
|
|
||||||
2
vcpkg
2
vcpkg
|
|
@ -1 +1 @@
|
||||||
Subproject commit 0ca64b4e1c70fa6d9f53b369b8f3f0843797c20c
|
Subproject commit f26ec398c25c4980f33a50391f00a75f7ad62ef7
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"default-registry": {
|
"default-registry": {
|
||||||
"kind": "git",
|
"kind": "git",
|
||||||
"baseline": "41c447cc210dc39aa85d4a5f58b4a1b9e573b3dc",
|
"baseline": "f26ec398c25c4980f33a50391f00a75f7ad62ef7",
|
||||||
"repository": "https://github.com/microsoft/vcpkg"
|
"repository": "https://github.com/microsoft/vcpkg"
|
||||||
},
|
},
|
||||||
"registries": [
|
"registries": [
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@
|
||||||
"tinygltf",
|
"tinygltf",
|
||||||
"vulkan-memory-allocator",
|
"vulkan-memory-allocator",
|
||||||
"entt",
|
"entt",
|
||||||
"shader-slang"
|
"shader-slang",
|
||||||
|
"foonathan-memory"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue