Skip to content

Commit 66d1d7c

Browse files
gmitrano-unityEvergreen
authored andcommitted
Add Depth Dependency Logic into RG CopyDepth Path
In the non-RG path, there's specialized logic that ensures the copy depth operation runs before any custom passes that require depth as input. Prior to this change, we didn't have similar logic in the RG path, so we were incorrectly executing some custom passes before the copy depth operation which can produce incorrect results. This change introduces similar scheduling logic to the RG path to ensure it behaves consistently with the non-RG path in the context of custom pass execution.
1 parent b690561 commit 66d1d7c

File tree

2 files changed

+45
-31
lines changed

2 files changed

+45
-31
lines changed

Packages/com.unity.render-pipelines.universal/Runtime/ScriptableRenderer.cs

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1202,34 +1202,39 @@ internal virtual void OnFinishRenderGraphRendering(CommandBuffer cmd)
12021202
{
12031203
}
12041204

1205-
/// <summary>
1206-
/// TODO RENDERGRAPH
1207-
/// </summary>
1208-
/// <param name="context"></param>
1209-
/// <param name="renderingData"></param>
1210-
/// <param name="injectionPoint"></param>
1211-
internal void RecordCustomRenderGraphPasses(RenderGraph renderGraph, RenderPassEvent injectionPoint)
1205+
internal void RecordCustomRenderGraphPassesInEventRange(RenderGraph renderGraph, RenderPassEvent eventStart, RenderPassEvent eventEnd)
12121206
{
1213-
int range = ScriptableRenderPass.GetRenderPassEventRange(injectionPoint);
1214-
int nextValue = (int) injectionPoint + range;
1215-
1216-
foreach (ScriptableRenderPass pass in m_ActiveRenderPassQueue)
1207+
// Only iterate over the active pass queue if we have a non-empty range
1208+
if (eventStart != eventEnd)
12171209
{
1218-
if (pass.renderPassEvent >= injectionPoint && (int) pass.renderPassEvent < nextValue)
1219-
pass.RecordRenderGraph(renderGraph, m_frameData);
1210+
foreach (ScriptableRenderPass pass in m_ActiveRenderPassQueue)
1211+
{
1212+
if (pass.renderPassEvent >= eventStart && pass.renderPassEvent < eventEnd)
1213+
pass.RecordRenderGraph(renderGraph, m_frameData);
1214+
}
12201215
}
12211216
}
12221217

1218+
internal void CalculateSplitEventRange(RenderPassEvent startInjectionPoint, RenderPassEvent targetEvent, out RenderPassEvent startEvent, out RenderPassEvent splitEvent, out RenderPassEvent endEvent)
1219+
{
1220+
int range = ScriptableRenderPass.GetRenderPassEventRange(startInjectionPoint);
1221+
1222+
startEvent = startInjectionPoint;
1223+
endEvent = startEvent + range;
1224+
1225+
splitEvent = (RenderPassEvent)Math.Clamp((int)targetEvent, (int)startEvent, (int)endEvent);
1226+
}
1227+
12231228
internal void RecordCustomRenderGraphPasses(RenderGraph renderGraph, RenderPassEvent startInjectionPoint, RenderPassEvent endInjectionPoint)
12241229
{
12251230
int range = ScriptableRenderPass.GetRenderPassEventRange(endInjectionPoint);
1226-
int nextValue = (int) endInjectionPoint + range;
12271231

1228-
foreach (ScriptableRenderPass pass in m_ActiveRenderPassQueue)
1229-
{
1230-
if (pass.renderPassEvent >= startInjectionPoint && (int) pass.renderPassEvent < nextValue)
1231-
pass.RecordRenderGraph(renderGraph, m_frameData);
1232-
}
1232+
RecordCustomRenderGraphPassesInEventRange(renderGraph, startInjectionPoint, endInjectionPoint + range);
1233+
}
1234+
1235+
internal void RecordCustomRenderGraphPasses(RenderGraph renderGraph, RenderPassEvent injectionPoint)
1236+
{
1237+
RecordCustomRenderGraphPasses(renderGraph, injectionPoint, injectionPoint);
12331238
}
12341239

12351240
// ScriptableRenderPass if executed in a critical point (such as in between Deferred and GBuffer) has to have

Packages/com.unity.render-pipelines.universal/Runtime/UniversalRendererRenderGraph.cs

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -934,6 +934,21 @@ private void InstanceOcclusionTest(RenderGraph renderGraph, UniversalCameraData
934934
GPUResidentDrawer.InstanceOcclusionTest(renderGraph, settings, subviewOcclusionTests);
935935
}
936936

937+
// Records the depth copy pass along with the specified custom passes in a way that properly handles depth read dependencies
938+
private void RecordCustomPassesWithDepthCopy(RenderGraph renderGraph, UniversalResourceData resourceData, RenderPassEvent earliestDepthReadEvent, RenderPassEvent currentEvent)
939+
{
940+
// Custom passes typically come before built-in passes but there's an exception for passes that require depth.
941+
// In cases where custom passes passes may depend on depth, we split the event range and execute the depth copy as late as possible while still ensuring valid depth reads.
942+
943+
CalculateSplitEventRange(currentEvent, earliestDepthReadEvent, out var startEvent, out var splitEvent, out var endEvent);
944+
945+
RecordCustomRenderGraphPassesInEventRange(renderGraph, startEvent, splitEvent);
946+
947+
m_CopyDepthPass.Render(renderGraph, frameData, resourceData.cameraDepthTexture, resourceData.activeDepthTexture, true);
948+
949+
RecordCustomRenderGraphPassesInEventRange(renderGraph, splitEvent, endEvent);
950+
}
951+
937952
private void OnMainRendering(RenderGraph renderGraph, ScriptableRenderContext context)
938953
{
939954
UniversalResourceData resourceData = frameData.Get<UniversalResourceData>();
@@ -1134,14 +1149,10 @@ private void OnMainRendering(RenderGraph renderGraph, ScriptableRenderContext co
11341149
needsOccluderUpdate = false;
11351150
}
11361151

1137-
// Custom passes come before built-in passes to keep parity with non-RG code path where custom passes are added before renderer Setup.
1138-
RecordCustomRenderGraphPasses(renderGraph, RenderPassEvent.AfterRenderingOpaques);
1139-
11401152
if (requiresDepthCopyPass && m_CopyDepthMode != CopyDepthMode.AfterTransparents)
1141-
{
1142-
TextureHandle cameraDepthTexture = resourceData.cameraDepthTexture;
1143-
m_CopyDepthPass.Render(renderGraph, frameData, cameraDepthTexture, resourceData.activeDepthTexture, true);
1144-
}
1153+
RecordCustomPassesWithDepthCopy(renderGraph, resourceData, renderPassInputs.requiresDepthTextureEarliestEvent, RenderPassEvent.AfterRenderingOpaques);
1154+
else
1155+
RecordCustomRenderGraphPasses(renderGraph, RenderPassEvent.AfterRenderingOpaques);
11451156

11461157
// Depends on the camera (copy) depth texture. Depth is reprojected to calculate motion vectors.
11471158
if (renderPassInputs.requiresMotionVectors && m_CopyDepthMode != CopyDepthMode.AfterTransparents)
@@ -1191,12 +1202,10 @@ private void OnMainRendering(RenderGraph renderGraph, ScriptableRenderContext co
11911202
resourceData.additionalShadowsTexture);
11921203
}
11931204

1194-
// Custom passes come before built-in passes to keep parity with non-RG code path where custom passes are added before renderer Setup.
1195-
1196-
RecordCustomRenderGraphPasses(renderGraph, RenderPassEvent.AfterRenderingTransparents);
1197-
11981205
if (requiresDepthCopyPass && m_CopyDepthMode == CopyDepthMode.AfterTransparents)
1199-
m_CopyDepthPass.Render(renderGraph, frameData, resourceData.cameraDepthTexture, resourceData.activeDepthTexture, true);
1206+
RecordCustomPassesWithDepthCopy(renderGraph, resourceData, renderPassInputs.requiresDepthTextureEarliestEvent, RenderPassEvent.AfterRenderingTransparents);
1207+
else
1208+
RecordCustomRenderGraphPasses(renderGraph, RenderPassEvent.AfterRenderingTransparents);
12001209

12011210
// TODO: Postprocess pass should be able configure its render pass inputs per camera per frame (settings) BEFORE building any of the graph
12021211
// TODO: Alternatively we could always build the graph (a potential graph) and cull away unused passes if "record + cull" is fast enough.

0 commit comments

Comments
 (0)