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:
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <XCEngine/Core/Asset/ResourceHandle.h>
|
||||
#include <XCEngine/Core/Containers/String.h>
|
||||
#include <XCEngine/Rendering/Execution/ScenePhase.h>
|
||||
#include <XCEngine/Rendering/FrameData/CullingResults.h>
|
||||
#include <XCEngine/Resources/Material/Material.h>
|
||||
@@ -12,10 +13,15 @@ struct DrawSettings {
|
||||
ScenePhase scenePhase = ScenePhase::Opaque;
|
||||
RendererListDesc rendererListDesc = {};
|
||||
Resources::ResourceHandle<Resources::Material> overrideMaterial = {};
|
||||
Containers::String shaderPassName = {};
|
||||
|
||||
bool HasOverrideMaterial() const {
|
||||
return overrideMaterial.IsValid();
|
||||
}
|
||||
|
||||
bool HasShaderPassName() const {
|
||||
return !shaderPassName.Empty();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace Rendering
|
||||
|
||||
@@ -297,10 +297,12 @@ private:
|
||||
void DestroyPipelineResources();
|
||||
static bool TryResolveSurfacePassType(
|
||||
const Resources::Material* material,
|
||||
const BuiltinMaterialPass* preferredPass,
|
||||
BuiltinMaterialPass& outPass);
|
||||
ResolvedShaderPass ResolveSurfaceShaderPass(
|
||||
const RenderSceneData& sceneData,
|
||||
const Resources::Material* material) const;
|
||||
const Resources::Material* material,
|
||||
const BuiltinMaterialPass* preferredPass) const;
|
||||
PassResourceLayout* GetOrCreatePassResourceLayout(
|
||||
const RenderContext& context,
|
||||
const ResolvedShaderPass& resolvedShaderPass);
|
||||
@@ -308,7 +310,8 @@ private:
|
||||
const RenderContext& context,
|
||||
const RenderSurface& surface,
|
||||
const RenderSceneData& sceneData,
|
||||
const Resources::Material* material);
|
||||
const Resources::Material* material,
|
||||
const BuiltinMaterialPass* preferredPass);
|
||||
RHI::RHIPipelineState* GetOrCreateSkyboxPipelineState(
|
||||
const RenderContext& context,
|
||||
const RenderSurface& surface);
|
||||
@@ -364,7 +367,8 @@ private:
|
||||
bool DrawVisibleItem(
|
||||
const FrameExecutionContext& executionContext,
|
||||
const VisibleRenderItem& visibleItem,
|
||||
const Resources::Material* material);
|
||||
const Resources::Material* material,
|
||||
const BuiltinMaterialPass* preferredPass);
|
||||
bool EnsureSkyboxResources(const RenderContext& context);
|
||||
bool CreateSkyboxResources(const RenderContext& context);
|
||||
void DestroySkyboxResources();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -20,6 +20,7 @@ namespace XCEngine.Rendering.Universal
|
||||
public bool overrideRenderLayerMask;
|
||||
public uint renderLayerMask = uint.MaxValue;
|
||||
public string overrideMaterialPath = string.Empty;
|
||||
public string shaderPassName = string.Empty;
|
||||
public bool overrideFilteringSettings;
|
||||
public FilteringSettings filteringSettings;
|
||||
public bool overrideSortingSettings;
|
||||
@@ -111,6 +112,8 @@ namespace XCEngine.Rendering.Universal
|
||||
DrawingSettings.CreateDefault();
|
||||
drawingSettings.overrideMaterialPath =
|
||||
overrideMaterialPath ?? string.Empty;
|
||||
drawingSettings.shaderPassName =
|
||||
shaderPassName ?? string.Empty;
|
||||
return drawingSettings;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -782,7 +782,8 @@ namespace XCEngine
|
||||
ulong nativeHandle,
|
||||
int scenePhase,
|
||||
ref Rendering.RendererListDesc rendererListDesc,
|
||||
string overrideMaterialPath);
|
||||
string overrideMaterialPath,
|
||||
string shaderPassName);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern bool
|
||||
|
||||
@@ -3,16 +3,22 @@ namespace XCEngine.Rendering
|
||||
public struct DrawingSettings
|
||||
{
|
||||
public string overrideMaterialPath;
|
||||
public string shaderPassName;
|
||||
|
||||
public bool hasOverrideMaterial =>
|
||||
!string.IsNullOrEmpty(
|
||||
overrideMaterialPath);
|
||||
|
||||
public bool hasShaderPassName =>
|
||||
!string.IsNullOrEmpty(
|
||||
shaderPassName);
|
||||
|
||||
public static DrawingSettings CreateDefault()
|
||||
{
|
||||
return new DrawingSettings
|
||||
{
|
||||
overrideMaterialPath = string.Empty
|
||||
overrideMaterialPath = string.Empty,
|
||||
shaderPassName = string.Empty
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,6 +107,8 @@ namespace XCEngine.Rendering
|
||||
(int)scenePhase,
|
||||
ref rendererListDesc,
|
||||
drawingSettings.overrideMaterialPath ??
|
||||
string.Empty,
|
||||
drawingSettings.shaderPassName ??
|
||||
string.Empty);
|
||||
}
|
||||
|
||||
|
||||
@@ -139,6 +139,8 @@ namespace ProjectScripts
|
||||
RenderPassEvent.RenderOpaques,
|
||||
scenePhase =
|
||||
SceneRenderPhase.Opaque,
|
||||
shaderPassName =
|
||||
"Unlit",
|
||||
overrideMaterialPath =
|
||||
"Assets/New Material.mat",
|
||||
overrideRenderQueueRange = true,
|
||||
|
||||
Reference in New Issue
Block a user