//#define USE_CUSTOM_TEMPORARY using UnityEngine; using System.Collections.Generic; namespace CW.Common { [ExecuteInEditMode] [DefaultExecutionOrder(1000)] [HelpURL(CwShared.HelpUrlPrefix + "CwRenderTextureManager")] [AddComponentMenu(CwShared.ComponentMenuPrefix + "Render Texture Manager")] public class CwRenderTextureManager : MonoBehaviour { /// This allows you to set how many frames an unused RenderTexture will remaining in memory before it's released. public int Lifetime { set { lifetime = value; } get { return lifetime; } } [SerializeField] private int lifetime = 3; #if USE_CUSTOM_TEMPORARY private class Entry { public RenderTexture RT; public RenderTextureDescriptor Desc; public int Life; public static Stack Pool = new Stack(); } private static List entries = new List(); private static LinkedList instances = new LinkedList(); private LinkedListNode node; public static RenderTexture GetTemporary(RenderTextureDescriptor desc, string title) { if (instances.Count == 0) { new GameObject("CwRenderTextureManager").AddComponent(); } for (var i = entries.Count - 1; i >= 0; i--) { var entry = entries[i]; if (entry.RT == null) { entry.RT = null; Entry.Pool.Push(entry); entries.RemoveAt(i); continue; } if (Match(ref entry.Desc, ref desc) == true) { Entry.Pool.Push(entry); entries.RemoveAt(i); entry.RT.name = title; if (entry.RT.IsCreated() == false) { entry.RT.Create(); } return entry.RT; } } var rt = new RenderTexture(desc); rt.name = title; return rt; } public static RenderTexture ReleaseTemporary(RenderTexture rt) { if (rt != null) { if (instances.Count > 0) { var entry = Entry.Pool.Count > 0 ? Entry.Pool.Pop() : new Entry(); entry.RT = rt; entry.Desc = rt.descriptor; entry.Life = Mathf.Max(1, instances.First.Value.lifetime); entries.Add(entry); rt.DiscardContents(); } else { rt.Release(); DestroyImmediate(rt); } } return null; } protected virtual void OnEnable() { node = instances.AddLast(this); } protected virtual void OnDisable() { instances.Remove(node); node = null; if (instances.Count == 0) { for (var i = entries.Count - 1; i >= 0; i--) { var entry = entries[i]; if (entry.RT != null) { entry.RT.Release(); DestroyImmediate(entry.RT); } Entry.Pool.Push(entry); } entries.Clear(); } } protected virtual void LateUpdate() { if (node == instances.First) { Tick(); } } private void Tick() { for (var i = entries.Count - 1; i >= 0; i--) { var entry = entries[i]; if (entry.Life > 0) { entry.Life -= 1; if (entry.Life == 0 && entry.RT != null && entry.RT.IsCreated() == true) { entry.RT.Release(); } } } } private static bool Match(ref RenderTextureDescriptor a, ref RenderTextureDescriptor b) { if (a.enableRandomWrite != b.enableRandomWrite) return false; if (a.autoGenerateMips != b.autoGenerateMips) return false; if (a.useMipMap != b.useMipMap) return false; if (a.memoryless != b.memoryless) return false; if (a.flags != b.flags) return false; if (a.vrUsage != b.vrUsage) return false; if (a.shadowSamplingMode != b.shadowSamplingMode) return false; if (a.dimension != b.dimension) return false; if (a.depthBufferBits != b.depthBufferBits) return false; if (a.stencilFormat != b.stencilFormat) return false; if (a.colorFormat != b.colorFormat) return false; if (a.bindMS != b.bindMS) return false; if (a.graphicsFormat != b.graphicsFormat) return false; if (a.mipCount != b.mipCount) return false; if (a.volumeDepth != b.volumeDepth) return false; if (a.msaaSamples != b.msaaSamples) return false; if (a.height != b.height) return false; if (a.width != b.width) return false; if (a.sRGB != b.sRGB) return false; if (a.useDynamicScale != b.useDynamicScale) return false; return true; } #else public static RenderTexture GetTemporary(RenderTextureDescriptor desc, string title) { var renderTexture = RenderTexture.GetTemporary(desc); // TODO: For some reason RenderTexture.GetTemporary ignores the useMipMap flag?! if (renderTexture.useMipMap != desc.useMipMap) { renderTexture.Release(); renderTexture.descriptor = desc; renderTexture.Create(); } return renderTexture; } public static RenderTexture ReleaseTemporary(RenderTexture renderTexture) { if (renderTexture != null) { renderTexture.DiscardContents(); RenderTexture.ReleaseTemporary(renderTexture); } return null; } #endif } } #if UNITY_EDITOR namespace CW.Common { using UnityEditor; using TARGET = CwRenderTextureManager; [CanEditMultipleObjects] [CustomEditor(typeof(TARGET))] public class CwRenderTextureManager_Editor : CwEditor { protected override void OnInspector() { TARGET tgt; TARGET[] tgts; GetTargets(out tgt, out tgts); Draw("lifetime", "This allows you to set how many frames an unused RenderTexture will remaining in memory before it's released."); } } } #endif