Share builtin pass layout assembly utilities

This commit is contained in:
2026-04-04 13:48:13 +08:00
parent 0ebd2d4979
commit a3ba08bb99
7 changed files with 328 additions and 180 deletions

View File

@@ -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;

View File

@@ -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,

View File

@@ -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();
};