using System; using System.Collections.Generic; namespace UnityEngine.Rendering.RenderGraphModule { /// /// Helper class provided in the RenderGraphContext to all Render Passes. /// It allows you to do temporary allocations of various objects during a Render Pass. /// public sealed class RenderGraphObjectPool { // Only used to clear all existing pools at once from here when needed static DynamicArray s_AllocatedPools = new DynamicArray(); // Non abstract class instead of an interface to store it in a DynamicArray class SharedObjectPoolBase { public SharedObjectPoolBase() {} public virtual void Clear() {} } class SharedObjectPool : SharedObjectPoolBase where T : class, new() { private static readonly Pool.ObjectPool s_Pool = AllocatePool(); private static Pool.ObjectPool AllocatePool() { var newPool = new Pool.ObjectPool(() => new T(), null, null); // Storing instance to clear the static pool of the same type if needed s_AllocatedPools.Add(new SharedObjectPool()); return newPool; } /// /// Clear the pool using SharedObjectPool instance. /// /// public override void Clear() { s_Pool.Clear(); } /// /// Get a new instance from the pool. /// /// public static T Get() => s_Pool.Get(); /// /// Release an object to the pool. /// /// instance to release. public static void Release(T toRelease) => s_Pool.Release(toRelease); } Dictionary<(Type, int), Stack> m_ArrayPool = new Dictionary<(Type, int), Stack>(); List<(object, (Type, int))> m_AllocatedArrays = new List<(object, (Type, int))>(); List m_AllocatedMaterialPropertyBlocks = new List(); internal RenderGraphObjectPool() { } /// /// Allocate a temporary typed array of a specific size. /// Unity releases the array at the end of the Render Pass. /// /// Type of the array to be allocated. /// Number of element in the array. /// A new array of type T with size number of elements. public T[] GetTempArray(int size) { if (!m_ArrayPool.TryGetValue((typeof(T), size), out var stack)) { stack = new Stack(); m_ArrayPool.Add((typeof(T), size), stack); } var result = stack.Count > 0 ? (T[])stack.Pop() : new T[size]; m_AllocatedArrays.Add((result, (typeof(T), size))); return result; } /// /// Allocate a temporary MaterialPropertyBlock for the Render Pass. /// /// A new clean MaterialPropertyBlock. public MaterialPropertyBlock GetTempMaterialPropertyBlock() { var result = SharedObjectPool.Get(); result.Clear(); m_AllocatedMaterialPropertyBlocks.Add(result); return result; } internal void ReleaseAllTempAlloc() { foreach (var arrayDesc in m_AllocatedArrays) { bool result = m_ArrayPool.TryGetValue(arrayDesc.Item2, out var stack); Debug.Assert(result, "Correct stack type should always be allocated."); stack.Push(arrayDesc.Item1); } m_AllocatedArrays.Clear(); foreach (var mpb in m_AllocatedMaterialPropertyBlocks) { SharedObjectPool.Release(mpb); } m_AllocatedMaterialPropertyBlocks.Clear(); } // Regular pooling API. Only internal use for now internal T Get() where T : class, new() { return SharedObjectPool.Get(); } internal void Release(T value) where T : class, new() { SharedObjectPool.Release(value); } internal void Cleanup() { m_AllocatedArrays.Clear(); m_AllocatedMaterialPropertyBlocks.Clear(); m_ArrayPool.Clear(); // Removing all objects in the pools foreach (var pool in s_AllocatedPools) pool.Clear(); } } }