feat(srp): add shader pass selection for scene draws

- let DrawingSettings carry an optional shaderPassName across managed and native scene draw APIs
- allow RenderObjectsRendererFeature to author explicit ForwardLit or Unlit scene draws
- exercise the new scene draw pass selection seam in the project render pipeline probe
This commit is contained in:
2026-04-20 22:58:08 +08:00
parent 0319680954
commit cd6f9aa4cf
9 changed files with 134 additions and 17 deletions

View File

@@ -106,6 +106,32 @@ bool UsesDynamicSurfaceDescriptorSet(const BuiltinPassSetLayoutMetadata& setLayo
setLayout.usesMaterialBuffers;
}
bool TryResolveRequestedSurfacePassType(
const DrawSettings& drawSettings,
BuiltinMaterialPass& outPass,
bool& outHasRequestedPass) {
outHasRequestedPass = false;
if (!drawSettings.HasShaderPassName()) {
return true;
}
outHasRequestedPass = true;
const Containers::String normalizedPassName =
NormalizeBuiltinPassMetadataValue(drawSettings.shaderPassName);
if (normalizedPassName == Containers::String("forward") ||
MatchesBuiltinPassName(normalizedPassName, BuiltinMaterialPass::ForwardLit)) {
outPass = BuiltinMaterialPass::ForwardLit;
return true;
}
if (MatchesBuiltinPassName(normalizedPassName, BuiltinMaterialPass::Unlit)) {
outPass = BuiltinMaterialPass::Unlit;
return true;
}
return false;
}
} // namespace
RHI::InputLayoutDesc BuiltinForwardPipeline::BuildInputLayout() {
@@ -172,7 +198,17 @@ RHI::InputLayoutDesc BuiltinForwardPipeline::BuildInputLayout() {
bool BuiltinForwardPipeline::TryResolveSurfacePassType(
const Resources::Material* material,
const BuiltinMaterialPass* preferredPass,
BuiltinMaterialPass& outPass) {
if (preferredPass != nullptr) {
if (MatchesBuiltinPass(material, *preferredPass)) {
outPass = *preferredPass;
return true;
}
return false;
}
if (MatchesBuiltinPass(material, BuiltinMaterialPass::Unlit)) {
outPass = BuiltinMaterialPass::Unlit;
return true;
@@ -188,10 +224,14 @@ bool BuiltinForwardPipeline::TryResolveSurfacePassType(
BuiltinForwardPipeline::ResolvedShaderPass BuiltinForwardPipeline::ResolveSurfaceShaderPass(
const RenderSceneData& sceneData,
const Resources::Material* material) const {
const Resources::Material* material,
const BuiltinMaterialPass* preferredPass) const {
ResolvedShaderPass resolved = {};
BuiltinMaterialPass pass = BuiltinMaterialPass::ForwardLit;
if (!TryResolveSurfacePassType(material, pass)) {
BuiltinMaterialPass pass =
preferredPass != nullptr
? *preferredPass
: BuiltinMaterialPass::ForwardLit;
if (!TryResolveSurfacePassType(material, preferredPass, pass)) {
return resolved;
}
@@ -227,9 +267,14 @@ RHI::RHIPipelineState* BuiltinForwardPipeline::GetOrCreatePipelineState(
const RenderContext& context,
const RenderSurface& surface,
const RenderSceneData& sceneData,
const Resources::Material* material) {
const Resources::Material* material,
const BuiltinMaterialPass* preferredPass) {
const Resources::ShaderKeywordSet keywordSet = ResolvePassKeywordSet(sceneData, material);
const ResolvedShaderPass resolvedShaderPass = ResolveSurfaceShaderPass(sceneData, material);
const ResolvedShaderPass resolvedShaderPass =
ResolveSurfaceShaderPass(
sceneData,
material,
preferredPass);
if (resolvedShaderPass.shader == nullptr || resolvedShaderPass.pass == nullptr) {
Debug::Logger::Get().Error(
Debug::LogCategory::Rendering,
@@ -402,7 +447,8 @@ bool BuiltinForwardPipeline::ExecuteForwardTransparentPass(
bool BuiltinForwardPipeline::DrawVisibleItem(
const FrameExecutionContext& executionContext,
const VisibleRenderItem& visibleItem,
const Resources::Material* material) {
const Resources::Material* material,
const BuiltinMaterialPass* preferredPass) {
const RenderContext& context = executionContext.renderContext;
const RenderSceneData& sceneData = executionContext.sceneData;
@@ -435,7 +481,11 @@ bool BuiltinForwardPipeline::DrawVisibleItem(
shadowReceiverConstants.shadowSampling = sceneData.lighting.mainDirectionalShadow.sampling;
}
const ResolvedShaderPass resolvedShaderPass = ResolveSurfaceShaderPass(sceneData, material);
const ResolvedShaderPass resolvedShaderPass =
ResolveSurfaceShaderPass(
sceneData,
material,
preferredPass);
if (resolvedShaderPass.shader == nullptr || resolvedShaderPass.pass == nullptr) {
return false;
}
@@ -578,6 +628,25 @@ bool BuiltinForwardPipeline::DrawVisibleItems(
RHI::RHICommandList* commandList = context.commandList;
RHI::RHIPipelineState* currentPipelineState = nullptr;
bool drawFailed = false;
BuiltinMaterialPass requestedPass = BuiltinMaterialPass::ForwardLit;
bool hasRequestedPass = false;
if (!TryResolveRequestedSurfacePassType(
drawSettings,
requestedPass,
hasRequestedPass)) {
Debug::Logger::Get().Error(
Debug::LogCategory::Rendering,
(Containers::String(
"BuiltinForwardPipeline only supports explicit shaderPassName values of ForwardLit or Unlit for scene draws, received: ") +
drawSettings.shaderPassName)
.CStr());
return false;
}
const BuiltinMaterialPass* preferredPass =
hasRequestedPass
? &requestedPass
: nullptr;
auto drawVisibleItem = [&](const VisibleRenderItem& visibleItem) {
if (drawFailed) {
@@ -588,12 +657,24 @@ bool BuiltinForwardPipeline::DrawVisibleItems(
drawSettings.HasOverrideMaterial()
? drawSettings.overrideMaterial.Get()
: ResolveMaterial(visibleItem);
BuiltinMaterialPass pass = BuiltinMaterialPass::ForwardLit;
if (!TryResolveSurfacePassType(material, pass)) {
BuiltinMaterialPass pass =
preferredPass != nullptr
? *preferredPass
: BuiltinMaterialPass::ForwardLit;
if (!TryResolveSurfacePassType(
material,
preferredPass,
pass)) {
return;
}
RHI::RHIPipelineState* pipelineState = GetOrCreatePipelineState(context, surface, sceneData, material);
RHI::RHIPipelineState* pipelineState =
GetOrCreatePipelineState(
context,
surface,
sceneData,
material,
preferredPass);
if (pipelineState == nullptr) {
drawFailed = true;
return;
@@ -603,7 +684,11 @@ bool BuiltinForwardPipeline::DrawVisibleItems(
currentPipelineState = pipelineState;
}
if (!DrawVisibleItem(executionContext, visibleItem, material)) {
if (!DrawVisibleItem(
executionContext,
visibleItem,
material,
preferredPass)) {
drawFailed = true;
}
};

View File

@@ -4592,7 +4592,8 @@ InternalCall_Rendering_ScriptableRenderContext_DrawRenderersByDesc(
uint64_t nativeHandle,
int32_t scenePhase,
ManagedRendererListDescData* rendererListDescData,
MonoString* overrideMaterialPath) {
MonoString* overrideMaterialPath,
MonoString* shaderPassName) {
ManagedScriptableRenderContextState* const state =
FindManagedScriptableRenderContextState(nativeHandle);
if (state == nullptr ||
@@ -4626,6 +4627,13 @@ InternalCall_Rendering_ScriptableRenderContext_DrawRenderersByDesc(
}
}
const std::string shaderPassNameUtf8 =
MonoStringToUtf8(shaderPassName);
if (!shaderPassNameUtf8.empty()) {
drawSettings.shaderPassName =
Containers::String(shaderPassNameUtf8.c_str());
}
return state->sceneRecorder->RecordSceneDrawSettings(
drawSettings)
? 1