Skip to content

Commit 229c766

Browse files
axolotoEvergreen
authored andcommitted
Graphics/SRP/RPF - RG Opt 3 - Disable Render Graph Validation Checks on demand
Render Graph does a lot of validation checks to ensure resources are not corrupted and correctly setup. These checks are costly. Disabling them provides 0.1-0.2ms gains on main CPU thread on PS4 and Switch with High Quality mode tests. This PR implements a way to enable/disable the validation layers from the UI in the editor for both URP and HDRP. Validations will always be disabled in release mode.
1 parent 646c007 commit 229c766

File tree

6 files changed

+285
-225
lines changed

6 files changed

+285
-225
lines changed
Lines changed: 44 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Diagnostics;
23
using UnityEngine.Rendering.RenderGraphModule;
34

45
namespace UnityEngine.Rendering
@@ -26,79 +27,83 @@ internal BaseCommandBuffer(CommandBuffer wrapped, RenderGraphPass executingPass,
2627
///<summary>See (https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer-sizeInBytes.html)</summary>
2728
public int sizeInBytes => m_WrappedCommandBuffer.sizeInBytes;
2829

30+
[Conditional("DEVELOPMENT_BUILD"), Conditional("UNITY_EDITOR")]
2931
internal protected void ThrowIfGlobalStateNotAllowed()
3032
{
31-
#if DEVELOPMENT_BUILD || UNITY_EDITOR
3233
if (m_ExecutingPass != null && !m_ExecutingPass.allowGlobalState) throw new InvalidOperationException($"{m_ExecutingPass.name}: Modifying global state from this command buffer is not allowed. Please ensure your render graph pass allows modifying global state.");
33-
#endif
3434
}
3535

3636
/// <summary>
3737
/// Checks if the Raster Command Buffer has set a valid render target.
3838
/// </summary>
3939
/// <exception cref="InvalidOperationException">Thrown if the there are no active render targets.</exception>
40+
[Conditional("DEVELOPMENT_BUILD"), Conditional("UNITY_EDITOR")]
4041
internal protected void ThrowIfRasterNotAllowed()
4142
{
42-
#if DEVELOPMENT_BUILD || UNITY_EDITOR
4343
if (m_ExecutingPass != null && !m_ExecutingPass.HasRenderAttachments()) throw new InvalidOperationException($"{m_ExecutingPass.name}: Using raster commands from a pass with no active render targets is not allowed as it will use an undefined render target state. Please set-up the pass's render targets using SetRenderAttachments.");
44-
#endif
4544
}
4645

4746

4847
// Validation when it is unknown if the texture will be read or written
48+
[Conditional("DEVELOPMENT_BUILD"), Conditional("UNITY_EDITOR")]
4949
internal protected void ValidateTextureHandle(TextureHandle h)
5050
{
51-
#if DEVELOPMENT_BUILD || UNITY_EDITOR
52-
if (m_ExecutingPass == null) return;
51+
if(RenderGraph.enableValidityChecks)
52+
{
53+
if (m_ExecutingPass == null) return;
5354

54-
if (h.IsBuiltin()) return;
55+
if (h.IsBuiltin()) return;
5556

56-
if (!m_ExecutingPass.IsRead(h.handle) && !m_ExecutingPass.IsWritten(h.handle))
57-
{
58-
throw new Exception("Pass '" + m_ExecutingPass.name + "' is trying to use a texture on the command buffer that was never registered with the pass builder. Please indicate the texture use to the pass builder.");
59-
}
60-
if (m_ExecutingPass.IsAttachment(h))
61-
{
62-
throw new Exception("Pass '" + m_ExecutingPass.name + "' is using a texture as a fragment attachment (SetRenderAttachment/SetRenderAttachmentDepth) but is also trying to bind it as regular texture. Please fix this pass. ");
57+
if (!m_ExecutingPass.IsRead(h.handle) && !m_ExecutingPass.IsWritten(h.handle))
58+
{
59+
throw new Exception("Pass '" + m_ExecutingPass.name + "' is trying to use a texture on the command buffer that was never registered with the pass builder. Please indicate the texture use to the pass builder.");
60+
}
61+
if (m_ExecutingPass.IsAttachment(h))
62+
{
63+
throw new Exception("Pass '" + m_ExecutingPass.name + "' is using a texture as a fragment attachment (SetRenderAttachment/SetRenderAttachmentDepth) but is also trying to bind it as regular texture. Please fix this pass. ");
64+
}
6365
}
64-
#endif
6566
}
6667

68+
[Conditional("DEVELOPMENT_BUILD"), Conditional("UNITY_EDITOR")]
6769
internal protected void ValidateTextureHandleRead(TextureHandle h)
6870
{
69-
#if DEVELOPMENT_BUILD || UNITY_EDITOR
70-
if (m_ExecutingPass == null) return;
71-
72-
if (!m_ExecutingPass.IsRead(h.handle))
73-
{
74-
throw new Exception("Pass '" + m_ExecutingPass.name + "' is trying to read a texture on the command buffer that was never registered with the pass builder. Please indicate the texture as read to the pass builder.");
75-
}
76-
if (m_ExecutingPass.IsAttachment(h))
71+
if(RenderGraph.enableValidityChecks)
7772
{
78-
throw new Exception("Pass '" + m_ExecutingPass.name + "' is using a texture as a fragment attachment (SetRenderAttachment/SetRenderAttachmentDepth) but is also trying to bind it as regular texture. Please fix this pass. ");
73+
if (m_ExecutingPass == null) return;
74+
75+
if (!m_ExecutingPass.IsRead(h.handle))
76+
{
77+
throw new Exception("Pass '" + m_ExecutingPass.name + "' is trying to read a texture on the command buffer that was never registered with the pass builder. Please indicate the texture as read to the pass builder.");
78+
}
79+
if (m_ExecutingPass.IsAttachment(h))
80+
{
81+
throw new Exception("Pass '" + m_ExecutingPass.name + "' is using a texture as a fragment attachment (SetRenderAttachment/SetRenderAttachmentDepth) but is also trying to bind it as regular texture. Please fix this pass. ");
82+
}
7983
}
80-
#endif
8184
}
8285

86+
[Conditional("DEVELOPMENT_BUILD"), Conditional("UNITY_EDITOR")]
8387
internal protected void ValidateTextureHandleWrite(TextureHandle h)
8488
{
85-
#if DEVELOPMENT_BUILD || UNITY_EDITOR
86-
if (m_ExecutingPass == null) return;
87-
88-
if (h.IsBuiltin())
89+
if(RenderGraph.enableValidityChecks)
8990
{
90-
throw new Exception("Pass '" + m_ExecutingPass.name + "' is trying to write to a built-in texture. This is not allowed built-in textures are small default resources like `white` or `black` that cannot be written to.");
91-
}
91+
if (m_ExecutingPass == null) return;
9292

93-
if (!m_ExecutingPass.IsWritten(h.handle))
94-
{
95-
throw new Exception("Pass '" + m_ExecutingPass.name + "' is trying to write a texture on the command buffer that was never registered with the pass builder. Please indicate the texture as written to the pass builder.");
96-
}
97-
if (m_ExecutingPass.IsAttachment(h))
98-
{
99-
throw new Exception("Pass '" + m_ExecutingPass.name + "' is using a texture as a fragment attachment (SetRenderAttachment/SetRenderAttachmentDepth) but is also trying to bind it as regular texture. Please fix this pass. ");
93+
if (h.IsBuiltin())
94+
{
95+
throw new Exception("Pass '" + m_ExecutingPass.name + "' is trying to write to a built-in texture. This is not allowed built-in textures are small default resources like `white` or `black` that cannot be written to.");
96+
}
97+
98+
if (!m_ExecutingPass.IsWritten(h.handle))
99+
{
100+
throw new Exception("Pass '" + m_ExecutingPass.name + "' is trying to write a texture on the command buffer that was never registered with the pass builder. Please indicate the texture as written to the pass builder.");
101+
}
102+
if (m_ExecutingPass.IsAttachment(h))
103+
{
104+
throw new Exception("Pass '" + m_ExecutingPass.name + "' is using a texture as a fragment attachment (SetRenderAttachment/SetRenderAttachmentDepth) but is also trying to bind it as regular texture. Please fix this pass. ");
105+
}
100106
}
101-
#endif
102107
}
103108
}
104109
}

Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraph.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -556,6 +556,9 @@ internal void RequestCaptureDebugData(string executionName)
556556
/// <summary>If true, the Render Graph Viewer is active.</summary>
557557
public static bool isRenderGraphViewerActive { get; internal set; }
558558

559+
/// <summary>If true, the Render Graph will run its various validity checks while processing (not considered in release mode).</summary>
560+
internal static bool enableValidityChecks { get; private set; }
561+
559562
/// <summary>
560563
/// Set of default resources usable in a pass rendering code.
561564
/// </summary>
@@ -579,6 +582,12 @@ public RenderGraph(string name = "RenderGraph")
579582
m_EnableCompilationCaching = renderGraphGlobalSettings.enableCompilationCaching;
580583
if (m_EnableCompilationCaching)
581584
m_CompilationCache = new RenderGraphCompilationCache();
585+
586+
enableValidityChecks = renderGraphGlobalSettings.enableValidityChecks;
587+
}
588+
else // No SRP pipeline is present/active, it can happen with unit tests
589+
{
590+
enableValidityChecks = true;
582591
}
583592

584593
m_Resources = new RenderGraphResourceRegistry(m_DebugParameters, m_FrameInformationLogger);

Packages/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphBuilder.cs

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Diagnostics;
23
using System.Collections.Generic;
34
using UnityEngine.Rendering;
45

@@ -318,28 +319,30 @@ void Dispose(bool disposing)
318319
m_Disposed = true;
319320
}
320321

322+
[Conditional("DEVELOPMENT_BUILD"), Conditional("UNITY_EDITOR")]
321323
void CheckResource(in ResourceHandle res, bool dontCheckTransientReadWrite = false)
322324
{
323-
#if DEVELOPMENT_BUILD || UNITY_EDITOR
324-
if (res.IsValid())
325+
if(RenderGraph.enableValidityChecks)
325326
{
326-
int transientIndex = m_Resources.GetRenderGraphResourceTransientIndex(res);
327-
// We have dontCheckTransientReadWrite here because users may want to use UseColorBuffer/UseDepthBuffer API to benefit from render target auto binding. In this case we don't want to raise the error.
328-
if (transientIndex == m_RenderPass.index && !dontCheckTransientReadWrite)
327+
if (res.IsValid())
329328
{
330-
Debug.LogError($"Trying to read or write a transient resource at pass {m_RenderPass.name}.Transient resource are always assumed to be both read and written.");
329+
int transientIndex = m_Resources.GetRenderGraphResourceTransientIndex(res);
330+
// We have dontCheckTransientReadWrite here because users may want to use UseColorBuffer/UseDepthBuffer API to benefit from render target auto binding. In this case we don't want to raise the error.
331+
if (transientIndex == m_RenderPass.index && !dontCheckTransientReadWrite)
332+
{
333+
Debug.LogError($"Trying to read or write a transient resource at pass {m_RenderPass.name}.Transient resource are always assumed to be both read and written.");
334+
}
335+
336+
if (transientIndex != -1 && transientIndex != m_RenderPass.index)
337+
{
338+
throw new ArgumentException($"Trying to use a transient texture (pass index {transientIndex}) in a different pass (pass index {m_RenderPass.index}).");
339+
}
331340
}
332-
333-
if (transientIndex != -1 && transientIndex != m_RenderPass.index)
341+
else
334342
{
335-
throw new ArgumentException($"Trying to use a transient texture (pass index {transientIndex}) in a different pass (pass index {m_RenderPass.index}).");
343+
throw new ArgumentException($"Trying to use an invalid resource (pass {m_RenderPass.name}).");
336344
}
337345
}
338-
else
339-
{
340-
throw new ArgumentException($"Trying to use an invalid resource (pass {m_RenderPass.name}).");
341-
}
342-
#endif
343346
}
344347

345348
internal void GenerateDebugData(bool value)

0 commit comments

Comments
 (0)