diff --git a/com.unity.render-pipelines.core/Runtime/Debugging/ProfilingScope.cs b/com.unity.render-pipelines.core/Runtime/Debugging/ProfilingScope.cs
index e0e17821416..1a7176e509e 100644
--- a/com.unity.render-pipelines.core/Runtime/Debugging/ProfilingScope.cs
+++ b/com.unity.render-pipelines.core/Runtime/Debugging/ProfilingScope.cs
@@ -98,6 +98,42 @@ public ProfilingSampler(string name)
#endif
}
+ ///
+ /// Begin the profiling block.
+ ///
+ /// Command buffer used by the profiling block.
+ public void Begin(CommandBuffer cmd)
+ {
+ if (cmd != null)
+#if UNITY_USE_RECORDER
+ if (sampler != null)
+ cmd.BeginSample(sampler);
+ else
+ cmd.BeginSample(name);
+#else
+ cmd.BeginSample(name);
+#endif
+ inlineSampler?.Begin();
+ }
+
+ ///
+ /// End the profiling block.
+ ///
+ /// Command buffer used by the profiling block.
+ public void End(CommandBuffer cmd)
+ {
+ if (cmd != null)
+#if UNITY_USE_RECORDER
+ if (sampler != null)
+ cmd.EndSample(sampler);
+ else
+ cmd.EndSample(name);
+#else
+ m_Cmd.EndSample(name);
+#endif
+ inlineSampler?.End();
+ }
+
internal bool IsValid() { return (sampler != null && inlineSampler != null); }
internal CustomSampler sampler { get; private set; }
@@ -187,11 +223,9 @@ public bool enableRecording
///
public struct ProfilingScope : IDisposable
{
- string m_Name;
- CommandBuffer m_Cmd;
- bool m_Disposed;
- CustomSampler m_Sampler;
- CustomSampler m_InlineSampler;
+ CommandBuffer m_Cmd;
+ bool m_Disposed;
+ ProfilingSampler m_Sampler;
///
/// Profiling Scope constructor
@@ -202,29 +236,8 @@ public ProfilingScope(CommandBuffer cmd, ProfilingSampler sampler)
{
m_Cmd = cmd;
m_Disposed = false;
- if (sampler != null)
- {
- m_Name = sampler.name; // Don't use CustomSampler.name because it causes garbage
- m_Sampler = sampler.sampler;
- m_InlineSampler = sampler.inlineSampler;
- }
- else
- {
- m_Name = "NullProfilingSampler"; // Don't use CustomSampler.name because it causes garbage
- m_Sampler = null;
- m_InlineSampler = null;
- }
-
- if (cmd != null)
-#if UNITY_USE_RECORDER
- if (m_Sampler != null)
- cmd.BeginSample(m_Sampler);
- else
- cmd.BeginSample(m_Name);
-#else
- cmd.BeginSample(m_Name);
-#endif
- m_InlineSampler?.Begin();
+ m_Sampler = sampler;
+ m_Sampler?.Begin(m_Cmd);
}
///
@@ -246,16 +259,7 @@ void Dispose(bool disposing)
// this but will generate garbage on every frame (and this struct is used quite a lot).
if (disposing)
{
- if (m_Cmd != null)
-#if UNITY_USE_RECORDER
- if (m_Sampler != null)
- m_Cmd.EndSample(m_Sampler);
- else
- m_Cmd.EndSample(m_Name);
-#else
- m_Cmd.EndSample(m_Name);
-#endif
- m_InlineSampler?.End();
+ m_Sampler?.End(m_Cmd);
}
m_Disposed = true;
diff --git a/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraph.cs b/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraph.cs
index 700251d73a0..8cd7f991fbc 100644
--- a/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraph.cs
+++ b/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraph.cs
@@ -1,8 +1,6 @@
using System;
-using System.Diagnostics;
using System.Collections.Generic;
using UnityEngine.Rendering;
-using UnityEngine.Profiling;
namespace UnityEngine.Experimental.Rendering.RenderGraphModule
{
@@ -95,110 +93,81 @@ public class RenderGraph
///Maximum number of MRTs supported by Render Graph.
public static readonly int kMaxMRTCount = 8;
- [DebuggerDisplay("RenderPass ({name})")]
- internal abstract class RenderPass
- {
- internal RenderFunc GetExecuteDelegate()
- where PassData : class, new() => ((RenderPass)this).renderFunc;
-
- internal abstract void Execute(RenderGraphContext renderGraphContext);
- internal abstract void Release(RenderGraphContext renderGraphContext);
- internal abstract bool HasRenderFunc();
-
- internal string name;
- internal int index;
- internal ProfilingSampler customSampler;
- internal List textureReadList = new List();
- internal List textureWriteList = new List();
- internal List bufferReadList = new List();
- internal List bufferWriteList = new List();
- internal List usedRendererListList = new List();
- internal bool enableAsyncCompute;
- internal TextureHandle depthBuffer { get { return m_DepthBuffer; } }
- internal TextureHandle[] colorBuffers { get { return m_ColorBuffers; } }
- internal int colorBufferMaxIndex { get { return m_MaxColorBufferIndex; } }
-
- protected TextureHandle[] m_ColorBuffers = new TextureHandle[kMaxMRTCount];
- protected TextureHandle m_DepthBuffer;
- protected int m_MaxColorBufferIndex = -1;
-
- internal void Clear()
- {
- name = "";
- index = -1;
- customSampler = null;
- textureReadList.Clear();
- textureWriteList.Clear();
- bufferReadList.Clear();
- bufferWriteList.Clear();
- usedRendererListList.Clear();
- enableAsyncCompute = false;
-
- // Invalidate everything
- m_MaxColorBufferIndex = -1;
- m_DepthBuffer = new TextureHandle();
- for (int i = 0; i < RenderGraph.kMaxMRTCount; ++i)
- {
- m_ColorBuffers[i] = new TextureHandle();
- }
- }
-
- internal void SetColorBuffer(TextureHandle resource, int index)
- {
- Debug.Assert(index < RenderGraph.kMaxMRTCount && index >= 0);
- m_MaxColorBufferIndex = Math.Max(m_MaxColorBufferIndex, index);
- m_ColorBuffers[index] = resource;
- textureWriteList.Add(resource);
- }
+ internal struct CompiledResourceInfo
+ {
+ public List producers;
+ public bool resourceCreated;
+ public int lastReadPassIndex;
+ public int firstWritePassIndex;
+ public int refCount;
- internal void SetDepthBuffer(TextureHandle resource, DepthAccess flags)
+ public void Reset()
{
- m_DepthBuffer = resource;
- if ((flags | DepthAccess.Read) != 0)
- textureReadList.Add(resource);
- if ((flags | DepthAccess.Write) != 0)
- textureWriteList.Add(resource);
-
+ if (producers == null)
+ producers = new List();
+
+ producers.Clear();
+ resourceCreated = false;
+ lastReadPassIndex = -1;
+ firstWritePassIndex = int.MaxValue;
+ refCount = 0;
}
}
- internal sealed class RenderPass : RenderPass
- where PassData : class, new()
+ internal struct CompiledPassInfo
{
- internal PassData data;
- internal RenderFunc renderFunc;
-
- internal override void Execute(RenderGraphContext renderGraphContext)
+ public RenderGraphPass pass;
+ public List textureCreateList;
+ public List textureReleaseList;
+ public int refCount;
+ public bool pruned;
+ public bool hasSideEffect;
+ public int syncToPassIndex; // Index of the pass that needs to be waited for.
+ public int syncFromPassIndex; // Smaller pass index that waits for this pass.
+ public bool needGraphicsFence;
+ public GraphicsFence fence;
+
+ public bool enableAsyncCompute { get { return pass.enableAsyncCompute; } }
+
+ public void Reset(RenderGraphPass pass)
{
- GetExecuteDelegate()(data, renderGraphContext);
- }
+ this.pass = pass;
- internal override void Release(RenderGraphContext renderGraphContext)
- {
- Clear();
- renderGraphContext.renderGraphPool.Release(data);
- data = null;
- renderFunc = null;
- renderGraphContext.renderGraphPool.Release(this);
- }
+ if (textureCreateList == null)
+ {
+ textureCreateList = new List();
+ textureReleaseList = new List();
+ }
- internal override bool HasRenderFunc()
- {
- return renderFunc != null;
+ textureCreateList.Clear();
+ textureReleaseList.Clear();
+ refCount = 0;
+ pruned = false;
+ hasSideEffect = false;
+ syncToPassIndex = -1;
+ syncFromPassIndex = -1;
+ needGraphicsFence = false;
}
}
- RenderGraphResourceRegistry m_Resources;
- RenderGraphObjectPool m_RenderGraphPool = new RenderGraphObjectPool();
- List m_RenderPasses = new List();
- List m_RendererLists = new List();
- RenderGraphDebugParams m_DebugParameters = new RenderGraphDebugParams();
- RenderGraphLogger m_Logger = new RenderGraphLogger();
- RenderGraphDefaultResources m_DefaultResources = new RenderGraphDefaultResources();
+ RenderGraphResourceRegistry m_Resources;
+ RenderGraphObjectPool m_RenderGraphPool = new RenderGraphObjectPool();
+ List m_RenderPasses = new List();
+ List m_RendererLists = new List();
+ RenderGraphDebugParams m_DebugParameters = new RenderGraphDebugParams();
+ RenderGraphLogger m_Logger = new RenderGraphLogger();
+ RenderGraphDefaultResources m_DefaultResources = new RenderGraphDefaultResources();
+ Dictionary m_DefaultProfilingSamplers = new Dictionary();
+
+ // Compiled Render Graph info.
+ DynamicArray m_CompiledTextureInfos = new DynamicArray();
+ DynamicArray m_CompiledBufferInfos = new DynamicArray();
+ DynamicArray m_CompiledPassInfos = new DynamicArray();
+ Stack m_PruningStack = new Stack();
#region Public Interface
- // TODO: Currently only needed by SSAO to sample correctly depth texture mips. Need to figure out a way to hide this behind a proper formalization.
+ // TODO RENDERGRAPH: Currently only needed by SSAO to sample correctly depth texture mips. Need to figure out a way to hide this behind a proper formalization.
///
/// Gets the RTHandleProperties structure associated with the Render Graph's RTHandle System.
///
@@ -347,12 +316,8 @@ public ComputeBufferHandle ImportComputeBuffer(ComputeBuffer computeBuffer)
/// A new instance of a RenderGraphBuilder used to setup the new Render Pass.
public RenderGraphBuilder AddRenderPass(string passName, out PassData passData, ProfilingSampler sampler = null) where PassData : class, new()
{
- var renderPass = m_RenderGraphPool.Get>();
- renderPass.Clear();
- renderPass.index = m_RenderPasses.Count;
- renderPass.data = m_RenderGraphPool.Get();
- renderPass.name = passName;
- renderPass.customSampler = sampler;
+ var renderPass = m_RenderGraphPool.Get>();
+ renderPass.Initialize(m_RenderPasses.Count, m_RenderGraphPool.Get(), passName, sampler != null ? sampler : GetDefaultProfilingSampler(passName));
passData = renderPass.data;
@@ -369,88 +334,363 @@ public ComputeBufferHandle ImportComputeBuffer(ComputeBuffer computeBuffer)
/// Render Graph execution parameters.
public void Execute(ScriptableRenderContext renderContext, CommandBuffer cmd, in RenderGraphExecuteParams parameters)
{
- m_Logger.Initialize();
+ try
+ {
+ m_Logger.Initialize();
- // Update RTHandleSystem with size for this rendering pass.
- m_Resources.SetRTHandleReferenceSize(parameters.renderingWidth, parameters.renderingHeight, parameters.msaaSamples);
+ // Update RTHandleSystem with size for this rendering pass.
+ m_Resources.SetRTHandleReferenceSize(parameters.renderingWidth, parameters.renderingHeight, parameters.msaaSamples);
- LogFrameInformation(parameters.renderingWidth, parameters.renderingHeight);
+ LogFrameInformation(parameters.renderingWidth, parameters.renderingHeight);
- // First pass, traversal and pruning
- for (int passIndex = 0; passIndex < m_RenderPasses.Count; ++passIndex)
+ CompileRenderGraph();
+ ExecuteRenderGraph(renderContext, cmd);
+ }
+ catch (Exception e)
{
- var pass = m_RenderPasses[passIndex];
+ Debug.LogError("Render Graph Execution error");
+ Debug.LogException(e);
+ }
+ finally
+ {
+ ClearCompiledGraph();
- // TODO: Pruning
+ if (m_DebugParameters.logFrameInformation || m_DebugParameters.logResources)
+ Debug.Log(m_Logger.GetLog());
- // Gather all renderer lists
- m_RendererLists.AddRange(pass.usedRendererListList);
+ m_DebugParameters.logFrameInformation = false;
+ m_DebugParameters.logResources = false;
}
+ }
+ #endregion
- // Creates all renderer lists
- m_Resources.CreateRendererLists(m_RendererLists);
- LogRendererListsCreation();
+ #region Internal Interface
+ private RenderGraph()
+ {
- // Second pass, execution
- RenderGraphContext rgContext = new RenderGraphContext();
- rgContext.cmd = cmd;
- rgContext.renderContext = renderContext;
- rgContext.renderGraphPool = m_RenderGraphPool;
- rgContext.resources = m_Resources;
- rgContext.defaultResources = m_DefaultResources;
+ }
- try
+ void ClearCompiledGraph()
+ {
+ ClearRenderPasses();
+ m_Resources.Clear();
+ m_DefaultResources.Clear();
+ m_RendererLists.Clear();
+ m_CompiledBufferInfos.Clear();
+ m_CompiledTextureInfos.Clear();
+ m_CompiledPassInfos.Clear();
+ }
+
+ void InitializeCompilationData()
+ {
+ m_CompiledBufferInfos.Resize(m_Resources.GetComputeBufferResourceCount());
+ for (int i = 0; i < m_CompiledBufferInfos.size; ++i)
+ m_CompiledBufferInfos[i].Reset();
+ m_CompiledTextureInfos.Resize(m_Resources.GetTextureResourceCount());
+ for (int i = 0; i < m_CompiledTextureInfos.size; ++i)
+ m_CompiledTextureInfos[i].Reset();
+ m_CompiledPassInfos.Resize(m_RenderPasses.Count);
+ for (int i = 0; i < m_CompiledPassInfos.size; ++i)
+ m_CompiledPassInfos[i].Reset(m_RenderPasses[i]);
+ }
+
+ void CountReferences()
+ {
+ for (int passIndex = 0; passIndex < m_CompiledPassInfos.size; ++passIndex)
{
- for (int passIndex = 0; passIndex < m_RenderPasses.Count; ++passIndex)
+ ref CompiledPassInfo passInfo = ref m_CompiledPassInfos[passIndex];
+
+ var textureRead = passInfo.pass.textureReadList;
+ foreach (TextureHandle texture in textureRead)
+ {
+ ref CompiledResourceInfo info = ref m_CompiledTextureInfos[texture];
+ info.refCount++;
+ }
+
+ var textureWrite = passInfo.pass.textureWriteList;
+ foreach (TextureHandle texture in textureWrite)
+ {
+ ref CompiledResourceInfo info = ref m_CompiledTextureInfos[texture];
+ info.producers.Add(passIndex);
+ passInfo.refCount++;
+
+ // Writing to an imported texture is considered as a side effect because we don't know what users will do with it outside of render graph.
+ if (m_Resources.IsTextureImported(texture))
+ passInfo.hasSideEffect = true;
+ }
+
+ // Can't share the code with a generic func as TextureHandle and ComputeBufferHandle are both struct and can't inherit from a common struct with a shared API (thanks C#)
+ var bufferRead = passInfo.pass.bufferReadList;
+ foreach (ComputeBufferHandle buffer in bufferRead)
+ {
+ ref CompiledResourceInfo info = ref m_CompiledBufferInfos[buffer];
+ info.refCount++;
+ }
+
+ var bufferWrite = passInfo.pass.bufferWriteList;
+ foreach (ComputeBufferHandle buffer in bufferWrite)
+ {
+ ref CompiledResourceInfo info = ref m_CompiledBufferInfos[buffer];
+ passInfo.refCount++;
+ }
+ }
+ }
+
+ void PruneUnusedPasses(DynamicArray resourceUsageList)
+ {
+ // First gather resources that are never read.
+ m_PruningStack.Clear();
+ for (int i = 0; i < resourceUsageList.size; ++i)
+ {
+ if (resourceUsageList[i].refCount == 0)
{
- var pass = m_RenderPasses[passIndex];
+ m_PruningStack.Push(i);
+ }
+ }
- if (!pass.HasRenderFunc())
+ while (m_PruningStack.Count != 0)
+ {
+ var unusedResource = resourceUsageList[m_PruningStack.Pop()];
+ foreach (var producerIndex in unusedResource.producers)
+ {
+ ref var producerInfo = ref m_CompiledPassInfos[producerIndex];
+ producerInfo.refCount--;
+ if (producerInfo.refCount == 0 && !producerInfo.hasSideEffect)
{
- throw new InvalidOperationException(string.Format("RenderPass {0} was not provided with an execute function.", pass.name));
+ // Producer is not necessary anymore as it produces zero resources
+ // Prune it and decrement refCount of all the textures it reads.
+ producerInfo.pruned = true;
+ foreach (var textureIndex in producerInfo.pass.textureReadList)
+ {
+ ref CompiledResourceInfo resourceInfo = ref resourceUsageList[textureIndex];
+ resourceInfo.refCount--;
+ // If a texture is not used anymore, add it to the stack to be processed in subsequent iteration.
+ if (resourceInfo.refCount == 0)
+ m_PruningStack.Push(textureIndex);
+ }
}
+ }
+ }
+ }
+
+ void PruneUnusedPasses()
+ {
+ PruneUnusedPasses(m_CompiledTextureInfos);
+ PruneUnusedPasses(m_CompiledBufferInfos);
+ LogPrunedPasses();
+ }
+
+ int GetLatestProducerIndex(int passIndex, in CompiledResourceInfo info)
+ {
+ // We want to know the highest pass index below the current pass that writes to the resource.
+ int result = -1;
+ foreach (var producer in info.producers)
+ {
+ // producers are by construction in increasing order.
+ if (producer < passIndex)
+ result = producer;
+ else
+ return result;
+ }
+
+ return result;
+ }
+
+
+ void UpdatePassSynchronization(ref CompiledPassInfo currentPassInfo, ref CompiledPassInfo producerPassInfo, int currentPassIndex, int lastProducer, ref int intLastSyncIndex)
+ {
+ // Current pass needs to wait for pass index lastProducer
+ currentPassInfo.syncToPassIndex = lastProducer;
+ // Update latest pass waiting for the other pipe.
+ intLastSyncIndex = lastProducer;
+
+ // Producer will need a graphics fence that this pass will wait on.
+ producerPassInfo.needGraphicsFence = true;
+ // We update the producer pass with the index of the smallest pass waiting for it.
+ // This will be used to "lock" resource from being reused until the pipe has been synchronized.
+ if (producerPassInfo.syncFromPassIndex == -1)
+ producerPassInfo.syncFromPassIndex = currentPassIndex;
+ }
- using (new ProfilingScope(cmd, pass.customSampler))
+ void UpdateResourceSynchronization(ref int lastGraphicsPipeSync, ref int lastComputePipeSync, int currentPassIndex, in CompiledResourceInfo resource)
+ {
+ int lastProducer = GetLatestProducerIndex(currentPassIndex, resource);
+ if (lastProducer != -1)
+ {
+ ref CompiledPassInfo currentPassInfo = ref m_CompiledPassInfos[currentPassIndex];
+
+ //If the passes are on different pipes, we need synchronization.
+ if (m_CompiledPassInfos[lastProducer].enableAsyncCompute != currentPassInfo.enableAsyncCompute)
+ {
+ // Pass is on compute pipe, need sync with graphics pipe.
+ if (currentPassInfo.enableAsyncCompute)
{
- LogRenderPassBegin(pass);
- using (new RenderGraphLogIndent(m_Logger))
+ if (lastProducer > lastGraphicsPipeSync)
{
- PreRenderPassExecute(passIndex, pass, rgContext);
- pass.Execute(rgContext);
- PostRenderPassExecute(passIndex, pass, rgContext);
+ UpdatePassSynchronization(ref currentPassInfo, ref m_CompiledPassInfos[lastProducer], currentPassIndex, lastProducer, ref lastGraphicsPipeSync);
+ }
+ }
+ else
+ {
+ if (lastProducer > lastComputePipeSync)
+ {
+ UpdatePassSynchronization(ref currentPassInfo, ref m_CompiledPassInfos[lastProducer], currentPassIndex, lastProducer, ref lastComputePipeSync);
}
}
}
}
- catch(Exception e)
+ }
+
+ void UpdateResourceAllocationAndSynchronization()
+ {
+ int lastGraphicsPipeSync = -1;
+ int lastComputePipeSync = -1;
+
+ // First go through all passes.
+ // - Update the last pass read index for each resource.
+ // - Add texture to creation list for passes that first write to a texture.
+ // - Update synchronization points for all resources between compute and graphics pipes.
+ for (int passIndex = 0; passIndex < m_CompiledPassInfos.size; ++passIndex)
{
- Debug.LogError("Render Graph Execution error");
- Debug.LogException(e);
+ ref CompiledPassInfo passInfo = ref m_CompiledPassInfos[passIndex];
+
+ if (passInfo.pruned)
+ continue;
+
+ foreach (TextureHandle texture in passInfo.pass.textureReadList)
+ {
+ ref CompiledResourceInfo resourceInfo = ref m_CompiledTextureInfos[texture];
+ resourceInfo.lastReadPassIndex = Math.Max(resourceInfo.lastReadPassIndex, passIndex);
+ UpdateResourceSynchronization(ref lastGraphicsPipeSync, ref lastComputePipeSync, passIndex, resourceInfo);
+ }
+
+ foreach (TextureHandle texture in passInfo.pass.textureWriteList)
+ {
+ ref CompiledResourceInfo resourceInfo = ref m_CompiledTextureInfos[texture];
+ if (resourceInfo.firstWritePassIndex == int.MaxValue)
+ {
+ resourceInfo.firstWritePassIndex = Math.Min(resourceInfo.firstWritePassIndex, passIndex);
+ passInfo.textureCreateList.Add(texture);
+ }
+ passInfo.refCount++;
+ UpdateResourceSynchronization(ref lastGraphicsPipeSync, ref lastComputePipeSync, passIndex, resourceInfo);
+ }
+
+ foreach (ComputeBufferHandle texture in passInfo.pass.bufferReadList)
+ {
+ UpdateResourceSynchronization(ref lastGraphicsPipeSync, ref lastComputePipeSync, passIndex, m_CompiledBufferInfos[texture]);
+ }
+ foreach (ComputeBufferHandle texture in passInfo.pass.bufferWriteList)
+ {
+ UpdateResourceSynchronization(ref lastGraphicsPipeSync, ref lastComputePipeSync, passIndex, m_CompiledBufferInfos[texture]);
+ }
+
+ // Add transient resources that are only used during this pass.
+ foreach (TextureHandle texture in passInfo.pass.transientTextureList)
+ {
+ passInfo.textureCreateList.Add(texture);
+
+ ref CompiledResourceInfo info = ref m_CompiledTextureInfos[texture];
+ info.lastReadPassIndex = passIndex;
+ }
+
+ // Gather all renderer lists
+ m_RendererLists.AddRange(passInfo.pass.usedRendererListList);
}
- finally
+
+ // Now push textures to the release list of the pass that reads it last.
+ for (int i = 0; i < m_CompiledTextureInfos.size; ++i)
{
- ClearRenderPasses();
- m_Resources.Clear();
- m_DefaultResources.Clear();
- m_RendererLists.Clear();
+ CompiledResourceInfo textureInfo = m_CompiledTextureInfos[i];
+ if (textureInfo.lastReadPassIndex != -1)
+ {
+ // In case of async passes, we need to extend lifetime of resource to the first pass on the graphics pipeline that wait for async passes to be over.
+ // Otherwise, if we freed the resource right away during an async pass, another non async pass could reuse the resource even though the async pipe is not done.
+ if (m_CompiledPassInfos[textureInfo.lastReadPassIndex].enableAsyncCompute)
+ {
+ int currentPassIndex = textureInfo.lastReadPassIndex;
+ int firstWaitingPassIndex = m_CompiledPassInfos[currentPassIndex].syncFromPassIndex;
+ // Find the first async pass that is synchronized by the graphics pipeline (ie: passInfo.syncFromPassIndex != -1)
+ while (firstWaitingPassIndex == -1 && currentPassIndex < m_CompiledPassInfos.size)
+ {
+ currentPassIndex++;
+ if(m_CompiledPassInfos[currentPassIndex].enableAsyncCompute)
+ firstWaitingPassIndex = m_CompiledPassInfos[currentPassIndex].syncFromPassIndex;
+ }
- if (m_DebugParameters.logFrameInformation || m_DebugParameters.logResources)
- Debug.Log(m_Logger.GetLog());
+ // Finally add the release command to the pass before the first pass that waits for the compute pipe.
+ ref CompiledPassInfo passInfo = ref m_CompiledPassInfos[Math.Max(0, firstWaitingPassIndex - 1)];
+ passInfo.textureReleaseList.Add(new TextureHandle(i));
- m_DebugParameters.logFrameInformation = false;
- m_DebugParameters.logResources = false;
+ // Fail safe in case render graph is badly formed.
+ if (currentPassIndex == m_CompiledPassInfos.size)
+ {
+ RenderGraphPass invalidPass = m_RenderPasses[textureInfo.lastReadPassIndex];
+ throw new InvalidOperationException($"Asynchronous pass {invalidPass.name} was never synchronized on the graphics pipeline.");
+ }
+ }
+ else
+ {
+ ref CompiledPassInfo passInfo = ref m_CompiledPassInfos[textureInfo.lastReadPassIndex];
+ passInfo.textureReleaseList.Add(new TextureHandle(i));
+ }
+ }
}
+
+ // Creates all renderer lists
+ m_Resources.CreateRendererLists(m_RendererLists);
}
- #endregion
- #region Internal Interface
- private RenderGraph()
+ // Traverse the render graph:
+ // - Determines when resources are created/released
+ // - Determines async compute pass synchronization
+ // - Prune unused render passes.
+ void CompileRenderGraph()
{
+ InitializeCompilationData();
+ CountReferences();
+ PruneUnusedPasses();
+ UpdateResourceAllocationAndSynchronization();
+ LogRendererListsCreation();
+ }
+
+ // Execute the compiled render graph
+ void ExecuteRenderGraph(ScriptableRenderContext renderContext, CommandBuffer cmd)
+ {
+ RenderGraphContext rgContext = new RenderGraphContext();
+ rgContext.cmd = cmd;
+ rgContext.renderContext = renderContext;
+ rgContext.renderGraphPool = m_RenderGraphPool;
+ rgContext.resources = m_Resources;
+ rgContext.defaultResources = m_DefaultResources;
+ for (int passIndex = 0; passIndex < m_CompiledPassInfos.size; ++passIndex)
+ {
+ ref var passInfo = ref m_CompiledPassInfos[passIndex];
+ if (passInfo.pruned)
+ continue;
+
+ if (!passInfo.pass.HasRenderFunc())
+ {
+ throw new InvalidOperationException(string.Format("RenderPass {0} was not provided with an execute function.", passInfo.pass.name));
+ }
+
+ using (new ProfilingScope(rgContext.cmd, passInfo.pass.customSampler))
+ {
+ LogRenderPassBegin(passInfo);
+ using (new RenderGraphLogIndent(m_Logger))
+ {
+ PreRenderPassExecute(passInfo, ref rgContext);
+ passInfo.pass.Execute(rgContext);
+ PostRenderPassExecute(cmd, ref passInfo, ref rgContext);
+ }
+ }
+ }
}
- void PreRenderPassSetRenderTargets(in RenderPass pass, RenderGraphContext rgContext)
+ void PreRenderPassSetRenderTargets(in CompiledPassInfo passInfo, RenderGraphContext rgContext)
{
+ var pass = passInfo.pass;
if (pass.depthBuffer.IsValid() || pass.colorBufferMaxIndex != -1)
{
var mrtArray = rgContext.renderGraphPool.GetTempArray(pass.colorBufferMaxIndex + 1);
@@ -492,21 +732,61 @@ void PreRenderPassSetRenderTargets(in RenderPass pass, RenderGraphContext rgCont
}
}
- void PreRenderPassExecute(int passIndex, in RenderPass pass, RenderGraphContext rgContext)
+ void PreRenderPassExecute(in CompiledPassInfo passInfo, ref RenderGraphContext rgContext)
{
- // TODO merge clear and setup here if possible
- m_Resources.CreateAndClearTexturesForPass(rgContext, pass.index, pass.textureWriteList);
- PreRenderPassSetRenderTargets(pass, rgContext);
+ // TODO RENDERGRAPH merge clear and setup here if possible
+ RenderGraphPass pass = passInfo.pass;
+
+ // TODO RENDERGRAPH remove this when we do away with auto global texture setup
+ // (can't put it in the profiling scope otherwise it might be executed on compute queue which is not possible for global sets)
m_Resources.PreRenderPassSetGlobalTextures(rgContext, pass.textureReadList);
+
+ foreach (var texture in passInfo.textureCreateList)
+ m_Resources.CreateAndClearTexture(rgContext, texture);
+
+ PreRenderPassSetRenderTargets(passInfo, rgContext);
+
+ // Flush first the current command buffer on the render context.
+ rgContext.renderContext.ExecuteCommandBuffer(rgContext.cmd);
+ rgContext.cmd.Clear();
+
+ if (pass.enableAsyncCompute)
+ {
+ CommandBuffer asyncCmd = CommandBufferPool.Get(pass.name);
+ asyncCmd.SetExecutionFlags(CommandBufferExecutionFlags.AsyncCompute);
+ rgContext.cmd = asyncCmd;
+ }
+
+ // Synchronize with graphics or compute pipe if needed.
+ if (passInfo.syncToPassIndex != -1)
+ {
+ rgContext.cmd.WaitOnAsyncGraphicsFence(m_CompiledPassInfos[passInfo.syncToPassIndex].fence);
+ }
}
- void PostRenderPassExecute(int passIndex, in RenderPass pass, RenderGraphContext rgContext)
+ void PostRenderPassExecute(CommandBuffer mainCmd, ref CompiledPassInfo passInfo, ref RenderGraphContext rgContext)
{
+ RenderGraphPass pass = passInfo.pass;
+
+ if (passInfo.needGraphicsFence)
+ passInfo.fence = rgContext.cmd.CreateAsyncGraphicsFence();
+
+ if (pass.enableAsyncCompute)
+ {
+ // The command buffer has been filled. We can kick the async task.
+ rgContext.renderContext.ExecuteCommandBufferAsync(rgContext.cmd, ComputeQueueType.Background);
+ CommandBufferPool.Release(rgContext.cmd);
+ rgContext.cmd = mainCmd; // Restore the main command buffer.
+ }
+
if (m_DebugParameters.unbindGlobalTextures)
m_Resources.PostRenderPassUnbindGlobalTextures(rgContext, pass.textureReadList);
m_RenderGraphPool.ReleaseAllTempAlloc();
- m_Resources.ReleaseTexturesForPass(rgContext, pass.index, pass.textureReadList, pass.textureWriteList);
+
+ foreach (var texture in passInfo.textureReleaseList)
+ m_Resources.ReleaseTexture(rgContext, texture);
+
pass.Release(rgContext);
}
@@ -520,7 +800,7 @@ void LogFrameInformation(int renderingWidth, int renderingHeight)
if (m_DebugParameters.logFrameInformation)
{
m_Logger.LogLine("==== Staring frame at resolution ({0}x{1}) ====", renderingWidth, renderingHeight);
- m_Logger.LogLine("Number of passes declared: {0}", m_RenderPasses.Count);
+ m_Logger.LogLine("Number of passes declared: {0}\n", m_RenderPasses.Count);
}
}
@@ -528,18 +808,57 @@ void LogRendererListsCreation()
{
if (m_DebugParameters.logFrameInformation)
{
- m_Logger.LogLine("Number of renderer lists created: {0}", m_RendererLists.Count);
+ m_Logger.LogLine("Number of renderer lists created: {0}\n", m_RendererLists.Count);
+ }
+ }
+
+ void LogRenderPassBegin(in CompiledPassInfo passInfo)
+ {
+ if (m_DebugParameters.logFrameInformation)
+ {
+ RenderGraphPass pass = passInfo.pass;
+
+ m_Logger.LogLine("[{0}][{1}] \"{2}\"", pass.index, pass.enableAsyncCompute ? "Compute" : "Graphics", pass.name);
+ using (new RenderGraphLogIndent(m_Logger))
+ {
+ if (passInfo.syncToPassIndex != -1)
+ m_Logger.LogLine("Synchronize with [{0}]", passInfo.syncToPassIndex);
+ }
}
}
- void LogRenderPassBegin(in RenderPass pass)
+ void LogPrunedPasses()
{
if (m_DebugParameters.logFrameInformation)
{
- m_Logger.LogLine("Executing pass \"{0}\" (index: {1})", pass.name, pass.index);
+ m_Logger.LogLine("Pass pruning report:");
+ using (new RenderGraphLogIndent(m_Logger))
+ {
+ for (int i = 0; i < m_CompiledPassInfos.size; ++i)
+ {
+ if (m_CompiledPassInfos[i].pruned)
+ {
+ var pass = m_RenderPasses[i];
+ m_Logger.LogLine("[{0}] {1}", pass.index, pass.name);
+ }
+ }
+ m_Logger.LogLine("\n");
+ }
}
}
+ ProfilingSampler GetDefaultProfilingSampler(string name)
+ {
+ int hash = name.GetHashCode();
+ if (!m_DefaultProfilingSamplers.TryGetValue(hash, out var sampler))
+ {
+ sampler = new ProfilingSampler(name);
+ m_DefaultProfilingSamplers.Add(hash, sampler);
+ }
+
+ return sampler;
+ }
+
#endregion
}
}
diff --git a/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphBuilder.cs b/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphBuilder.cs
index b100ba50abc..404565f4297 100644
--- a/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphBuilder.cs
+++ b/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphBuilder.cs
@@ -8,7 +8,7 @@ namespace UnityEngine.Experimental.Rendering.RenderGraphModule
///
public struct RenderGraphBuilder : IDisposable
{
- RenderGraph.RenderPass m_RenderPass;
+ RenderGraphPass m_RenderPass;
RenderGraphResourceRegistry m_Resources;
bool m_Disposed;
@@ -22,8 +22,9 @@ public struct RenderGraphBuilder : IDisposable
/// An updated resource handle to the input resource.
public TextureHandle UseColorBuffer(TextureHandle input, int index)
{
+ CheckTransientTexture(input);
+
m_RenderPass.SetColorBuffer(input, index);
- m_Resources.UpdateTextureFirstWrite(input, m_RenderPass.index);
return input;
}
@@ -35,11 +36,9 @@ public TextureHandle UseColorBuffer(TextureHandle input, int index)
/// An updated resource handle to the input resource.
public TextureHandle UseDepthBuffer(TextureHandle input, DepthAccess flags)
{
+ CheckTransientTexture(input);
+
m_RenderPass.SetDepthBuffer(input, flags);
- if ((flags | DepthAccess.Read) != 0)
- m_Resources.UpdateTextureLastRead(input, m_RenderPass.index);
- if ((flags | DepthAccess.Write) != 0)
- m_Resources.UpdateTextureFirstWrite(input, m_RenderPass.index);
return input;
}
@@ -50,8 +49,9 @@ public TextureHandle UseDepthBuffer(TextureHandle input, DepthAccess flags)
/// An updated resource handle to the input resource.
public TextureHandle ReadTexture(TextureHandle input)
{
- m_RenderPass.textureReadList.Add(input);
- m_Resources.UpdateTextureLastRead(input, m_RenderPass.index);
+ CheckTransientTexture(input);
+
+ m_RenderPass.AddTextureRead(input);
return input;
}
@@ -62,12 +62,39 @@ public TextureHandle ReadTexture(TextureHandle input)
/// An updated resource handle to the input resource.
public TextureHandle WriteTexture(TextureHandle input)
{
+ CheckTransientTexture(input);
+
// TODO: Manage resource "version" for debugging purpose
- m_RenderPass.textureWriteList.Add(input);
- m_Resources.UpdateTextureFirstWrite(input, m_RenderPass.index);
+ m_RenderPass.AddTextureWrite(input);
return input;
}
+ ///
+ /// Create a new Render Graph Texture resource.
+ /// This texture will only be available for the current pass and will be assumed to be both written and read so users don't need to add explicit read/write declarations.
+ ///
+ /// Texture descriptor.
+ /// A new transient TextureHandle.
+ public TextureHandle CreateTransientTexture(in TextureDesc desc)
+ {
+ var result = m_Resources.CreateTexture(desc, 0, m_RenderPass.index);
+ m_RenderPass.AddTransientTexture(result);
+ return result;
+ }
+
+ ///
+ /// Create a new Render Graph Texture resource using the descriptor from another texture.
+ ///
+ /// Texture from which the descriptor should be used.
+ /// A new transient TextureHandle.
+ public TextureHandle CreateTransientTexture(TextureHandle texture)
+ {
+ var desc = m_Resources.GetTextureResourceDesc(texture);
+ var result = m_Resources.CreateTexture(desc, 0, m_RenderPass.index);
+ m_RenderPass.AddTransientTexture(result);
+ return result;
+ }
+
///
/// Specify a Renderer List resource to use during the pass.
///
@@ -75,7 +102,7 @@ public TextureHandle WriteTexture(TextureHandle input)
/// An updated resource handle to the input resource.
public RendererListHandle UseRendererList(RendererListHandle input)
{
- m_RenderPass.usedRendererListList.Add(input);
+ m_RenderPass.UseRendererList(input);
return input;
}
@@ -86,7 +113,7 @@ public RendererListHandle UseRendererList(RendererListHandle input)
/// An updated resource handle to the input resource.
public ComputeBufferHandle ReadComputeBuffer(ComputeBufferHandle input)
{
- m_RenderPass.bufferReadList.Add(input);
+ m_RenderPass.AddBufferRead(input);
return input;
}
@@ -97,7 +124,7 @@ public ComputeBufferHandle ReadComputeBuffer(ComputeBufferHandle input)
/// An updated resource handle to the input resource.
public ComputeBufferHandle WriteComputeBuffer(ComputeBufferHandle input)
{
- m_RenderPass.bufferWriteList.Add(input);
+ m_RenderPass.AddBufferWrite(input);
return input;
}
@@ -109,7 +136,7 @@ public ComputeBufferHandle WriteComputeBuffer(ComputeBufferHandle input)
/// Render function for the pass.
public void SetRenderFunc(RenderFunc renderFunc) where PassData : class, new()
{
- ((RenderGraph.RenderPass)m_RenderPass).renderFunc = renderFunc;
+ ((RenderGraphPass)m_RenderPass).renderFunc = renderFunc;
}
///
@@ -118,7 +145,7 @@ public ComputeBufferHandle WriteComputeBuffer(ComputeBufferHandle input)
/// Set to true to enable asynchronous compute.
public void EnableAsyncCompute(bool value)
{
- m_RenderPass.enableAsyncCompute = value;
+ m_RenderPass.EnableAsyncCompute(value);
}
///
@@ -131,7 +158,7 @@ public void Dispose()
#endregion
#region Internal Interface
- internal RenderGraphBuilder(RenderGraph.RenderPass renderPass, RenderGraphResourceRegistry resources)
+ internal RenderGraphBuilder(RenderGraphPass renderPass, RenderGraphResourceRegistry resources)
{
m_RenderPass = renderPass;
m_Resources = resources;
@@ -145,6 +172,14 @@ void Dispose(bool disposing)
m_Disposed = true;
}
+
+ void CheckTransientTexture(TextureHandle input)
+ {
+ if (input.transientPassIndex != -1 && input.transientPassIndex != m_RenderPass.index)
+ {
+ throw new ArgumentException($"Trying to use a transient texture (pass index {input.transientPassIndex}) in a different pass (pass index {m_RenderPass.index}.");
+ }
+ }
#endregion
}
}
diff --git a/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphLogger.cs b/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphLogger.cs
index b41e1fcfe29..df946c91743 100644
--- a/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphLogger.cs
+++ b/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphLogger.cs
@@ -25,10 +25,12 @@ public void Dispose()
void Dispose(bool disposing)
{
+ Debug.Assert(m_Logger != null, "RenderGraphLogIndent: logger parameter should not be null.");
+
if (m_Disposed)
return;
- if (disposing)
+ if (disposing && m_Logger != null)
{
m_Logger.DecrementIndentation(m_Indentation);
}
diff --git a/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphPass.cs b/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphPass.cs
new file mode 100644
index 00000000000..7a3c5b5ca67
--- /dev/null
+++ b/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphPass.cs
@@ -0,0 +1,155 @@
+using System;
+using System.Diagnostics;
+using System.Collections.Generic;
+using UnityEngine.Rendering;
+
+namespace UnityEngine.Experimental.Rendering.RenderGraphModule
+{
+ [DebuggerDisplay("RenderPass: {name} (Index:{index} Async:{enableAsyncCompute})")]
+ abstract class RenderGraphPass
+ {
+ public RenderFunc GetExecuteDelegate()
+ where PassData : class, new() => ((RenderGraphPass)this).renderFunc;
+
+ public abstract void Execute(RenderGraphContext renderGraphContext);
+ public abstract void Release(RenderGraphContext renderGraphContext);
+ public abstract bool HasRenderFunc();
+
+ public string name { get; protected set; }
+ public int index { get; protected set; }
+ public ProfilingSampler customSampler { get; protected set; }
+ public bool enableAsyncCompute { get; protected set; }
+
+ public TextureHandle depthBuffer { get; protected set; }
+ public TextureHandle[] colorBuffers { get; protected set; } = new TextureHandle[RenderGraph.kMaxMRTCount];
+ public int colorBufferMaxIndex { get; protected set; } = -1;
+ public int refCount { get; protected set; }
+
+ List m_TextureReadList = new List();
+ List m_TextureWriteList = new List();
+ List m_TransientTextureList = new List();
+ List m_BufferReadList = new List();
+ List m_BufferWriteList = new List();
+ List m_UsedRendererListList = new List();
+
+ public IReadOnlyCollection textureReadList { get { return m_TextureReadList; } }
+ public IReadOnlyCollection textureWriteList { get { return m_TextureWriteList; } }
+ public IReadOnlyCollection transientTextureList { get { return m_TransientTextureList; } }
+ public IReadOnlyCollection bufferReadList { get { return m_BufferReadList; } }
+ public IReadOnlyCollection bufferWriteList { get { return m_BufferWriteList; } }
+ public IReadOnlyCollection usedRendererListList { get { return m_UsedRendererListList; } }
+
+ public void Clear()
+ {
+ name = "";
+ index = -1;
+ customSampler = null;
+ m_TextureReadList.Clear();
+ m_TextureWriteList.Clear();
+ m_BufferReadList.Clear();
+ m_BufferWriteList.Clear();
+ m_TransientTextureList.Clear();
+ m_UsedRendererListList.Clear();
+ enableAsyncCompute = false;
+ refCount = 0;
+
+ // Invalidate everything
+ colorBufferMaxIndex = -1;
+ depthBuffer = new TextureHandle();
+ for (int i = 0; i < RenderGraph.kMaxMRTCount; ++i)
+ {
+ colorBuffers[i] = new TextureHandle();
+ }
+ }
+
+ public void AddTextureWrite(TextureHandle texture)
+ {
+ m_TextureWriteList.Add(texture);
+ refCount++;
+ }
+
+ public void AddTextureRead(TextureHandle texture)
+ {
+ m_TextureReadList.Add(texture);
+ }
+
+ public void AddBufferWrite(ComputeBufferHandle buffer)
+ {
+ m_BufferWriteList.Add(buffer);
+ refCount++;
+ }
+
+ public void AddTransientTexture(TextureHandle texture)
+ {
+ m_TransientTextureList.Add(texture);
+ }
+
+ public void AddBufferRead(ComputeBufferHandle buffer)
+ {
+ m_BufferReadList.Add(buffer);
+ }
+
+ public void UseRendererList(RendererListHandle rendererList)
+ {
+ m_UsedRendererListList.Add(rendererList);
+ }
+
+ public void EnableAsyncCompute(bool value)
+ {
+ enableAsyncCompute = value;
+ }
+
+ public void SetColorBuffer(TextureHandle resource, int index)
+ {
+ Debug.Assert(index < RenderGraph.kMaxMRTCount && index >= 0);
+ colorBufferMaxIndex = Math.Max(colorBufferMaxIndex, index);
+ colorBuffers[index] = resource;
+ AddTextureWrite(resource);
+ }
+
+ public void SetDepthBuffer(TextureHandle resource, DepthAccess flags)
+ {
+ depthBuffer = resource;
+ if ((flags | DepthAccess.Read) != 0)
+ AddTextureRead(resource);
+ if ((flags | DepthAccess.Write) != 0)
+ AddTextureWrite(resource);
+ }
+ }
+
+ [DebuggerDisplay("RenderPass: {name} (Index:{index} Async:{enableAsyncCompute})")]
+ internal sealed class RenderGraphPass : RenderGraphPass
+ where PassData : class, new()
+ {
+ internal PassData data;
+ internal RenderFunc renderFunc;
+
+ public override void Execute(RenderGraphContext renderGraphContext)
+ {
+ GetExecuteDelegate()(data, renderGraphContext);
+ }
+
+ public void Initialize(int passIndex, PassData passData, string passName, ProfilingSampler sampler)
+ {
+ Clear();
+ index = passIndex;
+ data = passData;
+ name = passName;
+ customSampler = sampler;
+ }
+
+ public override void Release(RenderGraphContext renderGraphContext)
+ {
+ Clear();
+ renderGraphContext.renderGraphPool.Release(data);
+ data = null;
+ renderFunc = null;
+ renderGraphContext.renderGraphPool.Release(this);
+ }
+
+ public override bool HasRenderFunc()
+ {
+ return renderFunc != null;
+ }
+ }
+}
diff --git a/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphPass.cs.meta b/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphPass.cs.meta
new file mode 100644
index 00000000000..9f00928f05e
--- /dev/null
+++ b/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphPass.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 377a2b96156b1344eaf58df67e35de17
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphResourceRegistry.cs b/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphResourceRegistry.cs
index 3b8a66efc34..c186e92c47f 100644
--- a/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphResourceRegistry.cs
+++ b/com.unity.render-pipelines.core/Runtime/RenderGraph/RenderGraphResourceRegistry.cs
@@ -18,7 +18,8 @@ public struct TextureHandle
{
bool m_IsValid;
internal int handle { get; private set; }
- internal TextureHandle(int handle) { this.handle = handle; m_IsValid = true; }
+ internal int transientPassIndex { get; private set; }
+ internal TextureHandle(int handle, int transientPassIndex = -1) { this.handle = handle; m_IsValid = true; this.transientPassIndex = transientPassIndex; }
///
/// Conversion to int.
///
@@ -30,6 +31,7 @@ public struct TextureHandle
///
/// True if the handle is valid.
public bool IsValid() => m_IsValid;
+
}
///
@@ -292,8 +294,6 @@ internal struct TextureResource
public bool imported;
public RTHandle rt;
public int cachedHash;
- public int firstWritePassIndex;
- public int lastReadPassIndex;
public int shaderProperty;
public bool wasReleased;
@@ -321,8 +321,6 @@ void Reset()
imported = false;
rt = null;
cachedHash = -1;
- firstWritePassIndex = int.MaxValue;
- lastReadPassIndex = -1;
wasReleased = false;
}
}
@@ -441,6 +439,11 @@ internal TextureHandle ImportTexture(RTHandle rt, int shaderProperty = 0)
return new TextureHandle(newHandle);
}
+ internal bool IsTextureImported(TextureHandle handle)
+ {
+ return handle.IsValid() ? GetTextureResource(handle).imported : false;
+ }
+
internal TextureHandle ImportBackbuffer(RenderTargetIdentifier rt)
{
if (m_CurrentBackbuffer != null)
@@ -452,36 +455,17 @@ internal TextureHandle ImportBackbuffer(RenderTargetIdentifier rt)
return new TextureHandle(newHandle);
}
- internal TextureHandle CreateTexture(in TextureDesc desc, int shaderProperty = 0)
+ internal TextureHandle CreateTexture(in TextureDesc desc, int shaderProperty = 0, int transientPassIndex = -1)
{
ValidateTextureDesc(desc);
int newHandle = m_TextureResources.Add(new TextureResource(desc, shaderProperty));
- return new TextureHandle(newHandle);
- }
-
- internal void UpdateTextureFirstWrite(TextureHandle tex, int passIndex)
- {
- ref var res = ref GetTextureResource(tex);
- res.firstWritePassIndex = Math.Min(passIndex, res.firstWritePassIndex);
-
- //// We increment lastRead index here so that a resource used only for a single pass can be released at the end of said pass.
- //// This will also keep the resource alive as long as it is written to.
- //// Typical example is a depth buffer that may never be explicitly read from but is necessary all along
- ///
- // PROBLEM: Increasing last read on write operation will keep the target alive even if it's not used at all so it's not good.
- // If we don't do it though, it means that client code cannot write "by default" into a target as it will try to write to an already released target.
- // Example:
- // DepthPrepass: Writes to Depth and Normal buffers (pass will create normal buffer)
- // ObjectMotion: Writes to MotionVectors and Normal => Exception because NormalBuffer is already released as it not used.
- // => Solution includes : Shader Combination (without MRT for example) / Dummy Targets
- //res.lastReadPassIndex = Math.Max(passIndex, res.lastReadPassIndex);
+ return new TextureHandle(newHandle, transientPassIndex);
}
- internal void UpdateTextureLastRead(TextureHandle tex, int passIndex)
+ internal int GetTextureResourceCount()
{
- ref var res = ref GetTextureResource(tex);
- res.lastReadPassIndex = Math.Max(passIndex, res.lastReadPassIndex);
+ return m_TextureResources.size;
}
ref TextureResource GetTextureResource(TextureHandle res)
@@ -508,29 +492,36 @@ internal ComputeBufferHandle ImportComputeBuffer(ComputeBuffer computeBuffer)
return new ComputeBufferHandle(newHandle);
}
- internal void CreateAndClearTexturesForPass(RenderGraphContext rgContext, int passIndex, List textures)
+ internal int GetComputeBufferResourceCount()
+ {
+ return m_ComputeBufferResources.size;
+ }
+
+ internal ref ComputeBufferResource GetComputeBufferResource(ComputeBufferHandle res)
{
- foreach (var rgResource in textures)
+ return ref m_ComputeBufferResources[res];
+ }
+
+ internal void CreateAndClearTexture(RenderGraphContext rgContext, TextureHandle texture)
+ {
+ ref var resource = ref GetTextureResource(texture);
+ if (!resource.imported)
{
- ref var resource = ref GetTextureResource(rgResource);
- if (!resource.imported && resource.firstWritePassIndex == passIndex)
- {
- CreateTextureForPass(ref resource);
+ CreateTextureForPass(ref resource);
- if (resource.desc.clearBuffer || m_RenderGraphDebug.clearRenderTargetsAtCreation)
+ if (resource.desc.clearBuffer || m_RenderGraphDebug.clearRenderTargetsAtCreation)
+ {
+ bool debugClear = m_RenderGraphDebug.clearRenderTargetsAtCreation && !resource.desc.clearBuffer;
+ var name = debugClear ? "RenderGraph: Clear Buffer (Debug)" : "RenderGraph: Clear Buffer";
+ using (new ProfilingScope(rgContext.cmd, ProfilingSampler.Get(RenderGraphProfileId.RenderGraphClear)))
{
- bool debugClear = m_RenderGraphDebug.clearRenderTargetsAtCreation && !resource.desc.clearBuffer;
- var name = debugClear ? "RenderGraph: Clear Buffer (Debug)" : "RenderGraph: Clear Buffer";
- using (new ProfilingScope(rgContext.cmd, ProfilingSampler.Get(RenderGraphProfileId.RenderGraphClear)))
- {
- var clearFlag = resource.desc.depthBufferBits != DepthBits.None ? ClearFlag.Depth : ClearFlag.Color;
- var clearColor = debugClear ? Color.magenta : resource.desc.clearColor;
- CoreUtils.SetRenderTarget(rgContext.cmd, resource.rt, clearFlag, clearColor);
- }
+ var clearFlag = resource.desc.depthBufferBits != DepthBits.None ? ClearFlag.Depth : ClearFlag.Color;
+ var clearColor = debugClear ? Color.magenta : resource.desc.clearColor;
+ CoreUtils.SetRenderTarget(rgContext.cmd, resource.rt, clearFlag, clearColor);
}
-
- LogTextureCreation(resource.rt, resource.desc.clearBuffer || m_RenderGraphDebug.clearRenderTargetsAtCreation);
}
+
+ LogTextureCreation(resource.rt, resource.desc.clearBuffer || m_RenderGraphDebug.clearRenderTargetsAtCreation);
}
}
@@ -540,7 +531,7 @@ void CreateTextureForPass(ref TextureResource resource)
int hashCode = desc.GetHashCode();
if(resource.rt != null)
- throw new InvalidOperationException(string.Format("Trying to create an already created texture ({0}). Texture was probably declared for writing more than once.", resource.desc.name));
+ throw new InvalidOperationException(string.Format("Trying to create an already created texture ({0}). Texture was probably declared for writing more than once in the same pass.", resource.desc.name));
resource.rt = null;
if (!TryGetRenderTarget(hashCode, out resource.rt))
@@ -578,7 +569,7 @@ void CreateTextureForPass(ref TextureResource resource)
resource.cachedHash = hashCode;
}
- void SetGlobalTextures(RenderGraphContext rgContext, List textures, bool bindDummyTexture)
+ void SetGlobalTextures(RenderGraphContext rgContext, IReadOnlyCollection textures, bool bindDummyTexture)
{
foreach (var resource in textures)
{
@@ -595,62 +586,35 @@ void SetGlobalTextures(RenderGraphContext rgContext, List texture
}
- internal void PreRenderPassSetGlobalTextures(RenderGraphContext rgContext, List textures)
+ internal void PreRenderPassSetGlobalTextures(RenderGraphContext rgContext, IReadOnlyCollection textures)
{
SetGlobalTextures(rgContext, textures, false);
}
- internal void PostRenderPassUnbindGlobalTextures(RenderGraphContext rgContext, List textures)
+ internal void PostRenderPassUnbindGlobalTextures(RenderGraphContext rgContext, IReadOnlyCollection textures)
{
SetGlobalTextures(rgContext, textures, true);
}
- internal void ReleaseTexturesForPass(RenderGraphContext rgContext, int passIndex, List readTextures, List writtenTextures)
+ internal void ReleaseTexture(RenderGraphContext rgContext, TextureHandle resource)
{
- foreach (var resource in readTextures)
+ ref var resourceDesc = ref GetTextureResource(resource);
+ if (!resourceDesc.imported)
{
- ref var resourceDesc = ref GetTextureResource(resource);
- if (!resourceDesc.imported && resourceDesc.lastReadPassIndex == passIndex)
+ if (m_RenderGraphDebug.clearRenderTargetsAtRelease)
{
- if (m_RenderGraphDebug.clearRenderTargetsAtRelease)
+ using (new ProfilingScope(rgContext.cmd, ProfilingSampler.Get(RenderGraphProfileId.RenderGraphClearDebug)))
{
- using (new ProfilingScope(rgContext.cmd, ProfilingSampler.Get(RenderGraphProfileId.RenderGraphClearDebug)))
- {
- var clearFlag = resourceDesc.desc.depthBufferBits != DepthBits.None ? ClearFlag.Depth : ClearFlag.Color;
- CoreUtils.SetRenderTarget(rgContext.cmd, GetTexture(resource), clearFlag, Color.magenta);
- }
+ var clearFlag = resourceDesc.desc.depthBufferBits != DepthBits.None ? ClearFlag.Depth : ClearFlag.Color;
+ CoreUtils.SetRenderTarget(rgContext.cmd, GetTexture(resource), clearFlag, Color.magenta);
}
-
- ReleaseTextureForPass(resource);
- }
- }
-
- // If a resource was created for only a single pass, we don't want users to have to declare explicitly the read operation.
- // So to do that, we also update lastReadIndex on resource writes.
- // This means that we need to check written resources for destruction too
- foreach (var resource in writtenTextures)
- {
- ref var resourceDesc = ref GetTextureResource(resource);
- // <= because a texture that is only declared as written in a single pass (and read implicitly in the same pass) will have the default lastReadPassIndex at -1
- if (!resourceDesc.imported && resourceDesc.lastReadPassIndex <= passIndex)
- {
- ReleaseTextureForPass(resource);
}
- }
- }
-
- void ReleaseTextureForPass(TextureHandle res)
- {
- ref var resource = ref m_TextureResources[res];
- // This can happen because we release texture in two passes (see ReleaseTexturesForPass) and texture can be present in both passes
- if (resource.rt != null)
- {
- LogTextureRelease(resource.rt);
- ReleaseTextureResource(resource.cachedHash, resource.rt);
- resource.cachedHash = -1;
- resource.rt = null;
- resource.wasReleased = true;
+ LogTextureRelease(resourceDesc.rt);
+ ReleaseTextureResource(resourceDesc.cachedHash, resourceDesc.rt);
+ resourceDesc.cachedHash = -1;
+ resourceDesc.rt = null;
+ resourceDesc.wasReleased = true;
}
}
@@ -761,12 +725,16 @@ internal void Clear()
#if DEVELOPMENT_BUILD || UNITY_EDITOR
if (m_AllocatedTextures.Count != 0)
{
- Debug.LogWarning("RenderGraph: Not all textures were released.");
+ string logMessage = "RenderGraph: Not all textures were released.";
+
List<(int, RTHandle)> tempList = new List<(int, RTHandle)>(m_AllocatedTextures);
foreach (var value in tempList)
{
+ logMessage = $"{logMessage}\n\t{value.Item2.name}";
ReleaseTextureResource(value.Item1, value.Item2);
}
+
+ Debug.LogWarning(logMessage);
}
#endif
}
diff --git a/com.unity.render-pipelines.high-definition/Runtime/Lighting/ScreenSpaceLighting/AmbientOcclusion.RenderGraph.cs b/com.unity.render-pipelines.high-definition/Runtime/Lighting/ScreenSpaceLighting/AmbientOcclusion.RenderGraph.cs
index 926a23f2f84..49bd699a153 100644
--- a/com.unity.render-pipelines.high-definition/Runtime/Lighting/ScreenSpaceLighting/AmbientOcclusion.RenderGraph.cs
+++ b/com.unity.render-pipelines.high-definition/Runtime/Lighting/ScreenSpaceLighting/AmbientOcclusion.RenderGraph.cs
@@ -30,7 +30,7 @@ public TextureHandle Render(RenderGraph renderGraph, HDCamera hdCamera, TextureH
historyRT.referenceSize.y * historyRT.scaleFactor.y);
var rtScaleForHistory = hdCamera.historyRTHandleProperties.rtHandleScale;
- var aoParameters = PrepareRenderAOParameters(hdCamera, renderGraph.rtHandleProperties, historySize * rtScaleForHistory, frameCount);
+ var aoParameters = PrepareRenderAOParameters(hdCamera, historySize * rtScaleForHistory, frameCount);
var packedData = RenderAO(renderGraph, aoParameters, depthPyramid);
result = DenoiseAO(renderGraph, aoParameters, motionVectors, packedData, currentHistory, outputHistory);
@@ -102,8 +102,8 @@ TextureHandle DenoiseAO( RenderGraph renderGraph,
passData.parameters = parameters;
passData.packedData = builder.ReadTexture(aoPackedData);
passData.motionVectors = builder.ReadTexture(motionVectors);
- passData.packedDataBlurred = builder.WriteTexture(renderGraph.CreateTexture(
- new TextureDesc(Vector2.one * scaleFactor, true, true) { colorFormat = GraphicsFormat.R32_UInt, enableRandomWrite = true, name = "AO Packed blurred data" } ));
+ passData.packedDataBlurred = builder.CreateTransientTexture(
+ new TextureDesc(Vector2.one * scaleFactor, true, true) { colorFormat = GraphicsFormat.R32_UInt, enableRandomWrite = true, name = "AO Packed blurred data" } );
passData.currentHistory = builder.ReadTexture(currentHistory); // can also be written on first frame, but since it's an imported resource, it doesn't matter in term of lifetime.
passData.outputHistory = builder.WriteTexture(outputHistory);
diff --git a/com.unity.render-pipelines.high-definition/Runtime/Lighting/ScreenSpaceLighting/AmbientOcclusion.cs b/com.unity.render-pipelines.high-definition/Runtime/Lighting/ScreenSpaceLighting/AmbientOcclusion.cs
index 25273975777..74170876cb9 100644
--- a/com.unity.render-pipelines.high-definition/Runtime/Lighting/ScreenSpaceLighting/AmbientOcclusion.cs
+++ b/com.unity.render-pipelines.high-definition/Runtime/Lighting/ScreenSpaceLighting/AmbientOcclusion.cs
@@ -300,7 +300,7 @@ struct RenderAOParameters
public ShaderVariablesAmbientOcclusion cb;
}
- RenderAOParameters PrepareRenderAOParameters(HDCamera camera, RTHandleProperties rtHandleProperties, Vector2 historySize, int frameCount)
+ RenderAOParameters PrepareRenderAOParameters(HDCamera camera, Vector2 historySize, int frameCount)
{
var parameters = new RenderAOParameters();
@@ -567,7 +567,7 @@ internal void Dispatch(CommandBuffer cmd, HDCamera camera, int frameCount)
currentHistory.referenceSize.y * currentHistory.scaleFactor.y);
var rtScaleForHistory = camera.historyRTHandleProperties.rtHandleScale;
- var aoParameters = PrepareRenderAOParameters(camera, RTHandles.rtHandleProperties, historySize * rtScaleForHistory, frameCount);
+ var aoParameters = PrepareRenderAOParameters(camera, historySize * rtScaleForHistory, frameCount);
using (new ProfilingScope(cmd, ProfilingSampler.Get(HDProfileId.HorizonSSAO)))
{
RenderAO(aoParameters, m_PackedDataTex, m_Resources, cmd);
diff --git a/com.unity.render-pipelines.high-definition/Runtime/Lighting/VolumetricLighting/VolumetricLighting.cs b/com.unity.render-pipelines.high-definition/Runtime/Lighting/VolumetricLighting/VolumetricLighting.cs
index eaafd5edd74..7c3280d4d4f 100644
--- a/com.unity.render-pipelines.high-definition/Runtime/Lighting/VolumetricLighting/VolumetricLighting.cs
+++ b/com.unity.render-pipelines.high-definition/Runtime/Lighting/VolumetricLighting/VolumetricLighting.cs
@@ -467,7 +467,7 @@ internal void DestroyVolumetricLightingBuffers()
CoreUtils.SafeRelease(m_VisibleVolumeDataBuffer);
CoreUtils.SafeRelease(m_VisibleVolumeBoundsBuffer);
- m_VisibleVolumeData = null; // free()
+ m_VisibleVolumeData = null; // free()
m_VisibleVolumeBounds = null; // free()
}
@@ -493,7 +493,7 @@ internal void ResizeVolumetricLightingBuffers(HDCamera hdCamera, int frameIndex)
var currentParams = hdCamera.vBufferParams[currIdx];
- ResizeVolumetricBuffer(ref m_DensityBuffer, "VBufferDensity", currentParams.viewportSize.x,
+ ResizeVolumetricBuffer(ref m_DensityBuffer, "VBufferDensity", currentParams.viewportSize.x,
currentParams.viewportSize.y,
currentParams.viewportSize.z);
ResizeVolumetricBuffer(ref m_LightingBuffer, "VBufferLighting", currentParams.viewportSize.x,
diff --git a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/PostProcessSystem.RenderGraph.cs b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/PostProcessSystem.RenderGraph.cs
index 5b55edea50a..692f3918445 100644
--- a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/PostProcessSystem.RenderGraph.cs
+++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/PostProcessSystem.RenderGraph.cs
@@ -5,9 +5,9 @@ namespace UnityEngine.Rendering.HighDefinition
{
partial class PostProcessSystem
{
- public void Render( RenderGraph renderGraph,
- HDCamera hdCamera,
- BlueNoise blueNoise,
+ public void Render( RenderGraph renderGraph,
+ HDCamera hdCamera,
+ BlueNoise blueNoise,
TextureHandle colorBuffer,
TextureHandle afterPostProcessTexture,
TextureHandle depthBuffer,
diff --git a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/PostProcessSystem.cs b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/PostProcessSystem.cs
index af115aa692b..24985b52709 100644
--- a/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/PostProcessSystem.cs
+++ b/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/PostProcessSystem.cs
@@ -188,6 +188,15 @@ public PostProcessSystem(HDRenderPipelineAsset hdAsset, RenderPipelineResources
m_KeepAlpha = hdAsset.currentPlatformRenderPipelineSettings.supportsAlpha;
}
+ // Setup a default exposure textures and clear it to neutral values so that the exposure
+ // multiplier is 1 and thus has no effect
+ // Beware that 0 in EV100 maps to a multiplier of 0.833 so the EV100 value in this
+ // neutral exposure texture isn't 0
+ m_EmptyExposureTexture = RTHandles.Alloc(1, 1, colorFormat: k_ExposureFormat,
+ enableRandomWrite: true, name: "Empty EV100 Exposure");
+
+ FillEmptyExposureTexture();
+
// Call after initializing m_LutSize and m_KeepAlpha as it's needed for render target allocation.
InitializeNonRenderGraphResources(hdAsset);
}
@@ -196,6 +205,9 @@ public void Cleanup()
{
CleanupNonRenderGraphResources();
+ RTHandles.Release(m_EmptyExposureTexture);
+ m_EmptyExposureTexture = null;
+
CoreUtils.Destroy(m_ExposureCurveTexture);
CoreUtils.Destroy(m_InternalSpectralLut);
CoreUtils.Destroy(m_FinalPassMaterial);
@@ -247,16 +259,6 @@ public void InitializeNonRenderGraphResources(HDRenderPipelineAsset hdAsset)
enableRandomWrite: true
);
- // Setup a default exposure textures and clear it to neutral values so that the exposure
- // multiplier is 1 and thus has no effect
- // Beware that 0 in EV100 maps to a multiplier of 0.833 so the EV100 value in this
- // neutral exposure texture isn't 0
- m_EmptyExposureTexture = RTHandles.Alloc(1, 1, colorFormat: k_ExposureFormat,
- enableRandomWrite: true, name: "Empty EV100 Exposure"
- );
-
- FillEmptyExposureTexture();
-
// Misc targets
m_TempTexture1024 = RTHandles.Alloc(
1024, 1024, colorFormat: GraphicsFormat.R16G16_SFloat,
@@ -283,30 +285,29 @@ public void CleanupNonRenderGraphResources()
m_Pool.Cleanup();
- RTHandles.Release(m_EmptyExposureTexture);
RTHandles.Release(m_TempTexture1024);
RTHandles.Release(m_TempTexture32);
RTHandles.Release(m_AlphaTexture);
RTHandles.Release(m_InternalLogLut);
- m_EmptyExposureTexture = null;
m_TempTexture1024 = null;
m_TempTexture32 = null;
m_AlphaTexture = null;
m_InternalLogLut = null;
}
+
// In some cases, the internal buffer of render textures might be invalid.
// Usually when using these textures with API such as SetRenderTarget, they are recreated internally.
// This is not the case when these textures are used exclusively with Compute Shaders. So to make sure they work in this case, we recreate them here.
void CheckRenderTexturesValidity()
{
- if (!m_NonRenderGraphResourcesAvailable)
- return;
-
if (!m_EmptyExposureTexture.rt.IsCreated())
FillEmptyExposureTexture();
+ if (!m_NonRenderGraphResourcesAvailable)
+ return;
+
HDUtils.CheckRTCreated(m_InternalLogLut.rt);
HDUtils.CheckRTCreated(m_TempTexture1024.rt);
HDUtils.CheckRTCreated(m_TempTexture32.rt);
diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Camera/HDCamera.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Camera/HDCamera.cs
index 81881ecbf12..e77c0825e69 100644
--- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Camera/HDCamera.cs
+++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Camera/HDCamera.cs
@@ -746,8 +746,8 @@ internal void ExecuteCaptureActions(RenderGraph renderGraph, TextureHandle input
passData.input = builder.ReadTexture(input);
// We need to blit to an intermediate texture because input resolution can be bigger than the camera resolution
// Since recorder does not know about this, we need to send a texture of the right size.
- passData.tempTexture = builder.WriteTexture(renderGraph.CreateTexture(new TextureDesc(actualWidth, actualHeight)
- { colorFormat = inputDesc.colorFormat, name = "TempCaptureActions" }));
+ passData.tempTexture = builder.CreateTransientTexture(new TextureDesc(actualWidth, actualHeight)
+ { colorFormat = inputDesc.colorFormat, name = "TempCaptureActions" });
builder.SetRenderFunc(
(ExecuteCaptureActionsPassData data, RenderGraphContext ctx) =>
diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.Debug.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.Debug.cs
index 8eda7f371ca..fe353879da5 100644
--- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.Debug.cs
+++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.Debug.cs
@@ -137,12 +137,12 @@ static void RenderLightVolumes(RenderGraph renderGraph, in DebugParameters debug
using (var builder = renderGraph.AddRenderPass("LightVolumes", out var passData))
{
passData.parameters = s_lightVolumes.PrepareLightVolumeParameters(debugParameters.hdCamera, debugParameters.debugDisplaySettings.data.lightingDebugSettings, cullResults);
- passData.lightCountBuffer = builder.WriteTexture(renderGraph.CreateTexture(new TextureDesc(Vector2.one, true, true)
- { colorFormat= GraphicsFormat.R32_SFloat, clearBuffer = true, clearColor = Color.black, name = "LightVolumeCount" }));
- passData.colorAccumulationBuffer = builder.WriteTexture(renderGraph.CreateTexture(new TextureDesc(Vector2.one, true, true)
- { colorFormat = GraphicsFormat.R16G16B16A16_SFloat, clearBuffer = true, clearColor = Color.black, name = "LightVolumeColorAccumulation" }));
- passData.debugLightVolumesTexture = builder.WriteTexture(renderGraph.CreateTexture(new TextureDesc(Vector2.one, true, true)
- { colorFormat = GraphicsFormat.R16G16B16A16_SFloat, clearBuffer = true, clearColor = Color.black, enableRandomWrite = true, name = "LightVolumeDebugLightVolumesTexture" }));
+ passData.lightCountBuffer = builder.CreateTransientTexture(new TextureDesc(Vector2.one, true, true)
+ { colorFormat= GraphicsFormat.R32_SFloat, clearBuffer = true, clearColor = Color.black, name = "LightVolumeCount" });
+ passData.colorAccumulationBuffer = builder.CreateTransientTexture(new TextureDesc(Vector2.one, true, true)
+ { colorFormat = GraphicsFormat.R16G16B16A16_SFloat, clearBuffer = true, clearColor = Color.black, name = "LightVolumeColorAccumulation" });
+ passData.debugLightVolumesTexture = builder.CreateTransientTexture(new TextureDesc(Vector2.one, true, true)
+ { colorFormat = GraphicsFormat.R16G16B16A16_SFloat, clearBuffer = true, clearColor = Color.black, enableRandomWrite = true, name = "LightVolumeDebugLightVolumesTexture" });
passData.depthBuffer = builder.UseDepthBuffer(depthBuffer, DepthAccess.ReadWrite);
passData.destination = builder.WriteTexture(destination);
diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.LightLoop.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.LightLoop.cs
index caa18d08333..b17034843db 100644
--- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.LightLoop.cs
+++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.LightLoop.cs
@@ -235,7 +235,7 @@ LightingOutput RenderDeferredLighting( RenderGraph renderGraph,
// TODO RENDERGRAPH: Check how to avoid this kind of pattern.
// Unfortunately, the low level needs this texture to always be bound with UAV enabled, so in order to avoid effectively creating the full resolution texture here,
// we need to create a small dummy texture.
- passData.sssDiffuseLightingBuffer = builder.WriteTexture(renderGraph.CreateTexture(new TextureDesc(1, 1, true, true) { colorFormat = GraphicsFormat.B10G11R11_UFloatPack32, enableRandomWrite = true } ));
+ passData.sssDiffuseLightingBuffer = builder.CreateTransientTexture(new TextureDesc(1, 1, true, true) { colorFormat = GraphicsFormat.B10G11R11_UFloatPack32, enableRandomWrite = true } );
}
passData.depthBuffer = builder.ReadTexture(depthStencilBuffer);
passData.depthTexture = builder.ReadTexture(depthPyramidTexture);
@@ -274,7 +274,7 @@ LightingOutput RenderDeferredLighting( RenderGraph renderGraph,
resources.tileListBuffer = context.resources.GetComputeBuffer(data.tileListBuffer);
resources.dispatchIndirectBuffer = context.resources.GetComputeBuffer(data.dispatchIndirectBuffer);
- // RENDERGRAPH TODO: try to find a better way to bind this.
+ // TODO RENDERGRAPH: try to find a better way to bind this.
// Issue is that some GBuffers have several names (for example normal buffer is both NormalBuffer and GBuffer1)
// So it's not possible to use auto binding via dependency to shaderTagID
// Should probably get rid of auto binding and go explicit all the way (might need to wait for us to remove non rendergraph code path).
@@ -362,8 +362,8 @@ TextureHandle RenderSSR( RenderGraph renderGraph,
// In practice, these textures are sparse (mostly black). Therefore, clearing them is fast (due to CMASK),
// and much faster than fully overwriting them from within SSR shaders.
- passData.hitPointsTexture = builder.WriteTexture(renderGraph.CreateTexture(new TextureDesc(Vector2.one, true, true)
- { colorFormat = GraphicsFormat.R16G16_UNorm, clearBuffer = true, clearColor = Color.clear, enableRandomWrite = true, name = "SSR_Hit_Point_Texture" }));
+ passData.hitPointsTexture = builder.CreateTransientTexture(new TextureDesc(Vector2.one, true, true)
+ { colorFormat = GraphicsFormat.R16G16_UNorm, clearBuffer = true, clearColor = Color.clear, enableRandomWrite = true, name = "SSR_Hit_Point_Texture" });
passData.lightingTexture = builder.WriteTexture(renderGraph.CreateTexture(new TextureDesc(Vector2.one, true, true)
{ colorFormat = GraphicsFormat.R16G16B16A16_SFloat, clearBuffer = true, clearColor = Color.clear, enableRandomWrite = true, name = "SSR_Lighting_Texture" }, HDShaderIDs._SsrLightingTexture));
//passData.hitPointsTexture = builder.WriteTexture(renderGraph.CreateTexture(new TextureDesc(Vector2.one, true, true)
diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.Prepass.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.Prepass.cs
index ffb4c42da01..c6bafbc3155 100644
--- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.Prepass.cs
+++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.Prepass.cs
@@ -492,7 +492,7 @@ class ResolveStencilPassData
public BuildCoarseStencilAndResolveParameters parameters;
public TextureHandle inputDepth;
public TextureHandle resolvedStencil;
- public ComputeBuffer coarseStencilBuffer;
+ public ComputeBufferHandle coarseStencilBuffer;
}
void BuildCoarseStencilAndResolveIfNeeded(RenderGraph renderGraph, HDCamera hdCamera, ref PrepassOutput output)
@@ -501,8 +501,9 @@ void BuildCoarseStencilAndResolveIfNeeded(RenderGraph renderGraph, HDCamera hdCa
{
passData.parameters = PrepareBuildCoarseStencilParameters(hdCamera);
passData.inputDepth = output.depthBuffer;
- passData.coarseStencilBuffer = m_SharedRTManager.GetCoarseStencilBuffer();
- passData.resolvedStencil = builder.WriteTexture(renderGraph.CreateTexture(new TextureDesc(Vector2.one, true, true) { colorFormat = GraphicsFormat.R8G8_UInt, enableRandomWrite = true, name = "StencilBufferResolved" }));
+ passData.coarseStencilBuffer = builder.WriteComputeBuffer(renderGraph.ImportComputeBuffer(m_SharedRTManager.GetCoarseStencilBuffer()));
+ if (passData.parameters.resolveIsNecessary)
+ passData.resolvedStencil = builder.WriteTexture(renderGraph.CreateTexture(new TextureDesc(Vector2.one, true, true) { colorFormat = GraphicsFormat.R8G8_UInt, enableRandomWrite = true, name = "StencilBufferResolved" }));
builder.SetRenderFunc(
(ResolveStencilPassData data, RenderGraphContext context) =>
{
@@ -510,7 +511,7 @@ void BuildCoarseStencilAndResolveIfNeeded(RenderGraph renderGraph, HDCamera hdCa
BuildCoarseStencilAndResolveIfNeeded(data.parameters,
res.GetTexture(data.inputDepth),
res.GetTexture(data.resolvedStencil),
- data.coarseStencilBuffer,
+ res.GetComputeBuffer(data.coarseStencilBuffer),
context.cmd);
}
);
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 74384efdf78..2c0c9a1b3fd 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
@@ -211,14 +211,14 @@ void ExecuteWithRenderGraph( RenderRequest renderRequest,
hdCamera.ExecuteCaptureActions(m_RenderGraph, colorBuffer);
postProcessDest = RenderDebug( m_RenderGraph,
- hdCamera,
+ hdCamera,
postProcessDest,
- prepassOutput.depthBuffer,
- prepassOutput.depthPyramidTexture,
- m_DebugFullScreenTexture,
- colorPickerTexture,
- shadowResult,
- cullingResults);
+ prepassOutput.depthBuffer,
+ prepassOutput.depthPyramidTexture,
+ m_DebugFullScreenTexture,
+ colorPickerTexture,
+ shadowResult,
+ cullingResults);
BlitFinalCameraTexture(m_RenderGraph, hdCamera, postProcessDest, backBuffer, prepassOutput.resolvedMotionVectorsBuffer, prepassOutput.resolvedNormalBuffer);
@@ -459,10 +459,12 @@ void RenderForwardTransparent( RenderGraph renderGraph,
bool renderMotionVecForTransparent = NeedMotionVectorForTransparent(hdCamera.frameSettings);
- TextureHandle mrt1;
+ passData.renderTargetCount = 2;
+ passData.renderTarget[0] = builder.WriteTexture(colorBuffer);
+
if (renderMotionVecForTransparent)
{
- mrt1 = motionVectorBuffer;
+ passData.renderTarget[1] = builder.WriteTexture(motionVectorBuffer);
// TODO RENDERGRAPH
// WORKAROUND VELOCITY-MSAA
// This is a workaround for velocity with MSAA. Currently motion vector resolve is not implemented with MSAA
@@ -475,13 +477,9 @@ void RenderForwardTransparent( RenderGraph renderGraph,
// It doesn't really matter what gets bound here since the color mask state set will prevent this from ever being written to. However, we still need to bind something
// to avoid warnings about unbound render targets. The following rendertarget could really be anything if renderVelocitiesForTransparent
// Create a new target here should reuse existing already released one
- mrt1 = renderGraph.CreateTexture(new TextureDesc(Vector2.one, true, true) { colorFormat = GraphicsFormat.R8G8B8A8_SRGB, name = "Transparency Velocity Dummy" });
+ passData.renderTarget[1] = builder.CreateTransientTexture(new TextureDesc(Vector2.one, true, true) { colorFormat = GraphicsFormat.R8G8B8A8_SRGB, name = "Transparency Velocity Dummy" });
}
- passData.renderTargetCount = 2;
- passData.renderTarget[0] = builder.WriteTexture(colorBuffer);
- passData.renderTarget[1] = builder.WriteTexture(mrt1);
-
if (colorPyramid != null && hdCamera.frameSettings.IsEnabled(FrameSettingsField.Refraction) && !preRefractionPass)
{
builder.ReadTexture(colorPyramid.Value);
@@ -783,16 +781,16 @@ void RenderForwardError(RenderGraph renderGraph,
class RenderSkyPassData
{
- public VisualEnvironment visualEnvironment;
- public Light sunLight;
- public HDCamera hdCamera;
+ public VisualEnvironment visualEnvironment;
+ public Light sunLight;
+ public HDCamera hdCamera;
public TextureHandle volumetricLighting;
public TextureHandle colorBuffer;
public TextureHandle depthStencilBuffer;
public TextureHandle intermediateBuffer;
- public DebugDisplaySettings debugDisplaySettings;
- public SkyManager skyManager;
- public int frameCount;
+ public DebugDisplaySettings debugDisplaySettings;
+ public SkyManager skyManager;
+ public int frameCount;
}
void RenderSky(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle colorBuffer, TextureHandle volumetricLighting, TextureHandle depthStencilBuffer, TextureHandle depthTexture)
@@ -810,7 +808,7 @@ void RenderSky(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle colorBu
passData.volumetricLighting = builder.ReadTexture(volumetricLighting);
passData.colorBuffer = builder.WriteTexture(colorBuffer);
passData.depthStencilBuffer = builder.WriteTexture(depthStencilBuffer);
- passData.intermediateBuffer = builder.WriteTexture(renderGraph.CreateTexture(colorBuffer));
+ passData.intermediateBuffer = builder.CreateTransientTexture(colorBuffer);
passData.debugDisplaySettings = m_CurrentDebugDisplaySettings;
passData.skyManager = m_SkyManager;
passData.frameCount = m_FrameCount;
@@ -928,8 +926,8 @@ class RenderDistortionPassData
public Vector4 size;
}
- void RenderDistortion( RenderGraph renderGraph,
- HDCamera hdCamera,
+ void RenderDistortion( RenderGraph renderGraph,
+ HDCamera hdCamera,
TextureHandle colorBuffer,
TextureHandle depthStencilBuffer,
TextureHandle colorPyramidBuffer,
diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.SubsurfaceScattering.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.SubsurfaceScattering.cs
index 1830c6829c9..1204288ec02 100644
--- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.SubsurfaceScattering.cs
+++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.SubsurfaceScattering.cs
@@ -53,9 +53,9 @@ void RenderSubsurfaceScattering(RenderGraph renderGraph, HDCamera hdCamera, Text
passData.sssBuffer = builder.ReadTexture(lightingBuffers.sssBuffer);
if (passData.parameters.needTemporaryBuffer)
{
- passData.cameraFilteringBuffer = builder.WriteTexture(renderGraph.CreateTexture(
+ passData.cameraFilteringBuffer = builder.CreateTransientTexture(
new TextureDesc(Vector2.one, true, true)
- { colorFormat = GraphicsFormat.B10G11R11_UFloatPack32, enableRandomWrite = true, clearBuffer = true, clearColor = Color.clear, name = "SSSCameraFiltering" }));
+ { colorFormat = GraphicsFormat.B10G11R11_UFloatPack32, enableRandomWrite = true, clearBuffer = true, clearColor = Color.clear, name = "SSSCameraFiltering" });
}
builder.SetRenderFunc(
diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs
index 9c3b4df7b05..82f45408e04 100644
--- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs
+++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs
@@ -1267,8 +1267,10 @@ void CopyDepthBufferIfNeeded(HDCamera hdCamera, CommandBuffer cmd)
struct BuildCoarseStencilAndResolveParameters
{
- public HDCamera hdCamera;
- public ComputeShader resolveStencilCS;
+ public HDCamera hdCamera;
+ public ComputeShader resolveStencilCS;
+ public int resolveKernel;
+ public bool resolveIsNecessary;
}
BuildCoarseStencilAndResolveParameters PrepareBuildCoarseStencilParameters(HDCamera hdCamera)
@@ -1276,6 +1278,19 @@ BuildCoarseStencilAndResolveParameters PrepareBuildCoarseStencilParameters(HDCam
var parameters = new BuildCoarseStencilAndResolveParameters();
parameters.hdCamera = hdCamera;
parameters.resolveStencilCS = defaultResources.shaders.resolveStencilCS;
+
+ bool MSAAEnabled = hdCamera.frameSettings.IsEnabled(FrameSettingsField.MSAA);
+
+ // The following features require a copy of the stencil, if none are active, no need to do the resolve.
+ bool resolveIsNecessary = GetFeatureVariantsEnabled(hdCamera.frameSettings);
+ resolveIsNecessary = resolveIsNecessary || hdCamera.IsSSREnabled()
+ || hdCamera.IsTransparentSSREnabled();
+ // We need the resolve only with msaa
+ parameters.resolveIsNecessary = resolveIsNecessary && MSAAEnabled;
+
+ int kernel = SampleCountToPassIndex(MSAAEnabled ? hdCamera.msaaSamples : MSAASamples.None);
+ parameters.resolveKernel = parameters.resolveIsNecessary ? kernel + 3 : kernel; // We have a different variant if we need to resolve to non-MSAA stencil
+
return parameters;
}
@@ -1293,31 +1308,18 @@ static void BuildCoarseStencilAndResolveIfNeeded(BuildCoarseStencilAndResolvePar
{
using (new ProfilingScope(cmd, ProfilingSampler.Get(HDProfileId.CoarseStencilGeneration)))
{
- var hdCamera = parameters.hdCamera;
- bool MSAAEnabled = hdCamera.frameSettings.IsEnabled(FrameSettingsField.MSAA);
-
- // The following features require a copy of the stencil, if none are active, no need to do the resolve.
- bool resolveIsNecessary = GetFeatureVariantsEnabled(hdCamera.frameSettings);
- resolveIsNecessary = resolveIsNecessary || hdCamera.IsSSREnabled()
- || hdCamera.IsTransparentSSREnabled();
-
- // We need the resolve only with msaa
- resolveIsNecessary = resolveIsNecessary && MSAAEnabled;
-
ComputeShader cs = parameters.resolveStencilCS;
- int kernel = SampleCountToPassIndex(MSAAEnabled ? hdCamera.msaaSamples : MSAASamples.None);
- kernel = resolveIsNecessary ? kernel + 3 : kernel; // We have a different variant if we need to resolve to non-MSAA stencil
- cmd.SetComputeBufferParam(cs, kernel, HDShaderIDs._CoarseStencilBuffer, coarseStencilBuffer);
- cmd.SetComputeTextureParam(cs, kernel, HDShaderIDs._StencilTexture, depthStencilBuffer, 0, RenderTextureSubElement.Stencil);
+ cmd.SetComputeBufferParam(cs, parameters.resolveKernel, HDShaderIDs._CoarseStencilBuffer, coarseStencilBuffer);
+ cmd.SetComputeTextureParam(cs, parameters.resolveKernel, HDShaderIDs._StencilTexture, depthStencilBuffer, 0, RenderTextureSubElement.Stencil);
- if (resolveIsNecessary)
+ if (parameters.resolveIsNecessary)
{
- cmd.SetComputeTextureParam(cs, kernel, HDShaderIDs._OutputStencilBuffer, resolvedStencilBuffer);
+ cmd.SetComputeTextureParam(cs, parameters.resolveKernel, HDShaderIDs._OutputStencilBuffer, resolvedStencilBuffer);
}
- int coarseStencilWidth = HDUtils.DivRoundUp(hdCamera.actualWidth, 8);
- int coarseStencilHeight = HDUtils.DivRoundUp(hdCamera.actualHeight, 8);
- cmd.DispatchCompute(cs, kernel, coarseStencilWidth, coarseStencilHeight, hdCamera.viewCount);
+ int coarseStencilWidth = HDUtils.DivRoundUp(parameters.hdCamera.actualWidth, 8);
+ int coarseStencilHeight = HDUtils.DivRoundUp(parameters.hdCamera.actualHeight, 8);
+ cmd.DispatchCompute(cs, parameters.resolveKernel, coarseStencilWidth, coarseStencilHeight, parameters.hdCamera.viewCount);
}
}
diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Settings/FrameSettings.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Settings/FrameSettings.cs
index 1a6d9f69243..f64263a22bd 100644
--- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Settings/FrameSettings.cs
+++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Settings/FrameSettings.cs
@@ -315,7 +315,7 @@ public enum FrameSettingsField
[FrameSettingsField(2, displayedName: "SS Ambient Occlusion", positiveDependencies: new[] { AsyncCompute }, tooltip: "When enabled, HDRP calculates screen space ambient occlusion asynchronously.")]
SSAOAsync = 43,
// TODO: Enable thing when the render graph will be the default renderer.
- // [FrameSettingsField(2, displayedName: "Contact Shadows", positiveDependencies: new[] { AsyncCompute }, tooltip: "When enabled, HDRP calculates Contact Shadows asynchronously.")]
+ //[FrameSettingsField(2, displayedName: "Contact Shadows", positiveDependencies: new[] { AsyncCompute }, tooltip: "When enabled, HDRP calculates Contact Shadows asynchronously.")]
/// When enabled, HDRP calculates Contact Shadows asynchronously.
ContactShadowsAsync = 44,
/// When enabled, HDRP calculates volumetric voxelization asynchronously.
@@ -670,7 +670,7 @@ public int GetResolvedSssSampleBudget(HDRenderPipelineAsset hdrp)
internal bool SSRRunsAsync() => SystemInfo.supportsAsyncCompute && bitDatas[(int)FrameSettingsField.AsyncCompute] && bitDatas[(int)FrameSettingsField.SSRAsync];
internal bool SSAORunsAsync() => SystemInfo.supportsAsyncCompute && bitDatas[(int)FrameSettingsField.AsyncCompute] && bitDatas[(int)FrameSettingsField.SSAOAsync];
// TODO: Re-enable this when the render graph will be used by default.
- internal bool ContactShadowsRunAsync() => SystemInfo.supportsAsyncCompute && bitDatas[(int)FrameSettingsField.AsyncCompute] && /* bitDatas[(int)FrameSettingsField.ContactShadowsAsync] */ false;
+ internal bool ContactShadowsRunAsync() => SystemInfo.supportsAsyncCompute && bitDatas[(int)FrameSettingsField.AsyncCompute] && /*bitDatas[(int)FrameSettingsField.ContactShadowsAsync]*/ false;
internal bool VolumeVoxelizationRunsAsync() => SystemInfo.supportsAsyncCompute && bitDatas[(int)FrameSettingsField.AsyncCompute] && bitDatas[(int)FrameSettingsField.VolumeVoxelizationsAsync];
/// Override a frameSettings according to a mask.