Skip to content

Commit 1309fdd

Browse files
pastasfutureDeployer User
authored andcommitted
Hybrid Renderer Command Buffer: Unique systems on system name and world name - it is valid for a system to push commands independantly from multiple worlds. Force an immediate mode submit of the command buffer if we encounter a case where the HDRenderPipeline has not submitted the command buffer before the system updates again - this can happen in edge cases. (#70)
1 parent e1a7556 commit 1309fdd

File tree

1 file changed

+82
-32
lines changed

1 file changed

+82
-32
lines changed

com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.HybridRendererCommandBuffer.cs

Lines changed: 82 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -18,30 +18,33 @@ public partial class HDRenderPipeline : RenderPipeline
1818
// ImmediateMode exists for debugging purposes.
1919
public static class HybridRendererCommandBuffer
2020
{
21-
public static int GetSystemIDFromName(string name)
21+
public static HybridRendererCommandBufferSystemHandle CreateSystemHandle(string name, string worldName)
2222
{
2323
// In lieu of any standard string interning system, we're going to simply use Shader.PropertyToID() to generate stable IDs.
24-
int id = Shader.PropertyToID(name);
25-
s_HybridRendererCommandBufferData.EnsureProfilingSampler(name, id);
26-
return id;
24+
var handle = new HybridRendererCommandBufferSystemHandle()
25+
{
26+
systemID = Shader.PropertyToID(name),
27+
worldID = Shader.PropertyToID(worldName)
28+
};
29+
s_HybridRendererCommandBufferData.EnsureProfilingSampler(name, handle);
30+
return handle;
2731
}
2832

29-
public static CommandBuffer SystemBegin(int debugSystemID)
33+
public static CommandBuffer SystemBegin(HybridRendererCommandBufferSystemHandle handle)
3034
{
31-
return s_HybridRendererCommandBufferData.Begin(debugSystemID);
35+
return s_HybridRendererCommandBufferData.Begin(handle);
3236
}
3337

34-
public static void SystemEnd(int debugSystemID)
38+
public static void SystemEnd(HybridRendererCommandBufferSystemHandle handle)
3539
{
36-
s_HybridRendererCommandBufferData.End(debugSystemID);
40+
s_HybridRendererCommandBufferData.End(handle);
3741

3842
var hdrp = (RenderPipelineManager.currentPipeline as HDRenderPipeline);
3943
if (hdrp == null)
4044
{
4145
// HDRP is not initialized yet, rather than throwing out any work that was requested,
42-
//// to be safe, lets allow multiple frames to be queued up, in case any frame-agnostic data is computed in this queue.
43-
//s_HybridRendererCommandBuffer.AllowAdditionalFrameCommandBufferQueue();
44-
s_HybridRendererCommandBufferData.Clear();
46+
// to be safe, lets immediately submit the work, to ensure any global frame agnostic state changes get setup correctly.
47+
s_HybridRendererCommandBufferData.SubmitImmediate();
4548
}
4649
}
4750

@@ -53,19 +56,44 @@ public static void RequestImmediateMode(bool enabled)
5356

5457
private static HybridRendererCommandBufferData s_HybridRendererCommandBufferData = new HybridRendererCommandBufferData();
5558

59+
public struct HybridRendererCommandBufferSystemHandle : IEquatable<HybridRendererCommandBufferSystemHandle>
60+
{
61+
public int systemID;
62+
public int worldID;
63+
64+
public bool Equals(HybridRendererCommandBufferSystemHandle keyOther)
65+
{
66+
return (this.systemID == keyOther.systemID)
67+
&& (this.worldID == keyOther.worldID);
68+
}
69+
70+
public override bool Equals(object other)
71+
{
72+
return other is HybridRendererCommandBufferSystemHandle key && Equals(key);
73+
}
74+
75+
public override int GetHashCode()
76+
{
77+
var hash = systemID.GetHashCode();
78+
hash = hash * 23 + worldID.GetHashCode();
79+
80+
return hash;
81+
}
82+
}
83+
5684
private class HybridRendererCommandBufferData
5785
{
58-
private Dictionary<int, bool> debugSubmittedSystemState = new Dictionary<int, bool>();
86+
private Dictionary<HybridRendererCommandBufferSystemHandle, bool> debugSubmittedSystemState = new Dictionary<HybridRendererCommandBufferSystemHandle, bool>();
5987
private Dictionary<int, ProfilingSampler> profilingSamplers = new Dictionary<int, ProfilingSampler>();
6088
private CommandBuffer cmd = null;
6189
private bool immediateModeEnabled = false;
6290
private bool immediateModeEnabledNext = false;
6391

64-
public void EnsureProfilingSampler(string name, int id)
92+
public void EnsureProfilingSampler(string name, HybridRendererCommandBufferSystemHandle handle)
6593
{
66-
if (!profilingSamplers.TryGetValue(id, out var profilingSampler))
94+
if (!profilingSamplers.TryGetValue(handle.systemID, out var profilingSampler))
6795
{
68-
profilingSamplers.Add(id, new ProfilingSampler(name));
96+
profilingSamplers.Add(handle.systemID, new ProfilingSampler(name));
6997
}
7098
}
7199

@@ -82,46 +110,68 @@ public void Clear()
82110
immediateModeEnabled = immediateModeEnabledNext;
83111
}
84112

85-
public CommandBuffer Begin(int debugSystemID)
113+
public CommandBuffer Begin(HybridRendererCommandBufferSystemHandle handle)
86114
{
87-
Debug.Assert(!debugSubmittedSystemState.ContainsKey(debugSystemID));
88-
debugSubmittedSystemState.Add(debugSystemID, false);
115+
if (debugSubmittedSystemState.ContainsKey(handle))
116+
{
117+
// Encountered previous frame data, or a system from another world updating.
118+
// In the editor, there are a few edge cases where this can happen, such as changes to Project Settings (oddly enough).
119+
// Simply submit the command buffer immediately, and do not log any warnings.
120+
// If we are in a build, this case is unexpected, so we log a warning.
121+
SubmitImmediate();
122+
123+
#if !UNITY_EDITOR
124+
Debug.LogWarning("Warning: HybridRendererCommandBuffer: Encountered unexpected case of a command buffer having not been submitted between Simulation Update loops. It should have been submitted in the HDRenderPipeline::Render() loop.");
125+
#endif
126+
}
127+
debugSubmittedSystemState.Add(handle, false);
89128

90129
var cmd = EnsureCommandBuffer();
91-
profilingSamplers[debugSystemID].Begin(cmd);
130+
profilingSamplers[handle.systemID].Begin(cmd);
92131
return cmd;
93132
}
94133

95-
public void End(int debugSystemID)
134+
public void End(HybridRendererCommandBufferSystemHandle handle)
96135
{
97-
Debug.Assert(debugSubmittedSystemState.ContainsKey(debugSystemID));
98-
if (debugSubmittedSystemState.TryGetValue(debugSystemID, out bool submitted))
136+
if (debugSubmittedSystemState.TryGetValue(handle, out bool submitted))
99137
{
100-
Debug.Assert(submitted == false);
138+
Debug.AssertFormat(submitted == false, "Error: Encountered Hybrid Rendering System {0} with an already submitted command buffer. Was End() already called in this Simulation Update?", profilingSamplers[handle.systemID].name);
101139
}
102140
else
103141
{
104-
Debug.Assert(false);
142+
Debug.AssertFormat(false, "Error: Encountered Hybrid Rendering System {0} End() call with no Begin() call.", profilingSamplers[handle.systemID].name);
105143
}
106144

107-
debugSubmittedSystemState[debugSystemID] = true;
145+
debugSubmittedSystemState[handle] = true;
108146

109-
profilingSamplers[debugSystemID].End(cmd);
147+
profilingSamplers[handle.systemID].End(cmd);
110148

111149
if (immediateModeEnabled)
112150
{
113-
Graphics.ExecuteCommandBuffer(cmd);
114-
cmd.Clear();
151+
SubmitImmediate();
115152
}
116153
}
117154

118155
public void Submit(ScriptableRenderContext renderContext)
119156
{
120-
if (cmd == null) { return; }
157+
if (cmd != null)
158+
{
159+
renderContext.ExecuteCommandBuffer(cmd);
160+
renderContext.Submit();
161+
cmd.Clear();
162+
}
163+
164+
Clear();
165+
}
166+
167+
public void SubmitImmediate()
168+
{
169+
if (cmd != null)
170+
{
171+
Graphics.ExecuteCommandBuffer(cmd);
172+
cmd.Clear();
173+
}
121174

122-
renderContext.ExecuteCommandBuffer(cmd);
123-
renderContext.Submit();
124-
cmd.Clear();
125175
Clear();
126176
}
127177

0 commit comments

Comments
 (0)