A game about forced loneliness, made by TACStudios
1using System;
2using UnityEngine.Assertions;
3using UnityEngine.Experimental.Rendering;
4using UnityEngine.Rendering.RenderGraphModule;
5
6namespace UnityEngine.Rendering
7{
8 /// <summary>
9 /// Interface to the Spatial-Temporal Post-Processing Upscaler (STP).
10 /// This class allows users to configure and execute STP via render graph.
11 /// </summary>
12 public static class STP
13 {
14 /// <summary>
15 /// Returns true if STP is supported on the current device. Otherwise, false.
16 /// STP requires compute shaders
17 /// </summary>
18 /// <returns>True if supported</returns>
19 public static bool IsSupported()
20 {
21 bool isSupported = true;
22
23 // STP uses compute shaders as part of its implementation
24 isSupported &= SystemInfo.supportsComputeShaders;
25
26 // GLES has stricter rules than GL when it comes to image store format declarations and matching them with underlying image types.
27 // STP's implementation uses several image formats that don't translate accurately from HLSL to GLSL which means a format mismatch will occur.
28 // Image format mismatches result in undefined behavior on writes, so we disable STP support for GLES in order to avoid problems.
29 // In most cases, hardware that meets the requirements for STP should be capable of running Vulkan anyways.
30 isSupported &= (SystemInfo.graphicsDeviceType != GraphicsDeviceType.OpenGLES3);
31
32 return isSupported;
33 }
34
35 /// <summary>
36 /// Helper function that calculates the STP-specific jitter pattern associated with the provided frame index.
37 /// </summary>
38 /// <param name="frameIndex">Index of the current frame</param>
39 /// <returns>Jitter pattern for the provided frame index</returns>
40 public static Vector2 Jit16(int frameIndex)
41 {
42 Vector2 result;
43 result.x = HaltonSequence.Get(frameIndex, 2) - 0.5f;
44 result.y = HaltonSequence.Get(frameIndex, 3) - 0.5f;
45
46 return result;
47 }
48
49 // We use a constant to define the debug view arrays to guarantee that they're exactly the same length at compile time
50 const int kNumDebugViews = 6;
51
52 // We define a fixed array of GUIContent values here which map to supported debug views within the STP shader code
53 static readonly GUIContent[] s_DebugViewDescriptions = new GUIContent[kNumDebugViews]
54 {
55 new GUIContent("Clipped Input Color", "Shows input color clipped to {0 to 1}"),
56 new GUIContent("Log Input Depth", "Shows input depth in log scale"),
57 new GUIContent("Reversible Tonemapped Input Color", "Shows input color after conversion to reversible tonemaped space"),
58 new GUIContent("Shaped Absolute Input Motion", "Visualizes input motion vectors"),
59 new GUIContent("Motion Reprojection {R=Prior G=This Sqrt Luma Feedback Diff, B=Offscreen}", "Visualizes reprojected frame difference"),
60 new GUIContent("Sensitivity {G=No motion match, R=Responsive, B=Luma}", "Visualize pixel sensitivities"),
61 };
62
63 // Unfortunately we must maintain a sequence of index values that map to the supported debug view indices
64 // if we want to be able to display the debug views as an enum field without allocating any garbage.
65 static readonly int[] s_DebugViewIndices = new int[kNumDebugViews]
66 {
67 0,
68 1,
69 2,
70 3,
71 4,
72 5,
73 };
74
75 /// <summary>
76 /// Array of debug view descriptions expected to be used in the rendering debugger UI
77 /// </summary>
78 public static GUIContent[] debugViewDescriptions { get { return s_DebugViewDescriptions; } }
79
80 /// <summary>
81 /// Array of debug view indices expected to be used in the rendering debugger UI
82 /// </summary>
83 public static int[] debugViewIndices { get { return s_DebugViewIndices; } }
84
85 /// <summary>
86 /// STP configuration data that varies per rendered view
87 /// </summary>
88 public struct PerViewConfig
89 {
90 /// <summary>
91 /// Non-Jittered projection matrix for the current frame
92 /// Used by the static geometry reprojection feature
93 /// </summary>
94 public Matrix4x4 currentProj;
95
96 /// <summary>
97 /// Non-Jittered projection matrix for the previous frame
98 /// Used by the static geometry reprojection feature
99 /// </summary>
100 public Matrix4x4 lastProj;
101
102 /// <summary>
103 /// Non-Jittered projection matrix for the frame before the previous frame
104 /// Used by the static geometry reprojection feature
105 /// </summary>
106 public Matrix4x4 lastLastProj;
107
108 /// <summary>
109 /// View matrix for the current frame
110 /// Used by the static geometry reprojection feature
111 /// </summary>
112 public Matrix4x4 currentView;
113
114 /// <summary>
115 /// View matrix for the previous frame
116 /// Used by the static geometry reprojection feature
117 /// </summary>
118 public Matrix4x4 lastView;
119
120 /// <summary>
121 /// View matrix for the frame before the previous frame
122 /// Used by the static geometry reprojection feature
123 /// </summary>
124 public Matrix4x4 lastLastView;
125 }
126
127 /// <summary>
128 /// Maximum amount of supported per-view configurations
129 /// </summary>
130 const int kMaxPerViewConfigs = 2;
131
132 /// <summary>
133 /// Static allocation of per-view configurations
134 /// </summary>
135 static PerViewConfig[] s_PerViewConfigs = new PerViewConfig[kMaxPerViewConfigs];
136
137 /// <summary>
138 /// Static allocation of per-view configurations
139 /// Users are expected to populate this during STP configuration and then assign it to the relevant
140 /// configuration structure field(s) to avoid unnecessary allocations.
141 /// </summary>
142 public static PerViewConfig[] perViewConfigs
143 {
144 get { return s_PerViewConfigs; }
145 set { s_PerViewConfigs = value; }
146 }
147
148 /// <summary>
149 /// Top-level configuration structure required for STP execution
150 /// </summary>
151 public struct Config
152 {
153 /// <summary>
154 /// Blue noise texture used in various parts of the upscaling logic
155 /// </summary>
156 public Texture2D noiseTexture;
157
158 /// <summary>
159 /// Input color texture to be upscaled
160 /// </summary>
161 public TextureHandle inputColor;
162
163 /// <summary>
164 /// Input depth texture which will be analyzed during upscaling
165 /// </summary>
166 public TextureHandle inputDepth;
167
168 /// <summary>
169 /// Input motion vector texture which is used to reproject information across frames
170 /// </summary>
171 public TextureHandle inputMotion;
172
173 /// <summary>
174 /// [Optional] Input stencil texture which is used to identify pixels that need special treatment such as particles or in-game screens
175 /// </summary>
176 public TextureHandle inputStencil;
177
178 /// <summary>
179 /// [Optional] Output debug view texture which STP can be configured to render debug visualizations into
180 /// </summary>
181 public TextureHandle debugView;
182
183 /// <summary>
184 /// Output color texture which will receive the final upscaled color result
185 /// </summary>
186 public TextureHandle destination;
187
188 /// <summary>
189 /// Input history context to use when executing STP
190 /// </summary>
191 public HistoryContext historyContext;
192
193 /// <summary>
194 /// Set to true if hardware dynamic resolution scaling is currently active
195 /// </summary>
196 public bool enableHwDrs;
197
198 /// <summary>
199 /// Set to true if the rendering environment is using 2d array textures (usually due to XR)
200 /// </summary>
201 public bool enableTexArray;
202
203 /// <summary>
204 /// Set to true to enable the motion scaling feature which attempts to compensate for variable frame timing when working with motion vectors
205 /// </summary>
206 public bool enableMotionScaling;
207
208 /// <summary>
209 /// Distance to the camera's near plane
210 /// Used to encode depth values
211 /// </summary>
212 public float nearPlane;
213
214 /// <summary>
215 /// Distance to the camera's far plane
216 /// Used to encode depth values
217 /// </summary>
218 public float farPlane;
219
220 /// <summary>
221 /// Index of the current frame
222 /// Used to calculate jitter pattern
223 /// </summary>
224 public int frameIndex;
225
226 /// <summary>
227 /// True if the current frame has valid history information
228 /// Used to prevent STP from producing invalid data
229 /// </summary>
230 public bool hasValidHistory;
231
232 /// <summary>
233 /// A mask value applied that determines which stencil bit is associated with the responsive feature
234 /// Used to prevent STP from producing incorrect values on transparent pixels
235 /// Set to 0 if no stencil data is present
236 /// </summary>
237 public int stencilMask;
238
239 /// <summary>
240 /// An index value that indicates which debug visualization to render in the debug view
241 /// This value is only used when a valid debug view handle is provided
242 /// </summary>
243 public int debugViewIndex;
244
245 /// <summary>
246 /// Delta frame time for the current frame
247 /// Used to compensate for inconsistent frame timings when working with motion vectors
248 /// </summary>
249 public float deltaTime;
250
251 /// <summary>
252 /// Delta frame time for the previous frame
253 /// Used to compensate for inconsistent frame timings when working with motion vectors
254 /// </summary>
255 public float lastDeltaTime;
256
257 /// <summary>
258 /// Size of the current viewport in pixels
259 /// Used to calculate image coordinate scaling factors
260 /// </summary>
261 public Vector2Int currentImageSize;
262
263 /// <summary>
264 /// Size of the previous viewport in pixels
265 /// Used to calculate image coordinate scaling factors
266 /// </summary>
267 public Vector2Int priorImageSize;
268
269 /// <summary>
270 /// Size of the upscaled output image in pixels
271 /// Used to calculate image coordinate scaling factors
272 /// </summary>
273 public Vector2Int outputImageSize;
274
275 /// <summary>
276 /// Number of active views in the perViewConfigs array
277 /// </summary>
278 public int numActiveViews;
279
280 /// <summary>
281 /// Configuration parameters that are unique per rendered view
282 /// </summary>
283 public PerViewConfig[] perViewConfigs;
284 }
285
286 /// <summary>
287 /// Enumeration of unique types of history textures
288 /// </summary>
289 internal enum HistoryTextureType
290 {
291 DepthMotion,
292 Luma,
293 Convergence,
294 Feedback,
295
296 Count
297 }
298
299 /// <summary>
300 /// Number of unique types of history textures used by STP
301 /// </summary>
302 const int kNumHistoryTextureTypes = (int)HistoryTextureType.Count;
303
304 /// <summary>
305 /// Describes the information needed to update the history context
306 /// </summary>
307 public struct HistoryUpdateInfo
308 {
309 /// <summary>
310 /// Size of the target image before upscaling is applied
311 /// </summary>
312 public Vector2Int preUpscaleSize;
313
314 /// <summary>
315 /// Size of the target image after upscaling is applied
316 /// </summary>
317 public Vector2Int postUpscaleSize;
318
319 /// <summary>
320 /// True if hardware dynamic resolution scaling is active
321 /// </summary>
322 public bool useHwDrs;
323
324 /// <summary>
325 /// True if texture arrays are being used in the current rendering environment
326 /// </summary>
327 public bool useTexArray;
328 }
329
330 /// <summary>
331 /// Computes a hash value that changes whenever the history context needs to be re-created
332 /// </summary>
333 /// <param name="hashParams">parameters used to calculate the history hash</param>
334 /// <returns>A hash value that changes whenever the history context needs to be re-created</returns>
335 static Hash128 ComputeHistoryHash(ref HistoryUpdateInfo info)
336 {
337 Hash128 hash = new Hash128();
338
339 hash.Append(ref info.useHwDrs);
340 hash.Append(ref info.useTexArray);
341 hash.Append(ref info.postUpscaleSize);
342
343 // The pre-upscale size only affects the history texture logic when hardware dynamic resolution scaling is disabled.
344 if (!info.useHwDrs)
345 {
346 hash.Append(ref info.preUpscaleSize);
347 }
348
349 return hash;
350 }
351
352 /// <summary>
353 /// Calculates the correct size for the STP low-frequency convergence texture
354 /// </summary>
355 /// <param name="historyTextureSize">size of the render-size history textures used by STP</param>
356 /// <returns>size of the convergence texture</returns>
357 static Vector2Int CalculateConvergenceTextureSize(Vector2Int historyTextureSize)
358 {
359 // The convergence texture is a 4x4 reduction of data computed at render size, but we must always make sure the size is rounded up.
360 return new Vector2Int(CoreUtils.DivRoundUp(historyTextureSize.x, 4), CoreUtils.DivRoundUp(historyTextureSize.y, 4));
361 }
362
363 /// <summary>
364 /// Opaque history information required by STP's implementation
365 /// Users are expected to create their own persistent history context, update it once per frame, and provide it to
366 /// STP's execution logic through the configuration structure.
367 /// </summary>
368 public sealed class HistoryContext : IDisposable
369 {
370 /// <summary>
371 /// Array of history textures used by STP
372 /// The array is subdivided into two sets. Each set represents the history textures for a single frame.
373 /// </summary>
374 RTHandle[] m_textures = new RTHandle[kNumHistoryTextureTypes * 2];
375
376 /// <summary>
377 /// Hash value that changes whenever the history context needs to be re-created
378 /// </summary>
379 Hash128 m_hash = Hash128.Compute(0);
380
381 /// <summary>
382 /// Updated the state of the history context based on the provided information
383 /// This may result in re-allocation of resources internally if state has changed and is now incompatible or if this is the first update
384 /// </summary>
385 /// <param name="info">information required to update the history context</param>
386 /// <returns>True if the internal history data within the context is valid after the update operation</returns>
387 public bool Update(ref HistoryUpdateInfo info)
388 {
389 bool hasValidHistory = true;
390
391 var hash = ComputeHistoryHash(ref info);
392
393 if (hash != m_hash)
394 {
395 hasValidHistory = false;
396
397 Dispose();
398
399 m_hash = hash;
400
401 // Allocate two new sets of history textures for STP based on the current settings
402
403 Vector2Int historyTextureSize = info.useHwDrs ? info.postUpscaleSize : info.preUpscaleSize;
404 TextureDimension texDimension = info.useTexArray ? TextureDimension.Tex2DArray : TextureDimension.Tex2D;
405
406 int width = 0;
407 int height = 0;
408 GraphicsFormat format = GraphicsFormat.None;
409 bool useDynamicScaleExplicit = false;
410 string name = "";
411
412 for (int historyTypeIndex = 0; historyTypeIndex < kNumHistoryTextureTypes; ++historyTypeIndex)
413 {
414 switch ((HistoryTextureType)historyTypeIndex)
415 {
416 case HistoryTextureType.DepthMotion:
417 {
418 width = historyTextureSize.x;
419 height = historyTextureSize.y;
420 format = GraphicsFormat.R32_UInt;
421 useDynamicScaleExplicit = info.useHwDrs;
422 name = "STP Depth & Motion";
423 break;
424 }
425 case HistoryTextureType.Luma:
426 {
427 width = historyTextureSize.x;
428 height = historyTextureSize.y;
429 format = GraphicsFormat.R8G8_UNorm;
430 useDynamicScaleExplicit = info.useHwDrs;
431 name = "STP Luma";
432 break;
433 }
434 case HistoryTextureType.Convergence:
435 {
436 Vector2Int convergenceSize = CalculateConvergenceTextureSize(historyTextureSize);
437
438 width = convergenceSize.x;
439 height = convergenceSize.y;
440 format = GraphicsFormat.R8_UNorm;
441 useDynamicScaleExplicit = info.useHwDrs;
442 name = "STP Convergence";
443 break;
444 }
445 case HistoryTextureType.Feedback:
446 {
447 width = info.postUpscaleSize.x;
448 height = info.postUpscaleSize.y;
449 format = GraphicsFormat.A2B10G10R10_UNormPack32;
450 useDynamicScaleExplicit = false;
451 name = "STP Feedback";
452 break;
453 }
454 default:
455 {
456 // Invalid history texture type
457 Debug.Assert(false);
458 break;
459 }
460 }
461
462 for (int frameIndex = 0; frameIndex < 2; ++frameIndex)
463 {
464 int offset = (frameIndex * kNumHistoryTextureTypes) + historyTypeIndex;
465
466 m_textures[offset] = RTHandles.Alloc(
467 width, height, format, TextureXR.slices, dimension: texDimension, enableRandomWrite: true,
468 name: name, useDynamicScaleExplicit: useDynamicScaleExplicit
469 );
470 }
471 }
472 }
473
474 return hasValidHistory;
475 }
476
477 internal RTHandle GetCurrentHistoryTexture(HistoryTextureType historyType, int frameIndex)
478 {
479 return m_textures[((frameIndex & 1) * (int)HistoryTextureType.Count) + (int)historyType];
480 }
481
482 internal RTHandle GetPreviousHistoryTexture(HistoryTextureType historyType, int frameIndex)
483 {
484 return m_textures[(((frameIndex & 1) ^ 1) * (int)HistoryTextureType.Count) + (int)historyType];
485 }
486
487 /// <summary>
488 /// Releases the internal resources held within the history context
489 /// Typically things like texture allocations
490 /// </summary>
491 public void Dispose()
492 {
493 for (int texIndex = 0; texIndex < m_textures.Length; ++texIndex)
494 {
495 if (m_textures[texIndex] != null)
496 {
497 m_textures[texIndex].Release();
498 m_textures[texIndex] = null;
499 }
500 }
501
502 m_hash = Hash128.Compute(0);
503 }
504 }
505
506 /// <summary>
507 /// Returns a motion scaling ratio based on the difference in delta times across frames
508 /// </summary>
509 /// <param name="deltaTime">Time elapsed from the last frame to the current frame in seconds</param>
510 /// <param name="lastDeltaTime">Time elapsed from the frame before the last frame to the last frame in seconds</param>
511 /// <returns>Motion scale factor for the current frame</returns>
512 static float CalculateMotionScale(float deltaTime, float lastDeltaTime)
513 {
514 float motionScale = 1.0f;
515
516 float currentDeltaTime = deltaTime;
517 float previousDeltaTime = lastDeltaTime;
518 if (!Mathf.Approximately(previousDeltaTime, 0.0f))
519 {
520 motionScale = currentDeltaTime / previousDeltaTime;
521 }
522
523 return motionScale;
524 }
525
526 /// <summary>
527 /// Returns a matrix with the translation component removed
528 /// This function is intended to be used with view matrices
529 /// </summary>
530 /// <param name="input">input view matrix</param>
531 /// <returns>a matrix with the translation component removed</returns>
532 static Matrix4x4 ExtractRotation(Matrix4x4 input)
533 {
534 Matrix4x4 output = input;
535
536 output[0, 3] = 0.0f;
537 output[1, 3] = 0.0f;
538 output[2, 3] = 0.0f;
539 output[3, 3] = 1.0f;
540
541 return output;
542 }
543
544 /// <summary>
545 /// Helper function that converts the provided Vector2 into a packed integer with two FP16 values
546 /// </summary>
547 /// <param name="value">input Vector2 value to be packed</param>
548 /// <returns>an integer that contains the two vector components packed together as FP16 values</returns>
549 static int PackVector2ToInt(Vector2 value)
550 {
551 uint xAsHalf = Mathf.FloatToHalf(value.x);
552 uint yAsHalf = Mathf.FloatToHalf(value.y);
553 return (int)(xAsHalf | (yAsHalf << 16));
554 }
555
556 /// <summary>
557 /// Number of constants that contain per-view information for the setup pass
558 /// NOTE: The name here is important as it's directly translated into HLSL
559 /// </summary>
560 [GenerateHLSL(PackingRules.Exact)]
561 enum StpSetupPerViewConstants
562 {
563 Count = 8
564 };
565
566 /// <summary>
567 /// Total number of constants used for per-view data in STP
568 /// </summary>
569 const int kTotalSetupViewConstantsCount = kMaxPerViewConfigs * ((int)StpSetupPerViewConstants.Count);
570
571 /// <summary>
572 /// Constant buffer layout used by STP
573 /// NOTE: The name here is important as it's directly translated into HLSL
574 /// </summary>
575 [GenerateHLSL(needAccessors = false, generateCBuffer = true)]
576 unsafe struct StpConstantBufferData
577 {
578 public Vector4 _StpCommonConstant;
579
580 public Vector4 _StpSetupConstants0;
581 public Vector4 _StpSetupConstants1;
582 public Vector4 _StpSetupConstants2;
583 public Vector4 _StpSetupConstants3;
584 public Vector4 _StpSetupConstants4;
585 public Vector4 _StpSetupConstants5;
586
587 [HLSLArray(kTotalSetupViewConstantsCount, typeof(Vector4))]
588 public fixed float _StpSetupPerViewConstants[kTotalSetupViewConstantsCount * 4];
589
590 public Vector4 _StpDilConstants0;
591
592 public Vector4 _StpTaaConstants0;
593 public Vector4 _StpTaaConstants1;
594 public Vector4 _StpTaaConstants2;
595 public Vector4 _StpTaaConstants3;
596 }
597
598 /// <summary>
599 /// Produces constant buffer data in the format required by STP
600 /// </summary>
601 /// <param name="config">STP's configuration data</param>
602 /// <param name="constants">constant buffer data structure required by STP</param>
603 static void PopulateConstantData(ref Config config, ref StpConstantBufferData constants)
604 {
605 Assert.IsTrue(Mathf.IsPowerOfTwo(config.noiseTexture.width));
606
607 //
608 // Common
609 //
610
611 // [DebugViewIndex | StencilMask | HasValidHistory | (Width - 1)]
612 int packedBlueNoiseWidthMinusOne = (config.noiseTexture.width - 1) & 0xFF;
613 int packedHasValidHistory = (config.hasValidHistory ? 1 : 0) << 8;
614 int packedStencilMask = (config.stencilMask & 0xFF) << 16;
615 int packedDebugViewIndex = (config.debugViewIndex & 0xFF) << 24;
616
617 int constant0 = packedStencilMask | packedHasValidHistory | packedBlueNoiseWidthMinusOne | packedDebugViewIndex;
618
619 // Compute values used for linear depth conversion
620 // These values are normally in the _ZBufferParams constant, but we re-compute them here since this constant is defined differently across SRPs
621 float zBufferParamZ = (config.farPlane - config.nearPlane) / (config.nearPlane * config.farPlane);
622 float zBufferParamW = 1.0f / config.farPlane;
623
624 constants._StpCommonConstant = new Vector4(BitConverter.Int32BitsToSingle(constant0), zBufferParamZ, zBufferParamW, 0.0f);
625
626 //
627 // NOTE: The logic below is effectively a C# port of the HLSL constant setup logic found in Stp.hlsl
628 // The C# code attempts to be as close as possible to the HLSL in order to simplify maintenance.
629 //
630
631 //
632 // Setup
633 //
634
635 //------------------------------------------------------------------------------------------------------------------------------
636 // StpF2 kRcpC := 1.0 / size of current input image in pixels.
637 constants._StpSetupConstants0.x = (1.0f / config.currentImageSize.x);
638 constants._StpSetupConstants0.y = (1.0f / config.currentImageSize.y);
639 // StpF2 kHalfRcpC := 0.5 / size of current input image in pixels.
640 constants._StpSetupConstants0.z = (0.5f / config.currentImageSize.x);
641 constants._StpSetupConstants0.w = (0.5f / config.currentImageSize.y);
642 //------------------------------------------------------------------------------------------------------------------------------
643 // Grab jitter for current and prior frames.
644 Vector2 jitP = Jit16(config.frameIndex - 1);
645 Vector2 jitC = Jit16(config.frameIndex);
646 // StpF2 kJitCRcpCUnjitPRcpP := Map current into prior frame.
647 constants._StpSetupConstants1.x = (jitC.x / config.currentImageSize.x - jitP.x / config.priorImageSize.x);
648 constants._StpSetupConstants1.y = (jitC.y / config.currentImageSize.y - jitP.y / config.priorImageSize.y);
649 // StpF2 kJitCRcpC := Take {0 to 1} position in current image, and map back to {0 to 1} position in feedback (removes jitter).
650 constants._StpSetupConstants1.z = jitC.x / config.currentImageSize.x;
651 constants._StpSetupConstants1.w = jitC.y / config.currentImageSize.y;
652 //------------------------------------------------------------------------------------------------------------------------------
653 // StpF2 kF := size of feedback (aka output) in pixels.
654 constants._StpSetupConstants2.x = config.outputImageSize.x;
655 constants._StpSetupConstants2.y = config.outputImageSize.y;
656 // StpF2 kDepth := Copied logic from StpZCon().
657 float k0 = (1.0f / config.nearPlane);
658 float k1 = (1.0f / Mathf.Log(k0 * config.farPlane, 2.0f));
659 constants._StpSetupConstants2.z = k0;
660 constants._StpSetupConstants2.w = k1;
661 //------------------------------------------------------------------------------------------------------------------------------
662 // StpF4 kOS := Scale and bias to check for out of bounds (and kill feedback).
663 // Scaled and biased output needs to {-1 out of bounds, >-1 in bounds, <1 in bounds, 1 out of bounds}.
664 Vector2 s;
665 // Undo 'pM' scaling, and multiply by 2 (as this needs to be -1 to 1 at edge of acceptable reprojection).
666 s.x = 2.0f;
667 s.y = 2.0f;
668 // Scaling to push outside safe reprojection over 1.
669 s.x *= (config.priorImageSize.x / (config.priorImageSize.x + 4.0f));
670 s.y *= (config.priorImageSize.y / (config.priorImageSize.y + 4.0f));
671 constants._StpSetupConstants3.x = s[0];
672 constants._StpSetupConstants3.y = s[1];
673 // Factor out subtracting off the mid point scaled by the multiply term.
674 constants._StpSetupConstants3.z = (-0.5f * s[0]);
675 constants._StpSetupConstants3.w = (-0.5f * s[1]);
676 //------------------------------------------------------------------------------------------------------------------------------
677 // StpF2 kUnDepth := Copied logic from StpZUnCon().
678 constants._StpSetupConstants4.x = Mathf.Log(config.farPlane / config.nearPlane, 2.0f);
679 constants._StpSetupConstants4.y = config.nearPlane;
680 // kMotionMatch
681 constants._StpSetupConstants4.z = config.enableMotionScaling ? CalculateMotionScale(config.deltaTime, config.lastDeltaTime) : 1.0f;
682 // Unused for now.
683 constants._StpSetupConstants4.w = 0.0f;
684 //------------------------------------------------------------------------------------------------------------------------------
685 // StpF2 kC := Size of current input image in pixels.
686 constants._StpSetupConstants5.x = config.currentImageSize.x;
687 constants._StpSetupConstants5.y = config.currentImageSize.y;
688 //------------------------------------------------------------------------------------------------------------------------------
689 // StpF2 kFS := scale factor used to convert from feedback uv space to reduction uv space
690 constants._StpSetupConstants5.z = config.outputImageSize.x / (Mathf.Ceil(config.outputImageSize.x / 4.0f) * 4.0f);
691 constants._StpSetupConstants5.w = config.outputImageSize.y / (Mathf.Ceil(config.outputImageSize.y / 4.0f) * 4.0f);
692
693 // Per View
694 for (uint viewIndex = 0; viewIndex < config.numActiveViews; ++viewIndex)
695 {
696 uint baseViewDataOffset = viewIndex * ((int)StpSetupPerViewConstants.Count) * 4;
697 var perViewConfig = config.perViewConfigs[viewIndex];
698
699 //------------------------------------------------------------------------------------------------------------------------------
700 // See header docs in "STATIC GEOMETRY MOTION FORWARD PROJECTION".
701 Vector4 prjPriABEF;
702 prjPriABEF.x = perViewConfig.lastProj[0, 0];
703
704 // NOTE: Unity flips the Y axis inside the projection matrix. STP requires a non-flipped Y axis, so we undo the flip here with abs
705 prjPriABEF.y = Mathf.Abs(perViewConfig.lastProj[1, 1]);
706
707 // TODO: We need to understand why we need to negate these values for the inverse projection in order to get correct results.
708 prjPriABEF.z = -perViewConfig.lastProj[0, 2];
709 prjPriABEF.w = -perViewConfig.lastProj[1, 2];
710
711 Vector4 prjPriCDGH;
712 prjPriCDGH.x = perViewConfig.lastProj[2, 2];
713 prjPriCDGH.y = perViewConfig.lastProj[2, 3];
714 prjPriCDGH.z = perViewConfig.lastProj[3, 2];
715 prjPriCDGH.w = perViewConfig.lastProj[3, 3];
716
717 Vector4 prjCurABEF;
718 prjCurABEF.x = perViewConfig.currentProj[0, 0];
719
720 // NOTE: Unity flips the Y axis inside the projection matrix. STP requires a non-flipped Y axis, so we undo the flip here with abs
721 prjCurABEF.y = Mathf.Abs(perViewConfig.currentProj[1, 1]);
722
723 prjCurABEF.z = perViewConfig.currentProj[0, 2];
724 prjCurABEF.w = perViewConfig.currentProj[1, 2];
725
726 Vector4 prjCurCDGH;
727 prjCurCDGH.x = perViewConfig.currentProj[2, 2];
728 prjCurCDGH.y = perViewConfig.currentProj[2, 3];
729 prjCurCDGH.z = perViewConfig.currentProj[3, 2];
730 prjCurCDGH.w = perViewConfig.currentProj[3, 3];
731
732 Matrix4x4 forwardTransform = ExtractRotation(perViewConfig.currentView) *
733 Matrix4x4.Translate(-perViewConfig.currentView.GetColumn(3)) *
734 Matrix4x4.Translate(perViewConfig.lastView.GetColumn(3)) *
735 ExtractRotation(perViewConfig.lastView).transpose;
736
737 Vector4 forIJKL = forwardTransform.GetRow(0);
738 Vector4 forMNOP = forwardTransform.GetRow(1);
739 Vector4 forQRST = forwardTransform.GetRow(2);
740
741 Vector4 prjPrvABEF;
742 prjPrvABEF.x = perViewConfig.lastLastProj[0, 0];
743
744 // NOTE: Unity flips the Y axis inside the projection matrix. STP requires a non-flipped Y axis, so we undo the flip here with abs
745 prjPrvABEF.y = Mathf.Abs(perViewConfig.lastLastProj[1, 1]);
746
747 prjPrvABEF.z = perViewConfig.lastLastProj[0, 2];
748 prjPrvABEF.w = perViewConfig.lastLastProj[1, 2];
749
750 Vector4 prjPrvCDGH;
751 prjPrvCDGH.x = perViewConfig.lastLastProj[2, 2];
752 prjPrvCDGH.y = perViewConfig.lastLastProj[2, 3];
753 prjPrvCDGH.z = perViewConfig.lastLastProj[3, 2];
754 prjPrvCDGH.w = perViewConfig.lastLastProj[3, 3];
755
756 Matrix4x4 backwardTransform = ExtractRotation(perViewConfig.lastLastView) *
757 Matrix4x4.Translate(-perViewConfig.lastLastView.GetColumn(3)) *
758 Matrix4x4.Translate(perViewConfig.lastView.GetColumn(3)) *
759 ExtractRotation(perViewConfig.lastView).transpose;
760
761 Vector4 bckIJKL = backwardTransform.GetRow(0);
762 Vector4 bckMNOP = backwardTransform.GetRow(1);
763 Vector4 bckQRST = backwardTransform.GetRow(2);
764
765 unsafe
766 {
767 // Forwards
768
769 // k0123
770 constants._StpSetupPerViewConstants[baseViewDataOffset + 0] = prjPriCDGH.z / prjPriABEF.x;
771 constants._StpSetupPerViewConstants[baseViewDataOffset + 1] = prjPriCDGH.w / prjPriABEF.x;
772 constants._StpSetupPerViewConstants[baseViewDataOffset + 2] = prjPriABEF.z / prjPriABEF.x;
773 constants._StpSetupPerViewConstants[baseViewDataOffset + 3] = prjPriCDGH.z / prjPriABEF.y;
774 // k4567
775 constants._StpSetupPerViewConstants[baseViewDataOffset + 4] = prjPriCDGH.w / prjPriABEF.y;
776 constants._StpSetupPerViewConstants[baseViewDataOffset + 5] = prjPriABEF.w / prjPriABEF.y;
777 constants._StpSetupPerViewConstants[baseViewDataOffset + 6] = forIJKL.x * prjCurABEF.x + forQRST.x * prjCurABEF.z;
778 constants._StpSetupPerViewConstants[baseViewDataOffset + 7] = forIJKL.y * prjCurABEF.x + forQRST.y * prjCurABEF.z;
779 // k89AB
780 constants._StpSetupPerViewConstants[baseViewDataOffset + 8] = forIJKL.z * prjCurABEF.x + forQRST.z * prjCurABEF.z;
781 constants._StpSetupPerViewConstants[baseViewDataOffset + 9] = forIJKL.w * prjCurABEF.x + forQRST.w * prjCurABEF.z;
782 constants._StpSetupPerViewConstants[baseViewDataOffset + 10] = forMNOP.x * prjCurABEF.y + forQRST.x * prjCurABEF.w;
783 constants._StpSetupPerViewConstants[baseViewDataOffset + 11] = forMNOP.y * prjCurABEF.y + forQRST.y * prjCurABEF.w;
784 // kCDEF
785 constants._StpSetupPerViewConstants[baseViewDataOffset + 12] = forMNOP.z * prjCurABEF.y + forQRST.z * prjCurABEF.w;
786 constants._StpSetupPerViewConstants[baseViewDataOffset + 13] = forMNOP.w * prjCurABEF.y + forQRST.w * prjCurABEF.w;
787 constants._StpSetupPerViewConstants[baseViewDataOffset + 14] = forQRST.x * prjCurCDGH.z;
788 constants._StpSetupPerViewConstants[baseViewDataOffset + 15] = forQRST.y * prjCurCDGH.z;
789 // kGHIJ
790 constants._StpSetupPerViewConstants[baseViewDataOffset + 16] = forQRST.z * prjCurCDGH.z;
791 constants._StpSetupPerViewConstants[baseViewDataOffset + 17] = forQRST.w * prjCurCDGH.z + prjCurCDGH.w;
792
793 // Backwards
794
795 constants._StpSetupPerViewConstants[baseViewDataOffset + 18] = bckIJKL.x * prjPrvABEF.x + bckQRST.x * prjPrvABEF.z;
796 constants._StpSetupPerViewConstants[baseViewDataOffset + 19] = bckIJKL.y * prjPrvABEF.x + bckQRST.y * prjPrvABEF.z;
797 // kKLMN
798 constants._StpSetupPerViewConstants[baseViewDataOffset + 20] = bckIJKL.z * prjPrvABEF.x + bckQRST.z * prjPrvABEF.z;
799 constants._StpSetupPerViewConstants[baseViewDataOffset + 21] = bckIJKL.w * prjPrvABEF.x + bckQRST.w * prjPrvABEF.z;
800 constants._StpSetupPerViewConstants[baseViewDataOffset + 22] = bckMNOP.x * prjPrvABEF.y + bckQRST.x * prjPrvABEF.w;
801 constants._StpSetupPerViewConstants[baseViewDataOffset + 23] = bckMNOP.y * prjPrvABEF.y + bckQRST.y * prjPrvABEF.w;
802 // kOPQR
803 constants._StpSetupPerViewConstants[baseViewDataOffset + 24] = bckMNOP.z * prjPrvABEF.y + bckQRST.z * prjPrvABEF.w;
804 constants._StpSetupPerViewConstants[baseViewDataOffset + 25] = bckMNOP.w * prjPrvABEF.y + bckQRST.w * prjPrvABEF.w;
805 constants._StpSetupPerViewConstants[baseViewDataOffset + 26] = bckQRST.x * prjPrvCDGH.z;
806 constants._StpSetupPerViewConstants[baseViewDataOffset + 27] = bckQRST.y * prjPrvCDGH.z;
807 // kST
808 constants._StpSetupPerViewConstants[baseViewDataOffset + 28] = bckQRST.z * prjPrvCDGH.z;
809 constants._StpSetupPerViewConstants[baseViewDataOffset + 29] = bckQRST.w * prjPrvCDGH.z + prjPrvCDGH.w;
810 // Unused
811 constants._StpSetupPerViewConstants[baseViewDataOffset + 30] = 0.0f;
812 constants._StpSetupPerViewConstants[baseViewDataOffset + 31] = 0.0f;
813 }
814 }
815 //------------------------------------------------------------------------------------------------------------------------------
816
817 //
818 // Dilation
819 //
820 // StpF2 kRcpR := 4/size of current input image in pixels.
821 constants._StpDilConstants0.x = 4.0f / config.currentImageSize.x;
822 constants._StpDilConstants0.y = 4.0f / config.currentImageSize.y;
823 // StpU2 kR := size/4 of the current input image in pixels.
824 // Used for pass merging (DIL and SAA), since convergence is 1/16 area of input, must check position.
825 constants._StpDilConstants0.z = BitConverter.Int32BitsToSingle(config.currentImageSize.x >> 2);
826 constants._StpDilConstants0.w = BitConverter.Int32BitsToSingle(config.currentImageSize.y >> 2);
827
828 //
829 // TAA
830 //
831
832 //------------------------------------------------------------------------------------------------------------------------------
833 // Conversion from integer pix position to center pix float pixel position in image for current input.
834 // xy := multiply term (M) --- Scale by 1/imgF to get to {0 to 1}.
835 // zw := addition term (A) --- Add 0.5*M to get to center of pixel, then subtract jitC to undo jitter.
836 // StpF2 kCRcpF.
837 constants._StpTaaConstants0.x = (((float)config.currentImageSize.x) / config.outputImageSize.x);
838 constants._StpTaaConstants0.y = (((float)config.currentImageSize.y) / config.outputImageSize.y);
839 // StpF2 kHalfCRcpFUnjitC.
840 constants._StpTaaConstants0.z = (0.5f * config.currentImageSize.x / config.outputImageSize.x - jitC.x);
841 constants._StpTaaConstants0.w = (0.5f * config.currentImageSize.y / config.outputImageSize.y - jitC.y);
842 //------------------------------------------------------------------------------------------------------------------------------
843 // StpF2 kRcpC := 1/size of current input image in pixels.
844 constants._StpTaaConstants1.x = (1.0f / config.currentImageSize.x);
845 constants._StpTaaConstants1.y = (1.0f / config.currentImageSize.y);
846 //------------------------------------------------------------------------------------------------------------------------------
847 // StpF2 kRcpF := 1/size of feedback image (aka output) in pixels.
848 constants._StpTaaConstants1.z = (1.0f / config.outputImageSize.x);
849 constants._StpTaaConstants1.w = (1.0f / config.outputImageSize.y);
850 //------------------------------------------------------------------------------------------------------------------------------
851 // StpF2 kHalfRcpF := 0.5/size of feedback image (aka output) in pixels.
852 constants._StpTaaConstants2.x = (0.5f / config.outputImageSize.x);
853 constants._StpTaaConstants2.y = (0.5f / config.outputImageSize.y);
854 //------------------------------------------------------------------------------------------------------------------------------
855 // Conversion from a {0 to 1} position in current input to feedback.
856 // StpH3 kJitCRcpC0 := jitC / image image size in pixels + {-0.5/size, +0.5/size} of current input image in pixels.
857 constants._StpTaaConstants2.z = jitC.x / config.currentImageSize.x - 0.5f / config.currentImageSize.x;
858 constants._StpTaaConstants2.w = jitC.y / config.currentImageSize.y + 0.5f / config.currentImageSize.y;
859 //------------------------------------------------------------------------------------------------------------------------------
860 // StpF2 kHalfRcpC := 0.5/size of current input image in pixels.
861 constants._StpTaaConstants3.x = 0.5f / config.currentImageSize.x;
862 constants._StpTaaConstants3.y = 0.5f / config.currentImageSize.y;
863 //------------------------------------------------------------------------------------------------------------------------------
864 // StpF2 kF := size of feedback image in pixels.
865 constants._StpTaaConstants3.z = config.outputImageSize.x;
866 constants._StpTaaConstants3.w = config.outputImageSize.y;
867 }
868
869 /// <summary>
870 /// Shader resource ids used to communicate with the STP shader implementation
871 /// </summary>
872 static class ShaderResources
873 {
874 public static readonly int _StpConstantBufferData = Shader.PropertyToID("StpConstantBufferData");
875 public static readonly int _StpBlueNoiseIn = Shader.PropertyToID("_StpBlueNoiseIn");
876 public static readonly int _StpDebugOut = Shader.PropertyToID("_StpDebugOut");
877 public static readonly int _StpInputColor = Shader.PropertyToID("_StpInputColor");
878 public static readonly int _StpInputDepth = Shader.PropertyToID("_StpInputDepth");
879 public static readonly int _StpInputMotion = Shader.PropertyToID("_StpInputMotion");
880 public static readonly int _StpInputStencil = Shader.PropertyToID("_StpInputStencil");
881 public static readonly int _StpIntermediateColor = Shader.PropertyToID("_StpIntermediateColor");
882 public static readonly int _StpIntermediateConvergence = Shader.PropertyToID("_StpIntermediateConvergence");
883 public static readonly int _StpIntermediateWeights = Shader.PropertyToID("_StpIntermediateWeights");
884 public static readonly int _StpPriorLuma = Shader.PropertyToID("_StpPriorLuma");
885 public static readonly int _StpLuma = Shader.PropertyToID("_StpLuma");
886 public static readonly int _StpPriorDepthMotion = Shader.PropertyToID("_StpPriorDepthMotion");
887 public static readonly int _StpDepthMotion = Shader.PropertyToID("_StpDepthMotion");
888 public static readonly int _StpPriorFeedback = Shader.PropertyToID("_StpPriorFeedback");
889 public static readonly int _StpFeedback = Shader.PropertyToID("_StpFeedback");
890 public static readonly int _StpPriorConvergence = Shader.PropertyToID("_StpPriorConvergence");
891 public static readonly int _StpConvergence = Shader.PropertyToID("_StpConvergence");
892 public static readonly int _StpOutput = Shader.PropertyToID("_StpOutput");
893 }
894
895 /// <summary>
896 /// Shader keyword strings used to configure the STP shader implementation
897 /// </summary>
898 static class ShaderKeywords
899 {
900 public static readonly string EnableDebugMode = "ENABLE_DEBUG_MODE";
901 public static readonly string EnableLargeKernel = "ENABLE_LARGE_KERNEL";
902 public static readonly string EnableStencilResponsive = "ENABLE_STENCIL_RESPONSIVE";
903 public static readonly string DisableTexture2DXArray = "DISABLE_TEXTURE2D_X_ARRAY";
904 }
905
906 /// <summary>
907 /// Contains the compute shaders used during STP's passes
908 /// </summary>
909 [Serializable]
910 [SupportedOnRenderPipeline]
911 [Categorization.CategoryInfo(Name = "R: STP", Order = 1000)]
912 [Categorization.ElementInfo(Order = 0), HideInInspector]
913 internal class RuntimeResources : IRenderPipelineResources
914 {
915 public int version => 0;
916
917 [SerializeField, ResourcePath("Runtime/STP/StpSetup.compute")]
918 private ComputeShader m_setupCS;
919
920 public ComputeShader setupCS
921 {
922 get => m_setupCS;
923 set => this.SetValueAndNotify(ref m_setupCS, value);
924 }
925
926 [SerializeField, ResourcePath("Runtime/STP/StpPreTaa.compute")]
927 private ComputeShader m_preTaaCS;
928
929 public ComputeShader preTaaCS
930 {
931 get => m_preTaaCS;
932 set => this.SetValueAndNotify(ref m_preTaaCS, value);
933 }
934
935 [SerializeField, ResourcePath("Runtime/STP/StpTaa.compute")]
936 private ComputeShader m_taaCS;
937
938 public ComputeShader taaCS
939 {
940 get => m_taaCS;
941 set => this.SetValueAndNotify(ref m_taaCS, value);
942 }
943 }
944
945 /// <summary>
946 /// Profiling identifiers associated with STP's passes
947 /// </summary>
948 enum ProfileId
949 {
950 StpSetup,
951 StpPreTaa,
952 StpTaa
953 }
954
955 /// <summary>
956 /// Integer value used to identify when STP is running on a Qualcomm GPU
957 /// </summary>
958 static readonly int kQualcommVendorId = 0x5143;
959
960 /// <summary>
961 /// Information required for STP's setup pass
962 /// </summary>
963 class SetupData
964 {
965 public ComputeShader cs;
966 public int kernelIndex;
967 public int viewCount;
968 public Vector2Int dispatchSize;
969
970 public StpConstantBufferData constantBufferData;
971
972 // Common
973 public TextureHandle noiseTexture;
974 public TextureHandle debugView;
975
976 // Inputs
977 public TextureHandle inputColor;
978 public TextureHandle inputDepth;
979 public TextureHandle inputMotion;
980 public TextureHandle inputStencil;
981
982 // Intermediates
983 public TextureHandle intermediateColor;
984 public TextureHandle intermediateConvergence;
985
986 // History
987 public TextureHandle priorDepthMotion;
988 public TextureHandle depthMotion;
989 public TextureHandle priorLuma;
990 public TextureHandle luma;
991 public TextureHandle priorFeedback;
992 public TextureHandle priorConvergence;
993 }
994
995 /// <summary>
996 /// Information required for STP's Pre-TAA pass
997 /// </summary>
998 class PreTaaData
999 {
1000 public ComputeShader cs;
1001 public int kernelIndex;
1002 public int viewCount;
1003 public Vector2Int dispatchSize;
1004
1005 // Common
1006 public TextureHandle noiseTexture;
1007 public TextureHandle debugView;
1008
1009 // Inputs
1010 public TextureHandle intermediateConvergence;
1011
1012 // Intermediates
1013 public TextureHandle intermediateWeights;
1014
1015 // History
1016 public TextureHandle luma;
1017 public TextureHandle convergence;
1018 }
1019
1020 /// <summary>
1021 /// Information required for STP's TAA pass
1022 /// </summary>
1023 class TaaData
1024 {
1025 public ComputeShader cs;
1026 public int kernelIndex;
1027 public int viewCount;
1028 public Vector2Int dispatchSize;
1029
1030 // Common
1031 public TextureHandle noiseTexture;
1032 public TextureHandle debugView;
1033
1034 // Inputs
1035 public TextureHandle intermediateColor;
1036 public TextureHandle intermediateWeights;
1037
1038 // History
1039 public TextureHandle priorFeedback;
1040 public TextureHandle depthMotion;
1041 public TextureHandle convergence;
1042
1043 // Outputs
1044 public TextureHandle feedback;
1045 public TextureHandle output;
1046 }
1047
1048 // Internal helper function used to streamline usage of the render graph API
1049 static TextureHandle UseTexture(IBaseRenderGraphBuilder builder, TextureHandle texture, AccessFlags flags = AccessFlags.Read)
1050 {
1051 builder.UseTexture(texture, flags);
1052 return texture;
1053 }
1054
1055 /// <summary>
1056 /// Executes the STP technique using the provided configuration in the target render graph
1057 /// </summary>
1058 /// <param name="renderGraph">render graph to execute STP within</param>
1059 /// <param name="config">configuration parameters for STP</param>
1060 /// <returns>Texture handle that contains the upscaled color output</returns>
1061 public static TextureHandle Execute(RenderGraph renderGraph, ref Config config)
1062 {
1063 var runtimeResources = GraphicsSettings.GetRenderPipelineSettings<RuntimeResources>();
1064
1065 // Temporarily wrap the noise texture in an RTHandle so it can be imported into render graph
1066 var noiseTexture = config.noiseTexture;
1067 RTHandleStaticHelpers.SetRTHandleStaticWrapper(noiseTexture);
1068 var noiseTextureRtHandle = RTHandleStaticHelpers.s_RTHandleWrapper;
1069
1070 RenderTargetInfo noiseTextureInfo;
1071 noiseTextureInfo.width = noiseTexture.width;
1072 noiseTextureInfo.height = noiseTexture.height;
1073 noiseTextureInfo.volumeDepth = 1;
1074 noiseTextureInfo.msaaSamples = 1;
1075 noiseTextureInfo.format = noiseTexture.graphicsFormat;
1076 noiseTextureInfo.bindMS = false;
1077
1078 TextureHandle noiseTextureHandle = renderGraph.ImportTexture(noiseTextureRtHandle, noiseTextureInfo);
1079
1080 var priorDepthMotion = config.historyContext.GetPreviousHistoryTexture(HistoryTextureType.DepthMotion, config.frameIndex);
1081 var priorLuma = config.historyContext.GetPreviousHistoryTexture(HistoryTextureType.Luma, config.frameIndex);
1082 var priorConvergence = config.historyContext.GetPreviousHistoryTexture(HistoryTextureType.Convergence, config.frameIndex);
1083 var priorFeedback = config.historyContext.GetPreviousHistoryTexture(HistoryTextureType.Feedback, config.frameIndex);
1084
1085 var depthMotion = config.historyContext.GetCurrentHistoryTexture(HistoryTextureType.DepthMotion, config.frameIndex);
1086 var luma = config.historyContext.GetCurrentHistoryTexture(HistoryTextureType.Luma, config.frameIndex);
1087 var convergence = config.historyContext.GetCurrentHistoryTexture(HistoryTextureType.Convergence, config.frameIndex);
1088 var feedback = config.historyContext.GetCurrentHistoryTexture(HistoryTextureType.Feedback, config.frameIndex);
1089
1090 // Resize the current render-size history textures if hardware dynamic scaling is enabled
1091 if (config.enableHwDrs)
1092 {
1093 depthMotion.rt.ApplyDynamicScale();
1094 luma.rt.ApplyDynamicScale();
1095 convergence.rt.ApplyDynamicScale();
1096 }
1097
1098 Vector2Int intermediateSize = config.enableHwDrs ? config.outputImageSize : config.currentImageSize;
1099
1100 // Enable the large 128 wide kernel whenever STP runs on Qualcomm GPUs.
1101 // These GPUs require larger compute work groups in order to reach maximum FP16 ALU efficiency
1102 bool enableLargeKernel = SystemInfo.graphicsDeviceVendorID == kQualcommVendorId;
1103
1104 Vector2Int kernelSize = new Vector2Int(8, enableLargeKernel ? 16 : 8);
1105
1106 SetupData setupData;
1107
1108 using (var builder = renderGraph.AddComputePass<SetupData>("STP Setup", out var passData, ProfilingSampler.Get(ProfileId.StpSetup)))
1109 {
1110 passData.cs = runtimeResources.setupCS;
1111 passData.cs.shaderKeywords = null;
1112
1113 if (enableLargeKernel)
1114 passData.cs.EnableKeyword(ShaderKeywords.EnableLargeKernel);
1115
1116 if (!config.enableTexArray)
1117 passData.cs.EnableKeyword(ShaderKeywords.DisableTexture2DXArray);
1118
1119 // Populate the constant buffer data structure in the render graph pass data
1120 // This data will be uploaded to the GPU when the node executes later in the frame
1121 PopulateConstantData(ref config, ref passData.constantBufferData);
1122
1123 passData.noiseTexture = UseTexture(builder, noiseTextureHandle);
1124
1125 if (config.debugView.IsValid())
1126 {
1127 passData.cs.EnableKeyword(ShaderKeywords.EnableDebugMode);
1128 passData.debugView = UseTexture(builder, config.debugView, AccessFlags.WriteAll);
1129 }
1130
1131 passData.kernelIndex = passData.cs.FindKernel("StpSetup");
1132 passData.viewCount = config.numActiveViews;
1133 passData.dispatchSize = new Vector2Int(
1134 CoreUtils.DivRoundUp(config.currentImageSize.x, kernelSize.x),
1135 CoreUtils.DivRoundUp(config.currentImageSize.y, kernelSize.y)
1136 );
1137
1138 passData.inputColor = UseTexture(builder, config.inputColor);
1139 passData.inputDepth = UseTexture(builder, config.inputDepth);
1140 passData.inputMotion = UseTexture(builder, config.inputMotion);
1141
1142 if (config.inputStencil.IsValid())
1143 {
1144 passData.cs.EnableKeyword(ShaderKeywords.EnableStencilResponsive);
1145 passData.inputStencil = UseTexture(builder, config.inputStencil);
1146 }
1147
1148 passData.intermediateColor = UseTexture(builder, renderGraph.CreateTexture(new TextureDesc(intermediateSize.x, intermediateSize.y, config.enableHwDrs, config.enableTexArray)
1149 {
1150 name = "STP Intermediate Color",
1151 format = GraphicsFormat.A2B10G10R10_UNormPack32,
1152 enableRandomWrite = true
1153 }), AccessFlags.WriteAll);
1154
1155 Vector2Int convergenceSize = CalculateConvergenceTextureSize(intermediateSize);
1156 passData.intermediateConvergence = UseTexture(builder, renderGraph.CreateTexture(new TextureDesc(convergenceSize.x, convergenceSize.y, config.enableHwDrs, config.enableTexArray)
1157 {
1158 name = "STP Intermediate Convergence",
1159 format = GraphicsFormat.R8_UNorm,
1160 enableRandomWrite = true
1161 }), AccessFlags.WriteAll);
1162
1163 passData.priorDepthMotion = UseTexture(builder, renderGraph.ImportTexture(priorDepthMotion));
1164 passData.depthMotion = UseTexture(builder, renderGraph.ImportTexture(depthMotion), AccessFlags.WriteAll);
1165 passData.priorLuma = UseTexture(builder, renderGraph.ImportTexture(priorLuma));
1166 passData.luma = UseTexture(builder, renderGraph.ImportTexture(luma), AccessFlags.WriteAll);
1167
1168 passData.priorFeedback = UseTexture(builder, renderGraph.ImportTexture(priorFeedback));
1169 passData.priorConvergence = UseTexture(builder, renderGraph.ImportTexture(priorConvergence));
1170
1171 builder.SetRenderFunc(
1172 (SetupData data, ComputeGraphContext ctx) =>
1173 {
1174 // Update the constant buffer data on the GPU
1175 // TODO: Fix usage of m_WrappedCommandBuffer here once NRP support is added to ConstantBuffer.cs
1176 ConstantBuffer.UpdateData(ctx.cmd.m_WrappedCommandBuffer, data.constantBufferData);
1177
1178 ConstantBuffer.Set<StpConstantBufferData>(data.cs, ShaderResources._StpConstantBufferData);
1179
1180 ctx.cmd.SetComputeTextureParam(data.cs, data.kernelIndex, ShaderResources._StpBlueNoiseIn, data.noiseTexture);
1181
1182 if (data.debugView.IsValid())
1183 ctx.cmd.SetComputeTextureParam(data.cs, data.kernelIndex, ShaderResources._StpDebugOut, data.debugView);
1184
1185 ctx.cmd.SetComputeTextureParam(data.cs, data.kernelIndex, ShaderResources._StpInputColor, data.inputColor);
1186 ctx.cmd.SetComputeTextureParam(data.cs, data.kernelIndex, ShaderResources._StpInputDepth, data.inputDepth);
1187 ctx.cmd.SetComputeTextureParam(data.cs, data.kernelIndex, ShaderResources._StpInputMotion, data.inputMotion);
1188
1189 if (data.inputStencil.IsValid())
1190 ctx.cmd.SetComputeTextureParam(data.cs, data.kernelIndex, ShaderResources._StpInputStencil, data.inputStencil, 0, RenderTextureSubElement.Stencil);
1191
1192 ctx.cmd.SetComputeTextureParam(data.cs, data.kernelIndex, ShaderResources._StpIntermediateColor, data.intermediateColor);
1193 ctx.cmd.SetComputeTextureParam(data.cs, data.kernelIndex, ShaderResources._StpIntermediateConvergence, data.intermediateConvergence);
1194
1195 ctx.cmd.SetComputeTextureParam(data.cs, data.kernelIndex, ShaderResources._StpPriorDepthMotion, data.priorDepthMotion);
1196 ctx.cmd.SetComputeTextureParam(data.cs, data.kernelIndex, ShaderResources._StpDepthMotion, data.depthMotion);
1197 ctx.cmd.SetComputeTextureParam(data.cs, data.kernelIndex, ShaderResources._StpPriorLuma, data.priorLuma);
1198 ctx.cmd.SetComputeTextureParam(data.cs, data.kernelIndex, ShaderResources._StpLuma, data.luma);
1199
1200 ctx.cmd.SetComputeTextureParam(data.cs, data.kernelIndex, ShaderResources._StpPriorFeedback, data.priorFeedback);
1201 ctx.cmd.SetComputeTextureParam(data.cs, data.kernelIndex, ShaderResources._StpPriorConvergence, data.priorConvergence);
1202
1203 ctx.cmd.DispatchCompute(data.cs, data.kernelIndex, data.dispatchSize.x, data.dispatchSize.y, data.viewCount);
1204 });
1205
1206 setupData = passData;
1207 }
1208
1209 PreTaaData preTaaData;
1210
1211 using (var builder = renderGraph.AddComputePass<PreTaaData>("STP Pre-TAA", out var passData, ProfilingSampler.Get(ProfileId.StpPreTaa)))
1212 {
1213 passData.cs = runtimeResources.preTaaCS;
1214 passData.cs.shaderKeywords = null;
1215
1216 if (enableLargeKernel)
1217 passData.cs.EnableKeyword(ShaderKeywords.EnableLargeKernel);
1218
1219 if (!config.enableTexArray)
1220 passData.cs.EnableKeyword(ShaderKeywords.DisableTexture2DXArray);
1221
1222 passData.noiseTexture = UseTexture(builder, noiseTextureHandle);
1223
1224 if (config.debugView.IsValid())
1225 {
1226 passData.cs.EnableKeyword(ShaderKeywords.EnableDebugMode);
1227 passData.debugView = UseTexture(builder, config.debugView, AccessFlags.ReadWrite);
1228 }
1229
1230 passData.kernelIndex = passData.cs.FindKernel("StpPreTaa");
1231 passData.viewCount = config.numActiveViews;
1232 passData.dispatchSize = new Vector2Int(
1233 CoreUtils.DivRoundUp(config.currentImageSize.x, kernelSize.x),
1234 CoreUtils.DivRoundUp(config.currentImageSize.y, kernelSize.y)
1235 );
1236
1237 passData.intermediateConvergence = UseTexture(builder, setupData.intermediateConvergence);
1238
1239 passData.intermediateWeights = UseTexture(builder, renderGraph.CreateTexture(new TextureDesc(intermediateSize.x, intermediateSize.y, config.enableHwDrs, config.enableTexArray)
1240 {
1241 name = "STP Intermediate Weights",
1242 format = GraphicsFormat.R8_UNorm,
1243 enableRandomWrite = true
1244 }), AccessFlags.WriteAll);
1245
1246 passData.luma = UseTexture(builder, renderGraph.ImportTexture(luma));
1247 passData.convergence = UseTexture(builder, renderGraph.ImportTexture(convergence), AccessFlags.WriteAll);
1248
1249 builder.SetRenderFunc(
1250 (PreTaaData data, ComputeGraphContext ctx) =>
1251 {
1252 ConstantBuffer.Set<StpConstantBufferData>(data.cs, ShaderResources._StpConstantBufferData);
1253
1254 ctx.cmd.SetComputeTextureParam(data.cs, data.kernelIndex, ShaderResources._StpBlueNoiseIn, data.noiseTexture);
1255
1256 if (data.debugView.IsValid())
1257 ctx.cmd.SetComputeTextureParam(data.cs, data.kernelIndex, ShaderResources._StpDebugOut, data.debugView);
1258
1259 ctx.cmd.SetComputeTextureParam(data.cs, data.kernelIndex, ShaderResources._StpIntermediateConvergence, data.intermediateConvergence);
1260
1261 ctx.cmd.SetComputeTextureParam(data.cs, data.kernelIndex, ShaderResources._StpIntermediateWeights, data.intermediateWeights);
1262
1263 ctx.cmd.SetComputeTextureParam(data.cs, data.kernelIndex, ShaderResources._StpLuma, data.luma);
1264 ctx.cmd.SetComputeTextureParam(data.cs, data.kernelIndex, ShaderResources._StpConvergence, data.convergence);
1265
1266 ctx.cmd.DispatchCompute(data.cs, data.kernelIndex, data.dispatchSize.x, data.dispatchSize.y, data.viewCount);
1267 });
1268
1269 preTaaData = passData;
1270 }
1271
1272 TaaData taaData;
1273
1274 using (var builder = renderGraph.AddComputePass<TaaData>("STP TAA", out var passData, ProfilingSampler.Get(ProfileId.StpTaa)))
1275 {
1276 passData.cs = runtimeResources.taaCS;
1277 passData.cs.shaderKeywords = null;
1278
1279 if (enableLargeKernel)
1280 passData.cs.EnableKeyword(ShaderKeywords.EnableLargeKernel);
1281
1282 if (!config.enableTexArray)
1283 passData.cs.EnableKeyword(ShaderKeywords.DisableTexture2DXArray);
1284
1285 passData.noiseTexture = UseTexture(builder, noiseTextureHandle);
1286
1287 if (config.debugView.IsValid())
1288 {
1289 passData.cs.EnableKeyword(ShaderKeywords.EnableDebugMode);
1290 passData.debugView = UseTexture(builder, config.debugView, AccessFlags.ReadWrite);
1291 }
1292
1293 passData.kernelIndex = passData.cs.FindKernel("StpTaa");
1294 passData.viewCount = config.numActiveViews;
1295 passData.dispatchSize = new Vector2Int(
1296 CoreUtils.DivRoundUp(config.outputImageSize.x, kernelSize.x),
1297 CoreUtils.DivRoundUp(config.outputImageSize.y, kernelSize.y)
1298 );
1299
1300 passData.intermediateColor = UseTexture(builder, setupData.intermediateColor);
1301 passData.intermediateWeights = UseTexture(builder, preTaaData.intermediateWeights);
1302
1303 passData.priorFeedback = UseTexture(builder, renderGraph.ImportTexture(priorFeedback));
1304 passData.depthMotion = UseTexture(builder, renderGraph.ImportTexture(depthMotion));
1305 passData.convergence = UseTexture(builder, renderGraph.ImportTexture(convergence));
1306
1307 passData.feedback = UseTexture(builder, renderGraph.ImportTexture(feedback), AccessFlags.WriteAll);
1308
1309 passData.output = UseTexture(builder, config.destination, AccessFlags.WriteAll);
1310
1311 builder.SetRenderFunc(
1312 (TaaData data, ComputeGraphContext ctx) =>
1313 {
1314 ConstantBuffer.Set<StpConstantBufferData>(data.cs, ShaderResources._StpConstantBufferData);
1315
1316 ctx.cmd.SetComputeTextureParam(data.cs, data.kernelIndex, ShaderResources._StpBlueNoiseIn, data.noiseTexture);
1317
1318 if (data.debugView.IsValid())
1319 ctx.cmd.SetComputeTextureParam(data.cs, data.kernelIndex, ShaderResources._StpDebugOut, data.debugView);
1320
1321 ctx.cmd.SetComputeTextureParam(data.cs, data.kernelIndex, ShaderResources._StpIntermediateColor, data.intermediateColor);
1322 ctx.cmd.SetComputeTextureParam(data.cs, data.kernelIndex, ShaderResources._StpIntermediateWeights, data.intermediateWeights);
1323
1324 ctx.cmd.SetComputeTextureParam(data.cs, data.kernelIndex, ShaderResources._StpPriorFeedback, data.priorFeedback);
1325 ctx.cmd.SetComputeTextureParam(data.cs, data.kernelIndex, ShaderResources._StpDepthMotion, data.depthMotion);
1326 ctx.cmd.SetComputeTextureParam(data.cs, data.kernelIndex, ShaderResources._StpConvergence, data.convergence);
1327
1328 ctx.cmd.SetComputeTextureParam(data.cs, data.kernelIndex, ShaderResources._StpFeedback, data.feedback);
1329 ctx.cmd.SetComputeTextureParam(data.cs, data.kernelIndex, ShaderResources._StpOutput, data.output);
1330
1331 ctx.cmd.DispatchCompute(data.cs, data.kernelIndex, data.dispatchSize.x, data.dispatchSize.y, data.viewCount);
1332 });
1333
1334 taaData = passData;
1335 }
1336
1337 return taaData.output;
1338 }
1339 }
1340}