Share builtin pass layout assembly utilities
This commit is contained in:
@@ -56,6 +56,7 @@ private:
|
||||
RHI::RHIPipelineLayout* m_pipelineLayout = nullptr;
|
||||
RHI::RHIPipelineState* m_pipelineState = nullptr;
|
||||
PassResourceBindingLocation m_perObjectBinding = {};
|
||||
BuiltinPassSetLayoutMetadata m_perObjectSetLayout = {};
|
||||
Core::uint32 m_firstDescriptorSet = 0;
|
||||
Resources::ResourceHandle<Resources::Shader> m_builtinObjectIdShader;
|
||||
RenderResourceCache m_resourceCache;
|
||||
|
||||
@@ -89,22 +89,11 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
struct PassSetLayoutMetadata {
|
||||
std::vector<RHI::DescriptorSetLayoutBinding> bindings;
|
||||
RHI::DescriptorSetLayoutDesc layout = {};
|
||||
RHI::DescriptorHeapType heapType = RHI::DescriptorHeapType::CBV_SRV_UAV;
|
||||
bool shaderVisible = false;
|
||||
bool usesPerObject = false;
|
||||
bool usesMaterial = false;
|
||||
bool usesTexture = false;
|
||||
bool usesSampler = false;
|
||||
};
|
||||
|
||||
struct PassResourceLayout {
|
||||
RHI::RHIPipelineLayout* pipelineLayout = nullptr;
|
||||
Core::uint32 firstDescriptorSet = 0;
|
||||
Core::uint32 descriptorSetCount = 0;
|
||||
std::vector<PassSetLayoutMetadata> setLayouts;
|
||||
std::vector<BuiltinPassSetLayoutMetadata> setLayouts;
|
||||
std::vector<OwnedDescriptorSet> staticDescriptorSets;
|
||||
PassResourceBindingLocation perObject = {};
|
||||
PassResourceBindingLocation material = {};
|
||||
@@ -188,7 +177,7 @@ private:
|
||||
const RenderContext& context,
|
||||
const Resources::Material* material);
|
||||
bool CreateOwnedDescriptorSet(
|
||||
const PassSetLayoutMetadata& setLayout,
|
||||
const BuiltinPassSetLayoutMetadata& setLayout,
|
||||
OwnedDescriptorSet& descriptorSet);
|
||||
RHI::RHIDescriptorSet* GetOrCreateStaticDescriptorSet(
|
||||
PassResourceLayout& passLayout,
|
||||
@@ -196,7 +185,7 @@ private:
|
||||
CachedDescriptorSet* GetOrCreateDynamicDescriptorSet(
|
||||
const PassLayoutKey& passLayoutKey,
|
||||
const PassResourceLayout& passLayout,
|
||||
const PassSetLayoutMetadata& setLayout,
|
||||
const BuiltinPassSetLayoutMetadata& setLayout,
|
||||
Core::uint32 setIndex,
|
||||
Core::uint64 objectId,
|
||||
const Resources::Material* material,
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Rendering {
|
||||
@@ -70,6 +71,17 @@ struct BuiltinPassResourceBindingPlan {
|
||||
}
|
||||
};
|
||||
|
||||
struct BuiltinPassSetLayoutMetadata {
|
||||
std::vector<RHI::DescriptorSetLayoutBinding> bindings;
|
||||
RHI::DescriptorSetLayoutDesc layout = {};
|
||||
RHI::DescriptorHeapType heapType = RHI::DescriptorHeapType::CBV_SRV_UAV;
|
||||
bool shaderVisible = false;
|
||||
bool usesPerObject = false;
|
||||
bool usesMaterial = false;
|
||||
bool usesTexture = false;
|
||||
bool usesSampler = false;
|
||||
};
|
||||
|
||||
inline Containers::String NormalizeBuiltinPassMetadataValue(const Containers::String& value) {
|
||||
return value.Trim().ToLower();
|
||||
}
|
||||
@@ -356,6 +368,148 @@ inline bool TryBuildBuiltinPassResourceBindingPlan(
|
||||
return true;
|
||||
}
|
||||
|
||||
inline RHI::DescriptorType ToBuiltinPassDescriptorType(Resources::ShaderResourceType type) {
|
||||
switch (type) {
|
||||
case Resources::ShaderResourceType::ConstantBuffer:
|
||||
return RHI::DescriptorType::CBV;
|
||||
case Resources::ShaderResourceType::Texture2D:
|
||||
case Resources::ShaderResourceType::TextureCube:
|
||||
return RHI::DescriptorType::SRV;
|
||||
case Resources::ShaderResourceType::Sampler:
|
||||
return RHI::DescriptorType::Sampler;
|
||||
default:
|
||||
return RHI::DescriptorType::CBV;
|
||||
}
|
||||
}
|
||||
|
||||
inline RHI::DescriptorHeapType ResolveBuiltinPassDescriptorHeapType(Resources::ShaderResourceType type) {
|
||||
return type == Resources::ShaderResourceType::Sampler
|
||||
? RHI::DescriptorHeapType::Sampler
|
||||
: RHI::DescriptorHeapType::CBV_SRV_UAV;
|
||||
}
|
||||
|
||||
inline bool IsBuiltinPassShaderVisibleSet(const std::vector<RHI::DescriptorSetLayoutBinding>& bindings) {
|
||||
for (const RHI::DescriptorSetLayoutBinding& binding : bindings) {
|
||||
const RHI::DescriptorType descriptorType = static_cast<RHI::DescriptorType>(binding.type);
|
||||
if (descriptorType == RHI::DescriptorType::SRV ||
|
||||
descriptorType == RHI::DescriptorType::UAV ||
|
||||
descriptorType == RHI::DescriptorType::Sampler) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
inline Core::uint32 CountBuiltinPassHeapDescriptors(
|
||||
RHI::DescriptorHeapType heapType,
|
||||
const std::vector<RHI::DescriptorSetLayoutBinding>& bindings) {
|
||||
Core::uint32 descriptorCount = 0;
|
||||
for (const RHI::DescriptorSetLayoutBinding& binding : bindings) {
|
||||
const RHI::DescriptorType descriptorType = static_cast<RHI::DescriptorType>(binding.type);
|
||||
if (heapType == RHI::DescriptorHeapType::Sampler) {
|
||||
if (descriptorType == RHI::DescriptorType::Sampler) {
|
||||
descriptorCount += binding.count > 0 ? binding.count : 1u;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (descriptorType != RHI::DescriptorType::Sampler) {
|
||||
descriptorCount += binding.count > 0 ? binding.count : 1u;
|
||||
}
|
||||
}
|
||||
|
||||
return descriptorCount > 0 ? descriptorCount : 1u;
|
||||
}
|
||||
|
||||
inline void RefreshBuiltinPassSetLayoutMetadata(BuiltinPassSetLayoutMetadata& setLayout) {
|
||||
std::sort(
|
||||
setLayout.bindings.begin(),
|
||||
setLayout.bindings.end(),
|
||||
[](const RHI::DescriptorSetLayoutBinding& left, const RHI::DescriptorSetLayoutBinding& right) {
|
||||
return left.binding < right.binding;
|
||||
});
|
||||
setLayout.shaderVisible = IsBuiltinPassShaderVisibleSet(setLayout.bindings);
|
||||
setLayout.layout.bindings = setLayout.bindings.empty() ? nullptr : setLayout.bindings.data();
|
||||
setLayout.layout.bindingCount = static_cast<Core::uint32>(setLayout.bindings.size());
|
||||
}
|
||||
|
||||
inline void RefreshBuiltinPassSetLayouts(std::vector<BuiltinPassSetLayoutMetadata>& setLayouts) {
|
||||
for (BuiltinPassSetLayoutMetadata& setLayout : setLayouts) {
|
||||
RefreshBuiltinPassSetLayoutMetadata(setLayout);
|
||||
}
|
||||
}
|
||||
|
||||
inline bool TryBuildBuiltinPassSetLayouts(
|
||||
const BuiltinPassResourceBindingPlan& bindingPlan,
|
||||
std::vector<BuiltinPassSetLayoutMetadata>& outSetLayouts,
|
||||
Containers::String* outError = nullptr) {
|
||||
outSetLayouts.clear();
|
||||
|
||||
auto fail = [&outError](const char* message) {
|
||||
if (outError != nullptr) {
|
||||
*outError = message;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
if (bindingPlan.bindings.Empty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
outSetLayouts.resize(static_cast<size_t>(bindingPlan.maxSetIndex) + 1u);
|
||||
for (const BuiltinPassResourceBindingDesc& binding : bindingPlan.bindings) {
|
||||
if (binding.location.set >= outSetLayouts.size()) {
|
||||
return fail("Builtin pass encountered an invalid descriptor set index");
|
||||
}
|
||||
|
||||
const RHI::DescriptorType descriptorType = ToBuiltinPassDescriptorType(binding.resourceType);
|
||||
const RHI::DescriptorHeapType heapType = ResolveBuiltinPassDescriptorHeapType(binding.resourceType);
|
||||
BuiltinPassSetLayoutMetadata& setLayout = outSetLayouts[binding.location.set];
|
||||
|
||||
if (!setLayout.bindings.empty() && setLayout.heapType != heapType) {
|
||||
return fail("Builtin pass does not support mixing sampler and non-sampler bindings in one set");
|
||||
}
|
||||
|
||||
for (const RHI::DescriptorSetLayoutBinding& existingBinding : setLayout.bindings) {
|
||||
if (existingBinding.binding == binding.location.binding) {
|
||||
return fail("Builtin pass encountered duplicate bindings inside one descriptor set");
|
||||
}
|
||||
}
|
||||
|
||||
if (setLayout.bindings.empty()) {
|
||||
setLayout.heapType = heapType;
|
||||
}
|
||||
|
||||
RHI::DescriptorSetLayoutBinding layoutBinding = {};
|
||||
layoutBinding.binding = binding.location.binding;
|
||||
layoutBinding.type = static_cast<Core::uint32>(descriptorType);
|
||||
layoutBinding.count = 1;
|
||||
setLayout.bindings.push_back(layoutBinding);
|
||||
|
||||
switch (binding.semantic) {
|
||||
case BuiltinPassResourceSemantic::PerObject:
|
||||
setLayout.usesPerObject = true;
|
||||
break;
|
||||
case BuiltinPassResourceSemantic::Material:
|
||||
setLayout.usesMaterial = true;
|
||||
break;
|
||||
case BuiltinPassResourceSemantic::BaseColorTexture:
|
||||
setLayout.usesTexture = true;
|
||||
break;
|
||||
case BuiltinPassResourceSemantic::LinearClampSampler:
|
||||
setLayout.usesSampler = true;
|
||||
break;
|
||||
case BuiltinPassResourceSemantic::Unknown:
|
||||
default:
|
||||
return fail("Builtin pass encountered an unsupported resource semantic");
|
||||
}
|
||||
}
|
||||
|
||||
RefreshBuiltinPassSetLayouts(outSetLayouts);
|
||||
return true;
|
||||
}
|
||||
|
||||
struct BuiltinForwardMaterialData {
|
||||
Math::Vector4 baseColorFactor = Math::Vector4::One();
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user