A game about forced loneliness, made by TACStudios
at master 548 lines 24 kB view raw
1using System; 2using System.Diagnostics; 3using System.Runtime.CompilerServices; 4using UnityEngine.Experimental.Rendering; 5using UnityEngine.Rendering; 6using UnityEngine.Scripting.APIUpdating; 7 8namespace UnityEngine.Rendering.RenderGraphModule 9{ 10 internal struct TextureAccess 11 { 12 public TextureHandle textureHandle; 13 public int mipLevel; 14 public int depthSlice; 15 public AccessFlags flags; 16 17 public TextureAccess(TextureHandle handle, AccessFlags flags, int mipLevel, int depthSlice) 18 { 19 this.textureHandle = handle; 20 this.flags = flags; 21 this.mipLevel = mipLevel; 22 this.depthSlice = depthSlice; 23 } 24 } 25 26 27 /// <summary> 28 /// An abstract handle representing a texture resource as known by one particular record + execute of the render graph. 29 /// TextureHandles should not be used outside of the context of a render graph execution. 30 /// 31 /// A render graph needs to do additional state tracking on texture resources (lifetime, how is it used,...) to enable 32 /// this all textures relevant to the render graph need to be make known to it. A texture handle specifies such a texture as 33 /// known to the render graph. 34 /// 35 /// It is important to understand that a render graph texture handle does not necessarily represent an actual texture. For example 36 /// textures could be created the render graph that are only referenced by passes that are later culled when executing the graph. 37 /// Such textures would never be allocated as actual RenderTextures. 38 /// 39 /// Texture handles are only relevant to one particular record+execute phase of the render graph. After execution all texture 40 /// handles are invalidated. The system will catch texture handles from a different execution of the render graph but still 41 /// users should be careful to avoid keeping texture handles around from other render graph executions. 42 /// 43 /// Texture handles do not need to be disposed/freed (they are auto-invalidated at the end of graph execution). The RenderTextures they represent 44 /// are either freed by the render graph internally (when the handle was acquired through RenderGraph.CreateTexture) or explicitly managed by 45 /// some external system (when acquired through RenderGraph.ImportTexture). 46 /// 47 /// </summary> 48 [DebuggerDisplay("Texture ({handle.index})")] 49 [MovedFrom(true, "UnityEngine.Experimental.Rendering.RenderGraphModule", "UnityEngine.Rendering.RenderGraphModule")] 50 public struct TextureHandle 51 { 52 private static TextureHandle s_NullHandle = new TextureHandle(); 53 54 /// <summary> 55 /// Returns a null texture handle 56 /// </summary> 57 /// <value>A null texture handle.</value> 58 public static TextureHandle nullHandle { get { return s_NullHandle; } } 59 60 internal ResourceHandle handle; 61 62 private bool builtin; 63 64 internal TextureHandle(in ResourceHandle h) 65 { 66 handle = h; 67 builtin = false; 68 } 69 70 internal TextureHandle(int handle, bool shared = false, bool builtin = false) 71 { 72 this.handle = new ResourceHandle(handle, RenderGraphResourceType.Texture, shared); 73 this.builtin = builtin; 74 } 75 76 /// <summary> 77 /// Cast to RenderTargetIdentifier 78 /// </summary> 79 /// <param name="texture">Input TextureHandle.</param> 80 /// <returns>Resource as a RenderTargetIdentifier.</returns> 81 public static implicit operator RenderTargetIdentifier(TextureHandle texture) => texture.IsValid() ? RenderGraphResourceRegistry.current.GetTexture(texture) : default(RenderTargetIdentifier); 82 83 /// <summary> 84 /// Cast to Texture 85 /// </summary> 86 /// <param name="texture">Input TextureHandle.</param> 87 /// <returns>Resource as a Texture.</returns> 88 public static implicit operator Texture(TextureHandle texture) => texture.IsValid() ? RenderGraphResourceRegistry.current.GetTexture(texture) : null; 89 90 /// <summary> 91 /// Cast to RenderTexture 92 /// </summary> 93 /// <param name="texture">Input TextureHandle.</param> 94 /// <returns>Resource as a RenderTexture.</returns> 95 public static implicit operator RenderTexture(TextureHandle texture) => texture.IsValid() ? RenderGraphResourceRegistry.current.GetTexture(texture) : null; 96 97 /// <summary> 98 /// Cast to RTHandle 99 /// </summary> 100 /// <param name="texture">Input TextureHandle.</param> 101 /// <returns>Resource as a RTHandle.</returns> 102 public static implicit operator RTHandle(TextureHandle texture) => texture.IsValid() ? RenderGraphResourceRegistry.current.GetTexture(texture) : null; 103 104 /// <summary> 105 /// Return true if the handle is valid. 106 /// </summary> 107 /// <returns>True if the handle is valid.</returns> 108 [MethodImpl(MethodImplOptions.AggressiveInlining)] 109 public bool IsValid() => handle.IsValid(); 110 111 /// <summary> 112 /// Return true if the handle is a builtin handle managed by RenderGraph internally. 113 /// </summary> 114 /// <returns>True if the handle is a builtin handle.</returns> 115 [MethodImpl(MethodImplOptions.AggressiveInlining)] 116 internal bool IsBuiltin() => this.builtin; 117 118 /// <summary> 119 /// Get the Descriptor of the texture. This simply calls RenderGraph.GetTextureDesc but is more easily discoverable through auto complete. 120 /// </summary> 121 /// <param name="renderGraph">The rendergraph instance that was used to create the texture on. Texture handles are a lightweight object, all information is stored on the RenderGraph itself.</param> 122 /// <returns>The texture descriptor for the given texture handle.</returns> 123 public TextureDesc GetDescriptor(RenderGraph renderGraph) { return renderGraph.GetTextureDesc(this); } 124 } 125 126 /// <summary> 127 /// The mode that determines the size of a Texture. 128 /// </summary> 129 public enum TextureSizeMode 130 { 131 ///<summary>Explicit size.</summary> 132 Explicit, 133 ///<summary>Size automatically scaled by a Vector.</summary> 134 Scale, 135 ///<summary>Size automatically scaled by a Functor.</summary> 136 Functor 137 } 138 139#if UNITY_2020_2_OR_NEWER 140 /// <summary> 141 /// Subset of the texture desc containing information for fast memory allocation (when platform supports it) 142 /// </summary> 143 public struct FastMemoryDesc 144 { 145 ///<summary>Whether the texture will be in fast memory.</summary> 146 public bool inFastMemory; 147 ///<summary>Flag to determine what parts of the render target is spilled if not fully resident in fast memory.</summary> 148 public FastMemoryFlags flags; 149 ///<summary>How much of the render target is to be switched into fast memory (between 0 and 1).</summary> 150 public float residencyFraction; 151 } 152#endif 153 154 /// <summary> 155 /// Descriptor used to create texture resources 156 /// </summary> 157 public struct TextureDesc 158 { 159 ///<summary>Texture sizing mode.</summary> 160 public TextureSizeMode sizeMode; 161 ///<summary>Texture width.</summary> 162 public int width; 163 ///<summary>Texture height.</summary> 164 public int height; 165 ///<summary>Number of texture slices..</summary> 166 public int slices; 167 ///<summary>Texture scale.</summary> 168 public Vector2 scale; 169 ///<summary>Texture scale function.</summary> 170 public ScaleFunc func; 171 ///<summary>Color or depth stencil format.</summary> 172 public GraphicsFormat format; 173 ///<summary>Filtering mode.</summary> 174 public FilterMode filterMode; 175 ///<summary>Addressing mode.</summary> 176 public TextureWrapMode wrapMode; 177 ///<summary>Texture dimension.</summary> 178 public TextureDimension dimension; 179 ///<summary>Enable random UAV read/write on the texture.</summary> 180 public bool enableRandomWrite; 181 ///<summary>Texture needs mip maps.</summary> 182 public bool useMipMap; 183 ///<summary>Automatically generate mip maps.</summary> 184 public bool autoGenerateMips; 185 ///<summary>Texture is a shadow map.</summary> 186 public bool isShadowMap; 187 ///<summary>Anisotropic filtering level.</summary> 188 public int anisoLevel; 189 ///<summary>Mip map bias.</summary> 190 public float mipMapBias; 191 ///<summary>Number of MSAA samples.</summary> 192 public MSAASamples msaaSamples; 193 ///<summary>Bind texture multi sampled.</summary> 194 public bool bindTextureMS; 195 ///<summary>[See Dynamic Resolution documentation](https://docs.unity3d.com/Manual/DynamicResolution.html)</summary> 196 public bool useDynamicScale; 197 ///<summary>[See Dynamic Resolution documentation](https://docs.unity3d.com/Manual/DynamicResolution.html)</summary> 198 public bool useDynamicScaleExplicit; 199 ///<summary>Memory less flag.</summary> 200 public RenderTextureMemoryless memoryless; 201 ///<summary>Special treatment of the VR eye texture used in stereoscopic rendering.</summary> 202 public VRTextureUsage vrUsage; 203 ///<summary>Texture name.</summary> 204 public string name; 205#if UNITY_2020_2_OR_NEWER 206 ///<summary>Descriptor to determine how the texture will be in fast memory on platform that supports it.</summary> 207 public FastMemoryDesc fastMemoryDesc; 208#endif 209 ///<summary>Determines whether the texture will fallback to a black texture if it is read without ever writing to it.</summary> 210 public bool fallBackToBlackTexture; 211 ///<summary> 212 ///If all passes writing to a texture are culled by Dynamic Render Pass Culling, it will automatically fallback to a similar preallocated texture. 213 ///Set this to true to force the allocation. 214 ///</summary> 215 public bool disableFallBackToImportedTexture; 216 217 // Initial state. Those should not be used in the hash 218 ///<summary>Texture needs to be cleared on first use.</summary> 219 public bool clearBuffer; 220 ///<summary>Clear color.</summary> 221 public Color clearColor; 222 223 ///<summary>Texture needs to be discarded on last use.</summary> 224 public bool discardBuffer; 225 226 227 ///<summary>Depth buffer bit depth of the format. The setter convert the bits to valid depth stencil format and sets the format. The getter gets the depth bits of the format.</summary> 228 public DepthBits depthBufferBits 229 { 230 get { return (DepthBits)GraphicsFormatUtility.GetDepthBits(format); } 231 set 232 { 233 if (value == DepthBits.None) 234 { 235 if( !GraphicsFormatUtility.IsDepthStencilFormat(format) ) 236 return; 237 else 238 format = GraphicsFormat.None; 239 } 240 else 241 { 242 format = GraphicsFormatUtility.GetDepthStencilFormat((int)value); 243 } 244 } 245 } 246 247 ///<summary>Color format. Sets the format. The getter checks if format is a color format. Returns the format if a color format, otherwise returns GraphicsFormat.None.</summary> 248 public GraphicsFormat colorFormat 249 { 250 get { return GraphicsFormatUtility.IsDepthStencilFormat(format) ? GraphicsFormat.None : format; } 251 set { format = value; } 252 } 253 254 void InitDefaultValues(bool dynamicResolution, bool xrReady) 255 { 256 useDynamicScale = dynamicResolution; 257 vrUsage = VRTextureUsage.None; 258 // XR Ready 259 if (xrReady) 260 { 261 slices = TextureXR.slices; 262 dimension = TextureXR.dimension; 263 } 264 else 265 { 266 slices = 1; 267 dimension = TextureDimension.Tex2D; 268 } 269 270 discardBuffer = false; 271 } 272 273 /// <summary> 274 /// TextureDesc constructor for a texture using explicit size 275 /// </summary> 276 /// <param name="width">Texture width</param> 277 /// <param name="height">Texture height</param> 278 /// <param name="dynamicResolution">Use dynamic resolution</param> 279 /// <param name="xrReady">Set this to true if the Texture is a render texture in an XR setting.</param> 280 public TextureDesc(int width, int height, bool dynamicResolution = false, bool xrReady = false) 281 : this() 282 { 283 // Size related init 284 sizeMode = TextureSizeMode.Explicit; 285 this.width = width; 286 this.height = height; 287 // Important default values not handled by zero construction in this() 288 msaaSamples = MSAASamples.None; 289 InitDefaultValues(dynamicResolution, xrReady); 290 } 291 292 /// <summary> 293 /// TextureDesc constructor for a texture using a fixed scaling 294 /// </summary> 295 /// <param name="scale">RTHandle scale used for this texture</param> 296 /// <param name="dynamicResolution">Use dynamic resolution</param> 297 /// <param name="xrReady">Set this to true if the Texture is a render texture in an XR setting.</param> 298 public TextureDesc(Vector2 scale, bool dynamicResolution = false, bool xrReady = false) 299 : this() 300 { 301 // Size related init 302 sizeMode = TextureSizeMode.Scale; 303 this.scale = scale; 304 // Important default values not handled by zero construction in this() 305 msaaSamples = MSAASamples.None; 306 dimension = TextureDimension.Tex2D; 307 InitDefaultValues(dynamicResolution, xrReady); 308 } 309 310 /// <summary> 311 /// TextureDesc constructor for a texture using a functor for scaling 312 /// </summary> 313 /// <param name="func">Function used to determine the texture size</param> 314 /// <param name="dynamicResolution">Use dynamic resolution</param> 315 /// <param name="xrReady">Set this to true if the Texture is a render texture in an XR setting.</param> 316 public TextureDesc(ScaleFunc func, bool dynamicResolution = false, bool xrReady = false) 317 : this() 318 { 319 // Size related init 320 sizeMode = TextureSizeMode.Functor; 321 this.func = func; 322 // Important default values not handled by zero construction in this() 323 msaaSamples = MSAASamples.None; 324 dimension = TextureDimension.Tex2D; 325 InitDefaultValues(dynamicResolution, xrReady); 326 } 327 328 /// <summary> 329 /// Copy constructor 330 /// </summary> 331 /// <param name="input">The TextureDesc instance to copy from.</param> 332 public TextureDesc(TextureDesc input) 333 { 334 this = input; 335 } 336 337 /// <summary> 338 /// Do a best effort conversion from a RenderTextureDescriptor to a TextureDesc. This tries to initialize a descriptor to be as close as possible to the given render texture descriptor but there might be subtle differences when creating 339 /// render graph textures using this TextureDesc due to the underlying RTHandle system. 340 /// Some parameters of the TextureDesc (like name and filtering modes) are not present in the RenderTextureDescriptor for these the returned TextureDesc will contain plausible default values. 341 /// </summary> 342 /// <param name="input">The texture descriptor to create a TextureDesc from</param> 343 public TextureDesc(RenderTextureDescriptor input) 344 { 345 sizeMode = TextureSizeMode.Explicit; 346 width = input.width; 347 height = input.height; 348 slices = input.volumeDepth; 349 scale = Vector2.one; 350 func = null; 351 format = (input.depthStencilFormat != GraphicsFormat.None) ? input.depthStencilFormat : input.graphicsFormat; 352 filterMode = FilterMode.Bilinear; 353 wrapMode = TextureWrapMode.Clamp; 354 dimension = input.dimension; 355 enableRandomWrite = input.enableRandomWrite; 356 useMipMap = input.useMipMap; 357 autoGenerateMips = input.autoGenerateMips; 358 isShadowMap = (input.shadowSamplingMode != ShadowSamplingMode.None); 359 anisoLevel = 1; 360 mipMapBias = 0; 361 msaaSamples = (MSAASamples)input.msaaSamples; 362 bindTextureMS = input.bindMS; 363 useDynamicScale = input.useDynamicScale; 364 useDynamicScaleExplicit = false; 365 memoryless = input.memoryless; 366 vrUsage = input.vrUsage; 367 name = "UnNamedFromRenderTextureDescriptor"; 368 fastMemoryDesc = new FastMemoryDesc(); 369 fastMemoryDesc.inFastMemory = false; 370 fallBackToBlackTexture = false; 371 disableFallBackToImportedTexture = true; 372 clearBuffer = true; 373 clearColor = Color.black; 374 discardBuffer = false; 375 } 376 377 /// <summary> 378 /// Do a best effort conversion from a RenderTexture to a TextureDesc. This tries to initialize a descriptor to be as close as possible to the given render texture but there might be subtle differences when creating 379 /// render graph textures using this TextureDesc due to the underlying RTHandle system. 380 /// </summary> 381 /// <param name="input">The texture to create a TextureDesc from</param> 382 public TextureDesc(RenderTexture input) : this(input.descriptor) 383 { 384 filterMode = input.filterMode; 385 wrapMode = input.wrapMode; 386 anisoLevel = input.anisoLevel; 387 mipMapBias = input.mipMapBias; 388 name = "UnNamedFromRenderTextureDescriptor"; 389 } 390 391 /// <summary> 392 /// Hash function 393 /// </summary> 394 /// <returns>The texture descriptor hash.</returns> 395 public override int GetHashCode() 396 { 397 var hashCode = HashFNV1A32.Create(); 398 switch (sizeMode) 399 { 400 case TextureSizeMode.Explicit: 401 hashCode.Append(width); 402 hashCode.Append(height); 403 break; 404 case TextureSizeMode.Functor: 405 if (func != null) 406 hashCode.Append(func); 407 break; 408 case TextureSizeMode.Scale: 409 hashCode.Append(scale); 410 break; 411 } 412 413 hashCode.Append(mipMapBias); 414 hashCode.Append(slices); 415 hashCode.Append((int) format); 416 hashCode.Append((int) filterMode); 417 hashCode.Append((int) wrapMode); 418 hashCode.Append((int) dimension); 419 hashCode.Append((int) memoryless); 420 hashCode.Append((int) vrUsage); 421 hashCode.Append(anisoLevel); 422 hashCode.Append(enableRandomWrite); 423 hashCode.Append(useMipMap); 424 hashCode.Append(autoGenerateMips); 425 hashCode.Append(isShadowMap); 426 hashCode.Append(bindTextureMS); 427 hashCode.Append(useDynamicScale); 428 hashCode.Append((int) msaaSamples); 429#if UNITY_2020_2_OR_NEWER 430 hashCode.Append(fastMemoryDesc.inFastMemory); 431#endif 432 return hashCode.value; 433 } 434 435 /// <summary> 436 /// Calculate the final size of the texture descriptor in pixels. This takes into account the sizeMode set for this descriptor. 437 /// For the automatically scaled sizes the size will be relative to the RTHandle reference size <see cref="RTHandles.SetReferenceSize">SetReferenceSize</see>. 438 /// </summary> 439 /// <returns>The calculated size.</returns> 440 /// <exception cref="ArgumentOutOfRangeException">Thrown if the texture descriptor's size mode falls outside the expected range.</exception> 441 public Vector2Int CalculateFinalDimensions() 442 { 443 return sizeMode switch 444 { 445 TextureSizeMode.Explicit => new Vector2Int(width, height), 446 TextureSizeMode.Scale => RTHandles.CalculateDimensions(scale), 447 TextureSizeMode.Functor => RTHandles.CalculateDimensions(func), 448 _ => throw new ArgumentOutOfRangeException() 449 }; 450 451 } 452 } 453 454 [DebuggerDisplay("TextureResource ({desc.name})")] 455 class TextureResource : RenderGraphResource<TextureDesc, RTHandle> 456 { 457 static int m_TextureCreationIndex; 458 459 public override string GetName() 460 { 461 if (imported && !shared) 462 return graphicsResource != null ? graphicsResource.name : "null resource"; 463 else 464 return desc.name; 465 } 466 467 [MethodImpl(MethodImplOptions.AggressiveInlining)] 468 public override int GetDescHashCode() { return desc.GetHashCode(); } 469 470 public override void CreateGraphicsResource() 471 { 472 var name = GetName(); 473 474 // Textures are going to be reused under different aliases along the frame so we can't provide a specific name upon creation. 475 // The name in the desc is going to be used for debugging purpose and render graph visualization. 476 if (name == "") 477 name = $"RenderGraphTexture_{m_TextureCreationIndex++}"; 478 479 switch (desc.sizeMode) 480 { 481 case TextureSizeMode.Explicit: 482 graphicsResource = RTHandles.Alloc(desc.width, desc.height, desc.format, desc.slices, desc.filterMode, desc.wrapMode, desc.dimension, desc.enableRandomWrite, 483 desc.useMipMap, desc.autoGenerateMips, desc.isShadowMap, desc.anisoLevel, desc.mipMapBias, desc.msaaSamples, desc.bindTextureMS, desc.useDynamicScale, desc.useDynamicScaleExplicit, desc.memoryless, desc.vrUsage, name); 484 break; 485 case TextureSizeMode.Scale: 486 graphicsResource = RTHandles.Alloc(desc.scale, desc.format, desc.slices, desc.filterMode, desc.wrapMode, desc.dimension, desc.enableRandomWrite, 487 desc.useMipMap, desc.autoGenerateMips, desc.isShadowMap, desc.anisoLevel, desc.mipMapBias, desc.msaaSamples, desc.bindTextureMS, desc.useDynamicScale, desc.useDynamicScaleExplicit, desc.memoryless, desc.vrUsage, name); 488 break; 489 case TextureSizeMode.Functor: 490 graphicsResource = RTHandles.Alloc(desc.func, desc.format, desc.slices, desc.filterMode, desc.wrapMode, desc.dimension, desc.enableRandomWrite, 491 desc.useMipMap, desc.autoGenerateMips, desc.isShadowMap, desc.anisoLevel, desc.mipMapBias, desc.msaaSamples, desc.bindTextureMS, desc.useDynamicScale, desc.useDynamicScaleExplicit, desc.memoryless, desc.vrUsage, name); 492 break; 493 } 494 } 495 496 [MethodImpl(MethodImplOptions.AggressiveInlining)] 497 public override void UpdateGraphicsResource() 498 { 499 if (graphicsResource != null) 500 graphicsResource.m_Name = GetName(); 501 } 502 503 public override void ReleaseGraphicsResource() 504 { 505 if (graphicsResource != null) 506 graphicsResource.Release(); 507 base.ReleaseGraphicsResource(); 508 } 509 510 public override void LogCreation(RenderGraphLogger logger) 511 { 512 logger.LogLine($"Created Texture: {desc.name} (Cleared: {desc.clearBuffer})"); 513 } 514 515 public override void LogRelease(RenderGraphLogger logger) 516 { 517 logger.LogLine($"Released Texture: {desc.name}"); 518 } 519 } 520 521 class TexturePool : RenderGraphResourcePool<RTHandle> 522 { 523 protected override void ReleaseInternalResource(RTHandle res) 524 { 525 res.Release(); 526 } 527 528 protected override string GetResourceName(in RTHandle res) 529 { 530 return res.rt.name; 531 } 532 533 protected override long GetResourceSize(in RTHandle res) 534 { 535 return Profiling.Profiler.GetRuntimeMemorySizeLong(res.rt); 536 } 537 538 override protected string GetResourceTypeName() 539 { 540 return "Texture"; 541 } 542 543 override protected int GetSortIndex(RTHandle res) 544 { 545 return res.GetInstanceID(); 546 } 547 } 548}