A game about forced loneliness, made by TACStudios
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}