暫無描述
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

RenderGraph.cs 126KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using System.Runtime.CompilerServices;
  5. using UnityEngine.Experimental.Rendering;
  6. using UnityEngine.Scripting.APIUpdating;
  7. // Typedef for the in-engine RendererList API (to avoid conflicts with the experimental version)
  8. using CoreRendererListDesc = UnityEngine.Rendering.RendererUtils.RendererListDesc;
  9. namespace UnityEngine.Rendering.RenderGraphModule
  10. {
  11. /// <summary>
  12. /// Sets the read and write access for the depth buffer.
  13. /// </summary>
  14. [Flags][MovedFrom(true, "UnityEngine.Experimental.Rendering.RenderGraphModule", "UnityEngine.Rendering.RenderGraphModule")]
  15. public enum DepthAccess
  16. {
  17. ///<summary>Read Access.</summary>
  18. Read = 1 << 0,
  19. ///<summary>Write Access.</summary>
  20. Write = 1 << 1,
  21. ///<summary>Read and Write Access.</summary>
  22. ReadWrite = Read | Write,
  23. }
  24. /// <summary>
  25. /// Express the operations the rendergraph pass will do on a resource.
  26. /// </summary>
  27. [Flags][MovedFrom(true, "UnityEngine.Experimental.Rendering.RenderGraphModule", "UnityEngine.Rendering.RenderGraphModule")]
  28. public enum AccessFlags
  29. {
  30. ///<summary>The pass does not access the resource at all. Calling Use* functions with none has no effect.</summary>
  31. None = 0,
  32. ///<summary>This pass will read data the resource. Data in the resource should never be written unless one of the write flags is also present. Writing to a read-only resource may lead to undefined results, significant performance penaties, and GPU crashes.</summary>
  33. Read = 1 << 0,
  34. ///<summary>This pass will at least write some data to the resource. Data in the resource should never be read unless one of the read flags is also present. Reading from a write-only resource may lead to undefined results, significant performance penaties, and GPU crashes.</summary>
  35. Write = 1 << 1,
  36. ///<summary>Previous data in the resource is not preserved. The resource will contain undefined data at the beginning of the pass.</summary>
  37. Discard = 1 << 2,
  38. ///<summary>All data in the resource will be written by this pass. Data in the resource should never be read.</summary>
  39. WriteAll = Write | Discard,
  40. ///<summary> Shortcut for Read | Write</summary>
  41. ReadWrite = Read | Write
  42. }
  43. /// <summary>
  44. /// An object representing the internal context of a rendergraph pass execution.
  45. /// This object is public for technical reasons only and should not be used.
  46. /// </summary>
  47. [MovedFrom(true, "UnityEngine.Experimental.Rendering.RenderGraphModule", "UnityEngine.Rendering.RenderGraphModule")]
  48. public class InternalRenderGraphContext
  49. {
  50. internal ScriptableRenderContext renderContext;
  51. internal CommandBuffer cmd;
  52. internal RenderGraphObjectPool renderGraphPool;
  53. internal RenderGraphDefaultResources defaultResources;
  54. internal RenderGraphPass executingPass;
  55. internal bool contextlessTesting;
  56. }
  57. // This whole thing is a bit of a mess InternalRenderGraphContext is public (but all members are internal)
  58. // just because the C# standard says that all interface member function implementations should be public.
  59. // So below in for example the RasterGraphContext we can't implement the (internal) interface as
  60. // internal void FromInternalContext(InternalRenderGraphContext context) { ... }
  61. // So we have to make FromInternalContext public so InternalRenderGraphContext also becomes public.
  62. // This seems an oversight in c# where Interfaces used as Generic constraints could very well be useful
  63. // with internal only functions.
  64. internal interface IDerivedRendergraphContext
  65. {
  66. /// <summary>
  67. /// This function is only public for techical resons of the c# language and should not be called outside the package.
  68. /// </summary>
  69. /// <param name="context">The context to convert</param>
  70. public void FromInternalContext(InternalRenderGraphContext context);
  71. }
  72. /// <summary>
  73. /// This class specifies the context given to every render pass. This context type passes a generic
  74. /// command buffer that can be used to schedule all commands. This will eventually be deprecated
  75. /// in favor of more specific contexts that have more specific command buffer types.
  76. /// </summary>
  77. [MovedFrom(true, "UnityEngine.Experimental.Rendering.RenderGraphModule", "UnityEngine.Rendering.RenderGraphModule")]
  78. public struct RenderGraphContext : IDerivedRendergraphContext
  79. {
  80. private InternalRenderGraphContext wrappedContext;
  81. /// <inheritdoc />
  82. public void FromInternalContext(InternalRenderGraphContext context)
  83. {
  84. wrappedContext = context;
  85. }
  86. ///<summary>Scriptable Render Context used for rendering.</summary>
  87. public ScriptableRenderContext renderContext { get => wrappedContext.renderContext; }
  88. ///<summary>Command Buffer used for rendering.</summary>
  89. public CommandBuffer cmd { get => wrappedContext.cmd; }
  90. ///<summary>Render Graph pool used for temporary data.</summary>
  91. public RenderGraphObjectPool renderGraphPool { get => wrappedContext.renderGraphPool; }
  92. ///<summary>Render Graph default resources.</summary>
  93. public RenderGraphDefaultResources defaultResources { get => wrappedContext.defaultResources; }
  94. }
  95. /// <summary>
  96. /// This class declares the context object passed to the execute function of a raster render pass.
  97. /// <see cref="RenderGraph.AddRasterRenderPass"/>
  98. /// </summary>
  99. [MovedFrom(true, "UnityEngine.Experimental.Rendering.RenderGraphModule", "UnityEngine.Rendering.RenderGraphModule")]
  100. public struct RasterGraphContext : IDerivedRendergraphContext
  101. {
  102. private InternalRenderGraphContext wrappedContext;
  103. ///<summary>Command Buffer used for rendering.</summary>
  104. public RasterCommandBuffer cmd;
  105. ///<summary>Render Graph default resources.</summary>
  106. public RenderGraphDefaultResources defaultResources { get => wrappedContext.defaultResources; }
  107. ///<summary>Render Graph pool used for temporary data.</summary>
  108. public RenderGraphObjectPool renderGraphPool { get => wrappedContext.renderGraphPool; }
  109. static internal RasterCommandBuffer rastercmd = new RasterCommandBuffer(null, null, false);
  110. /// <inheritdoc />
  111. public void FromInternalContext(InternalRenderGraphContext context)
  112. {
  113. wrappedContext = context;
  114. rastercmd.m_WrappedCommandBuffer = wrappedContext.cmd;
  115. rastercmd.m_ExecutingPass = context.executingPass;
  116. cmd = rastercmd;
  117. }
  118. }
  119. /// <summary>
  120. /// This class declares the context object passed to the execute function of a compute render pass.
  121. /// <see cref="RenderGraph.AddComputePass"/>
  122. /// </summary>
  123. [MovedFrom(true, "UnityEngine.Experimental.Rendering.RenderGraphModule", "UnityEngine.Rendering.RenderGraphModule")]
  124. public class ComputeGraphContext : IDerivedRendergraphContext
  125. {
  126. private InternalRenderGraphContext wrappedContext;
  127. ///<summary>Command Buffer used for rendering.</summary>
  128. public ComputeCommandBuffer cmd;
  129. ///<summary>Render Graph default resources.</summary>
  130. public RenderGraphDefaultResources defaultResources { get => wrappedContext.defaultResources; }
  131. ///<summary>Render Graph pool used for temporary data.</summary>
  132. public RenderGraphObjectPool renderGraphPool { get => wrappedContext.renderGraphPool; }
  133. static internal ComputeCommandBuffer computecmd = new ComputeCommandBuffer(null, null, false);
  134. /// <inheritdoc />
  135. public void FromInternalContext(InternalRenderGraphContext context)
  136. {
  137. wrappedContext = context;
  138. computecmd.m_WrappedCommandBuffer = wrappedContext.cmd;
  139. computecmd.m_ExecutingPass = context.executingPass;
  140. cmd = computecmd;
  141. }
  142. }
  143. /// <summary>
  144. /// This class declares the context object passed to the execute function of an unsafe render pass.
  145. /// <see cref="RenderGraph.AddUnsafePass"/>
  146. /// </summary>
  147. [MovedFrom(true, "UnityEngine.Experimental.Rendering.RenderGraphModule", "UnityEngine.Rendering.RenderGraphModule")]
  148. public class UnsafeGraphContext : IDerivedRendergraphContext
  149. {
  150. private InternalRenderGraphContext wrappedContext;
  151. ///<summary>Unsafe Command Buffer used for rendering.</summary>
  152. public UnsafeCommandBuffer cmd;
  153. ///<summary>Render Graph default resources.</summary>
  154. public RenderGraphDefaultResources defaultResources { get => wrappedContext.defaultResources; }
  155. ///<summary>Render Graph pool used for temporary data.</summary>
  156. public RenderGraphObjectPool renderGraphPool { get => wrappedContext.renderGraphPool; }
  157. internal static UnsafeCommandBuffer unsCmd = new UnsafeCommandBuffer(null, null, false);
  158. /// <inheritdoc />
  159. public void FromInternalContext(InternalRenderGraphContext context)
  160. {
  161. wrappedContext = context;
  162. unsCmd.m_WrappedCommandBuffer = wrappedContext.cmd;
  163. unsCmd.m_ExecutingPass = context.executingPass;
  164. cmd = unsCmd;
  165. }
  166. }
  167. /// <summary>
  168. /// This struct contains properties which control the execution of the Render Graph.
  169. /// </summary>
  170. [MovedFrom(true, "UnityEngine.Experimental.Rendering.RenderGraphModule", "UnityEngine.Rendering.RenderGraphModule")]
  171. public struct RenderGraphParameters
  172. {
  173. ///<summary>Identifier for this render graph execution.</summary>
  174. public string executionName;
  175. ///<summary>Index of the current frame being rendered.</summary>
  176. public int currentFrameIndex;
  177. ///<summary> Controls whether to enable Renderer List culling or not.</summary>
  178. public bool rendererListCulling;
  179. ///<summary>Scriptable Render Context used by the render pipeline.</summary>
  180. public ScriptableRenderContext scriptableRenderContext;
  181. ///<summary>Command Buffer used to execute graphic commands.</summary>
  182. public CommandBuffer commandBuffer;
  183. ///<summary>When running tests indicate the context is intentionally invalid and all calls on it should just do nothing.
  184. ///This allows you to run tests that rely on code execution the way to the pass render functions
  185. ///This also changes some behaviours with exception handling and error logging so the test framework can act on exceptions to validate behaviour better.</summary>
  186. internal bool invalidContextForTesting;
  187. }
  188. /// <summary>
  189. /// The Render Pass rendering delegate to use with typed contexts.
  190. /// </summary>
  191. /// <typeparam name="PassData">The type of the class used to provide data to the Render Pass.</typeparam>
  192. /// <typeparam name="ContextType">The type of the context that will be passed to the render function.</typeparam>
  193. /// <param name="data">Render Pass specific data.</param>
  194. /// <param name="renderGraphContext">Global Render Graph context.</param>
  195. [MovedFrom(true, "UnityEngine.Experimental.Rendering.RenderGraphModule", "UnityEngine.Rendering.RenderGraphModule")]
  196. public delegate void BaseRenderFunc<PassData, ContextType>(PassData data, ContextType renderGraphContext) where PassData : class, new();
  197. /// <summary>
  198. /// This class is the main entry point of the Render Graph system.
  199. /// </summary>
  200. [MovedFrom(true, "UnityEngine.Experimental.Rendering.RenderGraphModule", "UnityEngine.Rendering.RenderGraphModule")]
  201. public partial class RenderGraph
  202. {
  203. ///<summary>Maximum number of MRTs supported by Render Graph.</summary>
  204. public static readonly int kMaxMRTCount = 8;
  205. internal struct CompiledResourceInfo
  206. {
  207. public List<int> producers;
  208. public List<int> consumers;
  209. public int refCount;
  210. public bool imported;
  211. public void Reset()
  212. {
  213. if (producers == null)
  214. producers = new List<int>();
  215. if (consumers == null)
  216. consumers = new List<int>();
  217. producers.Clear();
  218. consumers.Clear();
  219. refCount = 0;
  220. imported = false;
  221. }
  222. }
  223. [DebuggerDisplay("RenderPass: {name} (Index:{index} Async:{enableAsyncCompute})")]
  224. internal struct CompiledPassInfo
  225. {
  226. public string name;
  227. public int index;
  228. public List<int>[] resourceCreateList;
  229. public List<int>[] resourceReleaseList;
  230. public GraphicsFence fence;
  231. #if DEVELOPMENT_BUILD || UNITY_EDITOR
  232. // This members are only here to ease debugging.
  233. public List<string>[] debugResourceReads;
  234. public List<string>[] debugResourceWrites;
  235. #endif
  236. public int refCount;
  237. public int syncToPassIndex; // Index of the pass that needs to be waited for.
  238. public int syncFromPassIndex; // Smaller pass index that waits for this pass.
  239. public bool enableAsyncCompute;
  240. public bool allowPassCulling;
  241. public bool needGraphicsFence;
  242. public bool culled;
  243. public bool culledByRendererList;
  244. public bool hasSideEffect;
  245. public bool enableFoveatedRasterization;
  246. public void Reset(RenderGraphPass pass, int index)
  247. {
  248. name = pass.name;
  249. this.index = index;
  250. enableAsyncCompute = pass.enableAsyncCompute;
  251. allowPassCulling = pass.allowPassCulling;
  252. enableFoveatedRasterization = pass.enableFoveatedRasterization;
  253. if (resourceCreateList == null)
  254. {
  255. resourceCreateList = new List<int>[(int)RenderGraphResourceType.Count];
  256. resourceReleaseList = new List<int>[(int)RenderGraphResourceType.Count];
  257. for (int i = 0; i < (int)RenderGraphResourceType.Count; ++i)
  258. {
  259. resourceCreateList[i] = new List<int>();
  260. resourceReleaseList[i] = new List<int>();
  261. }
  262. #if DEVELOPMENT_BUILD || UNITY_EDITOR
  263. debugResourceReads = new List<string>[(int)RenderGraphResourceType.Count];
  264. debugResourceWrites = new List<string>[(int)RenderGraphResourceType.Count];
  265. for (int i = 0; i < (int)RenderGraphResourceType.Count; ++i)
  266. {
  267. debugResourceReads[i] = new List<string>();
  268. debugResourceWrites[i] = new List<string>();
  269. }
  270. #endif
  271. }
  272. for (int i = 0; i < (int)RenderGraphResourceType.Count; ++i)
  273. {
  274. resourceCreateList[i].Clear();
  275. resourceReleaseList[i].Clear();
  276. }
  277. refCount = 0;
  278. culled = false;
  279. culledByRendererList = false;
  280. hasSideEffect = false;
  281. syncToPassIndex = -1;
  282. syncFromPassIndex = -1;
  283. needGraphicsFence = false;
  284. #if DEVELOPMENT_BUILD || UNITY_EDITOR
  285. for (int i = 0; i < (int)RenderGraphResourceType.Count; ++i)
  286. {
  287. debugResourceReads[i].Clear();
  288. debugResourceWrites[i].Clear();
  289. }
  290. #endif
  291. }
  292. }
  293. /// <summary>
  294. /// Enable the use of the render pass API by the graph instead of traditional SetRenderTarget. This is an advanced
  295. /// feature and users have to be aware of the specific impact it has on rendergraph/graphics APIs below.
  296. ///
  297. /// When enabled, the render graph try to use render passes and supasses instead of relying on SetRendertarget. It
  298. /// will try to aggressively optimize the number of BeginRenderPass+EndRenderPass calls as well as calls to NextSubPass.
  299. /// This with the aim to maximize the time spent "on chip" on tile based renderers.
  300. ///
  301. /// The Graph will automatically determine when to break render passes as well as the load and store actions to apply to these render passes.
  302. /// To do this, the graph will analyze the use of textures. E.g. when a texture is used twice in a row as a active render target, the two
  303. /// render graph passes will be merged in a single render pass with two surpasses. On the other hand if a render target is sampled as a texture in
  304. /// a later pass this render target will be stored (and possibly resolved) and the render pass will be broken up.
  305. ///
  306. /// When setting this setting to true some existing render graph API is no longer valid as it can't express detailed frame information needed to emit
  307. /// native render pases. In particular:
  308. /// - The ImportBackbuffer overload without a RenderTargetInfo argument.
  309. /// - Any AddRenderPass overloads. The more specific AddRasterRenderPass/AddComputePass/AddUnsafePass functions should be used to register passes.
  310. ///
  311. /// In addition to this, additional validation will be done on the correctness of arguments of existing API that was not previously done. This could lead
  312. /// to new errors when using existing render graph code with nativeRenderPassesEnabled.
  313. ///
  314. /// Note: that CommandBuffer.BeginRenderPass/EndRenderPass calls are different by design from SetRenderTarget so this could also have
  315. /// effects outside of render graph (e.g. for code relying on the currently active render target as this will not be updated when using render passes).
  316. /// </summary>
  317. public bool nativeRenderPassesEnabled
  318. {
  319. get; set;
  320. }
  321. internal/*for tests*/ RenderGraphResourceRegistry m_Resources;
  322. RenderGraphObjectPool m_RenderGraphPool = new RenderGraphObjectPool();
  323. RenderGraphBuilders m_builderInstance = new RenderGraphBuilders();
  324. internal/*for tests*/ List<RenderGraphPass> m_RenderPasses = new List<RenderGraphPass>(64);
  325. List<RendererListHandle> m_RendererLists = new List<RendererListHandle>(32);
  326. RenderGraphDebugParams m_DebugParameters = new RenderGraphDebugParams();
  327. RenderGraphLogger m_FrameInformationLogger = new RenderGraphLogger();
  328. RenderGraphDefaultResources m_DefaultResources = new RenderGraphDefaultResources();
  329. Dictionary<int, ProfilingSampler> m_DefaultProfilingSamplers = new Dictionary<int, ProfilingSampler>();
  330. InternalRenderGraphContext m_RenderGraphContext = new InternalRenderGraphContext();
  331. CommandBuffer m_PreviousCommandBuffer;
  332. List<int>[] m_ImmediateModeResourceList = new List<int>[(int)RenderGraphResourceType.Count];
  333. RenderGraphCompilationCache m_CompilationCache;
  334. RenderTargetIdentifier[][] m_TempMRTArrays = null;
  335. internal interface ICompiledGraph
  336. {
  337. public void Clear();
  338. }
  339. // Compiled Render Graph info.
  340. internal class CompiledGraph : ICompiledGraph
  341. {
  342. // This is a 1:1 mapping on the resource handle indexes, this means the first element with index 0 will represent the "null" handle
  343. public DynamicArray<CompiledResourceInfo>[] compiledResourcesInfos = new DynamicArray<CompiledResourceInfo>[(int)RenderGraphResourceType.Count];
  344. public DynamicArray<CompiledPassInfo> compiledPassInfos = new DynamicArray<CompiledPassInfo>();
  345. public int lastExecutionFrame;
  346. public CompiledGraph()
  347. {
  348. for (int i = 0; i < (int)RenderGraphResourceType.Count; ++i)
  349. {
  350. compiledResourcesInfos[i] = new DynamicArray<CompiledResourceInfo>();
  351. }
  352. }
  353. public void Clear()
  354. {
  355. for (int i = 0; i < (int)RenderGraphResourceType.Count; ++i)
  356. compiledResourcesInfos[i].Clear();
  357. compiledPassInfos.Clear();
  358. }
  359. void InitResourceInfosData(DynamicArray<CompiledResourceInfo> resourceInfos, int count)
  360. {
  361. resourceInfos.Resize(count);
  362. for (int i = 0; i < resourceInfos.size; ++i)
  363. resourceInfos[i].Reset();
  364. }
  365. public void InitializeCompilationData(List<RenderGraphPass> passes, RenderGraphResourceRegistry resources)
  366. {
  367. InitResourceInfosData(compiledResourcesInfos[(int)RenderGraphResourceType.Texture], resources.GetTextureResourceCount());
  368. InitResourceInfosData(compiledResourcesInfos[(int)RenderGraphResourceType.Buffer], resources.GetBufferResourceCount());
  369. InitResourceInfosData(compiledResourcesInfos[(int)RenderGraphResourceType.AccelerationStructure], resources.GetRayTracingAccelerationStructureResourceCount());
  370. compiledPassInfos.Resize(passes.Count);
  371. for (int i = 0; i < compiledPassInfos.size; ++i)
  372. compiledPassInfos[i].Reset(passes[i], i);
  373. }
  374. }
  375. Stack<int> m_CullingStack = new Stack<int>();
  376. string m_CurrentExecutionName;
  377. int m_ExecutionCount;
  378. int m_CurrentFrameIndex;
  379. int m_CurrentImmediatePassIndex;
  380. bool m_ExecutionExceptionWasRaised;
  381. bool m_HasRenderGraphBegun;
  382. bool m_RendererListCulling;
  383. bool m_EnableCompilationCaching;
  384. CompiledGraph m_DefaultCompiledGraph = new();
  385. CompiledGraph m_CurrentCompiledGraph;
  386. string m_CaptureDebugDataForExecution; // Null unless debug data has been requested
  387. Dictionary<string, DebugData> m_DebugData = new Dictionary<string, DebugData>();
  388. // Global list of living render graphs
  389. static List<RenderGraph> s_RegisteredGraphs = new List<RenderGraph>();
  390. #region Public Interface
  391. /// <summary>Name of the Render Graph.</summary>
  392. public string name { get; private set; } = "RenderGraph";
  393. /// <summary>Request debug data be captured for the provided execution on the next frame.</summary>
  394. internal void RequestCaptureDebugData(string executionName)
  395. {
  396. m_CaptureDebugDataForExecution = executionName;
  397. }
  398. /// <summary>If true, the Render Graph Viewer is active.</summary>
  399. public static bool isRenderGraphViewerActive { get; internal set; }
  400. /// <summary>If true, the Render Graph will run its various validity checks while processing (not considered in release mode).</summary>
  401. internal static bool enableValidityChecks { get; private set; }
  402. /// <summary>
  403. /// Set of default resources usable in a pass rendering code.
  404. /// </summary>
  405. public RenderGraphDefaultResources defaultResources
  406. {
  407. get
  408. {
  409. return m_DefaultResources;
  410. }
  411. }
  412. /// <summary>
  413. /// Render Graph constructor.
  414. /// </summary>
  415. /// <param name="name">Optional name used to identify the render graph instnace.</param>
  416. public RenderGraph(string name = "RenderGraph")
  417. {
  418. this.name = name;
  419. if (GraphicsSettings.TryGetRenderPipelineSettings<RenderGraphGlobalSettings>(out var renderGraphGlobalSettings))
  420. {
  421. m_EnableCompilationCaching = renderGraphGlobalSettings.enableCompilationCaching;
  422. if (m_EnableCompilationCaching)
  423. m_CompilationCache = new RenderGraphCompilationCache();
  424. enableValidityChecks = renderGraphGlobalSettings.enableValidityChecks;
  425. }
  426. else // No SRP pipeline is present/active, it can happen with unit tests
  427. {
  428. enableValidityChecks = true;
  429. }
  430. m_TempMRTArrays = new RenderTargetIdentifier[kMaxMRTCount][];
  431. for (int i = 0; i < kMaxMRTCount; ++i)
  432. m_TempMRTArrays[i] = new RenderTargetIdentifier[i + 1];
  433. m_Resources = new RenderGraphResourceRegistry(m_DebugParameters, m_FrameInformationLogger);
  434. s_RegisteredGraphs.Add(this);
  435. onGraphRegistered?.Invoke(this);
  436. }
  437. /// <summary>
  438. /// Cleanup the Render Graph.
  439. /// </summary>
  440. public void Cleanup()
  441. {
  442. m_Resources.Cleanup();
  443. m_DefaultResources.Cleanup();
  444. m_RenderGraphPool.Cleanup();
  445. s_RegisteredGraphs.Remove(this);
  446. onGraphUnregistered?.Invoke(this);
  447. nativeCompiler?.contextData?.Dispose();
  448. m_CompilationCache?.Clear();
  449. }
  450. internal RenderGraphDebugParams debugParams => m_DebugParameters;
  451. internal List<DebugUI.Widget> GetWidgetList()
  452. {
  453. return m_DebugParameters.GetWidgetList(name);
  454. }
  455. internal bool areAnySettingsActive => m_DebugParameters.AreAnySettingsActive;
  456. /// <summary>
  457. /// Register the render graph to the debug window.
  458. /// </summary>
  459. /// <param name="panel">Optional debug panel to which the render graph debug parameters will be registered.</param>
  460. public void RegisterDebug(DebugUI.Panel panel = null)
  461. {
  462. m_DebugParameters.RegisterDebug(name, panel);
  463. }
  464. /// <summary>
  465. /// Unregister render graph from the debug window.
  466. /// </summary>
  467. public void UnRegisterDebug()
  468. {
  469. m_DebugParameters.UnRegisterDebug(this.name);
  470. }
  471. /// <summary>
  472. /// Get the list of all registered render graphs.
  473. /// </summary>
  474. /// <returns>The list of all registered render graphs.</returns>
  475. public static List<RenderGraph> GetRegisteredRenderGraphs()
  476. {
  477. return s_RegisteredGraphs;
  478. }
  479. /// <summary>
  480. /// Returns the last rendered frame debug data. Can be null if requireDebugData is set to false.
  481. /// </summary>
  482. /// <returns>The last rendered frame debug data</returns>
  483. internal DebugData GetDebugData(string executionName)
  484. {
  485. if (m_DebugData.TryGetValue(executionName, out var debugData))
  486. return debugData;
  487. return null;
  488. }
  489. /// <summary>
  490. /// End frame processing. Purge resources that have been used since last frame and resets internal states.
  491. /// This need to be called once per frame.
  492. /// </summary>
  493. public void EndFrame()
  494. {
  495. m_Resources.PurgeUnusedGraphicsResources();
  496. if (m_DebugParameters.logFrameInformation)
  497. {
  498. Debug.Log(m_FrameInformationLogger.GetAllLogs());
  499. m_DebugParameters.logFrameInformation = false;
  500. }
  501. if (m_DebugParameters.logResources)
  502. {
  503. m_Resources.FlushLogs();
  504. m_DebugParameters.logResources = false;
  505. }
  506. }
  507. /// <summary>
  508. /// Import an external texture to the Render Graph.
  509. /// Any pass writing to an imported texture will be considered having side effects and can't be automatically culled.
  510. /// </summary>
  511. /// <param name="rt">External RTHandle that needs to be imported.</param>
  512. /// <returns>A new TextureHandle that represents the imported texture in the context of this rendergraph.</returns>
  513. public TextureHandle ImportTexture(RTHandle rt)
  514. {
  515. return m_Resources.ImportTexture(rt);
  516. }
  517. /// <summary>
  518. /// Import an external texture to the Render Graph.
  519. /// Any pass writing to an imported texture will be considered having side effects and can't be automatically culled.
  520. ///
  521. /// Note: RTHandles that wrap RenderTargetIdentifier will fail to import using this overload as render graph can't derive the render texture's properties.
  522. /// In that case the overload taking a RenderTargetInfo argument should be used instead.
  523. /// </summary>
  524. /// <param name="rt">External RTHandle that needs to be imported.</param>
  525. /// <param name="importParams">Info describing the clear behavior of imported textures. Clearing textures using importParams may be more efficient than manually clearing the texture using `cmd.Clear` on some hardware.</param>
  526. /// <returns>A new TextureHandle that represents the imported texture in the context of this rendergraph.</returns>
  527. public TextureHandle ImportTexture(RTHandle rt, ImportResourceParams importParams )
  528. {
  529. return m_Resources.ImportTexture(rt, importParams);
  530. }
  531. /// <summary>
  532. /// Import an external texture to the Render Graph. This overload should be used for RTHandles wrapping a RenderTargetIdentifier.
  533. /// If the RTHandle is wrapping a RenderTargetIdentifer, Rendergrpah can't derive the render texture's properties so the user has to provide this info to the graph through RenderTargetInfo.
  534. ///
  535. /// Any pass writing to an imported texture will be considered having side effects and can't be automatically culled.
  536. ///
  537. /// Note: To avoid inconsistencies between the passed in RenderTargetInfo and render texture this overload can only be used when the RTHandle is wrapping a RenderTargetIdentifier.
  538. /// If this is not the case, the overload of ImportTexture without a RenderTargetInfo argument should be used instead.
  539. /// </summary>
  540. /// <param name="rt">External RTHandle that needs to be imported.</param>
  541. /// <param name="info">The properties of the passed in RTHandle.</param>
  542. /// <param name="importParams">Info describing the clear behavior of imported textures. Clearing textures using importParams may be more efficient than manually clearing the texture using `cmd.Clear` on some hardware.</param>
  543. /// <returns>A new TextureHandle that represents the imported texture in the context of this rendergraph.</returns>
  544. public TextureHandle ImportTexture(RTHandle rt, RenderTargetInfo info, ImportResourceParams importParams = new ImportResourceParams() )
  545. {
  546. return m_Resources.ImportTexture(rt, info, importParams);
  547. }
  548. /// <summary>
  549. /// Import an external texture to the Render Graph and set the handle as builtin handle. This can only happen from within the graph module
  550. /// so it is internal.
  551. /// </summary>
  552. internal TextureHandle ImportTexture(RTHandle rt, bool isBuiltin)
  553. {
  554. return m_Resources.ImportTexture(rt, isBuiltin);
  555. }
  556. /// <summary>
  557. /// Import the final backbuffer to render graph. The rendergraph can't derive the properties of a RenderTargetIdentifier as it is an opaque handle so the user has to pass them in through the info argument.
  558. /// </summary>
  559. /// <param name="rt">Backbuffer render target identifier.</param>
  560. /// <param name="info">The properties of the passed in RTHandle.</param>
  561. /// <param name="importParams">Info describing the clear behavior of imported textures. Clearing textures using importParams may be more efficient than manually clearing the texture using `cmd.Clear` on some hardware.</param>
  562. /// <returns>A new TextureHandle that represents the imported texture in the context of this rendergraph.</returns>
  563. public TextureHandle ImportBackbuffer(RenderTargetIdentifier rt, RenderTargetInfo info, ImportResourceParams importParams = new ImportResourceParams())
  564. {
  565. return m_Resources.ImportBackbuffer(rt, info, importParams);
  566. }
  567. /// <summary>
  568. /// Import the final backbuffer to render graph.
  569. /// This function can only be used when nativeRenderPassesEnabled is false.
  570. /// </summary>
  571. /// <param name="rt">Backbuffer render target identifier.</param>
  572. /// <returns>A new TextureHandle that represents the imported texture in the context of this rendergraph.</returns>
  573. public TextureHandle ImportBackbuffer(RenderTargetIdentifier rt)
  574. {
  575. RenderTargetInfo dummy = new RenderTargetInfo();
  576. dummy.width = dummy.height = dummy.volumeDepth = dummy.msaaSamples = 1;
  577. dummy.format = GraphicsFormat.R8G8B8A8_SRGB;
  578. return m_Resources.ImportBackbuffer(rt, dummy, new ImportResourceParams());
  579. }
  580. /// <summary>
  581. /// Create a new Render Graph Texture resource.
  582. /// </summary>
  583. /// <param name="desc">Texture descriptor.</param>
  584. /// <returns>A new TextureHandle.</returns>
  585. public TextureHandle CreateTexture(in TextureDesc desc)
  586. {
  587. return m_Resources.CreateTexture(desc);
  588. }
  589. /// <summary>
  590. /// Create a new Render Graph Shared Texture resource.
  591. /// This texture will be persistent across render graph executions.
  592. /// </summary>
  593. /// <param name="desc">Creation descriptor of the texture.</param>
  594. /// <param name="explicitRelease">Set to true if you want to manage the lifetime of the resource yourself. Otherwise the resource will be released automatically if unused for a time.</param>
  595. /// <returns>A new TextureHandle.</returns>
  596. public TextureHandle CreateSharedTexture(in TextureDesc desc, bool explicitRelease = false)
  597. {
  598. if (m_HasRenderGraphBegun)
  599. throw new InvalidOperationException("A shared texture can only be created outside of render graph execution.");
  600. return m_Resources.CreateSharedTexture(desc, explicitRelease);
  601. }
  602. /// <summary>
  603. /// Refresh a shared texture with a new descriptor.
  604. /// </summary>
  605. /// <param name="handle">Shared texture that needs to be updated.</param>
  606. /// <param name="desc">New Descriptor for the texture.</param>
  607. public void RefreshSharedTextureDesc(TextureHandle handle, in TextureDesc desc)
  608. {
  609. m_Resources.RefreshSharedTextureDesc(handle, desc);
  610. }
  611. /// <summary>
  612. /// Release a Render Graph shared texture resource.
  613. /// </summary>
  614. /// <param name="texture">The handle to the texture that needs to be release.</param>
  615. public void ReleaseSharedTexture(TextureHandle texture)
  616. {
  617. if (m_HasRenderGraphBegun)
  618. throw new InvalidOperationException("A shared texture can only be release outside of render graph execution.");
  619. m_Resources.ReleaseSharedTexture(texture);
  620. }
  621. /// <summary>
  622. /// Create a new Render Graph Texture resource using the descriptor from another texture.
  623. /// </summary>
  624. /// <param name="texture">Texture from which the descriptor should be used.</param>
  625. /// <returns>A new TextureHandle.</returns>
  626. public TextureHandle CreateTexture(TextureHandle texture)
  627. {
  628. return m_Resources.CreateTexture(m_Resources.GetTextureResourceDesc(texture.handle));
  629. }
  630. /// <summary>
  631. /// Create a new Render Graph Texture if the passed handle is invalid and use said handle as output.
  632. /// If the passed handle is valid, no texture is created.
  633. /// </summary>
  634. /// <param name="desc">Desc used to create the texture.</param>
  635. /// <param name="texture">Texture from which the descriptor should be used.</param>
  636. public void CreateTextureIfInvalid(in TextureDesc desc, ref TextureHandle texture)
  637. {
  638. if (!texture.IsValid())
  639. texture = m_Resources.CreateTexture(desc);
  640. }
  641. /// <summary>
  642. /// Gets the descriptor of the specified Texture resource.
  643. /// </summary>
  644. /// <param name="texture">Texture resource from which the descriptor is requested.</param>
  645. /// <returns>The input texture descriptor.</returns>
  646. public TextureDesc GetTextureDesc(TextureHandle texture)
  647. {
  648. return m_Resources.GetTextureResourceDesc(texture.handle);
  649. }
  650. /// <summary>
  651. /// Gets the descriptor of the specified Texture resource.
  652. /// </summary>
  653. /// <param name="texture">Texture resource from which the descriptor is requested.</param>
  654. /// <returns>The input texture descriptor.</returns>
  655. public RenderTargetInfo GetRenderTargetInfo(TextureHandle texture)
  656. {
  657. RenderTargetInfo info;
  658. m_Resources.GetRenderTargetInfo(texture.handle, out info);
  659. return info;
  660. }
  661. /// <summary>
  662. /// Creates a new Renderer List Render Graph resource.
  663. /// </summary>
  664. /// <param name="desc">Renderer List descriptor.</param>
  665. /// <returns>A new RendererListHandle.</returns>
  666. public RendererListHandle CreateRendererList(in CoreRendererListDesc desc)
  667. {
  668. return m_Resources.CreateRendererList(desc);
  669. }
  670. /// <summary>
  671. /// Creates a new Renderer List Render Graph resource.
  672. /// </summary>
  673. /// <param name="desc">Renderer List descriptor.</param>
  674. /// <returns>A new RendererListHandle.</returns>
  675. public RendererListHandle CreateRendererList(in RendererListParams desc)
  676. {
  677. return m_Resources.CreateRendererList(desc);
  678. }
  679. /// <summary>
  680. /// Creates a new Shadow Renderer List Render Graph resource.
  681. /// </summary>
  682. /// <param name="shadowDrawingSettings">DrawSettings that describe the shadow drawcall.</param>
  683. /// <returns>A new RendererListHandle.</returns>
  684. public RendererListHandle CreateShadowRendererList(ref ShadowDrawingSettings shadowDrawingSettings)
  685. {
  686. return m_Resources.CreateShadowRendererList(m_RenderGraphContext.renderContext, ref shadowDrawingSettings);
  687. }
  688. /// <summary>
  689. /// Creates a new Gizmo Renderer List Render Graph resource.
  690. /// </summary>
  691. /// <param name="camera">The camera that is used for rendering the Gizmo.</param>
  692. /// <param name="gizmoSubset">GizmoSubset that specifies whether gizmos render before or after postprocessing for a camera render. </param>
  693. /// <returns>A new RendererListHandle.</returns>
  694. public RendererListHandle CreateGizmoRendererList(in Camera camera, in GizmoSubset gizmoSubset)
  695. {
  696. return m_Resources.CreateGizmoRendererList(m_RenderGraphContext.renderContext, camera, gizmoSubset);
  697. }
  698. /// <summary>
  699. /// Creates a new UIOverlay Renderer List Render Graph resource.
  700. /// </summary>
  701. /// <param name="camera">The camera that is used for rendering the full UIOverlay.</param>
  702. /// <returns>A new RendererListHandle.</returns>
  703. public RendererListHandle CreateUIOverlayRendererList(in Camera camera)
  704. {
  705. return m_Resources.CreateUIOverlayRendererList(m_RenderGraphContext.renderContext, camera, UISubset.All);
  706. }
  707. /// <summary>
  708. /// Creates a new UIOverlay Renderer List Render Graph resource.
  709. /// </summary>
  710. /// <param name="camera">The camera that is used for rendering some subset of the UIOverlay.</param>
  711. /// <param name="uiSubset">Enum flag that specifies which subset to render.</param>
  712. /// <returns>A new RendererListHandle.</returns>
  713. public RendererListHandle CreateUIOverlayRendererList(in Camera camera, in UISubset uiSubset)
  714. {
  715. return m_Resources.CreateUIOverlayRendererList(m_RenderGraphContext.renderContext, camera, uiSubset);
  716. }
  717. /// <summary>
  718. /// Creates a new WireOverlay Renderer List Render Graph resource.
  719. /// </summary>
  720. /// <param name="camera">The camera that is used for rendering the WireOverlay.</param>
  721. /// <returns>A new RendererListHandle.</returns>
  722. public RendererListHandle CreateWireOverlayRendererList(in Camera camera)
  723. {
  724. return m_Resources.CreateWireOverlayRendererList(m_RenderGraphContext.renderContext, camera);
  725. }
  726. /// <summary>
  727. /// Creates a new Skybox Renderer List Render Graph resource.
  728. /// </summary>
  729. /// <param name="camera">The camera that is used for rendering the Skybox.</param>
  730. /// <returns>A new RendererListHandle.</returns>
  731. public RendererListHandle CreateSkyboxRendererList(in Camera camera)
  732. {
  733. return m_Resources.CreateSkyboxRendererList(m_RenderGraphContext.renderContext, camera);
  734. }
  735. /// <summary>
  736. /// Creates a new Skybox Renderer List Render Graph resource.
  737. /// </summary>
  738. /// <param name="camera">The camera that is used for rendering the Skybox.</param>
  739. /// <param name="projectionMatrix">The projection matrix used during XR rendering of the skybox.</param>
  740. /// <param name="viewMatrix">The view matrix used during XR rendering of the skybox.</param>
  741. /// <returns>A new RendererListHandle.</returns>
  742. public RendererListHandle CreateSkyboxRendererList(in Camera camera, Matrix4x4 projectionMatrix, Matrix4x4 viewMatrix)
  743. {
  744. return m_Resources.CreateSkyboxRendererList(m_RenderGraphContext.renderContext, camera, projectionMatrix, viewMatrix);
  745. }
  746. /// <summary>
  747. /// Creates a new Skybox Renderer List Render Graph resource.
  748. /// </summary>
  749. /// <param name="camera">The camera that is used for rendering the Skybox.</param>
  750. /// <param name="projectionMatrixL">The left eye projection matrix used during Legacy single pass XR rendering of the skybox.</param>
  751. /// <param name="viewMatrixL">The left eye view matrix used during Legacy single pass XR rendering of the skybox.</param>
  752. /// <param name="projectionMatrixR">The right eye projection matrix used during Legacy single pass XR rendering of the skybox.</param>
  753. /// <param name="viewMatrixR">The right eye view matrix used during Legacy single pass XR rendering of the skybox.</param>
  754. /// <returns>A new RendererListHandle.</returns>
  755. public RendererListHandle CreateSkyboxRendererList(in Camera camera, Matrix4x4 projectionMatrixL, Matrix4x4 viewMatrixL, Matrix4x4 projectionMatrixR, Matrix4x4 viewMatrixR)
  756. {
  757. return m_Resources.CreateSkyboxRendererList(m_RenderGraphContext.renderContext, camera, projectionMatrixL, viewMatrixL, projectionMatrixR, viewMatrixR);
  758. }
  759. /// <summary>
  760. /// Import an external Graphics Buffer to the Render Graph.
  761. /// Any pass writing to an imported graphics buffer will be considered having side effects and can't be automatically culled.
  762. /// </summary>
  763. /// <param name="graphicsBuffer">External Graphics Buffer that needs to be imported.</param>
  764. /// <param name="forceRelease">The imported graphics buffer will be released after usage.</param>
  765. /// <returns>A new GraphicsBufferHandle.</returns>
  766. public BufferHandle ImportBuffer(GraphicsBuffer graphicsBuffer, bool forceRelease = false)
  767. {
  768. return m_Resources.ImportBuffer(graphicsBuffer, forceRelease);
  769. }
  770. /// <summary>
  771. /// Create a new Render Graph Graphics Buffer resource.
  772. /// </summary>
  773. /// <param name="desc">Graphics Buffer descriptor.</param>
  774. /// <returns>A new GraphicsBufferHandle.</returns>
  775. public BufferHandle CreateBuffer(in BufferDesc desc)
  776. {
  777. return m_Resources.CreateBuffer(desc);
  778. }
  779. /// <summary>
  780. /// Create a new Render Graph Graphics Buffer resource using the descriptor from another graphics buffer.
  781. /// </summary>
  782. /// <param name="graphicsBuffer">Graphics Buffer from which the descriptor should be used.</param>
  783. /// <returns>A new GraphicsBufferHandle.</returns>
  784. public BufferHandle CreateBuffer(in BufferHandle graphicsBuffer)
  785. {
  786. return m_Resources.CreateBuffer(m_Resources.GetBufferResourceDesc(graphicsBuffer.handle));
  787. }
  788. /// <summary>
  789. /// Gets the descriptor of the specified Graphics Buffer resource.
  790. /// </summary>
  791. /// <param name="graphicsBuffer">Graphics Buffer resource from which the descriptor is requested.</param>
  792. /// <returns>The input graphics buffer descriptor.</returns>
  793. public BufferDesc GetBufferDesc(in BufferHandle graphicsBuffer)
  794. {
  795. return m_Resources.GetBufferResourceDesc(graphicsBuffer.handle);
  796. }
  797. /// <summary>
  798. /// Import an external RayTracingAccelerationStructure to the Render Graph.
  799. /// Any pass writing to (building) an imported RayTracingAccelerationStructure will be considered having side effects and can't be automatically culled.
  800. /// </summary>
  801. /// <param name="accelStruct">External RayTracingAccelerationStructure that needs to be imported.</param>
  802. /// <param name="name">Optional name for identifying the RayTracingAccelerationStructure in the Render Graph.</param>
  803. /// <returns>A new RayTracingAccelerationStructureHandle.</returns>
  804. public RayTracingAccelerationStructureHandle ImportRayTracingAccelerationStructure(in RayTracingAccelerationStructure accelStruct, string name = null)
  805. {
  806. return m_Resources.ImportRayTracingAccelerationStructure(accelStruct, name);
  807. }
  808. /// <summary>
  809. /// Add a new Raster Render Pass to the Render Graph. Raster passes can execute rasterization workloads but cannot do other GPU work like copies or compute.
  810. /// </summary>
  811. /// <typeparam name="PassData">Type of the class to use to provide data to the Render Pass.</typeparam>
  812. /// <param name="passName">Name of the new Render Pass (this is also be used to generate a GPU profiling marker).</param>
  813. /// <param name="passData">Instance of PassData that is passed to the render function and you must fill.</param>
  814. /// <param name="file">File name of the source file this function is called from. Used for debugging. This parameter is automatically generated by the compiler. Users do not need to pass it.</param>
  815. /// <param name="line">File line of the source file this function is called from. Used for debugging. This parameter is automatically generated by the compiler. Users do not need to pass it.</param>
  816. /// <returns>A new instance of a IRasterRenderGraphBuilder used to setup the new Rasterization Render Pass.</returns>
  817. public IRasterRenderGraphBuilder AddRasterRenderPass<PassData>(string passName, out PassData passData
  818. #if !CORE_PACKAGE_DOCTOOLS
  819. , [CallerFilePath] string file = "",
  820. [CallerLineNumber] int line = 0) where PassData : class, new()
  821. #endif
  822. {
  823. return AddRasterRenderPass(passName, out passData, GetDefaultProfilingSampler(passName), file, line);
  824. }
  825. /// <summary>
  826. /// Add a new Raster Render Pass to the Render Graph. Raster passes can execute rasterization workloads but cannot do other GPU work like copies or compute.
  827. /// </summary>
  828. /// <typeparam name="PassData">Type of the class to use to provide data to the Render Pass.</typeparam>
  829. /// <param name="passName">Name of the new Render Pass (this is also be used to generate a GPU profiling marker).</param>
  830. /// <param name="passData">Instance of PassData that is passed to the render function and you must fill.</param>
  831. /// <param name="sampler">Profiling sampler used around the pass.</param>
  832. /// <param name="file">File name of the source file this function is called from. Used for debugging. This parameter is automatically generated by the compiler. Users do not need to pass it.</param>
  833. /// <param name="line">File line of the source file this function is called from. Used for debugging. This parameter is automatically generated by the compiler. Users do not need to pass it.</param>
  834. /// <returns>A new instance of a IRasterRenderGraphBuilder used to setup the new Rasterization Render Pass.</returns>
  835. public IRasterRenderGraphBuilder AddRasterRenderPass<PassData>(string passName, out PassData passData, ProfilingSampler sampler
  836. #if !CORE_PACKAGE_DOCTOOLS
  837. ,[CallerFilePath] string file = "",
  838. [CallerLineNumber] int line = 0) where PassData : class, new()
  839. #endif
  840. {
  841. AddPassDebugMetadata(passName, file, line);
  842. var renderPass = m_RenderGraphPool.Get<RasterRenderGraphPass<PassData>>();
  843. renderPass.Initialize(m_RenderPasses.Count, m_RenderGraphPool.Get<PassData>(), passName, RenderGraphPassType.Raster, sampler);
  844. passData = renderPass.data;
  845. m_RenderPasses.Add(renderPass);
  846. m_builderInstance.Setup(renderPass, m_Resources, this);
  847. return m_builderInstance;
  848. }
  849. /// <summary>
  850. /// Add a new Compute Render Pass to the Render Graph. Raster passes can execute rasterization workloads but cannot do other GPU work like copies or compute.
  851. /// </summary>
  852. /// <typeparam name="PassData">Type of the class to use to provide data to the Render Pass.</typeparam>
  853. /// <param name="passName">Name of the new Render Pass (this is also be used to generate a GPU profiling marker).</param>
  854. /// <param name="passData">Instance of PassData that is passed to the render function and you must fill.</param>
  855. /// <param name="file">File name of the source file this function is called from. Used for debugging. This parameter is automatically generated by the compiler. Users do not need to pass it.</param>
  856. /// <param name="line">File line of the source file this function is called from. Used for debugging. This parameter is automatically generated by the compiler. Users do not need to pass it.</param>
  857. /// <returns>A new instance of a IRasterRenderGraphBuilder used to setup the new Rasterization Render Pass.</returns>
  858. public IComputeRenderGraphBuilder AddComputePass<PassData>(string passName, out PassData passData
  859. #if !CORE_PACKAGE_DOCTOOLS
  860. , [CallerFilePath] string file = "",
  861. [CallerLineNumber] int line = 0) where PassData : class, new()
  862. #endif
  863. {
  864. return AddComputePass(passName, out passData, GetDefaultProfilingSampler(passName), file, line);
  865. }
  866. /// <summary>
  867. /// Add a new Compute Render Pass to the Render Graph. Compute passes can execute compute workloads but cannot do rasterization.
  868. /// </summary>
  869. /// <typeparam name="PassData">Type of the class to use to provide data to the Render Pass.</typeparam>
  870. /// <param name="passName">Name of the new Render Pass (this is also be used to generate a GPU profiling marker).</param>
  871. /// <param name="passData">Instance of PassData that is passed to the render function and you must fill.</param>
  872. /// <param name="sampler">Profiling sampler used around the pass.</param>
  873. /// <param name="file">File name of the source file this function is called from. Used for debugging. This parameter is automatically generated by the compiler. Users do not need to pass it.</param>
  874. /// <param name="line">File line of the source file this function is called from. Used for debugging. This parameter is automatically generated by the compiler. Users do not need to pass it.</param>
  875. /// <returns>A new instance of a IComputeRenderGraphBuilder used to setup the new Compute Render Pass.</returns>
  876. public IComputeRenderGraphBuilder AddComputePass<PassData>(string passName, out PassData passData, ProfilingSampler sampler
  877. #if !CORE_PACKAGE_DOCTOOLS
  878. ,[CallerFilePath] string file = "",
  879. [CallerLineNumber] int line = 0) where PassData : class, new()
  880. #endif
  881. {
  882. AddPassDebugMetadata(passName, file, line);
  883. var renderPass = m_RenderGraphPool.Get<ComputeRenderGraphPass<PassData>>();
  884. renderPass.Initialize(m_RenderPasses.Count, m_RenderGraphPool.Get<PassData>(), passName, RenderGraphPassType.Compute, sampler);
  885. passData = renderPass.data;
  886. m_RenderPasses.Add(renderPass);
  887. m_builderInstance.Setup(renderPass, m_Resources, this);
  888. return m_builderInstance;
  889. }
  890. /// <summary>
  891. /// Add a new Unsafe Render Pass to the Render Graph. Unsafe passes can do certain operations compute/raster render passes cannot do and have
  892. /// access to the full command buffer API. The unsafe API should be used sparingly as it has the following downsides:
  893. /// - Limited automatic validation of the commands and resource dependencies. The user is responsible to ensure that all dependencies are correctly declared.
  894. /// - All native render passes will be serialized out.
  895. /// - In the future the render graph compiler may generate a sub-optimal command stream for unsafe passes.
  896. /// When using a unsafe pass the graph will also not automatically set up graphics state like rendertargets. The pass should do this itself
  897. /// using cmd.SetRenderTarget and related commands.
  898. /// </summary>
  899. /// <typeparam name="PassData">Type of the class to use to provide data to the Render Pass.</typeparam>
  900. /// <param name="passName">Name of the new Render Pass (this is also be used to generate a GPU profiling marker).</param>
  901. /// <param name="passData">Instance of PassData that is passed to the render function and you must fill.</param>
  902. /// <param name="file">File name of the source file this function is called from. Used for debugging. This parameter is automatically generated by the compiler. Users do not need to pass it.</param>
  903. /// <param name="line">File line of the source file this function is called from. Used for debugging. This parameter is automatically generated by the compiler. Users do not need to pass it.</param>
  904. /// <returns>A new instance of a IUnsafeRenderGraphBuilder used to setup the new Unsafe Render Pass.</returns>
  905. public IUnsafeRenderGraphBuilder AddUnsafePass<PassData>(string passName, out PassData passData
  906. #if !CORE_PACKAGE_DOCTOOLS
  907. , [CallerFilePath] string file = "",
  908. [CallerLineNumber] int line = 0) where PassData : class, new()
  909. #endif
  910. {
  911. return AddUnsafePass(passName, out passData, GetDefaultProfilingSampler(passName), file, line);
  912. }
  913. /// <summary>
  914. /// Add a new unsafe Render Pass to the Render Graph. Unsafe passes can do certain operations compute/raster render passes cannot do and have
  915. /// access to the full command buffer API. The unsafe API should be used sparingly as it has the following downsides:
  916. /// - Limited automatic validation of the commands and resource dependencies. The user is responsible to ensure that all dependencies are correctly declared.
  917. /// - All native render passes will be serialized out.
  918. /// - In the future the render graph compiler may generate a sub-optimal command stream for unsafe passes.
  919. /// When using an unsafe pass the graph will also not automatically set up graphics state like rendertargets. The pass should do this itself
  920. /// using cmd.SetRenderTarget and related commands.
  921. /// </summary>
  922. /// <typeparam name="PassData">Type of the class to use to provide data to the Render Pass.</typeparam>
  923. /// <param name="passName">Name of the new Render Pass (this is also be used to generate a GPU profiling marker).</param>
  924. /// <param name="passData">Instance of PassData that is passed to the render function and you must fill.</param>
  925. /// <param name="sampler">Profiling sampler used around the pass.</param>
  926. /// <param name="file">File name of the source file this function is called from. Used for debugging. This parameter is automatically generated by the compiler. Users do not need to pass it.</param>
  927. /// <param name="line">File line of the source file this function is called from. Used for debugging. This parameter is automatically generated by the compiler. Users do not need to pass it.</param>
  928. /// <returns>A new instance of a IUnsafeRenderGraphBuilder used to setup the new unsafe Render Pass.</returns>
  929. public IUnsafeRenderGraphBuilder AddUnsafePass<PassData>(string passName, out PassData passData, ProfilingSampler sampler
  930. #if !CORE_PACKAGE_DOCTOOLS
  931. , [CallerFilePath] string file = "",
  932. [CallerLineNumber] int line = 0) where PassData : class, new()
  933. #endif
  934. {
  935. AddPassDebugMetadata(passName, file, line);
  936. var renderPass = m_RenderGraphPool.Get<UnsafeRenderGraphPass<PassData>>();
  937. renderPass.Initialize(m_RenderPasses.Count, m_RenderGraphPool.Get<PassData>(), passName, RenderGraphPassType.Unsafe, sampler);
  938. renderPass.AllowGlobalState(true);
  939. passData = renderPass.data;
  940. m_RenderPasses.Add(renderPass);
  941. m_builderInstance.Setup(renderPass, m_Resources, this);
  942. return m_builderInstance;
  943. }
  944. /// <summary>
  945. /// Add a new Render Pass to the Render Graph.
  946. /// </summary>
  947. /// <typeparam name="PassData">Type of the class to use to provide data to the Render Pass.</typeparam>
  948. /// <param name="passName">Name of the new Render Pass (this is also be used to generate a GPU profiling marker).</param>
  949. /// <param name="passData">Instance of PassData that is passed to the render function and you must fill.</param>
  950. /// <param name="sampler">Profiling sampler used around the pass.</param>
  951. /// <param name="file">File name of the source file this function is called from. Used for debugging. This parameter is automatically generated by the compiler. Users do not need to pass it.</param>
  952. /// <param name="line">File line of the source file this function is called from. Used for debugging. This parameter is automatically generated by the compiler. Users do not need to pass it.</param>
  953. /// <returns>A new instance of a RenderGraphBuilder used to setup the new Render Pass.</returns>
  954. public RenderGraphBuilder AddRenderPass<PassData>(string passName, out PassData passData, ProfilingSampler sampler
  955. #if !CORE_PACKAGE_DOCTOOLS
  956. ,[CallerFilePath] string file = "",
  957. [CallerLineNumber] int line = 0) where PassData : class, new()
  958. #endif
  959. {
  960. AddPassDebugMetadata(passName, file, line);
  961. var renderPass = m_RenderGraphPool.Get<RenderGraphPass<PassData>>();
  962. renderPass.Initialize(m_RenderPasses.Count, m_RenderGraphPool.Get<PassData>(), passName, RenderGraphPassType.Legacy, sampler);
  963. renderPass.AllowGlobalState(true);// Old pass types allow global state by default as HDRP relies on it
  964. passData = renderPass.data;
  965. m_RenderPasses.Add(renderPass);
  966. return new RenderGraphBuilder(renderPass, m_Resources, this);
  967. }
  968. /// <summary>
  969. /// Add a new Render Pass to the Render Graph.
  970. /// </summary>
  971. /// <typeparam name="PassData">Type of the class to use to provide data to the Render Pass.</typeparam>
  972. /// <param name="passName">Name of the new Render Pass (this is also be used to generate a GPU profiling marker).</param>
  973. /// <param name="passData">Instance of PassData that is passed to the render function and you must fill.</param>
  974. /// <param name="file">File name of the source file this function is called from. Used for debugging. This parameter is automatically generated by the compiler. Users do not need to pass it.</param>
  975. /// <param name="line">File line of the source file this function is called from. Used for debugging. This parameter is automatically generated by the compiler. Users do not need to pass it.</param>
  976. /// <returns>A new instance of a RenderGraphBuilder used to setup the new Render Pass.</returns>
  977. public RenderGraphBuilder AddRenderPass<PassData>(string passName, out PassData passData
  978. #if !CORE_PACKAGE_DOCTOOLS
  979. ,[CallerFilePath] string file = "",
  980. [CallerLineNumber] int line = 0) where PassData : class, new()
  981. #endif
  982. {
  983. return AddRenderPass(passName, out passData, GetDefaultProfilingSampler(passName), file, line);
  984. }
  985. /// <summary>
  986. /// Starts the recording of the render graph.
  987. /// This must be called before adding any pass to the render graph.
  988. /// </summary>
  989. /// <param name="parameters">Parameters necessary for the render graph execution.</param>
  990. /// <example>
  991. /// <para>Begin recording the Render Graph.</para>
  992. /// <code>
  993. /// renderGraph.BeginRecording(parameters)
  994. /// // Add your render graph passes here.
  995. /// renderGraph.EndRecordingAndExecute()
  996. /// </code>
  997. /// </example>
  998. public void BeginRecording(in RenderGraphParameters parameters)
  999. {
  1000. m_CurrentFrameIndex = parameters.currentFrameIndex;
  1001. m_CurrentExecutionName = parameters.executionName != null ? parameters.executionName : "RenderGraphExecution";
  1002. m_HasRenderGraphBegun = true;
  1003. // Cannot do renderer list culling with compilation caching because it happens after compilation is done so it can lead to discrepancies.
  1004. m_RendererListCulling = parameters.rendererListCulling && !m_EnableCompilationCaching;
  1005. m_Resources.BeginRenderGraph(m_ExecutionCount++);
  1006. if (m_DebugParameters.enableLogging)
  1007. {
  1008. m_FrameInformationLogger.Initialize(m_CurrentExecutionName);
  1009. }
  1010. m_DefaultResources.InitializeForRendering(this);
  1011. m_RenderGraphContext.cmd = parameters.commandBuffer;
  1012. m_RenderGraphContext.renderContext = parameters.scriptableRenderContext;
  1013. m_RenderGraphContext.contextlessTesting = parameters.invalidContextForTesting;
  1014. m_RenderGraphContext.renderGraphPool = m_RenderGraphPool;
  1015. m_RenderGraphContext.defaultResources = m_DefaultResources;
  1016. if (m_DebugParameters.immediateMode)
  1017. {
  1018. UpdateCurrentCompiledGraph(graphHash: -1, forceNoCaching: true);
  1019. LogFrameInformation();
  1020. // Prepare the list of compiled pass info for immediate mode.
  1021. // Conservative resize because we don't know how many passes there will be.
  1022. // We might still need to grow the array later on anyway if it's not enough.
  1023. m_CurrentCompiledGraph.compiledPassInfos.Resize(m_CurrentCompiledGraph.compiledPassInfos.capacity);
  1024. m_CurrentImmediatePassIndex = 0;
  1025. for (int i = 0; i < (int)RenderGraphResourceType.Count; ++i)
  1026. {
  1027. if (m_ImmediateModeResourceList[i] == null)
  1028. m_ImmediateModeResourceList[i] = new List<int>();
  1029. m_ImmediateModeResourceList[i].Clear();
  1030. }
  1031. m_Resources.BeginExecute(m_CurrentFrameIndex);
  1032. }
  1033. }
  1034. /// <summary>
  1035. /// Ends the recording and executes the render graph.
  1036. /// This must be called once all passes have been added to the render graph.
  1037. /// </summary>
  1038. public void EndRecordingAndExecute()
  1039. {
  1040. Execute();
  1041. }
  1042. /// <summary>
  1043. /// Execute the Render Graph in its current state.
  1044. /// </summary>
  1045. internal void Execute()
  1046. {
  1047. m_ExecutionExceptionWasRaised = false;
  1048. try
  1049. {
  1050. #if DEVELOPMENT_BUILD || UNITY_EDITOR
  1051. if (m_RenderGraphContext.cmd == null)
  1052. throw new InvalidOperationException("RenderGraph.BeginRecording was not called before executing the render graph.");
  1053. #endif
  1054. if (!m_DebugParameters.immediateMode)
  1055. {
  1056. LogFrameInformation();
  1057. int graphHash = 0;
  1058. if (m_EnableCompilationCaching)
  1059. graphHash = ComputeGraphHash();
  1060. if (nativeRenderPassesEnabled)
  1061. CompileNativeRenderGraph(graphHash);
  1062. else
  1063. CompileRenderGraph(graphHash);
  1064. m_Resources.BeginExecute(m_CurrentFrameIndex);
  1065. #if UNITY_EDITOR
  1066. // Feeding Render Graph Viewer before resource deallocation at pass execution
  1067. GenerateDebugData();
  1068. #endif
  1069. if (nativeRenderPassesEnabled)
  1070. ExecuteNativeRenderGraph();
  1071. else
  1072. ExecuteRenderGraph();
  1073. }
  1074. }
  1075. catch (Exception e)
  1076. {
  1077. if (m_RenderGraphContext.contextlessTesting)
  1078. {
  1079. // Throw it for the tests to handle
  1080. throw;
  1081. }
  1082. else
  1083. {
  1084. // If we're not testing log the exception and swallow it.
  1085. // TODO: Do we really want to swallow exceptions here? Not a very c# thing to do.
  1086. Debug.LogError("Render Graph Execution error");
  1087. if (!m_ExecutionExceptionWasRaised) // Already logged. TODO: There is probably a better way in C# to handle that.
  1088. Debug.LogException(e);
  1089. m_ExecutionExceptionWasRaised = true;
  1090. }
  1091. }
  1092. finally
  1093. {
  1094. if (m_DebugParameters.immediateMode)
  1095. ReleaseImmediateModeResources();
  1096. ClearCompiledGraph(m_CurrentCompiledGraph, m_EnableCompilationCaching);
  1097. m_Resources.EndExecute();
  1098. InvalidateContext();
  1099. m_HasRenderGraphBegun = false;
  1100. }
  1101. }
  1102. class ProfilingScopePassData
  1103. {
  1104. public ProfilingSampler sampler;
  1105. }
  1106. const string k_BeginProfilingSamplerPassName = "BeginProfile";
  1107. const string k_EndProfilingSamplerPassName = "EndProfile";
  1108. /// <summary>
  1109. /// Begin a profiling scope.
  1110. /// </summary>
  1111. /// <param name="sampler">Sampler used for profiling.</param>
  1112. /// <param name="file">File name of the source file this function is called from. Used for debugging. This parameter is automatically generated by the compiler. Users do not need to pass it.</param>
  1113. /// <param name="line">File line of the source file this function is called from. Used for debugging. This parameter is automatically generated by the compiler. Users do not need to pass it.</param>
  1114. public void BeginProfilingSampler(ProfilingSampler sampler,
  1115. [CallerFilePath] string file = "",
  1116. [CallerLineNumber] int line = 0)
  1117. {
  1118. if (sampler == null)
  1119. return;
  1120. using (var builder = AddRenderPass<ProfilingScopePassData>(k_BeginProfilingSamplerPassName, out var passData, (ProfilingSampler)null, file, line))
  1121. {
  1122. passData.sampler = sampler;
  1123. builder.AllowPassCulling(false);
  1124. builder.GenerateDebugData(false);
  1125. builder.SetRenderFunc((ProfilingScopePassData data, RenderGraphContext ctx) =>
  1126. {
  1127. data.sampler.Begin(ctx.cmd);
  1128. });
  1129. }
  1130. }
  1131. /// <summary>
  1132. /// End a profiling scope.
  1133. /// </summary>
  1134. /// <param name="sampler">Sampler used for profiling.</param>
  1135. /// <param name="file">File name of the source file this function is called from. Used for debugging. This parameter is automatically generated by the compiler. Users do not need to pass it.</param>
  1136. /// <param name="line">File line of the source file this function is called from. Used for debugging. This parameter is automatically generated by the compiler. Users do not need to pass it.</param>
  1137. public void EndProfilingSampler(ProfilingSampler sampler,
  1138. [CallerFilePath] string file = "",
  1139. [CallerLineNumber] int line = 0)
  1140. {
  1141. if (sampler == null)
  1142. return;
  1143. using (var builder = AddRenderPass<ProfilingScopePassData>(k_EndProfilingSamplerPassName, out var passData, (ProfilingSampler)null, file, line))
  1144. {
  1145. passData.sampler = sampler;
  1146. builder.AllowPassCulling(false);
  1147. builder.GenerateDebugData(false);
  1148. builder.SetRenderFunc((ProfilingScopePassData data, RenderGraphContext ctx) =>
  1149. {
  1150. data.sampler.End(ctx.cmd);
  1151. });
  1152. }
  1153. }
  1154. #endregion
  1155. #region Internal Interface
  1156. // Internal for testing purpose only
  1157. internal DynamicArray<CompiledPassInfo> GetCompiledPassInfos() { return m_CurrentCompiledGraph.compiledPassInfos; }
  1158. // Internal for testing purpose only
  1159. internal void ClearCompiledGraph()
  1160. {
  1161. ClearCompiledGraph(m_CurrentCompiledGraph, false);
  1162. }
  1163. void ClearCompiledGraph(CompiledGraph compiledGraph, bool useCompilationCaching)
  1164. {
  1165. ClearRenderPasses();
  1166. m_Resources.Clear(m_ExecutionExceptionWasRaised);
  1167. m_RendererLists.Clear();
  1168. registeredGlobals.Clear();
  1169. // When using compilation caching, we need to keep alive the result of the compiled graph.
  1170. if (!useCompilationCaching)
  1171. {
  1172. if (!nativeRenderPassesEnabled)
  1173. compiledGraph?.Clear();
  1174. }
  1175. }
  1176. void InvalidateContext()
  1177. {
  1178. m_RenderGraphContext.cmd = null;
  1179. m_RenderGraphContext.renderGraphPool = null;
  1180. m_RenderGraphContext.defaultResources = null;
  1181. }
  1182. internal void OnPassAdded(RenderGraphPass pass)
  1183. {
  1184. if (m_DebugParameters.immediateMode)
  1185. {
  1186. ExecutePassImmediatly(pass);
  1187. }
  1188. }
  1189. internal delegate void OnGraphRegisteredDelegate(RenderGraph graph);
  1190. internal static event OnGraphRegisteredDelegate onGraphRegistered;
  1191. internal static event OnGraphRegisteredDelegate onGraphUnregistered;
  1192. internal delegate void OnExecutionRegisteredDelegate(RenderGraph graph, string executionName);
  1193. internal static event OnExecutionRegisteredDelegate onExecutionRegistered;
  1194. internal static event OnExecutionRegisteredDelegate onExecutionUnregistered;
  1195. internal static event Action onDebugDataCaptured;
  1196. #endregion
  1197. #region Private Interface
  1198. // Internal for testing purpose only.
  1199. internal int ComputeGraphHash()
  1200. {
  1201. using (new ProfilingScope(ProfilingSampler.Get(RenderGraphProfileId.ComputeHashRenderGraph)))
  1202. {
  1203. int hash = 0;
  1204. for (int i = 0; i < m_RenderPasses.Count; ++i)
  1205. hash = hash * 23 + m_RenderPasses[i].ComputeHash(m_Resources);
  1206. return hash;
  1207. }
  1208. }
  1209. void CountReferences()
  1210. {
  1211. var compiledPassInfo = m_CurrentCompiledGraph.compiledPassInfos;
  1212. var compiledResourceInfo = m_CurrentCompiledGraph.compiledResourcesInfos;
  1213. for (int passIndex = 0; passIndex < compiledPassInfo.size; ++passIndex)
  1214. {
  1215. RenderGraphPass pass = m_RenderPasses[passIndex];
  1216. ref CompiledPassInfo passInfo = ref compiledPassInfo[passIndex];
  1217. for (int type = 0; type < (int)RenderGraphResourceType.Count; ++type)
  1218. {
  1219. var resourceRead = pass.resourceReadLists[type];
  1220. foreach (var resource in resourceRead)
  1221. {
  1222. ref CompiledResourceInfo info = ref compiledResourceInfo[type][resource.index];
  1223. info.imported = m_Resources.IsRenderGraphResourceImported(resource);
  1224. info.consumers.Add(passIndex);
  1225. info.refCount++;
  1226. #if DEVELOPMENT_BUILD || UNITY_EDITOR
  1227. passInfo.debugResourceReads[type].Add(m_Resources.GetRenderGraphResourceName(resource));
  1228. #endif
  1229. }
  1230. var resourceWrite = pass.resourceWriteLists[type];
  1231. foreach (var resource in resourceWrite)
  1232. {
  1233. ref CompiledResourceInfo info = ref compiledResourceInfo[type][resource.index];
  1234. info.imported = m_Resources.IsRenderGraphResourceImported(resource);
  1235. info.producers.Add(passIndex);
  1236. // 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.
  1237. passInfo.hasSideEffect = info.imported;
  1238. passInfo.refCount++;
  1239. #if DEVELOPMENT_BUILD || UNITY_EDITOR
  1240. passInfo.debugResourceWrites[type].Add(m_Resources.GetRenderGraphResourceName(resource));
  1241. #endif
  1242. }
  1243. foreach (var resource in pass.transientResourceList[type])
  1244. {
  1245. ref CompiledResourceInfo info = ref compiledResourceInfo[type][resource.index];
  1246. info.refCount++;
  1247. info.consumers.Add(passIndex);
  1248. info.producers.Add(passIndex);
  1249. }
  1250. }
  1251. }
  1252. }
  1253. void CullUnusedPasses()
  1254. {
  1255. if (m_DebugParameters.disablePassCulling)
  1256. {
  1257. if (m_DebugParameters.enableLogging)
  1258. {
  1259. m_FrameInformationLogger.LogLine("- Pass Culling Disabled -\n");
  1260. }
  1261. return;
  1262. }
  1263. // This will cull all passes that produce resource that are never read.
  1264. for (int type = 0; type < (int)RenderGraphResourceType.Count; ++type)
  1265. {
  1266. DynamicArray<CompiledResourceInfo> resourceUsageList = m_CurrentCompiledGraph.compiledResourcesInfos[type];
  1267. // Gather resources that are never read.
  1268. m_CullingStack.Clear();
  1269. for (int i = 1; i < resourceUsageList.size; ++i) // 0 == null resource skip it
  1270. {
  1271. if (resourceUsageList[i].refCount == 0)
  1272. {
  1273. m_CullingStack.Push(i);
  1274. }
  1275. }
  1276. while (m_CullingStack.Count != 0)
  1277. {
  1278. var unusedResource = resourceUsageList[m_CullingStack.Pop()];
  1279. foreach (var producerIndex in unusedResource.producers)
  1280. {
  1281. ref var producerInfo = ref m_CurrentCompiledGraph.compiledPassInfos[producerIndex];
  1282. var producerPass = m_RenderPasses[producerIndex];
  1283. producerInfo.refCount--;
  1284. if (producerInfo.refCount == 0 && !producerInfo.hasSideEffect && producerInfo.allowPassCulling)
  1285. {
  1286. // Producer is not necessary anymore as it produces zero resources
  1287. // Cull it and decrement refCount of all the textures it reads.
  1288. producerInfo.culled = true;
  1289. foreach (var resource in producerPass.resourceReadLists[type])
  1290. {
  1291. ref CompiledResourceInfo resourceInfo = ref resourceUsageList[resource.index];
  1292. resourceInfo.refCount--;
  1293. // If a resource is not used anymore, add it to the stack to be processed in subsequent iteration.
  1294. if (resourceInfo.refCount == 0)
  1295. m_CullingStack.Push(resource.index);
  1296. }
  1297. }
  1298. }
  1299. }
  1300. }
  1301. LogCulledPasses();
  1302. }
  1303. void UpdatePassSynchronization(ref CompiledPassInfo currentPassInfo, ref CompiledPassInfo producerPassInfo, int currentPassIndex, int lastProducer, ref int intLastSyncIndex)
  1304. {
  1305. // Current pass needs to wait for pass index lastProducer
  1306. currentPassInfo.syncToPassIndex = lastProducer;
  1307. // Update latest pass waiting for the other pipe.
  1308. intLastSyncIndex = lastProducer;
  1309. // Producer will need a graphics fence that this pass will wait on.
  1310. producerPassInfo.needGraphicsFence = true;
  1311. // We update the producer pass with the index of the smallest pass waiting for it.
  1312. // This will be used to "lock" resource from being reused until the pipe has been synchronized.
  1313. if (producerPassInfo.syncFromPassIndex == -1)
  1314. producerPassInfo.syncFromPassIndex = currentPassIndex;
  1315. }
  1316. void UpdateResourceSynchronization(ref int lastGraphicsPipeSync, ref int lastComputePipeSync, int currentPassIndex, in CompiledResourceInfo resource)
  1317. {
  1318. int lastProducer = GetLatestProducerIndex(currentPassIndex, resource);
  1319. if (lastProducer != -1)
  1320. {
  1321. var compiledPassInfo = m_CurrentCompiledGraph.compiledPassInfos;
  1322. ref CompiledPassInfo currentPassInfo = ref compiledPassInfo[currentPassIndex];
  1323. //If the passes are on different pipes, we need synchronization.
  1324. if (m_CurrentCompiledGraph.compiledPassInfos[lastProducer].enableAsyncCompute != currentPassInfo.enableAsyncCompute)
  1325. {
  1326. // Pass is on compute pipe, need sync with graphics pipe.
  1327. if (currentPassInfo.enableAsyncCompute)
  1328. {
  1329. if (lastProducer > lastGraphicsPipeSync)
  1330. {
  1331. UpdatePassSynchronization(ref currentPassInfo, ref compiledPassInfo[lastProducer], currentPassIndex, lastProducer, ref lastGraphicsPipeSync);
  1332. }
  1333. }
  1334. else
  1335. {
  1336. if (lastProducer > lastComputePipeSync)
  1337. {
  1338. UpdatePassSynchronization(ref currentPassInfo, ref compiledPassInfo[lastProducer], currentPassIndex, lastProducer, ref lastComputePipeSync);
  1339. }
  1340. }
  1341. }
  1342. }
  1343. }
  1344. int GetFirstValidConsumerIndex(int passIndex, in CompiledResourceInfo info)
  1345. {
  1346. var compiledPassInfo = m_CurrentCompiledGraph.compiledPassInfos;
  1347. // We want to know the lowest pass index after the current pass that reads from the resource.
  1348. foreach (int consumer in info.consumers)
  1349. {
  1350. // consumers are by construction in increasing order.
  1351. if (consumer > passIndex && !compiledPassInfo[consumer].culled)
  1352. return consumer;
  1353. }
  1354. return -1;
  1355. }
  1356. int FindTextureProducer(int consumerPass, in CompiledResourceInfo info, out int index)
  1357. {
  1358. // We check all producers before the consumerPass. The first one not culled will be the one allocating the resource
  1359. // If they are all culled, we need to get the one right before the consumer, it will allocate or reuse the resource
  1360. var compiledPassInfo = m_CurrentCompiledGraph.compiledPassInfos;
  1361. int previousPass = 0;
  1362. for (index = 0; index < info.producers.Count; index++)
  1363. {
  1364. int currentPass = info.producers[index];
  1365. // We found a valid producer - he will allocate the texture
  1366. if (!compiledPassInfo[currentPass].culled)
  1367. return currentPass;
  1368. // We reached consumer pass, return last producer even if it's culled
  1369. if (currentPass >= consumerPass)
  1370. return previousPass;
  1371. previousPass = currentPass;
  1372. }
  1373. return previousPass;
  1374. }
  1375. int GetLatestProducerIndex(int passIndex, in CompiledResourceInfo info)
  1376. {
  1377. // We want to know the highest pass index below the current pass that writes to the resource.
  1378. int result = -1;
  1379. var compiledPassInfo = m_CurrentCompiledGraph.compiledPassInfos;
  1380. foreach (var producer in info.producers)
  1381. {
  1382. var producerPassInfo = compiledPassInfo[producer];
  1383. // producers are by construction in increasing order.
  1384. // We also need to make sure we don't return a pass that was culled (can happen at this point because of renderer list culling).
  1385. if (producer < passIndex && !(producerPassInfo.culled || producerPassInfo.culledByRendererList))
  1386. result = producer;
  1387. else
  1388. return result;
  1389. }
  1390. return result;
  1391. }
  1392. int GetLatestValidReadIndex(in CompiledResourceInfo info)
  1393. {
  1394. if (info.consumers.Count == 0)
  1395. return -1;
  1396. var compiledPassInfo = m_CurrentCompiledGraph.compiledPassInfos;
  1397. var consumers = info.consumers;
  1398. for (int i = consumers.Count - 1; i >= 0; --i)
  1399. {
  1400. if (!compiledPassInfo[consumers[i]].culled)
  1401. return consumers[i];
  1402. }
  1403. return -1;
  1404. }
  1405. int GetFirstValidWriteIndex(in CompiledResourceInfo info)
  1406. {
  1407. if (info.producers.Count == 0)
  1408. return -1;
  1409. var compiledPassInfo = m_CurrentCompiledGraph.compiledPassInfos;
  1410. var producers = info.producers;
  1411. for (int i = 0; i < producers.Count; i++)
  1412. {
  1413. if (!compiledPassInfo[producers[i]].culled)
  1414. return producers[i];
  1415. }
  1416. return -1;
  1417. }
  1418. int GetLatestValidWriteIndex(in CompiledResourceInfo info)
  1419. {
  1420. if (info.producers.Count == 0)
  1421. return -1;
  1422. var compiledPassInfo = m_CurrentCompiledGraph.compiledPassInfos;
  1423. var producers = info.producers;
  1424. for (int i = producers.Count - 1; i >= 0; --i)
  1425. {
  1426. if (!compiledPassInfo[producers[i]].culled)
  1427. return producers[i];
  1428. }
  1429. return -1;
  1430. }
  1431. void CreateRendererLists()
  1432. {
  1433. var compiledPassInfo = m_CurrentCompiledGraph.compiledPassInfos;
  1434. for (int passIndex = 0; passIndex < compiledPassInfo.size; ++passIndex)
  1435. {
  1436. ref CompiledPassInfo passInfo = ref compiledPassInfo[passIndex];
  1437. if (passInfo.culled)
  1438. continue;
  1439. // Gather all renderer lists
  1440. m_RendererLists.AddRange(m_RenderPasses[passInfo.index].usedRendererListList);
  1441. }
  1442. // Anything related to renderer lists needs a real context to be able to use/test it
  1443. Debug.Assert(m_RendererLists.Count == 0 || m_RenderGraphContext.contextlessTesting == false);
  1444. // Creates all renderer lists
  1445. m_Resources.CreateRendererLists(m_RendererLists, m_RenderGraphContext.renderContext, m_RendererListCulling);
  1446. }
  1447. internal bool GetImportedFallback(TextureDesc desc, out TextureHandle fallback)
  1448. {
  1449. fallback = TextureHandle.nullHandle;
  1450. // We don't have any fallback texture with MSAA
  1451. if (!desc.bindTextureMS)
  1452. {
  1453. if (desc.depthBufferBits != DepthBits.None)
  1454. {
  1455. fallback = defaultResources.whiteTexture;
  1456. }
  1457. else if (desc.clearColor == Color.black || desc.clearColor == default)
  1458. {
  1459. if (desc.dimension == TextureXR.dimension)
  1460. fallback = defaultResources.blackTextureXR;
  1461. else if (desc.dimension == TextureDimension.Tex3D)
  1462. fallback = defaultResources.blackTexture3DXR;
  1463. else if (desc.dimension == TextureDimension.Tex2D)
  1464. fallback = defaultResources.blackTexture;
  1465. }
  1466. else if (desc.clearColor == Color.white)
  1467. {
  1468. if (desc.dimension == TextureXR.dimension)
  1469. fallback = defaultResources.whiteTextureXR;
  1470. else if (desc.dimension == TextureDimension.Tex2D)
  1471. fallback = defaultResources.whiteTexture;
  1472. }
  1473. }
  1474. return fallback.IsValid();
  1475. }
  1476. void AllocateCulledPassResources(ref CompiledPassInfo passInfo)
  1477. {
  1478. var passIndex = passInfo.index;
  1479. var pass = m_RenderPasses[passIndex];
  1480. for (int type = 0; type < (int)RenderGraphResourceType.Count; ++type)
  1481. {
  1482. var resourcesInfo = m_CurrentCompiledGraph.compiledResourcesInfos[type];
  1483. foreach (var resourceHandle in pass.resourceWriteLists[type])
  1484. {
  1485. ref var compiledResource = ref resourcesInfo[resourceHandle.index];
  1486. // Check if there is a valid consumer and no other valid producer
  1487. int consumerPass = GetFirstValidConsumerIndex(passIndex, compiledResource);
  1488. int producerPass = FindTextureProducer(consumerPass, compiledResource, out int index);
  1489. if (consumerPass != -1 && passIndex == producerPass)
  1490. {
  1491. if (type == (int)RenderGraphResourceType.Texture)
  1492. {
  1493. // Try to transform into an imported resource - for some textures, this will save an allocation
  1494. // We have a way to disable the fallback, because we can't fallback to RenderTexture and sometimes it's necessary (eg. SampleCopyChannel_xyzw2x)
  1495. var textureResource = m_Resources.GetTextureResource(resourceHandle);
  1496. if (!textureResource.desc.disableFallBackToImportedTexture && GetImportedFallback(textureResource.desc, out var fallback))
  1497. {
  1498. compiledResource.imported = true;
  1499. textureResource.imported = true;
  1500. textureResource.graphicsResource = m_Resources.GetTexture(fallback);
  1501. continue;
  1502. }
  1503. textureResource.desc.sizeMode = TextureSizeMode.Explicit;
  1504. textureResource.desc.width = 1;
  1505. textureResource.desc.height = 1;
  1506. textureResource.desc.clearBuffer = true;
  1507. }
  1508. // Delegate resource allocation to the consumer
  1509. compiledResource.producers[index - 1] = consumerPass;
  1510. }
  1511. }
  1512. }
  1513. }
  1514. void UpdateResourceAllocationAndSynchronization()
  1515. {
  1516. int lastGraphicsPipeSync = -1;
  1517. int lastComputePipeSync = -1;
  1518. var compiledPassInfo = m_CurrentCompiledGraph.compiledPassInfos;
  1519. var compiledResourceInfo = m_CurrentCompiledGraph.compiledResourcesInfos;
  1520. // First go through all passes.
  1521. // - Update the last pass read index for each resource.
  1522. // - Add texture to creation list for passes that first write to a texture.
  1523. // - Update synchronization points for all resources between compute and graphics pipes.
  1524. for (int passIndex = 0; passIndex < compiledPassInfo.size; ++passIndex)
  1525. {
  1526. ref CompiledPassInfo passInfo = ref compiledPassInfo[passIndex];
  1527. // If this pass is culled, we need to make sure that any texture read by a later pass is still allocated
  1528. // We also try to find an imported fallback to save an allocation
  1529. if (passInfo.culledByRendererList)
  1530. AllocateCulledPassResources(ref passInfo);
  1531. if (passInfo.culled)
  1532. continue;
  1533. var pass = m_RenderPasses[passInfo.index];
  1534. for (int type = 0; type < (int)RenderGraphResourceType.Count; ++type)
  1535. {
  1536. var resourcesInfo = compiledResourceInfo[type];
  1537. foreach (var resource in pass.resourceReadLists[type])
  1538. {
  1539. UpdateResourceSynchronization(ref lastGraphicsPipeSync, ref lastComputePipeSync, passIndex, resourcesInfo[resource.index]);
  1540. }
  1541. foreach (var resource in pass.resourceWriteLists[type])
  1542. {
  1543. UpdateResourceSynchronization(ref lastGraphicsPipeSync, ref lastComputePipeSync, passIndex, resourcesInfo[resource.index]);
  1544. }
  1545. }
  1546. }
  1547. for (int type = 0; type < (int)RenderGraphResourceType.Count; ++type)
  1548. {
  1549. var resourceInfos = compiledResourceInfo[type];
  1550. // Now push resources to the release list of the pass that reads it last.
  1551. for (int i = 1; i < resourceInfos.size; ++i) // 0 == null resource skip it
  1552. {
  1553. CompiledResourceInfo resourceInfo = resourceInfos[i];
  1554. bool sharedResource = m_Resources.IsRenderGraphResourceShared((RenderGraphResourceType)type, i);
  1555. bool forceRelease = m_Resources.IsRenderGraphResourceForceReleased((RenderGraphResourceType) type, i);
  1556. // Imported resource needs neither creation nor release.
  1557. if (resourceInfo.imported && !sharedResource && !forceRelease)
  1558. continue;
  1559. // Resource creation
  1560. int firstWriteIndex = GetFirstValidWriteIndex(resourceInfo);
  1561. // Index -1 can happen for imported resources (for example an imported dummy black texture will never be written to but does not need creation anyway)
  1562. // Or when the only pass that was writting to this resource was culled dynamically by renderer lists
  1563. if (firstWriteIndex != -1)
  1564. compiledPassInfo[firstWriteIndex].resourceCreateList[type].Add(i);
  1565. var latestValidReadIndex = GetLatestValidReadIndex(resourceInfo);
  1566. var latestValidWriteIndex = GetLatestValidWriteIndex(resourceInfo);
  1567. // Sometimes, a texture can be written by a pass after the last pass that reads it.
  1568. // In this case, we need to extend its lifetime to this pass otherwise the pass would get an invalid texture.
  1569. // This is exhibited in cases where a pass might produce more than one output and one of them isn't used.
  1570. // Ex: Transparent pass in HDRP that writes to the color buffer and motion vectors.
  1571. // If TAA/MotionBlur aren't used, the movecs are never read after the transparent pass and it would raise this error.
  1572. // Because of that, it's hard to make this an actual error.
  1573. // Commented out code to check such cases if needed.
  1574. //if (latestValidReadIndex != -1 && (latestValidWriteIndex > latestValidReadIndex))
  1575. //{
  1576. // var name = m_Resources.GetRenderGraphResourceName((RenderGraphResourceType)type, i);
  1577. // var lastPassReadName = m_CompiledPassInfos[latestValidReadIndex].pass.name;
  1578. // var lastPassWriteName = m_CompiledPassInfos[latestValidWriteIndex].pass.name;
  1579. // Debug.LogError($"Resource {name} is written again after the last pass that reads it.\nLast pass read: {lastPassReadName}\nLast pass write: {lastPassWriteName}");
  1580. //}
  1581. // For not imported resources, make sure we don't try to release them if they were never created (due to culling).
  1582. bool shouldRelease = !(firstWriteIndex == -1 && !resourceInfo.imported);
  1583. int lastReadPassIndex = shouldRelease ? Math.Max(latestValidWriteIndex, latestValidReadIndex) : -1;
  1584. // Texture release
  1585. if (lastReadPassIndex != -1)
  1586. {
  1587. // 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.
  1588. // 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.
  1589. if (compiledPassInfo[lastReadPassIndex].enableAsyncCompute)
  1590. {
  1591. int currentPassIndex = lastReadPassIndex;
  1592. int firstWaitingPassIndex = compiledPassInfo[currentPassIndex].syncFromPassIndex;
  1593. // Find the first async pass that is synchronized by the graphics pipeline (ie: passInfo.syncFromPassIndex != -1)
  1594. while (firstWaitingPassIndex == -1 && currentPassIndex++ < compiledPassInfo.size - 1)
  1595. {
  1596. if (compiledPassInfo[currentPassIndex].enableAsyncCompute)
  1597. firstWaitingPassIndex = compiledPassInfo[currentPassIndex].syncFromPassIndex;
  1598. }
  1599. // Fail safe in case render graph is badly formed.
  1600. if (currentPassIndex == compiledPassInfo.size)
  1601. {
  1602. // This is not true with passes with side effect as they are writing to a resource that may not be read by the render graph this frame and to no other resource.
  1603. // In this case we extend the lifetime of resources to the end of the frame. It's not idea but it should not be the majority of cases.
  1604. if (compiledPassInfo[lastReadPassIndex].hasSideEffect)
  1605. {
  1606. firstWaitingPassIndex = currentPassIndex;
  1607. }
  1608. else
  1609. {
  1610. RenderGraphPass invalidPass = m_RenderPasses[lastReadPassIndex];
  1611. var resName = "<unknown>";
  1612. #if DEVELOPMENT_BUILD || UNITY_EDITOR
  1613. resName = m_Resources.GetRenderGraphResourceName((RenderGraphResourceType)type, i);
  1614. #endif
  1615. var msg = $"{(RenderGraphResourceType)type} resource '{resName}' in asynchronous pass '{invalidPass.name}' is missing synchronization on the graphics pipeline.";
  1616. throw new InvalidOperationException(msg);
  1617. }
  1618. }
  1619. // Finally add the release command to the pass before the first pass that waits for the compute pipe.
  1620. var releasePassIndex = Math.Max(0, firstWaitingPassIndex - 1);
  1621. // Check to ensure that we do not release resources on a culled pass (causes a leak otherwise).
  1622. while (compiledPassInfo[releasePassIndex].culled)
  1623. releasePassIndex = Math.Max(0, releasePassIndex - 1);
  1624. ref CompiledPassInfo passInfo = ref compiledPassInfo[releasePassIndex];
  1625. passInfo.resourceReleaseList[type].Add(i);
  1626. }
  1627. else
  1628. {
  1629. ref CompiledPassInfo passInfo = ref compiledPassInfo[lastReadPassIndex];
  1630. passInfo.resourceReleaseList[type].Add(i);
  1631. }
  1632. }
  1633. if (sharedResource && (firstWriteIndex != -1 || lastReadPassIndex != -1)) // A shared resource is considered used if it's either read or written at any pass.
  1634. {
  1635. m_Resources.UpdateSharedResourceLastFrameIndex(type, i);
  1636. }
  1637. }
  1638. }
  1639. }
  1640. void UpdateAllSharedResourceLastFrameIndex()
  1641. {
  1642. for (int type = 0; type < (int)RenderGraphResourceType.Count; ++type)
  1643. {
  1644. var resourceInfos = m_CurrentCompiledGraph.compiledResourcesInfos[type];
  1645. var sharedResourceCount = m_Resources.GetSharedResourceCount((RenderGraphResourceType)type);
  1646. for (int i = 1; i <= sharedResourceCount; ++i) // 0 == null resource skip it
  1647. {
  1648. CompiledResourceInfo resourceInfo = resourceInfos[i];
  1649. var latestValidReadIndex = GetLatestValidReadIndex(resourceInfo);
  1650. int firstWriteIndex = GetFirstValidWriteIndex(resourceInfo);
  1651. if ((firstWriteIndex != -1 || latestValidReadIndex != -1)) // A shared resource is considered used if it's either read or written at any pass.
  1652. {
  1653. m_Resources.UpdateSharedResourceLastFrameIndex(type, i);
  1654. }
  1655. }
  1656. }
  1657. }
  1658. bool AreRendererListsEmpty(List<RendererListHandle> rendererLists)
  1659. {
  1660. // Anything related to renderer lists needs a real context to be able to use/test it
  1661. Debug.Assert(m_RenderGraphContext.contextlessTesting == false);
  1662. foreach (RendererListHandle handle in rendererLists)
  1663. {
  1664. var rendererList = m_Resources.GetRendererList(handle);
  1665. if (m_RenderGraphContext.renderContext.QueryRendererListStatus(rendererList) == RendererListStatus.kRendererListPopulated)
  1666. {
  1667. return false;
  1668. }
  1669. }
  1670. // If the list of RendererLists is empty, then the default behavior is to not cull, so return false.
  1671. return rendererLists.Count > 0 ? true : false;
  1672. }
  1673. void TryCullPassAtIndex(int passIndex)
  1674. {
  1675. var compiledPassInfo = m_CurrentCompiledGraph.compiledPassInfos;
  1676. ref var compiledPass = ref compiledPassInfo[passIndex];
  1677. var pass = m_RenderPasses[passIndex];
  1678. if (!compiledPass.culled &&
  1679. pass.allowPassCulling &&
  1680. pass.allowRendererListCulling &&
  1681. !compiledPass.hasSideEffect)
  1682. {
  1683. if (AreRendererListsEmpty(pass.usedRendererListList))
  1684. {
  1685. //Debug.Log($"Culling pass <color=red> {pass.name} </color>");
  1686. compiledPass.culled = compiledPass.culledByRendererList = true;
  1687. }
  1688. }
  1689. }
  1690. void CullRendererLists()
  1691. {
  1692. var compiledPassInfo = m_CurrentCompiledGraph.compiledPassInfos;
  1693. for (int passIndex = 0; passIndex < compiledPassInfo.size; ++passIndex)
  1694. {
  1695. var compiledPass = compiledPassInfo[passIndex];
  1696. if (!compiledPass.culled && !compiledPass.hasSideEffect)
  1697. {
  1698. var pass = m_RenderPasses[passIndex];
  1699. if (pass.usedRendererListList.Count > 0)
  1700. {
  1701. TryCullPassAtIndex(passIndex);
  1702. }
  1703. }
  1704. }
  1705. }
  1706. bool UpdateCurrentCompiledGraph(int graphHash, bool forceNoCaching = false)
  1707. {
  1708. bool cached = false;
  1709. if (m_EnableCompilationCaching && !forceNoCaching)
  1710. cached = m_CompilationCache.GetCompilationCache(graphHash, m_ExecutionCount, out m_CurrentCompiledGraph);
  1711. else
  1712. m_CurrentCompiledGraph = m_DefaultCompiledGraph;
  1713. return cached;
  1714. }
  1715. // Internal visibility for testing purpose only
  1716. // Traverse the render graph:
  1717. // - Determines when resources are created/released
  1718. // - Determines async compute pass synchronization
  1719. // - Cull unused render passes.
  1720. internal void CompileRenderGraph(int graphHash)
  1721. {
  1722. using (new ProfilingScope(m_RenderGraphContext.cmd, ProfilingSampler.Get(RenderGraphProfileId.CompileRenderGraph)))
  1723. {
  1724. bool compilationIsCached = UpdateCurrentCompiledGraph(graphHash);
  1725. if (!compilationIsCached)
  1726. {
  1727. m_CurrentCompiledGraph.Clear();
  1728. m_CurrentCompiledGraph.InitializeCompilationData(m_RenderPasses, m_Resources);
  1729. CountReferences();
  1730. // First cull all passes that produce unused output
  1731. CullUnusedPasses();
  1732. }
  1733. // Create the renderer lists of the remaining passes
  1734. CreateRendererLists();
  1735. if (!compilationIsCached)
  1736. {
  1737. // Cull dynamically the graph passes based on the renderer list visibility
  1738. if (m_RendererListCulling)
  1739. CullRendererLists();
  1740. // After all culling passes, allocate the resources for this frame
  1741. UpdateResourceAllocationAndSynchronization();
  1742. }
  1743. else
  1744. {
  1745. // We need to update all shared resource frame index usage otherwise they might not be in a valid state.
  1746. // Otherwise it's done in UpdateResourceAllocationAndSynchronization().
  1747. UpdateAllSharedResourceLastFrameIndex();
  1748. }
  1749. LogRendererListsCreation();
  1750. }
  1751. }
  1752. ref CompiledPassInfo CompilePassImmediatly(RenderGraphPass pass)
  1753. {
  1754. var compiledPassInfo = m_CurrentCompiledGraph.compiledPassInfos;
  1755. // If we don't have enough pre allocated elements we double the size.
  1756. // It's pretty aggressive but the immediate mode is only for debug purpose so it should be fine.
  1757. if (m_CurrentImmediatePassIndex >= compiledPassInfo.size)
  1758. compiledPassInfo.Resize(compiledPassInfo.size * 2);
  1759. ref CompiledPassInfo passInfo = ref compiledPassInfo[m_CurrentImmediatePassIndex++];
  1760. passInfo.Reset(pass, m_CurrentImmediatePassIndex - 1);
  1761. // In immediate mode we don't have proper information to generate synchronization so we disable async compute.
  1762. passInfo.enableAsyncCompute = false;
  1763. // In immediate mode, we don't have any resource usage information so we'll just create resources whenever they are written to if not already alive.
  1764. // We will release all resources at the end of the render graph execution.
  1765. for (int iType = 0; iType < (int)RenderGraphResourceType.Count; ++iType)
  1766. {
  1767. foreach (var res in pass.transientResourceList[iType])
  1768. {
  1769. passInfo.resourceCreateList[iType].Add(res.index);
  1770. passInfo.resourceReleaseList[iType].Add(res.index);
  1771. #if DEVELOPMENT_BUILD || UNITY_EDITOR
  1772. passInfo.debugResourceWrites[iType].Add(m_Resources.GetRenderGraphResourceName(res));
  1773. passInfo.debugResourceReads[iType].Add(m_Resources.GetRenderGraphResourceName(res));
  1774. #endif
  1775. }
  1776. foreach (var res in pass.resourceWriteLists[iType])
  1777. {
  1778. if (pass.transientResourceList[iType].Contains(res))
  1779. continue; // Prevent registering writes to transient texture twice
  1780. if (!m_Resources.IsGraphicsResourceCreated(res))
  1781. {
  1782. passInfo.resourceCreateList[iType].Add(res.index);
  1783. m_ImmediateModeResourceList[iType].Add(res.index);
  1784. }
  1785. #if DEVELOPMENT_BUILD || UNITY_EDITOR
  1786. passInfo.debugResourceWrites[iType].Add(m_Resources.GetRenderGraphResourceName(res));
  1787. #endif
  1788. }
  1789. foreach (var res in pass.resourceReadLists[iType])
  1790. {
  1791. #if DEVELOPMENT_BUILD || UNITY_EDITOR
  1792. passInfo.debugResourceReads[iType].Add(m_Resources.GetRenderGraphResourceName(res));
  1793. #endif
  1794. }
  1795. }
  1796. // Create the necessary renderer lists
  1797. foreach (var rl in pass.usedRendererListList)
  1798. {
  1799. if (!m_Resources.IsRendererListCreated(rl))
  1800. m_RendererLists.Add(rl);
  1801. }
  1802. // Anything related to renderer lists needs a real context to be able to use/test it
  1803. Debug.Assert(m_RenderGraphContext.contextlessTesting == false);
  1804. m_Resources.CreateRendererLists(m_RendererLists, m_RenderGraphContext.renderContext);
  1805. m_RendererLists.Clear();
  1806. return ref passInfo;
  1807. }
  1808. void ExecutePassImmediatly(RenderGraphPass pass)
  1809. {
  1810. ExecuteCompiledPass(ref CompilePassImmediatly(pass));
  1811. }
  1812. void ExecuteCompiledPass(ref CompiledPassInfo passInfo)
  1813. {
  1814. if (passInfo.culled)
  1815. return;
  1816. var pass = m_RenderPasses[passInfo.index];
  1817. if (!pass.HasRenderFunc())
  1818. {
  1819. throw new InvalidOperationException(string.Format("RenderPass {0} was not provided with an execute function.", pass.name));
  1820. }
  1821. try
  1822. {
  1823. using (new ProfilingScope(m_RenderGraphContext.cmd, pass.customSampler))
  1824. {
  1825. LogRenderPassBegin(passInfo);
  1826. using (new RenderGraphLogIndent(m_FrameInformationLogger))
  1827. {
  1828. m_RenderGraphContext.executingPass = pass;
  1829. PreRenderPassExecute(passInfo, pass, m_RenderGraphContext);
  1830. pass.Execute(m_RenderGraphContext);
  1831. PostRenderPassExecute(ref passInfo, pass, m_RenderGraphContext);
  1832. }
  1833. }
  1834. }
  1835. catch (Exception e)
  1836. {
  1837. // Dont log errors during tests
  1838. if (m_RenderGraphContext.contextlessTesting == false)
  1839. {
  1840. // Log exception from the pass that raised it to have improved error logging quality for users
  1841. m_ExecutionExceptionWasRaised = true;
  1842. Debug.LogError($"Render Graph execution error at pass '{pass.name}' ({passInfo.index})");
  1843. Debug.LogException(e);
  1844. }
  1845. throw;
  1846. }
  1847. }
  1848. // Execute the compiled render graph
  1849. void ExecuteRenderGraph()
  1850. {
  1851. using (new ProfilingScope(m_RenderGraphContext.cmd, ProfilingSampler.Get(RenderGraphProfileId.ExecuteRenderGraph)))
  1852. {
  1853. var compiledPassInfo = m_CurrentCompiledGraph.compiledPassInfos;
  1854. for (int passIndex = 0; passIndex < compiledPassInfo.size; ++passIndex)
  1855. {
  1856. ExecuteCompiledPass(ref compiledPassInfo[passIndex]);
  1857. }
  1858. }
  1859. }
  1860. void PreRenderPassSetRenderTargets(in CompiledPassInfo passInfo, RenderGraphPass pass, InternalRenderGraphContext rgContext)
  1861. {
  1862. var depthBufferIsValid = pass.depthAccess.textureHandle.IsValid();
  1863. if (depthBufferIsValid || pass.colorBufferMaxIndex != -1)
  1864. {
  1865. var colorBufferAccess = pass.colorBufferAccess;
  1866. if (pass.colorBufferMaxIndex > 0)
  1867. {
  1868. var mrtArray = m_TempMRTArrays[pass.colorBufferMaxIndex];
  1869. for (int i = 0; i <= pass.colorBufferMaxIndex; ++i)
  1870. {
  1871. #if DEVELOPMENT_BUILD || UNITY_EDITOR
  1872. if (!colorBufferAccess[i].textureHandle.IsValid())
  1873. throw new InvalidOperationException("MRT setup is invalid. Some indices are not used.");
  1874. #endif
  1875. mrtArray[i] = m_Resources.GetTexture(colorBufferAccess[i].textureHandle);
  1876. }
  1877. if (depthBufferIsValid)
  1878. {
  1879. CoreUtils.SetRenderTarget(rgContext.cmd, mrtArray, m_Resources.GetTexture(pass.depthAccess.textureHandle));
  1880. }
  1881. else
  1882. {
  1883. throw new InvalidOperationException("Setting MRTs without a depth buffer is not supported.");
  1884. }
  1885. }
  1886. else
  1887. {
  1888. if (depthBufferIsValid)
  1889. {
  1890. if (pass.colorBufferMaxIndex > -1)
  1891. {
  1892. CoreUtils.SetRenderTarget(rgContext.cmd, m_Resources.GetTexture(pass.colorBufferAccess[0].textureHandle),
  1893. m_Resources.GetTexture(pass.depthAccess.textureHandle));
  1894. }
  1895. else
  1896. {
  1897. CoreUtils.SetRenderTarget(rgContext.cmd, m_Resources.GetTexture(pass.depthAccess.textureHandle));
  1898. }
  1899. }
  1900. else
  1901. {
  1902. if (pass.colorBufferAccess[0].textureHandle.IsValid())
  1903. {
  1904. CoreUtils.SetRenderTarget(rgContext.cmd, m_Resources.GetTexture(pass.colorBufferAccess[0].textureHandle));
  1905. }
  1906. else
  1907. throw new InvalidOperationException("Neither Depth nor color render targets are correctly setup at pass " + pass.name + ".");
  1908. }
  1909. }
  1910. }
  1911. }
  1912. void PreRenderPassExecute(in CompiledPassInfo passInfo, RenderGraphPass pass, InternalRenderGraphContext rgContext)
  1913. {
  1914. // Need to save the command buffer to restore it later as the one in the context can changed if running a pass async.
  1915. m_PreviousCommandBuffer = rgContext.cmd;
  1916. bool executedWorkDuringResourceCreation = false;
  1917. for (int type = 0; type < (int)RenderGraphResourceType.Count; ++type)
  1918. {
  1919. foreach (int resource in passInfo.resourceCreateList[type])
  1920. {
  1921. executedWorkDuringResourceCreation |= m_Resources.CreatePooledResource(rgContext, type, resource);
  1922. }
  1923. }
  1924. if (passInfo.enableFoveatedRasterization)
  1925. rgContext.cmd.SetFoveatedRenderingMode(FoveatedRenderingMode.Enabled);
  1926. PreRenderPassSetRenderTargets(passInfo, pass, rgContext);
  1927. if (passInfo.enableAsyncCompute)
  1928. {
  1929. GraphicsFence previousFence = new GraphicsFence();
  1930. if (executedWorkDuringResourceCreation)
  1931. {
  1932. previousFence = rgContext.cmd.CreateGraphicsFence(GraphicsFenceType.AsyncQueueSynchronisation, SynchronisationStageFlags.AllGPUOperations);
  1933. }
  1934. // Flush current command buffer on the render context before enqueuing async commands.
  1935. if (rgContext.contextlessTesting == false)
  1936. rgContext.renderContext.ExecuteCommandBuffer(rgContext.cmd);
  1937. rgContext.cmd.Clear();
  1938. CommandBuffer asyncCmd = CommandBufferPool.Get(pass.name);
  1939. asyncCmd.SetExecutionFlags(CommandBufferExecutionFlags.AsyncCompute);
  1940. rgContext.cmd = asyncCmd;
  1941. if (executedWorkDuringResourceCreation)
  1942. {
  1943. rgContext.cmd.WaitOnAsyncGraphicsFence(previousFence);
  1944. }
  1945. }
  1946. // Synchronize with graphics or compute pipe if needed.
  1947. if (passInfo.syncToPassIndex != -1)
  1948. {
  1949. rgContext.cmd.WaitOnAsyncGraphicsFence(m_CurrentCompiledGraph.compiledPassInfos[passInfo.syncToPassIndex].fence);
  1950. }
  1951. }
  1952. void PostRenderPassExecute(ref CompiledPassInfo passInfo, RenderGraphPass pass, InternalRenderGraphContext rgContext)
  1953. {
  1954. foreach (var tex in pass.setGlobalsList)
  1955. {
  1956. rgContext.cmd.SetGlobalTexture(tex.Item2, tex.Item1);
  1957. }
  1958. if (passInfo.needGraphicsFence)
  1959. passInfo.fence = rgContext.cmd.CreateAsyncGraphicsFence();
  1960. if (passInfo.enableAsyncCompute)
  1961. {
  1962. // Anything related to async command buffer execution needs a real context to be able to use/test it
  1963. // As the async will likely be waited for but never finish if there is no real context
  1964. Debug.Assert(m_RenderGraphContext.contextlessTesting == false);
  1965. // The command buffer has been filled. We can kick the async task.
  1966. rgContext.renderContext.ExecuteCommandBufferAsync(rgContext.cmd, ComputeQueueType.Background);
  1967. CommandBufferPool.Release(rgContext.cmd);
  1968. rgContext.cmd = m_PreviousCommandBuffer; // Restore the main command buffer.
  1969. }
  1970. if (passInfo.enableFoveatedRasterization)
  1971. rgContext.cmd.SetFoveatedRenderingMode(FoveatedRenderingMode.Disabled);
  1972. m_RenderGraphPool.ReleaseAllTempAlloc();
  1973. for (int type = 0; type < (int)RenderGraphResourceType.Count; ++type)
  1974. {
  1975. foreach (var resource in passInfo.resourceReleaseList[type])
  1976. {
  1977. m_Resources.ReleasePooledResource(rgContext, type, resource);
  1978. }
  1979. }
  1980. }
  1981. void ClearRenderPasses()
  1982. {
  1983. foreach (var pass in m_RenderPasses)
  1984. pass.Release(m_RenderGraphPool);
  1985. m_RenderPasses.Clear();
  1986. }
  1987. void ReleaseImmediateModeResources()
  1988. {
  1989. for (int type = 0; type < (int)RenderGraphResourceType.Count; ++type)
  1990. {
  1991. foreach (var resource in m_ImmediateModeResourceList[type])
  1992. {
  1993. m_Resources.ReleasePooledResource(m_RenderGraphContext, type, resource);
  1994. }
  1995. }
  1996. }
  1997. void LogFrameInformation()
  1998. {
  1999. if (m_DebugParameters.enableLogging)
  2000. {
  2001. m_FrameInformationLogger.LogLine($"==== Staring render graph frame for: {m_CurrentExecutionName} ====");
  2002. if (!m_DebugParameters.immediateMode)
  2003. m_FrameInformationLogger.LogLine("Number of passes declared: {0}\n", m_RenderPasses.Count);
  2004. }
  2005. }
  2006. void LogRendererListsCreation()
  2007. {
  2008. if (m_DebugParameters.enableLogging)
  2009. {
  2010. m_FrameInformationLogger.LogLine("Number of renderer lists created: {0}\n", m_RendererLists.Count);
  2011. }
  2012. }
  2013. void LogRenderPassBegin(in CompiledPassInfo passInfo)
  2014. {
  2015. if (m_DebugParameters.enableLogging)
  2016. {
  2017. RenderGraphPass pass = m_RenderPasses[passInfo.index];
  2018. m_FrameInformationLogger.LogLine("[{0}][{1}] \"{2}\"", pass.index, pass.enableAsyncCompute ? "Compute" : "Graphics", pass.name);
  2019. using (new RenderGraphLogIndent(m_FrameInformationLogger))
  2020. {
  2021. if (passInfo.syncToPassIndex != -1)
  2022. m_FrameInformationLogger.LogLine("Synchronize with [{0}]", passInfo.syncToPassIndex);
  2023. }
  2024. }
  2025. }
  2026. void LogCulledPasses()
  2027. {
  2028. if (m_DebugParameters.enableLogging)
  2029. {
  2030. m_FrameInformationLogger.LogLine("Pass Culling Report:");
  2031. using (new RenderGraphLogIndent(m_FrameInformationLogger))
  2032. {
  2033. var compiledPassInfo = m_CurrentCompiledGraph.compiledPassInfos;
  2034. for (int i = 0; i < compiledPassInfo.size; ++i)
  2035. {
  2036. if (compiledPassInfo[i].culled)
  2037. {
  2038. var pass = m_RenderPasses[i];
  2039. m_FrameInformationLogger.LogLine("[{0}] {1}", pass.index, pass.name);
  2040. }
  2041. }
  2042. m_FrameInformationLogger.LogLine("\n");
  2043. }
  2044. }
  2045. }
  2046. ProfilingSampler GetDefaultProfilingSampler(string name)
  2047. {
  2048. // In non-dev builds, ProfilingSampler.Get returns null, so we'd always end up executing this.
  2049. // To avoid that we also ifdef the code out here.
  2050. #if DEVELOPMENT_BUILD || UNITY_EDITOR
  2051. int hash = name.GetHashCode();
  2052. if (!m_DefaultProfilingSamplers.TryGetValue(hash, out var sampler))
  2053. {
  2054. sampler = new ProfilingSampler(name);
  2055. m_DefaultProfilingSamplers.Add(hash, sampler);
  2056. }
  2057. return sampler;
  2058. #else
  2059. return null;
  2060. #endif
  2061. }
  2062. void UpdateImportedResourceLifeTime(ref DebugData.ResourceData data, List<int> passList)
  2063. {
  2064. foreach (var pass in passList)
  2065. {
  2066. if (data.creationPassIndex == -1)
  2067. data.creationPassIndex = pass;
  2068. else
  2069. data.creationPassIndex = Math.Min(data.creationPassIndex, pass);
  2070. if (data.releasePassIndex == -1)
  2071. data.releasePassIndex = pass;
  2072. else
  2073. data.releasePassIndex = Math.Max(data.releasePassIndex, pass);
  2074. }
  2075. }
  2076. void GenerateDebugData()
  2077. {
  2078. if (m_ExecutionExceptionWasRaised)
  2079. return;
  2080. if (!isRenderGraphViewerActive)
  2081. {
  2082. CleanupDebugData();
  2083. return;
  2084. }
  2085. if (!m_DebugData.TryGetValue(m_CurrentExecutionName, out var debugData))
  2086. {
  2087. onExecutionRegistered?.Invoke(this, m_CurrentExecutionName);
  2088. debugData = new DebugData();
  2089. m_DebugData.Add(m_CurrentExecutionName, debugData);
  2090. return; // Generate the debug data on the next frame, because script metadata is collected during recording step
  2091. }
  2092. // Only generate debug data on request
  2093. if (m_CaptureDebugDataForExecution == null || !m_CaptureDebugDataForExecution.Equals(m_CurrentExecutionName))
  2094. return;
  2095. debugData.Clear();
  2096. if (nativeRenderPassesEnabled)
  2097. nativeCompiler.GenerateNativeCompilerDebugData(ref debugData);
  2098. else
  2099. GenerateCompilerDebugData(ref debugData);
  2100. onDebugDataCaptured?.Invoke();
  2101. m_CaptureDebugDataForExecution = null;
  2102. ClearPassDebugMetadata();
  2103. }
  2104. void GenerateCompilerDebugData(ref DebugData debugData)
  2105. {
  2106. var compiledPassInfo = m_CurrentCompiledGraph.compiledPassInfos;
  2107. var compiledResourceInfo = m_CurrentCompiledGraph.compiledResourcesInfos;
  2108. for (int type = 0; type < (int)RenderGraphResourceType.Count; ++type)
  2109. {
  2110. for (int i = 0; i < compiledResourceInfo[type].size; ++i)
  2111. {
  2112. ref var resourceInfo = ref compiledResourceInfo[type][i];
  2113. DebugData.ResourceData newResource = new DebugData.ResourceData();
  2114. if (i != 0)
  2115. {
  2116. var resName = m_Resources.GetRenderGraphResourceName((RenderGraphResourceType)type, i);
  2117. newResource.name = !string.IsNullOrEmpty(resName) ? resName : "(unnamed)";
  2118. newResource.imported = m_Resources.IsRenderGraphResourceImported((RenderGraphResourceType)type, i);
  2119. }
  2120. else
  2121. {
  2122. // The above functions will throw exceptions when used with the null argument so just use a dummy instead
  2123. newResource.name = "<null>";
  2124. newResource.imported = true;
  2125. }
  2126. newResource.creationPassIndex = -1;
  2127. newResource.releasePassIndex = -1;
  2128. RenderGraphResourceType resourceType = (RenderGraphResourceType) type;
  2129. var handle = new ResourceHandle(i, resourceType, false);
  2130. if (i != 0 && handle.IsValid())
  2131. {
  2132. if (resourceType == RenderGraphResourceType.Texture)
  2133. {
  2134. m_Resources.GetRenderTargetInfo(handle, out var renderTargetInfo);
  2135. var textureData = new DebugData.TextureResourceData();
  2136. textureData.width = renderTargetInfo.width;
  2137. textureData.height = renderTargetInfo.height;
  2138. textureData.depth = renderTargetInfo.volumeDepth;
  2139. textureData.samples = renderTargetInfo.msaaSamples;
  2140. textureData.format = renderTargetInfo.format;
  2141. newResource.textureData = textureData;
  2142. }
  2143. else if (resourceType == RenderGraphResourceType.Buffer)
  2144. {
  2145. var bufferDesc = m_Resources.GetBufferResourceDesc(handle, true);
  2146. var bufferData = new DebugData.BufferResourceData();
  2147. bufferData.count = bufferDesc.count;
  2148. bufferData.stride = bufferDesc.stride;
  2149. bufferData.target = bufferDesc.target;
  2150. bufferData.usage = bufferDesc.usageFlags;
  2151. newResource.bufferData = bufferData;
  2152. }
  2153. }
  2154. newResource.consumerList = new List<int>(resourceInfo.consumers);
  2155. newResource.producerList = new List<int>(resourceInfo.producers);
  2156. if (newResource.imported)
  2157. {
  2158. UpdateImportedResourceLifeTime(ref newResource, newResource.consumerList);
  2159. UpdateImportedResourceLifeTime(ref newResource, newResource.producerList);
  2160. }
  2161. debugData.resourceLists[type].Add(newResource);
  2162. }
  2163. }
  2164. for (int i = 0; i < compiledPassInfo.size; ++i)
  2165. {
  2166. ref CompiledPassInfo passInfo = ref compiledPassInfo[i];
  2167. RenderGraphPass pass = m_RenderPasses[passInfo.index];
  2168. DebugData.PassData newPass = new DebugData.PassData();
  2169. newPass.name = pass.name;
  2170. newPass.type = pass.type;
  2171. newPass.culled = passInfo.culled;
  2172. newPass.async = passInfo.enableAsyncCompute;
  2173. newPass.generateDebugData = pass.generateDebugData;
  2174. newPass.resourceReadLists = new List<int>[(int)RenderGraphResourceType.Count];
  2175. newPass.resourceWriteLists = new List<int>[(int)RenderGraphResourceType.Count];
  2176. newPass.syncFromPassIndex = passInfo.syncFromPassIndex;
  2177. newPass.syncToPassIndex = passInfo.syncToPassIndex;
  2178. DebugData.s_PassScriptMetadata.TryGetValue(pass.name, out newPass.scriptInfo);
  2179. for (int type = 0; type < (int)RenderGraphResourceType.Count; ++type)
  2180. {
  2181. newPass.resourceReadLists[type] = new List<int>();
  2182. newPass.resourceWriteLists[type] = new List<int>();
  2183. foreach (var resourceRead in pass.resourceReadLists[type])
  2184. newPass.resourceReadLists[type].Add(resourceRead.index);
  2185. foreach (var resourceWrite in pass.resourceWriteLists[type])
  2186. newPass.resourceWriteLists[type].Add(resourceWrite.index);
  2187. foreach (var resourceCreate in passInfo.resourceCreateList[type])
  2188. {
  2189. var res = debugData.resourceLists[type][resourceCreate];
  2190. if (res.imported)
  2191. continue;
  2192. res.creationPassIndex = i;
  2193. debugData.resourceLists[type][resourceCreate] = res;
  2194. }
  2195. foreach (var resourceRelease in passInfo.resourceReleaseList[type])
  2196. {
  2197. var res = debugData.resourceLists[type][resourceRelease];
  2198. if (res.imported)
  2199. continue;
  2200. res.releasePassIndex = i;
  2201. debugData.resourceLists[type][resourceRelease] = res;
  2202. }
  2203. }
  2204. debugData.passList.Add(newPass);
  2205. }
  2206. }
  2207. void CleanupDebugData()
  2208. {
  2209. foreach (var kvp in m_DebugData)
  2210. {
  2211. onExecutionUnregistered?.Invoke(this, kvp.Key);
  2212. }
  2213. m_DebugData.Clear();
  2214. }
  2215. #endregion
  2216. Dictionary<int, TextureHandle> registeredGlobals = new Dictionary<int, TextureHandle>();
  2217. internal void SetGlobal(TextureHandle h, int globalPropertyId)
  2218. {
  2219. registeredGlobals[globalPropertyId] = h;
  2220. }
  2221. internal bool IsGlobal(int globalPropertyId)
  2222. {
  2223. return registeredGlobals.ContainsKey(globalPropertyId);
  2224. }
  2225. internal Dictionary<int, TextureHandle>.ValueCollection AllGlobals()
  2226. {
  2227. return registeredGlobals.Values;
  2228. }
  2229. internal TextureHandle GetGlobal(int globalPropertyId)
  2230. {
  2231. TextureHandle h;
  2232. registeredGlobals.TryGetValue(globalPropertyId, out h);
  2233. return h;
  2234. }
  2235. }
  2236. /// <summary>
  2237. /// Render Graph Scoped Profiling markers
  2238. /// </summary>
  2239. [MovedFrom(true, "UnityEngine.Experimental.Rendering.RenderGraphModule", "UnityEngine.Rendering.RenderGraphModule")]
  2240. public struct RenderGraphProfilingScope : IDisposable
  2241. {
  2242. #if DEVELOPMENT_BUILD || UNITY_EDITOR
  2243. ProfilingSampler m_Sampler;
  2244. RenderGraph m_RenderGraph;
  2245. bool m_Disposed;
  2246. #endif
  2247. /// <summary>
  2248. /// Profiling Scope constructor
  2249. /// </summary>
  2250. /// <param name="renderGraph">Render Graph used for this scope.</param>
  2251. /// <param name="sampler">Profiling Sampler to be used for this scope.</param>
  2252. public RenderGraphProfilingScope(RenderGraph renderGraph, ProfilingSampler sampler)
  2253. {
  2254. #if DEVELOPMENT_BUILD || UNITY_EDITOR
  2255. m_RenderGraph = renderGraph;
  2256. m_Sampler = sampler;
  2257. m_Disposed = false;
  2258. renderGraph.BeginProfilingSampler(sampler);
  2259. #endif
  2260. }
  2261. /// <summary>
  2262. /// Dispose pattern implementation
  2263. /// </summary>
  2264. public void Dispose()
  2265. {
  2266. Dispose(true);
  2267. }
  2268. // Protected implementation of Dispose pattern.
  2269. void Dispose(bool disposing)
  2270. {
  2271. #if DEVELOPMENT_BUILD || UNITY_EDITOR
  2272. if (m_Disposed)
  2273. return;
  2274. // As this is a struct, it could have been initialized using an empty constructor so we
  2275. // need to make sure `cmd` isn't null to avoid a crash. Switching to a class would fix
  2276. // this but will generate garbage on every frame (and this struct is used quite a lot).
  2277. if (disposing)
  2278. {
  2279. m_RenderGraph.EndProfilingSampler(m_Sampler);
  2280. }
  2281. m_Disposed = true;
  2282. #endif
  2283. }
  2284. }
  2285. }