diff --git a/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraph.cs b/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraph.cs
index d6a8e05d272..7a7d2e8e094 100644
--- a/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraph.cs
+++ b/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraph.cs
@@ -42,11 +42,13 @@ public ref struct RenderGraphContext
public struct RenderGraphExecuteParams
{
///Rendering width.
- public int renderingWidth;
+ public int renderingWidth;
///Rendering height.
- public int renderingHeight;
+ public int renderingHeight;
///Number of MSAA samples.
- public MSAASamples msaaSamples;
+ public MSAASamples msaaSamples;
+ ///Index of the current frame being rendered.
+ public int currentFrameIndex;
}
class RenderGraphDebugParams
@@ -362,8 +364,7 @@ public void Execute(ScriptableRenderContext renderContext, CommandBuffer cmd, in
{
m_Logger.Initialize();
- // Update RTHandleSystem with size for this rendering pass.
- m_Resources.SetRTHandleReferenceSize(parameters.renderingWidth, parameters.renderingHeight, parameters.msaaSamples);
+ m_Resources.BeginRender(parameters.renderingWidth, parameters.renderingHeight, parameters.msaaSamples, parameters.currentFrameIndex);
LogFrameInformation(parameters.renderingWidth, parameters.renderingHeight);
diff --git a/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphResourceRegistry.cs b/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphResourceRegistry.cs
index 1af426e2518..8722df245d9 100644
--- a/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphResourceRegistry.cs
+++ b/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphResourceRegistry.cs
@@ -322,6 +322,85 @@ public override int GetHashCode()
}
#endregion
+ class RenderGraphTexturePool
+ {
+ // Dictionary tracks resources by hash and stores resources with same hash in a List (list instead of a stack because we need to be able to remove stale allocations).
+ Dictionary> m_ResourcePool = new Dictionary>();
+ static int s_CurrentFrameIndex;
+
+ public void ReleaseResource(int hash, RTHandle rt, int currentFrameIndex)
+ {
+ if (!m_ResourcePool.TryGetValue(hash, out var list))
+ {
+ list = new List<(RTHandle rt, int frameIndex)>();
+ m_ResourcePool.Add(hash, list);
+ }
+
+ list.Add((rt, currentFrameIndex));
+ }
+
+ public bool TryGetResource(int hashCode, out RTHandle rt)
+ {
+ if (m_ResourcePool.TryGetValue(hashCode, out var list) && list.Count > 0)
+ {
+ rt = list[list.Count - 1].resource;
+ list.RemoveAt(list.Count - 1); // O(1) since it's the last element.
+ return true;
+ }
+
+ rt = null;
+ return false;
+ }
+
+ public void PurgeUnusedResources(int currentFrameIndex)
+ {
+ // Update the frame index for the lambda. Static because we don't want to capture.
+ s_CurrentFrameIndex = currentFrameIndex;
+
+ foreach(var kvp in m_ResourcePool)
+ {
+ var list = kvp.Value;
+ list.RemoveAll(obj =>
+ {
+ if (obj.frameIndex < s_CurrentFrameIndex)
+ {
+ obj.resource.Release();
+ return true;
+ }
+ return false;
+ });
+ }
+ }
+
+ public void Cleanup()
+ {
+ foreach (var kvp in m_ResourcePool)
+ {
+ foreach (var res in kvp.Value)
+ {
+ res.resource.Release();
+ }
+ }
+ }
+
+ public void LogResources(RenderGraphLogger logger)
+ {
+ List allocationList = new List();
+ foreach (var kvp in m_ResourcePool)
+ {
+ foreach (var res in kvp.Value)
+ {
+ allocationList.Add(res.resource.rt.name);
+ }
+ }
+
+ allocationList.Sort();
+ int index = 0;
+ foreach (var element in allocationList)
+ logger.LogLine("[{0}] {1}", index++, element);
+ }
+ }
+
///
/// The RenderGraphResourceRegistry holds all resource allocated during Render Graph execution.
///
@@ -393,17 +472,19 @@ internal ComputeBufferResource(ComputeBuffer computeBuffer, bool imported)
#endregion
DynamicArray m_TextureResources = new DynamicArray();
- Dictionary> m_TexturePool = new Dictionary>();
+ RenderGraphTexturePool m_TexturePool = new RenderGraphTexturePool();
DynamicArray m_RendererListResources = new DynamicArray();
DynamicArray m_ComputeBufferResources = new DynamicArray();
RTHandleSystem m_RTHandleSystem = new RTHandleSystem();
RenderGraphDebugParams m_RenderGraphDebug;
RenderGraphLogger m_Logger;
+ int m_CurrentFrameIndex;
RTHandle m_CurrentBackbuffer;
// Diagnostic only
- List<(int, RTHandle)> m_AllocatedTextures = new List<(int, RTHandle)>();
+ // This list allows us to determine if all textures were correctly released in the frame.
+ List<(int, RTHandle)> m_FrameAllocatedTextures = new List<(int, RTHandle)>();
#region Public Interface
///
@@ -470,8 +551,10 @@ internal RenderGraphResourceRegistry(bool supportMSAA, MSAASamples initialSample
m_Logger = logger;
}
- internal void SetRTHandleReferenceSize(int width, int height, MSAASamples msaaSamples)
+ internal void BeginRender(int width, int height, MSAASamples msaaSamples, int currentFrameIndex)
{
+ m_CurrentFrameIndex = currentFrameIndex;
+ // Update RTHandleSystem with size for this rendering pass.
m_RTHandleSystem.SetReferenceSize(width, height, msaaSamples);
}
@@ -618,7 +701,7 @@ void CreateTextureForPass(ref TextureResource resource)
#if DEVELOPMENT_BUILD || UNITY_EDITOR
if (hashCode != -1)
{
- m_AllocatedTextures.Add((hashCode, resource.rt));
+ m_FrameAllocatedTextures.Add((hashCode, resource.rt));
}
#endif
@@ -675,16 +758,10 @@ internal void ReleaseTexture(RenderGraphContext rgContext, TextureHandle resourc
void ReleaseTextureResource(int hash, RTHandle rt)
{
- if (!m_TexturePool.TryGetValue(hash, out var stack))
- {
- stack = new Stack();
- m_TexturePool.Add(hash, stack);
- }
-
- stack.Push(rt);
+ m_TexturePool.ReleaseResource(hash, rt, m_CurrentFrameIndex);
#if DEVELOPMENT_BUILD || UNITY_EDITOR
- m_AllocatedTextures.Remove((hash, rt));
+ m_FrameAllocatedTextures.Remove((hash, rt));
#endif
}
@@ -746,14 +823,7 @@ void ValidateRendererListDesc(in RendererListDesc desc)
bool TryGetRenderTarget(int hashCode, out RTHandle rt)
{
- if (m_TexturePool.TryGetValue(hashCode, out var stack) && stack.Count > 0)
- {
- rt = stack.Pop();
- return true;
- }
-
- rt = null;
- return false;
+ return m_TexturePool.TryGetResource(hashCode, out rt);
}
internal void CreateRendererLists(List rendererLists)
@@ -778,11 +848,11 @@ internal void Clear(bool onException)
m_ComputeBufferResources.Clear();
#if DEVELOPMENT_BUILD || UNITY_EDITOR
- if (m_AllocatedTextures.Count != 0 && !onException)
+ if (m_FrameAllocatedTextures.Count != 0 && !onException)
{
- string logMessage = "RenderGraph: Not all textures were released.";
+ string logMessage = "RenderGraph: Not all textures were released. This can be caused by a textures being allocated but never read by any pass.";
- List<(int, RTHandle)> tempList = new List<(int, RTHandle)>(m_AllocatedTextures);
+ List<(int, RTHandle)> tempList = new List<(int, RTHandle)>(m_FrameAllocatedTextures);
foreach (var value in tempList)
{
logMessage = $"{logMessage}\n\t{value.Item2.name}";
@@ -792,10 +862,15 @@ internal void Clear(bool onException)
Debug.LogWarning(logMessage);
}
- // If an error occurred during execution, it's expected that textures are not all release so we clear the trakcing list.
+ // If an error occurred during execution, it's expected that textures are not all released so we clear the tracking list.
if (onException)
- m_AllocatedTextures.Clear();
+ m_FrameAllocatedTextures.Clear();
#endif
+
+ // TODO RENDERGRAPH: Might not be ideal to purge stale resources every frame.
+ // In case users enable/disable features along a level it might provoke performance spikes when things are reallocated...
+ // Will be much better when we have actual resource aliasing and we can manage memory more efficiently.
+ m_TexturePool.PurgeUnusedResources(m_CurrentFrameIndex);
}
internal void ResetRTHandleReferenceSize(int width, int height)
@@ -805,13 +880,7 @@ internal void ResetRTHandleReferenceSize(int width, int height)
internal void Cleanup()
{
- foreach (var value in m_TexturePool)
- {
- foreach (var rt in value.Value)
- {
- m_RTHandleSystem.Release(rt);
- }
- }
+ m_TexturePool.Cleanup();
}
void LogTextureCreation(RTHandle rt, bool cleared)
@@ -836,19 +905,7 @@ void LogResources()
{
m_Logger.LogLine("==== Allocated Resources ====\n");
- List allocationList = new List();
- foreach (var stack in m_TexturePool)
- {
- foreach (var rt in stack.Value)
- {
- allocationList.Add(rt.rt.name);
- }
- }
-
- allocationList.Sort();
- int index = 0;
- foreach (var element in allocationList)
- m_Logger.LogLine("[{0}] {1}", index++, element);
+ m_TexturePool.LogResources(m_Logger);
}
}
diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.RenderGraph.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.RenderGraph.cs
index f1f3a6f4bfa..706f7af6222 100644
--- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.RenderGraph.cs
+++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.RenderGraph.cs
@@ -251,18 +251,19 @@ void ExecuteWithRenderGraph( RenderRequest renderRequest,
RenderGizmos(m_RenderGraph, hdCamera, colorBuffer, GizmoSubset.PostImageEffects);
- ExecuteRenderGraph(m_RenderGraph, hdCamera, m_MSAASamples, renderContext, commandBuffer );
+ ExecuteRenderGraph(m_RenderGraph, hdCamera, m_MSAASamples, m_FrameCount, renderContext, commandBuffer );
aovRequest.Execute(commandBuffer, aovBuffers, RenderOutputProperties.From(hdCamera));
}
- static void ExecuteRenderGraph(RenderGraph renderGraph, HDCamera hdCamera, MSAASamples msaaSample, ScriptableRenderContext renderContext, CommandBuffer cmd)
+ static void ExecuteRenderGraph(RenderGraph renderGraph, HDCamera hdCamera, MSAASamples msaaSample, int frameIndex, ScriptableRenderContext renderContext, CommandBuffer cmd)
{
var renderGraphParams = new RenderGraphExecuteParams()
{
renderingWidth = hdCamera.actualWidth,
renderingHeight = hdCamera.actualHeight,
- msaaSamples = msaaSample
+ msaaSamples = msaaSample,
+ currentFrameIndex = frameIndex
};
renderGraph.Execute(renderContext, cmd, renderGraphParams);