RenderGraphResourceRegistry.cs 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713
  1. using System;
  2. using System.Collections.Generic;
  3. using UnityEngine.Rendering;
  4. namespace UnityEngine.Experimental.Rendering.RenderGraphModule
  5. {
  6. /// <summary>
  7. /// The mode that determines the size of a Texture.
  8. /// </summary>
  9. #region Resource Descriptors
  10. public enum TextureSizeMode
  11. {
  12. ///<summary>Explicit size.</summary>
  13. Explicit,
  14. ///<summary>Size automatically scaled by a Vector.</summary>
  15. Scale,
  16. ///<summary>Size automatically scaled by a Functor.</summary>
  17. Functor
  18. }
  19. /// <summary>
  20. /// Descriptor used to create texture resources
  21. /// </summary>
  22. public struct TextureDesc
  23. {
  24. ///<summary>Texture sizing mode.</summary>
  25. public TextureSizeMode sizeMode;
  26. ///<summary>Texture width.</summary>
  27. public int width;
  28. ///<summary>Texture height.</summary>
  29. public int height;
  30. ///<summary>Number of texture slices..</summary>
  31. public int slices;
  32. ///<summary>Texture scale.</summary>
  33. public Vector2 scale;
  34. ///<summary>Texture scale function.</summary>
  35. public ScaleFunc func;
  36. ///<summary>Depth buffer bit depth.</summary>
  37. public DepthBits depthBufferBits;
  38. ///<summary>Color format.</summary>
  39. public GraphicsFormat colorFormat;
  40. ///<summary>Filtering mode.</summary>
  41. public FilterMode filterMode;
  42. ///<summary>Addressing mode.</summary>
  43. public TextureWrapMode wrapMode;
  44. ///<summary>Texture dimension.</summary>
  45. public TextureDimension dimension;
  46. ///<summary>Enable random UAV read/write on the texture.</summary>
  47. public bool enableRandomWrite;
  48. ///<summary>Texture needs mip maps.</summary>
  49. public bool useMipMap;
  50. ///<summary>Automatically generate mip maps.</summary>
  51. public bool autoGenerateMips;
  52. ///<summary>Texture is a shadow map.</summary>
  53. public bool isShadowMap;
  54. ///<summary>Anisotropic filtering level.</summary>
  55. public int anisoLevel;
  56. ///<summary>Mip map bias.</summary>
  57. public float mipMapBias;
  58. ///<summary>Textre is multisampled. Only supported for Scale and Functor size mode.</summary>
  59. public bool enableMSAA;
  60. ///<summary>Number of MSAA samples. Only supported for Explicit size mode.</summary>
  61. public MSAASamples msaaSamples;
  62. ///<summary>Bind texture multi sampled.</summary>
  63. public bool bindTextureMS;
  64. ///<summary>Texture uses dynamic scaling.</summary>
  65. public bool useDynamicScale;
  66. ///<summary>Memory less flag.</summary>
  67. public RenderTextureMemoryless memoryless;
  68. ///<summary>Texture name.</summary>
  69. public string name;
  70. // Initial state. Those should not be used in the hash
  71. ///<summary>Texture needs to be cleared on first use.</summary>
  72. public bool clearBuffer;
  73. ///<summary>Clear color.</summary>
  74. public Color clearColor;
  75. void InitDefaultValues(bool dynamicResolution, bool xrReady)
  76. {
  77. useDynamicScale = dynamicResolution;
  78. // XR Ready
  79. if (xrReady)
  80. {
  81. slices = TextureXR.slices;
  82. dimension = TextureXR.dimension;
  83. }
  84. else
  85. {
  86. slices = 1;
  87. dimension = TextureDimension.Tex2D;
  88. }
  89. }
  90. /// <summary>
  91. /// TextureDesc constructor for a texture using explicit size
  92. /// </summary>
  93. /// <param name="width">Texture width</param>
  94. /// <param name="height">Texture height</param>
  95. /// <param name="dynamicResolution">Use dynamic resolution</param>
  96. /// <param name="xrReady">Set this to true if the Texture is a render texture in an XR setting.</param>
  97. public TextureDesc(int width, int height, bool dynamicResolution = false, bool xrReady = false)
  98. : this()
  99. {
  100. // Size related init
  101. sizeMode = TextureSizeMode.Explicit;
  102. this.width = width;
  103. this.height = height;
  104. // Important default values not handled by zero construction in this()
  105. msaaSamples = MSAASamples.None;
  106. InitDefaultValues(dynamicResolution, xrReady);
  107. }
  108. /// <summary>
  109. /// TextureDesc constructor for a texture using a fixed scaling
  110. /// </summary>
  111. /// <param name="scale">RTHandle scale used for this texture</param>
  112. /// <param name="dynamicResolution">Use dynamic resolution</param>
  113. /// <param name="xrReady">Set this to true if the Texture is a render texture in an XR setting.</param>
  114. public TextureDesc(Vector2 scale, bool dynamicResolution = false, bool xrReady = false)
  115. : this()
  116. {
  117. // Size related init
  118. sizeMode = TextureSizeMode.Scale;
  119. this.scale = scale;
  120. // Important default values not handled by zero construction in this()
  121. msaaSamples = MSAASamples.None;
  122. dimension = TextureDimension.Tex2D;
  123. InitDefaultValues(dynamicResolution, xrReady);
  124. }
  125. /// <summary>
  126. /// TextureDesc constructor for a texture using a functor for scaling
  127. /// </summary>
  128. /// <param name="func">Function used to determnine the texture size</param>
  129. /// <param name="dynamicResolution">Use dynamic resolution</param>
  130. /// <param name="xrReady">Set this to true if the Texture is a render texture in an XR setting.</param>
  131. public TextureDesc(ScaleFunc func, bool dynamicResolution = false, bool xrReady = false)
  132. : this()
  133. {
  134. // Size related init
  135. sizeMode = TextureSizeMode.Functor;
  136. this.func = func;
  137. // Important default values not handled by zero construction in this()
  138. msaaSamples = MSAASamples.None;
  139. dimension = TextureDimension.Tex2D;
  140. InitDefaultValues(dynamicResolution, xrReady);
  141. }
  142. /// <summary>
  143. /// Copy constructor
  144. /// </summary>
  145. /// <param name="input"></param>
  146. public TextureDesc(TextureDesc input)
  147. {
  148. this = input;
  149. }
  150. /// <summary>
  151. /// Hash function
  152. /// </summary>
  153. /// <returns>The texture descriptor hash.</returns>
  154. public override int GetHashCode()
  155. {
  156. int hashCode = 17;
  157. unchecked
  158. {
  159. switch (sizeMode)
  160. {
  161. case TextureSizeMode.Explicit:
  162. hashCode = hashCode * 23 + width;
  163. hashCode = hashCode * 23 + height;
  164. hashCode = hashCode * 23 + (int)msaaSamples;
  165. break;
  166. case TextureSizeMode.Functor:
  167. if (func != null)
  168. hashCode = hashCode * 23 + func.GetHashCode();
  169. hashCode = hashCode * 23 + (enableMSAA ? 1 : 0);
  170. break;
  171. case TextureSizeMode.Scale:
  172. hashCode = hashCode * 23 + scale.x.GetHashCode();
  173. hashCode = hashCode * 23 + scale.y.GetHashCode();
  174. hashCode = hashCode * 23 + (enableMSAA ? 1 : 0);
  175. break;
  176. }
  177. hashCode = hashCode * 23 + mipMapBias.GetHashCode();
  178. hashCode = hashCode * 23 + slices;
  179. hashCode = hashCode * 23 + (int)depthBufferBits;
  180. hashCode = hashCode * 23 + (int)colorFormat;
  181. hashCode = hashCode * 23 + (int)filterMode;
  182. hashCode = hashCode * 23 + (int)wrapMode;
  183. hashCode = hashCode * 23 + (int)dimension;
  184. hashCode = hashCode * 23 + (int)memoryless;
  185. hashCode = hashCode * 23 + anisoLevel;
  186. hashCode = hashCode * 23 + (enableRandomWrite ? 1 : 0);
  187. hashCode = hashCode * 23 + (useMipMap ? 1 : 0);
  188. hashCode = hashCode * 23 + (autoGenerateMips ? 1 : 0);
  189. hashCode = hashCode * 23 + (isShadowMap ? 1 : 0);
  190. hashCode = hashCode * 23 + (bindTextureMS ? 1 : 0);
  191. hashCode = hashCode * 23 + (useDynamicScale ? 1 : 0);
  192. }
  193. return hashCode;
  194. }
  195. }
  196. #endregion
  197. /// <summary>
  198. /// The RenderGraphResourceRegistry holds all resource allocated during Render Graph execution.
  199. /// </summary>
  200. public class RenderGraphResourceRegistry
  201. {
  202. static readonly ShaderTagId s_EmptyName = new ShaderTagId("");
  203. #region Resources
  204. internal struct TextureResource
  205. {
  206. public TextureDesc desc;
  207. public bool imported;
  208. public RTHandle rt;
  209. public int cachedHash;
  210. public int firstWritePassIndex;
  211. public int lastReadPassIndex;
  212. public int shaderProperty;
  213. public bool wasReleased;
  214. internal TextureResource(RTHandle rt, int shaderProperty)
  215. : this()
  216. {
  217. Reset();
  218. this.rt = rt;
  219. imported = true;
  220. this.shaderProperty = shaderProperty;
  221. }
  222. internal TextureResource(in TextureDesc desc, int shaderProperty)
  223. : this()
  224. {
  225. Reset();
  226. this.desc = desc;
  227. this.shaderProperty = shaderProperty;
  228. }
  229. void Reset()
  230. {
  231. imported = false;
  232. rt = null;
  233. cachedHash = -1;
  234. firstWritePassIndex = int.MaxValue;
  235. lastReadPassIndex = -1;
  236. wasReleased = false;
  237. }
  238. }
  239. internal struct RendererListResource
  240. {
  241. public RendererListDesc desc;
  242. public RendererList rendererList;
  243. internal RendererListResource(in RendererListDesc desc)
  244. {
  245. this.desc = desc;
  246. this.rendererList = new RendererList(); // Invalid by default
  247. }
  248. }
  249. #endregion
  250. DynamicArray<TextureResource> m_TextureResources = new DynamicArray<TextureResource>();
  251. Dictionary<int, Stack<RTHandle>> m_TexturePool = new Dictionary<int, Stack<RTHandle>>();
  252. DynamicArray<RendererListResource> m_RendererListResources = new DynamicArray<RendererListResource>();
  253. RTHandleSystem m_RTHandleSystem = new RTHandleSystem();
  254. RenderGraphDebugParams m_RenderGraphDebug;
  255. RenderGraphLogger m_Logger;
  256. // Diagnostic only
  257. List<(int, RTHandle)> m_AllocatedTextures = new List<(int, RTHandle)>();
  258. #region Public Interface
  259. /// <summary>
  260. /// Returns the RTHandle associated with the provided resource handle.
  261. /// </summary>
  262. /// <param name="handle">Handle to a texture resource.</param>
  263. /// <returns>The RTHandle associated with the provided resource handle.</returns>
  264. public RTHandle GetTexture(in RenderGraphResource handle)
  265. {
  266. #if DEVELOPMENT_BUILD || UNITY_EDITOR
  267. if (handle.type != RenderGraphResourceType.Texture)
  268. throw new InvalidOperationException("Trying to access a RenderGraphResource that is not a texture.");
  269. var res = m_TextureResources[handle.handle];
  270. if (res.rt == null && !res.wasReleased)
  271. throw new InvalidOperationException(string.Format("Trying to access texture \"{0}\" that was never created. Check that it was written at least once before trying to get it.", res.desc.name));
  272. if (res.rt == null && res.wasReleased)
  273. throw new InvalidOperationException(string.Format("Trying to access texture \"{0}\" that was already released. Check that the last pass where it's read is after this one.", res.desc.name));
  274. #endif
  275. return m_TextureResources[handle.handle].rt;
  276. }
  277. /// <summary>
  278. /// Returns the RendererList associated with the provided resource handle.
  279. /// </summary>
  280. /// <param name="handle">Handle to a Renderer List resource.</param>
  281. /// <returns>The Renderer List associated with the provided resource handle.</returns>
  282. public RendererList GetRendererList(in RenderGraphResource handle)
  283. {
  284. #if DEVELOPMENT_BUILD || UNITY_EDITOR
  285. if (handle.type != RenderGraphResourceType.RendererList)
  286. throw new InvalidOperationException("Trying to access a RenderGraphResource that is not a RendererList.");
  287. #endif
  288. return m_RendererListResources[handle.handle].rendererList;
  289. }
  290. #endregion
  291. #region Internal Interface
  292. private RenderGraphResourceRegistry()
  293. {
  294. }
  295. internal RenderGraphResourceRegistry(bool supportMSAA, MSAASamples initialSampleCount, RenderGraphDebugParams renderGraphDebug, RenderGraphLogger logger)
  296. {
  297. m_RTHandleSystem.Initialize(1, 1, supportMSAA, initialSampleCount);
  298. m_RenderGraphDebug = renderGraphDebug;
  299. m_Logger = logger;
  300. }
  301. internal void SetRTHandleReferenceSize(int width, int height, MSAASamples msaaSamples)
  302. {
  303. m_RTHandleSystem.SetReferenceSize(width, height, msaaSamples);
  304. }
  305. internal RTHandleProperties GetRTHandleProperties() { return m_RTHandleSystem.rtHandleProperties; }
  306. // Texture Creation/Import APIs are internal because creation should only go through RenderGraph
  307. internal RenderGraphMutableResource ImportTexture(RTHandle rt, int shaderProperty = 0)
  308. {
  309. int newHandle = m_TextureResources.Add(new TextureResource(rt, shaderProperty));
  310. return new RenderGraphMutableResource(newHandle, RenderGraphResourceType.Texture);
  311. }
  312. internal RenderGraphMutableResource CreateTexture(in TextureDesc desc, int shaderProperty = 0)
  313. {
  314. ValidateTextureDesc(desc);
  315. int newHandle = m_TextureResources.Add(new TextureResource(desc, shaderProperty));
  316. return new RenderGraphMutableResource(newHandle, RenderGraphResourceType.Texture);
  317. }
  318. internal void UpdateTextureFirstWrite(RenderGraphResource tex, int passIndex)
  319. {
  320. ref var res = ref GetTextureResource(tex);
  321. res.firstWritePassIndex = Math.Min(passIndex, res.firstWritePassIndex);
  322. //// We increment lastRead index here so that a resource used only for a single pass can be released at the end of said pass.
  323. //// This will also keep the resource alive as long as it is written to.
  324. //// Typical example is a depth buffer that may never be explicitly read from but is necessary all along
  325. ///
  326. // PROBLEM: Increasing last read on write operation will keep the target alive even if it's not used at all so it's not good.
  327. // If we don't do it though, it means that client code cannot write "by default" into a target as it will try to write to an already released target.
  328. // Example:
  329. // DepthPrepass: Writes to Depth and Normal buffers (pass will create normal buffer)
  330. // ObjectMotion: Writes to MotionVectors and Normal => Exception because NormalBuffer is already released as it not used.
  331. // => Solution includes : Shader Combination (without MRT for example) / Dummy Targets
  332. //res.lastReadPassIndex = Math.Max(passIndex, res.lastReadPassIndex);
  333. }
  334. internal void UpdateTextureLastRead(RenderGraphResource tex, int passIndex)
  335. {
  336. ref var res = ref GetTextureResource(tex);
  337. res.lastReadPassIndex = Math.Max(passIndex, res.lastReadPassIndex);
  338. }
  339. ref TextureResource GetTextureResource(RenderGraphResource res)
  340. {
  341. return ref m_TextureResources[res.handle];
  342. }
  343. internal TextureDesc GetTextureResourceDesc(RenderGraphResource res)
  344. {
  345. return m_TextureResources[res.handle].desc;
  346. }
  347. internal RenderGraphResource CreateRendererList(in RendererListDesc desc)
  348. {
  349. ValidateRendererListDesc(desc);
  350. int newHandle = m_RendererListResources.Add(new RendererListResource(desc));
  351. return new RenderGraphResource(newHandle, RenderGraphResourceType.RendererList);
  352. }
  353. internal void CreateAndClearTexturesForPass(RenderGraphContext rgContext, int passIndex, List<RenderGraphMutableResource> textures)
  354. {
  355. foreach (var rgResource in textures)
  356. {
  357. ref var resource = ref GetTextureResource(rgResource);
  358. if (!resource.imported && resource.firstWritePassIndex == passIndex)
  359. {
  360. CreateTextureForPass(ref resource);
  361. if (resource.desc.clearBuffer || m_RenderGraphDebug.clearRenderTargetsAtCreation)
  362. {
  363. bool debugClear = m_RenderGraphDebug.clearRenderTargetsAtCreation && !resource.desc.clearBuffer;
  364. var name = debugClear ? "RenderGraph: Clear Buffer (Debug)" : "RenderGraph: Clear Buffer";
  365. using (new ProfilingScope(rgContext.cmd, ProfilingSampler.Get(RenderGraphProfileId.RenderGraphClear)))
  366. {
  367. var clearFlag = resource.desc.depthBufferBits != DepthBits.None ? ClearFlag.Depth : ClearFlag.Color;
  368. var clearColor = debugClear ? Color.magenta : resource.desc.clearColor;
  369. CoreUtils.SetRenderTarget(rgContext.cmd, resource.rt, clearFlag, clearColor);
  370. }
  371. }
  372. LogTextureCreation(resource.rt, resource.desc.clearBuffer || m_RenderGraphDebug.clearRenderTargetsAtCreation);
  373. }
  374. }
  375. }
  376. void CreateTextureForPass(ref TextureResource resource)
  377. {
  378. var desc = resource.desc;
  379. int hashCode = desc.GetHashCode();
  380. if(resource.rt != null)
  381. throw new InvalidOperationException(string.Format("Trying to create an already created texture ({0}). Texture was probably declared for writing more than once.", resource.desc.name));
  382. resource.rt = null;
  383. if (!TryGetRenderTarget(hashCode, out resource.rt))
  384. {
  385. // Note: Name used here will be the one visible in the memory profiler so it means that whatever is the first pass that actually allocate the texture will set the name.
  386. // TODO: Find a way to display name by pass.
  387. switch (desc.sizeMode)
  388. {
  389. case TextureSizeMode.Explicit:
  390. resource.rt = m_RTHandleSystem.Alloc(desc.width, desc.height, desc.slices, desc.depthBufferBits, desc.colorFormat, desc.filterMode, desc.wrapMode, desc.dimension, desc.enableRandomWrite,
  391. desc.useMipMap, desc.autoGenerateMips, desc.isShadowMap, desc.anisoLevel, desc.mipMapBias, desc.msaaSamples, desc.bindTextureMS, desc.useDynamicScale, desc.memoryless, desc.name);
  392. break;
  393. case TextureSizeMode.Scale:
  394. resource.rt = m_RTHandleSystem.Alloc(desc.scale, desc.slices, desc.depthBufferBits, desc.colorFormat, desc.filterMode, desc.wrapMode, desc.dimension, desc.enableRandomWrite,
  395. desc.useMipMap, desc.autoGenerateMips, desc.isShadowMap, desc.anisoLevel, desc.mipMapBias, desc.enableMSAA, desc.bindTextureMS, desc.useDynamicScale, desc.memoryless, desc.name);
  396. break;
  397. case TextureSizeMode.Functor:
  398. resource.rt = m_RTHandleSystem.Alloc(desc.func, desc.slices, desc.depthBufferBits, desc.colorFormat, desc.filterMode, desc.wrapMode, desc.dimension, desc.enableRandomWrite,
  399. desc.useMipMap, desc.autoGenerateMips, desc.isShadowMap, desc.anisoLevel, desc.mipMapBias, desc.enableMSAA, desc.bindTextureMS, desc.useDynamicScale, desc.memoryless, desc.name);
  400. break;
  401. }
  402. }
  403. //// Try to update name when re-using a texture.
  404. //// TODO: Check if that actually works.
  405. //resource.rt.name = desc.name;
  406. #if DEVELOPMENT_BUILD || UNITY_EDITOR
  407. if (hashCode != -1)
  408. {
  409. m_AllocatedTextures.Add((hashCode, resource.rt));
  410. }
  411. #endif
  412. resource.cachedHash = hashCode;
  413. }
  414. void SetGlobalTextures(RenderGraphContext rgContext, List<RenderGraphResource> textures, bool bindDummyTexture)
  415. {
  416. foreach (var resource in textures)
  417. {
  418. var resourceDesc = GetTextureResource(resource);
  419. if (resourceDesc.shaderProperty != 0)
  420. {
  421. if (resourceDesc.rt == null)
  422. {
  423. throw new InvalidOperationException(string.Format("Trying to set Global Texture parameter for \"{0}\" which was never created.\nCheck that at least one write operation happens before reading it.", resourceDesc.desc.name));
  424. }
  425. rgContext.cmd.SetGlobalTexture(resourceDesc.shaderProperty, bindDummyTexture ? TextureXR.GetMagentaTexture() : resourceDesc.rt);
  426. }
  427. }
  428. }
  429. internal void PreRenderPassSetGlobalTextures(RenderGraphContext rgContext, List<RenderGraphResource> textures)
  430. {
  431. SetGlobalTextures(rgContext, textures, false);
  432. }
  433. internal void PostRenderPassUnbindGlobalTextures(RenderGraphContext rgContext, List<RenderGraphResource> textures)
  434. {
  435. SetGlobalTextures(rgContext, textures, true);
  436. }
  437. internal void ReleaseTexturesForPass(RenderGraphContext rgContext, int passIndex, List<RenderGraphResource> readTextures, List<RenderGraphMutableResource> writtenTextures)
  438. {
  439. foreach (var resource in readTextures)
  440. {
  441. ref var resourceDesc = ref GetTextureResource(resource);
  442. if (!resourceDesc.imported && resourceDesc.lastReadPassIndex == passIndex)
  443. {
  444. if (m_RenderGraphDebug.clearRenderTargetsAtRelease)
  445. {
  446. using (new ProfilingScope(rgContext.cmd, ProfilingSampler.Get(RenderGraphProfileId.RenderGraphClearDebug)))
  447. {
  448. var clearFlag = resourceDesc.desc.depthBufferBits != DepthBits.None ? ClearFlag.Depth : ClearFlag.Color;
  449. CoreUtils.SetRenderTarget(rgContext.cmd, GetTexture(resource), clearFlag, Color.magenta);
  450. }
  451. }
  452. ReleaseTextureForPass(resource);
  453. }
  454. }
  455. // If a resource was created for only a single pass, we don't want users to have to declare explicitly the read operation.
  456. // So to do that, we also update lastReadIndex on resource writes.
  457. // This means that we need to check written resources for destruction too
  458. foreach (var resource in writtenTextures)
  459. {
  460. ref var resourceDesc = ref GetTextureResource(resource);
  461. // <= because a texture that is only declared as written in a single pass (and read implicitly in the same pass) will have the default lastReadPassIndex at -1
  462. if (!resourceDesc.imported && resourceDesc.lastReadPassIndex <= passIndex)
  463. {
  464. ReleaseTextureForPass(resource);
  465. }
  466. }
  467. }
  468. void ReleaseTextureForPass(RenderGraphResource res)
  469. {
  470. Debug.Assert(res.type == RenderGraphResourceType.Texture);
  471. ref var resource = ref m_TextureResources[res.handle];
  472. // This can happen because we release texture in two passes (see ReleaseTexturesForPass) and texture can be present in both passes
  473. if (resource.rt != null)
  474. {
  475. LogTextureRelease(resource.rt);
  476. ReleaseTextureResource(resource.cachedHash, resource.rt);
  477. resource.cachedHash = -1;
  478. resource.rt = null;
  479. resource.wasReleased = true;
  480. }
  481. }
  482. void ReleaseTextureResource(int hash, RTHandle rt)
  483. {
  484. if (!m_TexturePool.TryGetValue(hash, out var stack))
  485. {
  486. stack = new Stack<RTHandle>();
  487. m_TexturePool.Add(hash, stack);
  488. }
  489. stack.Push(rt);
  490. #if DEVELOPMENT_BUILD || UNITY_EDITOR
  491. m_AllocatedTextures.Remove((hash, rt));
  492. #endif
  493. }
  494. void ValidateTextureDesc(in TextureDesc desc)
  495. {
  496. #if DEVELOPMENT_BUILD || UNITY_EDITOR
  497. if (desc.colorFormat == GraphicsFormat.None && desc.depthBufferBits == DepthBits.None)
  498. {
  499. throw new ArgumentException("Texture was created with an invalid color format.");
  500. }
  501. if (desc.dimension == TextureDimension.None)
  502. {
  503. throw new ArgumentException("Texture was created with an invalid texture dimension.");
  504. }
  505. if (desc.slices == 0)
  506. {
  507. throw new ArgumentException("Texture was created with a slices parameter value of zero.");
  508. }
  509. if (desc.sizeMode == TextureSizeMode.Explicit)
  510. {
  511. if (desc.width == 0 || desc.height == 0)
  512. throw new ArgumentException("Texture using Explicit size mode was create with either width or height at zero.");
  513. if (desc.enableMSAA)
  514. throw new ArgumentException("enableMSAA TextureDesc parameter is not supported for textures using Explicit size mode.");
  515. }
  516. if (desc.sizeMode == TextureSizeMode.Scale || desc.sizeMode == TextureSizeMode.Functor)
  517. {
  518. if (desc.msaaSamples != MSAASamples.None)
  519. throw new ArgumentException("msaaSamples TextureDesc parameter is not supported for textures using Scale or Functor size mode.");
  520. }
  521. #endif
  522. }
  523. void ValidateRendererListDesc(in RendererListDesc desc)
  524. {
  525. #if DEVELOPMENT_BUILD || UNITY_EDITOR
  526. if (desc.passName != ShaderTagId.none && desc.passNames != null
  527. || desc.passName == ShaderTagId.none && desc.passNames == null)
  528. {
  529. throw new ArgumentException("Renderer List creation descriptor must contain either a single passName or an array of passNames.");
  530. }
  531. if (desc.renderQueueRange.lowerBound == 0 && desc.renderQueueRange.upperBound == 0)
  532. {
  533. throw new ArgumentException("Renderer List creation descriptor must have a valid RenderQueueRange.");
  534. }
  535. if (desc.camera == null)
  536. {
  537. throw new ArgumentException("Renderer List creation descriptor must have a valid Camera.");
  538. }
  539. #endif
  540. }
  541. bool TryGetRenderTarget(int hashCode, out RTHandle rt)
  542. {
  543. if (m_TexturePool.TryGetValue(hashCode, out var stack) && stack.Count > 0)
  544. {
  545. rt = stack.Pop();
  546. return true;
  547. }
  548. rt = null;
  549. return false;
  550. }
  551. internal void CreateRendererLists(List<RenderGraphResource> rendererLists)
  552. {
  553. // For now we just create a simple structure
  554. // but when the proper API is available in trunk we'll kick off renderer lists creation jobs here.
  555. foreach (var rendererList in rendererLists)
  556. {
  557. Debug.Assert(rendererList.type == RenderGraphResourceType.RendererList);
  558. ref var rendererListResource = ref m_RendererListResources[rendererList.handle];
  559. ref var desc = ref rendererListResource.desc;
  560. RendererList newRendererList = RendererList.Create(desc);
  561. rendererListResource.rendererList = newRendererList;
  562. }
  563. }
  564. internal void Clear()
  565. {
  566. LogResources();
  567. m_TextureResources.Clear();
  568. m_RendererListResources.Clear();
  569. #if DEVELOPMENT_BUILD || UNITY_EDITOR
  570. if (m_AllocatedTextures.Count != 0)
  571. {
  572. Debug.LogWarning("RenderGraph: Not all textures were released.");
  573. List<(int, RTHandle)> tempList = new List<(int, RTHandle)>(m_AllocatedTextures);
  574. foreach (var value in tempList)
  575. {
  576. ReleaseTextureResource(value.Item1, value.Item2);
  577. }
  578. }
  579. #endif
  580. }
  581. internal void Cleanup()
  582. {
  583. foreach (var value in m_TexturePool)
  584. {
  585. foreach (var rt in value.Value)
  586. {
  587. m_RTHandleSystem.Release(rt);
  588. }
  589. }
  590. }
  591. void LogTextureCreation(RTHandle rt, bool cleared)
  592. {
  593. if (m_RenderGraphDebug.logFrameInformation)
  594. {
  595. m_Logger.LogLine("Created Texture: {0} (Cleared: {1})", rt.rt.name, cleared);
  596. }
  597. }
  598. void LogTextureRelease(RTHandle rt)
  599. {
  600. if (m_RenderGraphDebug.logFrameInformation)
  601. {
  602. m_Logger.LogLine("Released Texture: {0}", rt.rt.name);
  603. }
  604. }
  605. void LogResources()
  606. {
  607. if (m_RenderGraphDebug.logResources)
  608. {
  609. m_Logger.LogLine("==== Allocated Resources ====\n");
  610. List<string> allocationList = new List<string>();
  611. foreach (var stack in m_TexturePool)
  612. {
  613. foreach (var rt in stack.Value)
  614. {
  615. allocationList.Add(rt.rt.name);
  616. }
  617. }
  618. allocationList.Sort();
  619. int index = 0;
  620. foreach (var element in allocationList)
  621. m_Logger.LogLine("[{0}] {1}", index++, element);
  622. }
  623. }
  624. #endregion
  625. }
  626. }