Shader reflection added.

This commit is contained in:
Anish Bhobe 2025-05-10 18:00:25 +02:00
parent 3a7a2b4ab7
commit 41c91058b6
10 changed files with 578 additions and 157 deletions

View File

@ -52,8 +52,9 @@ constexpr u32 ASTER_API_VERSION = VK_API_VERSION_1_3;
#define Take(ELEMENT) eastl::exchange(ELEMENT, {})
#define TODO(MSG) assert(false && ("Unimplemented: " MSG))
#define FIX(MSG) static_assert(false && ("Unimplemented: " MSG))
#define TODO(...) assert(!("Unimplemented: " __VA_ARGS__))
#define FIX(...) static_assert(!("Unimplemented: " __VA_ARGS__))
#define UNREACHABLE(...) assert(!("Unreachable: " __VA_ARGS__))
#define AbortIfFailed(RESULT) \
do \
@ -67,7 +68,8 @@ constexpr u32 ASTER_API_VERSION = VK_API_VERSION_1_3;
do \
{ \
vk::Result _checkResultValue_; \
ERROR_IF(Failed(_checkResultValue_ = static_cast<vk::Result>(RESULT)), MSG " Cause: {}", EXTRA, _checkResultValue_) \
ERROR_IF(Failed(_checkResultValue_ = static_cast<vk::Result>(RESULT)), MSG " Cause: {}", EXTRA, \
_checkResultValue_) \
THEN_ABORT(_checkResultValue_); \
} while (false)
@ -221,15 +223,20 @@ GetMaskOffset(u32 val)
return count;
}
template <>
struct fmt::formatter<vk::Result> : nested_formatter<std::string>
template <typename T>
concept VkToString = requires(T a) {
{ vk::to_string(a) } -> std::convertible_to<std::string>;
};
template <VkToString T>
struct fmt::formatter<T> : nested_formatter<std::string>
{
auto
// ReSharper disable once CppInconsistentNaming
format(vk::Result result, format_context &ctx) const
format(T result, format_context &ctx) const
{
return write_padded(ctx,
[this, result](auto out) { return v11::format_to(out, "{}", nested(to_string(result))); });
[this, result](auto out) { return fmt::format_to(out, "{}", nested(to_string(result))); });
}
};

View File

@ -8,6 +8,8 @@
#include "global.h"
#include "surface.h"
#include <sstream>
#include <EASTL/fixed_vector.h>
struct Window;
@ -23,6 +25,31 @@ enum class QueueSupportFlagBits
using QueueSupportFlags = vk::Flags<QueueSupportFlagBits>;
inline std::string
// ReSharper disable once CppInconsistentNaming
format_as(const QueueSupportFlags &qfi)
{
std::stringstream sb;
if (qfi & QueueSupportFlagBits::eGraphics)
{
sb << "Graphics | ";
}
if (qfi & QueueSupportFlagBits::eTransfer)
{
sb << "Transfer | ";
}
if (qfi & QueueSupportFlagBits::eCompute)
{
sb << "Compute | ";
}
if (qfi & QueueSupportFlagBits::ePresent)
{
sb << "Present | ";
}
const auto sbv = sb.view();
return std::string(sbv.substr(0, sbv.size() - 3));
}
struct QueueFamilyInfo
{
u32 m_Index;
@ -30,6 +57,12 @@ struct QueueFamilyInfo
QueueSupportFlags m_Support;
};
inline std::string
format_as(const QueueFamilyInfo &qfi)
{
return fmt::format("Queue {}: Count={} Support={}", qfi.m_Index, qfi.m_Count, qfi.m_Support);
}
[[nodiscard]] vk::SurfaceCapabilitiesKHR
GetSurfaceCapabilities(vk::PhysicalDevice physicalDevice, vk::SurfaceKHR surface);

View File

@ -5,6 +5,7 @@
#pragma once
#include "pipeline_helpers.h"
#include "resource.h"
#include "aster/aster.h"
@ -231,59 +232,6 @@ struct SamplerCreateInfo
#pragma region Pipeline
// ----------------------------------------------------------------------------------------------------
struct PipelineCreationError
{
enum class Kind
{
eNone,
eVulkan,
eSlang,
} m_Kind;
union {
u32 uNone;
vk::Result uVulkanResult;
SlangResult uSlangResult;
};
operator bool() const
{
return m_Kind != Kind::eNone;
}
std::string
What()
{
switch (m_Kind)
{
case Kind::eNone:
return "No Error";
case Kind::eVulkan:
return fmt::format("{}", uVulkanResult);
case Kind::eSlang:
return fmt::format("{}", uSlangResult);
}
return "No Error";
}
PipelineCreationError()
: m_Kind{Kind::eNone}
, uNone{}
{
}
PipelineCreationError(vk::Result result)
: m_Kind{Kind::eVulkan}
, uVulkanResult{result}
{
}
PipelineCreationError(SlangResult result)
: m_Kind{Kind::eSlang}
, uSlangResult{result}
{
}
};
struct AttributeInfo
{
u32 m_Location;
@ -402,7 +350,7 @@ struct Frame;
class Context
{
protected:
protected:
vk::CommandBuffer m_Cmd;
friend Device;
@ -426,13 +374,14 @@ class GraphicsContext : public Context
friend Device;
friend Frame;
const Pipeline *m_PipelineInUse;
explicit GraphicsContext(const vk::CommandBuffer cmd)
: Context{cmd}
, m_PipelineInUse{nullptr}
{
}
const Pipeline *m_PipelineInUse;
public:
DEPRECATE_RAW_CALLS void SetViewport(const vk::Viewport &viewport);
void BindVertexBuffer(const Ref<VertexBuffer> &vertexBuffer);
@ -440,10 +389,14 @@ class GraphicsContext : public Context
void
PushConstantBlock(auto &block)
{
m_Cmd.pushConstants(m_PipelineInUse->m_Layout, vk::ShaderStageFlagBits::eAllGraphics, 0, sizeof block, &block);
if constexpr (sizeof(block) > 128)
{
WARN("Vulkan only guarantees 128 bytes of Push Constants. Size of PCB is {}", sizeof block);
}
void Draw(u32 vertexCount);
void DrawIndexed(u32 indexCount);
m_Cmd.pushConstants(m_PipelineInUse->m_Layout, vk::ShaderStageFlagBits::eAll, 0, sizeof block, &block);
}
void Draw(usize vertexCount);
void DrawIndexed(usize indexCount);
DEPRECATE_RAW_CALLS void BeginRendering(const vk::RenderingInfo &renderingInfo);
void EndRendering();
@ -480,6 +433,8 @@ class TransferContext : public Context
TransferContext &operator=(TransferContext &&other) noexcept;
DISALLOW_COPY_AND_ASSIGN(TransferContext);
~TransferContext() = default;
};
struct Frame
@ -514,6 +469,8 @@ struct Frame
Frame &operator=(Frame &&other) noexcept;
DISALLOW_COPY_AND_ASSIGN(Frame);
~Frame() = default;
};
class Device final

View File

@ -0,0 +1,74 @@
// =============================================
// Aster: pipeline_helpers.h
// Copyright (c) 2020-2025 Anish Bhobe
// =============================================
#pragma once
#include <aster/aster.h>
#include <EASTL/vector.h>
#include <slang.h>
#include <variant>
namespace systems
{
class Device;
struct PipelineCreationError
{
std::variant<std::monostate, vk::Result, SlangResult> m_Data;
std::string What();
i32 Value();
operator bool() const;
PipelineCreationError(vk::Result res);
PipelineCreationError(SlangResult res);
PipelineCreationError();
};
vk::ShaderStageFlagBits SlangToVulkanShaderStage(SlangStage stage);
namespace _internal
{
struct PipelineLayoutBuilder
{
Device *m_Device;
eastl::vector<vk::DescriptorSetLayout> m_DescriptorSetLayouts;
eastl::vector<vk::PushConstantRange> m_PushConstants;
vk::ShaderStageFlags m_Stage;
explicit PipelineLayoutBuilder(Device *device, vk::DescriptorSetLayout bindlessLayout = {});
[[nodiscard]] vk::PipelineLayout Build();
[[nodiscard]] vk::DescriptorSetLayout CreateDescriptorSetLayout(const vk::DescriptorSetLayoutCreateInfo &createInfo) const;
void AddDescriptorSetForParameterBlock(slang::TypeLayoutReflection * layout);
void AddPushConstantRangeForConstantBuffer(slang::TypeLayoutReflection * layout);
void AddSubObjectRange(slang::TypeLayoutReflection * layout, i64 subObjectRangeIndex);
void AddSubObjectRanges(slang::TypeLayoutReflection * layout);
};
struct DescriptorLayoutBuilder
{
PipelineLayoutBuilder *m_PipelineLayoutBuilder;
eastl::vector<vk::DescriptorSetLayoutBinding> m_LayoutBindings;
u32 m_SetIndex;
vk::ShaderStageFlags &Stage() const;
explicit DescriptorLayoutBuilder(PipelineLayoutBuilder *pipelineLayoutBuilder);
void AddGlobalScopeParameters(slang::ProgramLayout *layout);
void AddEntryPointParameters(slang::ProgramLayout *layout);
void AddEntryPointParameters(slang::EntryPointLayout *layout);
void AddAutomaticallyIntroducedUniformBuffer();
void AddRanges(slang::TypeLayoutReflection *layout);
void AddRangesForParamBlockElement(slang::TypeLayoutReflection *layout);
void AddDescriptorRange(slang::TypeLayoutReflection *layout, i64 relativeSetIndex, i64 rangeIndex);
void AddDescriptorRanges(slang::TypeLayoutReflection *layout);
void Build();
};
} // namespace _internal
} // namespace systems

View File

@ -69,13 +69,15 @@ CastView(const Ref<View<TFrom>> &from)
template <typename T>
class ResId
{
using IdType = u32;
public:
constexpr static u32 INVALID = MaxValue<u32>;
constexpr static IdType INVALID = MaxValue<IdType>;
private:
u32 m_Index;
IdType m_Index;
u32 m_Padding; //< Slang DescriptorHandle are a pair of u32. TODO: Use as validation.
explicit ResId(const u32 index)
explicit ResId(const IdType index)
: m_Index{index}
{
AddRef();

View File

@ -6,4 +6,5 @@ target_sources(aster_core
PRIVATE
"device.cpp"
"commit_manager.cpp"
"pipeline_helpers.cpp"
"sync_server.cpp")

View File

@ -562,7 +562,10 @@ systems::Device::CreatePipeline(Pipeline &pipelineOut, const GraphicsPipelineCre
}
vk::PipelineLayout pipelineLayout;
auto result = CreatePipelineLayout(pipelineLayout, program);
if (auto result = CreatePipelineLayout(pipelineLayout, program))
{
return result;
}
eastl::fixed_vector<vk::VertexInputBindingDescription, 4, false> inputBindingDescriptions;
eastl::fixed_vector<vk::VertexInputAttributeDescription, 4, false> inputAttributeDescriptions;
@ -699,47 +702,6 @@ systems::Device::CreatePipeline(Pipeline &pipelineOut, const GraphicsPipelineCre
ERROR("Unimplemented Stage " #STAGE); \
return SLANG_FAIL
static vk::ShaderStageFlagBits
SlangToVulkanShaderStage(const SlangStage stage)
{
switch (stage)
{
case SLANG_STAGE_VERTEX:
return vk::ShaderStageFlagBits::eVertex;
case SLANG_STAGE_HULL:
return vk::ShaderStageFlagBits::eTessellationControl;
case SLANG_STAGE_DOMAIN:
return vk::ShaderStageFlagBits::eTessellationEvaluation;
case SLANG_STAGE_GEOMETRY:
return vk::ShaderStageFlagBits::eGeometry;
case SLANG_STAGE_FRAGMENT:
return vk::ShaderStageFlagBits::eFragment;
case SLANG_STAGE_COMPUTE:
return vk::ShaderStageFlagBits::eCompute;
case SLANG_STAGE_RAY_GENERATION:
return vk::ShaderStageFlagBits::eRaygenKHR;
case SLANG_STAGE_INTERSECTION:
return vk::ShaderStageFlagBits::eIntersectionKHR;
case SLANG_STAGE_ANY_HIT:
return vk::ShaderStageFlagBits::eAnyHitKHR;
case SLANG_STAGE_CLOSEST_HIT:
return vk::ShaderStageFlagBits::eClosestHitKHR;
case SLANG_STAGE_MISS:
return vk::ShaderStageFlagBits::eMissKHR;
case SLANG_STAGE_CALLABLE:
return vk::ShaderStageFlagBits::eCallableKHR;
case SLANG_STAGE_MESH:
return vk::ShaderStageFlagBits::eMeshEXT;
case SLANG_STAGE_AMPLIFICATION:
return vk::ShaderStageFlagBits::eTaskEXT;
case SLANG_STAGE_NONE:
case SLANG_STAGE_COUNT:
ERROR("Invalid Shader Stage");
return {};
}
ERROR("Unreachable") THEN_ABORT(-1);
}
systems::PipelineCreationError
systems::Device::CreateShaders(
eastl::fixed_vector<vk::PipelineShaderStageCreateInfo, ShaderTypeCount, false> &shadersOut,
@ -905,6 +867,39 @@ systems::Device::CreateShaders(
return {};
}
struct PipelineLayoutBuilder
{
systems::Device *m_Device;
eastl::vector<vk::DescriptorSetLayout> m_DescriptorSetLayouts;
eastl::vector<vk::PushConstantRange> m_PushConstantRanges;
explicit PipelineLayoutBuilder(systems::Device *device)
: m_Device{device}
{
}
systems::PipelineCreationError
Build(vk::PipelineLayout &pipelineLayout, eastl::vector<vk::DescriptorSetLayout> &descriptorSetLayouts);
};
systems::PipelineCreationError
PipelineLayoutBuilder::Build(vk::PipelineLayout &pipelineLayout,
eastl::vector<vk::DescriptorSetLayout> &descriptorSetLayouts)
{
const vk::PipelineLayoutCreateInfo layoutCreateInfo = {
.setLayoutCount = static_cast<u32>(m_DescriptorSetLayouts.size()),
.pSetLayouts = m_DescriptorSetLayouts.data(),
.pushConstantRangeCount = static_cast<u32>(m_PushConstantRanges.size()),
.pPushConstantRanges = m_PushConstantRanges.data(),
};
const auto result = m_Device->m_Device->createPipelineLayout(&layoutCreateInfo, nullptr, &pipelineLayout);
for (const auto &descSet : descriptorSetLayouts)
{
m_Device->m_Device->destroy(descSet, nullptr);
}
return result;
}
systems::PipelineCreationError
systems::Device::CreatePipelineLayout(vk::PipelineLayout &pipelineLayout,
const Slang::ComPtr<slang::IComponentType> &program)
@ -919,39 +914,20 @@ systems::Device::CreatePipelineLayout(vk::PipelineLayout &pipelineLayout,
return SLANG_FAIL;
}
// TODO: Reflect to create the push constants and descriptor sets.
// TODO: Hackery. To FIX.
vk::PushConstantRange pcr{
.stageFlags = vk::ShaderStageFlagBits::eAllGraphics,
.offset = 0,
.size = 24,
};
u32 setLayoutCount = 0;
const vk::DescriptorSetLayout *setLayout = nullptr;
vk::DescriptorSetLayout setLayout = {};
if (m_CommitManager)
{
setLayoutCount = 1;
setLayout = &m_CommitManager->GetDescriptorSetLayout();
}
setLayout = m_CommitManager->GetDescriptorSetLayout();
// TODO: END EXPERIMENT
const vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo = {
.setLayoutCount = setLayoutCount,
.pSetLayouts = setLayout,
.pushConstantRangeCount = 1,
.pPushConstantRanges = &pcr,
_internal::PipelineLayoutBuilder pipelineLayoutBuilder{
this,
setLayout,
};
vk::Result result = m_Device->createPipelineLayout(&pipelineLayoutCreateInfo, nullptr, &pipelineLayout);
if (Failed(result))
{
ERROR("Could not create a pipeline layout. Cause: {}", result);
return result;
}
_internal::DescriptorLayoutBuilder descriptorLayoutBuilder{&pipelineLayoutBuilder};
descriptorLayoutBuilder.AddGlobalScopeParameters(layout);
descriptorLayoutBuilder.AddEntryPointParameters(layout);
descriptorLayoutBuilder.Build();
pipelineLayout = pipelineLayoutBuilder.Build();
return {};
}
@ -990,7 +966,7 @@ FindAsyncTransferQueue(const PhysicalDevice &physicalDevice, u32 primaryQueueFam
};
}
}
WARN("No async transfer queue. Falling back to primary queue");
WARN("No dedicated async transfer queue. Falling back to primary queue family.");
return std::nullopt;
}
@ -1002,7 +978,8 @@ FindAsyncComputeQueue(const PhysicalDevice &physicalDevice, u32 primaryQueueFami
if (queueFamilyInfo.m_Index == primaryQueueFamilyIndex)
continue;
if (queueFamilyInfo.m_Support == QueueSupportFlagBits::eCompute)
if (queueFamilyInfo.m_Support ==
(QueueSupportFlags{QueueSupportFlagBits::eCompute} | QueueSupportFlagBits::eTransfer))
{
return QueueAllocation{
.m_Family = queueFamilyInfo.m_Index,
@ -1010,7 +987,7 @@ FindAsyncComputeQueue(const PhysicalDevice &physicalDevice, u32 primaryQueueFami
};
}
}
WARN("No async compute queue. Falling back to primary queue");
WARN("No async compute queue. Falling back to primary queue family.");
return std::nullopt;
}
@ -1471,15 +1448,15 @@ systems::GraphicsContext::BindPipeline(const Pipeline &pipeline)
}
void
systems::GraphicsContext::Draw(u32 vertexCount)
systems::GraphicsContext::Draw(const usize vertexCount)
{
m_Cmd.draw(vertexCount, 1, 0, 0);
m_Cmd.draw(static_cast<u32>(vertexCount), 1, 0, 0);
}
void
systems::GraphicsContext::DrawIndexed(u32 indexCount)
systems::GraphicsContext::DrawIndexed(usize indexCount)
{
m_Cmd.drawIndexed(indexCount, 1, 0, 0, 0);
m_Cmd.drawIndexed(static_cast<u32>(indexCount), 1, 0, 0, 0);
}
void

View File

@ -0,0 +1,374 @@
// =============================================
// Aster: pipeline_helpers.cpp
// Copyright (c) 2020-2025 Anish Bhobe
// =============================================
#include "systems/device.h"
#include <aster/systems/pipeline_helpers.h>
using namespace systems::_internal;
struct WhatVisitor
{
std::string
operator()(std::monostate) const
{
return "No Error";
}
std::string
operator()(vk::Result result) const
{
return fmt::format("Vulkan Error: {}", result);
}
std::string
operator()(SlangResult result) const
{
return fmt::format("Slang Error: {}", result);
}
};
struct ValueVisitor
{
i32
operator()(std::monostate) const
{
return 0;
}
i32
operator()(vk::Result result) const
{
return static_cast<i32>(result);
}
i32
operator()(SlangResult result) const
{
return result;
}
};
i32
systems::PipelineCreationError::Value()
{
return std::visit(ValueVisitor{}, m_Data);
}
systems::PipelineCreationError::PipelineCreationError(vk::Result res)
: m_Data{res}
{
}
systems::PipelineCreationError::PipelineCreationError(SlangResult res)
: m_Data{res}
{
}
systems::PipelineCreationError::PipelineCreationError()
: m_Data{std::monostate{}}
{
}
systems::PipelineCreationError::operator bool() const
{
return not std::holds_alternative<std::monostate>(m_Data);
}
std::string
systems::PipelineCreationError::What()
{
return std::visit(WhatVisitor{}, m_Data);
}
vk::ShaderStageFlagBits
systems::SlangToVulkanShaderStage(const SlangStage stage)
{
switch (stage)
{
case SLANG_STAGE_VERTEX:
return vk::ShaderStageFlagBits::eVertex;
case SLANG_STAGE_HULL:
return vk::ShaderStageFlagBits::eTessellationControl;
case SLANG_STAGE_DOMAIN:
return vk::ShaderStageFlagBits::eTessellationEvaluation;
case SLANG_STAGE_GEOMETRY:
return vk::ShaderStageFlagBits::eGeometry;
case SLANG_STAGE_FRAGMENT:
return vk::ShaderStageFlagBits::eFragment;
case SLANG_STAGE_COMPUTE:
return vk::ShaderStageFlagBits::eCompute;
case SLANG_STAGE_RAY_GENERATION:
return vk::ShaderStageFlagBits::eRaygenKHR;
case SLANG_STAGE_INTERSECTION:
return vk::ShaderStageFlagBits::eIntersectionKHR;
case SLANG_STAGE_ANY_HIT:
return vk::ShaderStageFlagBits::eAnyHitKHR;
case SLANG_STAGE_CLOSEST_HIT:
return vk::ShaderStageFlagBits::eClosestHitKHR;
case SLANG_STAGE_MISS:
return vk::ShaderStageFlagBits::eMissKHR;
case SLANG_STAGE_CALLABLE:
return vk::ShaderStageFlagBits::eCallableKHR;
case SLANG_STAGE_MESH:
return vk::ShaderStageFlagBits::eMeshEXT;
case SLANG_STAGE_AMPLIFICATION:
return vk::ShaderStageFlagBits::eTaskEXT;
case SLANG_STAGE_NONE:
case SLANG_STAGE_COUNT:
UNREACHABLE();
return {};
}
UNREACHABLE();
return {};
}
PipelineLayoutBuilder::PipelineLayoutBuilder(Device *device, vk::DescriptorSetLayout bindlessLayout)
: m_Device{device}
, m_DescriptorSetLayouts{bindlessLayout} // if `null` will be filtered out during build.
{
}
vk::PipelineLayout
PipelineLayoutBuilder::Build()
{
vk::PipelineLayout pipelineLayout;
eastl::vector<vk::DescriptorSetLayout> filteredDescriptorSetLayouts;
filteredDescriptorSetLayouts.reserve(m_DescriptorSetLayouts.size());
for (auto dsl : m_DescriptorSetLayouts)
{
if (dsl)
{
filteredDescriptorSetLayouts.push_back(dsl);
}
}
const vk::PipelineLayoutCreateInfo createInfo = {
.setLayoutCount = static_cast<u32>(filteredDescriptorSetLayouts.size()),
.pSetLayouts = filteredDescriptorSetLayouts.data(),
.pushConstantRangeCount = static_cast<u32>(m_PushConstants.size()),
.pPushConstantRanges = m_PushConstants.data(),
};
AbortIfFailed(m_Device->m_Device->createPipelineLayout(&createInfo, nullptr, &pipelineLayout));
return pipelineLayout;
}
vk::DescriptorSetLayout
PipelineLayoutBuilder::CreateDescriptorSetLayout(const vk::DescriptorSetLayoutCreateInfo &createInfo) const
{
vk::DescriptorSetLayout dsl;
// Failure Cases are OoM errors. No recovery.
AbortIfFailed(m_Device->m_Device->createDescriptorSetLayout(&createInfo, nullptr, &dsl));
return dsl;
}
void
PipelineLayoutBuilder::AddDescriptorSetForParameterBlock(slang::TypeLayoutReflection *layout)
{
DescriptorLayoutBuilder descriptorLayoutBuilder{this};
descriptorLayoutBuilder.AddRangesForParamBlockElement(layout->getElementTypeLayout());
descriptorLayoutBuilder.Build();
}
void
PipelineLayoutBuilder::AddPushConstantRangeForConstantBuffer(slang::TypeLayoutReflection *layout)
{
const auto elementTypeLayout = layout->getElementTypeLayout();
const auto elementSize = elementTypeLayout->getSize();
if (elementSize == 0)
return;
m_PushConstants.push_back({
.stageFlags = m_Stage,
.offset = 0,
.size = static_cast<u32>(elementSize),
});
}
void
PipelineLayoutBuilder::AddSubObjectRange(slang::TypeLayoutReflection *layout, i64 subObjectRangeIndex)
{
auto bindingRangeIndex = layout->getSubObjectRangeBindingRangeIndex(subObjectRangeIndex);
switch (layout->getBindingRangeType(bindingRangeIndex))
{
case slang::BindingType::ParameterBlock: {
const auto parameterBlockTypeLayout = layout->getBindingRangeLeafTypeLayout(bindingRangeIndex);
AddDescriptorSetForParameterBlock(parameterBlockTypeLayout);
}
break;
case slang::BindingType::PushConstant: {
const auto constantBufferTypeLayout = layout->getBindingRangeLeafTypeLayout(bindingRangeIndex);
AddPushConstantRangeForConstantBuffer(constantBufferTypeLayout);
}
break;
default:
UNREACHABLE("Unexpected types");
}
}
vk::DescriptorType
BindingTypeToDescriptorType(slang::BindingType binding)
{
using vk::DescriptorType;
switch (binding)
{
case slang::BindingType::Sampler:
return DescriptorType::eSampler;
case slang::BindingType::Texture:
return DescriptorType::eSampledImage;
case slang::BindingType::ConstantBuffer:
return DescriptorType::eUniformBuffer;
case slang::BindingType::TypedBuffer:
return DescriptorType::eStorageBuffer;
case slang::BindingType::RawBuffer:
return DescriptorType::eStorageBuffer;
case slang::BindingType::CombinedTextureSampler:
return DescriptorType::eCombinedImageSampler;
case slang::BindingType::InlineUniformData:
return DescriptorType::eInlineUniformBlock;
case slang::BindingType::RayTracingAccelerationStructure:
return DescriptorType::eAccelerationStructureKHR;
case slang::BindingType::MutableTexture:
return DescriptorType::eStorageImage;
case slang::BindingType::MutableTypedBuffer:
return DescriptorType::eStorageBuffer;
case slang::BindingType::MutableRawBuffer:
return DescriptorType::eStorageBuffer;
default:
UNREACHABLE("Unsupported Types");
}
return {};
}
vk::ShaderStageFlags &
DescriptorLayoutBuilder::Stage() const
{
return m_PipelineLayoutBuilder->m_Stage;
}
DescriptorLayoutBuilder::DescriptorLayoutBuilder(PipelineLayoutBuilder *pipelineLayoutBuilder)
: m_PipelineLayoutBuilder{pipelineLayoutBuilder}
, m_SetIndex{static_cast<u32>(pipelineLayoutBuilder->m_DescriptorSetLayouts.size())}
{
m_PipelineLayoutBuilder->m_DescriptorSetLayouts.push_back();
}
void
DescriptorLayoutBuilder::AddDescriptorRange(slang::TypeLayoutReflection *layout, const i64 relativeSetIndex,
const i64 rangeIndex)
{
const auto bindingType = layout->getDescriptorSetDescriptorRangeType(relativeSetIndex, rangeIndex);
if (bindingType == slang::BindingType::PushConstant)
return;
const u32 descriptorCount =
static_cast<u32>(layout->getDescriptorSetDescriptorRangeDescriptorCount(relativeSetIndex, rangeIndex));
const u32 bindingIndex = static_cast<u32>(m_LayoutBindings.size());
const auto vkBindingType = BindingTypeToDescriptorType(bindingType);
m_LayoutBindings.push_back({
.binding = bindingIndex,
.descriptorType = vkBindingType,
.descriptorCount = descriptorCount,
.stageFlags = Stage(),
});
}
void
DescriptorLayoutBuilder::AddDescriptorRanges(slang::TypeLayoutReflection *layout)
{
i64 nSets = layout->getDescriptorSetCount();
for (i64 relativeSetIndex = 0; relativeSetIndex < nSets; ++relativeSetIndex)
{
i64 rangeCount = layout->getDescriptorSetDescriptorRangeCount(relativeSetIndex);
for (i64 rangeIndex = 0; rangeIndex < rangeCount; ++rangeIndex)
{
AddDescriptorRange(layout, relativeSetIndex, rangeIndex);
}
}
}
void
DescriptorLayoutBuilder::Build()
{
if (m_LayoutBindings.empty())
return;
const auto dsl = m_PipelineLayoutBuilder->CreateDescriptorSetLayout({
.bindingCount = static_cast<u32>(m_LayoutBindings.size()),
.pBindings = m_LayoutBindings.data(),
});
m_PipelineLayoutBuilder->m_DescriptorSetLayouts[m_SetIndex] = dsl;
}
void
DescriptorLayoutBuilder::AddAutomaticallyIntroducedUniformBuffer()
{
const auto vulkanBindingIndex = static_cast<u32>(m_LayoutBindings.size());
m_LayoutBindings.push_back({
.binding = vulkanBindingIndex,
.descriptorType = vk::DescriptorType::eUniformBuffer,
.descriptorCount = 1,
.stageFlags = vk::ShaderStageFlagBits::eAll,
});
}
void
DescriptorLayoutBuilder::AddRanges(slang::TypeLayoutReflection *layout)
{
AddDescriptorRanges(layout);
m_PipelineLayoutBuilder->AddSubObjectRanges(layout);
}
void
DescriptorLayoutBuilder::AddRangesForParamBlockElement(slang::TypeLayoutReflection *layout)
{
if (layout->getSize() > 0)
{
AddAutomaticallyIntroducedUniformBuffer();
}
AddRanges(layout);
}
void
DescriptorLayoutBuilder::AddGlobalScopeParameters(slang::ProgramLayout *layout)
{
Stage() = vk::ShaderStageFlagBits::eAll;
AddRangesForParamBlockElement(layout->getGlobalParamsTypeLayout());
}
void
DescriptorLayoutBuilder::AddEntryPointParameters(slang::ProgramLayout *layout)
{
u64 entryPointCount = layout->getEntryPointCount();
for (u64 i = 0; i < entryPointCount; ++i)
{
auto *entryPoint = layout->getEntryPointByIndex(i);
AddEntryPointParameters(entryPoint);
}
}
void
DescriptorLayoutBuilder::AddEntryPointParameters(slang::EntryPointLayout *layout)
{
Stage() = SlangToVulkanShaderStage(layout->getStage());
AddRangesForParamBlockElement(layout->getTypeLayout());
}
void
PipelineLayoutBuilder::AddSubObjectRanges(slang::TypeLayoutReflection *layout)
{
i64 subObjectRangeCount = layout->getSubObjectRangeCount();
for (i64 subObjectRangeIndex = 0; subObjectRangeIndex < subObjectRangeCount; ++subObjectRangeIndex)
{
AddSubObjectRange(layout, subObjectRangeIndex);
}
}

View File

@ -86,7 +86,7 @@ struct Camera
int
main(int, char **)
{
MIN_LOG_LEVEL(Logger::LogType::eInfo);
MIN_LOG_LEVEL(Logger::LogType::eDebug);
Window window = {"Box (Aster)", {640, 480}};
@ -125,7 +125,7 @@ main(int, char **)
{.m_ShaderFile = SHADER_FILE, .m_EntryPoints = {"vsmain", "fsmain"}},
}});
ERROR_IF(pipelineResult, "Could not create pipeline. Cause: {}", pipelineResult.What())
THEN_ABORT(pipelineResult.uNone);
THEN_ABORT(pipelineResult.Value());
auto swapchainSize = device.GetSwapchainSize();
Camera camera = {
@ -229,8 +229,8 @@ main(int, char **)
.dstAccessMask = vk::AccessFlagBits2::eShaderRead,
.oldLayout = vk::ImageLayout::eTransferDstOptimal,
.newLayout = vk::ImageLayout::eShaderReadOnlyOptimal,
.srcQueueFamilyIndex = vk::QueueFamilyIgnored,
.dstQueueFamilyIndex = vk::QueueFamilyIgnored,
.srcQueueFamilyIndex = device.m_TransferQueueFamily,
.dstQueueFamilyIndex = device.m_PrimaryQueueFamily,
.image = crate->GetImage(),
.subresourceRange =
{
@ -326,11 +326,8 @@ main(int, char **)
struct PCB
{
systems::ResId<Buffer> m_VertexBuffer;
u32 m_Pad0 = 0;
systems::ResId<Buffer> m_Camera;
u32 m_Pad1 = 0;
systems::ResId<TextureView> m_Texture;
u32 m_Pad2 = 0;
};
static_assert(sizeof(PCB) == 24);

View File

@ -20,7 +20,6 @@ struct PCB {
DescriptorHandle<Sampler2D> texture;
};
//uniform CameraData camera;
[vk::push_constant]
uniform PCB pcb;