Generalize builtin pass resource binding plan
This commit is contained in:
@@ -68,19 +68,10 @@ private:
|
||||
Math::Vector4 mainLightColorAndFlags = Math::Vector4::Zero();
|
||||
};
|
||||
|
||||
struct PerMaterialConstants {
|
||||
struct FallbackPerMaterialConstants {
|
||||
Math::Vector4 baseColorFactor = Math::Vector4::One();
|
||||
};
|
||||
|
||||
struct DescriptorBindingLocation {
|
||||
Core::uint32 set = UINT32_MAX;
|
||||
Core::uint32 binding = UINT32_MAX;
|
||||
|
||||
bool IsValid() const {
|
||||
return set != UINT32_MAX && binding != UINT32_MAX;
|
||||
}
|
||||
};
|
||||
|
||||
struct PassLayoutKey {
|
||||
const Resources::Shader* shader = nullptr;
|
||||
Containers::String passName;
|
||||
@@ -115,10 +106,10 @@ private:
|
||||
Core::uint32 descriptorSetCount = 0;
|
||||
std::vector<PassSetLayoutMetadata> setLayouts;
|
||||
std::vector<OwnedDescriptorSet> staticDescriptorSets;
|
||||
DescriptorBindingLocation perObject = {};
|
||||
DescriptorBindingLocation material = {};
|
||||
DescriptorBindingLocation baseColorTexture = {};
|
||||
DescriptorBindingLocation linearClampSampler = {};
|
||||
PassResourceBindingLocation perObject = {};
|
||||
PassResourceBindingLocation material = {};
|
||||
PassResourceBindingLocation baseColorTexture = {};
|
||||
PassResourceBindingLocation linearClampSampler = {};
|
||||
};
|
||||
|
||||
struct DynamicDescriptorSetKey {
|
||||
@@ -209,7 +200,7 @@ private:
|
||||
Core::uint32 setIndex,
|
||||
Core::uint64 objectId,
|
||||
const Resources::Material* material,
|
||||
const PerMaterialConstants& materialConstants,
|
||||
const MaterialConstantPayloadView& materialConstants,
|
||||
RHI::RHIResourceView* textureView);
|
||||
void DestroyOwnedDescriptorSet(OwnedDescriptorSet& descriptorSet);
|
||||
void DestroyPassResourceLayout(PassResourceLayout& passLayout);
|
||||
|
||||
@@ -7,7 +7,9 @@
|
||||
#include <XCEngine/Resources/Mesh/Mesh.h>
|
||||
#include <XCEngine/Rendering/VisibleRenderObject.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Rendering {
|
||||
@@ -21,6 +23,53 @@ enum class BuiltinMaterialPass : Core::uint32 {
|
||||
Forward = ForwardLit
|
||||
};
|
||||
|
||||
struct PassResourceBindingLocation {
|
||||
Core::uint32 set = UINT32_MAX;
|
||||
Core::uint32 binding = UINT32_MAX;
|
||||
|
||||
bool IsValid() const {
|
||||
return set != UINT32_MAX && binding != UINT32_MAX;
|
||||
}
|
||||
};
|
||||
|
||||
enum class BuiltinPassResourceSemantic : Core::uint8 {
|
||||
Unknown = 0,
|
||||
PerObject,
|
||||
Material,
|
||||
BaseColorTexture,
|
||||
LinearClampSampler
|
||||
};
|
||||
|
||||
struct BuiltinPassResourceBindingDesc {
|
||||
BuiltinPassResourceSemantic semantic = BuiltinPassResourceSemantic::Unknown;
|
||||
Resources::ShaderResourceType resourceType = Resources::ShaderResourceType::ConstantBuffer;
|
||||
PassResourceBindingLocation location = {};
|
||||
};
|
||||
|
||||
struct BuiltinPassResourceBindingPlan {
|
||||
Containers::Array<BuiltinPassResourceBindingDesc> bindings;
|
||||
Core::uint32 maxSetIndex = 0;
|
||||
Core::uint32 firstDescriptorSet = 0;
|
||||
Core::uint32 descriptorSetCount = 0;
|
||||
bool usesConstantBuffers = false;
|
||||
bool usesTextures = false;
|
||||
bool usesSamplers = false;
|
||||
PassResourceBindingLocation perObject = {};
|
||||
PassResourceBindingLocation material = {};
|
||||
PassResourceBindingLocation baseColorTexture = {};
|
||||
PassResourceBindingLocation linearClampSampler = {};
|
||||
|
||||
const BuiltinPassResourceBindingDesc* FindBinding(BuiltinPassResourceSemantic semantic) const {
|
||||
for (const BuiltinPassResourceBindingDesc& binding : bindings) {
|
||||
if (binding.semantic == semantic) {
|
||||
return &binding;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
inline Containers::String NormalizeBuiltinPassMetadataValue(const Containers::String& value) {
|
||||
return value.Trim().ToLower();
|
||||
}
|
||||
@@ -120,6 +169,180 @@ inline bool ShaderPassMatchesBuiltinPass(
|
||||
return hasMetadata;
|
||||
}
|
||||
|
||||
inline BuiltinPassResourceSemantic ResolveBuiltinPassResourceSemantic(
|
||||
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 BuiltinPassResourceSemantic::PerObject;
|
||||
}
|
||||
|
||||
if (semantic == Containers::String("material") ||
|
||||
semantic == Containers::String("materialconstants")) {
|
||||
return BuiltinPassResourceSemantic::Material;
|
||||
}
|
||||
|
||||
if (semantic == Containers::String("basecolortexture") ||
|
||||
semantic == Containers::String("maintex")) {
|
||||
return BuiltinPassResourceSemantic::BaseColorTexture;
|
||||
}
|
||||
|
||||
if (semantic == Containers::String("linearclampsampler")) {
|
||||
return BuiltinPassResourceSemantic::LinearClampSampler;
|
||||
}
|
||||
|
||||
return BuiltinPassResourceSemantic::Unknown;
|
||||
}
|
||||
|
||||
inline Containers::Array<Resources::ShaderResourceBindingDesc> BuildLegacyBuiltinForwardPassResourceBindings() {
|
||||
Containers::Array<Resources::ShaderResourceBindingDesc> bindings;
|
||||
bindings.Resize(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;
|
||||
}
|
||||
|
||||
inline bool IsBuiltinPassResourceTypeCompatible(
|
||||
BuiltinPassResourceSemantic semantic,
|
||||
Resources::ShaderResourceType type) {
|
||||
switch (semantic) {
|
||||
case BuiltinPassResourceSemantic::PerObject:
|
||||
case BuiltinPassResourceSemantic::Material:
|
||||
return type == Resources::ShaderResourceType::ConstantBuffer;
|
||||
case BuiltinPassResourceSemantic::BaseColorTexture:
|
||||
return type == Resources::ShaderResourceType::Texture2D ||
|
||||
type == Resources::ShaderResourceType::TextureCube;
|
||||
case BuiltinPassResourceSemantic::LinearClampSampler:
|
||||
return type == Resources::ShaderResourceType::Sampler;
|
||||
case BuiltinPassResourceSemantic::Unknown:
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool TryBuildBuiltinPassResourceBindingPlan(
|
||||
const Containers::Array<Resources::ShaderResourceBindingDesc>& bindings,
|
||||
BuiltinPassResourceBindingPlan& outPlan,
|
||||
Containers::String* outError = nullptr) {
|
||||
outPlan = {};
|
||||
|
||||
auto fail = [&outError](const char* message) {
|
||||
if (outError != nullptr) {
|
||||
*outError = message;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
if (bindings.Empty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
outPlan.bindings.Reserve(bindings.Size());
|
||||
Core::uint32 minBoundSet = UINT32_MAX;
|
||||
Core::uint32 maxBoundSet = 0;
|
||||
|
||||
for (const Resources::ShaderResourceBindingDesc& binding : bindings) {
|
||||
const BuiltinPassResourceSemantic semantic = ResolveBuiltinPassResourceSemantic(binding);
|
||||
if (semantic == BuiltinPassResourceSemantic::Unknown) {
|
||||
return fail("Unsupported builtin pass resource semantic");
|
||||
}
|
||||
if (!IsBuiltinPassResourceTypeCompatible(semantic, binding.type)) {
|
||||
return fail("Builtin pass resource semantic/type combination is invalid");
|
||||
}
|
||||
|
||||
PassResourceBindingLocation* location = nullptr;
|
||||
switch (semantic) {
|
||||
case BuiltinPassResourceSemantic::PerObject:
|
||||
location = &outPlan.perObject;
|
||||
break;
|
||||
case BuiltinPassResourceSemantic::Material:
|
||||
location = &outPlan.material;
|
||||
break;
|
||||
case BuiltinPassResourceSemantic::BaseColorTexture:
|
||||
location = &outPlan.baseColorTexture;
|
||||
break;
|
||||
case BuiltinPassResourceSemantic::LinearClampSampler:
|
||||
location = &outPlan.linearClampSampler;
|
||||
break;
|
||||
case BuiltinPassResourceSemantic::Unknown:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (location == nullptr) {
|
||||
return fail("Builtin pass resource semantic could not be mapped");
|
||||
}
|
||||
if (location->IsValid()) {
|
||||
return fail("Builtin pass resource semantic appears more than once");
|
||||
}
|
||||
|
||||
for (const BuiltinPassResourceBindingDesc& existingBinding : outPlan.bindings) {
|
||||
if (existingBinding.location.set == binding.set &&
|
||||
existingBinding.location.binding == binding.binding) {
|
||||
return fail("Builtin pass resource set/binding pair appears more than once");
|
||||
}
|
||||
}
|
||||
|
||||
*location = { binding.set, binding.binding };
|
||||
|
||||
BuiltinPassResourceBindingDesc resolvedBinding = {};
|
||||
resolvedBinding.semantic = semantic;
|
||||
resolvedBinding.resourceType = binding.type;
|
||||
resolvedBinding.location = *location;
|
||||
outPlan.bindings.PushBack(resolvedBinding);
|
||||
|
||||
outPlan.maxSetIndex = std::max(outPlan.maxSetIndex, binding.set);
|
||||
minBoundSet = std::min(minBoundSet, binding.set);
|
||||
maxBoundSet = std::max(maxBoundSet, binding.set);
|
||||
|
||||
switch (binding.type) {
|
||||
case Resources::ShaderResourceType::ConstantBuffer:
|
||||
outPlan.usesConstantBuffers = true;
|
||||
break;
|
||||
case Resources::ShaderResourceType::Texture2D:
|
||||
case Resources::ShaderResourceType::TextureCube:
|
||||
outPlan.usesTextures = true;
|
||||
break;
|
||||
case Resources::ShaderResourceType::Sampler:
|
||||
outPlan.usesSamplers = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
outPlan.firstDescriptorSet = minBoundSet;
|
||||
outPlan.descriptorSetCount = maxBoundSet - minBoundSet + 1u;
|
||||
return true;
|
||||
}
|
||||
|
||||
struct BuiltinForwardMaterialData {
|
||||
Math::Vector4 baseColorFactor = Math::Vector4::One();
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user