rendering: thread global shader keywords into builtin variants

This commit is contained in:
2026-04-06 20:30:25 +08:00
parent 0761079b4c
commit c318f34f07
14 changed files with 119 additions and 26 deletions

View File

@@ -23,14 +23,22 @@ namespace {
constexpr float kForwardAmbientIntensity = 0.28f;
constexpr float kSpotInnerAngleRatio = 0.8f;
Resources::ShaderKeywordSet ResolvePassKeywordSet(
const RenderSceneData& sceneData,
const Resources::Material* material) {
return Resources::CombineShaderKeywordSets(
sceneData.globalShaderKeywords,
material != nullptr ? material->GetKeywordSet() : Resources::ShaderKeywordSet());
}
const Resources::ShaderPass* FindCompatibleSurfacePass(
const Resources::Shader& shader,
const RenderSceneData& sceneData,
const Resources::Material* material,
BuiltinMaterialPass pass,
Resources::ShaderBackend backend) {
const bool shaderHasExplicitBuiltinMetadata = ShaderHasExplicitBuiltinMetadata(shader);
const Resources::ShaderKeywordSet keywordSet =
material != nullptr ? material->GetKeywordSet() : Resources::ShaderKeywordSet();
const Resources::ShaderKeywordSet keywordSet = ResolvePassKeywordSet(sceneData, material);
for (const Resources::ShaderPass& shaderPass : shader.GetPasses()) {
if (ShaderPassMatchesBuiltinPass(shaderPass, pass) &&
@@ -102,6 +110,7 @@ RHI::GraphicsPipelineDesc CreatePipelineDesc(
RHI::RHIPipelineLayout* pipelineLayout,
const Resources::Shader& shader,
const Containers::String& passName,
const Resources::ShaderKeywordSet& keywordSet,
const Resources::Material* material) {
RHI::GraphicsPipelineDesc pipelineDesc = {};
pipelineDesc.pipelineLayout = pipelineLayout;
@@ -115,8 +124,6 @@ RHI::GraphicsPipelineDesc CreatePipelineDesc(
pipelineDesc.inputLayout = BuiltinForwardPipeline::BuildInputLayout();
const Resources::ShaderBackend backend = ::XCEngine::Rendering::Detail::ToShaderBackend(backendType);
const Resources::ShaderKeywordSet keywordSet =
material != nullptr ? material->GetKeywordSet() : Resources::ShaderKeywordSet();
const Resources::ShaderStageVariant* vertexVariant =
shader.FindVariant(passName, Resources::ShaderType::Vertex, backend, keywordSet);
const Resources::ShaderStageVariant* fragmentVariant =
@@ -150,6 +157,7 @@ bool BuiltinForwardPipeline::TryResolveSurfacePassType(
}
BuiltinForwardPipeline::ResolvedShaderPass BuiltinForwardPipeline::ResolveSurfaceShaderPass(
const RenderSceneData& sceneData,
const Resources::Material* material) const {
ResolvedShaderPass resolved = {};
BuiltinMaterialPass pass = BuiltinMaterialPass::ForwardLit;
@@ -162,7 +170,7 @@ BuiltinForwardPipeline::ResolvedShaderPass BuiltinForwardPipeline::ResolveSurfac
if (material != nullptr && material->GetShader() != nullptr) {
const Resources::Shader* materialShader = material->GetShader();
if (const Resources::ShaderPass* shaderPass =
FindCompatibleSurfacePass(*materialShader, material, pass, backend)) {
FindCompatibleSurfacePass(*materialShader, sceneData, material, pass, backend)) {
resolved.shader = materialShader;
resolved.pass = shaderPass;
resolved.passName = shaderPass->name;
@@ -175,7 +183,7 @@ BuiltinForwardPipeline::ResolvedShaderPass BuiltinForwardPipeline::ResolveSurfac
if (builtinShaderHandle->IsValid()) {
const Resources::Shader* builtinShader = builtinShaderHandle->Get();
if (const Resources::ShaderPass* shaderPass =
FindCompatibleSurfacePass(*builtinShader, nullptr, pass, backend)) {
FindCompatibleSurfacePass(*builtinShader, sceneData, nullptr, pass, backend)) {
resolved.shader = builtinShader;
resolved.pass = shaderPass;
resolved.passName = shaderPass->name;
@@ -274,8 +282,10 @@ BuiltinForwardPipeline::PassResourceLayout* BuiltinForwardPipeline::GetOrCreateP
RHI::RHIPipelineState* BuiltinForwardPipeline::GetOrCreatePipelineState(
const RenderContext& context,
const RenderSceneData& sceneData,
const Resources::Material* material) {
const ResolvedShaderPass resolvedShaderPass = ResolveSurfaceShaderPass(material);
const Resources::ShaderKeywordSet keywordSet = ResolvePassKeywordSet(sceneData, material);
const ResolvedShaderPass resolvedShaderPass = ResolveSurfaceShaderPass(sceneData, material);
if (resolvedShaderPass.shader == nullptr || resolvedShaderPass.pass == nullptr) {
Debug::Logger::Get().Error(
Debug::LogCategory::Rendering,
@@ -293,9 +303,7 @@ RHI::RHIPipelineState* BuiltinForwardPipeline::GetOrCreatePipelineState(
material != nullptr ? material->GetRenderState() : Resources::MaterialRenderState();
pipelineKey.shader = resolvedShaderPass.shader;
pipelineKey.passName = resolvedShaderPass.passName;
pipelineKey.keywordSignature =
::XCEngine::Rendering::Detail::BuildShaderKeywordSignature(
material != nullptr ? material->GetKeywordSet() : Resources::ShaderKeywordSet());
pipelineKey.keywordSignature = ::XCEngine::Rendering::Detail::BuildShaderKeywordSignature(keywordSet);
const auto existing = m_pipelineStates.find(pipelineKey);
if (existing != m_pipelineStates.end()) {
@@ -308,6 +316,7 @@ RHI::RHIPipelineState* BuiltinForwardPipeline::GetOrCreatePipelineState(
passLayout->pipelineLayout,
*resolvedShaderPass.shader,
resolvedShaderPass.passName,
keywordSet,
material);
RHI::RHIPipelineState* pipelineState = context.device->CreatePipelineState(pipelineDesc);
if (pipelineState == nullptr || !pipelineState->IsValid()) {
@@ -665,7 +674,7 @@ bool BuiltinForwardPipeline::DrawVisibleItem(
};
const Resources::Material* material = ResolveMaterial(visibleItem);
const ResolvedShaderPass resolvedShaderPass = ResolveSurfaceShaderPass(material);
const ResolvedShaderPass resolvedShaderPass = ResolveSurfaceShaderPass(sceneData, material);
if (resolvedShaderPass.shader == nullptr || resolvedShaderPass.pass == nullptr) {
return false;
}