123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269 |
- using System;
- using System.Diagnostics;
- using System.Runtime.CompilerServices;
-
- namespace UnityEngine.Rendering.RenderGraphModule
- {
- // RendererList is a different case so not represented here.
- internal enum RenderGraphResourceType
- {
- Texture = 0,
- Buffer,
- AccelerationStructure,
- Count
- }
-
- internal struct ResourceHandle : IEquatable<ResourceHandle>
- {
- // Note on handles validity.
- // PassData classes used during render graph passes are pooled and because of that, when users don't fill them completely,
- // they can contain stale handles from a previous render graph execution that could still be considered valid if we only checked the index.
- // 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.
- // If not, it's considered invalid.
- // We store this validity mask in the upper 16 bits of the index.
- const uint kValidityMask = 0xFFFF0000;
- const uint kIndexMask = 0xFFFF;
-
- uint m_Value;
- int m_Version; // A freshly created resource always starts at version 0 the first write should bring it to v1
-
- static uint s_CurrentValidBit = 1 << 16;
- static uint s_SharedResourceValidBit = 0x7FFF << 16;
-
- public int index
- {
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- get { return (int)(m_Value & kIndexMask); }
- }
- public int iType
- {
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- get { return (int)type; }
- }
- public int version
- {
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- get { return m_Version; }
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- set { m_Version = value; }
- }
- public RenderGraphResourceType type { get; private set; }
-
- internal ResourceHandle(int value, RenderGraphResourceType type, bool shared)
- {
- Debug.Assert(value <= 0xFFFF);
- m_Value = ((uint)value & kIndexMask) | (shared ? s_SharedResourceValidBit : s_CurrentValidBit);
- this.type = type;
- this.m_Version = -1;
- }
-
- internal ResourceHandle(in ResourceHandle h, int version)
- {
- this.m_Value = h.m_Value;
- this.type = h.type;
- this.m_Version = version;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public bool IsValid()
- {
- var validity = m_Value & kValidityMask;
- return validity != 0 && (validity == s_CurrentValidBit || validity == s_SharedResourceValidBit);
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public bool IsNull()
- {
- if (index == 0)
- {
- // Make sure everything is zero
- Debug.Assert(m_Value == 0);
- Debug.Assert(m_Version == 0);
- return true;
- }
- return false;
- }
-
- static public void NewFrame(int executionIndex)
- {
- uint previousValidBit = s_CurrentValidBit;
- // Scramble frame count to avoid collision when wrapping around.
- s_CurrentValidBit = (uint)(((executionIndex >> 16) ^ (executionIndex & 0xffff) * 58546883) << 16);
- // In case the current valid bit is 0, even though perfectly valid, 0 represents an invalid handle, hence we'll
- // trigger an invalid state incorrectly. To account for this, we actually skip 0 as a viable s_CurrentValidBit and
- // start from 1 again.
- // In the same spirit, s_SharedResourceValidBit is reserved for shared textures so we should never use it otherwise
- // resources could be considered valid at frame N+1 (because shared) even though they aren't.
- if (s_CurrentValidBit == 0 || s_CurrentValidBit == s_SharedResourceValidBit)
- {
- // We need to make sure we don't pick the same value twice.
- uint value = 1;
- while (previousValidBit == (value << 16))
- value++;
- s_CurrentValidBit = (value << 16);
- }
- }
-
- public bool IsVersioned
- {
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- get
- {
- return m_Version >= 0;
- }
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public bool Equals(ResourceHandle hdl)
- {
- return hdl.m_Value == this.m_Value && hdl.m_Version == this.m_Version && hdl.type == this.type;
- }
- }
-
- class IRenderGraphResource
- {
- public bool imported;
- public bool shared;
- public bool sharedExplicitRelease;
- public bool requestFallBack;
- public bool forceRelease;
- public uint writeCount;
- public int cachedHash;
- public int transientPassIndex;
- public int sharedResourceLastFrameUsed;
- public int version;
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public virtual void Reset(IRenderGraphResourcePool _ = null)
- {
- imported = false;
- shared = false;
- sharedExplicitRelease = false;
- cachedHash = -1;
- transientPassIndex = -1;
- sharedResourceLastFrameUsed = -1;
- requestFallBack = false;
- forceRelease = false;
- writeCount = 0;
- version = 0;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public virtual string GetName()
- {
- return "";
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public virtual bool IsCreated()
- {
- return false;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public virtual void IncrementWriteCount()
- {
- writeCount++;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public virtual int NewVersion()
- {
- version++;
- return version;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public virtual bool NeedsFallBack()
- {
- return requestFallBack && writeCount == 0;
- }
-
- public virtual void CreatePooledGraphicsResource() { }
- public virtual void CreateGraphicsResource() { }
- public virtual void UpdateGraphicsResource() { }
- public virtual void ReleasePooledGraphicsResource(int frameIndex) { }
- public virtual void ReleaseGraphicsResource() { }
- public virtual void LogCreation(RenderGraphLogger logger) { }
- public virtual void LogRelease(RenderGraphLogger logger) { }
- public virtual int GetSortIndex() { return 0; }
- public virtual int GetDescHashCode() { return 0; }
- }
-
- [DebuggerDisplay("Resource ({GetType().Name}:{GetName()})")]
- abstract class RenderGraphResource<DescType, ResType>
- : IRenderGraphResource
- where DescType : struct
- where ResType : class
- {
- public DescType desc;
- public bool validDesc; // Does the descriptor contain valid data (this is not always the case for imported resources)
- public ResType graphicsResource;
-
- protected RenderGraphResourcePool<ResType> m_Pool;
-
- protected RenderGraphResource()
- {
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public override void Reset(IRenderGraphResourcePool pool = null)
- {
- base.Reset();
- m_Pool = pool as RenderGraphResourcePool<ResType>;
- graphicsResource = null;
- validDesc = false;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public override bool IsCreated()
- {
- return graphicsResource != null;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public override void ReleaseGraphicsResource()
- {
- graphicsResource = null;
- }
-
- public override void CreatePooledGraphicsResource()
- {
- Debug.Assert(m_Pool != null, "RenderGraphResource: CreatePooledGraphicsResource should only be called for regular pooled resources");
-
- int hashCode = GetDescHashCode();
-
- if (graphicsResource != null)
- 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()));
-
- // If the pool doesn't have any available resource that we can use, we will create one
- // In any case, we will update the graphicsResource name based on the RenderGraph resource name
- if (!m_Pool.TryGetResource(hashCode, out graphicsResource))
- {
- CreateGraphicsResource();
- }
- else
- {
- UpdateGraphicsResource();
- }
-
- cachedHash = hashCode;
- m_Pool.RegisterFrameAllocation(cachedHash, graphicsResource);
- }
-
- public override void ReleasePooledGraphicsResource(int frameIndex)
- {
- if (graphicsResource == null)
- 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.");
-
- // Shared resources don't use the pool
- if (m_Pool != null)
- {
- m_Pool.ReleaseResource(cachedHash, graphicsResource, frameIndex);
- m_Pool.UnregisterFrameAllocation(cachedHash, graphicsResource);
- }
-
- Reset();
- }
- }
- }
|