fix(rendering): derive URP stages from pass queue
This commit is contained in:
@@ -35,7 +35,7 @@ Unity 兼容的公开命名、对象所有权和扩展点。
|
||||
- 将 `BuiltinForwardPipeline` 从策略中心降级为默认 native scene draw backend。它可以
|
||||
继续作为 backend/fallback 实现存在,但不应决定 URP pass 顺序、feature 参与方式或
|
||||
stage 策略。
|
||||
- 让 `ScriptableRenderer` 及其 active pass queue 成为 URP main-scene scheduling 的权威。
|
||||
- 让 `ScriptableRenderer` 及其 active pass queue 成为 URP stage planning 和 recording 的权威。
|
||||
Opaque、skybox、transparent、depth、shadow、post 和 final-output 流程应来自 URP
|
||||
blocks 和 passes。
|
||||
- 保持 `DrawObjectsPass` 和 `DrawSkyboxPass` 作为 managed URP pass declarations,并通过
|
||||
@@ -210,6 +210,9 @@ package。
|
||||
- `ScriptableRenderer` 按 stage 构建 `m_activePassQueue`。它依次调用 feature `SetupRenderPasses`、feature
|
||||
`AddRenderPasses`,再调用 renderer-owned `AddRenderPasses`;passes 按 `RenderPassEvent` 顺序插入,并归组到
|
||||
`RendererBlocks`。
|
||||
- URP stage planning 以 `ScriptableRenderer` 的 active pass queue 为最终事实源。`ConfigureCameraFramePlan`
|
||||
仍是兼容和高级策略 hook,但它不能单独声明 shadow、depth、post 或 final-output stage;没有被 pass queue
|
||||
覆盖到的 side/fullscreen stage 必须在最终 plan 中清掉。
|
||||
- `RendererBlock` 将 pass events 映射到 camera stages:shadow caster、depth prepass、main opaque、main
|
||||
skybox、main transparent、post process 和 final output。
|
||||
- `UniversalRenderer` 拥有具体 blocks:
|
||||
@@ -219,9 +222,9 @@ package。
|
||||
implementations 包括 `RenderObjectsRendererFeature`、`ColorScalePostProcessRendererFeature` 和
|
||||
`DisableDirectionalShadowRendererFeature`。
|
||||
- 新增 URP feature 时,保持 serializable settings、runtime hash、`Create`、
|
||||
`ConfigureCameraRenderRequest`、`ConfigureCameraFramePlan`、`ConfigureRenderSceneSetup`、
|
||||
`AddRenderPasses` 和 stage gate behavior 一致。如果 feature 需要 stage,先在 planning 阶段 request,
|
||||
再 enqueue pass。
|
||||
`ConfigureCameraRenderRequest`、`ConfigureRenderSceneSetup`、`AddRenderPasses` 和 stage gate behavior 一致。
|
||||
如果 feature 需要 stage,必须 enqueue 一个 `RenderPassEvent` 匹配该 stage 的 pass;不要只依赖
|
||||
`ConfigureCameraFramePlan` 请求 stage。
|
||||
|
||||
### Managed RenderGraph
|
||||
|
||||
@@ -306,7 +309,8 @@ Scene data 每个 camera frame 提取一次,然后由 pipeline 调整。
|
||||
- Managed `CommandBuffer` 和 public `SetRenderFunc` 还不会执行 deferred native command lists。
|
||||
- Managed RenderGraph 当前暴露 raster authoring。Native graph 有 compute pass support,但 managed compute
|
||||
authoring 还未公开。
|
||||
- `UniversalPostProcessBlock` 主要负责 planning 和 promotion。实际 post-process work 当前来自 features/passes。
|
||||
- `UniversalPostProcessBlock` 仍保留 post-process source promotion helper;实际 post-process stage 由
|
||||
active pass queue 中的 features/passes 声明。
|
||||
- `UniversalRendererData` 和 features 是 code-created objects,还不是完整 Unity 风格 serialized asset pipeline。
|
||||
- 当前 shadow support 是单个 main directional shadow path,没有 cascades。
|
||||
- Graph compiler/executor 当前没有实现 pass culling 或 transient aliasing。
|
||||
@@ -325,6 +329,8 @@ Scene data 每个 camera frame 提取一次,然后由 pipeline 调整。
|
||||
RenderGraph。
|
||||
- URP 现在已有 renderer data、renderer features、renderer pass queueing、renderer blocks、renderer-index
|
||||
resolution 和 per-stage recording。
|
||||
- URP stage planning 已收口到 renderer active pass queue 派生的 stage manifest,关闭了 feature planning hook
|
||||
与实际 pass queue 分离的重复事实源。
|
||||
- Public managed RenderGraph raster authoring 已存在;internal fullscreen kernels 仍是 URP implementation
|
||||
details。
|
||||
- Public `ScriptableRenderPass.RecordRenderGraph(RenderGraph, ContextContainer)` 通过 `RenderingData`、
|
||||
|
||||
@@ -423,83 +423,6 @@ namespace Gameplay
|
||||
}
|
||||
}
|
||||
|
||||
public override void ConfigureCameraFramePlan(
|
||||
ScriptableRenderPipelinePlanningContext context)
|
||||
{
|
||||
if (context == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
bool hasPostProcessPass = false;
|
||||
bool hasFinalOutputPass = false;
|
||||
for (int i = 0; i < m_passes.Length; ++i)
|
||||
{
|
||||
ScriptableRenderPass renderPass = m_passes[i];
|
||||
if (renderPass == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (renderPass.SupportsStage(
|
||||
CameraFrameStage.PostProcess))
|
||||
{
|
||||
hasPostProcessPass = true;
|
||||
}
|
||||
|
||||
if (renderPass.SupportsStage(
|
||||
CameraFrameStage.FinalOutput))
|
||||
{
|
||||
hasFinalOutputPass = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool needsGraphManagedPostProcessOutput =
|
||||
context.HasFinalColorProcessing() ||
|
||||
context.IsStageRequested(
|
||||
CameraFrameStage.FinalOutput) ||
|
||||
hasFinalOutputPass;
|
||||
|
||||
if (hasPostProcessPass)
|
||||
{
|
||||
if (!context.IsStageRequested(
|
||||
CameraFrameStage.PostProcess))
|
||||
{
|
||||
context.RequestFullscreenStage(
|
||||
CameraFrameStage.PostProcess,
|
||||
CameraFrameColorSource.MainSceneColor,
|
||||
needsGraphManagedPostProcessOutput);
|
||||
}
|
||||
else if (needsGraphManagedPostProcessOutput &&
|
||||
context.GetStageColorSource(
|
||||
CameraFrameStage.PostProcess) !=
|
||||
CameraFrameColorSource.ExplicitSurface &&
|
||||
!context.UsesGraphManagedOutputColor(
|
||||
CameraFrameStage.PostProcess))
|
||||
{
|
||||
CameraFrameColorSource source =
|
||||
context.GetStageColorSource(
|
||||
CameraFrameStage.PostProcess);
|
||||
context.ClearFullscreenStage(
|
||||
CameraFrameStage.PostProcess);
|
||||
context.RequestFullscreenStage(
|
||||
CameraFrameStage.PostProcess,
|
||||
source,
|
||||
true);
|
||||
}
|
||||
}
|
||||
|
||||
if (hasFinalOutputPass &&
|
||||
!context.IsStageRequested(
|
||||
CameraFrameStage.FinalOutput))
|
||||
{
|
||||
context.RequestFullscreenStage(
|
||||
CameraFrameStage.FinalOutput,
|
||||
hasPostProcessPass
|
||||
? CameraFrameColorSource.PostProcessColor
|
||||
: CameraFrameColorSource.MainSceneColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class ProbeSceneRenderer : ScriptableRenderer
|
||||
|
||||
@@ -71,13 +71,6 @@ namespace XCEngine.Rendering.Universal
|
||||
BuildSettings());
|
||||
}
|
||||
|
||||
public override void ConfigureCameraFramePlan(
|
||||
ScriptableRenderPipelinePlanningContext context)
|
||||
{
|
||||
m_controller.ConfigureCameraFramePlan(
|
||||
context);
|
||||
}
|
||||
|
||||
public override void AddRenderPasses(
|
||||
ScriptableRenderer renderer,
|
||||
RenderingData renderingData)
|
||||
|
||||
@@ -27,6 +27,27 @@ namespace XCEngine.Rendering.Universal
|
||||
{
|
||||
}
|
||||
|
||||
internal static RenderingData CreatePlanning(
|
||||
CameraFrameStage stage,
|
||||
int rendererIndex,
|
||||
bool finalColorRequiresProcessing)
|
||||
{
|
||||
return new RenderingData(
|
||||
stage,
|
||||
rendererIndex,
|
||||
CameraData.Default,
|
||||
LightingData.Default,
|
||||
ShadowData.Default,
|
||||
EnvironmentData.Default,
|
||||
finalColorRequiresProcessing
|
||||
? new FinalColorData(
|
||||
CreatePlanningFinalColorSettings(),
|
||||
true,
|
||||
false)
|
||||
: FinalColorData.Default,
|
||||
StageColorData.Default);
|
||||
}
|
||||
|
||||
internal RenderingData(ScriptableRenderContext context)
|
||||
: this(
|
||||
context != null
|
||||
@@ -116,5 +137,19 @@ namespace XCEngine.Rendering.Universal
|
||||
|
||||
public bool isFinalOutputStage =>
|
||||
stage == CameraFrameStage.FinalOutput;
|
||||
|
||||
private static FinalColorSettings
|
||||
CreatePlanningFinalColorSettings()
|
||||
{
|
||||
FinalColorSettings settings =
|
||||
FinalColorSettings.CreateDefault();
|
||||
settings.finalColorScale =
|
||||
new Vector4(
|
||||
0.5f,
|
||||
0.5f,
|
||||
0.5f,
|
||||
1.0f);
|
||||
return settings;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,14 @@ namespace XCEngine.Rendering.Universal
|
||||
{
|
||||
public abstract class ScriptableRenderer
|
||||
{
|
||||
private struct PassQueueStageManifest
|
||||
{
|
||||
public bool shadowCaster;
|
||||
public bool depthOnly;
|
||||
public bool postProcess;
|
||||
public bool finalOutput;
|
||||
}
|
||||
|
||||
private readonly List<ScriptableRendererFeature> m_features =
|
||||
new List<ScriptableRendererFeature>();
|
||||
private readonly List<ScriptableRenderPass> m_activePassQueue =
|
||||
@@ -118,6 +126,20 @@ namespace XCEngine.Rendering.Universal
|
||||
ConfigureRendererFeaturesCameraFramePlan(context);
|
||||
}
|
||||
|
||||
internal void ConfigurePassQueueCameraFramePlanInstance(
|
||||
ScriptableRenderPipelinePlanningContext context)
|
||||
{
|
||||
if (context == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
PassQueueStageManifest manifest =
|
||||
BuildPassQueueStageManifest(context);
|
||||
ApplyPassQueueStageManifest(context, manifest);
|
||||
ClearPassQueue();
|
||||
}
|
||||
|
||||
internal void FinalizeCameraFramePlanInstance(
|
||||
ScriptableRenderPipelinePlanningContext context)
|
||||
{
|
||||
@@ -282,7 +304,13 @@ namespace XCEngine.Rendering.Universal
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (context.stage)
|
||||
return HasRendererStageBlocks(context.stage);
|
||||
}
|
||||
|
||||
private bool HasRendererStageBlocks(
|
||||
CameraFrameStage stage)
|
||||
{
|
||||
switch (stage)
|
||||
{
|
||||
case CameraFrameStage.ShadowCaster:
|
||||
return HasRendererBlock(
|
||||
@@ -308,6 +336,180 @@ namespace XCEngine.Rendering.Universal
|
||||
}
|
||||
}
|
||||
|
||||
private PassQueueStageManifest BuildPassQueueStageManifest(
|
||||
ScriptableRenderPipelinePlanningContext context)
|
||||
{
|
||||
bool finalColorRequiresProcessing =
|
||||
context.HasFinalColorProcessing();
|
||||
int rendererIndex = context.rendererIndex;
|
||||
|
||||
return new PassQueueStageManifest
|
||||
{
|
||||
shadowCaster =
|
||||
HasPassQueueStage(
|
||||
CameraFrameStage.ShadowCaster,
|
||||
rendererIndex,
|
||||
finalColorRequiresProcessing),
|
||||
depthOnly =
|
||||
HasPassQueueStage(
|
||||
CameraFrameStage.DepthOnly,
|
||||
rendererIndex,
|
||||
finalColorRequiresProcessing),
|
||||
postProcess =
|
||||
HasPassQueueStage(
|
||||
CameraFrameStage.PostProcess,
|
||||
rendererIndex,
|
||||
finalColorRequiresProcessing),
|
||||
finalOutput =
|
||||
HasPassQueueStage(
|
||||
CameraFrameStage.FinalOutput,
|
||||
rendererIndex,
|
||||
finalColorRequiresProcessing)
|
||||
};
|
||||
}
|
||||
|
||||
private bool HasPassQueueStage(
|
||||
CameraFrameStage stage,
|
||||
int rendererIndex,
|
||||
bool finalColorRequiresProcessing)
|
||||
{
|
||||
BuildPassQueue(
|
||||
RenderingData.CreatePlanning(
|
||||
stage,
|
||||
rendererIndex,
|
||||
finalColorRequiresProcessing));
|
||||
return HasRendererStageBlocks(stage);
|
||||
}
|
||||
|
||||
private static void ApplyPassQueueStageManifest(
|
||||
ScriptableRenderPipelinePlanningContext context,
|
||||
PassQueueStageManifest manifest)
|
||||
{
|
||||
if (manifest.shadowCaster)
|
||||
{
|
||||
context.RequestShadowCasterStage();
|
||||
}
|
||||
else
|
||||
{
|
||||
context.ClearShadowCasterStage();
|
||||
}
|
||||
|
||||
if (manifest.depthOnly)
|
||||
{
|
||||
context.RequestCameraDepthOnlyStage();
|
||||
}
|
||||
else
|
||||
{
|
||||
context.ClearDepthOnlyStage();
|
||||
}
|
||||
|
||||
ApplyPostProcessStageManifest(context, manifest);
|
||||
ApplyFinalOutputStageManifest(context, manifest);
|
||||
}
|
||||
|
||||
private static void ApplyPostProcessStageManifest(
|
||||
ScriptableRenderPipelinePlanningContext context,
|
||||
PassQueueStageManifest manifest)
|
||||
{
|
||||
if (!manifest.postProcess)
|
||||
{
|
||||
context.ClearFullscreenStage(
|
||||
CameraFrameStage.PostProcess);
|
||||
return;
|
||||
}
|
||||
|
||||
bool finalOutputReadsPostProcess =
|
||||
ShouldFinalOutputReadPostProcess(
|
||||
context,
|
||||
manifest);
|
||||
|
||||
if (!context.IsStageRequested(
|
||||
CameraFrameStage.PostProcess))
|
||||
{
|
||||
context.RequestFullscreenStage(
|
||||
CameraFrameStage.PostProcess,
|
||||
CameraFrameColorSource.MainSceneColor,
|
||||
finalOutputReadsPostProcess);
|
||||
return;
|
||||
}
|
||||
|
||||
if (finalOutputReadsPostProcess &&
|
||||
!context.UsesGraphManagedOutputColor(
|
||||
CameraFrameStage.PostProcess))
|
||||
{
|
||||
CameraFrameColorSource source =
|
||||
context.GetStageColorSource(
|
||||
CameraFrameStage.PostProcess);
|
||||
context.ClearFullscreenStage(
|
||||
CameraFrameStage.PostProcess);
|
||||
context.RequestFullscreenStage(
|
||||
CameraFrameStage.PostProcess,
|
||||
source,
|
||||
true);
|
||||
}
|
||||
}
|
||||
|
||||
private static bool ShouldFinalOutputReadPostProcess(
|
||||
ScriptableRenderPipelinePlanningContext context,
|
||||
PassQueueStageManifest manifest)
|
||||
{
|
||||
if (!manifest.finalOutput ||
|
||||
!manifest.postProcess)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return !context.IsStageRequested(
|
||||
CameraFrameStage.PostProcess) ||
|
||||
context.GetStageColorSource(
|
||||
CameraFrameStage.PostProcess) !=
|
||||
CameraFrameColorSource.ExplicitSurface;
|
||||
}
|
||||
|
||||
private static void ApplyFinalOutputStageManifest(
|
||||
ScriptableRenderPipelinePlanningContext context,
|
||||
PassQueueStageManifest manifest)
|
||||
{
|
||||
if (!manifest.finalOutput)
|
||||
{
|
||||
context.ClearFullscreenStage(
|
||||
CameraFrameStage.FinalOutput);
|
||||
return;
|
||||
}
|
||||
|
||||
if (context.IsStageRequested(
|
||||
CameraFrameStage.FinalOutput) &&
|
||||
context.GetStageColorSource(
|
||||
CameraFrameStage.FinalOutput) ==
|
||||
CameraFrameColorSource.ExplicitSurface)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
context.ClearFullscreenStage(
|
||||
CameraFrameStage.FinalOutput);
|
||||
context.RequestFullscreenStage(
|
||||
CameraFrameStage.FinalOutput,
|
||||
ResolveFinalOutputSource(context));
|
||||
}
|
||||
|
||||
private static CameraFrameColorSource ResolveFinalOutputSource(
|
||||
ScriptableRenderPipelinePlanningContext context)
|
||||
{
|
||||
if (context == null ||
|
||||
!context.IsStageRequested(
|
||||
CameraFrameStage.PostProcess))
|
||||
{
|
||||
return CameraFrameColorSource.MainSceneColor;
|
||||
}
|
||||
|
||||
return context.GetStageColorSource(
|
||||
CameraFrameStage.PostProcess) ==
|
||||
CameraFrameColorSource.ExplicitSurface
|
||||
? CameraFrameColorSource.MainSceneColor
|
||||
: CameraFrameColorSource.PostProcessColor;
|
||||
}
|
||||
|
||||
protected virtual bool RecordRendererStage(
|
||||
RendererRecordingContext context,
|
||||
RenderGraph renderGraph,
|
||||
@@ -432,8 +634,7 @@ namespace XCEngine.Rendering.Universal
|
||||
private void BuildPassQueue(
|
||||
RenderingData renderingData)
|
||||
{
|
||||
m_activePassQueue.Clear();
|
||||
m_rendererBlocks.Clear();
|
||||
ClearPassQueue();
|
||||
m_isBuildingPassQueue = true;
|
||||
m_passQueueStage =
|
||||
renderingData != null
|
||||
@@ -469,6 +670,12 @@ namespace XCEngine.Rendering.Universal
|
||||
}
|
||||
}
|
||||
|
||||
private void ClearPassQueue()
|
||||
{
|
||||
m_activePassQueue.Clear();
|
||||
m_rendererBlocks.Clear();
|
||||
}
|
||||
|
||||
private void FinishCameraStackRendering()
|
||||
{
|
||||
for (int i = 0; i < m_activePassQueue.Count; ++i)
|
||||
|
||||
@@ -110,6 +110,12 @@ namespace XCEngine.Rendering.Universal
|
||||
renderer.FinalizeCameraFramePlanInstance(
|
||||
context);
|
||||
}
|
||||
|
||||
if (renderer != null)
|
||||
{
|
||||
renderer.ConfigurePassQueueCameraFramePlanInstance(
|
||||
context);
|
||||
}
|
||||
}
|
||||
|
||||
internal bool ConfigureRenderSceneSetupInstance(
|
||||
|
||||
@@ -42,7 +42,7 @@ namespace XCEngine.Rendering.Universal
|
||||
return;
|
||||
}
|
||||
|
||||
if (!renderingData.isFinalOutputStage &&
|
||||
if (!renderingData.isFinalOutputStage ||
|
||||
!renderingData.finalColorData.requiresProcessing)
|
||||
{
|
||||
return;
|
||||
|
||||
@@ -78,21 +78,6 @@ namespace ProjectScripts
|
||||
new ProjectPostProcessColorScalePass();
|
||||
}
|
||||
|
||||
public override void ConfigureCameraFramePlan(
|
||||
ScriptableRenderPipelinePlanningContext context)
|
||||
{
|
||||
if (context == null ||
|
||||
context.IsStageRequested(
|
||||
CameraFrameStage.PostProcess))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
context.RequestFullscreenStage(
|
||||
CameraFrameStage.PostProcess,
|
||||
CameraFrameColorSource.MainSceneColor);
|
||||
}
|
||||
|
||||
public override void AddRenderPasses(
|
||||
ScriptableRenderer renderer,
|
||||
RenderingData renderingData)
|
||||
|
||||
@@ -4614,7 +4614,7 @@ TEST_F(
|
||||
|
||||
TEST_F(
|
||||
MonoScriptRuntimeTest,
|
||||
ManagedRenderPipelineAssetPlansFullscreenStagesFromPipelineStageSupport) {
|
||||
ManagedRenderPipelineAssetPlansFullscreenStagesFromRendererPassQueue) {
|
||||
const XCEngine::Rendering::Pipelines::ManagedRenderPipelineAssetDescriptor descriptor = {
|
||||
"GameScripts",
|
||||
"Gameplay",
|
||||
@@ -4743,7 +4743,7 @@ TEST_F(
|
||||
|
||||
TEST_F(
|
||||
MonoScriptRuntimeTest,
|
||||
ManagedRendererFeatureConfiguresCameraFramePlanThroughPlanningContext) {
|
||||
ManagedRendererFeaturePlanningHookAloneDoesNotDeclareFullscreenStage) {
|
||||
Scene* runtimeScene =
|
||||
CreateScene("ManagedFeatureFramePlanningScene");
|
||||
GameObject* cameraObject = runtimeScene->CreateGameObject("Camera");
|
||||
@@ -4796,13 +4796,13 @@ TEST_F(
|
||||
ASSERT_EQ(plans.size(), 1u);
|
||||
const XCEngine::Rendering::CameraFramePlan& plan = plans[0];
|
||||
|
||||
EXPECT_TRUE(
|
||||
EXPECT_FALSE(
|
||||
plan.IsFullscreenStageRequested(
|
||||
XCEngine::Rendering::CameraFrameStage::PostProcess));
|
||||
EXPECT_EQ(
|
||||
plan.ResolveStageColorSource(
|
||||
XCEngine::Rendering::CameraFrameStage::PostProcess),
|
||||
XCEngine::Rendering::CameraFrameColorSource::MainSceneColor);
|
||||
XCEngine::Rendering::CameraFrameColorSource::ExplicitSurface);
|
||||
EXPECT_FALSE(
|
||||
plan.UsesGraphManagedOutputColor(
|
||||
XCEngine::Rendering::CameraFrameStage::PostProcess));
|
||||
|
||||
Reference in New Issue
Block a user