A game about forced loneliness, made by TACStudios
at master 318 lines 12 kB view raw
1using System; 2using System.Collections.Generic; 3using UnityEngine.Assertions; 4using UnityEngine.Rendering; 5 6namespace UnityEngine.Rendering 7{ 8 /// <summary> 9 /// Implement a multiple buffering for RenderTextures. 10 /// </summary> 11 /// <example> 12 /// <code> 13 /// enum BufferType 14 /// { 15 /// Color, 16 /// Depth 17 /// } 18 /// 19 /// void Render() 20 /// { 21 /// var camera = GetCamera(); 22 /// var buffers = GetFrameHistoryBuffersFor(camera); 23 /// 24 /// // Set reference size in case the rendering size changed this frame 25 /// buffers.SetReferenceSize( 26 /// GetCameraWidth(camera), GetCameraHeight(camera), 27 /// GetCameraUseMSAA(camera), GetCameraMSAASamples(camera) 28 /// ); 29 /// buffers.Swap(); 30 /// 31 /// var currentColor = buffer.GetFrameRT((int)BufferType.Color, 0); 32 /// if (currentColor == null) // Buffer was not allocated 33 /// { 34 /// buffer.AllocBuffer( 35 /// (int)BufferType.Color, // Color buffer id 36 /// ColorBufferAllocator, // Custom functor to implement allocation 37 /// 2 // Use 2 RT for this buffer for double buffering 38 /// ); 39 /// currentColor = buffer.GetFrameRT((int)BufferType.Color, 0); 40 /// } 41 /// 42 /// var previousColor = buffers.GetFrameRT((int)BufferType.Color, 1); 43 /// 44 /// // Use previousColor and write into currentColor 45 /// } 46 /// </code> 47 /// </example> 48 public class BufferedRTHandleSystem : IDisposable 49 { 50 Dictionary<int, RTHandle[]> m_RTHandles = new Dictionary<int, RTHandle[]>(); 51 52 RTHandleSystem m_RTHandleSystem = new RTHandleSystem(); 53 bool m_DisposedValue = false; 54 55 /// <summary> 56 /// Maximum allocated width of the Buffered RTHandle System 57 /// </summary> 58 public int maxWidth { get { return m_RTHandleSystem.GetMaxWidth(); } } 59 /// <summary> 60 /// Maximum allocated height of the Buffered RTHandle System 61 /// </summary> 62 public int maxHeight { get { return m_RTHandleSystem.GetMaxHeight(); } } 63 /// <summary> 64 /// Current properties of the Buffered RTHandle System 65 /// </summary> 66 public RTHandleProperties rtHandleProperties { get { return m_RTHandleSystem.rtHandleProperties; } } 67 68 /// <summary> 69 /// Return the frame RT or null. 70 /// </summary> 71 /// <param name="bufferId">Defines the buffer to use.</param> 72 /// <param name="frameIndex">Defines which frame to access within the buffer.</param> 73 /// <returns>The frame RT or null when the <paramref name="bufferId"/> was not previously allocated (<see cref="BufferedRTHandleSystem.AllocBuffer(int, Func{RTHandleSystem, int, RTHandle}, int)" />).</returns> 74 public RTHandle GetFrameRT(int bufferId, int frameIndex) 75 { 76 if (!m_RTHandles.ContainsKey(bufferId)) 77 return null; 78 79 Assert.IsTrue(frameIndex >= 0 && frameIndex < m_RTHandles[bufferId].Length); 80 81 return m_RTHandles[bufferId][frameIndex]; 82 } 83 84 /// <summary> 85 /// Clears all the previously created history buffers 86 /// </summary> 87 /// <param name="cmd">Defines the command buffer used for clearing.</param> 88 89 public void ClearBuffers(CommandBuffer cmd) 90 { 91 foreach (var rtHandle in m_RTHandles) 92 { 93 for (int i = 0; i < rtHandle.Value.Length; ++i) 94 { 95 CoreUtils.SetRenderTarget(cmd, rtHandle.Value[i], clearFlag: ClearFlag.Color, clearColor: Color.black); 96 } 97 } 98 } 99 100 /// <summary> 101 /// Allocate RT handles for a buffer. 102 /// </summary> 103 /// <param name="bufferId">The buffer to allocate.</param> 104 /// <param name="allocator">The functor to use for allocation.</param> 105 /// <param name="bufferCount">The number of RT handles for this buffer.</param> 106 public void AllocBuffer( 107 int bufferId, 108 Func<RTHandleSystem, int, RTHandle> allocator, 109 int bufferCount 110 ) 111 { 112 // This function should only be used when there is a non-zero number of buffers to allocate. 113 // If the caller provides a value of zero, they're likely doing something unintentional in the calling code. 114 Debug.Assert(bufferCount > 0); 115 116 var buffer = new RTHandle[bufferCount]; 117 m_RTHandles.Add(bufferId, buffer); 118 119 // First is autoresized 120 buffer[0] = allocator(m_RTHandleSystem, 0); 121 122 // Other are resized on demand 123 for (int i = 1, c = buffer.Length; i < c; ++i) 124 { 125 buffer[i] = allocator(m_RTHandleSystem, i); 126 m_RTHandleSystem.SwitchResizeMode(buffer[i], RTHandleSystem.ResizeMode.OnDemand); 127 } 128 } 129 130 /// <summary> 131 /// Allocate RT handles for a buffer using a RenderTextureDescriptor. 132 /// </summary> 133 /// <param name="bufferId">The buffer to allocate.</param> 134 /// <param name="bufferCount">The number of RT handles for this buffer.</param> 135 /// <param name="descriptor">RenderTexture descriptor of the RTHandles.</param> 136 /// <param name="filterMode">Filtering mode of the RTHandles.</param> 137 /// <param name="wrapMode">Addressing mode of the RTHandles.</param> 138 /// <param name="isShadowMap">Set to true if the depth buffer should be used as a shadow map.</param> 139 /// <param name="anisoLevel">Anisotropic filtering level.</param> 140 /// <param name="mipMapBias">Bias applied to mipmaps during filtering.</param> 141 /// <param name="name">Name of the RTHandle.</param> 142 // NOTE: API is similar to RTHandles.Alloc. 143 public void AllocBuffer(int bufferId, int bufferCount, 144 ref RenderTextureDescriptor descriptor, 145 FilterMode filterMode = FilterMode.Point, 146 TextureWrapMode wrapMode = TextureWrapMode.Repeat, 147 bool isShadowMap = false, 148 int anisoLevel = 1, 149 float mipMapBias = 0, 150 string name = "") 151 { 152 // This function should only be used when there is a non-zero number of buffers to allocate. 153 // If the caller provides a value of zero, they're likely doing something unintentional in the calling code. 154 Debug.Assert(bufferCount > 0); 155 156 var buffer = new RTHandle[bufferCount]; 157 m_RTHandles.Add(bufferId, buffer); 158 159 var format = RTHandles.GetFormat(descriptor.graphicsFormat, descriptor.depthStencilFormat); 160 161 RTHandle Alloc(ref RenderTextureDescriptor d, FilterMode fMode, TextureWrapMode wMode, bool isShadow, int aniso, float mipBias, string n) 162 { 163 return m_RTHandleSystem.Alloc( 164 d.width, 165 d.height, 166 format, 167 d.volumeDepth, 168 fMode, 169 wMode, 170 d.dimension, 171 d.enableRandomWrite, 172 d.useMipMap, 173 d.autoGenerateMips, 174 isShadow, 175 aniso, 176 mipBias, 177 (MSAASamples)d.msaaSamples, 178 d.bindMS, 179 d.useDynamicScale, 180 d.useDynamicScaleExplicit, 181 d.memoryless, 182 d.vrUsage, 183 n); 184 } 185 186 // First is autoresized 187 buffer[0] = Alloc(ref descriptor, filterMode, wrapMode, isShadowMap, anisoLevel, mipMapBias, name); 188 189 // Other are resized on demand 190 for (int i = 1, c = buffer.Length; i < c; ++i) 191 { 192 buffer[i] = Alloc(ref descriptor, filterMode, wrapMode, isShadowMap, anisoLevel, mipMapBias, name); 193 m_RTHandleSystem.SwitchResizeMode(buffer[i], RTHandleSystem.ResizeMode.OnDemand); 194 } 195 } 196 197 /// <summary> 198 /// Release a buffer 199 /// </summary> 200 /// <param name="bufferId">Id of the buffer that needs to be released.</param> 201 public void ReleaseBuffer(int bufferId) 202 { 203 if (m_RTHandles.TryGetValue(bufferId, out var buffers)) 204 { 205 foreach (var rt in buffers) 206 m_RTHandleSystem.Release(rt); 207 } 208 209 m_RTHandles.Remove(bufferId); 210 } 211 212 /// <summary> 213 /// Swap buffers Set the reference size for this RT Handle System (<see cref="RTHandleSystem.SetReferenceSize(int, int, bool)"/>) 214 /// </summary> 215 /// <param name="width">The width of the RTs of this buffer.</param> 216 /// <param name="height">The height of the RTs of this buffer.</param> 217 public void SwapAndSetReferenceSize(int width, int height) 218 { 219 Swap(); 220 m_RTHandleSystem.SetReferenceSize(width, height); 221 } 222 223 /// <summary> 224 /// Reset the reference size of the system and reallocate all textures. 225 /// </summary> 226 /// <param name="width">New width.</param> 227 /// <param name="height">New height.</param> 228 public void ResetReferenceSize(int width, int height) 229 { 230 m_RTHandleSystem.ResetReferenceSize(width, height); 231 } 232 233 /// <summary> 234 /// Queries the number of RT handle buffers allocated for a buffer ID. 235 /// </summary> 236 /// <param name="bufferId">The buffer ID to query.</param> 237 /// <returns>The num of frames allocated</returns> 238 public int GetNumFramesAllocated(int bufferId) 239 { 240 if (!m_RTHandles.ContainsKey(bufferId)) 241 return 0; 242 243 return m_RTHandles[bufferId].Length; 244 } 245 246 /// <summary> 247 /// Returns the ratio against the current target's max resolution 248 /// </summary> 249 /// <param name="width">width to utilize</param> 250 /// <param name="height">height to utilize</param> 251 /// <returns> retruns the width,height / maxTargetSize.xy ratio. </returns> 252 public Vector2 CalculateRatioAgainstMaxSize(int width, int height) 253 { 254 return m_RTHandleSystem.CalculateRatioAgainstMaxSize(new Vector2Int(width, height)); 255 } 256 257 void Swap() 258 { 259 foreach (var item in m_RTHandles) 260 { 261 // Do not index out of bounds... 262 if (item.Value.Length > 1) 263 { 264 var nextFirst = item.Value[item.Value.Length - 1]; 265 for (int i = 0, c = item.Value.Length - 1; i < c; ++i) 266 item.Value[i + 1] = item.Value[i]; 267 item.Value[0] = nextFirst; 268 269 // First is autoresize, other are on demand 270 m_RTHandleSystem.SwitchResizeMode(item.Value[0], RTHandleSystem.ResizeMode.Auto); 271 m_RTHandleSystem.SwitchResizeMode(item.Value[1], RTHandleSystem.ResizeMode.OnDemand); 272 } 273 else 274 { 275 m_RTHandleSystem.SwitchResizeMode(item.Value[0], RTHandleSystem.ResizeMode.Auto); 276 } 277 } 278 } 279 280 void Dispose(bool disposing) 281 { 282 if (!m_DisposedValue) 283 { 284 if (disposing) 285 { 286 ReleaseAll(); 287 m_RTHandleSystem.Dispose(); 288 m_RTHandleSystem = null; 289 } 290 291 m_DisposedValue = true; 292 } 293 } 294 295 /// <summary> 296 /// Dispose implementation 297 /// </summary> 298 public void Dispose() 299 { 300 Dispose(true); 301 } 302 303 /// <summary> 304 /// Deallocate and clear all buffers. 305 /// </summary> 306 public void ReleaseAll() 307 { 308 foreach (var item in m_RTHandles) 309 { 310 for (int i = 0, c = item.Value.Length; i < c; ++i) 311 { 312 m_RTHandleSystem.Release(item.Value[i]); 313 } 314 } 315 m_RTHandles.Clear(); 316 } 317 } 318}