A game about forced loneliness, made by TACStudios
at master 213 lines 6.3 kB view raw
1using System.Collections.Generic; 2using Unity.Collections; 3using UnityEngine.Profiling; 4using UnityEngine.Rendering; 5#if UNITY_EDITOR 6using UnityEditor; 7#endif 8 9namespace UnityEngine.U2D.Animation 10{ 11 internal class VertexBuffer 12 { 13 /// <summary> 14 /// Number of buffers currently allocated. 15 /// </summary> 16 public int bufferCount => m_Buffers.Length; 17 18 private readonly int m_Id; 19 private bool m_IsActive = true; 20 private int m_DeactivateFrame = -1; 21 22 private NativeByteArray[] m_Buffers; 23 private int m_ActiveIndex = 0; 24 25 public VertexBuffer(int id, int size, bool needDoubleBuffering) 26 { 27 m_Id = id; 28 29 var noOfBuffers = needDoubleBuffering ? 2 : 1; 30 m_Buffers = new NativeByteArray[noOfBuffers]; 31 for (var i = 0; i < noOfBuffers; i++) 32 m_Buffers[i] = new NativeByteArray(new NativeArray<byte>(size, Allocator.Persistent, NativeArrayOptions.UninitializedMemory)); 33 } 34 35 public override int GetHashCode() => m_Id; 36 private static int GetCurrentFrame() => Time.frameCount; 37 38 public NativeByteArray GetBuffer(int size) 39 { 40 if (!m_IsActive) 41 { 42 Debug.LogError($"Cannot request deactivated buffer. ID: {m_Id}"); 43 return null; 44 } 45 46 m_ActiveIndex = (m_ActiveIndex + 1) % m_Buffers.Length; 47 if (m_Buffers[m_ActiveIndex].Length != size) 48 ResizeBuffer(m_ActiveIndex, size); 49 50 return m_Buffers[m_ActiveIndex]; 51 } 52 53 private void ResizeBuffer(int bufferId, int newSize) 54 { 55 m_Buffers[bufferId].Dispose(); 56 m_Buffers[bufferId] = new NativeByteArray(new NativeArray<byte>(newSize, Allocator.Persistent, NativeArrayOptions.UninitializedMemory)); 57 } 58 59 public void Deactivate() 60 { 61 if (!m_IsActive) 62 return; 63 64 m_IsActive = false; 65 m_DeactivateFrame = GetCurrentFrame(); 66 } 67 68 public void Dispose() 69 { 70 for (var i = 0; i < m_Buffers.Length; i++) 71 { 72 if (m_Buffers[i].IsCreated) 73 m_Buffers[i].Dispose(); 74 } 75 } 76 77 public bool IsSafeToDispose() => !m_IsActive && GetCurrentFrame() > m_DeactivateFrame; 78 } 79 80 internal class BufferManager : ScriptableObject 81 { 82 private static BufferManager s_Instance; 83 84 private Dictionary<int, VertexBuffer> m_Buffers = new Dictionary<int, VertexBuffer>(); 85 private Queue<VertexBuffer> m_BuffersToDispose = new Queue<VertexBuffer>(); 86 87 /// <summary> 88 /// Number of buffers currently allocated. 89 /// </summary> 90 public int bufferCount 91 { 92 get 93 { 94 var count = 0; 95 foreach (var buffer in m_Buffers.Values) 96 count += buffer.bufferCount; 97 return count; 98 } 99 } 100 101 /// <summary> 102 /// Creates two buffers instead of one if enabled. 103 /// </summary> 104 public bool needDoubleBuffering { get; set; } 105 106 public static BufferManager instance 107 { 108 get 109 { 110 if (s_Instance == null) 111 { 112 var bufferMGRs = Resources.FindObjectsOfTypeAll<BufferManager>(); 113 if (bufferMGRs.Length > 0) 114 s_Instance = bufferMGRs[0]; 115 else 116 s_Instance = ScriptableObject.CreateInstance<BufferManager>(); 117 s_Instance.hideFlags = HideFlags.HideAndDontSave; 118 } 119 120 return s_Instance; 121 } 122 } 123 124 private void OnEnable() 125 { 126 if (s_Instance == null) 127 s_Instance = this; 128 129 needDoubleBuffering = SystemInfo.renderingThreadingMode != RenderingThreadingMode.Direct; 130#if UNITY_EDITOR 131 EditorApplication.update += Update; 132#else 133 Application.onBeforeRender += Update; 134#endif 135 } 136 137 private void OnDisable() 138 { 139 if (s_Instance == this) 140 s_Instance = null; 141 142 ForceClearBuffers(); 143 144#if UNITY_EDITOR 145 EditorApplication.update -= Update; 146#else 147 Application.onBeforeRender -= Update; 148#endif 149 } 150 151 private void ForceClearBuffers() 152 { 153 foreach (var vertexBuffer in m_Buffers.Values) 154 vertexBuffer.Dispose(); 155 foreach (var vertexBuffer in m_BuffersToDispose) 156 vertexBuffer.Dispose(); 157 158 m_Buffers.Clear(); 159 m_BuffersToDispose.Clear(); 160 } 161 162 public NativeByteArray GetBuffer(int id, int bufferSize) 163 { 164 Profiler.BeginSample("BufferManager.GetBuffer"); 165 var foundBuffer = m_Buffers.TryGetValue(id, out var buffer); 166 if (!foundBuffer) 167 buffer = CreateBuffer(id, bufferSize); 168 169 Profiler.EndSample(); 170 return buffer?.GetBuffer(bufferSize); 171 } 172 173 private VertexBuffer CreateBuffer(int id, int bufferSize) 174 { 175 if (bufferSize < 1) 176 { 177 Debug.LogError("Cannot create a buffer smaller than 1 byte."); 178 return null; 179 } 180 181 var buffer = new VertexBuffer(id, bufferSize, needDoubleBuffering); 182 m_Buffers.Add(id, buffer); 183 184 return buffer; 185 } 186 187 public void ReturnBuffer(int id) 188 { 189 Profiler.BeginSample("BufferManager.ReturnBuffer"); 190 if (m_Buffers.TryGetValue(id, out var buffer)) 191 { 192 buffer.Deactivate(); 193 m_BuffersToDispose.Enqueue(buffer); 194 m_Buffers.Remove(id); 195 } 196 197 Profiler.EndSample(); 198 } 199 200 private void Update() 201 { 202 Profiler.BeginSample("BufferManager.Update"); 203 204 while (m_BuffersToDispose.Count > 0 && m_BuffersToDispose.Peek().IsSafeToDispose()) 205 { 206 var buffer = m_BuffersToDispose.Dequeue(); 207 buffer.Dispose(); 208 } 209 210 Profiler.EndSample(); 211 } 212 } 213}