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}