Generalize builtin pass resource binding plan
This commit is contained in:
@@ -52,42 +52,6 @@ private:
|
||||
|
||||
namespace {
|
||||
|
||||
enum class ForwardPassSemantic : uint8_t {
|
||||
Unknown = 0,
|
||||
PerObject,
|
||||
Material,
|
||||
BaseColorTexture,
|
||||
LinearClampSampler
|
||||
};
|
||||
|
||||
ForwardPassSemantic ResolveForwardPassSemantic(const Resources::ShaderResourceBindingDesc& binding) {
|
||||
Containers::String semantic = NormalizeBuiltinPassMetadataValue(binding.semantic);
|
||||
if (semantic.Empty()) {
|
||||
semantic = NormalizeBuiltinPassMetadataValue(binding.name);
|
||||
}
|
||||
|
||||
if (semantic == Containers::String("perobject") ||
|
||||
semantic == Containers::String("perobjectconstants")) {
|
||||
return ForwardPassSemantic::PerObject;
|
||||
}
|
||||
|
||||
if (semantic == Containers::String("material") ||
|
||||
semantic == Containers::String("materialconstants")) {
|
||||
return ForwardPassSemantic::Material;
|
||||
}
|
||||
|
||||
if (semantic == Containers::String("basecolortexture") ||
|
||||
semantic == Containers::String("maintex")) {
|
||||
return ForwardPassSemantic::BaseColorTexture;
|
||||
}
|
||||
|
||||
if (semantic == Containers::String("linearclampsampler")) {
|
||||
return ForwardPassSemantic::LinearClampSampler;
|
||||
}
|
||||
|
||||
return ForwardPassSemantic::Unknown;
|
||||
}
|
||||
|
||||
RHI::DescriptorType ToDescriptorType(Resources::ShaderResourceType type) {
|
||||
switch (type) {
|
||||
case Resources::ShaderResourceType::ConstantBuffer:
|
||||
@@ -154,36 +118,6 @@ bool BindingNumberExists(
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<Resources::ShaderResourceBindingDesc> BuildLegacyForwardResourceBindings() {
|
||||
std::vector<Resources::ShaderResourceBindingDesc> bindings(4);
|
||||
|
||||
bindings[0].name = "PerObjectConstants";
|
||||
bindings[0].type = Resources::ShaderResourceType::ConstantBuffer;
|
||||
bindings[0].set = 1;
|
||||
bindings[0].binding = 0;
|
||||
bindings[0].semantic = "PerObject";
|
||||
|
||||
bindings[1].name = "MaterialConstants";
|
||||
bindings[1].type = Resources::ShaderResourceType::ConstantBuffer;
|
||||
bindings[1].set = 2;
|
||||
bindings[1].binding = 0;
|
||||
bindings[1].semantic = "Material";
|
||||
|
||||
bindings[2].name = "BaseColorTexture";
|
||||
bindings[2].type = Resources::ShaderResourceType::Texture2D;
|
||||
bindings[2].set = 3;
|
||||
bindings[2].binding = 0;
|
||||
bindings[2].semantic = "BaseColorTexture";
|
||||
|
||||
bindings[3].name = "LinearClampSampler";
|
||||
bindings[3].type = Resources::ShaderResourceType::Sampler;
|
||||
bindings[3].set = 4;
|
||||
bindings[3].binding = 0;
|
||||
bindings[3].semantic = "LinearClampSampler";
|
||||
|
||||
return bindings;
|
||||
}
|
||||
|
||||
const Resources::ShaderPass* FindForwardCompatiblePass(
|
||||
const Resources::Shader& shader,
|
||||
const Resources::Material* material,
|
||||
@@ -588,16 +522,6 @@ BuiltinForwardPipeline::PassResourceLayout* BuiltinForwardPipeline::GetOrCreateP
|
||||
return &existing->second;
|
||||
}
|
||||
|
||||
std::vector<Resources::ShaderResourceBindingDesc> resourceBindings;
|
||||
if (resolvedShaderPass.pass->resources.Empty()) {
|
||||
resourceBindings = BuildLegacyForwardResourceBindings();
|
||||
} else {
|
||||
resourceBindings.reserve(resolvedShaderPass.pass->resources.Size());
|
||||
for (const Resources::ShaderResourceBindingDesc& binding : resolvedShaderPass.pass->resources) {
|
||||
resourceBindings.push_back(binding);
|
||||
}
|
||||
}
|
||||
|
||||
PassResourceLayout passLayout = {};
|
||||
auto failLayout = [this, &passLayout](const char* message) -> PassResourceLayout* {
|
||||
Debug::Logger::Get().Error(Debug::LogCategory::Rendering, message);
|
||||
@@ -605,61 +529,44 @@ BuiltinForwardPipeline::PassResourceLayout* BuiltinForwardPipeline::GetOrCreateP
|
||||
return nullptr;
|
||||
};
|
||||
|
||||
Core::uint32 minBoundSet = UINT32_MAX;
|
||||
Core::uint32 maxBoundSet = 0;
|
||||
Core::uint32 maxSetIndex = 0;
|
||||
bool hasAnyResource = false;
|
||||
bool usesConstantBuffers = false;
|
||||
bool usesTextures = false;
|
||||
bool usesSamplers = false;
|
||||
for (const Resources::ShaderResourceBindingDesc& binding : resourceBindings) {
|
||||
maxSetIndex = std::max(maxSetIndex, binding.set);
|
||||
hasAnyResource = true;
|
||||
minBoundSet = std::min(minBoundSet, binding.set);
|
||||
maxBoundSet = std::max(maxBoundSet, binding.set);
|
||||
|
||||
switch (binding.type) {
|
||||
case Resources::ShaderResourceType::ConstantBuffer:
|
||||
usesConstantBuffers = true;
|
||||
break;
|
||||
case Resources::ShaderResourceType::Texture2D:
|
||||
case Resources::ShaderResourceType::TextureCube:
|
||||
usesTextures = true;
|
||||
break;
|
||||
case Resources::ShaderResourceType::Sampler:
|
||||
usesSamplers = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
Containers::Array<Resources::ShaderResourceBindingDesc> resourceBindings = resolvedShaderPass.pass->resources;
|
||||
if (resourceBindings.Empty()) {
|
||||
resourceBindings = BuildLegacyBuiltinForwardPassResourceBindings();
|
||||
}
|
||||
|
||||
BuiltinPassResourceBindingPlan bindingPlan = {};
|
||||
Containers::String bindingPlanError;
|
||||
if (!TryBuildBuiltinPassResourceBindingPlan(resourceBindings, bindingPlan, &bindingPlanError)) {
|
||||
return failLayout(bindingPlanError.CStr());
|
||||
}
|
||||
|
||||
const bool hasAnyResource = !bindingPlan.bindings.Empty();
|
||||
if (hasAnyResource) {
|
||||
passLayout.setLayouts.resize(static_cast<size_t>(maxSetIndex) + 1u);
|
||||
passLayout.setLayouts.resize(static_cast<size_t>(bindingPlan.maxSetIndex) + 1u);
|
||||
passLayout.staticDescriptorSets.resize(passLayout.setLayouts.size());
|
||||
passLayout.firstDescriptorSet = minBoundSet;
|
||||
passLayout.descriptorSetCount = maxBoundSet - minBoundSet + 1u;
|
||||
passLayout.firstDescriptorSet = bindingPlan.firstDescriptorSet;
|
||||
passLayout.descriptorSetCount = bindingPlan.descriptorSetCount;
|
||||
}
|
||||
|
||||
for (const Resources::ShaderResourceBindingDesc& binding : resourceBindings) {
|
||||
ForwardPassSemantic semantic = ResolveForwardPassSemantic(binding);
|
||||
if (semantic == ForwardPassSemantic::Unknown) {
|
||||
return failLayout("BuiltinForwardPipeline encountered an unsupported forward shader resource semantic");
|
||||
}
|
||||
passLayout.perObject = bindingPlan.perObject;
|
||||
passLayout.material = bindingPlan.material;
|
||||
passLayout.baseColorTexture = bindingPlan.baseColorTexture;
|
||||
passLayout.linearClampSampler = bindingPlan.linearClampSampler;
|
||||
|
||||
if (binding.set >= passLayout.setLayouts.size()) {
|
||||
for (const BuiltinPassResourceBindingDesc& binding : bindingPlan.bindings) {
|
||||
if (binding.location.set >= passLayout.setLayouts.size()) {
|
||||
return failLayout("BuiltinForwardPipeline encountered an invalid forward shader resource set");
|
||||
}
|
||||
|
||||
const RHI::DescriptorType descriptorType = ToDescriptorType(binding.type);
|
||||
const RHI::DescriptorHeapType heapType = ResolveDescriptorHeapType(binding.type);
|
||||
PassSetLayoutMetadata& setLayout = passLayout.setLayouts[binding.set];
|
||||
const RHI::DescriptorType descriptorType = ToDescriptorType(binding.resourceType);
|
||||
const RHI::DescriptorHeapType heapType = ResolveDescriptorHeapType(binding.resourceType);
|
||||
PassSetLayoutMetadata& setLayout = passLayout.setLayouts[binding.location.set];
|
||||
|
||||
if (!setLayout.bindings.empty() && setLayout.heapType != heapType) {
|
||||
return failLayout("BuiltinForwardPipeline does not support mixing sampler and non-sampler bindings in one set");
|
||||
}
|
||||
|
||||
if (BindingNumberExists(setLayout.bindings, binding.binding)) {
|
||||
if (BindingNumberExists(setLayout.bindings, binding.location.binding)) {
|
||||
return failLayout("BuiltinForwardPipeline encountered duplicate bindings inside one descriptor set");
|
||||
}
|
||||
|
||||
@@ -668,40 +575,22 @@ BuiltinForwardPipeline::PassResourceLayout* BuiltinForwardPipeline::GetOrCreateP
|
||||
}
|
||||
|
||||
RHI::DescriptorSetLayoutBinding layoutBinding = {};
|
||||
layoutBinding.binding = binding.binding;
|
||||
layoutBinding.binding = binding.location.binding;
|
||||
layoutBinding.type = static_cast<uint32_t>(descriptorType);
|
||||
layoutBinding.count = 1;
|
||||
setLayout.bindings.push_back(layoutBinding);
|
||||
|
||||
switch (semantic) {
|
||||
case ForwardPassSemantic::PerObject:
|
||||
if (binding.type != Resources::ShaderResourceType::ConstantBuffer || passLayout.perObject.IsValid()) {
|
||||
return failLayout("BuiltinForwardPipeline requires a single constant-buffer PerObject resource");
|
||||
}
|
||||
passLayout.perObject = { binding.set, binding.binding };
|
||||
switch (binding.semantic) {
|
||||
case BuiltinPassResourceSemantic::PerObject:
|
||||
setLayout.usesPerObject = true;
|
||||
break;
|
||||
case ForwardPassSemantic::Material:
|
||||
if (binding.type != Resources::ShaderResourceType::ConstantBuffer || passLayout.material.IsValid()) {
|
||||
return failLayout("BuiltinForwardPipeline requires a single constant-buffer Material resource");
|
||||
}
|
||||
passLayout.material = { binding.set, binding.binding };
|
||||
case BuiltinPassResourceSemantic::Material:
|
||||
setLayout.usesMaterial = true;
|
||||
break;
|
||||
case ForwardPassSemantic::BaseColorTexture:
|
||||
if ((binding.type != Resources::ShaderResourceType::Texture2D &&
|
||||
binding.type != Resources::ShaderResourceType::TextureCube) ||
|
||||
passLayout.baseColorTexture.IsValid()) {
|
||||
return failLayout("BuiltinForwardPipeline requires a single texture BaseColorTexture resource");
|
||||
}
|
||||
passLayout.baseColorTexture = { binding.set, binding.binding };
|
||||
case BuiltinPassResourceSemantic::BaseColorTexture:
|
||||
setLayout.usesTexture = true;
|
||||
break;
|
||||
case ForwardPassSemantic::LinearClampSampler:
|
||||
if (binding.type != Resources::ShaderResourceType::Sampler || passLayout.linearClampSampler.IsValid()) {
|
||||
return failLayout("BuiltinForwardPipeline requires a single sampler LinearClampSampler resource");
|
||||
}
|
||||
passLayout.linearClampSampler = { binding.set, binding.binding };
|
||||
case BuiltinPassResourceSemantic::LinearClampSampler:
|
||||
setLayout.usesSampler = true;
|
||||
break;
|
||||
default:
|
||||
@@ -718,7 +607,7 @@ BuiltinForwardPipeline::PassResourceLayout* BuiltinForwardPipeline::GetOrCreateP
|
||||
!passLayout.setLayouts.empty() &&
|
||||
passLayout.setLayouts[0].bindings.empty()) {
|
||||
PassSetLayoutMetadata& compatibilitySet = passLayout.setLayouts[0];
|
||||
if (usesConstantBuffers) {
|
||||
if (bindingPlan.usesConstantBuffers) {
|
||||
compatibilitySet.bindings.push_back({
|
||||
0,
|
||||
static_cast<uint32_t>(RHI::DescriptorType::CBV),
|
||||
@@ -726,7 +615,7 @@ BuiltinForwardPipeline::PassResourceLayout* BuiltinForwardPipeline::GetOrCreateP
|
||||
0
|
||||
});
|
||||
}
|
||||
if (usesTextures) {
|
||||
if (bindingPlan.usesTextures) {
|
||||
compatibilitySet.bindings.push_back({
|
||||
0,
|
||||
static_cast<uint32_t>(RHI::DescriptorType::SRV),
|
||||
@@ -734,7 +623,7 @@ BuiltinForwardPipeline::PassResourceLayout* BuiltinForwardPipeline::GetOrCreateP
|
||||
0
|
||||
});
|
||||
}
|
||||
if (usesSamplers) {
|
||||
if (bindingPlan.usesSamplers) {
|
||||
compatibilitySet.bindings.push_back({
|
||||
0,
|
||||
static_cast<uint32_t>(RHI::DescriptorType::Sampler),
|
||||
|
||||
Reference in New Issue
Block a user