refactor(srp): add renderer data invalidation seam

Introduce ScriptableRendererData dirty/invalidation support so renderer and feature caches can be released and rebuilt within the same managed asset runtime.

Add managed probes and scripting coverage for non-public dirty APIs and for renderer rebuild after invalidation, then archive the completed phase plan.
This commit is contained in:
2026-04-20 02:48:16 +08:00
parent 5e88449e3d
commit d196ec9264
5 changed files with 466 additions and 24 deletions

View File

@@ -898,6 +898,76 @@ namespace Gameplay
}
}
internal static class ManagedRendererInvalidationProbeState
{
public static int CreateRendererCallCount;
public static int SetupRendererCallCount;
public static int CreateFeatureCallCount;
public static int DisposeRendererCallCount;
public static int DisposeFeatureCallCount;
public static int InvalidateRendererCallCount;
public static void Reset()
{
CreateRendererCallCount = 0;
SetupRendererCallCount = 0;
CreateFeatureCallCount = 0;
DisposeRendererCallCount = 0;
DisposeFeatureCallCount = 0;
InvalidateRendererCallCount = 0;
}
}
internal sealed class ManagedRendererInvalidationProbeFeature
: ScriptableRendererFeature
{
protected override void ReleaseRuntimeResources()
{
ManagedRendererInvalidationProbeState.DisposeFeatureCallCount++;
}
}
internal sealed class ManagedRendererInvalidationProbeRenderer
: ProbeSceneRenderer
{
protected override void ReleaseRuntimeResources()
{
ManagedRendererInvalidationProbeState.DisposeRendererCallCount++;
}
}
internal sealed class ManagedRendererInvalidationProbeRendererData
: ProbeRendererData
{
protected override ScriptableRenderer CreateProbeRenderer()
{
ManagedRendererInvalidationProbeState.CreateRendererCallCount++;
return new ManagedRendererInvalidationProbeRenderer();
}
protected override void SetupRenderer(
ScriptableRenderer renderer)
{
ManagedRendererInvalidationProbeState.SetupRendererCallCount++;
base.SetupRenderer(renderer);
}
protected override ScriptableRendererFeature[] CreateRendererFeatures()
{
ManagedRendererInvalidationProbeState.CreateFeatureCallCount++;
return new ScriptableRendererFeature[]
{
new ManagedRendererInvalidationProbeFeature()
};
}
public void InvalidateForTest()
{
ManagedRendererInvalidationProbeState.InvalidateRendererCallCount++;
SetDirty();
}
}
internal sealed class ManagedPlannedFullscreenRenderPipelineProbeRendererData
: ProbeRendererData
{
@@ -1235,6 +1305,33 @@ namespace Gameplay
}
}
public sealed class ManagedRendererInvalidationProbeAsset
: RendererBackedRenderPipelineAsset
{
private readonly ManagedRendererInvalidationProbeRendererData
m_rendererData;
public ManagedRendererInvalidationProbeAsset()
{
ManagedRendererInvalidationProbeState.Reset();
m_rendererData = new ManagedRendererInvalidationProbeRendererData();
rendererDataList = new ScriptableRendererData[]
{
m_rendererData
};
}
public void InvalidateDefaultRendererForTest()
{
if (m_rendererData == null)
{
return;
}
m_rendererData.InvalidateForTest();
}
}
public sealed class ManagedPlannedFullscreenRenderPipelineProbeAsset
: UniversalRenderPipelineAsset
{
@@ -1517,6 +1614,57 @@ namespace Gameplay
}
}
public sealed class ManagedRendererInvalidationRuntimeSelectionProbe
: MonoBehaviour
{
public void Start()
{
GraphicsSettings.renderPipelineAsset =
new ManagedRendererInvalidationProbeAsset();
}
}
public sealed class ManagedRendererInvalidationObservationProbe
: MonoBehaviour
{
public int ObservedCreateRendererCallCount;
public int ObservedSetupRendererCallCount;
public int ObservedCreateFeatureCallCount;
public int ObservedDisposeRendererCallCount;
public int ObservedDisposeFeatureCallCount;
public int ObservedInvalidateRendererCallCount;
private bool m_requestedInvalidation;
public void Update()
{
ManagedRendererInvalidationProbeAsset selectedAsset =
GraphicsSettings.renderPipelineAsset
as ManagedRendererInvalidationProbeAsset;
if (!m_requestedInvalidation &&
selectedAsset != null &&
ManagedRendererInvalidationProbeState
.CreateRendererCallCount > 0)
{
selectedAsset.InvalidateDefaultRendererForTest();
m_requestedInvalidation = true;
}
ObservedCreateRendererCallCount =
ManagedRendererInvalidationProbeState.CreateRendererCallCount;
ObservedSetupRendererCallCount =
ManagedRendererInvalidationProbeState.SetupRendererCallCount;
ObservedCreateFeatureCallCount =
ManagedRendererInvalidationProbeState.CreateFeatureCallCount;
ObservedDisposeRendererCallCount =
ManagedRendererInvalidationProbeState.DisposeRendererCallCount;
ObservedDisposeFeatureCallCount =
ManagedRendererInvalidationProbeState.DisposeFeatureCallCount;
ObservedInvalidateRendererCallCount =
ManagedRendererInvalidationProbeState.InvalidateRendererCallCount;
}
}
public sealed class RenderPipelineApiProbe : MonoBehaviour
{
public bool InitialAssetWasNull;

View File

@@ -35,6 +35,8 @@ namespace Gameplay
public bool HasRendererBackedRenderPipelineType;
public bool HasRendererDrivenRenderPipelineType;
public bool HasRendererDataSetupRenderer;
public bool HasRendererDataSetDirty;
public bool HasRendererDataIsInvalidated;
public bool HasRendererSupportsRendererRecording;
public bool HasRendererRecordRenderer;
public bool HasPublicRendererSupportsStageRenderGraph;
@@ -180,6 +182,17 @@ namespace Gameplay
"SetupRenderer",
BindingFlags.Instance |
BindingFlags.NonPublic) != null;
HasRendererDataSetDirty =
rendererDataType.GetMethod(
"SetDirty",
BindingFlags.Instance |
BindingFlags.NonPublic) != null;
HasRendererDataIsInvalidated =
rendererDataType.GetProperty(
"isInvalidated",
BindingFlags.Instance |
BindingFlags.NonPublic |
BindingFlags.Public) != null;
HasRendererSupportsRendererRecording =
rendererType.GetMethod(
"SupportsRendererRecording",