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