RenderGraph.cs 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506
  1. using System;
  2. using System.Collections.Generic;
  3. using UnityEngine.Rendering;
  4. using UnityEngine.Profiling;
  5. namespace UnityEngine.Experimental.Rendering.RenderGraphModule
  6. {
  7. /// <summary>
  8. /// Sets the read and write access for the depth buffer.
  9. /// </summary>
  10. [Flags]
  11. public enum DepthAccess
  12. {
  13. ///<summary>Read Access.</summary>
  14. Read = 1 << 0,
  15. ///<summary>Write Access.</summary>
  16. Write = 1 << 1,
  17. ///<summary>Read and Write Access.</summary>
  18. ReadWrite = Read | Write,
  19. }
  20. /// <summary>
  21. /// This struct specifies the context given to every render pass.
  22. /// </summary>
  23. public ref struct RenderGraphContext
  24. {
  25. ///<summary>Scriptable Render Context used for rendering.</summary>
  26. public ScriptableRenderContext renderContext;
  27. ///<summary>Command Buffer used for rendering.</summary>
  28. public CommandBuffer cmd;
  29. ///<summary>Render Graph pooll used for temporary data.</summary>
  30. public RenderGraphObjectPool renderGraphPool;
  31. ///<summary>Render Graph Resource Registry used for accessing resources.</summary>
  32. public RenderGraphResourceRegistry resources;
  33. }
  34. /// <summary>
  35. /// This struct contains properties which control the execution of the Render Graph.
  36. /// </summary>
  37. public struct RenderGraphExecuteParams
  38. {
  39. ///<summary>Rendering width.</summary>
  40. public int renderingWidth;
  41. ///<summary>Rendering height.</summary>
  42. public int renderingHeight;
  43. ///<summary>Number of MSAA samples.</summary>
  44. public MSAASamples msaaSamples;
  45. }
  46. class RenderGraphDebugParams
  47. {
  48. public bool enableRenderGraph = false; // TODO: TEMP TO REMOVE
  49. public bool tagResourceNamesWithRG;
  50. public bool clearRenderTargetsAtCreation;
  51. public bool clearRenderTargetsAtRelease;
  52. public bool unbindGlobalTextures;
  53. public bool logFrameInformation;
  54. public bool logResources;
  55. public void RegisterDebug()
  56. {
  57. var list = new List<DebugUI.Widget>();
  58. list.Add(new DebugUI.BoolField { displayName = "Enable Render Graph", getter = () => enableRenderGraph, setter = value => enableRenderGraph = value });
  59. list.Add(new DebugUI.BoolField { displayName = "Tag Resources with RG", getter = () => tagResourceNamesWithRG, setter = value => tagResourceNamesWithRG = value });
  60. list.Add(new DebugUI.BoolField { displayName = "Clear Render Targets at creation", getter = () => clearRenderTargetsAtCreation, setter = value => clearRenderTargetsAtCreation = value });
  61. list.Add(new DebugUI.BoolField { displayName = "Clear Render Targets at release", getter = () => clearRenderTargetsAtRelease, setter = value => clearRenderTargetsAtRelease = value });
  62. list.Add(new DebugUI.BoolField { displayName = "Unbind Global Textures", getter = () => unbindGlobalTextures, setter = value => unbindGlobalTextures = value });
  63. list.Add(new DebugUI.Button { displayName = "Log Frame Information", action = () => logFrameInformation = true });
  64. list.Add(new DebugUI.Button { displayName = "Log Resources", action = () => logResources = true });
  65. var testPanel = DebugManager.instance.GetPanel("Render Graph", true);
  66. testPanel.children.Add(list.ToArray());
  67. }
  68. public void UnRegisterDebug()
  69. {
  70. DebugManager.instance.RemovePanel("Render Graph");
  71. }
  72. }
  73. /// <summary>
  74. /// The Render Pass rendering delegate.
  75. /// </summary>
  76. /// <typeparam name="PassData">The type of the class used to provide data to the Render Pass.</typeparam>
  77. /// <param name="data">Render Pass specific data.</param>
  78. /// <param name="renderGraphContext">Global Render Graph context.</param>
  79. public delegate void RenderFunc<PassData>(PassData data, RenderGraphContext renderGraphContext) where PassData : class, new();
  80. /// <summary>
  81. /// This class is the main entry point of the Render Graph system.
  82. /// </summary>
  83. public class RenderGraph
  84. {
  85. ///<summary>Maximum number of MRTs supported by Render Graph.</summary>
  86. public static readonly int kMaxMRTCount = 8;
  87. internal abstract class RenderPass
  88. {
  89. internal RenderFunc<PassData> GetExecuteDelegate<PassData>()
  90. where PassData : class, new() => ((RenderPass<PassData>)this).renderFunc;
  91. internal abstract void Execute(RenderGraphContext renderGraphContext);
  92. internal abstract void Release(RenderGraphContext renderGraphContext);
  93. internal abstract bool HasRenderFunc();
  94. internal string name;
  95. internal int index;
  96. internal ProfilingSampler customSampler;
  97. internal List<RenderGraphResource> resourceReadList = new List<RenderGraphResource>();
  98. internal List<RenderGraphMutableResource> resourceWriteList = new List<RenderGraphMutableResource>();
  99. internal List<RenderGraphResource> usedRendererListList = new List<RenderGraphResource>();
  100. internal bool enableAsyncCompute;
  101. internal RenderGraphMutableResource depthBuffer { get { return m_DepthBuffer; } }
  102. internal RenderGraphMutableResource[] colorBuffers { get { return m_ColorBuffers; } }
  103. internal int colorBufferMaxIndex { get { return m_MaxColorBufferIndex; } }
  104. protected RenderGraphMutableResource[] m_ColorBuffers = new RenderGraphMutableResource[RenderGraph.kMaxMRTCount];
  105. protected RenderGraphMutableResource m_DepthBuffer;
  106. protected int m_MaxColorBufferIndex = -1;
  107. internal void Clear()
  108. {
  109. name = "";
  110. index = -1;
  111. customSampler = null;
  112. resourceReadList.Clear();
  113. resourceWriteList.Clear();
  114. usedRendererListList.Clear();
  115. enableAsyncCompute = false;
  116. // Invalidate everything
  117. m_MaxColorBufferIndex = -1;
  118. m_DepthBuffer = new RenderGraphMutableResource();
  119. for (int i = 0; i < RenderGraph.kMaxMRTCount; ++i)
  120. {
  121. m_ColorBuffers[i] = new RenderGraphMutableResource();
  122. }
  123. }
  124. internal void SetColorBuffer(in RenderGraphMutableResource resource, int index)
  125. {
  126. Debug.Assert(index < RenderGraph.kMaxMRTCount && index >= 0);
  127. m_MaxColorBufferIndex = Math.Max(m_MaxColorBufferIndex, index);
  128. m_ColorBuffers[index] = resource;
  129. resourceWriteList.Add(resource);
  130. }
  131. internal void SetDepthBuffer(in RenderGraphMutableResource resource, DepthAccess flags)
  132. {
  133. m_DepthBuffer = resource;
  134. if ((flags | DepthAccess.Read) != 0)
  135. resourceReadList.Add(resource);
  136. if ((flags | DepthAccess.Write) != 0)
  137. resourceWriteList.Add(resource);
  138. }
  139. }
  140. internal sealed class RenderPass<PassData> : RenderPass
  141. where PassData : class, new()
  142. {
  143. internal PassData data;
  144. internal RenderFunc<PassData> renderFunc;
  145. internal override void Execute(RenderGraphContext renderGraphContext)
  146. {
  147. GetExecuteDelegate<PassData>()(data, renderGraphContext);
  148. }
  149. internal override void Release(RenderGraphContext renderGraphContext)
  150. {
  151. Clear();
  152. renderGraphContext.renderGraphPool.Release(data);
  153. data = null;
  154. renderFunc = null;
  155. renderGraphContext.renderGraphPool.Release(this);
  156. }
  157. internal override bool HasRenderFunc()
  158. {
  159. return renderFunc != null;
  160. }
  161. }
  162. RenderGraphResourceRegistry m_Resources;
  163. RenderGraphObjectPool m_RenderGraphPool = new RenderGraphObjectPool();
  164. List<RenderPass> m_RenderPasses = new List<RenderPass>();
  165. List<RenderGraphResource> m_RendererLists = new List<RenderGraphResource>();
  166. RenderGraphDebugParams m_DebugParameters = new RenderGraphDebugParams();
  167. RenderGraphLogger m_Logger = new RenderGraphLogger();
  168. #region Public Interface
  169. /// <summary>
  170. /// Returns true if rendering with Render Graph is enabled.
  171. /// </summary>
  172. public bool enabled { get { return m_DebugParameters.enableRenderGraph; } }
  173. // 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.
  174. /// <summary>
  175. /// Gets the RTHandleProperties structure associated with the Render Graph's RTHandle System.
  176. /// </summary>
  177. public RTHandleProperties rtHandleProperties { get { return m_Resources.GetRTHandleProperties(); } }
  178. /// <summary>
  179. /// Render Graph constructor.
  180. /// </summary>
  181. /// <param name="supportMSAA">Specify if this Render Graph should support MSAA.</param>
  182. /// <param name="initialSampleCount">Specify the initial sample count of MSAA render textures.</param>
  183. public RenderGraph(bool supportMSAA, MSAASamples initialSampleCount)
  184. {
  185. m_Resources = new RenderGraphResourceRegistry(supportMSAA, initialSampleCount, m_DebugParameters, m_Logger);
  186. }
  187. /// <summary>
  188. /// Cleanup the Render Graph.
  189. /// </summary>
  190. public void Cleanup()
  191. {
  192. m_Resources.Cleanup();
  193. }
  194. /// <summary>
  195. /// Register this Render Graph to the debug window.
  196. /// </summary>
  197. public void RegisterDebug()
  198. {
  199. //m_DebugParameters.RegisterDebug();
  200. }
  201. /// <summary>
  202. /// Unregister this Render Graph from the debug window.
  203. /// </summary>
  204. public void UnRegisterDebug()
  205. {
  206. //m_DebugParameters.UnRegisterDebug();
  207. }
  208. /// <summary>
  209. /// Import an external texture to the Render Graph.
  210. /// </summary>
  211. /// <param name="rt">External RTHandle that needs to be imported.</param>
  212. /// <param name="shaderProperty">Optional property that allows you to specify a Shader property name to use for automatic resource binding.</param>
  213. /// <returns>A new RenderGraphMutableResource.</returns>
  214. public RenderGraphMutableResource ImportTexture(RTHandle rt, int shaderProperty = 0)
  215. {
  216. return m_Resources.ImportTexture(rt, shaderProperty);
  217. }
  218. /// <summary>
  219. /// Create a new Render Graph Texture resource.
  220. /// </summary>
  221. /// <param name="desc">Texture descriptor.</param>
  222. /// <param name="shaderProperty">Optional property that allows you to specify a Shader property name to use for automatic resource binding.</param>
  223. /// <returns>A new RenderGraphMutableResource.</returns>
  224. public RenderGraphMutableResource CreateTexture(TextureDesc desc, int shaderProperty = 0)
  225. {
  226. if (m_DebugParameters.tagResourceNamesWithRG)
  227. desc.name = string.Format("{0}_RenderGraph", desc.name);
  228. return m_Resources.CreateTexture(desc, shaderProperty);
  229. }
  230. /// <summary>
  231. /// Create a new Render Graph Texture resource using the descriptor from another texture.
  232. /// </summary>
  233. /// <param name="texture">Texture from which the descriptor should be used.</param>
  234. /// <param name="shaderProperty">Optional property that allows you to specify a Shader property name to use for automatic resource binding.</param>
  235. /// <returns>A new RenderGraphMutableResource.</returns>
  236. public RenderGraphMutableResource CreateTexture(in RenderGraphResource texture, int shaderProperty = 0)
  237. {
  238. var desc = m_Resources.GetTextureResourceDesc(texture);
  239. if (m_DebugParameters.tagResourceNamesWithRG)
  240. desc.name = string.Format("{0}_RenderGraph", desc.name);
  241. return m_Resources.CreateTexture(desc, shaderProperty);
  242. }
  243. /// <summary>
  244. /// Gets the descriptor of the specified Texture resource.
  245. /// </summary>
  246. /// <param name="texture"></param>
  247. /// <returns>The input texture descriptor.</returns>
  248. public TextureDesc GetTextureDesc(in RenderGraphResource texture)
  249. {
  250. if (texture.type != RenderGraphResourceType.Texture)
  251. {
  252. throw new ArgumentException("Trying to retrieve a TextureDesc from a resource that is not a texture.");
  253. }
  254. return m_Resources.GetTextureResourceDesc(texture);
  255. }
  256. /// <summary>
  257. /// Creates a new Renderer List Render Graph resource.
  258. /// </summary>
  259. /// <param name="desc">Renderer List descriptor.</param>
  260. /// <returns>A new RenderGraphResource.</returns>
  261. public RenderGraphResource CreateRendererList(in RendererListDesc desc)
  262. {
  263. return m_Resources.CreateRendererList(desc);
  264. }
  265. /// <summary>
  266. /// Add a new Render Pass to the current Render Graph.
  267. /// </summary>
  268. /// <typeparam name="PassData">Type of the class to use to provide data to the Render Pass.</typeparam>
  269. /// <param name="passName">Name of the new Render Pass (this is also be used to generate a GPU profiling marker).</param>
  270. /// <param name="passData">Instance of PassData that is passed to the render function and you must fill.</param>
  271. /// <param name="sampler">Optional profiling sampler.</param>
  272. /// <returns>A new instance of a RenderGraphBuilder used to setup the new Render Pass.</returns>
  273. public RenderGraphBuilder AddRenderPass<PassData>(string passName, out PassData passData, ProfilingSampler sampler = null) where PassData : class, new()
  274. {
  275. var renderPass = m_RenderGraphPool.Get<RenderPass<PassData>>();
  276. renderPass.Clear();
  277. renderPass.index = m_RenderPasses.Count;
  278. renderPass.data = m_RenderGraphPool.Get<PassData>();
  279. renderPass.name = passName;
  280. renderPass.customSampler = sampler;
  281. passData = renderPass.data;
  282. m_RenderPasses.Add(renderPass);
  283. return new RenderGraphBuilder(renderPass, m_Resources);
  284. }
  285. /// <summary>
  286. /// Execute the Render Graph in its current state.
  287. /// </summary>
  288. /// <param name="renderContext">ScriptableRenderContext used to execute Scriptable Render Pipeline.</param>
  289. /// <param name="cmd">Command Buffer used for Render Passes rendering.</param>
  290. /// <param name="parameters">Render Graph execution parameters.</param>
  291. public void Execute(ScriptableRenderContext renderContext, CommandBuffer cmd, in RenderGraphExecuteParams parameters)
  292. {
  293. m_Logger.Initialize();
  294. // Update RTHandleSystem with size for this rendering pass.
  295. m_Resources.SetRTHandleReferenceSize(parameters.renderingWidth, parameters.renderingHeight, parameters.msaaSamples);
  296. LogFrameInformation(parameters.renderingWidth, parameters.renderingHeight);
  297. // First pass, traversal and pruning
  298. for (int passIndex = 0; passIndex < m_RenderPasses.Count; ++passIndex)
  299. {
  300. var pass = m_RenderPasses[passIndex];
  301. // TODO: Pruning
  302. // Gather all renderer lists
  303. m_RendererLists.AddRange(pass.usedRendererListList);
  304. }
  305. // Creates all renderer lists
  306. m_Resources.CreateRendererLists(m_RendererLists);
  307. LogRendererListsCreation();
  308. // Second pass, execution
  309. RenderGraphContext rgContext = new RenderGraphContext();
  310. rgContext.cmd = cmd;
  311. rgContext.renderContext = renderContext;
  312. rgContext.renderGraphPool = m_RenderGraphPool;
  313. rgContext.resources = m_Resources;
  314. try
  315. {
  316. for (int passIndex = 0; passIndex < m_RenderPasses.Count; ++passIndex)
  317. {
  318. var pass = m_RenderPasses[passIndex];
  319. if (!pass.HasRenderFunc())
  320. {
  321. throw new InvalidOperationException(string.Format("RenderPass {0} was not provided with an execute function.", pass.name));
  322. }
  323. using (new ProfilingScope(cmd, pass.customSampler))
  324. {
  325. LogRenderPassBegin(pass);
  326. using (new RenderGraphLogIndent(m_Logger))
  327. {
  328. PreRenderPassExecute(passIndex, pass, rgContext);
  329. pass.Execute(rgContext);
  330. PostRenderPassExecute(passIndex, pass, rgContext);
  331. }
  332. }
  333. }
  334. }
  335. catch(Exception e)
  336. {
  337. Debug.LogError("Render Graph Execution error");
  338. Debug.LogException(e);
  339. }
  340. finally
  341. {
  342. ClearRenderPasses();
  343. m_Resources.Clear();
  344. m_RendererLists.Clear();
  345. if (m_DebugParameters.logFrameInformation || m_DebugParameters.logResources)
  346. Debug.Log(m_Logger.GetLog());
  347. m_DebugParameters.logFrameInformation = false;
  348. m_DebugParameters.logResources = false;
  349. }
  350. }
  351. #endregion
  352. #region Internal Interface
  353. private RenderGraph()
  354. {
  355. }
  356. void PreRenderPassSetRenderTargets(in RenderPass pass, RenderGraphContext rgContext)
  357. {
  358. if (pass.depthBuffer.IsValid() || pass.colorBufferMaxIndex != -1)
  359. {
  360. var mrtArray = rgContext.renderGraphPool.GetTempArray<RenderTargetIdentifier>(pass.colorBufferMaxIndex + 1);
  361. var colorBuffers = pass.colorBuffers;
  362. if (pass.colorBufferMaxIndex > 0)
  363. {
  364. for (int i = 0; i <= pass.colorBufferMaxIndex; ++i)
  365. {
  366. if (!colorBuffers[i].IsValid())
  367. throw new InvalidOperationException("MRT setup is invalid. Some indices are not used.");
  368. mrtArray[i] = m_Resources.GetTexture(colorBuffers[i]);
  369. }
  370. if (pass.depthBuffer.IsValid())
  371. {
  372. CoreUtils.SetRenderTarget(rgContext.cmd, mrtArray, m_Resources.GetTexture(pass.depthBuffer));
  373. }
  374. else
  375. {
  376. throw new InvalidOperationException("Setting MRTs without a depth buffer is not supported.");
  377. }
  378. }
  379. else
  380. {
  381. if (pass.depthBuffer.IsValid())
  382. {
  383. if (pass.colorBufferMaxIndex > -1)
  384. CoreUtils.SetRenderTarget(rgContext.cmd, m_Resources.GetTexture(pass.colorBuffers[0]), m_Resources.GetTexture(pass.depthBuffer));
  385. else
  386. CoreUtils.SetRenderTarget(rgContext.cmd, m_Resources.GetTexture(pass.depthBuffer));
  387. }
  388. else
  389. {
  390. CoreUtils.SetRenderTarget(rgContext.cmd, m_Resources.GetTexture(pass.colorBuffers[0]));
  391. }
  392. }
  393. }
  394. }
  395. void PreRenderPassExecute(int passIndex, in RenderPass pass, RenderGraphContext rgContext)
  396. {
  397. // TODO merge clear and setup here if possible
  398. m_Resources.CreateAndClearTexturesForPass(rgContext, pass.index, pass.resourceWriteList);
  399. PreRenderPassSetRenderTargets(pass, rgContext);
  400. m_Resources.PreRenderPassSetGlobalTextures(rgContext, pass.resourceReadList);
  401. }
  402. void PostRenderPassExecute(int passIndex, in RenderPass pass, RenderGraphContext rgContext)
  403. {
  404. if (m_DebugParameters.unbindGlobalTextures)
  405. m_Resources.PostRenderPassUnbindGlobalTextures(rgContext, pass.resourceReadList);
  406. m_RenderGraphPool.ReleaseAllTempAlloc();
  407. m_Resources.ReleaseTexturesForPass(rgContext, pass.index, pass.resourceReadList, pass.resourceWriteList);
  408. pass.Release(rgContext);
  409. }
  410. void ClearRenderPasses()
  411. {
  412. m_RenderPasses.Clear();
  413. }
  414. void LogFrameInformation(int renderingWidth, int renderingHeight)
  415. {
  416. if (m_DebugParameters.logFrameInformation)
  417. {
  418. m_Logger.LogLine("==== Staring frame at resolution ({0}x{1}) ====", renderingWidth, renderingHeight);
  419. m_Logger.LogLine("Number of passes declared: {0}", m_RenderPasses.Count);
  420. }
  421. }
  422. void LogRendererListsCreation()
  423. {
  424. if (m_DebugParameters.logFrameInformation)
  425. {
  426. m_Logger.LogLine("Number of renderer lists created: {0}", m_RendererLists.Count);
  427. }
  428. }
  429. void LogRenderPassBegin(in RenderPass pass)
  430. {
  431. if (m_DebugParameters.logFrameInformation)
  432. {
  433. m_Logger.LogLine("Executing pass \"{0}\" (index: {1})", pass.name, pass.index);
  434. }
  435. }
  436. #endregion
  437. }
  438. }