暫無描述
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.

RenderGraphResources.cs 9.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. using System;
  2. using System.Diagnostics;
  3. using System.Runtime.CompilerServices;
  4. namespace UnityEngine.Rendering.RenderGraphModule
  5. {
  6. // RendererList is a different case so not represented here.
  7. internal enum RenderGraphResourceType
  8. {
  9. Texture = 0,
  10. Buffer,
  11. AccelerationStructure,
  12. Count
  13. }
  14. internal struct ResourceHandle : IEquatable<ResourceHandle>
  15. {
  16. // Note on handles validity.
  17. // PassData classes used during render graph passes are pooled and because of that, when users don't fill them completely,
  18. // they can contain stale handles from a previous render graph execution that could still be considered valid if we only checked the index.
  19. // In order to avoid using those, we incorporate the execution index in a 16 bits hash to make sure the handle is coming from the current execution.
  20. // If not, it's considered invalid.
  21. // We store this validity mask in the upper 16 bits of the index.
  22. const uint kValidityMask = 0xFFFF0000;
  23. const uint kIndexMask = 0xFFFF;
  24. uint m_Value;
  25. int m_Version; // A freshly created resource always starts at version 0 the first write should bring it to v1
  26. static uint s_CurrentValidBit = 1 << 16;
  27. static uint s_SharedResourceValidBit = 0x7FFF << 16;
  28. public int index
  29. {
  30. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  31. get { return (int)(m_Value & kIndexMask); }
  32. }
  33. public int iType
  34. {
  35. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  36. get { return (int)type; }
  37. }
  38. public int version
  39. {
  40. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  41. get { return m_Version; }
  42. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  43. set { m_Version = value; }
  44. }
  45. public RenderGraphResourceType type { get; private set; }
  46. internal ResourceHandle(int value, RenderGraphResourceType type, bool shared)
  47. {
  48. Debug.Assert(value <= 0xFFFF);
  49. m_Value = ((uint)value & kIndexMask) | (shared ? s_SharedResourceValidBit : s_CurrentValidBit);
  50. this.type = type;
  51. this.m_Version = -1;
  52. }
  53. internal ResourceHandle(in ResourceHandle h, int version)
  54. {
  55. this.m_Value = h.m_Value;
  56. this.type = h.type;
  57. this.m_Version = version;
  58. }
  59. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  60. public bool IsValid()
  61. {
  62. var validity = m_Value & kValidityMask;
  63. return validity != 0 && (validity == s_CurrentValidBit || validity == s_SharedResourceValidBit);
  64. }
  65. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  66. public bool IsNull()
  67. {
  68. if (index == 0)
  69. {
  70. // Make sure everything is zero
  71. Debug.Assert(m_Value == 0);
  72. Debug.Assert(m_Version == 0);
  73. return true;
  74. }
  75. return false;
  76. }
  77. static public void NewFrame(int executionIndex)
  78. {
  79. uint previousValidBit = s_CurrentValidBit;
  80. // Scramble frame count to avoid collision when wrapping around.
  81. s_CurrentValidBit = (uint)(((executionIndex >> 16) ^ (executionIndex & 0xffff) * 58546883) << 16);
  82. // In case the current valid bit is 0, even though perfectly valid, 0 represents an invalid handle, hence we'll
  83. // trigger an invalid state incorrectly. To account for this, we actually skip 0 as a viable s_CurrentValidBit and
  84. // start from 1 again.
  85. // In the same spirit, s_SharedResourceValidBit is reserved for shared textures so we should never use it otherwise
  86. // resources could be considered valid at frame N+1 (because shared) even though they aren't.
  87. if (s_CurrentValidBit == 0 || s_CurrentValidBit == s_SharedResourceValidBit)
  88. {
  89. // We need to make sure we don't pick the same value twice.
  90. uint value = 1;
  91. while (previousValidBit == (value << 16))
  92. value++;
  93. s_CurrentValidBit = (value << 16);
  94. }
  95. }
  96. public bool IsVersioned
  97. {
  98. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  99. get
  100. {
  101. return m_Version >= 0;
  102. }
  103. }
  104. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  105. public bool Equals(ResourceHandle hdl)
  106. {
  107. return hdl.m_Value == this.m_Value && hdl.m_Version == this.m_Version && hdl.type == this.type;
  108. }
  109. }
  110. class IRenderGraphResource
  111. {
  112. public bool imported;
  113. public bool shared;
  114. public bool sharedExplicitRelease;
  115. public bool requestFallBack;
  116. public bool forceRelease;
  117. public uint writeCount;
  118. public int cachedHash;
  119. public int transientPassIndex;
  120. public int sharedResourceLastFrameUsed;
  121. public int version;
  122. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  123. public virtual void Reset(IRenderGraphResourcePool _ = null)
  124. {
  125. imported = false;
  126. shared = false;
  127. sharedExplicitRelease = false;
  128. cachedHash = -1;
  129. transientPassIndex = -1;
  130. sharedResourceLastFrameUsed = -1;
  131. requestFallBack = false;
  132. forceRelease = false;
  133. writeCount = 0;
  134. version = 0;
  135. }
  136. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  137. public virtual string GetName()
  138. {
  139. return "";
  140. }
  141. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  142. public virtual bool IsCreated()
  143. {
  144. return false;
  145. }
  146. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  147. public virtual void IncrementWriteCount()
  148. {
  149. writeCount++;
  150. }
  151. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  152. public virtual int NewVersion()
  153. {
  154. version++;
  155. return version;
  156. }
  157. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  158. public virtual bool NeedsFallBack()
  159. {
  160. return requestFallBack && writeCount == 0;
  161. }
  162. public virtual void CreatePooledGraphicsResource() { }
  163. public virtual void CreateGraphicsResource() { }
  164. public virtual void UpdateGraphicsResource() { }
  165. public virtual void ReleasePooledGraphicsResource(int frameIndex) { }
  166. public virtual void ReleaseGraphicsResource() { }
  167. public virtual void LogCreation(RenderGraphLogger logger) { }
  168. public virtual void LogRelease(RenderGraphLogger logger) { }
  169. public virtual int GetSortIndex() { return 0; }
  170. public virtual int GetDescHashCode() { return 0; }
  171. }
  172. [DebuggerDisplay("Resource ({GetType().Name}:{GetName()})")]
  173. abstract class RenderGraphResource<DescType, ResType>
  174. : IRenderGraphResource
  175. where DescType : struct
  176. where ResType : class
  177. {
  178. public DescType desc;
  179. public bool validDesc; // Does the descriptor contain valid data (this is not always the case for imported resources)
  180. public ResType graphicsResource;
  181. protected RenderGraphResourcePool<ResType> m_Pool;
  182. protected RenderGraphResource()
  183. {
  184. }
  185. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  186. public override void Reset(IRenderGraphResourcePool pool = null)
  187. {
  188. base.Reset();
  189. m_Pool = pool as RenderGraphResourcePool<ResType>;
  190. graphicsResource = null;
  191. validDesc = false;
  192. }
  193. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  194. public override bool IsCreated()
  195. {
  196. return graphicsResource != null;
  197. }
  198. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  199. public override void ReleaseGraphicsResource()
  200. {
  201. graphicsResource = null;
  202. }
  203. public override void CreatePooledGraphicsResource()
  204. {
  205. Debug.Assert(m_Pool != null, "RenderGraphResource: CreatePooledGraphicsResource should only be called for regular pooled resources");
  206. int hashCode = GetDescHashCode();
  207. if (graphicsResource != null)
  208. throw new InvalidOperationException(string.Format("RenderGraphResource: Trying to create an already created resource ({0}). Resource was probably declared for writing more than once in the same pass.", GetName()));
  209. // If the pool doesn't have any available resource that we can use, we will create one
  210. // In any case, we will update the graphicsResource name based on the RenderGraph resource name
  211. if (!m_Pool.TryGetResource(hashCode, out graphicsResource))
  212. {
  213. CreateGraphicsResource();
  214. }
  215. else
  216. {
  217. UpdateGraphicsResource();
  218. }
  219. cachedHash = hashCode;
  220. m_Pool.RegisterFrameAllocation(cachedHash, graphicsResource);
  221. }
  222. public override void ReleasePooledGraphicsResource(int frameIndex)
  223. {
  224. if (graphicsResource == null)
  225. throw new InvalidOperationException($"RenderGraphResource: Tried to release a resource ({GetName()}) that was never created. Check that there is at least one pass writing to it first.");
  226. // Shared resources don't use the pool
  227. if (m_Pool != null)
  228. {
  229. m_Pool.ReleaseResource(cachedHash, graphicsResource, frameIndex);
  230. m_Pool.UnregisterFrameAllocation(cachedHash, graphicsResource);
  231. }
  232. Reset();
  233. }
  234. }
  235. }