Compare commits

...

77 Commits

Author SHA1 Message Date
Nico de Poel cb4321b8ae Updated shaders and passes to the framework changes 2 years ago
Nico de Poel 5e9272b75a Merge branch 'framework' into fsr3framegen 2 years ago
Nico de Poel a0b519ff66 Reworked pass base class so it doesn't impose a dispatch method signature, as that proved to be too restrictive. Instead made adding a profiler sample easier using a disposable struct. 2 years ago
Nico de Poel 5944893e4b Renamed UNITY_FSR_ keywords and macros to UNITY_FFX_ to reflect that they're to be commonly used by all sorts of FidelityFX shaders. 2 years ago
Nico de Poel 8d289fdfa7 Renamed ffx_fsr_unity_common include file to ffx_unity_common, so it can be more generally used for all sorts of FidelityFX shaders. 2 years ago
Nico de Poel f1e963dfc1 Merge branch 'framework' into fsr3framegen 2 years ago
Nico de Poel 80f42cae73 Struct constraint on dispatch parameters can now be enforced 2 years ago
Nico de Poel 33f410125f Minor cleanup 2 years ago
Nico de Poel 9c377cc144 Use derived classes to reference passes. 2 years ago
Nico de Poel 76d0ee5425 Changed all dispatch descriptions into structs, renamed some fields, cleaned up some unused code. 2 years ago
Nico de Poel 2bb45ffb76 Merge branch 'framework' into fsr3framegen 2 years ago
Nico de Poel 452f9e13a9 Turned all dispatch descriptions into structs with a default value, applied in-parameters wherever appropriate, renamed a few things, and made pass references use the most derived type. 2 years ago
Nico de Poel 2ff4b9772b Made block size and texture size available through the optical flow context, which is better encapsulation. 2 years ago
Nico de Poel b1ddc9ba0d Moved duplicated BackbufferTransferFunction enum to a common enums file 2 years ago
Nico de Poel f41a81f1a8 Merge branch 'framework' into fsr3framegen 2 years ago
Nico de Poel 43e0f15ab8 Made the pass classes sealed, which is a more sensible way to please the compiler about using virtual methods inside constructors. 2 years ago
Nico de Poel 404a090adf Reworked optical flow passes to inherit from FfxPassBase, with a bit of a hack to work around the need for the extra level parameter. 2 years ago
Nico de Poel 371743ca70 Applied in-parameter for context and dispatch descriptions more consistently 2 years ago
Nico de Poel b21b1b43c4 Reworked passes to make the context description copy unnecessary, and made use of extension methods to simplify resource binding in Optical Flow passes. 2 years ago
Nico de Poel ac96933f9d Merge branch 'framework' into fsr3framegen 2 years ago
Nico de Poel b565ca029f Made flags a field of the FfxPassWithFlags class, obviating the need to hold on to a context description copy, or the need to pass flags around. 2 years ago
Nico de Poel acb54c821f Refactored frame interpolation passes to use the common base class, and simplified all of the shader resource bindings. 2 years ago
Nico de Poel 7b988fd39d Reworked dispatching code to use the common SPD and depth params methods. 2 years ago
Nico de Poel de4f5bd83d Refactored context classes to use common base class, and reworked constant buffers to use the wrapper class. 2 years ago
Nico de Poel 097eaa960a Refactored resources classes to use common base class 2 years ago
Nico de Poel 9d35022137 Merge branch 'framework' into fsr3framegen 2 years ago
Nico de Poel 3e4e0bb003 Moved SetupDeviceDepthToViewSpaceDepthParams to the common FfxUtils class 2 years ago
Nico de Poel 74a127a40d Further generalized SPD constants and setup 2 years ago
Nico de Poel d583c750d2 Moved SPD setup method into a separate common FfxSpd class 2 years ago
Nico de Poel 328011f7ba Added profiling samplers around the entire FSR2/3 process 2 years ago
Nico de Poel c5130f8236 Renamed frameIndex to bufferIndex 2 years ago
Nico de Poel 3e91f84cf8 Simplified handling of compute buffer data by wrapping it inside a helper class 2 years ago
Nico de Poel 19a74fee45 Created an abstract base class for context objects, with a few common helper methods 2 years ago
Nico de Poel c33ec9d4ed Further abstracted base pass class to allow for passes without shader keyword flags, and to allow custom kernel names. 2 years ago
Nico de Poel 7c923f8ce8 Renamed frameIndex to bufferIndex, which works in all contexts and makes it more clear that it'll be used as an array index 2 years ago
Nico de Poel 13b9b98318 Created additional extension methods to bind various compute shader resources, to make the dispatching code a lot more straightforward. 2 years ago
Nico de Poel 15b380eebf Abstracted some of the common pass code into a new base class for passes. 2 years ago
Nico de Poel 2d446333c1 Created additional shared helped methods for creating lookup textures and the Lanczos2 LUT 2 years ago
Nico de Poel 3bb3d78610 Refactored resource creation to make use of shared helped methods 2 years ago
Nico de Poel 6219d6159d Moved all create/destroy methods for various types of resources to a new common base class 2 years ago
Nico de Poel 9f06f24943 Moved a number of shared static helper methods to a new FfxUtils class 2 years ago
Nico de Poel 4282b10eb4 Revert "Disabling inverted depth flag while I try to figure out what the correct way to deal with this is. For now, this fixes the broken disocclusion mask causing holes in the interpolated frame, which then get filled in with junk by the inpainting pass." 2 years ago
Nico de Poel 49d197e60f Disabling inverted depth flag while I try to figure out what the correct way to deal with this is. For now, this fixes the broken disocclusion mask causing holes in the interpolated frame, which then get filled in with junk by the inpainting pass. 2 years ago
Nico de Poel 32692053a4 Small cleanup 2 years ago
Nico de Poel 875b90f6ef Simplified backbuffer selection for interpolation source 2 years ago
Nico de Poel 4e29c3dfb4 Replaced allocating lambda expression with a regular method. 2 years ago
Nico de Poel 01eb878a3e Removed pointless dispatch count, when it's only used to check for first execution 2 years ago
Nico de Poel c215db4017 Removed a few TODOs for things that have been checked and seem fine 2 years ago
Nico de Poel 4b675d285e Modified inpainting pyramid passes to use a maximum of 7 mip levels. This allows the shaders to stay within the limit of 8 UAV bindings required by DX11.0, and gets rid of Unity's warnings and errors about breaking this limit. 2 years ago
Nico de Poel a72e842bee Fixed unintentional cap on SPD mip levels 2 years ago
Nico de Poel 279edd4429 Allocate double buffers only when async compute support is enabled 2 years ago
Nico de Poel 80d63d74fa Fixed mipmap bindings when going over the RT's mipmap count, and pick the correct backbuffer to copy for the next frame. 2 years ago
Nico de Poel 910621b019 Couple of tweaks to facilitate integration 2 years ago
Nico de Poel ec705e3d8d Implemented remaining dispatch code 2 years ago
Nico de Poel 28ca91c32f Implemented prepare process and started on main dispatch 2 years ago
Nico de Poel 1fab819f35 Implemented remaining passes 2 years ago
Nico de Poel 4cd63e62a8 Implemented a bunch more FI passes 2 years ago
Nico de Poel 57b78d7bac Implemented prepare (reconstruct and dilate) pass 2 years ago
Nico de Poel df9db23e6a Set up shader IDs and dispatch descriptions 2 years ago
Nico de Poel e9c46dfdd7 Set up pass classes and instances 2 years ago
Nico de Poel c9f6b3f29d Implemented resources and some initialization code and structs 2 years ago
Nico de Poel 88a7c95666 Added script meta files that weren't generated yet last time around 2 years ago
Nico de Poel e6c714c02e Set up initial skeleton for Frame Interpolation implementation 2 years ago
Nico de Poel 198f2725af Renamed namespaces for OF and FI to FrameGen. Logically groups the two together, and it avoids the need for awkward OpticalFlow.OpticalFlow.something references. 2 years ago
Nico de Poel eeb4095685 Reworked backbuffer transfer function parameter into a clearly designated enum 2 years ago
Nico de Poel 9a72a8f180 Implemented the remaining optical flow passes and fixed a few small issues. 2 years ago
Nico de Poel c74320613b Reworked multi-level double-buffered resources into arrays of arrays of render textures 2 years ago
Nico de Poel 0701d8bf52 Moved some helper methods to the static OpticalFlow class 2 years ago
Nico de Poel 4be784e427 Implemented passes up to and including SCD divergence 2 years ago
Nico de Poel 70121d1516 Implemented resources, shader IDs, the skeleton for all passes, setup and destruction, a bunch of helper methods and dispatch of the prepare luma pass. 2 years ago
Nico de Poel 07a7571935 Set up first skeleton for optical flow data structures and dispatching 2 years ago
Nico de Poel b11aa5e50d Added asset container scriptable objects for optical flow and frame interpolation shaders. 2 years ago
Nico de Poel 95e86b769f Added multi-compile keywords for frame interpolation shaders 2 years ago
Nico de Poel 941bf006a2 Added compute shaders for all frame interpolation passes, configured them to compile with DXC and wave operation support. 2 years ago
Nico de Poel 280bd41ac8 Added compute shaders for all optical flow passes, configured them to compile with DXC and wave operation support. 2 years ago
Nico de Poel c3165c9880 Merge branch 'master' into fsr3framegen 2 years ago
Nico de Poel d0f6ddf019 Added FSR3 optical flow and frame interpolation shaders and headers, directly from the FidelityFX SDK. 2 years ago
  1. 57
      Runtime/Common/FfxContextBase.cs
  2. 11
      Runtime/Common/FfxContextBase.cs.meta
  3. 9
      Runtime/Common/FfxEnums.cs
  4. 11
      Runtime/Common/FfxEnums.cs.meta
  5. 79
      Runtime/Common/FfxPassBase.cs
  6. 11
      Runtime/Common/FfxPassBase.cs.meta
  7. 96
      Runtime/Common/FfxResourcesBase.cs
  8. 11
      Runtime/Common/FfxResourcesBase.cs.meta
  9. 46
      Runtime/Common/FfxSpd.cs
  10. 11
      Runtime/Common/FfxSpd.cs.meta
  11. 118
      Runtime/Common/FfxUtils.cs
  12. 11
      Runtime/Common/FfxUtils.cs.meta
  13. 90
      Runtime/FSR2/Fsr2.cs
  14. 267
      Runtime/FSR2/Fsr2Context.cs
  15. 267
      Runtime/FSR2/Fsr2Pass.cs
  16. 89
      Runtime/FSR2/Fsr2Resources.cs
  17. 90
      Runtime/FSR3/Fsr3Upscaler.cs
  18. 1
      Runtime/FSR3/Fsr3UpscalerAssets.cs
  19. 295
      Runtime/FSR3/Fsr3UpscalerContext.cs
  20. 332
      Runtime/FSR3/Fsr3UpscalerPass.cs
  21. 93
      Runtime/FSR3/Fsr3UpscalerResources.cs
  22. 8
      Runtime/FrameInterpolation.meta
  23. 162
      Runtime/FrameInterpolation/FrameInterpolation.cs
  24. 11
      Runtime/FrameInterpolation/FrameInterpolation.cs.meta
  25. 176
      Runtime/FrameInterpolation/FrameInterpolationAssets.cs
  26. 11
      Runtime/FrameInterpolation/FrameInterpolationAssets.cs.meta
  27. 260
      Runtime/FrameInterpolation/FrameInterpolationContext.cs
  28. 11
      Runtime/FrameInterpolation/FrameInterpolationContext.cs.meta
  29. 333
      Runtime/FrameInterpolation/FrameInterpolationPass.cs
  30. 11
      Runtime/FrameInterpolation/FrameInterpolationPass.cs.meta
  31. 64
      Runtime/FrameInterpolation/FrameInterpolationResources.cs
  32. 11
      Runtime/FrameInterpolation/FrameInterpolationResources.cs.meta
  33. 60
      Runtime/FrameInterpolation/FrameInterpolationShaderIDs.cs
  34. 11
      Runtime/FrameInterpolation/FrameInterpolationShaderIDs.cs.meta
  35. 8
      Runtime/OpticalFlow.meta
  36. 102
      Runtime/OpticalFlow/OpticalFlow.cs
  37. 11
      Runtime/OpticalFlow/OpticalFlow.cs.meta
  38. 144
      Runtime/OpticalFlow/OpticalFlowAssets.cs
  39. 11
      Runtime/OpticalFlow/OpticalFlowAssets.cs.meta
  40. 228
      Runtime/OpticalFlow/OpticalFlowContext.cs
  41. 11
      Runtime/OpticalFlow/OpticalFlowContext.cs.meta
  42. 200
      Runtime/OpticalFlow/OpticalFlowPass.cs
  43. 11
      Runtime/OpticalFlow/OpticalFlowPass.cs.meta
  44. 76
      Runtime/OpticalFlow/OpticalFlowResources.cs
  45. 11
      Runtime/OpticalFlow/OpticalFlowResources.cs.meta
  46. 33
      Runtime/OpticalFlow/OpticalFlowShaderIDs.cs
  47. 11
      Runtime/OpticalFlow/OpticalFlowShaderIDs.cs.meta
  48. 33
      Shaders/ffx_frameinterpolation_compute_game_vector_field_inpainting_pyramid_pass.compute
  49. 8
      Shaders/ffx_frameinterpolation_compute_game_vector_field_inpainting_pyramid_pass.compute.meta
  50. 33
      Shaders/ffx_frameinterpolation_compute_inpainting_pyramid_pass.compute
  51. 8
      Shaders/ffx_frameinterpolation_compute_inpainting_pyramid_pass.compute.meta
  52. 33
      Shaders/ffx_frameinterpolation_debug_view_pass.compute
  53. 8
      Shaders/ffx_frameinterpolation_debug_view_pass.compute.meta
  54. 33
      Shaders/ffx_frameinterpolation_disocclusion_mask_pass.compute
  55. 8
      Shaders/ffx_frameinterpolation_disocclusion_mask_pass.compute.meta
  56. 33
      Shaders/ffx_frameinterpolation_game_motion_vector_field_pass.compute
  57. 8
      Shaders/ffx_frameinterpolation_game_motion_vector_field_pass.compute.meta
  58. 33
      Shaders/ffx_frameinterpolation_inpainting_pass.compute
  59. 8
      Shaders/ffx_frameinterpolation_inpainting_pass.compute.meta
  60. 33
      Shaders/ffx_frameinterpolation_optical_flow_vector_field_pass.compute
  61. 8
      Shaders/ffx_frameinterpolation_optical_flow_vector_field_pass.compute.meta
  62. 33
      Shaders/ffx_frameinterpolation_pass.compute
  63. 8
      Shaders/ffx_frameinterpolation_pass.compute.meta
  64. 34
      Shaders/ffx_frameinterpolation_reconstruct_and_dilate_pass.compute
  65. 8
      Shaders/ffx_frameinterpolation_reconstruct_and_dilate_pass.compute.meta
  66. 33
      Shaders/ffx_frameinterpolation_reconstruct_previous_depth_pass.compute
  67. 8
      Shaders/ffx_frameinterpolation_reconstruct_previous_depth_pass.compute.meta
  68. 33
      Shaders/ffx_frameinterpolation_setup_pass.compute
  69. 8
      Shaders/ffx_frameinterpolation_setup_pass.compute.meta
  70. 4
      Shaders/ffx_fsr2_accumulate_pass.compute
  71. 4
      Shaders/ffx_fsr2_autogen_reactive_pass.compute
  72. 4
      Shaders/ffx_fsr2_compute_luminance_pyramid_pass.compute
  73. 4
      Shaders/ffx_fsr2_depth_clip_pass.compute
  74. 4
      Shaders/ffx_fsr2_lock_pass.compute
  75. 4
      Shaders/ffx_fsr2_rcas_pass.compute
  76. 4
      Shaders/ffx_fsr2_reconstruct_previous_depth_pass.compute
  77. 4
      Shaders/ffx_fsr2_tcr_autogen_pass.compute
  78. 4
      Shaders/ffx_fsr3upscaler_accumulate_pass.compute
  79. 4
      Shaders/ffx_fsr3upscaler_autogen_reactive_pass.compute
  80. 4
      Shaders/ffx_fsr3upscaler_debug_view_pass.compute
  81. 4
      Shaders/ffx_fsr3upscaler_luma_instability_pass.compute
  82. 4
      Shaders/ffx_fsr3upscaler_luma_pyramid_pass.compute
  83. 4
      Shaders/ffx_fsr3upscaler_prepare_inputs_pass.compute
  84. 4
      Shaders/ffx_fsr3upscaler_prepare_reactivity_pass.compute
  85. 4
      Shaders/ffx_fsr3upscaler_rcas_pass.compute
  86. 4
      Shaders/ffx_fsr3upscaler_shading_change_pass.compute
  87. 4
      Shaders/ffx_fsr3upscaler_shading_change_pyramid_pass.compute
  88. 4
      Shaders/ffx_fsr3upscaler_tcr_autogen_pass.compute
  89. 30
      Shaders/ffx_opticalflow_compute_luminance_pyramid_pass.compute
  90. 8
      Shaders/ffx_opticalflow_compute_luminance_pyramid_pass.compute.meta
  91. 30
      Shaders/ffx_opticalflow_compute_optical_flow_advanced_pass_v5.compute
  92. 8
      Shaders/ffx_opticalflow_compute_optical_flow_advanced_pass_v5.compute.meta
  93. 30
      Shaders/ffx_opticalflow_compute_scd_divergence_pass.compute
  94. 8
      Shaders/ffx_opticalflow_compute_scd_divergence_pass.compute.meta
  95. 30
      Shaders/ffx_opticalflow_filter_optical_flow_pass_v5.compute
  96. 8
      Shaders/ffx_opticalflow_filter_optical_flow_pass_v5.compute.meta
  97. 30
      Shaders/ffx_opticalflow_generate_scd_histogram_pass.compute
  98. 8
      Shaders/ffx_opticalflow_generate_scd_histogram_pass.compute.meta
  99. 30
      Shaders/ffx_opticalflow_prepare_luma_pass.compute
  100. 8
      Shaders/ffx_opticalflow_prepare_luma_pass.compute.meta

57
Runtime/Common/FfxContextBase.cs

@ -0,0 +1,57 @@
using System;
using System.Runtime.InteropServices;
using UnityEngine;
using UnityEngine.Rendering;
namespace FidelityFX
{
public abstract class FfxContextBase
{
protected static void DestroyPass<TPass>(ref TPass pass)
where TPass: class, IDisposable
{
if (pass == null)
return;
pass.Dispose();
pass = null;
}
/// <summary>
/// Convenience class for handling a constants buffer containing a single struct item.
/// This wraps the compute buffer and the value array, as well as providing easy access to both.
/// </summary>
protected class ConstantsBuffer<TConst>
where TConst: struct
{
private ComputeBuffer _computeBuffer;
private readonly TConst[] _constArray = { new TConst() };
public ref TConst Value => ref _constArray[0];
public void Create()
{
_computeBuffer = new ComputeBuffer(1, Marshal.SizeOf<TConst>(), ComputeBufferType.Constant);
}
public void UpdateBufferData(CommandBuffer commandBuffer)
{
commandBuffer.SetBufferData(_computeBuffer, _constArray);
}
public void Destroy()
{
if (_computeBuffer == null)
return;
_computeBuffer.Release();
_computeBuffer = null;
}
public static implicit operator ComputeBuffer(ConstantsBuffer<TConst> constants)
{
return constants._computeBuffer;
}
}
}
}

11
Runtime/Common/FfxContextBase.cs.meta

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f4aeccbeb6e61434eb2e50b7190fda8d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

9
Runtime/Common/FfxEnums.cs

@ -0,0 +1,9 @@
namespace FidelityFX
{
public enum BackbufferTransferFunction
{
LDR_sRGB,
HDR_PQ,
HDR_scRGB,
}
}

11
Runtime/Common/FfxEnums.cs.meta

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d71b9fd70a8fb26439d07bf3fbb6bd65
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

79
Runtime/Common/FfxPassBase.cs

@ -0,0 +1,79 @@
using System;
using UnityEngine;
using UnityEngine.Profiling;
using UnityEngine.Rendering;
namespace FidelityFX
{
internal abstract class FfxPassBase: IDisposable
{
private readonly string _techName;
private string _passName;
protected ComputeShader ComputeShader;
protected int KernelIndex;
protected FfxPassBase(string techName)
{
_techName = techName;
}
protected virtual void InitComputeShader(string passName, ComputeShader shader, string kernelName = "CS")
{
if (shader == null)
{
throw new MissingReferenceException($"Shader for {_techName} pass '{passName}' could not be loaded! Please ensure it is included in the project correctly.");
}
_passName = passName;
ComputeShader = shader;
KernelIndex = ComputeShader.FindKernel(kernelName);
}
public virtual void Dispose()
{
}
protected ProfilerSampler ProfilerSample(CommandBuffer commandBuffer)
{
return new ProfilerSampler(_passName, commandBuffer);
}
protected readonly struct ProfilerSampler : IDisposable
{
private readonly string _name;
private readonly CommandBuffer _commandBuffer;
public ProfilerSampler(string name, CommandBuffer commandBuffer)
{
_name = name;
_commandBuffer = commandBuffer;
_commandBuffer.BeginSample(_name);
}
public void Dispose()
{
_commandBuffer.EndSample(_name);
}
}
}
internal abstract class FfxPassWithFlags<TFlags> : FfxPassBase
where TFlags: Enum
{
protected readonly TFlags Flags;
protected FfxPassWithFlags(string techName, TFlags flags) : base(techName)
{
Flags = flags;
}
protected override void InitComputeShader(string passName, ComputeShader shader, string kernelName = "CS")
{
base.InitComputeShader(passName, shader, kernelName);
SetupShaderKeywords();
}
protected abstract void SetupShaderKeywords();
}
}

11
Runtime/Common/FfxPassBase.cs.meta

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: deac9cc5a4c6df64db05956030e79425
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

96
Runtime/Common/FfxResourcesBase.cs

@ -0,0 +1,96 @@
using System;
using System.Runtime.InteropServices;
using UnityEngine;
using UnityEngine.Experimental.Rendering;
namespace FidelityFX
{
internal abstract class FfxResourcesBase
{
protected static ComputeBuffer CreateBuffer<TElem>(string name, int count)
{
return new ComputeBuffer(count, Marshal.SizeOf<TElem>());
}
protected static Texture2D CreateLookup(string name, GraphicsFormat format, Color data)
{
var tex = new Texture2D(1, 1, format, TextureCreationFlags.None) { name = name };
tex.SetPixel(0, 0, data);
tex.Apply();
return tex;
}
protected static Texture2D CreateLookup<T>(string name, in Vector2Int size, GraphicsFormat format, T[] data)
{
var tex = new Texture2D(size.x, size.y, format, TextureCreationFlags.None) { name = name };
tex.SetPixelData(data, 0);
tex.Apply();
return tex;
}
protected static RenderTexture CreateResource(string name, in Vector2Int size, GraphicsFormat format)
{
var rt = new RenderTexture(size.x, size.y, 0, format) { name = name, enableRandomWrite = true };
rt.Create();
return rt;
}
protected static RenderTexture CreateResourceMips(string name, in Vector2Int size, GraphicsFormat format)
{
int mipCount = 1 + Mathf.FloorToInt(Mathf.Log(Math.Max(size.x, size.y), 2.0f));
var rt = new RenderTexture(size.x, size.y, 0, format, mipCount) { name = name, enableRandomWrite = true, useMipMap = true, autoGenerateMips = false };
rt.Create();
return rt;
}
protected static void CreateDoubleBufferedResource(RenderTexture[] resource, string name, in Vector2Int size, GraphicsFormat format, int numElements = 2)
{
numElements = Math.Min(resource.Length, numElements);
for (int i = 0; i < numElements; ++i)
{
resource[i] = new RenderTexture(size.x, size.y, 0, format) { name = name + (i + 1), enableRandomWrite = true };
resource[i].Create();
}
}
protected static void DestroyResource(ref Texture2D resource)
{
if (resource == null)
return;
#if UNITY_EDITOR
if (Application.isPlaying && !UnityEditor.EditorApplication.isPaused)
UnityEngine.Object.Destroy(resource);
else
UnityEngine.Object.DestroyImmediate(resource);
#else
UnityEngine.Object.Destroy(resource);
#endif
resource = null;
}
protected static void DestroyResource(ref RenderTexture resource)
{
if (resource == null)
return;
resource.Release();
resource = null;
}
protected static void DestroyResource(ref ComputeBuffer resource)
{
if (resource == null)
return;
resource.Release();
resource = null;
}
protected static void DestroyResource(RenderTexture[] resource)
{
for (int i = 0; i < resource.Length; ++i)
DestroyResource(ref resource[i]);
}
}
}

11
Runtime/Common/FfxResourcesBase.cs.meta

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2a46b97ac72c45545a80a896462e1112
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

46
Runtime/Common/FfxSpd.cs

@ -0,0 +1,46 @@
using System;
using System.Runtime.InteropServices;
using UnityEngine;
namespace FidelityFX
{
public static class FfxSpd
{
public static void SetupSpdConstants(Vector2Int resolution, ref SpdConstants spdConstants, out Vector2Int dispatchThreadGroupCount, int mips = -1)
{
RectInt rectInfo = new RectInt(0, 0, resolution.x, resolution.y);
SpdSetup(rectInfo, out dispatchThreadGroupCount, out Vector2Int workGroupOffset, out Vector2Int numWorkGroupsAndMips, mips);
spdConstants.numWorkGroups = (uint)numWorkGroupsAndMips.x;
spdConstants.mips = (uint)numWorkGroupsAndMips.y;
spdConstants.workGroupOffsetX = (uint)workGroupOffset.x;
spdConstants.workGroupOffsetY = (uint)workGroupOffset.y;
}
public static void SpdSetup(RectInt rectInfo, out Vector2Int dispatchThreadGroupCount, out Vector2Int workGroupOffset, out Vector2Int numWorkGroupsAndMips, int mips = -1)
{
workGroupOffset = new Vector2Int(rectInfo.x / 64, rectInfo.y / 64);
int endIndexX = (rectInfo.x + rectInfo.width - 1) / 64;
int endIndexY = (rectInfo.y + rectInfo.height - 1) / 64;
dispatchThreadGroupCount = new Vector2Int(endIndexX + 1 - workGroupOffset.x, endIndexY + 1 - workGroupOffset.y);
numWorkGroupsAndMips = new Vector2Int(dispatchThreadGroupCount.x * dispatchThreadGroupCount.y, mips);
if (mips < 0)
{
float resolution = Math.Max(rectInfo.width, rectInfo.height);
numWorkGroupsAndMips.y = Math.Min(Mathf.FloorToInt(Mathf.Log(resolution, 2.0f)), 12);
}
}
[Serializable, StructLayout(LayoutKind.Sequential)]
public struct SpdConstants
{
public uint mips;
public uint numWorkGroups;
public uint workGroupOffsetX;
public uint workGroupOffsetY;
}
}
}

11
Runtime/Common/FfxSpd.cs.meta

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: aee0f42dc1676ab4db5c01520b0b925a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

118
Runtime/Common/FfxUtils.cs

@ -0,0 +1,118 @@
using System;
using System.Runtime.InteropServices;
using UnityEngine;
using UnityEngine.Rendering;
namespace FidelityFX
{
public static class FfxUtils
{
public static float GetMipmapBiasOffset(int renderWidth, int displayWidth)
{
return Mathf.Log((float)renderWidth / displayWidth, 2.0f) - 1.0f;
}
public static int GetJitterPhaseCount(int renderWidth, int displayWidth)
{
const float basePhaseCount = 8.0f;
int jitterPhaseCount = (int)(basePhaseCount * Mathf.Pow((float)displayWidth / renderWidth, 2.0f));
return jitterPhaseCount;
}
public static void GetJitterOffset(out float outX, out float outY, int index, int phaseCount)
{
outX = Halton((index % phaseCount) + 1, 2) - 0.5f;
outY = Halton((index % phaseCount) + 1, 3) - 0.5f;
}
// Calculate halton number for index and base.
private static float Halton(int index, int @base)
{
float f = 1.0f, result = 0.0f;
for (int currentIndex = index; currentIndex > 0;) {
f /= @base;
result += f * (currentIndex % @base);
currentIndex = (int)Mathf.Floor((float)currentIndex / @base);
}
return result;
}
public static float Lanczos2(float value)
{
return Mathf.Abs(value) < Mathf.Epsilon ? 1.0f : Mathf.Sin(Mathf.PI * value) / (Mathf.PI * value) * (Mathf.Sin(0.5f * Mathf.PI * value) / (0.5f * Mathf.PI * value));
}
public static float[] GenerateLanczos2Table(int width)
{
float[] lanczos2Weights = new float[width];
for (int currentLanczosWidthIndex = 0; currentLanczosWidthIndex < width; ++currentLanczosWidthIndex)
{
float x = 2.0f * currentLanczosWidthIndex / (width - 1);
float y = Lanczos2(x);
lanczos2Weights[currentLanczosWidthIndex] = y;
}
return lanczos2Weights;
}
public static Vector4 SetupDeviceDepthToViewSpaceDepthParams(Vector2Int renderSize, float cameraNear, float cameraFar, float cameraFovAngleVertical, bool inverted, bool infinite)
{
// make sure it has no impact if near and far plane values are swapped in dispatch params
// the flags "inverted" and "infinite" will decide what transform to use
float min = Mathf.Min(cameraNear, cameraFar);
float max = Mathf.Max(cameraNear, cameraFar);
if (inverted)
{
(min, max) = (max, min);
}
float q = max / (min - max);
float d = -1.0f;
Vector4 matrixElemC = new Vector4(q, -1.0f - Mathf.Epsilon, q, 0.0f + Mathf.Epsilon);
Vector4 matrixElemE = new Vector4(q * min, -min - Mathf.Epsilon, q * min, max);
// Revert x and y coords
float aspect = (float)renderSize.x / renderSize.y;
float cotHalfFovY = Mathf.Cos(0.5f * cameraFovAngleVertical) / Mathf.Sin(0.5f * cameraFovAngleVertical);
int matrixIndex = (inverted ? 2 : 0) + (infinite ? 1 : 0);
return new Vector4(
d * matrixElemC[matrixIndex],
matrixElemE[matrixIndex],
aspect / cotHalfFovY,
1.0f / cotHalfFovY);
}
#if !UNITY_2021_1_OR_NEWER
internal static void SetBufferData(this CommandBuffer commandBuffer, ComputeBuffer computeBuffer, Array data)
{
commandBuffer.SetComputeBufferData(computeBuffer, data);
}
#endif
/// <summary>
/// Alternative for CommandBuffer.SetComputeTextureParam that guards against attempts to bind mip levels that don't exist.
/// </summary>
internal static void SetComputeTextureMipParam(this CommandBuffer commandBuffer, ComputeShader computeShader, int kernelIndex, int nameID, Texture texture, int mipLevel)
{
mipLevel = Math.Min(mipLevel, texture.mipmapCount - 1);
commandBuffer.SetComputeTextureParam(computeShader, kernelIndex, nameID, texture, mipLevel);
}
internal static void SetComputeResourceParam(this CommandBuffer commandBuffer, ComputeShader computeShader, int kernelIndex, int nameID, in ResourceView resource)
{
commandBuffer.SetComputeTextureParam(computeShader, kernelIndex, nameID, resource.RenderTarget, resource.MipLevel, resource.SubElement);
}
internal static void SetComputeConstantBufferParam<TBuf>(this CommandBuffer commandBuffer, ComputeShader computeShader, int nameID, ComputeBuffer buffer)
where TBuf: struct
{
commandBuffer.SetComputeConstantBufferParam(computeShader, nameID, buffer, 0, Marshal.SizeOf<TBuf>());
}
}
}

11
Runtime/Common/FfxUtils.cs.meta

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9c5c0f0b987cca64c8dfd8051e09962e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

90
Runtime/FSR2/Fsr2.cs

@ -21,7 +21,6 @@
using System; using System;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using UnityEngine; using UnityEngine;
using UnityEngine.Rendering;
namespace FidelityFX.FSR2 namespace FidelityFX.FSR2
{ {
@ -80,60 +79,13 @@ namespace FidelityFX.FSR2
} }
} }
public static void GetRenderResolutionFromQualityMode(
out int renderWidth, out int renderHeight,
int displayWidth, int displayHeight, QualityMode qualityMode)
public static void GetRenderResolutionFromQualityMode(out int renderWidth, out int renderHeight, int displayWidth, int displayHeight, QualityMode qualityMode)
{ {
float ratio = GetUpscaleRatioFromQualityMode(qualityMode); float ratio = GetUpscaleRatioFromQualityMode(qualityMode);
renderWidth = Mathf.RoundToInt(displayWidth / ratio); renderWidth = Mathf.RoundToInt(displayWidth / ratio);
renderHeight = Mathf.RoundToInt(displayHeight / ratio); renderHeight = Mathf.RoundToInt(displayHeight / ratio);
} }
public static float GetMipmapBiasOffset(int renderWidth, int displayWidth)
{
return Mathf.Log((float)renderWidth / displayWidth, 2.0f) - 1.0f;
}
public static int GetJitterPhaseCount(int renderWidth, int displayWidth)
{
const float basePhaseCount = 8.0f;
int jitterPhaseCount = (int)(basePhaseCount * Mathf.Pow((float)displayWidth / renderWidth, 2.0f));
return jitterPhaseCount;
}
public static void GetJitterOffset(out float outX, out float outY, int index, int phaseCount)
{
outX = Halton((index % phaseCount) + 1, 2) - 0.5f;
outY = Halton((index % phaseCount) + 1, 3) - 0.5f;
}
// Calculate halton number for index and base.
private static float Halton(int index, int @base)
{
float f = 1.0f, result = 0.0f;
for (int currentIndex = index; currentIndex > 0;) {
f /= @base;
result += f * (currentIndex % @base);
currentIndex = (int)Mathf.Floor((float)currentIndex / @base);
}
return result;
}
public static float Lanczos2(float value)
{
return Mathf.Abs(value) < Mathf.Epsilon ? 1.0f : Mathf.Sin(Mathf.PI * value) / (Mathf.PI * value) * (Mathf.Sin(0.5f * Mathf.PI * value) / (0.5f * Mathf.PI * value));
}
#if !UNITY_2021_1_OR_NEWER
internal static void SetBufferData(this CommandBuffer commandBuffer, ComputeBuffer computeBuffer, Array data)
{
commandBuffer.SetComputeBufferData(computeBuffer, data);
}
#endif
public enum QualityMode public enum QualityMode
{ {
NativeAA = 0, NativeAA = 0,
@ -172,7 +124,7 @@ namespace FidelityFX.FSR2
/// <summary> /// <summary>
/// A structure encapsulating the parameters for dispatching the various passes of FidelityFX Super Resolution 2. /// A structure encapsulating the parameters for dispatching the various passes of FidelityFX Super Resolution 2.
/// </summary> /// </summary>
public class DispatchDescription
public struct DispatchDescription
{ {
public ResourceView Color; public ResourceView Color;
public ResourceView Depth; public ResourceView Depth;
@ -199,26 +151,42 @@ namespace FidelityFX.FSR2
// EXPERIMENTAL reactive mask generation parameters // EXPERIMENTAL reactive mask generation parameters
public bool EnableAutoReactive; public bool EnableAutoReactive;
public ResourceView ColorOpaqueOnly; public ResourceView ColorOpaqueOnly;
public float AutoTcThreshold = 0.05f;
public float AutoTcScale = 1.0f;
public float AutoReactiveScale = 5.0f;
public float AutoReactiveMax = 0.9f;
public float AutoTcThreshold;
public float AutoTcScale;
public float AutoReactiveScale;
public float AutoReactiveMax;
public static readonly DispatchDescription Default = new DispatchDescription
{
AutoTcThreshold = 0.05f,
AutoTcScale = 1.0f,
AutoReactiveScale = 5.0f,
AutoReactiveMax = 0.9f,
};
} }
/// <summary> /// <summary>
/// A structure encapsulating the parameters for automatic generation of a reactive mask. /// A structure encapsulating the parameters for automatic generation of a reactive mask.
/// The default values for Scale, CutoffThreshold, BinaryValue and Flags were taken from the FSR2 demo project. /// The default values for Scale, CutoffThreshold, BinaryValue and Flags were taken from the FSR2 demo project.
/// </summary> /// </summary>
public class GenerateReactiveDescription
public struct GenerateReactiveDescription
{ {
public ResourceView ColorOpaqueOnly; public ResourceView ColorOpaqueOnly;
public ResourceView ColorPreUpscale; public ResourceView ColorPreUpscale;
public ResourceView OutReactive; public ResourceView OutReactive;
public Vector2Int RenderSize; public Vector2Int RenderSize;
public float Scale = 0.5f;
public float CutoffThreshold = 0.2f;
public float BinaryValue = 0.9f;
public GenerateReactiveFlags Flags = GenerateReactiveFlags.ApplyTonemap | GenerateReactiveFlags.ApplyThreshold | GenerateReactiveFlags.UseComponentsMax;
public float Scale;
public float CutoffThreshold;
public float BinaryValue;
public GenerateReactiveFlags Flags;
public static readonly GenerateReactiveDescription Default = new GenerateReactiveDescription
{
Scale = 0.5f,
CutoffThreshold = 0.2f,
BinaryValue = 0.9f,
Flags = GenerateReactiveFlags.ApplyTonemap | GenerateReactiveFlags.ApplyThreshold | GenerateReactiveFlags.UseComponentsMax,
};
} }
[Flags] [Flags]
@ -259,9 +227,7 @@ namespace FidelityFX.FSR2
[Serializable, StructLayout(LayoutKind.Sequential)] [Serializable, StructLayout(LayoutKind.Sequential)]
internal struct SpdConstants internal struct SpdConstants
{ {
public uint mips;
public uint numWorkGroups;
public uint workGroupOffsetX, workGroupOffsetY;
public FfxSpd.SpdConstants spd;
public uint renderSizeX, renderSizeY; public uint renderSizeX, renderSizeY;
} }

267
Runtime/FSR2/Fsr2Context.cs

@ -19,8 +19,8 @@
// THE SOFTWARE. // THE SOFTWARE.
using System; using System;
using System.Runtime.InteropServices;
using UnityEngine; using UnityEngine;
using UnityEngine.Profiling;
using UnityEngine.Rendering; using UnityEngine.Rendering;
namespace FidelityFX.FSR2 namespace FidelityFX.FSR2
@ -31,64 +31,52 @@ namespace FidelityFX.FSR2
/// Note that this class does not know anything about Unity render pipelines; all it knows is CommandBuffers and RenderTargetIdentifiers. /// Note that this class does not know anything about Unity render pipelines; all it knows is CommandBuffers and RenderTargetIdentifiers.
/// This should make it suitable for integration with any of the available Unity render pipelines. /// This should make it suitable for integration with any of the available Unity render pipelines.
/// </summary> /// </summary>
public class Fsr2Context
public class Fsr2Context: FfxContextBase
{ {
private const int MaxQueuedFrames = 16; private const int MaxQueuedFrames = 16;
private Fsr2.ContextDescription _contextDescription; private Fsr2.ContextDescription _contextDescription;
private CommandBuffer _commandBuffer; private CommandBuffer _commandBuffer;
private Fsr2Pass _computeLuminancePyramidPass;
private Fsr2Pass _reconstructPreviousDepthPass;
private Fsr2Pass _depthClipPass;
private Fsr2Pass _lockPass;
private Fsr2Pass _accumulatePass;
private Fsr2Pass _sharpenPass;
private Fsr2Pass _generateReactivePass;
private Fsr2Pass _tcrAutogeneratePass;
private Fsr2ComputeLuminancePyramidPass _computeLuminancePyramidPass;
private Fsr2ReconstructPreviousDepthPass _reconstructPreviousDepthPass;
private Fsr2DepthClipPass _depthClipPass;
private Fsr2LockPass _lockPass;
private Fsr2AccumulatePass _accumulatePass;
private Fsr2SharpenPass _sharpenPass;
private Fsr2GenerateReactivePass _generateReactivePass;
private Fsr2TcrAutogeneratePass _tcrAutogeneratePass;
private readonly Fsr2Resources _resources = new Fsr2Resources(); private readonly Fsr2Resources _resources = new Fsr2Resources();
private ComputeBuffer _upscalerConstantsBuffer;
private readonly Fsr2.UpscalerConstants[] _upscalerConstantsArray = { new Fsr2.UpscalerConstants() };
private ref Fsr2.UpscalerConstants UpscalerConsts => ref _upscalerConstantsArray[0];
private ComputeBuffer _spdConstantsBuffer;
private readonly Fsr2.SpdConstants[] _spdConstantsArray = { new Fsr2.SpdConstants() };
private ref Fsr2.SpdConstants SpdConsts => ref _spdConstantsArray[0];
private ComputeBuffer _rcasConstantsBuffer;
private readonly Fsr2.RcasConstants[] _rcasConstantsArray = new Fsr2.RcasConstants[1];
private ref Fsr2.RcasConstants RcasConsts => ref _rcasConstantsArray[0];
private ComputeBuffer _generateReactiveConstantsBuffer;
private readonly Fsr2.GenerateReactiveConstants[] _generateReactiveConstantsArray = { new Fsr2.GenerateReactiveConstants() };
private ref Fsr2.GenerateReactiveConstants GenReactiveConsts => ref _generateReactiveConstantsArray[0];
private ComputeBuffer _tcrAutogenerateConstantsBuffer;
private readonly Fsr2.GenerateReactiveConstants2[] _tcrAutogenerateConstantsArray = { new Fsr2.GenerateReactiveConstants2() };
private ref Fsr2.GenerateReactiveConstants2 TcrAutoGenConsts => ref _tcrAutogenerateConstantsArray[0];
private readonly ConstantsBuffer<Fsr2.UpscalerConstants> _upscalerConstants = new ConstantsBuffer<Fsr2.UpscalerConstants>();
private readonly ConstantsBuffer<Fsr2.SpdConstants> _spdConstants = new ConstantsBuffer<Fsr2.SpdConstants>();
private readonly ConstantsBuffer<Fsr2.RcasConstants> _rcasConstants = new ConstantsBuffer<Fsr2.RcasConstants>();
private readonly ConstantsBuffer<Fsr2.GenerateReactiveConstants> _generateReactiveConstants = new ConstantsBuffer<Fsr2.GenerateReactiveConstants>();
private readonly ConstantsBuffer<Fsr2.GenerateReactiveConstants2> _tcrAutogenerateConstants = new ConstantsBuffer<Fsr2.GenerateReactiveConstants2>();
private bool _firstExecution; private bool _firstExecution;
private Vector2 _previousJitterOffset; private Vector2 _previousJitterOffset;
private int _resourceFrameIndex; private int _resourceFrameIndex;
private readonly CustomSampler _sampler = CustomSampler.Create("FSR2");
public void Create(Fsr2.ContextDescription contextDescription)
public void Create(in Fsr2.ContextDescription contextDescription)
{ {
_contextDescription = contextDescription; _contextDescription = contextDescription;
_commandBuffer = new CommandBuffer { name = "FSR2" }; _commandBuffer = new CommandBuffer { name = "FSR2" };
_upscalerConstantsBuffer = CreateConstantBuffer<Fsr2.UpscalerConstants>();
_spdConstantsBuffer = CreateConstantBuffer<Fsr2.SpdConstants>();
_rcasConstantsBuffer = CreateConstantBuffer<Fsr2.RcasConstants>();
_generateReactiveConstantsBuffer = CreateConstantBuffer<Fsr2.GenerateReactiveConstants>();
_tcrAutogenerateConstantsBuffer = CreateConstantBuffer<Fsr2.GenerateReactiveConstants2>();
_upscalerConstants.Create();
_spdConstants.Create();
_rcasConstants.Create();
_generateReactiveConstants.Create();
_tcrAutogenerateConstants.Create();
// Set defaults // Set defaults
_firstExecution = true; _firstExecution = true;
_resourceFrameIndex = 0; _resourceFrameIndex = 0;
UpscalerConsts.displaySize = _contextDescription.DisplaySize;
_upscalerConstants.Value.displaySize = _contextDescription.DisplaySize;
_resources.Create(_contextDescription); _resources.Create(_contextDescription);
CreatePasses(); CreatePasses();
@ -96,14 +84,14 @@ namespace FidelityFX.FSR2
private void CreatePasses() private void CreatePasses()
{ {
_computeLuminancePyramidPass = new Fsr2ComputeLuminancePyramidPass(_contextDescription, _resources, _upscalerConstantsBuffer, _spdConstantsBuffer);
_reconstructPreviousDepthPass = new Fsr2ReconstructPreviousDepthPass(_contextDescription, _resources, _upscalerConstantsBuffer);
_depthClipPass = new Fsr2DepthClipPass(_contextDescription, _resources, _upscalerConstantsBuffer);
_lockPass = new Fsr2LockPass(_contextDescription, _resources, _upscalerConstantsBuffer);
_accumulatePass = new Fsr2AccumulatePass(_contextDescription, _resources, _upscalerConstantsBuffer);
_sharpenPass = new Fsr2SharpenPass(_contextDescription, _resources, _upscalerConstantsBuffer, _rcasConstantsBuffer);
_generateReactivePass = new Fsr2GenerateReactivePass(_contextDescription, _resources, _generateReactiveConstantsBuffer);
_tcrAutogeneratePass = new Fsr2TcrAutogeneratePass(_contextDescription, _resources, _upscalerConstantsBuffer, _tcrAutogenerateConstantsBuffer);
_computeLuminancePyramidPass = new Fsr2ComputeLuminancePyramidPass(_contextDescription, _resources, _upscalerConstants, _spdConstants);
_reconstructPreviousDepthPass = new Fsr2ReconstructPreviousDepthPass(_contextDescription, _resources, _upscalerConstants);
_depthClipPass = new Fsr2DepthClipPass(_contextDescription, _resources, _upscalerConstants);
_lockPass = new Fsr2LockPass(_contextDescription, _resources, _upscalerConstants);
_accumulatePass = new Fsr2AccumulatePass(_contextDescription, _resources, _upscalerConstants);
_sharpenPass = new Fsr2SharpenPass(_contextDescription, _resources, _upscalerConstants, _rcasConstants);
_generateReactivePass = new Fsr2GenerateReactivePass(_contextDescription, _resources, _generateReactiveConstants);
_tcrAutogeneratePass = new Fsr2TcrAutogeneratePass(_contextDescription, _resources, _upscalerConstants, _tcrAutogenerateConstants);
} }
public void Destroy() public void Destroy()
@ -119,11 +107,11 @@ namespace FidelityFX.FSR2
_resources.Destroy(); _resources.Destroy();
DestroyConstantBuffer(ref _tcrAutogenerateConstantsBuffer);
DestroyConstantBuffer(ref _generateReactiveConstantsBuffer);
DestroyConstantBuffer(ref _rcasConstantsBuffer);
DestroyConstantBuffer(ref _spdConstantsBuffer);
DestroyConstantBuffer(ref _upscalerConstantsBuffer);
_tcrAutogenerateConstants.Destroy();
_generateReactiveConstants.Destroy();
_rcasConstants.Destroy();
_spdConstants.Destroy();
_upscalerConstants.Destroy();
if (_commandBuffer != null) if (_commandBuffer != null)
{ {
@ -132,7 +120,7 @@ namespace FidelityFX.FSR2
} }
} }
public void Dispatch(Fsr2.DispatchDescription dispatchParams)
public void Dispatch(in Fsr2.DispatchDescription dispatchParams)
{ {
_commandBuffer.Clear(); _commandBuffer.Clear();
Dispatch(dispatchParams, _commandBuffer); Dispatch(dispatchParams, _commandBuffer);
@ -141,13 +129,15 @@ namespace FidelityFX.FSR2
public void Dispatch(Fsr2.DispatchDescription dispatchParams, CommandBuffer commandBuffer) public void Dispatch(Fsr2.DispatchDescription dispatchParams, CommandBuffer commandBuffer)
{ {
commandBuffer.BeginSample(_sampler);
if ((_contextDescription.Flags & Fsr2.InitializationFlags.EnableDebugChecking) != 0) if ((_contextDescription.Flags & Fsr2.InitializationFlags.EnableDebugChecking) != 0)
{ {
DebugCheckDispatch(dispatchParams); DebugCheckDispatch(dispatchParams);
} }
if (dispatchParams.UseTextureArrays) if (dispatchParams.UseTextureArrays)
commandBuffer.EnableShaderKeyword("UNITY_FSR_TEXTURE2D_X_ARRAY");
commandBuffer.EnableShaderKeyword("UNITY_FFX_TEXTURE2D_X_ARRAY");
if (_firstExecution) if (_firstExecution)
{ {
@ -157,7 +147,7 @@ namespace FidelityFX.FSR2
commandBuffer.ClearRenderTarget(false, true, Color.clear); commandBuffer.ClearRenderTarget(false, true, Color.clear);
} }
int frameIndex = _resourceFrameIndex % 2;
int bufferIndex = _resourceFrameIndex % 2;
bool resetAccumulation = dispatchParams.Reset || _firstExecution; bool resetAccumulation = dispatchParams.Reset || _firstExecution;
_firstExecution = false; _firstExecution = false;
@ -176,7 +166,7 @@ namespace FidelityFX.FSR2
if (resetAccumulation) if (resetAccumulation)
{ {
RenderTargetIdentifier opaqueOnly = dispatchParams.ColorOpaqueOnly.IsValid ? dispatchParams.ColorOpaqueOnly.RenderTarget : Fsr2ShaderIDs.SrvOpaqueOnly; RenderTargetIdentifier opaqueOnly = dispatchParams.ColorOpaqueOnly.IsValid ? dispatchParams.ColorOpaqueOnly.RenderTarget : Fsr2ShaderIDs.SrvOpaqueOnly;
commandBuffer.Blit(_resources.PrevPreAlpha[frameIndex ^ 1], opaqueOnly);
commandBuffer.Blit(_resources.PrevPreAlpha[bufferIndex ^ 1], opaqueOnly);
} }
} }
else if (_resources.AutoReactive != null) else if (_resources.AutoReactive != null)
@ -187,24 +177,24 @@ namespace FidelityFX.FSR2
if (!dispatchParams.Reactive.IsValid) dispatchParams.Reactive = new ResourceView(_resources.DefaultReactive); if (!dispatchParams.Reactive.IsValid) dispatchParams.Reactive = new ResourceView(_resources.DefaultReactive);
if (!dispatchParams.TransparencyAndComposition.IsValid) dispatchParams.TransparencyAndComposition = new ResourceView(_resources.DefaultReactive); if (!dispatchParams.TransparencyAndComposition.IsValid) dispatchParams.TransparencyAndComposition = new ResourceView(_resources.DefaultReactive);
Fsr2Resources.CreateAliasableResources(commandBuffer, _contextDescription, dispatchParams);
Fsr2Resources.CreateAliasableResources(commandBuffer, _contextDescription);
SetupConstants(dispatchParams, resetAccumulation); SetupConstants(dispatchParams, resetAccumulation);
// Reactive mask bias // Reactive mask bias
const int threadGroupWorkRegionDim = 8; const int threadGroupWorkRegionDim = 8;
int dispatchSrcX = (UpscalerConsts.renderSize.x + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
int dispatchSrcY = (UpscalerConsts.renderSize.y + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
int dispatchSrcX = (_upscalerConstants.Value.renderSize.x + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
int dispatchSrcY = (_upscalerConstants.Value.renderSize.y + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
int dispatchDstX = (_contextDescription.DisplaySize.x + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim; int dispatchDstX = (_contextDescription.DisplaySize.x + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
int dispatchDstY = (_contextDescription.DisplaySize.y + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim; int dispatchDstY = (_contextDescription.DisplaySize.y + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
// Clear reconstructed depth for max depth store // Clear reconstructed depth for max depth store
if (resetAccumulation) if (resetAccumulation)
{ {
commandBuffer.SetRenderTarget(_resources.LockStatus[frameIndex ^ 1]);
commandBuffer.SetRenderTarget(_resources.LockStatus[bufferIndex ^ 1]);
commandBuffer.ClearRenderTarget(false, true, Color.clear); commandBuffer.ClearRenderTarget(false, true, Color.clear);
commandBuffer.SetRenderTarget(_resources.InternalUpscaled[frameIndex ^ 1]);
commandBuffer.SetRenderTarget(_resources.InternalUpscaled[bufferIndex ^ 1]);
commandBuffer.ClearRenderTarget(false, true, Color.clear); commandBuffer.ClearRenderTarget(false, true, Color.clear);
commandBuffer.SetRenderTarget(_resources.SceneLuminance); commandBuffer.SetRenderTarget(_resources.SceneLuminance);
@ -220,7 +210,7 @@ namespace FidelityFX.FSR2
} }
// FSR3: need to clear here since we need the content of this surface for frame interpolation, so clearing in the lock pass is not an option // FSR3: need to clear here since we need the content of this surface for frame interpolation, so clearing in the lock pass is not an option
bool depthInverted = (_contextDescription.Flags & Fsr2.InitializationFlags.EnableDepthInverted) == Fsr2.InitializationFlags.EnableDepthInverted;
bool depthInverted = (_contextDescription.Flags & Fsr2.InitializationFlags.EnableDepthInverted) != 0;
commandBuffer.SetRenderTarget(Fsr2ShaderIDs.UavReconstructedPrevNearestDepth); commandBuffer.SetRenderTarget(Fsr2ShaderIDs.UavReconstructedPrevNearestDepth);
commandBuffer.ClearRenderTarget(false, true, depthInverted ? Color.clear : Color.white); commandBuffer.ClearRenderTarget(false, true, depthInverted ? Color.clear : Color.white);
@ -228,92 +218,95 @@ namespace FidelityFX.FSR2
SetupSpdConstants(dispatchParams, out var dispatchThreadGroupCount); SetupSpdConstants(dispatchParams, out var dispatchThreadGroupCount);
// Initialize constant buffers data // Initialize constant buffers data
commandBuffer.SetBufferData(_upscalerConstantsBuffer, _upscalerConstantsArray);
commandBuffer.SetBufferData(_spdConstantsBuffer, _spdConstantsArray);
_upscalerConstants.UpdateBufferData(commandBuffer);
_spdConstants.UpdateBufferData(commandBuffer);
// Auto reactive // Auto reactive
if (dispatchParams.EnableAutoReactive) if (dispatchParams.EnableAutoReactive)
{ {
GenerateTransparencyCompositionReactive(dispatchParams, commandBuffer, frameIndex);
GenerateTransparencyCompositionReactive(dispatchParams, commandBuffer, bufferIndex);
dispatchParams.Reactive = new ResourceView(_resources.AutoReactive); dispatchParams.Reactive = new ResourceView(_resources.AutoReactive);
dispatchParams.TransparencyAndComposition = new ResourceView(_resources.AutoComposition); dispatchParams.TransparencyAndComposition = new ResourceView(_resources.AutoComposition);
} }
// Compute luminance pyramid // Compute luminance pyramid
_computeLuminancePyramidPass.ScheduleDispatch(commandBuffer, dispatchParams, frameIndex, dispatchThreadGroupCount.x, dispatchThreadGroupCount.y);
_computeLuminancePyramidPass.ScheduleDispatch(commandBuffer, dispatchParams, bufferIndex, dispatchThreadGroupCount.x, dispatchThreadGroupCount.y);
// Reconstruct previous depth // Reconstruct previous depth
_reconstructPreviousDepthPass.ScheduleDispatch(commandBuffer, dispatchParams, frameIndex, dispatchSrcX, dispatchSrcY);
_reconstructPreviousDepthPass.ScheduleDispatch(commandBuffer, dispatchParams, bufferIndex, dispatchSrcX, dispatchSrcY);
// Depth clip // Depth clip
_depthClipPass.ScheduleDispatch(commandBuffer, dispatchParams, frameIndex, dispatchSrcX, dispatchSrcY);
_depthClipPass.ScheduleDispatch(commandBuffer, dispatchParams, bufferIndex, dispatchSrcX, dispatchSrcY);
// Create locks // Create locks
_lockPass.ScheduleDispatch(commandBuffer, dispatchParams, frameIndex, dispatchSrcX, dispatchSrcY);
_lockPass.ScheduleDispatch(commandBuffer, dispatchParams, bufferIndex, dispatchSrcX, dispatchSrcY);
// Accumulate // Accumulate
_accumulatePass.ScheduleDispatch(commandBuffer, dispatchParams, frameIndex, dispatchDstX, dispatchDstY);
_accumulatePass.ScheduleDispatch(commandBuffer, dispatchParams, bufferIndex, dispatchDstX, dispatchDstY);
if (dispatchParams.EnableSharpening) if (dispatchParams.EnableSharpening)
{ {
// Compute the constants // Compute the constants
SetupRcasConstants(dispatchParams); SetupRcasConstants(dispatchParams);
commandBuffer.SetBufferData(_rcasConstantsBuffer, _rcasConstantsArray);
_rcasConstants.UpdateBufferData(commandBuffer);
// Dispatch RCAS // Dispatch RCAS
const int threadGroupWorkRegionDimRcas = 16; const int threadGroupWorkRegionDimRcas = 16;
int threadGroupsX = (Screen.width + threadGroupWorkRegionDimRcas - 1) / threadGroupWorkRegionDimRcas; int threadGroupsX = (Screen.width + threadGroupWorkRegionDimRcas - 1) / threadGroupWorkRegionDimRcas;
int threadGroupsY = (Screen.height + threadGroupWorkRegionDimRcas - 1) / threadGroupWorkRegionDimRcas; int threadGroupsY = (Screen.height + threadGroupWorkRegionDimRcas - 1) / threadGroupWorkRegionDimRcas;
_sharpenPass.ScheduleDispatch(commandBuffer, dispatchParams, frameIndex, threadGroupsX, threadGroupsY);
_sharpenPass.ScheduleDispatch(commandBuffer, dispatchParams, bufferIndex, threadGroupsX, threadGroupsY);
} }
_resourceFrameIndex = (_resourceFrameIndex + 1) % MaxQueuedFrames; _resourceFrameIndex = (_resourceFrameIndex + 1) % MaxQueuedFrames;
Fsr2Resources.DestroyAliasableResources(commandBuffer); Fsr2Resources.DestroyAliasableResources(commandBuffer);
commandBuffer.DisableShaderKeyword("UNITY_FSR_TEXTURE2D_X_ARRAY");
commandBuffer.DisableShaderKeyword("UNITY_FFX_TEXTURE2D_X_ARRAY");
commandBuffer.EndSample(_sampler);
} }
public void GenerateReactiveMask(Fsr2.GenerateReactiveDescription dispatchParams)
public void GenerateReactiveMask(in Fsr2.GenerateReactiveDescription dispatchParams)
{ {
_commandBuffer.Clear(); _commandBuffer.Clear();
GenerateReactiveMask(dispatchParams, _commandBuffer); GenerateReactiveMask(dispatchParams, _commandBuffer);
Graphics.ExecuteCommandBuffer(_commandBuffer); Graphics.ExecuteCommandBuffer(_commandBuffer);
} }
public void GenerateReactiveMask(Fsr2.GenerateReactiveDescription dispatchParams, CommandBuffer commandBuffer)
public void GenerateReactiveMask(in Fsr2.GenerateReactiveDescription dispatchParams, CommandBuffer commandBuffer)
{ {
const int threadGroupWorkRegionDim = 8; const int threadGroupWorkRegionDim = 8;
int dispatchSrcX = (dispatchParams.RenderSize.x + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim; int dispatchSrcX = (dispatchParams.RenderSize.x + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
int dispatchSrcY = (dispatchParams.RenderSize.y + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim; int dispatchSrcY = (dispatchParams.RenderSize.y + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
GenReactiveConsts.scale = dispatchParams.Scale;
GenReactiveConsts.threshold = dispatchParams.CutoffThreshold;
GenReactiveConsts.binaryValue = dispatchParams.BinaryValue;
GenReactiveConsts.flags = (uint)dispatchParams.Flags;
commandBuffer.SetBufferData(_generateReactiveConstantsBuffer, _generateReactiveConstantsArray);
ref var genReactiveConsts = ref _generateReactiveConstants.Value;
genReactiveConsts.scale = dispatchParams.Scale;
genReactiveConsts.threshold = dispatchParams.CutoffThreshold;
genReactiveConsts.binaryValue = dispatchParams.BinaryValue;
genReactiveConsts.flags = (uint)dispatchParams.Flags;
_generateReactiveConstants.UpdateBufferData(commandBuffer);
((Fsr2GenerateReactivePass)_generateReactivePass).ScheduleDispatch(commandBuffer, dispatchParams, dispatchSrcX, dispatchSrcY);
_generateReactivePass.ScheduleDispatch(commandBuffer, dispatchParams, dispatchSrcX, dispatchSrcY);
} }
private void GenerateTransparencyCompositionReactive(Fsr2.DispatchDescription dispatchParams, CommandBuffer commandBuffer, int frameIndex)
private void GenerateTransparencyCompositionReactive(in Fsr2.DispatchDescription dispatchParams, CommandBuffer commandBuffer, int bufferIndex)
{ {
const int threadGroupWorkRegionDim = 8; const int threadGroupWorkRegionDim = 8;
int dispatchSrcX = (dispatchParams.RenderSize.x + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim; int dispatchSrcX = (dispatchParams.RenderSize.x + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
int dispatchSrcY = (dispatchParams.RenderSize.y + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim; int dispatchSrcY = (dispatchParams.RenderSize.y + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
TcrAutoGenConsts.autoTcThreshold = dispatchParams.AutoTcThreshold;
TcrAutoGenConsts.autoTcScale = dispatchParams.AutoTcScale;
TcrAutoGenConsts.autoReactiveScale = dispatchParams.AutoReactiveScale;
TcrAutoGenConsts.autoReactiveMax = dispatchParams.AutoReactiveMax;
commandBuffer.SetBufferData(_tcrAutogenerateConstantsBuffer, _tcrAutogenerateConstantsArray);
ref var tcrAutoGenConsts = ref _tcrAutogenerateConstants.Value;
tcrAutoGenConsts.autoTcThreshold = dispatchParams.AutoTcThreshold;
tcrAutoGenConsts.autoTcScale = dispatchParams.AutoTcScale;
tcrAutoGenConsts.autoReactiveScale = dispatchParams.AutoReactiveScale;
tcrAutoGenConsts.autoReactiveMax = dispatchParams.AutoReactiveMax;
_tcrAutogenerateConstants.UpdateBufferData(commandBuffer);
_tcrAutogeneratePass.ScheduleDispatch(commandBuffer, dispatchParams, frameIndex, dispatchSrcX, dispatchSrcY);
_tcrAutogeneratePass.ScheduleDispatch(commandBuffer, dispatchParams, bufferIndex, dispatchSrcX, dispatchSrcY);
} }
private void SetupConstants(Fsr2.DispatchDescription dispatchParams, bool resetAccumulation)
private void SetupConstants(in Fsr2.DispatchDescription dispatchParams, bool resetAccumulation)
{ {
ref Fsr2.UpscalerConstants constants = ref UpscalerConsts;
ref Fsr2.UpscalerConstants constants = ref _upscalerConstants.Value;
constants.jitterOffset = dispatchParams.JitterOffset; constants.jitterOffset = dispatchParams.JitterOffset;
constants.renderSize = dispatchParams.RenderSize; constants.renderSize = dispatchParams.RenderSize;
@ -327,7 +320,10 @@ namespace FidelityFX.FSR2
constants.viewSpaceToMetersFactor = (dispatchParams.ViewSpaceToMetersFactor > 0.0f) ? dispatchParams.ViewSpaceToMetersFactor : 1.0f; constants.viewSpaceToMetersFactor = (dispatchParams.ViewSpaceToMetersFactor > 0.0f) ? dispatchParams.ViewSpaceToMetersFactor : 1.0f;
// Compute params to enable device depth to view space depth computation in shader // Compute params to enable device depth to view space depth computation in shader
constants.deviceToViewDepth = SetupDeviceDepthToViewSpaceDepthParams(dispatchParams);
bool inverted = (_contextDescription.Flags & Fsr2.InitializationFlags.EnableDepthInverted) != 0;
bool infinite = (_contextDescription.Flags & Fsr2.InitializationFlags.EnableDepthInfinite) != 0;
constants.deviceToViewDepth = FfxUtils.SetupDeviceDepthToViewSpaceDepthParams(
dispatchParams.RenderSize, dispatchParams.CameraNear, dispatchParams.CameraFar, dispatchParams.CameraFovAngleVertical, inverted, infinite);
// To be updated if resource is larger than the actual image size // To be updated if resource is larger than the actual image size
constants.downscaleFactor = new Vector2((float)constants.renderSize.x / _contextDescription.DisplaySize.x, (float)constants.renderSize.y / _contextDescription.DisplaySize.y); constants.downscaleFactor = new Vector2((float)constants.renderSize.x / _contextDescription.DisplaySize.x, (float)constants.renderSize.y / _contextDescription.DisplaySize.y);
@ -345,7 +341,7 @@ namespace FidelityFX.FSR2
_previousJitterOffset = constants.jitterOffset; _previousJitterOffset = constants.jitterOffset;
} }
int jitterPhaseCount = Fsr2.GetJitterPhaseCount(dispatchParams.RenderSize.x, _contextDescription.DisplaySize.x);
int jitterPhaseCount = FfxUtils.GetJitterPhaseCount(dispatchParams.RenderSize.x, _contextDescription.DisplaySize.x);
if (resetAccumulation || constants.jitterPhaseCount == 0) if (resetAccumulation || constants.jitterPhaseCount == 0)
{ {
constants.jitterPhaseCount = jitterPhaseCount; constants.jitterPhaseCount = jitterPhaseCount;
@ -374,79 +370,23 @@ namespace FidelityFX.FSR2
constants.lumaMipDimensions.x = (int)(constants.maxRenderSize.x / mipDiv); constants.lumaMipDimensions.x = (int)(constants.maxRenderSize.x / mipDiv);
constants.lumaMipDimensions.y = (int)(constants.maxRenderSize.y / mipDiv); constants.lumaMipDimensions.y = (int)(constants.maxRenderSize.y / mipDiv);
} }
private Vector4 SetupDeviceDepthToViewSpaceDepthParams(Fsr2.DispatchDescription dispatchParams)
{
bool inverted = (_contextDescription.Flags & Fsr2.InitializationFlags.EnableDepthInverted) != 0;
bool infinite = (_contextDescription.Flags & Fsr2.InitializationFlags.EnableDepthInfinite) != 0;
// make sure it has no impact if near and far plane values are swapped in dispatch params
// the flags "inverted" and "infinite" will decide what transform to use
float min = Mathf.Min(dispatchParams.CameraNear, dispatchParams.CameraFar);
float max = Mathf.Max(dispatchParams.CameraNear, dispatchParams.CameraFar);
if (inverted)
{
(min, max) = (max, min);
}
float q = max / (min - max);
float d = -1.0f;
Vector4 matrixElemC = new Vector4(q, -1.0f - Mathf.Epsilon, q, 0.0f + Mathf.Epsilon);
Vector4 matrixElemE = new Vector4(q * min, -min - Mathf.Epsilon, q * min, max);
// Revert x and y coords
float aspect = (float)dispatchParams.RenderSize.x / dispatchParams.RenderSize.y;
float cotHalfFovY = Mathf.Cos(0.5f * dispatchParams.CameraFovAngleVertical) / Mathf.Sin(0.5f * dispatchParams.CameraFovAngleVertical);
int matrixIndex = (inverted ? 2 : 0) + (infinite ? 1 : 0);
return new Vector4(
d * matrixElemC[matrixIndex],
matrixElemE[matrixIndex],
aspect / cotHalfFovY,
1.0f / cotHalfFovY);
}
private void SetupRcasConstants(Fsr2.DispatchDescription dispatchParams)
private void SetupRcasConstants(in Fsr2.DispatchDescription dispatchParams)
{ {
int sharpnessIndex = Mathf.RoundToInt(Mathf.Clamp01(dispatchParams.Sharpness) * (RcasConfigs.Length - 1)); int sharpnessIndex = Mathf.RoundToInt(Mathf.Clamp01(dispatchParams.Sharpness) * (RcasConfigs.Length - 1));
RcasConsts = RcasConfigs[sharpnessIndex];
_rcasConstants.Value = RcasConfigs[sharpnessIndex];
} }
private void SetupSpdConstants(Fsr2.DispatchDescription dispatchParams, out Vector2Int dispatchThreadGroupCount)
private void SetupSpdConstants(in Fsr2.DispatchDescription dispatchParams, out Vector2Int dispatchThreadGroupCount)
{ {
RectInt rectInfo = new RectInt(0, 0, dispatchParams.RenderSize.x, dispatchParams.RenderSize.y);
SpdSetup(rectInfo, out dispatchThreadGroupCount, out var workGroupOffset, out var numWorkGroupsAndMips);
// Downsample // Downsample
ref Fsr2.SpdConstants spdConstants = ref SpdConsts;
spdConstants.numWorkGroups = (uint)numWorkGroupsAndMips.x;
spdConstants.mips = (uint)numWorkGroupsAndMips.y;
spdConstants.workGroupOffsetX = (uint)workGroupOffset.x;
spdConstants.workGroupOffsetY = (uint)workGroupOffset.y;
ref Fsr2.SpdConstants spdConstants = ref _spdConstants.Value;
FfxSpd.SetupSpdConstants(dispatchParams.RenderSize, ref spdConstants.spd, out dispatchThreadGroupCount);
spdConstants.renderSizeX = (uint)dispatchParams.RenderSize.x; spdConstants.renderSizeX = (uint)dispatchParams.RenderSize.x;
spdConstants.renderSizeY = (uint)dispatchParams.RenderSize.y; spdConstants.renderSizeY = (uint)dispatchParams.RenderSize.y;
} }
private static void SpdSetup(RectInt rectInfo, out Vector2Int dispatchThreadGroupCount, out Vector2Int workGroupOffset, out Vector2Int numWorkGroupsAndMips, int mips = -1)
{
workGroupOffset = new Vector2Int(rectInfo.x / 64, rectInfo.y / 64);
int endIndexX = (rectInfo.x + rectInfo.width - 1) / 64;
int endIndexY = (rectInfo.y + rectInfo.height - 1) / 64;
dispatchThreadGroupCount = new Vector2Int(endIndexX + 1 - workGroupOffset.x, endIndexY + 1 - workGroupOffset.y);
numWorkGroupsAndMips = new Vector2Int(dispatchThreadGroupCount.x * dispatchThreadGroupCount.y, mips);
if (mips < 0)
{
float resolution = Math.Max(rectInfo.width, rectInfo.height);
numWorkGroupsAndMips.y = Math.Min(Mathf.FloorToInt(Mathf.Log(resolution, 2.0f)), 12);
}
}
private void DebugCheckDispatch(Fsr2.DispatchDescription dispatchParams)
private void DebugCheckDispatch(in Fsr2.DispatchDescription dispatchParams)
{ {
if (!dispatchParams.Color.IsValid) if (!dispatchParams.Color.IsValid)
{ {
@ -591,28 +531,5 @@ namespace FidelityFX.FSR2
new Fsr2.RcasConstants(1064229695u, 997604214u), new Fsr2.RcasConstants(1064229695u, 997604214u),
new Fsr2.RcasConstants(1065353216u, 1006648320), new Fsr2.RcasConstants(1065353216u, 1006648320),
}; };
private static ComputeBuffer CreateConstantBuffer<TConstants>() where TConstants: struct
{
return new ComputeBuffer(1, Marshal.SizeOf<TConstants>(), ComputeBufferType.Constant);
}
private static void DestroyConstantBuffer(ref ComputeBuffer bufferRef)
{
if (bufferRef == null)
return;
bufferRef.Release();
bufferRef = null;
}
private static void DestroyPass(ref Fsr2Pass pass)
{
if (pass == null)
return;
pass.Dispose();
pass = null;
}
} }
} }

267
Runtime/FSR2/Fsr2Pass.cs

@ -18,10 +18,7 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. // THE SOFTWARE.
using System;
using System.Runtime.InteropServices;
using UnityEngine; using UnityEngine;
using UnityEngine.Profiling;
using UnityEngine.Rendering; using UnityEngine.Rendering;
namespace FidelityFX.FSR2 namespace FidelityFX.FSR2
@ -31,55 +28,32 @@ namespace FidelityFX.FSR2
/// This loosely matches the FfxPipelineState struct from the original FSR2 codebase, wrapped in an object-oriented blanket. /// This loosely matches the FfxPipelineState struct from the original FSR2 codebase, wrapped in an object-oriented blanket.
/// These classes are responsible for loading compute shaders, managing temporary resources, binding resources to shader kernels and dispatching said shaders. /// These classes are responsible for loading compute shaders, managing temporary resources, binding resources to shader kernels and dispatching said shaders.
/// </summary> /// </summary>
internal abstract class Fsr2Pass: IDisposable
internal abstract class Fsr2Pass: FfxPassWithFlags<Fsr2.InitializationFlags>
{ {
internal const int ShadingChangeMipLevel = 4; // This matches the FFX_FSR2_SHADING_CHANGE_MIP_LEVEL define internal const int ShadingChangeMipLevel = 4; // This matches the FFX_FSR2_SHADING_CHANGE_MIP_LEVEL define
protected readonly Fsr2.ContextDescription ContextDescription;
protected readonly Fsr2Resources Resources; protected readonly Fsr2Resources Resources;
protected readonly ComputeBuffer Constants; protected readonly ComputeBuffer Constants;
protected ComputeShader ComputeShader;
protected int KernelIndex;
protected CustomSampler Sampler;
protected Fsr2Pass(Fsr2.ContextDescription contextDescription, Fsr2Resources resources, ComputeBuffer constants)
protected Fsr2Pass(in Fsr2.ContextDescription contextDescription, Fsr2Resources resources, ComputeBuffer constants)
: base("FSR2", contextDescription.Flags)
{ {
ContextDescription = contextDescription;
Resources = resources; Resources = resources;
Constants = constants; Constants = constants;
} }
public virtual void Dispose()
{
}
public void ScheduleDispatch(CommandBuffer commandBuffer, Fsr2.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY)
public void ScheduleDispatch(CommandBuffer commandBuffer, in Fsr2.DispatchDescription dispatchParams, int bufferIndex, int dispatchX, int dispatchY, int dispatchZ = 1)
{ {
commandBuffer.BeginSample(Sampler);
DoScheduleDispatch(commandBuffer, dispatchParams, frameIndex, dispatchX, dispatchY);
commandBuffer.EndSample(Sampler);
using (ProfilerSample(commandBuffer))
{
Dispatch(commandBuffer, dispatchParams, bufferIndex, dispatchX, dispatchY, dispatchZ);
}
} }
protected abstract void DoScheduleDispatch(CommandBuffer commandBuffer, Fsr2.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY);
protected void InitComputeShader(string passName, ComputeShader shader)
{
InitComputeShader(passName, shader, ContextDescription.Flags);
}
protected abstract void Dispatch(CommandBuffer commandBuffer, in Fsr2.DispatchDescription dispatchParams, int bufferIndex, int dispatchX, int dispatchY, int dispatchZ);
private void InitComputeShader(string passName, ComputeShader shader, Fsr2.InitializationFlags flags)
protected override void SetupShaderKeywords()
{ {
if (shader == null)
{
throw new MissingReferenceException($"Shader for FSR2 pass '{passName}' could not be loaded! Please ensure it is included in the project correctly.");
}
ComputeShader = shader;
KernelIndex = ComputeShader.FindKernel("CS");
Sampler = CustomSampler.Create(passName);
bool useLut = false; bool useLut = false;
#if UNITY_2022_1_OR_NEWER // This will also work in 2020.3.43+ and 2021.3.14+ #if UNITY_2022_1_OR_NEWER // This will also work in 2020.3.43+ and 2021.3.14+
if (SystemInfo.computeSubGroupSize == 64) if (SystemInfo.computeSubGroupSize == 64)
@ -89,20 +63,20 @@ namespace FidelityFX.FSR2
#endif #endif
// This matches the permutation rules from the CreatePipeline* functions // This matches the permutation rules from the CreatePipeline* functions
if ((flags & Fsr2.InitializationFlags.EnableHighDynamicRange) != 0) ComputeShader.EnableKeyword("FFX_FSR2_OPTION_HDR_COLOR_INPUT");
if ((flags & Fsr2.InitializationFlags.EnableDisplayResolutionMotionVectors) == 0) ComputeShader.EnableKeyword("FFX_FSR2_OPTION_LOW_RESOLUTION_MOTION_VECTORS");
if ((flags & Fsr2.InitializationFlags.EnableMotionVectorsJitterCancellation) != 0) ComputeShader.EnableKeyword("FFX_FSR2_OPTION_JITTERED_MOTION_VECTORS");
if ((flags & Fsr2.InitializationFlags.EnableDepthInverted) != 0) ComputeShader.EnableKeyword("FFX_FSR2_OPTION_INVERTED_DEPTH");
if ((Flags & Fsr2.InitializationFlags.EnableHighDynamicRange) != 0) ComputeShader.EnableKeyword("FFX_FSR2_OPTION_HDR_COLOR_INPUT");
if ((Flags & Fsr2.InitializationFlags.EnableDisplayResolutionMotionVectors) == 0) ComputeShader.EnableKeyword("FFX_FSR2_OPTION_LOW_RESOLUTION_MOTION_VECTORS");
if ((Flags & Fsr2.InitializationFlags.EnableMotionVectorsJitterCancellation) != 0) ComputeShader.EnableKeyword("FFX_FSR2_OPTION_JITTERED_MOTION_VECTORS");
if ((Flags & Fsr2.InitializationFlags.EnableDepthInverted) != 0) ComputeShader.EnableKeyword("FFX_FSR2_OPTION_INVERTED_DEPTH");
if (useLut) ComputeShader.EnableKeyword("FFX_FSR2_OPTION_REPROJECT_USE_LANCZOS_TYPE"); if (useLut) ComputeShader.EnableKeyword("FFX_FSR2_OPTION_REPROJECT_USE_LANCZOS_TYPE");
if ((flags & Fsr2.InitializationFlags.EnableFP16Usage) != 0) ComputeShader.EnableKeyword("FFX_HALF");
if ((Flags & Fsr2.InitializationFlags.EnableFP16Usage) != 0) ComputeShader.EnableKeyword("FFX_HALF");
} }
} }
internal class Fsr2ComputeLuminancePyramidPass : Fsr2Pass
internal sealed class Fsr2ComputeLuminancePyramidPass : Fsr2Pass
{ {
private readonly ComputeBuffer _spdConstants; private readonly ComputeBuffer _spdConstants;
public Fsr2ComputeLuminancePyramidPass(Fsr2.ContextDescription contextDescription, Fsr2Resources resources, ComputeBuffer constants, ComputeBuffer spdConstants)
public Fsr2ComputeLuminancePyramidPass(in Fsr2.ContextDescription contextDescription, Fsr2Resources resources, ComputeBuffer constants, ComputeBuffer spdConstants)
: base(contextDescription, resources, constants) : base(contextDescription, resources, constants)
{ {
_spdConstants = spdConstants; _spdConstants = spdConstants;
@ -110,104 +84,91 @@ namespace FidelityFX.FSR2
InitComputeShader("Compute Luminance Pyramid", contextDescription.Shaders.computeLuminancePyramidPass); InitComputeShader("Compute Luminance Pyramid", contextDescription.Shaders.computeLuminancePyramidPass);
} }
protected override void DoScheduleDispatch(CommandBuffer commandBuffer, Fsr2.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY)
protected override void Dispatch(CommandBuffer commandBuffer, in Fsr2.DispatchDescription dispatchParams, int bufferIndex, int dispatchX, int dispatchY, int dispatchZ)
{ {
ref var color = ref dispatchParams.Color;
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputColor, color.RenderTarget, color.MipLevel, color.SubElement);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputColor, dispatchParams.Color);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavSpdAtomicCount, Resources.SpdAtomicCounter); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavSpdAtomicCount, Resources.SpdAtomicCounter);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavExposureMipLumaChange, Resources.SceneLuminance, ShadingChangeMipLevel);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavExposureMip5, Resources.SceneLuminance, 5);
commandBuffer.SetComputeTextureMipParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavExposureMipLumaChange, Resources.SceneLuminance, ShadingChangeMipLevel);
commandBuffer.SetComputeTextureMipParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavExposureMip5, Resources.SceneLuminance, 5);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavAutoExposure, Resources.AutoExposure); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavAutoExposure, Resources.AutoExposure);
commandBuffer.SetComputeConstantBufferParam(ComputeShader, Fsr2ShaderIDs.CbFsr2, Constants, 0, Marshal.SizeOf<Fsr2.UpscalerConstants>());
commandBuffer.SetComputeConstantBufferParam(ComputeShader, Fsr2ShaderIDs.CbSpd, _spdConstants, 0, Marshal.SizeOf<Fsr2.SpdConstants>());
commandBuffer.SetComputeConstantBufferParam<Fsr2.UpscalerConstants>(ComputeShader, Fsr2ShaderIDs.CbFsr2, Constants);
commandBuffer.SetComputeConstantBufferParam<Fsr2.SpdConstants>(ComputeShader, Fsr2ShaderIDs.CbSpd, _spdConstants);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, 1);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, dispatchZ);
} }
} }
internal class Fsr2ReconstructPreviousDepthPass : Fsr2Pass
internal sealed class Fsr2ReconstructPreviousDepthPass : Fsr2Pass
{ {
public Fsr2ReconstructPreviousDepthPass(Fsr2.ContextDescription contextDescription, Fsr2Resources resources, ComputeBuffer constants)
public Fsr2ReconstructPreviousDepthPass(in Fsr2.ContextDescription contextDescription, Fsr2Resources resources, ComputeBuffer constants)
: base(contextDescription, resources, constants) : base(contextDescription, resources, constants)
{ {
InitComputeShader("Reconstruct & Dilate", contextDescription.Shaders.reconstructPreviousDepthPass); InitComputeShader("Reconstruct & Dilate", contextDescription.Shaders.reconstructPreviousDepthPass);
} }
protected override void DoScheduleDispatch(CommandBuffer commandBuffer, Fsr2.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY)
protected override void Dispatch(CommandBuffer commandBuffer, in Fsr2.DispatchDescription dispatchParams, int bufferIndex, int dispatchX, int dispatchY, int dispatchZ)
{ {
ref var color = ref dispatchParams.Color;
ref var depth = ref dispatchParams.Depth;
ref var motionVectors = ref dispatchParams.MotionVectors;
ref var exposure = ref dispatchParams.Exposure;
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputColor, color.RenderTarget, color.MipLevel, color.SubElement);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputDepth, depth.RenderTarget, depth.MipLevel, depth.SubElement);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputMotionVectors, motionVectors.RenderTarget, motionVectors.MipLevel, motionVectors.SubElement);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputExposure, exposure.RenderTarget, exposure.MipLevel, exposure.SubElement);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputColor, dispatchParams.Color);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputDepth, dispatchParams.Depth);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputMotionVectors, dispatchParams.MotionVectors);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputExposure, dispatchParams.Exposure);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavDilatedMotionVectors, Resources.DilatedMotionVectors[frameIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavDilatedMotionVectors, Resources.DilatedMotionVectors[bufferIndex]);
commandBuffer.SetComputeConstantBufferParam(ComputeShader, Fsr2ShaderIDs.CbFsr2, Constants, 0, Marshal.SizeOf<Fsr2.UpscalerConstants>());
commandBuffer.SetComputeConstantBufferParam<Fsr2.UpscalerConstants>(ComputeShader, Fsr2ShaderIDs.CbFsr2, Constants);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, 1);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, dispatchZ);
} }
} }
internal class Fsr2DepthClipPass : Fsr2Pass
internal sealed class Fsr2DepthClipPass : Fsr2Pass
{ {
public Fsr2DepthClipPass(Fsr2.ContextDescription contextDescription, Fsr2Resources resources, ComputeBuffer constants)
public Fsr2DepthClipPass(in Fsr2.ContextDescription contextDescription, Fsr2Resources resources, ComputeBuffer constants)
: base(contextDescription, resources, constants) : base(contextDescription, resources, constants)
{ {
InitComputeShader("Depth Clip", contextDescription.Shaders.depthClipPass); InitComputeShader("Depth Clip", contextDescription.Shaders.depthClipPass);
} }
protected override void DoScheduleDispatch(CommandBuffer commandBuffer, Fsr2.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY)
protected override void Dispatch(CommandBuffer commandBuffer, in Fsr2.DispatchDescription dispatchParams, int bufferIndex, int dispatchX, int dispatchY, int dispatchZ)
{ {
ref var color = ref dispatchParams.Color;
ref var depth = ref dispatchParams.Depth;
ref var motionVectors = ref dispatchParams.MotionVectors;
ref var exposure = ref dispatchParams.Exposure;
ref var reactive = ref dispatchParams.Reactive;
ref var tac = ref dispatchParams.TransparencyAndComposition;
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputColor, color.RenderTarget, color.MipLevel, color.SubElement);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputDepth, depth.RenderTarget, depth.MipLevel, depth.SubElement);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputMotionVectors, motionVectors.RenderTarget, motionVectors.MipLevel, motionVectors.SubElement);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputExposure, exposure.RenderTarget, exposure.MipLevel, exposure.SubElement);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvReactiveMask, reactive.RenderTarget, reactive.MipLevel, reactive.SubElement);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvTransparencyAndCompositionMask, tac.RenderTarget, tac.MipLevel, tac.SubElement);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputColor, dispatchParams.Color);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputDepth, dispatchParams.Depth);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputMotionVectors, dispatchParams.MotionVectors);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputExposure, dispatchParams.Exposure);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvReactiveMask, dispatchParams.Reactive);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvTransparencyAndCompositionMask, dispatchParams.TransparencyAndComposition);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvReconstructedPrevNearestDepth, Fsr2ShaderIDs.UavReconstructedPrevNearestDepth); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvReconstructedPrevNearestDepth, Fsr2ShaderIDs.UavReconstructedPrevNearestDepth);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvDilatedMotionVectors, Resources.DilatedMotionVectors[frameIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvDilatedMotionVectors, Resources.DilatedMotionVectors[bufferIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvDilatedDepth, Fsr2ShaderIDs.UavDilatedDepth); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvDilatedDepth, Fsr2ShaderIDs.UavDilatedDepth);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvPrevDilatedMotionVectors, Resources.DilatedMotionVectors[frameIndex ^ 1]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvPrevDilatedMotionVectors, Resources.DilatedMotionVectors[bufferIndex ^ 1]);
commandBuffer.SetComputeConstantBufferParam(ComputeShader, Fsr2ShaderIDs.CbFsr2, Constants, 0, Marshal.SizeOf<Fsr2.UpscalerConstants>());
commandBuffer.SetComputeConstantBufferParam<Fsr2.UpscalerConstants>(ComputeShader, Fsr2ShaderIDs.CbFsr2, Constants);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, 1);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, dispatchZ);
} }
} }
internal class Fsr2LockPass : Fsr2Pass
internal sealed class Fsr2LockPass : Fsr2Pass
{ {
public Fsr2LockPass(Fsr2.ContextDescription contextDescription, Fsr2Resources resources, ComputeBuffer constants)
public Fsr2LockPass(in Fsr2.ContextDescription contextDescription, Fsr2Resources resources, ComputeBuffer constants)
: base(contextDescription, resources, constants) : base(contextDescription, resources, constants)
{ {
InitComputeShader("Create Locks", contextDescription.Shaders.lockPass); InitComputeShader("Create Locks", contextDescription.Shaders.lockPass);
} }
protected override void DoScheduleDispatch(CommandBuffer commandBuffer, Fsr2.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY)
protected override void Dispatch(CommandBuffer commandBuffer, in Fsr2.DispatchDescription dispatchParams, int bufferIndex, int dispatchX, int dispatchY, int dispatchZ)
{ {
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvLockInputLuma, Fsr2ShaderIDs.UavLockInputLuma); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvLockInputLuma, Fsr2ShaderIDs.UavLockInputLuma);
commandBuffer.SetComputeConstantBufferParam(ComputeShader, Fsr2ShaderIDs.CbFsr2, Constants, 0, Marshal.SizeOf<Fsr2.UpscalerConstants>());
commandBuffer.SetComputeConstantBufferParam<Fsr2.UpscalerConstants>(ComputeShader, Fsr2ShaderIDs.CbFsr2, Constants);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, 1);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, dispatchZ);
} }
} }
internal class Fsr2AccumulatePass : Fsr2Pass
internal sealed class Fsr2AccumulatePass : Fsr2Pass
{ {
private const string SharpeningKeyword = "FFX_FSR2_OPTION_APPLY_SHARPENING"; private const string SharpeningKeyword = "FFX_FSR2_OPTION_APPLY_SHARPENING";
@ -215,7 +176,7 @@ namespace FidelityFX.FSR2
private readonly LocalKeyword _sharpeningKeyword; private readonly LocalKeyword _sharpeningKeyword;
#endif #endif
public Fsr2AccumulatePass(Fsr2.ContextDescription contextDescription, Fsr2Resources resources, ComputeBuffer constants)
public Fsr2AccumulatePass(in Fsr2.ContextDescription contextDescription, Fsr2Resources resources, ComputeBuffer constants)
: base(contextDescription, resources, constants) : base(contextDescription, resources, constants)
{ {
InitComputeShader("Reproject & Accumulate", contextDescription.Shaders.accumulatePass); InitComputeShader("Reproject & Accumulate", contextDescription.Shaders.accumulatePass);
@ -224,7 +185,7 @@ namespace FidelityFX.FSR2
#endif #endif
} }
protected override void DoScheduleDispatch(CommandBuffer commandBuffer, Fsr2.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY)
protected override void Dispatch(CommandBuffer commandBuffer, in Fsr2.DispatchDescription dispatchParams, int bufferIndex, int dispatchX, int dispatchY, int dispatchZ)
{ {
#if UNITY_2021_2_OR_NEWER #if UNITY_2021_2_OR_NEWER
if (dispatchParams.EnableSharpening) if (dispatchParams.EnableSharpening)
@ -238,47 +199,44 @@ namespace FidelityFX.FSR2
commandBuffer.DisableShaderKeyword(SharpeningKeyword); commandBuffer.DisableShaderKeyword(SharpeningKeyword);
#endif #endif
if ((ContextDescription.Flags & Fsr2.InitializationFlags.EnableDisplayResolutionMotionVectors) == 0)
if ((Flags & Fsr2.InitializationFlags.EnableDisplayResolutionMotionVectors) == 0)
{ {
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvDilatedMotionVectors, Resources.DilatedMotionVectors[frameIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvDilatedMotionVectors, Resources.DilatedMotionVectors[bufferIndex]);
} }
else else
{ {
ref var motionVectors = ref dispatchParams.MotionVectors;
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputMotionVectors, motionVectors.RenderTarget, motionVectors.MipLevel, motionVectors.SubElement);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputMotionVectors, dispatchParams.MotionVectors);
} }
ref var exposure = ref dispatchParams.Exposure;
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputExposure, exposure.RenderTarget, exposure.MipLevel, exposure.SubElement);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputExposure, dispatchParams.Exposure);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvDilatedReactiveMasks, Fsr2ShaderIDs.UavDilatedReactiveMasks); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvDilatedReactiveMasks, Fsr2ShaderIDs.UavDilatedReactiveMasks);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInternalUpscaled, Resources.InternalUpscaled[frameIndex ^ 1]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvLockStatus, Resources.LockStatus[frameIndex ^ 1]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInternalUpscaled, Resources.InternalUpscaled[bufferIndex ^ 1]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvLockStatus, Resources.LockStatus[bufferIndex ^ 1]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvPreparedInputColor, Fsr2ShaderIDs.UavPreparedInputColor); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvPreparedInputColor, Fsr2ShaderIDs.UavPreparedInputColor);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvLanczosLut, Resources.LanczosLut); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvLanczosLut, Resources.LanczosLut);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvUpscaleMaximumBiasLut, Resources.MaximumBiasLut); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvUpscaleMaximumBiasLut, Resources.MaximumBiasLut);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvSceneLuminanceMips, Resources.SceneLuminance); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvSceneLuminanceMips, Resources.SceneLuminance);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvAutoExposure, Resources.AutoExposure); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvAutoExposure, Resources.AutoExposure);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvLumaHistory, Resources.LumaHistory[frameIndex ^ 1]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvLumaHistory, Resources.LumaHistory[bufferIndex ^ 1]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavInternalUpscaled, Resources.InternalUpscaled[frameIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavLockStatus, Resources.LockStatus[frameIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavLumaHistory, Resources.LumaHistory[frameIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavInternalUpscaled, Resources.InternalUpscaled[bufferIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavLockStatus, Resources.LockStatus[bufferIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavLumaHistory, Resources.LumaHistory[bufferIndex]);
ref var output = ref dispatchParams.Output;
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavUpscaledOutput, output.RenderTarget, output.MipLevel, output.SubElement);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavUpscaledOutput, dispatchParams.Output);
commandBuffer.SetComputeConstantBufferParam(ComputeShader, Fsr2ShaderIDs.CbFsr2, Constants, 0, Marshal.SizeOf<Fsr2.UpscalerConstants>());
commandBuffer.SetComputeConstantBufferParam<Fsr2.UpscalerConstants>(ComputeShader, Fsr2ShaderIDs.CbFsr2, Constants);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, 1);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, dispatchZ);
} }
} }
internal class Fsr2SharpenPass : Fsr2Pass
internal sealed class Fsr2SharpenPass : Fsr2Pass
{ {
private readonly ComputeBuffer _rcasConstants; private readonly ComputeBuffer _rcasConstants;
public Fsr2SharpenPass(Fsr2.ContextDescription contextDescription, Fsr2Resources resources, ComputeBuffer constants, ComputeBuffer rcasConstants)
public Fsr2SharpenPass(in Fsr2.ContextDescription contextDescription, Fsr2Resources resources, ComputeBuffer constants, ComputeBuffer rcasConstants)
: base(contextDescription, resources, constants) : base(contextDescription, resources, constants)
{ {
_rcasConstants = rcasConstants; _rcasConstants = rcasConstants;
@ -286,27 +244,25 @@ namespace FidelityFX.FSR2
InitComputeShader("RCAS Sharpening", contextDescription.Shaders.sharpenPass); InitComputeShader("RCAS Sharpening", contextDescription.Shaders.sharpenPass);
} }
protected override void DoScheduleDispatch(CommandBuffer commandBuffer, Fsr2.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY)
protected override void Dispatch(CommandBuffer commandBuffer, in Fsr2.DispatchDescription dispatchParams, int bufferIndex, int dispatchX, int dispatchY, int dispatchZ)
{ {
ref var exposure = ref dispatchParams.Exposure;
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputExposure, exposure.RenderTarget, exposure.MipLevel, exposure.SubElement);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvRcasInput, Resources.InternalUpscaled[frameIndex]);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputExposure, dispatchParams.Exposure);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvRcasInput, Resources.InternalUpscaled[bufferIndex]);
ref var output = ref dispatchParams.Output;
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavUpscaledOutput, output.RenderTarget, output.MipLevel, output.SubElement);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavUpscaledOutput, dispatchParams.Output);
commandBuffer.SetComputeConstantBufferParam(ComputeShader, Fsr2ShaderIDs.CbFsr2, Constants, 0, Marshal.SizeOf<Fsr2.UpscalerConstants>());
commandBuffer.SetComputeConstantBufferParam(ComputeShader, Fsr2ShaderIDs.CbRcas, _rcasConstants, 0, Marshal.SizeOf<Fsr2.RcasConstants>());
commandBuffer.SetComputeConstantBufferParam<Fsr2.UpscalerConstants>(ComputeShader, Fsr2ShaderIDs.CbFsr2, Constants);
commandBuffer.SetComputeConstantBufferParam<Fsr2.RcasConstants>(ComputeShader, Fsr2ShaderIDs.CbRcas, _rcasConstants);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, 1);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, dispatchZ);
} }
} }
internal class Fsr2GenerateReactivePass : Fsr2Pass
internal sealed class Fsr2GenerateReactivePass : Fsr2Pass
{ {
private readonly ComputeBuffer _generateReactiveConstants; private readonly ComputeBuffer _generateReactiveConstants;
public Fsr2GenerateReactivePass(Fsr2.ContextDescription contextDescription, Fsr2Resources resources, ComputeBuffer generateReactiveConstants)
public Fsr2GenerateReactivePass(in Fsr2.ContextDescription contextDescription, Fsr2Resources resources, ComputeBuffer generateReactiveConstants)
: base(contextDescription, resources, null) : base(contextDescription, resources, null)
{ {
_generateReactiveConstants = generateReactiveConstants; _generateReactiveConstants = generateReactiveConstants;
@ -314,35 +270,30 @@ namespace FidelityFX.FSR2
InitComputeShader("Auto-Generate Reactive Mask", contextDescription.Shaders.autoGenReactivePass); InitComputeShader("Auto-Generate Reactive Mask", contextDescription.Shaders.autoGenReactivePass);
} }
protected override void DoScheduleDispatch(CommandBuffer commandBuffer, Fsr2.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY)
protected override void Dispatch(CommandBuffer commandBuffer, in Fsr2.DispatchDescription dispatchParams, int bufferIndex, int dispatchX, int dispatchY, int dispatchZ)
{ {
} }
public void ScheduleDispatch(CommandBuffer commandBuffer, Fsr2.GenerateReactiveDescription dispatchParams, int dispatchX, int dispatchY)
public void ScheduleDispatch(CommandBuffer commandBuffer, in Fsr2.GenerateReactiveDescription dispatchParams, int dispatchX, int dispatchY)
{ {
commandBuffer.BeginSample(Sampler);
ref var opaqueOnly = ref dispatchParams.ColorOpaqueOnly;
ref var color = ref dispatchParams.ColorPreUpscale;
ref var reactive = ref dispatchParams.OutReactive;
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvOpaqueOnly, opaqueOnly.RenderTarget, opaqueOnly.MipLevel, opaqueOnly.SubElement);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputColor, color.RenderTarget, color.MipLevel, color.SubElement);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavAutoReactive, reactive.RenderTarget, reactive.MipLevel, reactive.SubElement);
commandBuffer.SetComputeConstantBufferParam(ComputeShader, Fsr2ShaderIDs.CbGenReactive, _generateReactiveConstants, 0, Marshal.SizeOf<Fsr2.GenerateReactiveConstants>());
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, 1);
commandBuffer.EndSample(Sampler);
using (ProfilerSample(commandBuffer))
{
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvOpaqueOnly, dispatchParams.ColorOpaqueOnly);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputColor, dispatchParams.ColorPreUpscale);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavAutoReactive, dispatchParams.OutReactive);
commandBuffer.SetComputeConstantBufferParam<Fsr2.GenerateReactiveConstants>(ComputeShader, Fsr2ShaderIDs.CbGenReactive, _generateReactiveConstants);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, 1);
}
} }
} }
internal class Fsr2TcrAutogeneratePass : Fsr2Pass
internal sealed class Fsr2TcrAutogeneratePass : Fsr2Pass
{ {
private readonly ComputeBuffer _tcrAutogenerateConstants; private readonly ComputeBuffer _tcrAutogenerateConstants;
public Fsr2TcrAutogeneratePass(Fsr2.ContextDescription contextDescription, Fsr2Resources resources, ComputeBuffer constants, ComputeBuffer tcrAutogenerateConstants)
public Fsr2TcrAutogeneratePass(in Fsr2.ContextDescription contextDescription, Fsr2Resources resources, ComputeBuffer constants, ComputeBuffer tcrAutogenerateConstants)
: base(contextDescription, resources, constants) : base(contextDescription, resources, constants)
{ {
_tcrAutogenerateConstants = tcrAutogenerateConstants; _tcrAutogenerateConstants = tcrAutogenerateConstants;
@ -350,31 +301,25 @@ namespace FidelityFX.FSR2
InitComputeShader("Auto-Generate Transparency & Composition Mask", contextDescription.Shaders.tcrAutoGenPass); InitComputeShader("Auto-Generate Transparency & Composition Mask", contextDescription.Shaders.tcrAutoGenPass);
} }
protected override void DoScheduleDispatch(CommandBuffer commandBuffer, Fsr2.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY)
protected override void Dispatch(CommandBuffer commandBuffer, in Fsr2.DispatchDescription dispatchParams, int bufferIndex, int dispatchX, int dispatchY, int dispatchZ)
{ {
ref var color = ref dispatchParams.Color;
ref var motionVectors = ref dispatchParams.MotionVectors;
ref var opaqueOnly = ref dispatchParams.ColorOpaqueOnly;
ref var reactive = ref dispatchParams.Reactive;
ref var tac = ref dispatchParams.TransparencyAndComposition;
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvOpaqueOnly, opaqueOnly.RenderTarget, opaqueOnly.MipLevel, opaqueOnly.SubElement);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputColor, color.RenderTarget, color.MipLevel, color.SubElement);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputMotionVectors, motionVectors.RenderTarget, motionVectors.MipLevel, motionVectors.SubElement);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvPrevColorPreAlpha, Resources.PrevPreAlpha[frameIndex ^ 1]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvPrevColorPostAlpha, Resources.PrevPostAlpha[frameIndex ^ 1]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvReactiveMask, reactive.RenderTarget, reactive.MipLevel, reactive.SubElement);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvTransparencyAndCompositionMask, tac.RenderTarget, tac.MipLevel, tac.SubElement);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvOpaqueOnly, dispatchParams.ColorOpaqueOnly);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputColor, dispatchParams.Color);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputMotionVectors, dispatchParams.MotionVectors);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvPrevColorPreAlpha, Resources.PrevPreAlpha[bufferIndex ^ 1]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvPrevColorPostAlpha, Resources.PrevPostAlpha[bufferIndex ^ 1]);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvReactiveMask, dispatchParams.Reactive);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvTransparencyAndCompositionMask, dispatchParams.TransparencyAndComposition);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavAutoReactive, Resources.AutoReactive); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavAutoReactive, Resources.AutoReactive);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavAutoComposition, Resources.AutoComposition); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavAutoComposition, Resources.AutoComposition);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavPrevColorPreAlpha, Resources.PrevPreAlpha[frameIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavPrevColorPostAlpha, Resources.PrevPostAlpha[frameIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavPrevColorPreAlpha, Resources.PrevPreAlpha[bufferIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavPrevColorPostAlpha, Resources.PrevPostAlpha[bufferIndex]);
commandBuffer.SetComputeConstantBufferParam(ComputeShader, Fsr2ShaderIDs.CbFsr2, Constants, 0, Marshal.SizeOf<Fsr2.UpscalerConstants>());
commandBuffer.SetComputeConstantBufferParam(ComputeShader, Fsr2ShaderIDs.CbGenReactive, _tcrAutogenerateConstants, 0, Marshal.SizeOf<Fsr2.GenerateReactiveConstants2>());
commandBuffer.SetComputeConstantBufferParam<Fsr2.UpscalerConstants>(ComputeShader, Fsr2ShaderIDs.CbFsr2, Constants);
commandBuffer.SetComputeConstantBufferParam<Fsr2.GenerateReactiveConstants2>(ComputeShader, Fsr2ShaderIDs.CbGenReactive, _tcrAutogenerateConstants);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, 1);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, dispatchZ);
} }
} }
} }

89
Runtime/FSR2/Fsr2Resources.cs

@ -29,7 +29,7 @@ namespace FidelityFX.FSR2
/// Helper class for bundling and managing persistent resources required by the FSR2 process. /// Helper class for bundling and managing persistent resources required by the FSR2 process.
/// This includes lookup tables, default fallback resources and double-buffered resources that get swapped between frames. /// This includes lookup tables, default fallback resources and double-buffered resources that get swapped between frames.
/// </summary> /// </summary>
internal class Fsr2Resources
internal class Fsr2Resources: FfxResourcesBase
{ {
public Texture2D DefaultExposure; public Texture2D DefaultExposure;
public Texture2D DefaultReactive; public Texture2D DefaultReactive;
@ -47,17 +47,11 @@ namespace FidelityFX.FSR2
public readonly RenderTexture[] PrevPreAlpha = new RenderTexture[2]; public readonly RenderTexture[] PrevPreAlpha = new RenderTexture[2];
public readonly RenderTexture[] PrevPostAlpha = new RenderTexture[2]; public readonly RenderTexture[] PrevPostAlpha = new RenderTexture[2];
public void Create(Fsr2.ContextDescription contextDescription)
public void Create(in Fsr2.ContextDescription contextDescription)
{ {
// Generate the data for the LUT // Generate the data for the LUT
const int lanczos2LutWidth = 128; const int lanczos2LutWidth = 128;
float[] lanczos2Weights = new float[lanczos2LutWidth];
for (int currentLanczosWidthIndex = 0; currentLanczosWidthIndex < lanczos2LutWidth; ++currentLanczosWidthIndex)
{
float x = 2.0f * currentLanczosWidthIndex / (lanczos2LutWidth - 1);
float y = Fsr2.Lanczos2(x);
lanczos2Weights[currentLanczosWidthIndex] = y;
}
float[] lanczos2Weights = FfxUtils.GenerateLanczos2Table(lanczos2LutWidth);
float[] maximumBias = new float[MaximumBiasTextureWidth * MaximumBiasTextureHeight]; float[] maximumBias = new float[MaximumBiasTextureWidth * MaximumBiasTextureHeight];
for (int i = 0; i < maximumBias.Length; ++i) for (int i = 0; i < maximumBias.Length; ++i)
@ -67,40 +61,27 @@ namespace FidelityFX.FSR2
// Resource FSR2_LanczosLutData: FFX_RESOURCE_USAGE_READ_ONLY, FFX_SURFACE_FORMAT_R16_SNORM, FFX_RESOURCE_FLAGS_NONE // Resource FSR2_LanczosLutData: FFX_RESOURCE_USAGE_READ_ONLY, FFX_SURFACE_FORMAT_R16_SNORM, FFX_RESOURCE_FLAGS_NONE
// R16_SNorm textures are not supported by Unity on most platforms, strangely enough. So instead we use R32_SFloat and upload pre-normalized float data. // R16_SNorm textures are not supported by Unity on most platforms, strangely enough. So instead we use R32_SFloat and upload pre-normalized float data.
LanczosLut = new Texture2D(lanczos2LutWidth, 1, GraphicsFormat.R32_SFloat, TextureCreationFlags.None) { name = "FSR2_LanczosLutData" };
LanczosLut.SetPixelData(lanczos2Weights, 0);
LanczosLut.Apply();
LanczosLut = CreateLookup("FSR2_LanczosLutData", new Vector2Int(lanczos2LutWidth, 1), GraphicsFormat.R32_SFloat, lanczos2Weights);
// Resource FSR2_MaximumUpsampleBias: FFX_RESOURCE_USAGE_READ_ONLY, FFX_SURFACE_FORMAT_R16_SNORM, FFX_RESOURCE_FLAGS_NONE // Resource FSR2_MaximumUpsampleBias: FFX_RESOURCE_USAGE_READ_ONLY, FFX_SURFACE_FORMAT_R16_SNORM, FFX_RESOURCE_FLAGS_NONE
MaximumBiasLut = new Texture2D(MaximumBiasTextureWidth, MaximumBiasTextureHeight, GraphicsFormat.R32_SFloat, TextureCreationFlags.None) { name = "FSR2_MaximumUpsampleBias" };
MaximumBiasLut.SetPixelData(maximumBias, 0);
MaximumBiasLut.Apply();
MaximumBiasLut = CreateLookup("FSR2_MaximumUpsampleBias", new Vector2Int(MaximumBiasTextureWidth, MaximumBiasTextureHeight), GraphicsFormat.R32_SFloat, maximumBias);
// Resource FSR2_DefaultExposure: FFX_RESOURCE_USAGE_READ_ONLY, FFX_SURFACE_FORMAT_R32G32_FLOAT, FFX_RESOURCE_FLAGS_NONE // Resource FSR2_DefaultExposure: FFX_RESOURCE_USAGE_READ_ONLY, FFX_SURFACE_FORMAT_R32G32_FLOAT, FFX_RESOURCE_FLAGS_NONE
DefaultExposure = new Texture2D(1, 1, GraphicsFormat.R32G32_SFloat, TextureCreationFlags.None) { name = "FSR2_DefaultExposure" };
DefaultExposure.SetPixel(0, 0, Color.clear);
DefaultExposure.Apply();
DefaultExposure = CreateLookup("FSR2_DefaultExposure", GraphicsFormat.R32G32_SFloat, Color.clear);
// Resource FSR2_DefaultReactivityMask: FFX_RESOURCE_USAGE_READ_ONLY, FFX_SURFACE_FORMAT_R8_UNORM, FFX_RESOURCE_FLAGS_NONE // Resource FSR2_DefaultReactivityMask: FFX_RESOURCE_USAGE_READ_ONLY, FFX_SURFACE_FORMAT_R8_UNORM, FFX_RESOURCE_FLAGS_NONE
DefaultReactive = new Texture2D(1, 1, GraphicsFormat.R8_UNorm, TextureCreationFlags.None) { name = "FSR2_DefaultReactivityMask" };
DefaultReactive.SetPixel(0, 0, Color.clear);
DefaultReactive.Apply();
DefaultReactive = CreateLookup("FSR2_DefaultReactivityMask", GraphicsFormat.R8_UNorm, Color.clear);
// Resource FSR2_SpdAtomicCounter: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R32_UINT, FFX_RESOURCE_FLAGS_ALIASABLE // Resource FSR2_SpdAtomicCounter: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R32_UINT, FFX_RESOURCE_FLAGS_ALIASABLE
// Despite what the original FSR2 codebase says, this resource really isn't aliasable. Resetting this counter to 0 every frame breaks auto-exposure on MacOS Metal. // Despite what the original FSR2 codebase says, this resource really isn't aliasable. Resetting this counter to 0 every frame breaks auto-exposure on MacOS Metal.
SpdAtomicCounter = new RenderTexture(1, 1, 0, GraphicsFormat.R32_UInt) { name = "FSR2_SpdAtomicCounter", enableRandomWrite = true };
SpdAtomicCounter.Create();
SpdAtomicCounter = CreateResource("FSR2_SpdAtomicCounter", Vector2Int.one, GraphicsFormat.R32_UInt);
// Resource FSR2_AutoExposure: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R32G32_FLOAT, FFX_RESOURCE_FLAGS_NONE // Resource FSR2_AutoExposure: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R32G32_FLOAT, FFX_RESOURCE_FLAGS_NONE
AutoExposure = new RenderTexture(1, 1, 0, GraphicsFormat.R32G32_SFloat) { name = "FSR2_AutoExposure", enableRandomWrite = true };
AutoExposure.Create();
AutoExposure = CreateResource("FSR2_AutoExposure", Vector2Int.one, GraphicsFormat.R32G32_SFloat);
// Resource FSR2_ExposureMips: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R16_FLOAT, FFX_RESOURCE_FLAGS_ALIASABLE // Resource FSR2_ExposureMips: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R16_FLOAT, FFX_RESOURCE_FLAGS_ALIASABLE
// This is a rather special case: it's an aliasable resource, but because we require a mipmap chain and bind specific mip levels per shader, we can't easily use temporary RTs for this. // This is a rather special case: it's an aliasable resource, but because we require a mipmap chain and bind specific mip levels per shader, we can't easily use temporary RTs for this.
int w = contextDescription.MaxRenderSize.x / 2, h = contextDescription.MaxRenderSize.y / 2;
int mipCount = 1 + Mathf.FloorToInt(Mathf.Log(Math.Max(w, h), 2.0f));
SceneLuminance = new RenderTexture(w, h, 0, GraphicsFormat.R16_SFloat, mipCount) { name = "FSR2_ExposureMips", enableRandomWrite = true, useMipMap = true, autoGenerateMips = false };
SceneLuminance.Create();
SceneLuminance = CreateResourceMips("FSR2_ExposureMips", contextDescription.MaxRenderSize / 2, GraphicsFormat.R16_SFloat);
// Resources FSR2_InternalDilatedVelocity1/2: FFX_RESOURCE_USAGE_RENDERTARGET | FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R16G16_FLOAT, FFX_RESOURCE_FLAGS_NONE // Resources FSR2_InternalDilatedVelocity1/2: FFX_RESOURCE_USAGE_RENDERTARGET | FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R16G16_FLOAT, FFX_RESOURCE_FLAGS_NONE
CreateDoubleBufferedResource(DilatedMotionVectors, "FSR2_InternalDilatedVelocity", contextDescription.MaxRenderSize, GraphicsFormat.R16G16_SFloat); CreateDoubleBufferedResource(DilatedMotionVectors, "FSR2_InternalDilatedVelocity", contextDescription.MaxRenderSize, GraphicsFormat.R16G16_SFloat);
@ -115,15 +96,13 @@ namespace FidelityFX.FSR2
CreateDoubleBufferedResource(LumaHistory, "FSR2_LumaHistory", contextDescription.DisplaySize, GraphicsFormat.R8G8B8A8_UNorm); CreateDoubleBufferedResource(LumaHistory, "FSR2_LumaHistory", contextDescription.DisplaySize, GraphicsFormat.R8G8B8A8_UNorm);
} }
public void CreateTcrAutogenResources(Fsr2.ContextDescription contextDescription)
public void CreateTcrAutogenResources(in Fsr2.ContextDescription contextDescription)
{ {
// Resource FSR2_AutoReactive: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R8_UNORM, FFX_RESOURCE_FLAGS_NONE // Resource FSR2_AutoReactive: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R8_UNORM, FFX_RESOURCE_FLAGS_NONE
AutoReactive = new RenderTexture(contextDescription.MaxRenderSize.x, contextDescription.MaxRenderSize.y, 0, GraphicsFormat.R8_UNorm) { name = "FSR2_AutoReactive", enableRandomWrite = true };
AutoReactive.Create();
AutoReactive = CreateResource("FSR2_AutoReactive", contextDescription.MaxRenderSize, GraphicsFormat.R8_UNorm);
// Resource FSR2_AutoComposition: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R8_UNORM, FFX_RESOURCE_FLAGS_NONE // Resource FSR2_AutoComposition: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R8_UNORM, FFX_RESOURCE_FLAGS_NONE
AutoComposition = new RenderTexture(contextDescription.MaxRenderSize.x, contextDescription.MaxRenderSize.y, 0, GraphicsFormat.R8_UNorm) { name = "FSR2_AutoComposition", enableRandomWrite = true };
AutoComposition.Create();
AutoComposition = CreateResource("FSR2_AutoComposition", contextDescription.MaxRenderSize, GraphicsFormat.R8_UNorm);
// Resources FSR2_PrevPreAlpha0/1: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R11G11B10_FLOAT, FFX_RESOURCE_FLAGS_NONE // Resources FSR2_PrevPreAlpha0/1: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R11G11B10_FLOAT, FFX_RESOURCE_FLAGS_NONE
CreateDoubleBufferedResource(PrevPreAlpha, "FSR2_PrevPreAlpha", contextDescription.MaxRenderSize, GraphicsFormat.B10G11R11_UFloatPack32); CreateDoubleBufferedResource(PrevPreAlpha, "FSR2_PrevPreAlpha", contextDescription.MaxRenderSize, GraphicsFormat.B10G11R11_UFloatPack32);
@ -134,7 +113,7 @@ namespace FidelityFX.FSR2
// Set up shared aliasable resources, i.e. temporary render textures // Set up shared aliasable resources, i.e. temporary render textures
// These do not need to persist between frames, but they do need to be available between passes // These do not need to persist between frames, but they do need to be available between passes
public static void CreateAliasableResources(CommandBuffer commandBuffer, Fsr2.ContextDescription contextDescription, Fsr2.DispatchDescription dispatchParams)
public static void CreateAliasableResources(CommandBuffer commandBuffer, in Fsr2.ContextDescription contextDescription)
{ {
Vector2Int displaySize = contextDescription.DisplaySize; Vector2Int displaySize = contextDescription.DisplaySize;
Vector2Int maxRenderSize = contextDescription.MaxRenderSize; Vector2Int maxRenderSize = contextDescription.MaxRenderSize;
@ -169,15 +148,6 @@ namespace FidelityFX.FSR2
commandBuffer.ReleaseTemporaryRT(Fsr2ShaderIDs.UavNewLocks); commandBuffer.ReleaseTemporaryRT(Fsr2ShaderIDs.UavNewLocks);
} }
private static void CreateDoubleBufferedResource(RenderTexture[] resource, string name, Vector2Int size, GraphicsFormat format)
{
for (int i = 0; i < 2; ++i)
{
resource[i] = new RenderTexture(size.x, size.y, 0, format) { name = name + (i + 1), enableRandomWrite = true };
resource[i].Create();
}
}
public void Destroy() public void Destroy()
{ {
DestroyTcrAutogenResources(); DestroyTcrAutogenResources();
@ -201,37 +171,6 @@ namespace FidelityFX.FSR2
DestroyResource(ref AutoComposition); DestroyResource(ref AutoComposition);
DestroyResource(ref AutoReactive); DestroyResource(ref AutoReactive);
} }
private static void DestroyResource(ref Texture2D resource)
{
if (resource == null)
return;
#if UNITY_EDITOR
if (Application.isPlaying && !UnityEditor.EditorApplication.isPaused)
UnityEngine.Object.Destroy(resource);
else
UnityEngine.Object.DestroyImmediate(resource);
#else
UnityEngine.Object.Destroy(resource);
#endif
resource = null;
}
private static void DestroyResource(ref RenderTexture resource)
{
if (resource == null)
return;
resource.Release();
resource = null;
}
private static void DestroyResource(RenderTexture[] resource)
{
for (int i = 0; i < resource.Length; ++i)
DestroyResource(ref resource[i]);
}
private const int MaximumBiasTextureWidth = 16; private const int MaximumBiasTextureWidth = 16;
private const int MaximumBiasTextureHeight = 16; private const int MaximumBiasTextureHeight = 16;

90
Runtime/FSR3/Fsr3Upscaler.cs

@ -21,7 +21,6 @@
using System; using System;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using UnityEngine; using UnityEngine;
using UnityEngine.Rendering;
namespace FidelityFX.FSR3 namespace FidelityFX.FSR3
{ {
@ -80,60 +79,13 @@ namespace FidelityFX.FSR3
} }
} }
public static void GetRenderResolutionFromQualityMode(
out int renderWidth, out int renderHeight,
int displayWidth, int displayHeight, QualityMode qualityMode)
public static void GetRenderResolutionFromQualityMode(out int renderWidth, out int renderHeight, int displayWidth, int displayHeight, QualityMode qualityMode)
{ {
float ratio = GetUpscaleRatioFromQualityMode(qualityMode); float ratio = GetUpscaleRatioFromQualityMode(qualityMode);
renderWidth = Mathf.RoundToInt(displayWidth / ratio); renderWidth = Mathf.RoundToInt(displayWidth / ratio);
renderHeight = Mathf.RoundToInt(displayHeight / ratio); renderHeight = Mathf.RoundToInt(displayHeight / ratio);
} }
public static float GetMipmapBiasOffset(int renderWidth, int displayWidth)
{
return Mathf.Log((float)renderWidth / displayWidth, 2.0f) - 1.0f;
}
public static int GetJitterPhaseCount(int renderWidth, int displayWidth)
{
const float basePhaseCount = 8.0f;
int jitterPhaseCount = (int)(basePhaseCount * Mathf.Pow((float)displayWidth / renderWidth, 2.0f));
return jitterPhaseCount;
}
public static void GetJitterOffset(out float outX, out float outY, int index, int phaseCount)
{
outX = Halton((index % phaseCount) + 1, 2) - 0.5f;
outY = Halton((index % phaseCount) + 1, 3) - 0.5f;
}
// Calculate halton number for index and base.
private static float Halton(int index, int @base)
{
float f = 1.0f, result = 0.0f;
for (int currentIndex = index; currentIndex > 0;) {
f /= @base;
result += f * (currentIndex % @base);
currentIndex = (int)Mathf.Floor((float)currentIndex / @base);
}
return result;
}
public static float Lanczos2(float value)
{
return Mathf.Abs(value) < Mathf.Epsilon ? 1.0f : Mathf.Sin(Mathf.PI * value) / (Mathf.PI * value) * (Mathf.Sin(0.5f * Mathf.PI * value) / (0.5f * Mathf.PI * value));
}
#if !UNITY_2021_1_OR_NEWER
internal static void SetBufferData(this CommandBuffer commandBuffer, ComputeBuffer computeBuffer, Array data)
{
commandBuffer.SetComputeBufferData(computeBuffer, data);
}
#endif
public enum QualityMode public enum QualityMode
{ {
NativeAA = 0, NativeAA = 0,
@ -178,7 +130,7 @@ namespace FidelityFX.FSR3
/// <summary> /// <summary>
/// A structure encapsulating the parameters for dispatching the various passes of FidelityFX Super Resolution 3. /// A structure encapsulating the parameters for dispatching the various passes of FidelityFX Super Resolution 3.
/// </summary> /// </summary>
public class DispatchDescription
public struct DispatchDescription
{ {
public ResourceView Color; public ResourceView Color;
public ResourceView Depth; public ResourceView Depth;
@ -206,26 +158,42 @@ namespace FidelityFX.FSR3
// EXPERIMENTAL reactive mask generation parameters // EXPERIMENTAL reactive mask generation parameters
public bool EnableAutoReactive; public bool EnableAutoReactive;
public ResourceView ColorOpaqueOnly; public ResourceView ColorOpaqueOnly;
public float AutoTcThreshold = 0.05f;
public float AutoTcScale = 1.0f;
public float AutoReactiveScale = 5.0f;
public float AutoReactiveMax = 0.9f;
public float AutoTcThreshold;
public float AutoTcScale;
public float AutoReactiveScale;
public float AutoReactiveMax;
public static readonly DispatchDescription Default = new DispatchDescription
{
AutoTcThreshold = 0.05f,
AutoTcScale = 1.0f,
AutoReactiveScale = 5.0f,
AutoReactiveMax = 0.9f,
};
} }
/// <summary> /// <summary>
/// A structure encapsulating the parameters for automatic generation of a reactive mask. /// A structure encapsulating the parameters for automatic generation of a reactive mask.
/// The default values for Scale, CutoffThreshold, BinaryValue and Flags were taken from the FSR3 demo project. /// The default values for Scale, CutoffThreshold, BinaryValue and Flags were taken from the FSR3 demo project.
/// </summary> /// </summary>
public class GenerateReactiveDescription
public struct GenerateReactiveDescription
{ {
public ResourceView ColorOpaqueOnly; public ResourceView ColorOpaqueOnly;
public ResourceView ColorPreUpscale; public ResourceView ColorPreUpscale;
public ResourceView OutReactive; public ResourceView OutReactive;
public Vector2Int RenderSize; public Vector2Int RenderSize;
public float Scale = 0.5f;
public float CutoffThreshold = 0.2f;
public float BinaryValue = 0.9f;
public GenerateReactiveFlags Flags = GenerateReactiveFlags.ApplyTonemap | GenerateReactiveFlags.ApplyThreshold | GenerateReactiveFlags.UseComponentsMax;
public float Scale;
public float CutoffThreshold;
public float BinaryValue;
public GenerateReactiveFlags Flags;
public static readonly GenerateReactiveDescription Default = new GenerateReactiveDescription
{
Scale = 0.5f,
CutoffThreshold = 0.2f,
BinaryValue = 0.9f,
Flags = GenerateReactiveFlags.ApplyTonemap | GenerateReactiveFlags.ApplyThreshold | GenerateReactiveFlags.UseComponentsMax,
};
} }
[Flags] [Flags]
@ -270,9 +238,7 @@ namespace FidelityFX.FSR3
[Serializable, StructLayout(LayoutKind.Sequential)] [Serializable, StructLayout(LayoutKind.Sequential)]
internal struct SpdConstants internal struct SpdConstants
{ {
public uint mips;
public uint numWorkGroups;
public uint workGroupOffsetX, workGroupOffsetY;
public FfxSpd.SpdConstants spd;
public uint renderSizeX, renderSizeY; public uint renderSizeX, renderSizeY;
} }

1
Runtime/FSR3/Fsr3UpscalerAssets.cs

@ -19,7 +19,6 @@
// THE SOFTWARE. // THE SOFTWARE.
using UnityEngine; using UnityEngine;
using UnityEngine.Serialization;
namespace FidelityFX.FSR3 namespace FidelityFX.FSR3
{ {

295
Runtime/FSR3/Fsr3UpscalerContext.cs

@ -19,8 +19,8 @@
// THE SOFTWARE. // THE SOFTWARE.
using System; using System;
using System.Runtime.InteropServices;
using UnityEngine; using UnityEngine;
using UnityEngine.Profiling;
using UnityEngine.Rendering; using UnityEngine.Rendering;
namespace FidelityFX.FSR3 namespace FidelityFX.FSR3
@ -31,71 +31,59 @@ namespace FidelityFX.FSR3
/// Note that this class does not know anything about Unity render pipelines; all it knows is CommandBuffers and RenderTargetIdentifiers. /// Note that this class does not know anything about Unity render pipelines; all it knows is CommandBuffers and RenderTargetIdentifiers.
/// This should make it suitable for integration with any of the available Unity render pipelines. /// This should make it suitable for integration with any of the available Unity render pipelines.
/// </summary> /// </summary>
public class Fsr3UpscalerContext
public class Fsr3UpscalerContext: FfxContextBase
{ {
private const int MaxQueuedFrames = 16; private const int MaxQueuedFrames = 16;
private Fsr3Upscaler.ContextDescription _contextDescription; private Fsr3Upscaler.ContextDescription _contextDescription;
private CommandBuffer _commandBuffer; private CommandBuffer _commandBuffer;
private Fsr3UpscalerPass _prepareInputsPass;
private Fsr3UpscalerPass _lumaPyramidPass;
private Fsr3UpscalerPass _shadingChangePyramidPass;
private Fsr3UpscalerPass _shadingChangePass;
private Fsr3UpscalerPass _prepareReactivityPass;
private Fsr3UpscalerPass _lumaInstabilityPass;
private Fsr3UpscalerPass _accumulatePass;
private Fsr3UpscalerPass _sharpenPass;
private Fsr3UpscalerPass _generateReactivePass;
private Fsr3UpscalerPass _tcrAutogeneratePass;
private Fsr3UpscalerPrepareInputsPass _prepareInputsPass;
private Fsr3UpscalerLumaPyramidPass _lumaPyramidPass;
private Fsr3UpscalerShadingChangePyramidPass _shadingChangePyramidPass;
private Fsr3UpscalerShadingChangePass _shadingChangePass;
private Fsr3UpscalerPrepareReactivityPass _prepareReactivityPass;
private Fsr3UpscalerLumaInstabilityPass _lumaInstabilityPass;
private Fsr3UpscalerAccumulatePass _accumulatePass;
private Fsr3UpscalerSharpenPass _sharpenPass;
private Fsr3UpscalerGenerateReactivePass _generateReactivePass;
private Fsr3UpscalerTcrAutogeneratePass _tcrAutogeneratePass;
#if UNITY_EDITOR || DEVELOPMENT_BUILD #if UNITY_EDITOR || DEVELOPMENT_BUILD
private Fsr3UpscalerPass _debugViewPass;
private Fsr3UpscalerDebugViewPass _debugViewPass;
#endif #endif
private readonly Fsr3UpscalerResources _resources = new Fsr3UpscalerResources(); private readonly Fsr3UpscalerResources _resources = new Fsr3UpscalerResources();
private ComputeBuffer _upscalerConstantsBuffer;
private readonly Fsr3Upscaler.UpscalerConstants[] _upscalerConstantsArray = { new Fsr3Upscaler.UpscalerConstants() };
private ref Fsr3Upscaler.UpscalerConstants UpscalerConsts => ref _upscalerConstantsArray[0];
private ComputeBuffer _spdConstantsBuffer;
private readonly Fsr3Upscaler.SpdConstants[] _spdConstantsArray = { new Fsr3Upscaler.SpdConstants() };
private ref Fsr3Upscaler.SpdConstants SpdConsts => ref _spdConstantsArray[0];
private ComputeBuffer _rcasConstantsBuffer;
private readonly Fsr3Upscaler.RcasConstants[] _rcasConstantsArray = new Fsr3Upscaler.RcasConstants[1];
private ref Fsr3Upscaler.RcasConstants RcasConsts => ref _rcasConstantsArray[0];
private ComputeBuffer _generateReactiveConstantsBuffer;
private readonly Fsr3Upscaler.GenerateReactiveConstants[] _generateReactiveConstantsArray = { new Fsr3Upscaler.GenerateReactiveConstants() };
private ref Fsr3Upscaler.GenerateReactiveConstants GenReactiveConsts => ref _generateReactiveConstantsArray[0];
private ComputeBuffer _tcrAutogenerateConstantsBuffer;
private readonly Fsr3Upscaler.GenerateReactiveConstants2[] _tcrAutogenerateConstantsArray = { new Fsr3Upscaler.GenerateReactiveConstants2() };
private ref Fsr3Upscaler.GenerateReactiveConstants2 TcrAutoGenConsts => ref _tcrAutogenerateConstantsArray[0];
private readonly ConstantsBuffer<Fsr3Upscaler.UpscalerConstants> _upscalerConstants = new ConstantsBuffer<Fsr3Upscaler.UpscalerConstants>();
private readonly ConstantsBuffer<Fsr3Upscaler.SpdConstants> _spdConstants = new ConstantsBuffer<Fsr3Upscaler.SpdConstants>();
private readonly ConstantsBuffer<Fsr3Upscaler.RcasConstants> _rcasConstants = new ConstantsBuffer<Fsr3Upscaler.RcasConstants>();
private readonly ConstantsBuffer<Fsr3Upscaler.GenerateReactiveConstants> _generateReactiveConstants = new ConstantsBuffer<Fsr3Upscaler.GenerateReactiveConstants>();
private readonly ConstantsBuffer<Fsr3Upscaler.GenerateReactiveConstants2> _tcrAutogenerateConstants = new ConstantsBuffer<Fsr3Upscaler.GenerateReactiveConstants2>();
private bool _firstExecution; private bool _firstExecution;
private int _resourceFrameIndex; private int _resourceFrameIndex;
private Vector2 _previousJitterOffset; private Vector2 _previousJitterOffset;
private float _preExposure; private float _preExposure;
private float _previousFramePreExposure; private float _previousFramePreExposure;
private readonly CustomSampler _sampler = CustomSampler.Create("FSR3 Upscaler");
public void Create(Fsr3Upscaler.ContextDescription contextDescription)
public void Create(in Fsr3Upscaler.ContextDescription contextDescription)
{ {
_contextDescription = contextDescription; _contextDescription = contextDescription;
_commandBuffer = new CommandBuffer { name = "FSR3 Upscaler" }; _commandBuffer = new CommandBuffer { name = "FSR3 Upscaler" };
_upscalerConstantsBuffer = CreateConstantBuffer<Fsr3Upscaler.UpscalerConstants>();
_spdConstantsBuffer = CreateConstantBuffer<Fsr3Upscaler.SpdConstants>();
_rcasConstantsBuffer = CreateConstantBuffer<Fsr3Upscaler.RcasConstants>();
_generateReactiveConstantsBuffer = CreateConstantBuffer<Fsr3Upscaler.GenerateReactiveConstants>();
_tcrAutogenerateConstantsBuffer = CreateConstantBuffer<Fsr3Upscaler.GenerateReactiveConstants2>();
_upscalerConstants.Create();
_spdConstants.Create();
_rcasConstants.Create();
_generateReactiveConstants.Create();
_tcrAutogenerateConstants.Create();
// Set defaults // Set defaults
_firstExecution = true; _firstExecution = true;
_resourceFrameIndex = 0; _resourceFrameIndex = 0;
UpscalerConsts.maxUpscaleSize = _contextDescription.MaxUpscaleSize;
_upscalerConstants.Value.maxUpscaleSize = _contextDescription.MaxUpscaleSize;
_resources.Create(_contextDescription); _resources.Create(_contextDescription);
CreatePasses(); CreatePasses();
@ -103,18 +91,18 @@ namespace FidelityFX.FSR3
private void CreatePasses() private void CreatePasses()
{ {
_prepareInputsPass = new Fsr3UpscalerPrepareInputsPass(_contextDescription, _resources, _upscalerConstantsBuffer);
_lumaPyramidPass = new Fsr3UpscalerLumaPyramidPass(_contextDescription, _resources, _upscalerConstantsBuffer, _spdConstantsBuffer);
_shadingChangePyramidPass = new Fsr3UpscalerShadingChangePyramidPass(_contextDescription, _resources, _upscalerConstantsBuffer, _spdConstantsBuffer);
_shadingChangePass = new Fsr3UpscalerShadingChangePass(_contextDescription, _resources, _upscalerConstantsBuffer);
_prepareReactivityPass = new Fsr3UpscalerPrepareReactivityPass(_contextDescription, _resources, _upscalerConstantsBuffer);
_lumaInstabilityPass = new Fsr3UpscalerLumaInstabilityPass(_contextDescription, _resources, _upscalerConstantsBuffer);
_accumulatePass = new Fsr3UpscalerAccumulatePass(_contextDescription, _resources, _upscalerConstantsBuffer);
_sharpenPass = new Fsr3UpscalerSharpenPass(_contextDescription, _resources, _upscalerConstantsBuffer, _rcasConstantsBuffer);
_generateReactivePass = new Fsr3UpscalerGenerateReactivePass(_contextDescription, _resources, _generateReactiveConstantsBuffer);
_tcrAutogeneratePass = new Fsr3UpscalerTcrAutogeneratePass(_contextDescription, _resources, _upscalerConstantsBuffer, _tcrAutogenerateConstantsBuffer);
_prepareInputsPass = new Fsr3UpscalerPrepareInputsPass(_contextDescription, _resources, _upscalerConstants);
_lumaPyramidPass = new Fsr3UpscalerLumaPyramidPass(_contextDescription, _resources, _upscalerConstants, _spdConstants);
_shadingChangePyramidPass = new Fsr3UpscalerShadingChangePyramidPass(_contextDescription, _resources, _upscalerConstants, _spdConstants);
_shadingChangePass = new Fsr3UpscalerShadingChangePass(_contextDescription, _resources, _upscalerConstants);
_prepareReactivityPass = new Fsr3UpscalerPrepareReactivityPass(_contextDescription, _resources, _upscalerConstants);
_lumaInstabilityPass = new Fsr3UpscalerLumaInstabilityPass(_contextDescription, _resources, _upscalerConstants);
_accumulatePass = new Fsr3UpscalerAccumulatePass(_contextDescription, _resources, _upscalerConstants);
_sharpenPass = new Fsr3UpscalerSharpenPass(_contextDescription, _resources, _upscalerConstants, _rcasConstants);
_generateReactivePass = new Fsr3UpscalerGenerateReactivePass(_contextDescription, _resources, _upscalerConstants);
_tcrAutogeneratePass = new Fsr3UpscalerTcrAutogeneratePass(_contextDescription, _resources, _upscalerConstants, _tcrAutogenerateConstants);
#if UNITY_EDITOR || DEVELOPMENT_BUILD #if UNITY_EDITOR || DEVELOPMENT_BUILD
_debugViewPass = new Fsr3UpscalerDebugViewPass(_contextDescription, _resources, _upscalerConstantsBuffer);
_debugViewPass = new Fsr3UpscalerDebugViewPass(_contextDescription, _resources, _upscalerConstants);
#endif #endif
} }
@ -136,11 +124,11 @@ namespace FidelityFX.FSR3
_resources.Destroy(); _resources.Destroy();
DestroyConstantBuffer(ref _tcrAutogenerateConstantsBuffer);
DestroyConstantBuffer(ref _generateReactiveConstantsBuffer);
DestroyConstantBuffer(ref _rcasConstantsBuffer);
DestroyConstantBuffer(ref _spdConstantsBuffer);
DestroyConstantBuffer(ref _upscalerConstantsBuffer);
_tcrAutogenerateConstants.Destroy();
_generateReactiveConstants.Destroy();
_rcasConstants.Destroy();
_spdConstants.Destroy();
_upscalerConstants.Destroy();
if (_commandBuffer != null) if (_commandBuffer != null)
{ {
@ -149,7 +137,7 @@ namespace FidelityFX.FSR3
} }
} }
public void Dispatch(Fsr3Upscaler.DispatchDescription dispatchParams)
public void Dispatch(in Fsr3Upscaler.DispatchDescription dispatchParams)
{ {
_commandBuffer.Clear(); _commandBuffer.Clear();
Dispatch(dispatchParams, _commandBuffer); Dispatch(dispatchParams, _commandBuffer);
@ -158,13 +146,15 @@ namespace FidelityFX.FSR3
public void Dispatch(Fsr3Upscaler.DispatchDescription dispatchParams, CommandBuffer commandBuffer) public void Dispatch(Fsr3Upscaler.DispatchDescription dispatchParams, CommandBuffer commandBuffer)
{ {
commandBuffer.BeginSample(_sampler);
if ((_contextDescription.Flags & Fsr3Upscaler.InitializationFlags.EnableDebugChecking) != 0) if ((_contextDescription.Flags & Fsr3Upscaler.InitializationFlags.EnableDebugChecking) != 0)
{ {
DebugCheckDispatch(dispatchParams); DebugCheckDispatch(dispatchParams);
} }
if (dispatchParams.UseTextureArrays) if (dispatchParams.UseTextureArrays)
commandBuffer.EnableShaderKeyword("UNITY_FSR_TEXTURE2D_X_ARRAY");
commandBuffer.EnableShaderKeyword("UNITY_FFX_TEXTURE2D_X_ARRAY");
if (_firstExecution) if (_firstExecution)
{ {
@ -178,7 +168,7 @@ namespace FidelityFX.FSR3
commandBuffer.ClearRenderTarget(false, true, Color.clear); commandBuffer.ClearRenderTarget(false, true, Color.clear);
} }
int frameIndex = _resourceFrameIndex % 2;
int bufferIndex = _resourceFrameIndex % 2;
bool resetAccumulation = dispatchParams.Reset || _firstExecution; bool resetAccumulation = dispatchParams.Reset || _firstExecution;
_firstExecution = false; _firstExecution = false;
@ -197,7 +187,7 @@ namespace FidelityFX.FSR3
if (resetAccumulation) if (resetAccumulation)
{ {
RenderTargetIdentifier opaqueOnly = dispatchParams.ColorOpaqueOnly.IsValid ? dispatchParams.ColorOpaqueOnly.RenderTarget : Fsr3ShaderIDs.SrvOpaqueOnly; RenderTargetIdentifier opaqueOnly = dispatchParams.ColorOpaqueOnly.IsValid ? dispatchParams.ColorOpaqueOnly.RenderTarget : Fsr3ShaderIDs.SrvOpaqueOnly;
commandBuffer.Blit(_resources.PrevPreAlpha[frameIndex ^ 1], opaqueOnly);
commandBuffer.Blit(_resources.PrevPreAlpha[bufferIndex ^ 1], opaqueOnly);
} }
} }
else if (_resources.AutoReactive != null) else if (_resources.AutoReactive != null)
@ -208,23 +198,25 @@ namespace FidelityFX.FSR3
if (!dispatchParams.Reactive.IsValid) dispatchParams.Reactive = new ResourceView(_resources.DefaultReactive); if (!dispatchParams.Reactive.IsValid) dispatchParams.Reactive = new ResourceView(_resources.DefaultReactive);
if (!dispatchParams.TransparencyAndComposition.IsValid) dispatchParams.TransparencyAndComposition = new ResourceView(_resources.DefaultReactive); if (!dispatchParams.TransparencyAndComposition.IsValid) dispatchParams.TransparencyAndComposition = new ResourceView(_resources.DefaultReactive);
Fsr3UpscalerResources.CreateAliasableResources(commandBuffer, _contextDescription, dispatchParams);
Fsr3UpscalerResources.CreateAliasableResources(commandBuffer, _contextDescription);
SetupConstants(dispatchParams, resetAccumulation); SetupConstants(dispatchParams, resetAccumulation);
// Reactive mask bias // Reactive mask bias
const int threadGroupWorkRegionDim = 8; const int threadGroupWorkRegionDim = 8;
int dispatchSrcX = (UpscalerConsts.renderSize.x + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
int dispatchSrcY = (UpscalerConsts.renderSize.y + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
int dispatchDstX = (UpscalerConsts.upscaleSize.x + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
int dispatchDstY = (UpscalerConsts.upscaleSize.y + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
int dispatchShadingChangePassX = ((UpscalerConsts.renderSize.x / 2) + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
int dispatchShadingChangePassY = ((UpscalerConsts.renderSize.y / 2) + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
var renderSize = _upscalerConstants.Value.renderSize;
var upscaleSize = _upscalerConstants.Value.upscaleSize;
int dispatchSrcX = (renderSize.x + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
int dispatchSrcY = (renderSize.y + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
int dispatchDstX = (upscaleSize.x + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
int dispatchDstY = (upscaleSize.y + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
int dispatchShadingChangePassX = ((renderSize.x / 2) + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
int dispatchShadingChangePassY = ((renderSize.y / 2) + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
// Clear reconstructed depth for max depth store // Clear reconstructed depth for max depth store
if (resetAccumulation) if (resetAccumulation)
{ {
commandBuffer.SetRenderTarget(_resources.Accumulation[frameIndex ^ 1]);
commandBuffer.SetRenderTarget(_resources.Accumulation[bufferIndex ^ 1]);
commandBuffer.ClearRenderTarget(false, true, Color.clear); commandBuffer.ClearRenderTarget(false, true, Color.clear);
commandBuffer.SetRenderTarget(_resources.SpdMips); commandBuffer.SetRenderTarget(_resources.SpdMips);
@ -240,7 +232,7 @@ namespace FidelityFX.FSR3
} }
// FSR3: need to clear here since we need the content of this surface for frame interpolation, so clearing in the lock pass is not an option // FSR3: need to clear here since we need the content of this surface for frame interpolation, so clearing in the lock pass is not an option
bool depthInverted = (_contextDescription.Flags & Fsr3Upscaler.InitializationFlags.EnableDepthInverted) == Fsr3Upscaler.InitializationFlags.EnableDepthInverted;
bool depthInverted = (_contextDescription.Flags & Fsr3Upscaler.InitializationFlags.EnableDepthInverted) != 0;
commandBuffer.SetRenderTarget(_resources.ReconstructedPrevNearestDepth); commandBuffer.SetRenderTarget(_resources.ReconstructedPrevNearestDepth);
commandBuffer.ClearRenderTarget(false, true, depthInverted ? Color.clear : Color.white); commandBuffer.ClearRenderTarget(false, true, depthInverted ? Color.clear : Color.white);
@ -248,43 +240,43 @@ namespace FidelityFX.FSR3
SetupSpdConstants(dispatchParams, out var dispatchThreadGroupCount); SetupSpdConstants(dispatchParams, out var dispatchThreadGroupCount);
// Initialize constant buffers data // Initialize constant buffers data
commandBuffer.SetBufferData(_upscalerConstantsBuffer, _upscalerConstantsArray);
commandBuffer.SetBufferData(_spdConstantsBuffer, _spdConstantsArray);
_upscalerConstants.UpdateBufferData(commandBuffer);
_spdConstants.UpdateBufferData(commandBuffer);
// Auto reactive // Auto reactive
if (dispatchParams.EnableAutoReactive) if (dispatchParams.EnableAutoReactive)
{ {
GenerateTransparencyCompositionReactive(dispatchParams, commandBuffer, frameIndex);
GenerateTransparencyCompositionReactive(dispatchParams, commandBuffer, bufferIndex);
dispatchParams.Reactive = new ResourceView(_resources.AutoReactive); dispatchParams.Reactive = new ResourceView(_resources.AutoReactive);
dispatchParams.TransparencyAndComposition = new ResourceView(_resources.AutoComposition); dispatchParams.TransparencyAndComposition = new ResourceView(_resources.AutoComposition);
} }
_prepareInputsPass.ScheduleDispatch(commandBuffer, dispatchParams, frameIndex, dispatchSrcX, dispatchSrcY);
_lumaPyramidPass.ScheduleDispatch(commandBuffer, dispatchParams, frameIndex, dispatchThreadGroupCount.x, dispatchThreadGroupCount.y);
_shadingChangePyramidPass.ScheduleDispatch(commandBuffer, dispatchParams, frameIndex, dispatchThreadGroupCount.x, dispatchThreadGroupCount.y);
_shadingChangePass.ScheduleDispatch(commandBuffer, dispatchParams, frameIndex, dispatchShadingChangePassX, dispatchShadingChangePassY);
_prepareReactivityPass.ScheduleDispatch(commandBuffer, dispatchParams, frameIndex, dispatchSrcX, dispatchSrcY);
_lumaInstabilityPass.ScheduleDispatch(commandBuffer, dispatchParams, frameIndex, dispatchSrcX, dispatchSrcY);
_prepareInputsPass.ScheduleDispatch(commandBuffer, dispatchParams, bufferIndex, dispatchSrcX, dispatchSrcY);
_lumaPyramidPass.ScheduleDispatch(commandBuffer, dispatchParams, bufferIndex, dispatchThreadGroupCount.x, dispatchThreadGroupCount.y);
_shadingChangePyramidPass.ScheduleDispatch(commandBuffer, dispatchParams, bufferIndex, dispatchThreadGroupCount.x, dispatchThreadGroupCount.y);
_shadingChangePass.ScheduleDispatch(commandBuffer, dispatchParams, bufferIndex, dispatchShadingChangePassX, dispatchShadingChangePassY);
_prepareReactivityPass.ScheduleDispatch(commandBuffer, dispatchParams, bufferIndex, dispatchSrcX, dispatchSrcY);
_lumaInstabilityPass.ScheduleDispatch(commandBuffer, dispatchParams, bufferIndex, dispatchSrcX, dispatchSrcY);
_accumulatePass.ScheduleDispatch(commandBuffer, dispatchParams, frameIndex, dispatchDstX, dispatchDstY);
_accumulatePass.ScheduleDispatch(commandBuffer, dispatchParams, bufferIndex, dispatchDstX, dispatchDstY);
if (dispatchParams.EnableSharpening) if (dispatchParams.EnableSharpening)
{ {
// Compute the constants // Compute the constants
SetupRcasConstants(dispatchParams); SetupRcasConstants(dispatchParams);
commandBuffer.SetBufferData(_rcasConstantsBuffer, _rcasConstantsArray);
_rcasConstants.UpdateBufferData(commandBuffer);
// Dispatch RCAS // Dispatch RCAS
const int threadGroupWorkRegionDimRcas = 16; const int threadGroupWorkRegionDimRcas = 16;
int threadGroupsX = (UpscalerConsts.upscaleSize.x + threadGroupWorkRegionDimRcas - 1) / threadGroupWorkRegionDimRcas;
int threadGroupsY = (UpscalerConsts.upscaleSize.y + threadGroupWorkRegionDimRcas - 1) / threadGroupWorkRegionDimRcas;
_sharpenPass.ScheduleDispatch(commandBuffer, dispatchParams, frameIndex, threadGroupsX, threadGroupsY);
int threadGroupsX = (upscaleSize.x + threadGroupWorkRegionDimRcas - 1) / threadGroupWorkRegionDimRcas;
int threadGroupsY = (upscaleSize.y + threadGroupWorkRegionDimRcas - 1) / threadGroupWorkRegionDimRcas;
_sharpenPass.ScheduleDispatch(commandBuffer, dispatchParams, bufferIndex, threadGroupsX, threadGroupsY);
} }
#if UNITY_EDITOR || DEVELOPMENT_BUILD #if UNITY_EDITOR || DEVELOPMENT_BUILD
if ((dispatchParams.Flags & Fsr3Upscaler.DispatchFlags.DrawDebugView) != 0) if ((dispatchParams.Flags & Fsr3Upscaler.DispatchFlags.DrawDebugView) != 0)
{ {
_debugViewPass.ScheduleDispatch(commandBuffer, dispatchParams, frameIndex, dispatchDstX, dispatchDstY);
_debugViewPass.ScheduleDispatch(commandBuffer, dispatchParams, bufferIndex, dispatchDstX, dispatchDstY);
} }
#endif #endif
@ -292,49 +284,52 @@ namespace FidelityFX.FSR3
Fsr3UpscalerResources.DestroyAliasableResources(commandBuffer); Fsr3UpscalerResources.DestroyAliasableResources(commandBuffer);
commandBuffer.DisableShaderKeyword("UNITY_FSR_TEXTURE2D_X_ARRAY");
commandBuffer.DisableShaderKeyword("UNITY_FFX_TEXTURE2D_X_ARRAY");
commandBuffer.EndSample(_sampler);
} }
public void GenerateReactiveMask(Fsr3Upscaler.GenerateReactiveDescription dispatchParams)
public void GenerateReactiveMask(in Fsr3Upscaler.GenerateReactiveDescription dispatchParams)
{ {
_commandBuffer.Clear(); _commandBuffer.Clear();
GenerateReactiveMask(dispatchParams, _commandBuffer); GenerateReactiveMask(dispatchParams, _commandBuffer);
Graphics.ExecuteCommandBuffer(_commandBuffer); Graphics.ExecuteCommandBuffer(_commandBuffer);
} }
public void GenerateReactiveMask(Fsr3Upscaler.GenerateReactiveDescription dispatchParams, CommandBuffer commandBuffer)
public void GenerateReactiveMask(in Fsr3Upscaler.GenerateReactiveDescription dispatchParams, CommandBuffer commandBuffer)
{ {
const int threadGroupWorkRegionDim = 8; const int threadGroupWorkRegionDim = 8;
int dispatchSrcX = (dispatchParams.RenderSize.x + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim; int dispatchSrcX = (dispatchParams.RenderSize.x + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
int dispatchSrcY = (dispatchParams.RenderSize.y + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim; int dispatchSrcY = (dispatchParams.RenderSize.y + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
GenReactiveConsts.scale = dispatchParams.Scale;
GenReactiveConsts.threshold = dispatchParams.CutoffThreshold;
GenReactiveConsts.binaryValue = dispatchParams.BinaryValue;
GenReactiveConsts.flags = (uint)dispatchParams.Flags;
commandBuffer.SetBufferData(_generateReactiveConstantsBuffer, _generateReactiveConstantsArray);
ref var genReactiveConsts = ref _generateReactiveConstants.Value;
genReactiveConsts.scale = dispatchParams.Scale;
genReactiveConsts.threshold = dispatchParams.CutoffThreshold;
genReactiveConsts.binaryValue = dispatchParams.BinaryValue;
genReactiveConsts.flags = (uint)dispatchParams.Flags;
_generateReactiveConstants.UpdateBufferData(commandBuffer);
((Fsr3UpscalerGenerateReactivePass)_generateReactivePass).ScheduleDispatch(commandBuffer, dispatchParams, dispatchSrcX, dispatchSrcY);
_generateReactivePass.ScheduleDispatch(commandBuffer, dispatchParams, dispatchSrcX, dispatchSrcY);
} }
private void GenerateTransparencyCompositionReactive(Fsr3Upscaler.DispatchDescription dispatchParams, CommandBuffer commandBuffer, int frameIndex)
private void GenerateTransparencyCompositionReactive(in Fsr3Upscaler.DispatchDescription dispatchParams, CommandBuffer commandBuffer, int bufferIndex)
{ {
const int threadGroupWorkRegionDim = 8; const int threadGroupWorkRegionDim = 8;
int dispatchSrcX = (dispatchParams.RenderSize.x + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim; int dispatchSrcX = (dispatchParams.RenderSize.x + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
int dispatchSrcY = (dispatchParams.RenderSize.y + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim; int dispatchSrcY = (dispatchParams.RenderSize.y + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
TcrAutoGenConsts.autoTcThreshold = dispatchParams.AutoTcThreshold;
TcrAutoGenConsts.autoTcScale = dispatchParams.AutoTcScale;
TcrAutoGenConsts.autoReactiveScale = dispatchParams.AutoReactiveScale;
TcrAutoGenConsts.autoReactiveMax = dispatchParams.AutoReactiveMax;
commandBuffer.SetBufferData(_tcrAutogenerateConstantsBuffer, _tcrAutogenerateConstantsArray);
ref var tcrAutoGenConsts = ref _tcrAutogenerateConstants.Value;
tcrAutoGenConsts.autoTcThreshold = dispatchParams.AutoTcThreshold;
tcrAutoGenConsts.autoTcScale = dispatchParams.AutoTcScale;
tcrAutoGenConsts.autoReactiveScale = dispatchParams.AutoReactiveScale;
tcrAutoGenConsts.autoReactiveMax = dispatchParams.AutoReactiveMax;
_tcrAutogenerateConstants.UpdateBufferData(commandBuffer);
_tcrAutogeneratePass.ScheduleDispatch(commandBuffer, dispatchParams, frameIndex, dispatchSrcX, dispatchSrcY);
_tcrAutogeneratePass.ScheduleDispatch(commandBuffer, dispatchParams, bufferIndex, dispatchSrcX, dispatchSrcY);
} }
private void SetupConstants(Fsr3Upscaler.DispatchDescription dispatchParams, bool resetAccumulation)
private void SetupConstants(in Fsr3Upscaler.DispatchDescription dispatchParams, bool resetAccumulation)
{ {
ref Fsr3Upscaler.UpscalerConstants constants = ref UpscalerConsts;
ref Fsr3Upscaler.UpscalerConstants constants = ref _upscalerConstants.Value;
constants.previousFrameJitterOffset = constants.jitterOffset; constants.previousFrameJitterOffset = constants.jitterOffset;
constants.jitterOffset = dispatchParams.JitterOffset; constants.jitterOffset = dispatchParams.JitterOffset;
@ -350,7 +345,10 @@ namespace FidelityFX.FSR3
constants.viewSpaceToMetersFactor = (dispatchParams.ViewSpaceToMetersFactor > 0.0f) ? dispatchParams.ViewSpaceToMetersFactor : 1.0f; constants.viewSpaceToMetersFactor = (dispatchParams.ViewSpaceToMetersFactor > 0.0f) ? dispatchParams.ViewSpaceToMetersFactor : 1.0f;
// Compute params to enable device depth to view space depth computation in shader // Compute params to enable device depth to view space depth computation in shader
constants.deviceToViewDepth = SetupDeviceDepthToViewSpaceDepthParams(dispatchParams);
bool inverted = (_contextDescription.Flags & Fsr3Upscaler.InitializationFlags.EnableDepthInverted) != 0;
bool infinite = (_contextDescription.Flags & Fsr3Upscaler.InitializationFlags.EnableDepthInfinite) != 0;
constants.deviceToViewDepth = FfxUtils.SetupDeviceDepthToViewSpaceDepthParams(
dispatchParams.RenderSize, dispatchParams.CameraNear, dispatchParams.CameraFar, dispatchParams.CameraFovAngleVertical, inverted, infinite);
constants.previousFrameUpscaleSize = constants.upscaleSize; constants.previousFrameUpscaleSize = constants.upscaleSize;
if (dispatchParams.UpscaleSize.x == 0 && dispatchParams.UpscaleSize.y == 0) if (dispatchParams.UpscaleSize.x == 0 && dispatchParams.UpscaleSize.y == 0)
@ -386,7 +384,7 @@ namespace FidelityFX.FSR3
_previousJitterOffset = constants.jitterOffset; _previousJitterOffset = constants.jitterOffset;
} }
int jitterPhaseCount = Fsr3Upscaler.GetJitterPhaseCount(dispatchParams.RenderSize.x, _contextDescription.MaxUpscaleSize.x);
int jitterPhaseCount = FfxUtils.GetJitterPhaseCount(dispatchParams.RenderSize.x, _contextDescription.MaxUpscaleSize.x);
if (resetAccumulation || constants.jitterPhaseCount == 0) if (resetAccumulation || constants.jitterPhaseCount == 0)
{ {
constants.jitterPhaseCount = jitterPhaseCount; constants.jitterPhaseCount = jitterPhaseCount;
@ -408,79 +406,23 @@ namespace FidelityFX.FSR3
else else
constants.frameIndex += 1.0f; constants.frameIndex += 1.0f;
} }
private Vector4 SetupDeviceDepthToViewSpaceDepthParams(Fsr3Upscaler.DispatchDescription dispatchParams)
{
bool inverted = (_contextDescription.Flags & Fsr3Upscaler.InitializationFlags.EnableDepthInverted) != 0;
bool infinite = (_contextDescription.Flags & Fsr3Upscaler.InitializationFlags.EnableDepthInfinite) != 0;
// make sure it has no impact if near and far plane values are swapped in dispatch params
// the flags "inverted" and "infinite" will decide what transform to use
float min = Mathf.Min(dispatchParams.CameraNear, dispatchParams.CameraFar);
float max = Mathf.Max(dispatchParams.CameraNear, dispatchParams.CameraFar);
if (inverted)
{
(min, max) = (max, min);
}
float q = max / (min - max);
float d = -1.0f;
Vector4 matrixElemC = new Vector4(q, -1.0f - Mathf.Epsilon, q, 0.0f + Mathf.Epsilon);
Vector4 matrixElemE = new Vector4(q * min, -min - Mathf.Epsilon, q * min, max);
// Revert x and y coords
float aspect = (float)dispatchParams.RenderSize.x / dispatchParams.RenderSize.y;
float cotHalfFovY = Mathf.Cos(0.5f * dispatchParams.CameraFovAngleVertical) / Mathf.Sin(0.5f * dispatchParams.CameraFovAngleVertical);
int matrixIndex = (inverted ? 2 : 0) + (infinite ? 1 : 0);
return new Vector4(
d * matrixElemC[matrixIndex],
matrixElemE[matrixIndex],
aspect / cotHalfFovY,
1.0f / cotHalfFovY);
}
private void SetupRcasConstants(Fsr3Upscaler.DispatchDescription dispatchParams)
private void SetupRcasConstants(in Fsr3Upscaler.DispatchDescription dispatchParams)
{ {
int sharpnessIndex = Mathf.RoundToInt(Mathf.Clamp01(dispatchParams.Sharpness) * (RcasConfigs.Length - 1)); int sharpnessIndex = Mathf.RoundToInt(Mathf.Clamp01(dispatchParams.Sharpness) * (RcasConfigs.Length - 1));
RcasConsts = RcasConfigs[sharpnessIndex];
_rcasConstants.Value = RcasConfigs[sharpnessIndex];
} }
private void SetupSpdConstants(Fsr3Upscaler.DispatchDescription dispatchParams, out Vector2Int dispatchThreadGroupCount)
private void SetupSpdConstants(in Fsr3Upscaler.DispatchDescription dispatchParams, out Vector2Int dispatchThreadGroupCount)
{ {
RectInt rectInfo = new RectInt(0, 0, dispatchParams.RenderSize.x, dispatchParams.RenderSize.y);
SpdSetup(rectInfo, out dispatchThreadGroupCount, out var workGroupOffset, out var numWorkGroupsAndMips);
// Downsample // Downsample
ref Fsr3Upscaler.SpdConstants spdConstants = ref SpdConsts;
spdConstants.numWorkGroups = (uint)numWorkGroupsAndMips.x;
spdConstants.mips = (uint)numWorkGroupsAndMips.y;
spdConstants.workGroupOffsetX = (uint)workGroupOffset.x;
spdConstants.workGroupOffsetY = (uint)workGroupOffset.y;
ref Fsr3Upscaler.SpdConstants spdConstants = ref _spdConstants.Value;
FfxSpd.SetupSpdConstants(dispatchParams.RenderSize, ref spdConstants.spd, out dispatchThreadGroupCount);
spdConstants.renderSizeX = (uint)dispatchParams.RenderSize.x; spdConstants.renderSizeX = (uint)dispatchParams.RenderSize.x;
spdConstants.renderSizeY = (uint)dispatchParams.RenderSize.y; spdConstants.renderSizeY = (uint)dispatchParams.RenderSize.y;
} }
private static void SpdSetup(RectInt rectInfo, out Vector2Int dispatchThreadGroupCount, out Vector2Int workGroupOffset, out Vector2Int numWorkGroupsAndMips, int mips = -1)
{
workGroupOffset = new Vector2Int(rectInfo.x / 64, rectInfo.y / 64);
int endIndexX = (rectInfo.x + rectInfo.width - 1) / 64;
int endIndexY = (rectInfo.y + rectInfo.height - 1) / 64;
dispatchThreadGroupCount = new Vector2Int(endIndexX + 1 - workGroupOffset.x, endIndexY + 1 - workGroupOffset.y);
numWorkGroupsAndMips = new Vector2Int(dispatchThreadGroupCount.x * dispatchThreadGroupCount.y, mips);
if (mips < 0)
{
float resolution = Math.Max(rectInfo.width, rectInfo.height);
numWorkGroupsAndMips.y = Math.Min(Mathf.FloorToInt(Mathf.Log(resolution, 2.0f)), 12);
}
}
private void DebugCheckDispatch(Fsr3Upscaler.DispatchDescription dispatchParams)
private void DebugCheckDispatch(in Fsr3Upscaler.DispatchDescription dispatchParams)
{ {
if (!dispatchParams.Color.IsValid) if (!dispatchParams.Color.IsValid)
{ {
@ -630,28 +572,5 @@ namespace FidelityFX.FSR3
new Fsr3Upscaler.RcasConstants(1064229695u, 997604214u), new Fsr3Upscaler.RcasConstants(1064229695u, 997604214u),
new Fsr3Upscaler.RcasConstants(1065353216u, 1006648320), new Fsr3Upscaler.RcasConstants(1065353216u, 1006648320),
}; };
private static ComputeBuffer CreateConstantBuffer<TConstants>() where TConstants: struct
{
return new ComputeBuffer(1, Marshal.SizeOf<TConstants>(), ComputeBufferType.Constant);
}
private static void DestroyConstantBuffer(ref ComputeBuffer bufferRef)
{
if (bufferRef == null)
return;
bufferRef.Release();
bufferRef = null;
}
private static void DestroyPass(ref Fsr3UpscalerPass pass)
{
if (pass == null)
return;
pass.Dispose();
pass = null;
}
} }
} }

332
Runtime/FSR3/Fsr3UpscalerPass.cs

@ -18,10 +18,7 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. // THE SOFTWARE.
using System;
using System.Runtime.InteropServices;
using UnityEngine; using UnityEngine;
using UnityEngine.Profiling;
using UnityEngine.Rendering; using UnityEngine.Rendering;
namespace FidelityFX.FSR3 namespace FidelityFX.FSR3
@ -31,53 +28,30 @@ namespace FidelityFX.FSR3
/// This loosely matches the FfxPipelineState struct from the original FSR3 codebase, wrapped in an object-oriented blanket. /// This loosely matches the FfxPipelineState struct from the original FSR3 codebase, wrapped in an object-oriented blanket.
/// These classes are responsible for loading compute shaders, managing temporary resources, binding resources to shader kernels and dispatching said shaders. /// These classes are responsible for loading compute shaders, managing temporary resources, binding resources to shader kernels and dispatching said shaders.
/// </summary> /// </summary>
internal abstract class Fsr3UpscalerPass: IDisposable
internal abstract class Fsr3UpscalerPass: FfxPassWithFlags<Fsr3Upscaler.InitializationFlags>
{ {
protected readonly Fsr3Upscaler.ContextDescription ContextDescription;
protected readonly Fsr3UpscalerResources Resources; protected readonly Fsr3UpscalerResources Resources;
protected readonly ComputeBuffer Constants; protected readonly ComputeBuffer Constants;
protected ComputeShader ComputeShader;
protected int KernelIndex;
protected CustomSampler Sampler;
protected Fsr3UpscalerPass(Fsr3Upscaler.ContextDescription contextDescription, Fsr3UpscalerResources resources, ComputeBuffer constants)
protected Fsr3UpscalerPass(in Fsr3Upscaler.ContextDescription contextDescription, Fsr3UpscalerResources resources, ComputeBuffer constants)
: base("FSR3 Upscaler", contextDescription.Flags)
{ {
ContextDescription = contextDescription;
Resources = resources; Resources = resources;
Constants = constants; Constants = constants;
} }
public virtual void Dispose()
{
}
public void ScheduleDispatch(CommandBuffer commandBuffer, Fsr3Upscaler.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY)
{
commandBuffer.BeginSample(Sampler);
DoScheduleDispatch(commandBuffer, dispatchParams, frameIndex, dispatchX, dispatchY);
commandBuffer.EndSample(Sampler);
}
protected abstract void DoScheduleDispatch(CommandBuffer commandBuffer, Fsr3Upscaler.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY);
protected void InitComputeShader(string passName, ComputeShader shader)
{
InitComputeShader(passName, shader, ContextDescription.Flags);
}
private void InitComputeShader(string passName, ComputeShader shader, Fsr3Upscaler.InitializationFlags flags)
public void ScheduleDispatch(CommandBuffer commandBuffer, in Fsr3Upscaler.DispatchDescription dispatchParams, int bufferIndex, int dispatchX, int dispatchY, int dispatchZ = 1)
{ {
if (shader == null)
using (ProfilerSample(commandBuffer))
{ {
throw new MissingReferenceException($"Shader for FSR3 Upscaler pass '{passName}' could not be loaded! Please ensure it is included in the project correctly.");
Dispatch(commandBuffer, dispatchParams, bufferIndex, dispatchX, dispatchY, dispatchZ);
} }
}
ComputeShader = shader;
KernelIndex = ComputeShader.FindKernel("CS");
Sampler = CustomSampler.Create(passName);
protected abstract void Dispatch(CommandBuffer commandBuffer, in Fsr3Upscaler.DispatchDescription dispatchParams, int bufferIndex, int dispatchX, int dispatchY, int dispatchZ);
protected override void SetupShaderKeywords()
{
bool useLut = false; bool useLut = false;
#if UNITY_2022_1_OR_NEWER // This will also work in 2020.3.43+ and 2021.3.14+ #if UNITY_2022_1_OR_NEWER // This will also work in 2020.3.43+ and 2021.3.14+
if (SystemInfo.computeSubGroupSize == 64) if (SystemInfo.computeSubGroupSize == 64)
@ -87,50 +61,46 @@ namespace FidelityFX.FSR3
#endif #endif
// This matches the permutation rules from the CreatePipeline* functions // This matches the permutation rules from the CreatePipeline* functions
if ((flags & Fsr3Upscaler.InitializationFlags.EnableHighDynamicRange) != 0) ComputeShader.EnableKeyword("FFX_FSR3UPSCALER_OPTION_HDR_COLOR_INPUT");
if ((flags & Fsr3Upscaler.InitializationFlags.EnableDisplayResolutionMotionVectors) == 0) ComputeShader.EnableKeyword("FFX_FSR3UPSCALER_OPTION_LOW_RESOLUTION_MOTION_VECTORS");
if ((flags & Fsr3Upscaler.InitializationFlags.EnableMotionVectorsJitterCancellation) != 0) ComputeShader.EnableKeyword("FFX_FSR3UPSCALER_OPTION_JITTERED_MOTION_VECTORS");
if ((flags & Fsr3Upscaler.InitializationFlags.EnableDepthInverted) != 0) ComputeShader.EnableKeyword("FFX_FSR3UPSCALER_OPTION_INVERTED_DEPTH");
if ((Flags & Fsr3Upscaler.InitializationFlags.EnableHighDynamicRange) != 0) ComputeShader.EnableKeyword("FFX_FSR3UPSCALER_OPTION_HDR_COLOR_INPUT");
if ((Flags & Fsr3Upscaler.InitializationFlags.EnableDisplayResolutionMotionVectors) == 0) ComputeShader.EnableKeyword("FFX_FSR3UPSCALER_OPTION_LOW_RESOLUTION_MOTION_VECTORS");
if ((Flags & Fsr3Upscaler.InitializationFlags.EnableMotionVectorsJitterCancellation) != 0) ComputeShader.EnableKeyword("FFX_FSR3UPSCALER_OPTION_JITTERED_MOTION_VECTORS");
if ((Flags & Fsr3Upscaler.InitializationFlags.EnableDepthInverted) != 0) ComputeShader.EnableKeyword("FFX_FSR3UPSCALER_OPTION_INVERTED_DEPTH");
if (useLut) ComputeShader.EnableKeyword("FFX_FSR3UPSCALER_OPTION_REPROJECT_USE_LANCZOS_TYPE"); if (useLut) ComputeShader.EnableKeyword("FFX_FSR3UPSCALER_OPTION_REPROJECT_USE_LANCZOS_TYPE");
if ((flags & Fsr3Upscaler.InitializationFlags.EnableFP16Usage) != 0) ComputeShader.EnableKeyword("FFX_HALF");
if ((Flags & Fsr3Upscaler.InitializationFlags.EnableFP16Usage) != 0) ComputeShader.EnableKeyword("FFX_HALF");
} }
} }
internal class Fsr3UpscalerPrepareInputsPass : Fsr3UpscalerPass
internal sealed class Fsr3UpscalerPrepareInputsPass : Fsr3UpscalerPass
{ {
public Fsr3UpscalerPrepareInputsPass(Fsr3Upscaler.ContextDescription contextDescription, Fsr3UpscalerResources resources, ComputeBuffer constants)
public Fsr3UpscalerPrepareInputsPass(in Fsr3Upscaler.ContextDescription contextDescription, Fsr3UpscalerResources resources, ComputeBuffer constants)
: base(contextDescription, resources, constants) : base(contextDescription, resources, constants)
{ {
InitComputeShader("Prepare Inputs", contextDescription.Shaders.prepareInputsPass); InitComputeShader("Prepare Inputs", contextDescription.Shaders.prepareInputsPass);
} }
protected override void DoScheduleDispatch(CommandBuffer commandBuffer, Fsr3Upscaler.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY)
protected override void Dispatch(CommandBuffer commandBuffer, in Fsr3Upscaler.DispatchDescription dispatchParams, int bufferIndex, int dispatchX, int dispatchY, int dispatchZ)
{ {
ref var color = ref dispatchParams.Color;
ref var depth = ref dispatchParams.Depth;
ref var motionVectors = ref dispatchParams.MotionVectors;
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvInputColor, color.RenderTarget, color.MipLevel, color.SubElement);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvInputDepth, depth.RenderTarget, depth.MipLevel, depth.SubElement);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvInputMotionVectors, motionVectors.RenderTarget, motionVectors.MipLevel, motionVectors.SubElement);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvInputColor, dispatchParams.Color);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvInputDepth, dispatchParams.Depth);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvInputMotionVectors, dispatchParams.MotionVectors);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavDilatedMotionVectors, Resources.DilatedVelocity); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavDilatedMotionVectors, Resources.DilatedVelocity);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavDilatedDepth, Resources.DilatedDepth); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavDilatedDepth, Resources.DilatedDepth);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavReconstructedPrevNearestDepth, Resources.ReconstructedPrevNearestDepth); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavReconstructedPrevNearestDepth, Resources.ReconstructedPrevNearestDepth);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavFarthestDepth, Fsr3ShaderIDs.UavIntermediate); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavFarthestDepth, Fsr3ShaderIDs.UavIntermediate);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavCurrentLuma, Resources.Luma[frameIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavCurrentLuma, Resources.Luma[bufferIndex]);
commandBuffer.SetComputeConstantBufferParam(ComputeShader, Fsr3ShaderIDs.CbFsr3Upscaler, Constants, 0, Marshal.SizeOf<Fsr3Upscaler.UpscalerConstants>());
commandBuffer.SetComputeConstantBufferParam<Fsr3Upscaler.UpscalerConstants>(ComputeShader, Fsr3ShaderIDs.CbFsr3Upscaler, Constants);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, 1);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, dispatchZ);
} }
} }
internal class Fsr3UpscalerLumaPyramidPass : Fsr3UpscalerPass
internal sealed class Fsr3UpscalerLumaPyramidPass : Fsr3UpscalerPass
{ {
private readonly ComputeBuffer _spdConstants; private readonly ComputeBuffer _spdConstants;
public Fsr3UpscalerLumaPyramidPass(Fsr3Upscaler.ContextDescription contextDescription, Fsr3UpscalerResources resources, ComputeBuffer constants, ComputeBuffer spdConstants)
public Fsr3UpscalerLumaPyramidPass(in Fsr3Upscaler.ContextDescription contextDescription, Fsr3UpscalerResources resources, ComputeBuffer constants, ComputeBuffer spdConstants)
: base(contextDescription, resources, constants) : base(contextDescription, resources, constants)
{ {
_spdConstants = spdConstants; _spdConstants = spdConstants;
@ -138,32 +108,32 @@ namespace FidelityFX.FSR3
InitComputeShader("Compute Luminance Pyramid", contextDescription.Shaders.lumaPyramidPass); InitComputeShader("Compute Luminance Pyramid", contextDescription.Shaders.lumaPyramidPass);
} }
protected override void DoScheduleDispatch(CommandBuffer commandBuffer, Fsr3Upscaler.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY)
protected override void Dispatch(CommandBuffer commandBuffer, in Fsr3Upscaler.DispatchDescription dispatchParams, int bufferIndex, int dispatchX, int dispatchY, int dispatchZ)
{ {
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvCurrentLuma, Resources.Luma[frameIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvCurrentLuma, Resources.Luma[bufferIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvFarthestDepth, Fsr3ShaderIDs.UavIntermediate); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvFarthestDepth, Fsr3ShaderIDs.UavIntermediate);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavSpdAtomicCount, Resources.SpdAtomicCounter); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavSpdAtomicCount, Resources.SpdAtomicCounter);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavFrameInfo, Resources.FrameInfo); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavFrameInfo, Resources.FrameInfo);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavSpdMip0, Resources.SpdMips, 0);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavSpdMip1, Resources.SpdMips, 1);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavSpdMip2, Resources.SpdMips, 2);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavSpdMip3, Resources.SpdMips, 3);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavSpdMip4, Resources.SpdMips, 4);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavSpdMip5, Resources.SpdMips, 5);
commandBuffer.SetComputeConstantBufferParam(ComputeShader, Fsr3ShaderIDs.CbFsr3Upscaler, Constants, 0, Marshal.SizeOf<Fsr3Upscaler.UpscalerConstants>());
commandBuffer.SetComputeConstantBufferParam(ComputeShader, Fsr3ShaderIDs.CbSpd, _spdConstants, 0, Marshal.SizeOf<Fsr3Upscaler.SpdConstants>());
commandBuffer.SetComputeTextureMipParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavSpdMip0, Resources.SpdMips, 0);
commandBuffer.SetComputeTextureMipParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavSpdMip1, Resources.SpdMips, 1);
commandBuffer.SetComputeTextureMipParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavSpdMip2, Resources.SpdMips, 2);
commandBuffer.SetComputeTextureMipParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavSpdMip3, Resources.SpdMips, 3);
commandBuffer.SetComputeTextureMipParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavSpdMip4, Resources.SpdMips, 4);
commandBuffer.SetComputeTextureMipParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavSpdMip5, Resources.SpdMips, 5);
commandBuffer.SetComputeConstantBufferParam<Fsr3Upscaler.UpscalerConstants>(ComputeShader, Fsr3ShaderIDs.CbFsr3Upscaler, Constants);
commandBuffer.SetComputeConstantBufferParam<Fsr3Upscaler.SpdConstants>(ComputeShader, Fsr3ShaderIDs.CbSpd, _spdConstants);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, 1);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, dispatchZ);
} }
} }
internal class Fsr3UpscalerShadingChangePyramidPass : Fsr3UpscalerPass
internal sealed class Fsr3UpscalerShadingChangePyramidPass : Fsr3UpscalerPass
{ {
private readonly ComputeBuffer _spdConstants; private readonly ComputeBuffer _spdConstants;
public Fsr3UpscalerShadingChangePyramidPass(Fsr3Upscaler.ContextDescription contextDescription, Fsr3UpscalerResources resources, ComputeBuffer constants, ComputeBuffer spdConstants)
public Fsr3UpscalerShadingChangePyramidPass(in Fsr3Upscaler.ContextDescription contextDescription, Fsr3UpscalerResources resources, ComputeBuffer constants, ComputeBuffer spdConstants)
: base(contextDescription, resources, constants) : base(contextDescription, resources, constants)
{ {
_spdConstants = spdConstants; _spdConstants = spdConstants;
@ -171,110 +141,102 @@ namespace FidelityFX.FSR3
InitComputeShader("Compute Shading Change Pyramid", contextDescription.Shaders.shadingChangePyramidPass); InitComputeShader("Compute Shading Change Pyramid", contextDescription.Shaders.shadingChangePyramidPass);
} }
protected override void DoScheduleDispatch(CommandBuffer commandBuffer, Fsr3Upscaler.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY)
protected override void Dispatch(CommandBuffer commandBuffer, in Fsr3Upscaler.DispatchDescription dispatchParams, int bufferIndex, int dispatchX, int dispatchY, int dispatchZ)
{ {
ref var exposure = ref dispatchParams.Exposure;
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvCurrentLuma, Resources.Luma[frameIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvPreviousLuma, Resources.Luma[frameIndex ^ 1]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvCurrentLuma, Resources.Luma[bufferIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvPreviousLuma, Resources.Luma[bufferIndex ^ 1]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvDilatedMotionVectors, Resources.DilatedVelocity); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvDilatedMotionVectors, Resources.DilatedVelocity);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvInputExposure, exposure.RenderTarget, exposure.MipLevel, exposure.SubElement);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvInputExposure, dispatchParams.Exposure);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavSpdAtomicCount, Resources.SpdAtomicCounter); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavSpdAtomicCount, Resources.SpdAtomicCounter);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavSpdMip0, Resources.SpdMips, 0);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavSpdMip1, Resources.SpdMips, 1);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavSpdMip2, Resources.SpdMips, 2);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavSpdMip3, Resources.SpdMips, 3);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavSpdMip4, Resources.SpdMips, 4);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavSpdMip5, Resources.SpdMips, 5);
commandBuffer.SetComputeTextureMipParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavSpdMip0, Resources.SpdMips, 0);
commandBuffer.SetComputeTextureMipParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavSpdMip1, Resources.SpdMips, 1);
commandBuffer.SetComputeTextureMipParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavSpdMip2, Resources.SpdMips, 2);
commandBuffer.SetComputeTextureMipParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavSpdMip3, Resources.SpdMips, 3);
commandBuffer.SetComputeTextureMipParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavSpdMip4, Resources.SpdMips, 4);
commandBuffer.SetComputeTextureMipParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavSpdMip5, Resources.SpdMips, 5);
commandBuffer.SetComputeConstantBufferParam(ComputeShader, Fsr3ShaderIDs.CbFsr3Upscaler, Constants, 0, Marshal.SizeOf<Fsr3Upscaler.UpscalerConstants>());
commandBuffer.SetComputeConstantBufferParam(ComputeShader, Fsr3ShaderIDs.CbSpd, _spdConstants, 0, Marshal.SizeOf<Fsr3Upscaler.SpdConstants>());
commandBuffer.SetComputeConstantBufferParam<Fsr3Upscaler.UpscalerConstants>(ComputeShader, Fsr3ShaderIDs.CbFsr3Upscaler, Constants);
commandBuffer.SetComputeConstantBufferParam<Fsr3Upscaler.SpdConstants>(ComputeShader, Fsr3ShaderIDs.CbSpd, _spdConstants);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, 1);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, dispatchZ);
} }
} }
internal class Fsr3UpscalerShadingChangePass : Fsr3UpscalerPass
internal sealed class Fsr3UpscalerShadingChangePass : Fsr3UpscalerPass
{ {
public Fsr3UpscalerShadingChangePass(Fsr3Upscaler.ContextDescription contextDescription, Fsr3UpscalerResources resources, ComputeBuffer constants)
public Fsr3UpscalerShadingChangePass(in Fsr3Upscaler.ContextDescription contextDescription, Fsr3UpscalerResources resources, ComputeBuffer constants)
: base(contextDescription, resources, constants) : base(contextDescription, resources, constants)
{ {
InitComputeShader("Compute Shading Change", contextDescription.Shaders.shadingChangePass); InitComputeShader("Compute Shading Change", contextDescription.Shaders.shadingChangePass);
} }
protected override void DoScheduleDispatch(CommandBuffer commandBuffer, Fsr3Upscaler.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY)
protected override void Dispatch(CommandBuffer commandBuffer, in Fsr3Upscaler.DispatchDescription dispatchParams, int bufferIndex, int dispatchX, int dispatchY, int dispatchZ)
{ {
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvSpdMips, Resources.SpdMips); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvSpdMips, Resources.SpdMips);
commandBuffer.SetComputeConstantBufferParam(ComputeShader, Fsr3ShaderIDs.CbFsr3Upscaler, Constants, 0, Marshal.SizeOf<Fsr3Upscaler.UpscalerConstants>());
commandBuffer.SetComputeConstantBufferParam<Fsr3Upscaler.UpscalerConstants>(ComputeShader, Fsr3ShaderIDs.CbFsr3Upscaler, Constants);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, 1);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, dispatchZ);
} }
} }
internal class Fsr3UpscalerPrepareReactivityPass : Fsr3UpscalerPass
internal sealed class Fsr3UpscalerPrepareReactivityPass : Fsr3UpscalerPass
{ {
public Fsr3UpscalerPrepareReactivityPass(Fsr3Upscaler.ContextDescription contextDescription, Fsr3UpscalerResources resources, ComputeBuffer constants)
public Fsr3UpscalerPrepareReactivityPass(in Fsr3Upscaler.ContextDescription contextDescription, Fsr3UpscalerResources resources, ComputeBuffer constants)
: base(contextDescription, resources, constants) : base(contextDescription, resources, constants)
{ {
InitComputeShader("Prepare Reactivity", contextDescription.Shaders.prepareReactivityPass); InitComputeShader("Prepare Reactivity", contextDescription.Shaders.prepareReactivityPass);
} }
protected override void DoScheduleDispatch(CommandBuffer commandBuffer, Fsr3Upscaler.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY)
protected override void Dispatch(CommandBuffer commandBuffer, in Fsr3Upscaler.DispatchDescription dispatchParams, int bufferIndex, int dispatchX, int dispatchY, int dispatchZ)
{ {
ref var exposure = ref dispatchParams.Exposure;
ref var reactive = ref dispatchParams.Reactive;
ref var tac = ref dispatchParams.TransparencyAndComposition;
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvReconstructedPrevNearestDepth, Resources.ReconstructedPrevNearestDepth); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvReconstructedPrevNearestDepth, Resources.ReconstructedPrevNearestDepth);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvDilatedMotionVectors, Resources.DilatedVelocity); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvDilatedMotionVectors, Resources.DilatedVelocity);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvDilatedDepth, Resources.DilatedDepth); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvDilatedDepth, Resources.DilatedDepth);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvReactiveMask, reactive.RenderTarget, reactive.MipLevel, reactive.SubElement);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvTransparencyAndCompositionMask, tac.RenderTarget, tac.MipLevel, tac.SubElement);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvAccumulation, Resources.Accumulation[frameIndex ^ 1]);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvReactiveMask, dispatchParams.Reactive);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvTransparencyAndCompositionMask, dispatchParams.TransparencyAndComposition);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvAccumulation, Resources.Accumulation[bufferIndex ^ 1]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvShadingChange, Fsr3ShaderIDs.UavShadingChange); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvShadingChange, Fsr3ShaderIDs.UavShadingChange);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvCurrentLuma, Resources.Luma[frameIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvInputExposure, exposure.RenderTarget, exposure.MipLevel, exposure.SubElement);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvCurrentLuma, Resources.Luma[bufferIndex]);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvInputExposure, dispatchParams.Exposure);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavAccumulation, Resources.Accumulation[frameIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavAccumulation, Resources.Accumulation[bufferIndex]);
commandBuffer.SetComputeConstantBufferParam(ComputeShader, Fsr3ShaderIDs.CbFsr3Upscaler, Constants, 0, Marshal.SizeOf<Fsr3Upscaler.UpscalerConstants>());
commandBuffer.SetComputeConstantBufferParam<Fsr3Upscaler.UpscalerConstants>(ComputeShader, Fsr3ShaderIDs.CbFsr3Upscaler, Constants);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, 1);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, dispatchZ);
} }
} }
internal class Fsr3UpscalerLumaInstabilityPass : Fsr3UpscalerPass
internal sealed class Fsr3UpscalerLumaInstabilityPass : Fsr3UpscalerPass
{ {
public Fsr3UpscalerLumaInstabilityPass(Fsr3Upscaler.ContextDescription contextDescription, Fsr3UpscalerResources resources, ComputeBuffer constants)
public Fsr3UpscalerLumaInstabilityPass(in Fsr3Upscaler.ContextDescription contextDescription, Fsr3UpscalerResources resources, ComputeBuffer constants)
: base(contextDescription, resources, constants) : base(contextDescription, resources, constants)
{ {
InitComputeShader("Compute Luminance Instability", contextDescription.Shaders.lumaInstabilityPass); InitComputeShader("Compute Luminance Instability", contextDescription.Shaders.lumaInstabilityPass);
} }
protected override void DoScheduleDispatch(CommandBuffer commandBuffer, Fsr3Upscaler.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY)
protected override void Dispatch(CommandBuffer commandBuffer, in Fsr3Upscaler.DispatchDescription dispatchParams, int bufferIndex, int dispatchX, int dispatchY, int dispatchZ)
{ {
ref var exposure = ref dispatchParams.Exposure;
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvInputExposure, exposure.RenderTarget, exposure.MipLevel, exposure.SubElement);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvInputExposure, dispatchParams.Exposure);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvDilatedReactiveMasks, Fsr3ShaderIDs.UavDilatedReactiveMasks); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvDilatedReactiveMasks, Fsr3ShaderIDs.UavDilatedReactiveMasks);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvDilatedMotionVectors, Resources.DilatedVelocity); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvDilatedMotionVectors, Resources.DilatedVelocity);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvFrameInfo, Resources.FrameInfo); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvFrameInfo, Resources.FrameInfo);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvLumaHistory, Resources.LumaHistory[frameIndex ^ 1]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvLumaHistory, Resources.LumaHistory[bufferIndex ^ 1]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvFarthestDepthMip1, Fsr3ShaderIDs.UavFarthestDepthMip1); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvFarthestDepthMip1, Fsr3ShaderIDs.UavFarthestDepthMip1);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvCurrentLuma, Resources.Luma[frameIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvCurrentLuma, Resources.Luma[bufferIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavLumaHistory, Resources.LumaHistory[frameIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavLumaHistory, Resources.LumaHistory[bufferIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavLumaInstability, Fsr3ShaderIDs.UavIntermediate); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavLumaInstability, Fsr3ShaderIDs.UavIntermediate);
commandBuffer.SetComputeConstantBufferParam(ComputeShader, Fsr3ShaderIDs.CbFsr3Upscaler, Constants, 0, Marshal.SizeOf<Fsr3Upscaler.UpscalerConstants>());
commandBuffer.SetComputeConstantBufferParam<Fsr3Upscaler.UpscalerConstants>(ComputeShader, Fsr3ShaderIDs.CbFsr3Upscaler, Constants);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, 1);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, dispatchZ);
} }
} }
internal class Fsr3UpscalerAccumulatePass : Fsr3UpscalerPass
internal sealed class Fsr3UpscalerAccumulatePass : Fsr3UpscalerPass
{ {
private const string SharpeningKeyword = "FFX_FSR3UPSCALER_OPTION_APPLY_SHARPENING"; private const string SharpeningKeyword = "FFX_FSR3UPSCALER_OPTION_APPLY_SHARPENING";
@ -282,7 +244,7 @@ namespace FidelityFX.FSR3
private readonly LocalKeyword _sharpeningKeyword; private readonly LocalKeyword _sharpeningKeyword;
#endif #endif
public Fsr3UpscalerAccumulatePass(Fsr3Upscaler.ContextDescription contextDescription, Fsr3UpscalerResources resources, ComputeBuffer constants)
public Fsr3UpscalerAccumulatePass(in Fsr3Upscaler.ContextDescription contextDescription, Fsr3UpscalerResources resources, ComputeBuffer constants)
: base(contextDescription, resources, constants) : base(contextDescription, resources, constants)
{ {
InitComputeShader("Accumulate", contextDescription.Shaders.accumulatePass); InitComputeShader("Accumulate", contextDescription.Shaders.accumulatePass);
@ -291,7 +253,7 @@ namespace FidelityFX.FSR3
#endif #endif
} }
protected override void DoScheduleDispatch(CommandBuffer commandBuffer, Fsr3Upscaler.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY)
protected override void Dispatch(CommandBuffer commandBuffer, in Fsr3Upscaler.DispatchDescription dispatchParams, int bufferIndex, int dispatchX, int dispatchY, int dispatchZ)
{ {
#if UNITY_2021_2_OR_NEWER #if UNITY_2021_2_OR_NEWER
if (dispatchParams.EnableSharpening) if (dispatchParams.EnableSharpening)
@ -305,44 +267,39 @@ namespace FidelityFX.FSR3
commandBuffer.DisableShaderKeyword(SharpeningKeyword); commandBuffer.DisableShaderKeyword(SharpeningKeyword);
#endif #endif
ref var color = ref dispatchParams.Color;
ref var exposure = ref dispatchParams.Exposure;
ref var output = ref dispatchParams.Output;
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvInputExposure, exposure.RenderTarget, exposure.MipLevel, exposure.SubElement);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvInputExposure, dispatchParams.Exposure);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvDilatedReactiveMasks, Fsr3ShaderIDs.UavDilatedReactiveMasks); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvDilatedReactiveMasks, Fsr3ShaderIDs.UavDilatedReactiveMasks);
if ((ContextDescription.Flags & Fsr3Upscaler.InitializationFlags.EnableDisplayResolutionMotionVectors) == 0)
if ((Flags & Fsr3Upscaler.InitializationFlags.EnableDisplayResolutionMotionVectors) == 0)
{ {
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvDilatedMotionVectors, Resources.DilatedVelocity); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvDilatedMotionVectors, Resources.DilatedVelocity);
} }
else else
{ {
ref var motionVectors = ref dispatchParams.MotionVectors;
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvInputMotionVectors, motionVectors.RenderTarget, motionVectors.MipLevel, motionVectors.SubElement);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvInputMotionVectors, dispatchParams.MotionVectors);
} }
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvInternalUpscaled, Resources.InternalUpscaled[frameIndex ^ 1]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvInternalUpscaled, Resources.InternalUpscaled[bufferIndex ^ 1]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvLanczosLut, Resources.LanczosLut); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvLanczosLut, Resources.LanczosLut);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvFarthestDepthMip1, Fsr3ShaderIDs.UavFarthestDepthMip1); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvFarthestDepthMip1, Fsr3ShaderIDs.UavFarthestDepthMip1);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvCurrentLuma, Resources.Luma[frameIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvCurrentLuma, Resources.Luma[bufferIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvLumaInstability, Fsr3ShaderIDs.UavIntermediate); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvLumaInstability, Fsr3ShaderIDs.UavIntermediate);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvInputColor, color.RenderTarget, color.MipLevel, color.SubElement);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvInputColor, dispatchParams.Color);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavInternalUpscaled, Resources.InternalUpscaled[frameIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavUpscaledOutput, output.RenderTarget, output.MipLevel, output.SubElement);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavInternalUpscaled, Resources.InternalUpscaled[bufferIndex]);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavUpscaledOutput, dispatchParams.Output);
commandBuffer.SetComputeConstantBufferParam(ComputeShader, Fsr3ShaderIDs.CbFsr3Upscaler, Constants, 0, Marshal.SizeOf<Fsr3Upscaler.UpscalerConstants>());
commandBuffer.SetComputeConstantBufferParam<Fsr3Upscaler.UpscalerConstants>(ComputeShader, Fsr3ShaderIDs.CbFsr3Upscaler, Constants);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, 1);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, dispatchZ);
} }
} }
internal class Fsr3UpscalerSharpenPass : Fsr3UpscalerPass
internal sealed class Fsr3UpscalerSharpenPass : Fsr3UpscalerPass
{ {
private readonly ComputeBuffer _rcasConstants; private readonly ComputeBuffer _rcasConstants;
public Fsr3UpscalerSharpenPass(Fsr3Upscaler.ContextDescription contextDescription, Fsr3UpscalerResources resources, ComputeBuffer constants, ComputeBuffer rcasConstants)
public Fsr3UpscalerSharpenPass(in Fsr3Upscaler.ContextDescription contextDescription, Fsr3UpscalerResources resources, ComputeBuffer constants, ComputeBuffer rcasConstants)
: base(contextDescription, resources, constants) : base(contextDescription, resources, constants)
{ {
_rcasConstants = rcasConstants; _rcasConstants = rcasConstants;
@ -350,27 +307,25 @@ namespace FidelityFX.FSR3
InitComputeShader("RCAS Sharpening", contextDescription.Shaders.sharpenPass); InitComputeShader("RCAS Sharpening", contextDescription.Shaders.sharpenPass);
} }
protected override void DoScheduleDispatch(CommandBuffer commandBuffer, Fsr3Upscaler.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY)
protected override void Dispatch(CommandBuffer commandBuffer, in Fsr3Upscaler.DispatchDescription dispatchParams, int bufferIndex, int dispatchX, int dispatchY, int dispatchZ)
{ {
ref var exposure = ref dispatchParams.Exposure;
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvInputExposure, exposure.RenderTarget, exposure.MipLevel, exposure.SubElement);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvRcasInput, Resources.InternalUpscaled[frameIndex]);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvInputExposure, dispatchParams.Exposure);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvRcasInput, Resources.InternalUpscaled[bufferIndex]);
ref var output = ref dispatchParams.Output;
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavUpscaledOutput, output.RenderTarget, output.MipLevel, output.SubElement);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavUpscaledOutput, dispatchParams.Output);
commandBuffer.SetComputeConstantBufferParam(ComputeShader, Fsr3ShaderIDs.CbFsr3Upscaler, Constants, 0, Marshal.SizeOf<Fsr3Upscaler.UpscalerConstants>());
commandBuffer.SetComputeConstantBufferParam(ComputeShader, Fsr3ShaderIDs.CbRcas, _rcasConstants, 0, Marshal.SizeOf<Fsr3Upscaler.RcasConstants>());
commandBuffer.SetComputeConstantBufferParam<Fsr3Upscaler.UpscalerConstants>(ComputeShader, Fsr3ShaderIDs.CbFsr3Upscaler, Constants);
commandBuffer.SetComputeConstantBufferParam<Fsr3Upscaler.RcasConstants>(ComputeShader, Fsr3ShaderIDs.CbRcas, _rcasConstants);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, 1);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, dispatchZ);
} }
} }
internal class Fsr3UpscalerGenerateReactivePass : Fsr3UpscalerPass
internal sealed class Fsr3UpscalerGenerateReactivePass : Fsr3UpscalerPass
{ {
private readonly ComputeBuffer _generateReactiveConstants; private readonly ComputeBuffer _generateReactiveConstants;
public Fsr3UpscalerGenerateReactivePass(Fsr3Upscaler.ContextDescription contextDescription, Fsr3UpscalerResources resources, ComputeBuffer generateReactiveConstants)
public Fsr3UpscalerGenerateReactivePass(in Fsr3Upscaler.ContextDescription contextDescription, Fsr3UpscalerResources resources, ComputeBuffer generateReactiveConstants)
: base(contextDescription, resources, null) : base(contextDescription, resources, null)
{ {
_generateReactiveConstants = generateReactiveConstants; _generateReactiveConstants = generateReactiveConstants;
@ -378,35 +333,30 @@ namespace FidelityFX.FSR3
InitComputeShader("Auto-Generate Reactive Mask", contextDescription.Shaders.autoGenReactivePass); InitComputeShader("Auto-Generate Reactive Mask", contextDescription.Shaders.autoGenReactivePass);
} }
protected override void DoScheduleDispatch(CommandBuffer commandBuffer, Fsr3Upscaler.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY)
protected override void Dispatch(CommandBuffer commandBuffer, in Fsr3Upscaler.DispatchDescription dispatchParams, int bufferIndex, int dispatchX, int dispatchY, int dispatchZ)
{ {
} }
public void ScheduleDispatch(CommandBuffer commandBuffer, Fsr3Upscaler.GenerateReactiveDescription dispatchParams, int dispatchX, int dispatchY)
public void ScheduleDispatch(CommandBuffer commandBuffer, in Fsr3Upscaler.GenerateReactiveDescription dispatchParams, int dispatchX, int dispatchY)
{ {
commandBuffer.BeginSample(Sampler);
ref var opaqueOnly = ref dispatchParams.ColorOpaqueOnly;
ref var color = ref dispatchParams.ColorPreUpscale;
ref var reactive = ref dispatchParams.OutReactive;
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvOpaqueOnly, opaqueOnly.RenderTarget, opaqueOnly.MipLevel, opaqueOnly.SubElement);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvInputColor, color.RenderTarget, color.MipLevel, color.SubElement);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavAutoReactive, reactive.RenderTarget, reactive.MipLevel, reactive.SubElement);
commandBuffer.SetComputeConstantBufferParam(ComputeShader, Fsr3ShaderIDs.CbGenReactive, _generateReactiveConstants, 0, Marshal.SizeOf<Fsr3Upscaler.GenerateReactiveConstants>());
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, 1);
commandBuffer.EndSample(Sampler);
using (ProfilerSample(commandBuffer))
{
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvOpaqueOnly, dispatchParams.ColorOpaqueOnly);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvInputColor, dispatchParams.ColorPreUpscale);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavAutoReactive, dispatchParams.OutReactive);
commandBuffer.SetComputeConstantBufferParam<Fsr3Upscaler.GenerateReactiveConstants>(ComputeShader, Fsr3ShaderIDs.CbGenReactive, _generateReactiveConstants);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, 1);
}
} }
} }
internal class Fsr3UpscalerTcrAutogeneratePass : Fsr3UpscalerPass
internal sealed class Fsr3UpscalerTcrAutogeneratePass : Fsr3UpscalerPass
{ {
private readonly ComputeBuffer _tcrAutogenerateConstants; private readonly ComputeBuffer _tcrAutogenerateConstants;
public Fsr3UpscalerTcrAutogeneratePass(Fsr3Upscaler.ContextDescription contextDescription, Fsr3UpscalerResources resources, ComputeBuffer constants, ComputeBuffer tcrAutogenerateConstants)
public Fsr3UpscalerTcrAutogeneratePass(in Fsr3Upscaler.ContextDescription contextDescription, Fsr3UpscalerResources resources, ComputeBuffer constants, ComputeBuffer tcrAutogenerateConstants)
: base(contextDescription, resources, constants) : base(contextDescription, resources, constants)
{ {
_tcrAutogenerateConstants = tcrAutogenerateConstants; _tcrAutogenerateConstants = tcrAutogenerateConstants;
@ -414,58 +364,50 @@ namespace FidelityFX.FSR3
InitComputeShader("Auto-Generate Transparency & Composition Mask", contextDescription.Shaders.tcrAutoGenPass); InitComputeShader("Auto-Generate Transparency & Composition Mask", contextDescription.Shaders.tcrAutoGenPass);
} }
protected override void DoScheduleDispatch(CommandBuffer commandBuffer, Fsr3Upscaler.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY)
protected override void Dispatch(CommandBuffer commandBuffer, in Fsr3Upscaler.DispatchDescription dispatchParams, int bufferIndex, int dispatchX, int dispatchY, int dispatchZ)
{ {
ref var color = ref dispatchParams.Color;
ref var motionVectors = ref dispatchParams.MotionVectors;
ref var opaqueOnly = ref dispatchParams.ColorOpaqueOnly;
ref var reactive = ref dispatchParams.Reactive;
ref var tac = ref dispatchParams.TransparencyAndComposition;
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvOpaqueOnly, opaqueOnly.RenderTarget, opaqueOnly.MipLevel, opaqueOnly.SubElement);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvInputColor, color.RenderTarget, color.MipLevel, color.SubElement);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvInputMotionVectors, motionVectors.RenderTarget, motionVectors.MipLevel, motionVectors.SubElement);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvPrevColorPreAlpha, Resources.PrevPreAlpha[frameIndex ^ 1]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvPrevColorPostAlpha, Resources.PrevPostAlpha[frameIndex ^ 1]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvReactiveMask, reactive.RenderTarget, reactive.MipLevel, reactive.SubElement);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvTransparencyAndCompositionMask, tac.RenderTarget, tac.MipLevel, tac.SubElement);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvOpaqueOnly, dispatchParams.ColorOpaqueOnly);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvInputColor, dispatchParams.Color);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvInputMotionVectors, dispatchParams.MotionVectors);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvPrevColorPreAlpha, Resources.PrevPreAlpha[bufferIndex ^ 1]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvPrevColorPostAlpha, Resources.PrevPostAlpha[bufferIndex ^ 1]);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvReactiveMask, dispatchParams.Reactive);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvTransparencyAndCompositionMask, dispatchParams.TransparencyAndComposition);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavAutoReactive, Resources.AutoReactive); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavAutoReactive, Resources.AutoReactive);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavAutoComposition, Resources.AutoComposition); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavAutoComposition, Resources.AutoComposition);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavPrevColorPreAlpha, Resources.PrevPreAlpha[frameIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavPrevColorPostAlpha, Resources.PrevPostAlpha[frameIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavPrevColorPreAlpha, Resources.PrevPreAlpha[bufferIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavPrevColorPostAlpha, Resources.PrevPostAlpha[bufferIndex]);
commandBuffer.SetComputeConstantBufferParam(ComputeShader, Fsr3ShaderIDs.CbFsr3Upscaler, Constants, 0, Marshal.SizeOf<Fsr3Upscaler.UpscalerConstants>());
commandBuffer.SetComputeConstantBufferParam(ComputeShader, Fsr3ShaderIDs.CbGenReactive, _tcrAutogenerateConstants, 0, Marshal.SizeOf<Fsr3Upscaler.GenerateReactiveConstants2>());
commandBuffer.SetComputeConstantBufferParam<Fsr3Upscaler.UpscalerConstants>(ComputeShader, Fsr3ShaderIDs.CbFsr3Upscaler, Constants);
commandBuffer.SetComputeConstantBufferParam<Fsr3Upscaler.GenerateReactiveConstants2>(ComputeShader, Fsr3ShaderIDs.CbGenReactive, _tcrAutogenerateConstants);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, 1);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, dispatchZ);
} }
} }
#if UNITY_EDITOR || DEVELOPMENT_BUILD #if UNITY_EDITOR || DEVELOPMENT_BUILD
internal class Fsr3UpscalerDebugViewPass : Fsr3UpscalerPass
internal sealed class Fsr3UpscalerDebugViewPass : Fsr3UpscalerPass
{ {
public Fsr3UpscalerDebugViewPass(Fsr3Upscaler.ContextDescription contextDescription, Fsr3UpscalerResources resources, ComputeBuffer constants)
public Fsr3UpscalerDebugViewPass(in Fsr3Upscaler.ContextDescription contextDescription, Fsr3UpscalerResources resources, ComputeBuffer constants)
: base(contextDescription, resources, constants) : base(contextDescription, resources, constants)
{ {
InitComputeShader("Debug View", contextDescription.Shaders.debugViewPass); InitComputeShader("Debug View", contextDescription.Shaders.debugViewPass);
} }
protected override void DoScheduleDispatch(CommandBuffer commandBuffer, Fsr3Upscaler.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY)
protected override void Dispatch(CommandBuffer commandBuffer, in Fsr3Upscaler.DispatchDescription dispatchParams, int bufferIndex, int dispatchX, int dispatchY, int dispatchZ)
{ {
ref var exposure = ref dispatchParams.Exposure;
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvDilatedReactiveMasks, Fsr3ShaderIDs.UavDilatedReactiveMasks); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvDilatedReactiveMasks, Fsr3ShaderIDs.UavDilatedReactiveMasks);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvDilatedMotionVectors, Resources.DilatedVelocity); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvDilatedMotionVectors, Resources.DilatedVelocity);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvDilatedDepth, Resources.DilatedDepth); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvDilatedDepth, Resources.DilatedDepth);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvInternalUpscaled, Resources.InternalUpscaled[frameIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvInputExposure, exposure.RenderTarget, exposure.MipLevel, exposure.SubElement);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvInternalUpscaled, Resources.InternalUpscaled[bufferIndex]);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvInputExposure, dispatchParams.Exposure);
ref var output = ref dispatchParams.Output;
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavUpscaledOutput, output.RenderTarget, output.MipLevel, output.SubElement);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavUpscaledOutput, dispatchParams.Output);
commandBuffer.SetComputeConstantBufferParam(ComputeShader, Fsr3ShaderIDs.CbFsr3Upscaler, Constants, 0, Marshal.SizeOf<Fsr3Upscaler.UpscalerConstants>());
commandBuffer.SetComputeConstantBufferParam<Fsr3Upscaler.UpscalerConstants>(ComputeShader, Fsr3ShaderIDs.CbFsr3Upscaler, Constants);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, 1);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, dispatchZ);
} }
} }
#endif #endif

93
Runtime/FSR3/Fsr3UpscalerResources.cs

@ -29,7 +29,7 @@ namespace FidelityFX.FSR3
/// Helper class for bundling and managing persistent resources required by the FSR3 Upscaler process. /// Helper class for bundling and managing persistent resources required by the FSR3 Upscaler process.
/// This includes lookup tables, default fallback resources and double-buffered resources that get swapped between frames. /// This includes lookup tables, default fallback resources and double-buffered resources that get swapped between frames.
/// </summary> /// </summary>
internal class Fsr3UpscalerResources
internal class Fsr3UpscalerResources: FfxResourcesBase
{ {
public Texture2D LanczosLut; public Texture2D LanczosLut;
public Texture2D DefaultExposure; public Texture2D DefaultExposure;
@ -51,63 +51,44 @@ namespace FidelityFX.FSR3
public readonly RenderTexture[] PrevPreAlpha = new RenderTexture[2]; public readonly RenderTexture[] PrevPreAlpha = new RenderTexture[2];
public readonly RenderTexture[] PrevPostAlpha = new RenderTexture[2]; public readonly RenderTexture[] PrevPostAlpha = new RenderTexture[2];
public void Create(Fsr3Upscaler.ContextDescription contextDescription)
public void Create(in Fsr3Upscaler.ContextDescription contextDescription)
{ {
// Generate the data for the LUT // Generate the data for the LUT
const int lanczos2LutWidth = 128; const int lanczos2LutWidth = 128;
float[] lanczos2Weights = new float[lanczos2LutWidth];
for (int currentLanczosWidthIndex = 0; currentLanczosWidthIndex < lanczos2LutWidth; ++currentLanczosWidthIndex)
{
float x = 2.0f * currentLanczosWidthIndex / (lanczos2LutWidth - 1);
float y = Fsr3Upscaler.Lanczos2(x);
lanczos2Weights[currentLanczosWidthIndex] = y;
}
float[] lanczos2Weights = FfxUtils.GenerateLanczos2Table(lanczos2LutWidth);
Vector2Int maxRenderSize = contextDescription.MaxRenderSize; Vector2Int maxRenderSize = contextDescription.MaxRenderSize;
Vector2Int maxRenderSizeDiv2 = maxRenderSize / 2; Vector2Int maxRenderSizeDiv2 = maxRenderSize / 2;
// Resource FSR3UPSCALER_LanczosLutData: FFX_RESOURCE_USAGE_READ_ONLY, FFX_SURFACE_FORMAT_R16_SNORM, FFX_RESOURCE_FLAGS_NONE // Resource FSR3UPSCALER_LanczosLutData: FFX_RESOURCE_USAGE_READ_ONLY, FFX_SURFACE_FORMAT_R16_SNORM, FFX_RESOURCE_FLAGS_NONE
// R16_SNorm textures are not supported by Unity on most platforms, strangely enough. So instead we use R32_SFloat and upload pre-normalized float data. // R16_SNorm textures are not supported by Unity on most platforms, strangely enough. So instead we use R32_SFloat and upload pre-normalized float data.
LanczosLut = new Texture2D(lanczos2LutWidth, 1, GraphicsFormat.R32_SFloat, TextureCreationFlags.None) { name = "FSR3UPSCALER_LanczosLutData" };
LanczosLut.SetPixelData(lanczos2Weights, 0);
LanczosLut.Apply();
LanczosLut = CreateLookup("FSR3UPSCALER_LanczosLutData", new Vector2Int(lanczos2LutWidth, 1), GraphicsFormat.R32_SFloat, lanczos2Weights);
// Resource FSR3UPSCALER_DefaultReactivityMask: FFX_RESOURCE_USAGE_READ_ONLY, FFX_SURFACE_FORMAT_R8_UNORM, FFX_RESOURCE_FLAGS_NONE // Resource FSR3UPSCALER_DefaultReactivityMask: FFX_RESOURCE_USAGE_READ_ONLY, FFX_SURFACE_FORMAT_R8_UNORM, FFX_RESOURCE_FLAGS_NONE
DefaultReactive = new Texture2D(1, 1, GraphicsFormat.R8_UNorm, TextureCreationFlags.None) { name = "FSR3UPSCALER_DefaultReactivityMask" };
DefaultReactive.SetPixel(0, 0, Color.clear);
DefaultReactive.Apply();
DefaultReactive = CreateLookup("FSR3UPSCALER_DefaultReactivityMask", GraphicsFormat.R8_UNorm, Color.clear);
// Resource FSR3UPSCALER_DefaultExposure: FFX_RESOURCE_USAGE_READ_ONLY, FFX_SURFACE_FORMAT_R32G32_FLOAT, FFX_RESOURCE_FLAGS_NONE // Resource FSR3UPSCALER_DefaultExposure: FFX_RESOURCE_USAGE_READ_ONLY, FFX_SURFACE_FORMAT_R32G32_FLOAT, FFX_RESOURCE_FLAGS_NONE
DefaultExposure = new Texture2D(1, 1, GraphicsFormat.R32G32_SFloat, TextureCreationFlags.None) { name = "FSR3UPSCALER_DefaultExposure" };
DefaultExposure.SetPixel(0, 0, Color.clear);
DefaultExposure.Apply();
DefaultExposure = CreateLookup("FSR3UPSCALER_DefaultExposure", GraphicsFormat.R32G32_SFloat, Color.clear);
// Resource FSR3UPSCALER_SpdAtomicCounter: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R32_UINT, FFX_RESOURCE_FLAGS_ALIASABLE // Resource FSR3UPSCALER_SpdAtomicCounter: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R32_UINT, FFX_RESOURCE_FLAGS_ALIASABLE
// Despite what the original FSR3 codebase says, this resource really isn't aliasable. Resetting this counter to 0 every frame breaks auto-exposure on MacOS Metal. // Despite what the original FSR3 codebase says, this resource really isn't aliasable. Resetting this counter to 0 every frame breaks auto-exposure on MacOS Metal.
SpdAtomicCounter = new RenderTexture(1, 1, 0, GraphicsFormat.R32_UInt) { name = "FSR3UPSCALER_SpdAtomicCounter", enableRandomWrite = true };
SpdAtomicCounter.Create();
SpdAtomicCounter = CreateResource("FSR3UPSCALER_SpdAtomicCounter", Vector2Int.one, GraphicsFormat.R32_UInt);
// Resource FSR3UPSCALER_SpdMips: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R16G16_FLOAT, FFX_RESOURCE_FLAGS_ALIASABLE // Resource FSR3UPSCALER_SpdMips: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R16G16_FLOAT, FFX_RESOURCE_FLAGS_ALIASABLE
// This is a rather special case: it's an aliasable resource, but because we require a mipmap chain and bind specific mip levels per shader, we can't easily use temporary RTs for this. // This is a rather special case: it's an aliasable resource, but because we require a mipmap chain and bind specific mip levels per shader, we can't easily use temporary RTs for this.
int mipCount = 1 + Mathf.FloorToInt(Mathf.Log(Math.Max(maxRenderSizeDiv2.x, maxRenderSizeDiv2.y), 2.0f));
SpdMips = new RenderTexture(maxRenderSizeDiv2.x, maxRenderSizeDiv2.y, 0, GraphicsFormat.R16G16_SFloat, mipCount) { name = "FSR3UPSCALER_SpdMips", enableRandomWrite = true, useMipMap = true, autoGenerateMips = false };
SpdMips.Create();
SpdMips = CreateResourceMips("FSR3UPSCALER_SpdMips", maxRenderSizeDiv2, GraphicsFormat.R16G16_SFloat);
// Resource FSR3UPSCALER_DilatedVelocity: FFX_RESOURCE_USAGE_RENDERTARGET | FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R16G16_FLOAT, FFX_RESOURCE_FLAGS_NONE // Resource FSR3UPSCALER_DilatedVelocity: FFX_RESOURCE_USAGE_RENDERTARGET | FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R16G16_FLOAT, FFX_RESOURCE_FLAGS_NONE
DilatedVelocity = new RenderTexture(maxRenderSize.x, maxRenderSize.y, 0, GraphicsFormat.R16G16_SFloat) { name = "FSR3UPSCALER_DilatedVelocity", enableRandomWrite = true };
DilatedVelocity.Create();
DilatedVelocity = CreateResource("FSR3UPSCALER_DilatedVelocity", maxRenderSize, GraphicsFormat.R16G16_SFloat);
// Resource FSR3UPSCALER_DilatedDepth: FFX_RESOURCE_USAGE_RENDERTARGET | FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R32_FLOAT, FFX_RESOURCE_FLAGS_NONE // Resource FSR3UPSCALER_DilatedDepth: FFX_RESOURCE_USAGE_RENDERTARGET | FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R32_FLOAT, FFX_RESOURCE_FLAGS_NONE
DilatedDepth = new RenderTexture(maxRenderSize.x, maxRenderSize.y, 0, GraphicsFormat.R32_SFloat) { name = "FSR3UPSCALER_DilatedDepth", enableRandomWrite = true };
DilatedDepth.Create();
DilatedDepth = CreateResource("FSR3UPSCALER_DilatedDepth", maxRenderSize, GraphicsFormat.R32_SFloat);
// Resource FSR3UPSCALER_ReconstructedPrevNearestDepth: FFX_RESOURCE_USAGE_RENDERTARGET | FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R32_UINT, FFX_RESOURCE_FLAGS_NONE // Resource FSR3UPSCALER_ReconstructedPrevNearestDepth: FFX_RESOURCE_USAGE_RENDERTARGET | FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R32_UINT, FFX_RESOURCE_FLAGS_NONE
ReconstructedPrevNearestDepth = new RenderTexture(maxRenderSize.x, maxRenderSize.y, 0, GraphicsFormat.R32_UInt) { name = "FSR3UPSCALER_ReconstructedPrevNearestDepth", enableRandomWrite = true };
ReconstructedPrevNearestDepth.Create();
ReconstructedPrevNearestDepth = CreateResource("FSR3UPSCALER_ReconstructedPrevNearestDepth", maxRenderSize, GraphicsFormat.R32_UInt);
// Resource FSR3UPSCALER_FrameInfo: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R32G32B32A32_FLOAT, FFX_RESOURCE_FLAGS_NONE // Resource FSR3UPSCALER_FrameInfo: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R32G32B32A32_FLOAT, FFX_RESOURCE_FLAGS_NONE
FrameInfo = new RenderTexture(1, 1, 0, GraphicsFormat.R32G32B32A32_SFloat) { name = "FSR3UPSCALER_FrameInfo", enableRandomWrite = true };
FrameInfo.Create();
FrameInfo = CreateResource("FSR3UPSCALER_FrameInfo", Vector2Int.one, GraphicsFormat.R32G32B32A32_SFloat);
// Resources FSR3UPSCALER_Accumulation1/2: FFX_RESOURCE_USAGE_RENDERTARGET | FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R8_UNORM, FFX_RESOURCE_FLAGS_NONE // Resources FSR3UPSCALER_Accumulation1/2: FFX_RESOURCE_USAGE_RENDERTARGET | FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R8_UNORM, FFX_RESOURCE_FLAGS_NONE
CreateDoubleBufferedResource(Accumulation, "FSR3UPSCALER_Accumulation", maxRenderSize, GraphicsFormat.R8_UNorm); CreateDoubleBufferedResource(Accumulation, "FSR3UPSCALER_Accumulation", maxRenderSize, GraphicsFormat.R8_UNorm);
@ -122,15 +103,13 @@ namespace FidelityFX.FSR3
CreateDoubleBufferedResource(LumaHistory, "FSR3UPSCALER_LumaHistory", maxRenderSize, GraphicsFormat.R16G16B16A16_SFloat); CreateDoubleBufferedResource(LumaHistory, "FSR3UPSCALER_LumaHistory", maxRenderSize, GraphicsFormat.R16G16B16A16_SFloat);
} }
public void CreateTcrAutogenResources(Fsr3Upscaler.ContextDescription contextDescription)
public void CreateTcrAutogenResources(in Fsr3Upscaler.ContextDescription contextDescription)
{ {
// Resource FSR3UPSCALER_AutoReactive: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R8_UNORM, FFX_RESOURCE_FLAGS_NONE // Resource FSR3UPSCALER_AutoReactive: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R8_UNORM, FFX_RESOURCE_FLAGS_NONE
AutoReactive = new RenderTexture(contextDescription.MaxRenderSize.x, contextDescription.MaxRenderSize.y, 0, GraphicsFormat.R8_UNorm) { name = "FSR3UPSCALER_AutoReactive", enableRandomWrite = true };
AutoReactive.Create();
AutoReactive = CreateResource("FSR3UPSCALER_AutoReactive", contextDescription.MaxRenderSize, GraphicsFormat.R8_UNorm);
// Resource FSR3UPSCALER_AutoComposition: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R8_UNORM, FFX_RESOURCE_FLAGS_NONE // Resource FSR3UPSCALER_AutoComposition: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R8_UNORM, FFX_RESOURCE_FLAGS_NONE
AutoComposition = new RenderTexture(contextDescription.MaxRenderSize.x, contextDescription.MaxRenderSize.y, 0, GraphicsFormat.R8_UNorm) { name = "FSR3UPSCALER_AutoComposition", enableRandomWrite = true };
AutoComposition.Create();
AutoComposition = CreateResource("FSR3UPSCALER_AutoComposition", contextDescription.MaxRenderSize, GraphicsFormat.R8_UNorm);
// Resources FSR3UPSCALER_PrevPreAlpha0/1: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R11G11B10_FLOAT, FFX_RESOURCE_FLAGS_NONE // Resources FSR3UPSCALER_PrevPreAlpha0/1: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R11G11B10_FLOAT, FFX_RESOURCE_FLAGS_NONE
CreateDoubleBufferedResource(PrevPreAlpha, "FSR3UPSCALER_PrevPreAlpha", contextDescription.MaxRenderSize, GraphicsFormat.B10G11R11_UFloatPack32); CreateDoubleBufferedResource(PrevPreAlpha, "FSR3UPSCALER_PrevPreAlpha", contextDescription.MaxRenderSize, GraphicsFormat.B10G11R11_UFloatPack32);
@ -141,7 +120,7 @@ namespace FidelityFX.FSR3
// Set up shared aliasable resources, i.e. temporary render textures // Set up shared aliasable resources, i.e. temporary render textures
// These do not need to persist between frames, but they do need to be available between passes // These do not need to persist between frames, but they do need to be available between passes
public static void CreateAliasableResources(CommandBuffer commandBuffer, Fsr3Upscaler.ContextDescription contextDescription, Fsr3Upscaler.DispatchDescription dispatchParams)
public static void CreateAliasableResources(CommandBuffer commandBuffer, in Fsr3Upscaler.ContextDescription contextDescription)
{ {
Vector2Int maxUpscaleSize = contextDescription.MaxUpscaleSize; Vector2Int maxUpscaleSize = contextDescription.MaxUpscaleSize;
Vector2Int maxRenderSize = contextDescription.MaxRenderSize; Vector2Int maxRenderSize = contextDescription.MaxRenderSize;
@ -173,15 +152,6 @@ namespace FidelityFX.FSR3
commandBuffer.ReleaseTemporaryRT(Fsr3ShaderIDs.UavIntermediate); commandBuffer.ReleaseTemporaryRT(Fsr3ShaderIDs.UavIntermediate);
} }
private static void CreateDoubleBufferedResource(RenderTexture[] resource, string name, Vector2Int size, GraphicsFormat format)
{
for (int i = 0; i < 2; ++i)
{
resource[i] = new RenderTexture(size.x, size.y, 0, format) { name = name + (i + 1), enableRandomWrite = true };
resource[i].Create();
}
}
public void Destroy() public void Destroy()
{ {
DestroyTcrAutogenResources(); DestroyTcrAutogenResources();
@ -210,36 +180,5 @@ namespace FidelityFX.FSR3
DestroyResource(ref AutoComposition); DestroyResource(ref AutoComposition);
DestroyResource(ref AutoReactive); DestroyResource(ref AutoReactive);
} }
private static void DestroyResource(ref Texture2D resource)
{
if (resource == null)
return;
#if UNITY_EDITOR
if (Application.isPlaying && !UnityEditor.EditorApplication.isPaused)
UnityEngine.Object.Destroy(resource);
else
UnityEngine.Object.DestroyImmediate(resource);
#else
UnityEngine.Object.Destroy(resource);
#endif
resource = null;
}
private static void DestroyResource(ref RenderTexture resource)
{
if (resource == null)
return;
resource.Release();
resource = null;
}
private static void DestroyResource(RenderTexture[] resource)
{
for (int i = 0; i < resource.Length; ++i)
DestroyResource(ref resource[i]);
}
} }
} }

8
Runtime/FrameInterpolation.meta

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: bd29728b817dd3f478a426dcb34e360b
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

162
Runtime/FrameInterpolation/FrameInterpolation.cs

@ -0,0 +1,162 @@
using System;
using System.Runtime.InteropServices;
using UnityEngine;
using UnityEngine.Experimental.Rendering;
namespace FidelityFX.FrameGen
{
public static class FrameInterpolation
{
public static FrameInterpolationContext CreateContext(Vector2Int displaySize, Vector2Int maxRenderSize, FrameInterpolationShaders shaders, GraphicsFormat backBufferFormat, InitializationFlags flags = 0)
{
if (SystemInfo.usesReversedZBuffer)
flags |= InitializationFlags.EnableDepthInverted;
else
flags &= ~InitializationFlags.EnableDepthInverted;
var contextDescription = new ContextDescription
{
flags = flags,
maxRenderSize = maxRenderSize,
displaySize = displaySize,
backBufferFormat = backBufferFormat,
shaders = shaders,
};
Debug.Log($"Setting up Frame Interpolation with render size: {maxRenderSize.x}x{maxRenderSize.y}, display size: {displaySize.x}x{displaySize.y}, backbuffer format: {backBufferFormat}, flags: {flags}");
var context = new FrameInterpolationContext();
context.Create(contextDescription);
return context;
}
public struct ContextDescription
{
public InitializationFlags flags;
public Vector2Int maxRenderSize;
public Vector2Int displaySize;
public GraphicsFormat backBufferFormat;
public FrameInterpolationShaders shaders;
}
public struct PrepareDescription
{
public DispatchFlags flags;
public Vector2Int renderSize;
public Vector2 jitterOffset;
public Vector2 motionVectorScale;
public float frameTimeDelta;
public float cameraNear;
public float cameraFar;
public float viewSpaceToMetersFactor;
public float cameraFovAngleVertical;
public ResourceView depth;
public ResourceView motionVectors;
public ulong frameID;
}
public struct DispatchDescription
{
public DispatchFlags flags;
public Vector2Int displaySize;
public Vector2Int renderSize;
public ResourceView currentBackBuffer;
public ResourceView currentBackBuffer_HUDLess; // Optional
public ResourceView output;
public RectInt interpolationRect;
public ResourceView opticalFlowVector;
public ResourceView opticalFlowSceneChangeDetection;
public Vector2Int opticalFlowBufferSize;
public Vector2 opticalFlowScale;
public int opticalFlowBlockSize;
public float cameraNear;
public float cameraFar;
public float cameraFovAngleVertical;
public float viewSpaceToMetersFactor;
public float frameTimeDelta;
public bool reset;
public BackbufferTransferFunction backbufferTransferFunction;
public Vector2 minMaxLuminance;
public ulong frameID;
public ResourceView InterpolationSource
{
get
{
if (currentBackBuffer_HUDLess.IsValid)
return currentBackBuffer_HUDLess;
return currentBackBuffer;
}
}
}
[Flags]
public enum InitializationFlags
{
EnableDepthInverted = 1 << 0,
EnableDepthInfinite = 1 << 1,
EnableHDRColorInput = 1 << 3,
EnableDisplayResolutionMotionVectors = 1 << 4,
EnableJitterMotionVectors = 1 << 5,
EnableAsyncSupport = 1 << 6,
}
[Flags]
public enum DispatchFlags
{
DrawDebugTearLines = 1 << 0,
DrawDebugResetIndicators = 1 << 1,
DrawDebugView = 1 << 2,
}
[Serializable, StructLayout(LayoutKind.Sequential)]
internal struct Constants
{
public Vector2Int renderSize;
public Vector2Int displaySize;
public Vector2 displaySizeRcp;
public float cameraNear;
public float cameraFar;
public Vector2Int upscalerTargetSize;
public int mode;
public int reset;
public Vector4 deviceToViewDepth;
public float deltaTime;
public int HUDLessAttachedFactor;
public Vector2 unused;
public Vector2 opticalFlowScale;
public int opticalFlowBlockSize;
public uint dispatchFlags;
public Vector2Int maxRenderSize;
public int opticalFlowHalfResMode;
public int numInstances;
public Vector2Int interpolationRectBase;
public Vector2Int interpolationRectSize;
public Vector3 debugBarColor;
public uint backBufferTransferFunction;
public Vector2 minMaxLuminance;
public float tanHalfFOV;
public float pad;
public Vector2 jitter;
public Vector2 motionVectorScale;
}
}
}

11
Runtime/FrameInterpolation/FrameInterpolation.cs.meta

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 463b39d7227b18b40946829a3c68a462
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

176
Runtime/FrameInterpolation/FrameInterpolationAssets.cs

@ -0,0 +1,176 @@
// Copyright (c) 2024 Nico de Poel
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using UnityEngine;
namespace FidelityFX.FrameGen
{
/// <summary>
/// Scriptable object containing all shader resources required by FidelityFX Frame Interpolation.
/// These can be stored in an asset file and referenced from a scene or prefab, avoiding the need to load the shaders from a Resources folder.
/// </summary>
[CreateAssetMenu(fileName = "Frame Interpolation Assets", menuName = "FidelityFX/Frame Interpolation Assets", order = 1112)]
public class FrameInterpolationAssets : ScriptableObject
{
public FrameInterpolationShaders shaders;
#if UNITY_EDITOR
private void Reset()
{
shaders = new FrameInterpolationShaders
{
reconstructAndDilate = FindComputeShader("ffx_frameinterpolation_reconstruct_and_dilate_pass"),
setup = FindComputeShader("ffx_frameinterpolation_setup_pass"),
reconstructPreviousDepth = FindComputeShader("ffx_frameinterpolation_reconstruct_previous_depth_pass"),
gameMotionVectorField = FindComputeShader("ffx_frameinterpolation_game_motion_vector_field_pass"),
opticalFlowVectorField = FindComputeShader("ffx_frameinterpolation_optical_flow_vector_field_pass"),
disocclusionMask = FindComputeShader("ffx_frameinterpolation_disocclusion_mask_pass"),
interpolation = FindComputeShader("ffx_frameinterpolation_pass"),
inpaintingPyramid = FindComputeShader("ffx_frameinterpolation_compute_inpainting_pyramid_pass"),
inpainting = FindComputeShader("ffx_frameinterpolation_inpainting_pass"),
gameVectorFieldInpaintingPyramid = FindComputeShader("ffx_frameinterpolation_compute_game_vector_field_inpainting_pyramid_pass"),
debugView = FindComputeShader("ffx_frameinterpolation_debug_view_pass"),
};
}
private static ComputeShader FindComputeShader(string name)
{
string[] assetGuids = UnityEditor.AssetDatabase.FindAssets($"t:ComputeShader {name}");
if (assetGuids == null || assetGuids.Length == 0)
return null;
string assetPath = UnityEditor.AssetDatabase.GUIDToAssetPath(assetGuids[0]);
return UnityEditor.AssetDatabase.LoadAssetAtPath<ComputeShader>(assetPath);
}
#endif
}
/// <summary>
/// All the compute shaders used by Frame Interpolation.
/// </summary>
[System.Serializable]
public class FrameInterpolationShaders
{
/// <summary>
/// The compute shader used by the reconstruct and dilate pass.
/// </summary>
public ComputeShader reconstructAndDilate;
/// <summary>
/// The compute shader used by the setup pass.
/// </summary>
public ComputeShader setup;
/// <summary>
/// The compute shader used by the reconstruct previous depth pass.
/// </summary>
public ComputeShader reconstructPreviousDepth;
/// <summary>
/// The compute shader used by the game motion vector field pass.
/// </summary>
public ComputeShader gameMotionVectorField;
/// <summary>
/// The compute shader used by the optical flow vector field pass.
/// </summary>
public ComputeShader opticalFlowVectorField;
/// <summary>
/// The compute shader used by the disocclusion mask pass.
/// </summary>
public ComputeShader disocclusionMask;
/// <summary>
/// The compute shader used by the interpolation pass.
/// </summary>
public ComputeShader interpolation;
/// <summary>
/// The compute shader used by the inpainting pyramid pass.
/// </summary>
public ComputeShader inpaintingPyramid;
/// <summary>
/// The compute shader used by the inpainting pass.
/// </summary>
public ComputeShader inpainting;
/// <summary>
/// The compute shader used by the game vector field inpainting pyramid pass.
/// </summary>
public ComputeShader gameVectorFieldInpaintingPyramid;
/// <summary>
/// The compute shader used by the debug view pass.
/// </summary>
public ComputeShader debugView;
/// <summary>
/// Returns a copy of this class and its contents.
/// </summary>
public FrameInterpolationShaders Clone()
{
return (FrameInterpolationShaders)MemberwiseClone();
}
/// <summary>
/// Returns a copy of this class with clones of all its shaders.
/// This can be useful if you're running multiple Frame Interpolation instances with different shader configurations.
/// Be sure to clean up these clones through Dispose once you're done with them.
/// </summary>
public FrameInterpolationShaders DeepCopy()
{
return new FrameInterpolationShaders
{
reconstructAndDilate = Object.Instantiate(reconstructAndDilate),
setup = Object.Instantiate(setup),
reconstructPreviousDepth = Object.Instantiate(reconstructPreviousDepth),
gameMotionVectorField = Object.Instantiate(gameMotionVectorField),
opticalFlowVectorField = Object.Instantiate(opticalFlowVectorField),
disocclusionMask = Object.Instantiate(disocclusionMask),
interpolation = Object.Instantiate(interpolation),
inpaintingPyramid = Object.Instantiate(inpaintingPyramid),
inpainting = Object.Instantiate(inpainting),
gameVectorFieldInpaintingPyramid = Object.Instantiate(gameVectorFieldInpaintingPyramid),
debugView = Object.Instantiate(debugView),
};
}
/// <summary>
/// Destroy all the shaders within this instance.
/// Use this only on clones created through DeepCopy.
/// </summary>
public void Dispose()
{
Object.Destroy(debugView);
Object.Destroy(gameVectorFieldInpaintingPyramid);
Object.Destroy(inpainting);
Object.Destroy(inpaintingPyramid);
Object.Destroy(interpolation);
Object.Destroy(disocclusionMask);
Object.Destroy(opticalFlowVectorField);
Object.Destroy(gameMotionVectorField);
Object.Destroy(reconstructPreviousDepth);
Object.Destroy(setup);
Object.Destroy(reconstructAndDilate);
}
}
}

11
Runtime/FrameInterpolation/FrameInterpolationAssets.cs.meta

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1f0e52bd03044d74f8e7ea17af3c8d7b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

260
Runtime/FrameInterpolation/FrameInterpolationContext.cs

@ -0,0 +1,260 @@
using System;
using System.Runtime.InteropServices;
using UnityEngine;
using UnityEngine.Assertions;
using UnityEngine.Profiling;
using UnityEngine.Rendering;
namespace FidelityFX.FrameGen
{
public class FrameInterpolationContext: FfxContextBase
{
private FrameInterpolation.ContextDescription _contextDescription;
private FrameInterpolationReconstructAndDilatePass _reconstructAndDilatePass;
private FrameInterpolationSetupPass _setupPass;
private FrameInterpolationReconstructPreviousDepthPass _reconstructPreviousDepthPass;
private FrameInterpolationGameMotionVectorFieldPass _gameMotionVectorFieldPass;
private FrameInterpolationOpticalFlowVectorFieldPass _opticalFlowVectorFieldPass;
private FrameInterpolationDisocclusionMaskPass _disocclusionMaskPass;
private FrameInterpolationInterpolationPass _interpolationPass;
private FrameInterpolationInpaintingPyramidPass _inpaintingPyramidPass;
private FrameInterpolationInpaintingPass _inpaintingPass;
private FrameInterpolationGameVectorFieldInpaintingPyramidPass _gameVectorFieldInpaintingPyramidPass;
private FrameInterpolationDebugViewPass _debugViewPass;
private readonly FrameInterpolationResources _resources = new FrameInterpolationResources();
private readonly ConstantsBuffer<FrameInterpolation.Constants> _frameInterpolationConstants = new ConstantsBuffer<FrameInterpolation.Constants>();
private readonly ConstantsBuffer<FfxSpd.SpdConstants> _spdConstants = new ConstantsBuffer<FfxSpd.SpdConstants>();
private readonly CustomSampler _sampler = CustomSampler.Create("Frame Interpolation");
private readonly CustomSampler _prepareSampler = CustomSampler.Create("Frame Interpolation - Prepare");
private bool _firstExecution;
private bool _asyncSupported;
private ulong _previousFrameID;
public void Create(in FrameInterpolation.ContextDescription contextDescription)
{
_contextDescription = contextDescription;
_frameInterpolationConstants.Create();
_spdConstants.Create();
_firstExecution = true;
_previousFrameID = 0;
_asyncSupported = (_contextDescription.flags & FrameInterpolation.InitializationFlags.EnableAsyncSupport) == FrameInterpolation.InitializationFlags.EnableAsyncSupport;
ref var constants = ref _frameInterpolationConstants.Value;
constants.maxRenderSize = _contextDescription.maxRenderSize;
constants.displaySize = _contextDescription.displaySize;
constants.displaySizeRcp.x = 1.0f / _contextDescription.displaySize.x;
constants.displaySizeRcp.y = 1.0f / _contextDescription.displaySize.y;
constants.interpolationRectBase = Vector2Int.zero;
constants.interpolationRectSize = _contextDescription.displaySize;
_resources.Create(_contextDescription);
CreatePasses();
}
private void CreatePasses()
{
_reconstructAndDilatePass = new FrameInterpolationReconstructAndDilatePass(_contextDescription, _resources, _frameInterpolationConstants);
_setupPass = new FrameInterpolationSetupPass(_contextDescription, _resources, _frameInterpolationConstants);
_reconstructPreviousDepthPass = new FrameInterpolationReconstructPreviousDepthPass(_contextDescription, _resources, _frameInterpolationConstants);
_gameMotionVectorFieldPass = new FrameInterpolationGameMotionVectorFieldPass(_contextDescription, _resources, _frameInterpolationConstants);
_opticalFlowVectorFieldPass = new FrameInterpolationOpticalFlowVectorFieldPass(_contextDescription, _resources, _frameInterpolationConstants);
_disocclusionMaskPass = new FrameInterpolationDisocclusionMaskPass(_contextDescription, _resources, _frameInterpolationConstants);
_interpolationPass = new FrameInterpolationInterpolationPass(_contextDescription, _resources, _frameInterpolationConstants);
_inpaintingPyramidPass = new FrameInterpolationInpaintingPyramidPass(_contextDescription, _resources, _frameInterpolationConstants, _spdConstants);
_inpaintingPass = new FrameInterpolationInpaintingPass(_contextDescription, _resources, _frameInterpolationConstants);
_gameVectorFieldInpaintingPyramidPass = new FrameInterpolationGameVectorFieldInpaintingPyramidPass(_contextDescription, _resources, _frameInterpolationConstants, _spdConstants);
_debugViewPass = new FrameInterpolationDebugViewPass(_contextDescription, _resources, _frameInterpolationConstants);
}
public void Destroy()
{
DestroyPass(ref _debugViewPass);
DestroyPass(ref _gameVectorFieldInpaintingPyramidPass);
DestroyPass(ref _inpaintingPass);
DestroyPass(ref _inpaintingPyramidPass);
DestroyPass(ref _interpolationPass);
DestroyPass(ref _disocclusionMaskPass);
DestroyPass(ref _opticalFlowVectorFieldPass);
DestroyPass(ref _gameMotionVectorFieldPass);
DestroyPass(ref _reconstructPreviousDepthPass);
DestroyPass(ref _setupPass);
DestroyPass(ref _reconstructAndDilatePass);
_resources.Destroy();
_spdConstants.Destroy();
_frameInterpolationConstants.Destroy();
}
public void Prepare(CommandBuffer commandBuffer, in FrameInterpolation.PrepareDescription prepareDescription)
{
commandBuffer.BeginSample(_prepareSampler);
int doubleBufferId = _asyncSupported ? (int)(prepareDescription.frameID & 1) : 0;
ref var constants = ref _frameInterpolationConstants.Value;
constants.renderSize = prepareDescription.renderSize;
constants.jitter = prepareDescription.jitterOffset;
Vector2Int motionVectorsTargetSize = (_contextDescription.flags & FrameInterpolation.InitializationFlags.EnableDisplayResolutionMotionVectors) != 0 ? constants.displaySize : constants.renderSize;
constants.motionVectorScale.x = prepareDescription.motionVectorScale.x / motionVectorsTargetSize.x;
constants.motionVectorScale.y = prepareDescription.motionVectorScale.y / motionVectorsTargetSize.y;
_frameInterpolationConstants.UpdateBufferData(commandBuffer);
Assert.IsTrue(prepareDescription.depth.IsValid);
Assert.IsTrue(prepareDescription.motionVectors.IsValid);
// clear estimated depth resources
{
bool inverted = (_contextDescription.flags & FrameInterpolation.InitializationFlags.EnableDepthInverted) == FrameInterpolation.InitializationFlags.EnableDepthInverted;
commandBuffer.SetRenderTarget(_resources.ReconstructedDepth[doubleBufferId]);
commandBuffer.ClearRenderTarget(false, true, inverted ? Color.clear : Color.white);
}
int renderDispatchSizeX = (prepareDescription.renderSize.x + 7) / 8;
int renderDispatchSizeY = (prepareDescription.renderSize.y + 7) / 8;
_reconstructAndDilatePass.ScheduleDispatch(commandBuffer, prepareDescription, doubleBufferId, renderDispatchSizeX, renderDispatchSizeY);
commandBuffer.EndSample(_prepareSampler);
}
public void Dispatch(CommandBuffer commandBuffer, in FrameInterpolation.DispatchDescription dispatchDescription)
{
commandBuffer.BeginSample(_sampler);
bool reset = _firstExecution || dispatchDescription.reset;
_firstExecution = false;
Assert.IsTrue(!_asyncSupported || reset || dispatchDescription.frameID > _previousFrameID,
"When async support is enabled, and the reset flag is not set, frame ID must increment in each dispatch.");
bool frameIdDecreased = dispatchDescription.frameID < _previousFrameID;
bool frameIdSkipped = (dispatchDescription.frameID - _previousFrameID) > 1;
bool disjointFrameId = frameIdDecreased || frameIdSkipped;
_previousFrameID = dispatchDescription.frameID;
ref var constants = ref _frameInterpolationConstants.Value;
constants.renderSize = dispatchDescription.renderSize;
constants.displaySize = dispatchDescription.displaySize;
constants.displaySizeRcp.x = 1.0f / dispatchDescription.displaySize.x;
constants.displaySizeRcp.y = 1.0f / dispatchDescription.displaySize.y;
constants.upscalerTargetSize = dispatchDescription.interpolationRect.size;
constants.mode = 0;
constants.reset = (reset || disjointFrameId) ? 1 : 0;
constants.deltaTime = dispatchDescription.frameTimeDelta;
constants.HUDLessAttachedFactor = dispatchDescription.currentBackBuffer_HUDLess.IsValid ? 1 : 0;
constants.opticalFlowScale = dispatchDescription.opticalFlowScale;
constants.opticalFlowBlockSize = dispatchDescription.opticalFlowBlockSize;
constants.dispatchFlags = (uint)dispatchDescription.flags;
constants.cameraNear = dispatchDescription.cameraNear;
constants.cameraFar = dispatchDescription.cameraFar;
constants.interpolationRectBase = dispatchDescription.interpolationRect.position;
constants.interpolationRectSize = dispatchDescription.interpolationRect.size;
// Debug bar
constants.debugBarColor.x = DebugBarColorSequence[_debugIndex * 3 + 0];
constants.debugBarColor.y = DebugBarColorSequence[_debugIndex * 3 + 1];
constants.debugBarColor.z = DebugBarColorSequence[_debugIndex * 3 + 2];
_debugIndex = (_debugIndex + 1) % (DebugBarColorSequence.Length / 3);
constants.backBufferTransferFunction = (uint)dispatchDescription.backbufferTransferFunction;
constants.minMaxLuminance = dispatchDescription.minMaxLuminance;
float aspectRatio = dispatchDescription.renderSize.x / (float)dispatchDescription.renderSize.y;
float cameraAngleHorizontal = Mathf.Atan(Mathf.Tan(dispatchDescription.cameraFovAngleVertical / 2) * aspectRatio) * 2;
constants.tanHalfFOV = Mathf.Tan(cameraAngleHorizontal * 0.5f);
bool inverted = (_contextDescription.flags & FrameInterpolation.InitializationFlags.EnableDepthInverted) != 0;
bool infinite = (_contextDescription.flags & FrameInterpolation.InitializationFlags.EnableDepthInfinite) != 0;
constants.deviceToViewDepth = FfxUtils.SetupDeviceDepthToViewSpaceDepthParams(
dispatchDescription.renderSize, dispatchDescription.cameraNear, dispatchDescription.cameraFar, dispatchDescription.cameraFovAngleVertical, inverted, infinite);
_frameInterpolationConstants.UpdateBufferData(commandBuffer);
int doubleBufferId = _asyncSupported ? (int)(dispatchDescription.frameID & 1) : 0;
int displayDispatchSizeX = (dispatchDescription.displaySize.x + 7) / 8;
int displayDispatchSizeY = (dispatchDescription.displaySize.y + 7) / 8;
int renderDispatchSizeX = (dispatchDescription.renderSize.x + 7) / 8;
int renderDispatchSizeY = (dispatchDescription.renderSize.y + 7) / 8;
int opticalFlowDispatchSizeX = (int)(dispatchDescription.displaySize.x / (float)dispatchDescription.opticalFlowBlockSize + 7) / 8;
int opticalFlowDispatchSizeY = (int)(dispatchDescription.displaySize.y / (float)dispatchDescription.opticalFlowBlockSize + 7) / 8;
bool executePreparationPasses = (constants.reset == 0);
// Schedule work for the interpolation command list
_setupPass.ScheduleDispatch(commandBuffer, dispatchDescription, doubleBufferId, renderDispatchSizeX, renderDispatchSizeY);
// Only execute FG data preparation passes when reset wasn't triggered
if (executePreparationPasses)
{
// Clear estimated depth resources
commandBuffer.SetRenderTarget(_resources.ReconstructedDepthInterpolatedFrame);
commandBuffer.ClearRenderTarget(false, true, inverted ? Color.clear : Color.white);
_reconstructPreviousDepthPass.ScheduleDispatch(commandBuffer, dispatchDescription, doubleBufferId, renderDispatchSizeX, renderDispatchSizeY);
_gameMotionVectorFieldPass.ScheduleDispatch(commandBuffer, dispatchDescription, doubleBufferId, renderDispatchSizeX, renderDispatchSizeY);
DispatchGameVectorFieldInpaintingPyramid(commandBuffer, dispatchDescription, doubleBufferId);
_opticalFlowVectorFieldPass.ScheduleDispatch(commandBuffer, dispatchDescription, doubleBufferId, opticalFlowDispatchSizeX, opticalFlowDispatchSizeY);
_disocclusionMaskPass.ScheduleDispatch(commandBuffer, dispatchDescription, doubleBufferId, renderDispatchSizeX, renderDispatchSizeY);
}
_interpolationPass.ScheduleDispatch(commandBuffer, dispatchDescription, doubleBufferId, displayDispatchSizeX, displayDispatchSizeY);
// Inpainting pyramid
SetupSpdConstants(dispatchDescription.displaySize, out var dispatchThreadGroupCount);
_spdConstants.UpdateBufferData(commandBuffer);
_inpaintingPyramidPass.ScheduleDispatch(commandBuffer, dispatchDescription, doubleBufferId, dispatchThreadGroupCount.x, dispatchThreadGroupCount.y);
_inpaintingPass.ScheduleDispatch(commandBuffer, dispatchDescription, doubleBufferId, displayDispatchSizeX, displayDispatchSizeY);
if ((dispatchDescription.flags & FrameInterpolation.DispatchFlags.DrawDebugView) != 0)
{
DispatchGameVectorFieldInpaintingPyramid(commandBuffer, dispatchDescription, doubleBufferId);
_debugViewPass.ScheduleDispatch(commandBuffer, dispatchDescription, doubleBufferId, displayDispatchSizeX, displayDispatchSizeY);
}
// Store current buffer
commandBuffer.CopyTexture(dispatchDescription.InterpolationSource.RenderTarget, _resources.PreviousInterpolationSource);
commandBuffer.EndSample(_sampler);
}
private void DispatchGameVectorFieldInpaintingPyramid(CommandBuffer commandBuffer, in FrameInterpolation.DispatchDescription dispatchDescription, int doubleBufferId)
{
SetupSpdConstants(dispatchDescription.renderSize, out var dispatchThreadGroupCount);
_spdConstants.UpdateBufferData(commandBuffer);
_gameVectorFieldInpaintingPyramidPass.ScheduleDispatch(commandBuffer, dispatchDescription, doubleBufferId, dispatchThreadGroupCount.x, dispatchThreadGroupCount.y);
}
private void SetupSpdConstants(Vector2Int resolution, out Vector2Int dispatchThreadGroupCount)
{
ref var spdConstants = ref _spdConstants.Value;
FfxSpd.SetupSpdConstants(resolution, ref spdConstants, out dispatchThreadGroupCount);
spdConstants.mips = Math.Min(spdConstants.mips, 7);
}
private int _debugIndex = 0;
private static readonly float[] DebugBarColorSequence =
{
0.0f, 1.0f, 1.0f, // teal
1.0f, 0.42f, 0.0f, // orange
0.0f, 0.16f, 1.0f, // blue
0.74f, 1.0f, 0.0f, // lime
0.68f, 0.0f, 1.0f, // purple
0.0f, 1.0f, 0.1f, // green
1.0f, 1.0f, 0.48f // bright yellow
};
}
}

11
Runtime/FrameInterpolation/FrameInterpolationContext.cs.meta

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e5dd3cf3772023443982f14a66852110
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

333
Runtime/FrameInterpolation/FrameInterpolationPass.cs

@ -0,0 +1,333 @@
using UnityEngine;
using UnityEngine.Rendering;
namespace FidelityFX.FrameGen
{
internal abstract class FrameInterpolationPass: FfxPassWithFlags<FrameInterpolation.InitializationFlags>
{
protected readonly FrameInterpolationResources Resources;
protected readonly ComputeBuffer Constants;
protected FrameInterpolationPass(in FrameInterpolation.ContextDescription contextDescription, FrameInterpolationResources resources, ComputeBuffer constants)
: base("Frame Interpolation", contextDescription.flags)
{
Resources = resources;
Constants = constants;
}
public void ScheduleDispatch(CommandBuffer commandBuffer, FrameInterpolation.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY, int dispatchZ = 1)
{
using (ProfilerSample(commandBuffer))
{
Dispatch(commandBuffer, dispatchParams, frameIndex, dispatchX, dispatchY, dispatchZ);
}
}
protected abstract void Dispatch(CommandBuffer commandBuffer, in FrameInterpolation.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY, int dispatchZ);
protected override void SetupShaderKeywords()
{
if ((Flags & FrameInterpolation.InitializationFlags.EnableDisplayResolutionMotionVectors) == 0) ComputeShader.EnableKeyword("FFX_FRAMEINTERPOLATION_OPTION_LOW_RES_MOTION_VECTORS");
if ((Flags & FrameInterpolation.InitializationFlags.EnableJitterMotionVectors) != 0) ComputeShader.EnableKeyword("FFX_FRAMEINTERPOLATION_OPTION_JITTERED_MOTION_VECTORS");
if ((Flags & FrameInterpolation.InitializationFlags.EnableDepthInverted) != 0) ComputeShader.EnableKeyword("FFX_FRAMEINTERPOLATION_OPTION_INVERTED_DEPTH");
}
}
internal sealed class FrameInterpolationReconstructAndDilatePass : FrameInterpolationPass
{
public FrameInterpolationReconstructAndDilatePass(in FrameInterpolation.ContextDescription contextDescription, FrameInterpolationResources resources, ComputeBuffer constants)
: base(contextDescription, resources, constants)
{
InitComputeShader("Reconstruct and Dilate", contextDescription.shaders.reconstructAndDilate);
}
protected override void Dispatch(CommandBuffer commandBuffer, in FrameInterpolation.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY, int dispatchZ)
{
}
public void ScheduleDispatch(CommandBuffer commandBuffer, FrameInterpolation.PrepareDescription prepareParams, int frameIndex, int dispatchX, int dispatchY, int dispatchZ = 1)
{
using (ProfilerSample(commandBuffer))
{
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.SrvInputMotionVectors, prepareParams.motionVectors);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.SrvInputDepth, prepareParams.depth);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.UavReconstructedDepthPreviousFrame, Resources.ReconstructedDepth[frameIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.UavDilatedMotionVectors, Resources.DilatedMotionVectors[frameIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.UavDilatedDepth, Resources.DilatedDepth[frameIndex]);
commandBuffer.SetComputeConstantBufferParam<FrameInterpolation.Constants>(ComputeShader, FrameInterpolationShaderIDs.CbFrameInterpolation, Constants);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, dispatchZ);
}
}
}
internal sealed class FrameInterpolationSetupPass : FrameInterpolationPass
{
public FrameInterpolationSetupPass(in FrameInterpolation.ContextDescription contextDescription, FrameInterpolationResources resources, ComputeBuffer constants)
: base(contextDescription, resources, constants)
{
InitComputeShader("Setup", contextDescription.shaders.setup);
}
protected override void Dispatch(CommandBuffer commandBuffer, in FrameInterpolation.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY, int dispatchZ)
{
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.SrvOpticalFlowSceneChangeDetection, dispatchParams.opticalFlowSceneChangeDetection);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.UavGameMotionVectorFieldX, Resources.GameMotionVectorFieldX);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.UavGameMotionVectorFieldY, Resources.GameMotionVectorFieldY);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.UavOpticalFlowMotionVectorFieldX, Resources.OpticalFlowMotionVectorFieldX);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.UavOpticalFlowMotionVectorFieldY, Resources.OpticalFlowMotionVectorFieldY);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.UavDisocclusionMask, Resources.DisocclusionMask);
commandBuffer.SetComputeBufferParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.UavCounters, Resources.Counters);
commandBuffer.SetComputeConstantBufferParam<FrameInterpolation.Constants>(ComputeShader, FrameInterpolationShaderIDs.CbFrameInterpolation, Constants);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, dispatchZ);
}
}
internal sealed class FrameInterpolationReconstructPreviousDepthPass : FrameInterpolationPass
{
public FrameInterpolationReconstructPreviousDepthPass(in FrameInterpolation.ContextDescription contextDescription, FrameInterpolationResources resources, ComputeBuffer constants)
: base(contextDescription, resources, constants)
{
InitComputeShader("Reconstruct Previous Depth", contextDescription.shaders.reconstructPreviousDepth);
}
protected override void Dispatch(CommandBuffer commandBuffer, in FrameInterpolation.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY, int dispatchZ)
{
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.SrvDilatedMotionVectors, Resources.DilatedMotionVectors[frameIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.SrvDilatedDepth, Resources.DilatedDepth[frameIndex]);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.SrvCurrentInterpolationSource, dispatchParams.InterpolationSource);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.UavReconstructedDepthInterpolatedFrame, Resources.ReconstructedDepthInterpolatedFrame);
commandBuffer.SetComputeConstantBufferParam<FrameInterpolation.Constants>(ComputeShader, FrameInterpolationShaderIDs.CbFrameInterpolation, Constants);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, dispatchZ);
}
}
internal sealed class FrameInterpolationGameMotionVectorFieldPass : FrameInterpolationPass
{
public FrameInterpolationGameMotionVectorFieldPass(in FrameInterpolation.ContextDescription contextDescription, FrameInterpolationResources resources, ComputeBuffer constants)
: base(contextDescription, resources, constants)
{
InitComputeShader("Game Motion Vector Field", contextDescription.shaders.gameMotionVectorField);
}
protected override void Dispatch(CommandBuffer commandBuffer, in FrameInterpolation.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY, int dispatchZ)
{
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.SrvDilatedMotionVectors, Resources.DilatedMotionVectors[frameIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.SrvDilatedDepth, Resources.DilatedDepth[frameIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.SrvPreviousInterpolationSource, Resources.PreviousInterpolationSource);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.SrvCurrentInterpolationSource, dispatchParams.InterpolationSource);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.UavGameMotionVectorFieldX, Resources.GameMotionVectorFieldX);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.UavGameMotionVectorFieldY, Resources.GameMotionVectorFieldY);
commandBuffer.SetComputeConstantBufferParam<FrameInterpolation.Constants>(ComputeShader, FrameInterpolationShaderIDs.CbFrameInterpolation, Constants);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, dispatchZ);
}
}
internal sealed class FrameInterpolationOpticalFlowVectorFieldPass : FrameInterpolationPass
{
public FrameInterpolationOpticalFlowVectorFieldPass(in FrameInterpolation.ContextDescription contextDescription, FrameInterpolationResources resources, ComputeBuffer constants)
: base(contextDescription, resources, constants)
{
InitComputeShader("Optical Flow Vector Field", contextDescription.shaders.opticalFlowVectorField);
}
protected override void Dispatch(CommandBuffer commandBuffer, in FrameInterpolation.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY, int dispatchZ)
{
if (dispatchParams.opticalFlowScale.x > 0f)
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.SrvOpticalFlowVector, dispatchParams.opticalFlowVector);
else
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.SrvOpticalFlowVector, BuiltinRenderTextureType.None);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.SrvOpticalFlowConfidence, BuiltinRenderTextureType.None);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.SrvDilatedDepth, Resources.DilatedDepth[frameIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.SrvPreviousInterpolationSource, Resources.PreviousInterpolationSource);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.SrvCurrentInterpolationSource, dispatchParams.InterpolationSource);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.UavOpticalFlowMotionVectorFieldX, Resources.OpticalFlowMotionVectorFieldX);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.UavOpticalFlowMotionVectorFieldY, Resources.OpticalFlowMotionVectorFieldY);
commandBuffer.SetComputeConstantBufferParam<FrameInterpolation.Constants>(ComputeShader, FrameInterpolationShaderIDs.CbFrameInterpolation, Constants);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, dispatchZ);
}
}
internal sealed class FrameInterpolationDisocclusionMaskPass : FrameInterpolationPass
{
public FrameInterpolationDisocclusionMaskPass(in FrameInterpolation.ContextDescription contextDescription, FrameInterpolationResources resources, ComputeBuffer constants)
: base(contextDescription, resources, constants)
{
InitComputeShader("Disocclusion Mask", contextDescription.shaders.disocclusionMask);
}
protected override void Dispatch(CommandBuffer commandBuffer, in FrameInterpolation.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY, int dispatchZ)
{
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.SrvGameMotionVectorFieldX, Resources.GameMotionVectorFieldX);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.SrvGameMotionVectorFieldY, Resources.GameMotionVectorFieldY);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.SrvReconstructedDepthPreviousFrame, Resources.ReconstructedDepth[frameIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.SrvDilatedDepth, Resources.DilatedDepth[frameIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.SrvReconstructedDepthInterpolatedFrame, Resources.ReconstructedDepthInterpolatedFrame);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.SrvInpaintingPyramid, Resources.InpaintingPyramid);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.UavDisocclusionMask, Resources.DisocclusionMask);
commandBuffer.SetComputeConstantBufferParam<FrameInterpolation.Constants>(ComputeShader, FrameInterpolationShaderIDs.CbFrameInterpolation, Constants);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, dispatchZ);
}
}
internal sealed class FrameInterpolationInterpolationPass : FrameInterpolationPass
{
public FrameInterpolationInterpolationPass(in FrameInterpolation.ContextDescription contextDescription, FrameInterpolationResources resources, ComputeBuffer constants)
: base(contextDescription, resources, constants)
{
InitComputeShader("Interpolation", contextDescription.shaders.interpolation);
}
protected override void Dispatch(CommandBuffer commandBuffer, in FrameInterpolation.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY, int dispatchZ)
{
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.SrvGameMotionVectorFieldX, Resources.GameMotionVectorFieldX);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.SrvGameMotionVectorFieldY, Resources.GameMotionVectorFieldY);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.SrvOpticalFlowMotionVectorFieldX, Resources.OpticalFlowMotionVectorFieldX);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.SrvOpticalFlowMotionVectorFieldY, Resources.OpticalFlowMotionVectorFieldY);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.SrvPreviousInterpolationSource, Resources.PreviousInterpolationSource);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.SrvCurrentInterpolationSource, dispatchParams.InterpolationSource);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.SrvDisocclusionMask, Resources.DisocclusionMask);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.SrvInpaintingPyramid, Resources.InpaintingPyramid);
commandBuffer.SetComputeBufferParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.SrvCounters, Resources.Counters);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.UavOutput, dispatchParams.output);
commandBuffer.SetComputeConstantBufferParam<FrameInterpolation.Constants>(ComputeShader, FrameInterpolationShaderIDs.CbFrameInterpolation, Constants);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, dispatchZ);
}
}
internal sealed class FrameInterpolationInpaintingPyramidPass : FrameInterpolationPass
{
private readonly ComputeBuffer _spdConstants;
public FrameInterpolationInpaintingPyramidPass(in FrameInterpolation.ContextDescription contextDescription, FrameInterpolationResources resources, ComputeBuffer constants, ComputeBuffer spdConstants)
: base(contextDescription, resources, constants)
{
_spdConstants = spdConstants;
InitComputeShader("Inpainting Pyramid", contextDescription.shaders.inpaintingPyramid);
}
protected override void Dispatch(CommandBuffer commandBuffer, in FrameInterpolation.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY, int dispatchZ)
{
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.SrvOutput, dispatchParams.output);
commandBuffer.SetComputeBufferParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.UavCounters, Resources.Counters);
commandBuffer.SetComputeTextureMipParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.UavInpaintingPyramidMipmap0, Resources.InpaintingPyramid, 0);
commandBuffer.SetComputeTextureMipParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.UavInpaintingPyramidMipmap1, Resources.InpaintingPyramid, 1);
commandBuffer.SetComputeTextureMipParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.UavInpaintingPyramidMipmap2, Resources.InpaintingPyramid, 2);
commandBuffer.SetComputeTextureMipParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.UavInpaintingPyramidMipmap3, Resources.InpaintingPyramid, 3);
commandBuffer.SetComputeTextureMipParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.UavInpaintingPyramidMipmap4, Resources.InpaintingPyramid, 4);
commandBuffer.SetComputeTextureMipParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.UavInpaintingPyramidMipmap5, Resources.InpaintingPyramid, 5);
commandBuffer.SetComputeTextureMipParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.UavInpaintingPyramidMipmap6, Resources.InpaintingPyramid, 6);
commandBuffer.SetComputeConstantBufferParam<FrameInterpolation.Constants>(ComputeShader, FrameInterpolationShaderIDs.CbFrameInterpolation, Constants);
commandBuffer.SetComputeConstantBufferParam<FfxSpd.SpdConstants>(ComputeShader, FrameInterpolationShaderIDs.CbInpaintingPyramid, _spdConstants);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, dispatchZ);
}
}
internal sealed class FrameInterpolationInpaintingPass : FrameInterpolationPass
{
public FrameInterpolationInpaintingPass(in FrameInterpolation.ContextDescription contextDescription, FrameInterpolationResources resources, ComputeBuffer constants)
: base(contextDescription, resources, constants)
{
InitComputeShader("Inpainting", contextDescription.shaders.inpainting);
}
protected override void Dispatch(CommandBuffer commandBuffer, in FrameInterpolation.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY, int dispatchZ)
{
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.SrvOpticalFlowSceneChangeDetection, dispatchParams.opticalFlowSceneChangeDetection);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.SrvInpaintingPyramid, Resources.InpaintingPyramid);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.SrvPresentBackbuffer, dispatchParams.currentBackBuffer);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.SrvCurrentInterpolationSource, dispatchParams.InterpolationSource);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.UavOutput, dispatchParams.output);
commandBuffer.SetComputeConstantBufferParam<FrameInterpolation.Constants>(ComputeShader, FrameInterpolationShaderIDs.CbFrameInterpolation, Constants);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, dispatchZ);
}
}
internal sealed class FrameInterpolationGameVectorFieldInpaintingPyramidPass : FrameInterpolationPass
{
private readonly ComputeBuffer _spdConstants;
public FrameInterpolationGameVectorFieldInpaintingPyramidPass(in FrameInterpolation.ContextDescription contextDescription, FrameInterpolationResources resources, ComputeBuffer constants, ComputeBuffer spdConstants)
: base(contextDescription, resources, constants)
{
_spdConstants = spdConstants;
InitComputeShader("Game Vector Field Inpainting Pyramid", contextDescription.shaders.gameVectorFieldInpaintingPyramid);
}
protected override void Dispatch(CommandBuffer commandBuffer, in FrameInterpolation.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY, int dispatchZ)
{
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.SrvGameMotionVectorFieldX, Resources.GameMotionVectorFieldX);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.SrvGameMotionVectorFieldY, Resources.GameMotionVectorFieldY);
commandBuffer.SetComputeBufferParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.UavCounters, Resources.Counters);
commandBuffer.SetComputeTextureMipParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.UavInpaintingPyramidMipmap0, Resources.InpaintingPyramid, 0);
commandBuffer.SetComputeTextureMipParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.UavInpaintingPyramidMipmap1, Resources.InpaintingPyramid, 1);
commandBuffer.SetComputeTextureMipParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.UavInpaintingPyramidMipmap2, Resources.InpaintingPyramid, 2);
commandBuffer.SetComputeTextureMipParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.UavInpaintingPyramidMipmap3, Resources.InpaintingPyramid, 3);
commandBuffer.SetComputeTextureMipParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.UavInpaintingPyramidMipmap4, Resources.InpaintingPyramid, 4);
commandBuffer.SetComputeTextureMipParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.UavInpaintingPyramidMipmap5, Resources.InpaintingPyramid, 5);
commandBuffer.SetComputeTextureMipParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.UavInpaintingPyramidMipmap6, Resources.InpaintingPyramid, 6);
commandBuffer.SetComputeConstantBufferParam<FrameInterpolation.Constants>(ComputeShader, FrameInterpolationShaderIDs.CbFrameInterpolation, Constants);
commandBuffer.SetComputeConstantBufferParam<FfxSpd.SpdConstants>(ComputeShader, FrameInterpolationShaderIDs.CbInpaintingPyramid, _spdConstants);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, dispatchZ);
}
}
internal sealed class FrameInterpolationDebugViewPass : FrameInterpolationPass
{
public FrameInterpolationDebugViewPass(in FrameInterpolation.ContextDescription contextDescription, FrameInterpolationResources resources, ComputeBuffer constants)
: base(contextDescription, resources, constants)
{
InitComputeShader("Debug View", contextDescription.shaders.debugView);
}
protected override void Dispatch(CommandBuffer commandBuffer, in FrameInterpolation.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY, int dispatchZ)
{
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.SrvGameMotionVectorFieldX, Resources.GameMotionVectorFieldX);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.SrvGameMotionVectorFieldY, Resources.GameMotionVectorFieldY);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.SrvOpticalFlowMotionVectorFieldX, Resources.OpticalFlowMotionVectorFieldX);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.SrvOpticalFlowMotionVectorFieldY, Resources.OpticalFlowMotionVectorFieldY);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.SrvDisocclusionMask, Resources.DisocclusionMask);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.SrvPresentBackbuffer, dispatchParams.currentBackBuffer);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.SrvInpaintingPyramid, Resources.InpaintingPyramid);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.SrvCurrentInterpolationSource, dispatchParams.InterpolationSource);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, FrameInterpolationShaderIDs.UavOutput, dispatchParams.output);
commandBuffer.SetComputeConstantBufferParam<FrameInterpolation.Constants>(ComputeShader, FrameInterpolationShaderIDs.CbFrameInterpolation, Constants);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, dispatchZ);
}
}
}

11
Runtime/FrameInterpolation/FrameInterpolationPass.cs.meta

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 923f12e91a899ce4f87665a073515a50
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

64
Runtime/FrameInterpolation/FrameInterpolationResources.cs

@ -0,0 +1,64 @@
using System;
using System.Runtime.InteropServices;
using UnityEngine;
using UnityEngine.Experimental.Rendering;
namespace FidelityFX.FrameGen
{
internal class FrameInterpolationResources: FfxResourcesBase
{
public RenderTexture ReconstructedDepthInterpolatedFrame;
public RenderTexture GameMotionVectorFieldX;
public RenderTexture GameMotionVectorFieldY;
public RenderTexture InpaintingPyramid;
public ComputeBuffer Counters;
public RenderTexture OpticalFlowMotionVectorFieldX;
public RenderTexture OpticalFlowMotionVectorFieldY;
public RenderTexture PreviousInterpolationSource;
public RenderTexture DisocclusionMask;
public readonly RenderTexture[] DilatedDepth = new RenderTexture[2];
public readonly RenderTexture[] DilatedMotionVectors = new RenderTexture[2];
public readonly RenderTexture[] ReconstructedDepth = new RenderTexture[2];
public void Create(in FrameInterpolation.ContextDescription contextDescription)
{
Vector2Int displaySize = contextDescription.displaySize;
Vector2Int displaySizeDiv2 = new Vector2Int(displaySize.x / 2, displaySize.y / 2);
Vector2Int maxRenderSize = contextDescription.maxRenderSize;
ReconstructedDepthInterpolatedFrame = CreateResource("FI_ReconstructedDepthInterpolatedFrame", maxRenderSize, GraphicsFormat.R32_UInt);
GameMotionVectorFieldX = CreateResource("FI_GameMotionVectorFieldX", maxRenderSize, GraphicsFormat.R32_UInt);
GameMotionVectorFieldY = CreateResource("FI_GameMotionVectorFieldY", maxRenderSize, GraphicsFormat.R32_UInt);
InpaintingPyramid = CreateResourceMips("FI_InpaintingPyramid", displaySizeDiv2, GraphicsFormat.R16G16B16A16_SFloat);
Counters = CreateBuffer<uint>("FI_Counters", 2); // structured buffer containing 2 UINT values
OpticalFlowMotionVectorFieldX = CreateResource("FI_OpticalFlowMotionVectorFieldX", maxRenderSize, GraphicsFormat.R32_UInt);
OpticalFlowMotionVectorFieldY = CreateResource("FI_OpticalFlowMotionVectorFieldY", maxRenderSize, GraphicsFormat.R32_UInt);
PreviousInterpolationSource = CreateResource("FI_PreviousInterpolationSource", displaySize, contextDescription.backBufferFormat);
DisocclusionMask = CreateResource("FI_DisocclusionMask", maxRenderSize, GraphicsFormat.R8G8_UNorm);
// Double buffering is used only when async support is enabled
int numBuffers = (contextDescription.flags & FrameInterpolation.InitializationFlags.EnableAsyncSupport) != 0 ? 2 : 1;
CreateDoubleBufferedResource(DilatedDepth, "FI_DilatedDepth_", maxRenderSize, GraphicsFormat.R32_SFloat, numBuffers);
CreateDoubleBufferedResource(DilatedMotionVectors, "FI_DilatedMVs_", maxRenderSize, GraphicsFormat.R16G16_SFloat, numBuffers);
CreateDoubleBufferedResource(ReconstructedDepth, "FI_ReconstructedDepth_", maxRenderSize, GraphicsFormat.R32_UInt, numBuffers);
}
public void Destroy()
{
DestroyResource(ReconstructedDepth);
DestroyResource(DilatedMotionVectors);
DestroyResource(DilatedDepth);
DestroyResource(ref DisocclusionMask);
DestroyResource(ref PreviousInterpolationSource);
DestroyResource(ref OpticalFlowMotionVectorFieldY);
DestroyResource(ref OpticalFlowMotionVectorFieldX);
DestroyResource(ref Counters);
DestroyResource(ref InpaintingPyramid);
DestroyResource(ref GameMotionVectorFieldY);
DestroyResource(ref GameMotionVectorFieldX);
DestroyResource(ref ReconstructedDepthInterpolatedFrame);
}
}
}

11
Runtime/FrameInterpolation/FrameInterpolationResources.cs.meta

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c73ba9378b4e74b4db13de2812c61ad9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

60
Runtime/FrameInterpolation/FrameInterpolationShaderIDs.cs

@ -0,0 +1,60 @@
using UnityEngine;
namespace FidelityFX.FrameGen
{
public static class FrameInterpolationShaderIDs
{
// Shader resource views, i.e. read-only bindings
public static readonly int SrvInputDepth = Shader.PropertyToID("r_input_depth");
public static readonly int SrvInputMotionVectors = Shader.PropertyToID("r_input_motion_vectors");
public static readonly int SrvDilatedDepth = Shader.PropertyToID("r_dilated_depth");
public static readonly int SrvDilatedMotionVectors = Shader.PropertyToID("r_dilated_motion_vectors");
public static readonly int SrvReconstructedDepthPreviousFrame = Shader.PropertyToID("r_reconstructed_depth_previous_frame");
public static readonly int SrvReconstructedDepthInterpolatedFrame = Shader.PropertyToID("r_reconstructed_depth_interpolated_frame");
public static readonly int SrvPreviousInterpolationSource = Shader.PropertyToID("r_previous_interpolation_source");
public static readonly int SrvCurrentInterpolationSource = Shader.PropertyToID("r_current_interpolation_source");
public static readonly int SrvDisocclusionMask = Shader.PropertyToID("r_disocclusion_mask");
public static readonly int SrvGameMotionVectorFieldX = Shader.PropertyToID("r_game_motion_vector_field_x");
public static readonly int SrvGameMotionVectorFieldY = Shader.PropertyToID("r_game_motion_vector_field_y");
public static readonly int SrvOpticalFlowMotionVectorFieldX = Shader.PropertyToID("r_optical_flow_motion_vector_field_x");
public static readonly int SrvOpticalFlowMotionVectorFieldY = Shader.PropertyToID("r_optical_flow_motion_vector_field_y");
public static readonly int SrvOpticalFlowVector = Shader.PropertyToID("r_optical_flow");
public static readonly int SrvOpticalFlowConfidence = Shader.PropertyToID("r_optical_flow_confidence");
public static readonly int SrvOpticalFlowGlobalMotion = Shader.PropertyToID("r_optical_flow_global_motion");
public static readonly int SrvOpticalFlowSceneChangeDetection = Shader.PropertyToID("r_optical_flow_scd");
public static readonly int SrvOutput = Shader.PropertyToID("r_output");
public static readonly int SrvInpaintingPyramid = Shader.PropertyToID("r_inpainting_pyramid");
public static readonly int SrvPresentBackbuffer = Shader.PropertyToID("r_present_backbuffer");
public static readonly int SrvCounters = Shader.PropertyToID("r_counters");
// Unordered access views, i.e. random read/write bindings
public static readonly int UavDilatedDepth = Shader.PropertyToID("rw_dilated_depth");
public static readonly int UavDilatedMotionVectors = Shader.PropertyToID("rw_dilated_motion_vectors");
public static readonly int UavReconstructedDepthPreviousFrame = Shader.PropertyToID("rw_reconstructed_depth_previous_frame");
public static readonly int UavReconstructedDepthInterpolatedFrame = Shader.PropertyToID("rw_reconstructed_depth_interpolated_frame");
public static readonly int UavOutput = Shader.PropertyToID("rw_output");
public static readonly int UavDisocclusionMask = Shader.PropertyToID("rw_disocclusion_mask");
public static readonly int UavGameMotionVectorFieldX = Shader.PropertyToID("rw_game_motion_vector_field_x");
public static readonly int UavGameMotionVectorFieldY = Shader.PropertyToID("rw_game_motion_vector_field_y");
public static readonly int UavOpticalFlowMotionVectorFieldX = Shader.PropertyToID("rw_optical_flow_motion_vector_field_x");
public static readonly int UavOpticalFlowMotionVectorFieldY = Shader.PropertyToID("rw_optical_flow_motion_vector_field_y");
public static readonly int UavCounters = Shader.PropertyToID("rw_counters");
public static readonly int UavInpaintingPyramidMipmap0 = Shader.PropertyToID("rw_inpainting_pyramid0");
public static readonly int UavInpaintingPyramidMipmap1 = Shader.PropertyToID("rw_inpainting_pyramid1");
public static readonly int UavInpaintingPyramidMipmap2 = Shader.PropertyToID("rw_inpainting_pyramid2");
public static readonly int UavInpaintingPyramidMipmap3 = Shader.PropertyToID("rw_inpainting_pyramid3");
public static readonly int UavInpaintingPyramidMipmap4 = Shader.PropertyToID("rw_inpainting_pyramid4");
public static readonly int UavInpaintingPyramidMipmap5 = Shader.PropertyToID("rw_inpainting_pyramid5");
public static readonly int UavInpaintingPyramidMipmap6 = Shader.PropertyToID("rw_inpainting_pyramid6");
public static readonly int UavInpaintingPyramidMipmap7 = Shader.PropertyToID("rw_inpainting_pyramid7");
public static readonly int UavInpaintingPyramidMipmap8 = Shader.PropertyToID("rw_inpainting_pyramid8");
public static readonly int UavInpaintingPyramidMipmap9 = Shader.PropertyToID("rw_inpainting_pyramid9");
public static readonly int UavInpaintingPyramidMipmap10 = Shader.PropertyToID("rw_inpainting_pyramid10");
public static readonly int UavInpaintingPyramidMipmap11 = Shader.PropertyToID("rw_inpainting_pyramid11");
public static readonly int UavInpaintingPyramidMipmap12 = Shader.PropertyToID("rw_inpainting_pyramid12");
// Constant buffer bindings
public static readonly int CbFrameInterpolation = Shader.PropertyToID("cbFI");
public static readonly int CbInpaintingPyramid = Shader.PropertyToID("cbInpaintingPyramid");
}
}

11
Runtime/FrameInterpolation/FrameInterpolationShaderIDs.cs.meta

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ac109e3b6c9c55645a230f5e6ab9e49f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

8
Runtime/OpticalFlow.meta

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 52b9ee437d2c45248a5410ed4160929e
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

102
Runtime/OpticalFlow/OpticalFlow.cs

@ -0,0 +1,102 @@
using System;
using System.Runtime.InteropServices;
using UnityEngine;
namespace FidelityFX.FrameGen
{
public static class OpticalFlow
{
internal const int MinBlockSize = 8;
internal const int OpticalFlowMaxPyramidLevels = 7;
internal const int HistogramBins = 256;
internal const int HistogramsPerDim = 3;
internal const int HistogramShifts = 3;
public static OpticalFlowContext CreateContext(Vector2Int resolution, OpticalFlowShaders shaders)
{
Debug.Log($"Setting up Optical Flow with resolution: {resolution.x}x{resolution.y}");
var contextDescription = new ContextDescription
{
resolution = resolution,
shaders = shaders,
};
var context = new OpticalFlowContext();
context.Create(contextDescription);
return context;
}
public struct ContextDescription
{
public Vector2Int resolution;
public OpticalFlowShaders shaders;
}
public struct DispatchDescription
{
public ResourceView color;
public ResourceView opticalFlowVector;
public ResourceView opticalFlowSCD;
public bool reset;
public BackbufferTransferFunction backbufferTransferFunction;
public Vector2 minMaxLuminance;
}
internal static Vector2Int GetOpticalFlowTextureSize(Vector2Int displaySize, int opticalFlowBlockSize)
{
int width = (displaySize.x + opticalFlowBlockSize - 1) / opticalFlowBlockSize;
int height = (displaySize.y + opticalFlowBlockSize - 1) / opticalFlowBlockSize;
return new Vector2Int(width, height);
}
internal static Vector2Int GetOpticalFlowHistogramSize(int level)
{
const int searchRadius = 8;
int maxVelocity = searchRadius * (1 << (OpticalFlowMaxPyramidLevels - 1 - level));
int binsPerDimension = 2 * maxVelocity + 1;
return new Vector2Int(binsPerDimension, binsPerDimension);
}
internal static Vector2Int GetGlobalMotionSearchDispatchSize(int level)
{
const int threadGroupSizeX = 16;
const int threadGroupSizeY = 16;
Vector2Int opticalFlowHistogramSize = GetOpticalFlowHistogramSize(level);
int additionalElementsDueToShiftsX = opticalFlowHistogramSize.x / threadGroupSizeX;
int additionalElementsDueToShiftsY = opticalFlowHistogramSize.y / threadGroupSizeY;
int dispatchX = (opticalFlowHistogramSize.x + additionalElementsDueToShiftsX + threadGroupSizeX - 1) / threadGroupSizeX;
int dispatchY = (opticalFlowHistogramSize.y + additionalElementsDueToShiftsY + threadGroupSizeY - 1) / threadGroupSizeY;
return new Vector2Int(dispatchX, dispatchY);
}
internal static int GetSCDHistogramTextureWidth()
{
return HistogramBins * (HistogramsPerDim * HistogramsPerDim);
}
[Serializable, StructLayout(LayoutKind.Sequential)]
internal struct OpticalFlowConstants
{
public Vector2Int inputLumaResolution;
public uint opticalFlowPyramidLevel;
public uint opticalFlowPyramidLevelCount;
public int frameIndex;
public uint backbufferTransferFunction;
public Vector2 minMaxLuminance;
}
[Serializable, StructLayout(LayoutKind.Sequential)]
internal struct SpdConstants
{
public FfxSpd.SpdConstants spd;
public uint numWorkGroupsOpticalFlowInputPyramid;
public uint pad0_;
public uint pad1_;
public uint pad2_;
}
}
}

11
Runtime/OpticalFlow/OpticalFlow.cs.meta

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: cb98adb74c696524e900d3b0b965e1dc
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

144
Runtime/OpticalFlow/OpticalFlowAssets.cs

@ -0,0 +1,144 @@
// Copyright (c) 2024 Nico de Poel
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using UnityEngine;
namespace FidelityFX.FrameGen
{
/// <summary>
/// Scriptable object containing all shader resources required by FidelityFX Optical Flow.
/// These can be stored in an asset file and referenced from a scene or prefab, avoiding the need to load the shaders from a Resources folder.
/// </summary>
[CreateAssetMenu(fileName = "Optical Flow Assets", menuName = "FidelityFX/Optical Flow Assets", order = 1111)]
public class OpticalFlowAssets : ScriptableObject
{
public OpticalFlowShaders shaders;
#if UNITY_EDITOR
private void Reset()
{
shaders = new OpticalFlowShaders
{
generateOpticalFlowInputPyramid = FindComputeShader("ffx_opticalflow_compute_luminance_pyramid_pass"),
prepareLuma = FindComputeShader("ffx_opticalflow_prepare_luma_pass"),
generateScdHistogram = FindComputeShader("ffx_opticalflow_generate_scd_histogram_pass"),
computeScdDivergence = FindComputeShader("ffx_opticalflow_compute_scd_divergence_pass"),
computeOpticalFlow = FindComputeShader("ffx_opticalflow_compute_optical_flow_advanced_pass_v5"),
filterOpticalFlow = FindComputeShader("ffx_opticalflow_filter_optical_flow_pass_v5"),
scaleOpticalFlow = FindComputeShader("ffx_opticalflow_scale_optical_flow_advanced_pass_v5"),
};
}
private static ComputeShader FindComputeShader(string name)
{
string[] assetGuids = UnityEditor.AssetDatabase.FindAssets($"t:ComputeShader {name}");
if (assetGuids == null || assetGuids.Length == 0)
return null;
string assetPath = UnityEditor.AssetDatabase.GUIDToAssetPath(assetGuids[0]);
return UnityEditor.AssetDatabase.LoadAssetAtPath<ComputeShader>(assetPath);
}
#endif
}
/// <summary>
/// All the compute shaders used by Optical Flow.
/// </summary>
[System.Serializable]
public class OpticalFlowShaders
{
/// <summary>
/// The compute shader used by the generate optical flow input pass.
/// </summary>
public ComputeShader generateOpticalFlowInputPyramid;
/// <summary>
/// The compute shader used by the prepare luma pass.
/// </summary>
public ComputeShader prepareLuma;
/// <summary>
/// The compute shader used by the generate scene change detection histogram pass.
/// </summary>
public ComputeShader generateScdHistogram;
/// <summary>
/// The compute shader used by the compute scene change detection divergence pass.
/// </summary>
public ComputeShader computeScdDivergence;
/// <summary>
/// The compute shader used by the compute optical flow pass.
/// </summary>
public ComputeShader computeOpticalFlow;
/// <summary>
/// The compute shader used by the filter optical flow pass.
/// </summary>
public ComputeShader filterOpticalFlow;
/// <summary>
/// The compute shader used by the scale optical flow mask.
/// </summary>
public ComputeShader scaleOpticalFlow;
/// <summary>
/// Returns a copy of this class and its contents.
/// </summary>
public OpticalFlowShaders Clone()
{
return (OpticalFlowShaders)MemberwiseClone();
}
/// <summary>
/// Returns a copy of this class with clones of all its shaders.
/// This can be useful if you're running multiple Optical Flow instances with different shader configurations.
/// Be sure to clean up these clones through Dispose once you're done with them.
/// </summary>
public OpticalFlowShaders DeepCopy()
{
return new OpticalFlowShaders
{
generateOpticalFlowInputPyramid = Object.Instantiate(generateOpticalFlowInputPyramid),
prepareLuma = Object.Instantiate(prepareLuma),
generateScdHistogram = Object.Instantiate(generateScdHistogram),
computeScdDivergence = Object.Instantiate(computeScdDivergence),
computeOpticalFlow = Object.Instantiate(computeOpticalFlow),
filterOpticalFlow = Object.Instantiate(filterOpticalFlow),
scaleOpticalFlow = Object.Instantiate(scaleOpticalFlow),
};
}
/// <summary>
/// Destroy all the shaders within this instance.
/// Use this only on clones created through DeepCopy.
/// </summary>
public void Dispose()
{
Object.Destroy(scaleOpticalFlow);
Object.Destroy(filterOpticalFlow);
Object.Destroy(computeOpticalFlow);
Object.Destroy(computeScdDivergence);
Object.Destroy(generateScdHistogram);
Object.Destroy(prepareLuma);
Object.Destroy(generateOpticalFlowInputPyramid);
}
}
}

11
Runtime/OpticalFlow/OpticalFlowAssets.cs.meta

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0ac13db1d14fa3f498ce3c78c44dfb84
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

228
Runtime/OpticalFlow/OpticalFlowContext.cs

@ -0,0 +1,228 @@
using System;
using UnityEngine;
using UnityEngine.Assertions;
using UnityEngine.Profiling;
using UnityEngine.Rendering;
namespace FidelityFX.FrameGen
{
public class OpticalFlowContext: FfxContextBase
{
private const int MaxQueuedFrames = 16;
public int BlockSize => OpticalFlow.MinBlockSize;
public Vector2Int TextureSize => OpticalFlow.GetOpticalFlowTextureSize(_contextDescription.resolution, OpticalFlow.MinBlockSize);
private OpticalFlow.ContextDescription _contextDescription;
private OpticalFlowPrepareLumaPass _prepareLumaPass;
private OpticalFlowGenerateInputPyramidPass _generateInputPyramidPass;
private OpticalFlowGenerateSCDHistogramPass _generateScdHistogramPass;
private OpticalFlowComputeSCDDivergencePass _computeScdDivergencePass;
private OpticalFlowComputePass _computeOpticalFlowPass;
private OpticalFlowFilterPass _filterOpticalFlowPass;
private OpticalFlowScalePass _scaleOpticalFlowPass;
private readonly OpticalFlowResources _resources = new OpticalFlowResources();
private readonly ConstantsBuffer<OpticalFlow.OpticalFlowConstants> _opticalFlowConstants = new ConstantsBuffer<OpticalFlow.OpticalFlowConstants>();
private readonly ConstantsBuffer<OpticalFlow.SpdConstants> _spdConstants = new ConstantsBuffer<OpticalFlow.SpdConstants>();
private bool _firstExecution;
private int _resourceFrameIndex;
private readonly Vector2Int[] _opticalFlowTextureSizes = new Vector2Int[OpticalFlow.OpticalFlowMaxPyramidLevels];
private readonly CustomSampler _sampler = CustomSampler.Create("Optical Flow");
public void Create(in OpticalFlow.ContextDescription contextDescription)
{
_contextDescription = contextDescription;
_opticalFlowConstants.Create();
_spdConstants.Create();
_firstExecution = true;
_resourceFrameIndex = 0;
_opticalFlowConstants.Value.inputLumaResolution = _contextDescription.resolution;
_resources.Create(_contextDescription);
CreatePasses();
}
private void CreatePasses()
{
_prepareLumaPass = new OpticalFlowPrepareLumaPass(_contextDescription, _resources, _opticalFlowConstants);
_generateInputPyramidPass = new OpticalFlowGenerateInputPyramidPass(_contextDescription, _resources, _opticalFlowConstants, _spdConstants);
_generateScdHistogramPass = new OpticalFlowGenerateSCDHistogramPass(_contextDescription, _resources, _opticalFlowConstants);
_computeScdDivergencePass = new OpticalFlowComputeSCDDivergencePass(_contextDescription, _resources, _opticalFlowConstants);
_computeOpticalFlowPass = new OpticalFlowComputePass(_contextDescription, _resources, _opticalFlowConstants);
_filterOpticalFlowPass = new OpticalFlowFilterPass(_contextDescription, _resources, _opticalFlowConstants);
_scaleOpticalFlowPass = new OpticalFlowScalePass(_contextDescription, _resources, _opticalFlowConstants);
}
public void Destroy()
{
DestroyPass(ref _scaleOpticalFlowPass);
DestroyPass(ref _filterOpticalFlowPass);
DestroyPass(ref _computeOpticalFlowPass);
DestroyPass(ref _computeScdDivergencePass);
DestroyPass(ref _generateScdHistogramPass);
DestroyPass(ref _generateInputPyramidPass);
DestroyPass(ref _prepareLumaPass);
_resources.Destroy();
_spdConstants.Destroy();
_opticalFlowConstants.Destroy();
}
public void Dispatch(CommandBuffer commandBuffer, OpticalFlow.DispatchDescription dispatchDescription)
{
const int advancedAlgorithmIterations = 7;
const int opticalFlowBlockSize = 8;
ref var constants = ref _opticalFlowConstants.Value;
constants.backbufferTransferFunction = (uint)dispatchDescription.backbufferTransferFunction;
constants.minMaxLuminance = dispatchDescription.minMaxLuminance;
int frameIndex = _resourceFrameIndex % 2;
bool resetAccumulation = dispatchDescription.reset || _firstExecution;
_firstExecution = false;
if (resetAccumulation)
constants.frameIndex = 0;
else
constants.frameIndex++;
commandBuffer.BeginSample(_sampler);
if (resetAccumulation)
{
commandBuffer.SetRenderTarget(_resources.OpticalFlowSCDTemp);
commandBuffer.ClearRenderTarget(false, true, Color.clear);
commandBuffer.SetRenderTarget(dispatchDescription.opticalFlowSCD.RenderTarget);
commandBuffer.ClearRenderTarget(false, true, Color.clear);
commandBuffer.SetRenderTarget(_resources.OpticalFlowSCDHistogram);
commandBuffer.ClearRenderTarget(false, true, Color.clear);
commandBuffer.SetRenderTarget(_resources.OpticalFlowSCDPreviousHistogram);
commandBuffer.ClearRenderTarget(false, true, Color.clear);
for (int i = 0; i < 2; ++i)
{
for (int level = 0; level < OpticalFlow.OpticalFlowMaxPyramidLevels; ++level)
{
commandBuffer.SetRenderTarget(_resources.OpticalFlowInputLevels[level][i]);
commandBuffer.ClearRenderTarget(false, true, Color.clear);
}
}
}
SetupSpdConstants(out var threadGroupSizeOpticalFlowInputPyramid);
_opticalFlowConstants.UpdateBufferData(commandBuffer);
_spdConstants.UpdateBufferData(commandBuffer);
{
const int threadGroupSizeX = 16;
const int threadGroupSizeY = 16;
const int threadPixelsX = 2;
const int threadPixelsY = 2;
int dispatchX = ((_contextDescription.resolution.x + (threadPixelsX - 1)) / threadPixelsX + (threadGroupSizeX - 1)) / threadGroupSizeX;
int dispatchY = ((_contextDescription.resolution.y + (threadPixelsY - 1)) / threadPixelsY + (threadGroupSizeY - 1)) / threadGroupSizeY;
_prepareLumaPass.ScheduleDispatch(commandBuffer, dispatchDescription, frameIndex, 0, dispatchX, dispatchY);
}
_generateInputPyramidPass.ScheduleDispatch(commandBuffer, dispatchDescription, frameIndex, 0, threadGroupSizeOpticalFlowInputPyramid.x, threadGroupSizeOpticalFlowInputPyramid.y);
{
const int threadGroupSizeX = 32;
//const int threadGroupSizeY = 8;
int strataWidth = (_contextDescription.resolution.x / 4) / OpticalFlow.HistogramsPerDim;
int strataHeight = _contextDescription.resolution.y / OpticalFlow.HistogramsPerDim;
int dispatchX = (strataWidth + threadGroupSizeX - 1) / threadGroupSizeX;
const int dispatchY = 16;
const int dispatchZ = OpticalFlow.HistogramsPerDim * OpticalFlow.HistogramsPerDim;
_generateScdHistogramPass.ScheduleDispatch(commandBuffer, dispatchDescription, frameIndex, 0, dispatchX, dispatchY, dispatchZ);
}
{
const int dispatchX = OpticalFlow.HistogramsPerDim * OpticalFlow.HistogramsPerDim;
const int dispatchY = OpticalFlow.HistogramShifts;
_computeScdDivergencePass.ScheduleDispatch(commandBuffer, dispatchDescription, frameIndex, 0, dispatchX, dispatchY);
}
const int pyramidMaxIterations = advancedAlgorithmIterations;
Assert.IsTrue(pyramidMaxIterations <= OpticalFlow.OpticalFlowMaxPyramidLevels);
_opticalFlowTextureSizes[0] = OpticalFlow.GetOpticalFlowTextureSize(_contextDescription.resolution, opticalFlowBlockSize);
for (int i = 1; i < pyramidMaxIterations; ++i)
{
_opticalFlowTextureSizes[i] = new Vector2Int(
(_opticalFlowTextureSizes[i - 1].x + 1) / 2,
(_opticalFlowTextureSizes[i - 1].y + 1) / 2
);
}
for (int level = pyramidMaxIterations - 1; level >= 0; --level)
{
constants.opticalFlowPyramidLevel = (uint)level;
constants.opticalFlowPyramidLevelCount = pyramidMaxIterations;
_opticalFlowConstants.UpdateBufferData(commandBuffer);
{
int inputLumaWidth = Math.Max(_contextDescription.resolution.x >> level, 1);
int inputLumaHeight = Math.Max(_contextDescription.resolution.y >> level, 1);
const int threadPixels = 4;
Assert.IsTrue(opticalFlowBlockSize >= threadPixels);
//const int threadGroupSizeX = 4;
const int threadGroupSizeY = 16;
const int threadGroupSize = 64;
int dispatchX = ((inputLumaWidth + threadPixels - 1) / threadPixels * threadGroupSizeY + (threadGroupSize - 1)) / threadGroupSize;
int dispatchY = (inputLumaHeight + (threadGroupSizeY - 1)) / threadGroupSizeY;
_computeOpticalFlowPass.ScheduleDispatch(commandBuffer, dispatchDescription, frameIndex, level, dispatchX, dispatchY);
}
{
int levelWidth = _opticalFlowTextureSizes[level].x;
int levelHeight = _opticalFlowTextureSizes[level].y;
const int threadGroupSizeX = 16;
const int threadGroupSizeY = 4;
int dispatchX = (levelWidth + threadGroupSizeX - 1) / threadGroupSizeX;
int dispatchY = (levelHeight + threadGroupSizeY - 1) / threadGroupSizeY;
_filterOpticalFlowPass.ScheduleDispatch(commandBuffer, dispatchDescription, frameIndex, level, dispatchX, dispatchY);
}
if (level > 0)
{
int nextLevelWidth = _opticalFlowTextureSizes[level - 1].x;
int nextLevelHeight = _opticalFlowTextureSizes[level - 1].y;
const int threadGroupSizeX = opticalFlowBlockSize / 2;
const int threadGroupSizeY = opticalFlowBlockSize / 2;
//const int threadGroupSizeZ = 4;
int dispatchX = (nextLevelWidth + threadGroupSizeX - 1) / threadGroupSizeX;
int dispatchY = (nextLevelHeight + threadGroupSizeY - 1) / threadGroupSizeY;
const int dispatchZ = 1;
_scaleOpticalFlowPass.ScheduleDispatch(commandBuffer, dispatchDescription, frameIndex, level, dispatchX, dispatchY, dispatchZ);
}
}
commandBuffer.EndSample(_sampler);
_resourceFrameIndex = (_resourceFrameIndex + 1) % MaxQueuedFrames;
}
private void SetupSpdConstants(out Vector2Int dispatchThreadGroupCount)
{
const int resolutionMultiplier = 1;
ref OpticalFlow.SpdConstants spdConstants = ref _spdConstants.Value;
FfxSpd.SetupSpdConstants(_contextDescription.resolution * resolutionMultiplier, ref spdConstants.spd, out dispatchThreadGroupCount);
spdConstants.numWorkGroupsOpticalFlowInputPyramid = spdConstants.spd.numWorkGroups;
}
}
}

11
Runtime/OpticalFlow/OpticalFlowContext.cs.meta

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: baebcaebda3cbd344a546d7f3c47ae0d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

200
Runtime/OpticalFlow/OpticalFlowPass.cs

@ -0,0 +1,200 @@
using System;
using System.Runtime.InteropServices;
using UnityEngine;
using UnityEngine.Profiling;
using UnityEngine.Rendering;
namespace FidelityFX.FrameGen
{
internal abstract class OpticalFlowPass: FfxPassBase
{
protected readonly OpticalFlowResources Resources;
protected readonly ComputeBuffer Constants;
protected OpticalFlowPass(OpticalFlowResources resources, ComputeBuffer constants)
: base("Optical Flow")
{
Resources = resources;
Constants = constants;
}
public void ScheduleDispatch(CommandBuffer commandBuffer, in OpticalFlow.DispatchDescription dispatchParams, int bufferIndex, int level, int dispatchX, int dispatchY, int dispatchZ = 1)
{
using (ProfilerSample(commandBuffer))
{
Dispatch(commandBuffer, dispatchParams, bufferIndex, level, dispatchX, dispatchY, dispatchZ);
}
}
protected abstract void Dispatch(CommandBuffer commandBuffer, in OpticalFlow.DispatchDescription dispatchParams, int bufferIndex, int level, int dispatchX, int dispatchY, int dispatchZ);
}
internal sealed class OpticalFlowPrepareLumaPass : OpticalFlowPass
{
public OpticalFlowPrepareLumaPass(in OpticalFlow.ContextDescription contextDescription, OpticalFlowResources resources, ComputeBuffer constants)
: base(resources, constants)
{
InitComputeShader("Prepare Luma", contextDescription.shaders.prepareLuma);
}
protected override void Dispatch(CommandBuffer commandBuffer, in OpticalFlow.DispatchDescription dispatchParams, int bufferIndex, int level, int dispatchX, int dispatchY, int dispatchZ)
{
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, OpticalFlowShaderIDs.SrvInputColor, dispatchParams.color);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, OpticalFlowShaderIDs.UavOpticalFlowInput, Resources.OpticalFlowInputLevels[0][bufferIndex]);
commandBuffer.SetComputeConstantBufferParam<OpticalFlow.OpticalFlowConstants>(ComputeShader, OpticalFlowShaderIDs.CbOpticalFlow, Constants);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, dispatchZ);
}
}
internal sealed class OpticalFlowGenerateInputPyramidPass : OpticalFlowPass
{
private ComputeBuffer _spdConstants;
public OpticalFlowGenerateInputPyramidPass(in OpticalFlow.ContextDescription contextDescription, OpticalFlowResources resources, ComputeBuffer constants, ComputeBuffer spdConstants)
: base(resources, constants)
{
_spdConstants = spdConstants;
InitComputeShader("Generate Optical Flow Input Pyramid", contextDescription.shaders.generateOpticalFlowInputPyramid);
}
protected override void Dispatch(CommandBuffer commandBuffer, in OpticalFlow.DispatchDescription dispatchParams, int bufferIndex, int level, int dispatchX, int dispatchY, int dispatchZ)
{
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, OpticalFlowShaderIDs.UavOpticalFlowInput, Resources.OpticalFlowInputLevels[0][bufferIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, OpticalFlowShaderIDs.UavOpticalFlowInputLevel1, Resources.OpticalFlowInputLevels[1][bufferIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, OpticalFlowShaderIDs.UavOpticalFlowInputLevel2, Resources.OpticalFlowInputLevels[2][bufferIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, OpticalFlowShaderIDs.UavOpticalFlowInputLevel3, Resources.OpticalFlowInputLevels[3][bufferIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, OpticalFlowShaderIDs.UavOpticalFlowInputLevel4, Resources.OpticalFlowInputLevels[4][bufferIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, OpticalFlowShaderIDs.UavOpticalFlowInputLevel5, Resources.OpticalFlowInputLevels[5][bufferIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, OpticalFlowShaderIDs.UavOpticalFlowInputLevel6, Resources.OpticalFlowInputLevels[6][bufferIndex]);
commandBuffer.SetComputeConstantBufferParam<OpticalFlow.OpticalFlowConstants>(ComputeShader, OpticalFlowShaderIDs.CbOpticalFlow, Constants);
commandBuffer.SetComputeConstantBufferParam<OpticalFlow.SpdConstants>(ComputeShader, OpticalFlowShaderIDs.CbSpd, _spdConstants);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, dispatchZ);
}
}
internal sealed class OpticalFlowGenerateSCDHistogramPass : OpticalFlowPass
{
public OpticalFlowGenerateSCDHistogramPass(in OpticalFlow.ContextDescription contextDescription, OpticalFlowResources resources, ComputeBuffer constants)
: base(resources, constants)
{
InitComputeShader("Generate SCD Histogram", contextDescription.shaders.generateScdHistogram);
}
protected override void Dispatch(CommandBuffer commandBuffer, in OpticalFlow.DispatchDescription dispatchParams, int bufferIndex, int level, int dispatchX, int dispatchY, int dispatchZ)
{
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, OpticalFlowShaderIDs.SrvOpticalFlowInput, Resources.OpticalFlowInputLevels[0][bufferIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, OpticalFlowShaderIDs.UavOpticalFlowScdHistogram, Resources.OpticalFlowSCDHistogram);
commandBuffer.SetComputeConstantBufferParam<OpticalFlow.OpticalFlowConstants>(ComputeShader, OpticalFlowShaderIDs.CbOpticalFlow, Constants);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, dispatchZ);
}
}
internal sealed class OpticalFlowComputeSCDDivergencePass : OpticalFlowPass
{
public OpticalFlowComputeSCDDivergencePass(in OpticalFlow.ContextDescription contextDescription, OpticalFlowResources resources, ComputeBuffer constants)
: base(resources, constants)
{
InitComputeShader("Compute SCD Divergence", contextDescription.shaders.computeScdDivergence);
}
protected override void Dispatch(CommandBuffer commandBuffer, in OpticalFlow.DispatchDescription dispatchParams, int bufferIndex, int level, int dispatchX, int dispatchY, int dispatchZ)
{
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, OpticalFlowShaderIDs.UavOpticalFlowScdHistogram, Resources.OpticalFlowSCDHistogram);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, OpticalFlowShaderIDs.UavOpticalFlowScdPreviousHistogram, Resources.OpticalFlowSCDPreviousHistogram);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, OpticalFlowShaderIDs.UavOpticalFlowScdTemp, Resources.OpticalFlowSCDTemp);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, OpticalFlowShaderIDs.UavOpticalFlowScdOutput, dispatchParams.opticalFlowSCD);
commandBuffer.SetComputeConstantBufferParam<OpticalFlow.OpticalFlowConstants>(ComputeShader, OpticalFlowShaderIDs.CbOpticalFlow, Constants);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, dispatchZ);
}
}
internal sealed class OpticalFlowComputePass : OpticalFlowPass
{
public OpticalFlowComputePass(in OpticalFlow.ContextDescription contextDescription, OpticalFlowResources resources, ComputeBuffer constants)
: base(resources, constants)
{
InitComputeShader("Optical Flow Search", contextDescription.shaders.computeOpticalFlow);
}
protected override void Dispatch(CommandBuffer commandBuffer, in OpticalFlow.DispatchDescription dispatchParams, int bufferIndex, int level, int dispatchX, int dispatchY, int dispatchZ)
{
int levelIndex = bufferIndex ^ (level & 1);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, OpticalFlowShaderIDs.SrvOpticalFlowInput, Resources.OpticalFlowInputLevels[level][bufferIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, OpticalFlowShaderIDs.SrvOpticalFlowPreviousInput, Resources.OpticalFlowInputLevels[level][bufferIndex ^ 1]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, OpticalFlowShaderIDs.UavOpticalFlow, Resources.OpticalFlowLevels[level][levelIndex]);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, OpticalFlowShaderIDs.UavOpticalFlowScdOutput, dispatchParams.opticalFlowSCD);
commandBuffer.SetComputeConstantBufferParam<OpticalFlow.OpticalFlowConstants>(ComputeShader, OpticalFlowShaderIDs.CbOpticalFlow, Constants);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, dispatchZ);
}
}
internal sealed class OpticalFlowFilterPass : OpticalFlowPass
{
public OpticalFlowFilterPass(in OpticalFlow.ContextDescription contextDescription, OpticalFlowResources resources, ComputeBuffer constants)
: base(resources, constants)
{
InitComputeShader("Optical Flow Filter", contextDescription.shaders.filterOpticalFlow);
}
protected override void Dispatch(CommandBuffer commandBuffer, in OpticalFlow.DispatchDescription dispatchParams, int bufferIndex, int level, int dispatchX, int dispatchY, int dispatchZ)
{
int levelIndex = bufferIndex ^ (level & 1);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, OpticalFlowShaderIDs.SrvOpticalFlowPrevious, Resources.OpticalFlowLevels[level][levelIndex]);
if (level == 0)
{
// Final output (levels are counted in reverse)
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, OpticalFlowShaderIDs.UavOpticalFlow, dispatchParams.opticalFlowVector);
}
else
{
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, OpticalFlowShaderIDs.UavOpticalFlow, Resources.OpticalFlowLevels[level][levelIndex ^ 1]);
}
commandBuffer.SetComputeConstantBufferParam<OpticalFlow.OpticalFlowConstants>(ComputeShader, OpticalFlowShaderIDs.CbOpticalFlow, Constants);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, dispatchZ);
}
}
internal sealed class OpticalFlowScalePass : OpticalFlowPass
{
public OpticalFlowScalePass(in OpticalFlow.ContextDescription contextDescription, OpticalFlowResources resources, ComputeBuffer constants)
: base(resources, constants)
{
InitComputeShader("Optical Flow Scale", contextDescription.shaders.scaleOpticalFlow);
}
protected override void Dispatch(CommandBuffer commandBuffer, in OpticalFlow.DispatchDescription dispatchParams, int bufferIndex, int level, int dispatchX, int dispatchY, int dispatchZ)
{
if (level <= 0)
return;
int levelIndex = bufferIndex ^ (level & 1);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, OpticalFlowShaderIDs.SrvOpticalFlowInput, Resources.OpticalFlowInputLevels[level][bufferIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, OpticalFlowShaderIDs.SrvOpticalFlowPreviousInput, Resources.OpticalFlowInputLevels[level][bufferIndex ^ 1]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, OpticalFlowShaderIDs.SrvOpticalFlow, Resources.OpticalFlowLevels[level][levelIndex ^ 1]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, OpticalFlowShaderIDs.UavOpticalFlowNextLevel, Resources.OpticalFlowLevels[level - 1][levelIndex ^ 1]);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, OpticalFlowShaderIDs.UavOpticalFlowScdOutput, dispatchParams.opticalFlowSCD);
commandBuffer.SetComputeConstantBufferParam<OpticalFlow.OpticalFlowConstants>(ComputeShader, OpticalFlowShaderIDs.CbOpticalFlow, Constants);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, dispatchZ);
}
}
}

11
Runtime/OpticalFlow/OpticalFlowPass.cs.meta

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a509b94b3bffef549b9d3316b44df221
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

76
Runtime/OpticalFlow/OpticalFlowResources.cs

@ -0,0 +1,76 @@
using UnityEngine;
using UnityEngine.Experimental.Rendering;
namespace FidelityFX.FrameGen
{
internal class OpticalFlowResources: FfxResourcesBase
{
public readonly RenderTexture[][] OpticalFlowInputLevels =
{
new RenderTexture[2],
new RenderTexture[2],
new RenderTexture[2],
new RenderTexture[2],
new RenderTexture[2],
new RenderTexture[2],
new RenderTexture[2],
};
public readonly RenderTexture[][] OpticalFlowLevels =
{
new RenderTexture[2],
new RenderTexture[2],
new RenderTexture[2],
new RenderTexture[2],
new RenderTexture[2],
new RenderTexture[2],
new RenderTexture[2],
};
public RenderTexture OpticalFlowSCDHistogram;
public RenderTexture OpticalFlowSCDPreviousHistogram;
public RenderTexture OpticalFlowSCDTemp;
public void Create(in OpticalFlow.ContextDescription contextDescription)
{
Vector2Int opticalFlowInputTextureSize = contextDescription.resolution;
Vector2Int opticalFlowTextureSize = OpticalFlow.GetOpticalFlowTextureSize(contextDescription.resolution, OpticalFlow.MinBlockSize);
for (int level = 0; level < OpticalFlow.OpticalFlowMaxPyramidLevels; ++level)
{
CreateDoubleBufferedResource(OpticalFlowInputLevels[level], $"OPTICALFLOW_OpticalFlowInputLevel{level}-", opticalFlowInputTextureSize, GraphicsFormat.R8_UInt);
CreateDoubleBufferedResource(OpticalFlowLevels[level], $"OPTICALFLOW_OpticalFlowLevel{level}-", opticalFlowTextureSize, GraphicsFormat.R16G16_SInt);
opticalFlowTextureSize = NextLevelSize(opticalFlowTextureSize);
opticalFlowInputTextureSize = new Vector2Int(opticalFlowInputTextureSize.x >> 1, opticalFlowInputTextureSize.y >> 1);
}
OpticalFlowSCDHistogram = CreateResource("OPTICALFLOW_OpticalFlowSCDHistogram", new Vector2Int(OpticalFlow.GetSCDHistogramTextureWidth(), 1), GraphicsFormat.R32_UInt);
OpticalFlowSCDPreviousHistogram = CreateResource("OPTICALFLOW_OpticalFlowSCDPreviousHistogram", new Vector2Int(OpticalFlow.GetSCDHistogramTextureWidth(), 1), GraphicsFormat.R32_SFloat);
OpticalFlowSCDTemp = CreateResource("OPTICALFLOW_OpticalFlowSCDTemp", new Vector2Int(3, 1), GraphicsFormat.R32_UInt);
}
public void Destroy()
{
DestroyResource(ref OpticalFlowSCDTemp);
DestroyResource(ref OpticalFlowSCDPreviousHistogram);
DestroyResource(ref OpticalFlowSCDHistogram);
for (int level = 0; level < OpticalFlow.OpticalFlowMaxPyramidLevels; ++level)
{
DestroyResource(OpticalFlowLevels[level]);
DestroyResource(OpticalFlowInputLevels[level]);
}
}
private static Vector2Int NextLevelSize(Vector2Int size)
{
return new Vector2Int(AlignUp(size.x, 2) / 2, AlignUp(size.y, 2) / 2);
}
private static int AlignUp(int x, int y)
{
return (x + (y - 1)) & ~(y - 1);
}
}
}

11
Runtime/OpticalFlow/OpticalFlowResources.cs.meta

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 56e728c675f67404a966d919d71f9041
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

33
Runtime/OpticalFlow/OpticalFlowShaderIDs.cs

@ -0,0 +1,33 @@
using UnityEngine;
namespace FidelityFX.FrameGen
{
public static class OpticalFlowShaderIDs
{
// Shader resource views, i.e. read-only bindings
public static readonly int SrvInputColor = Shader.PropertyToID("r_input_color");
public static readonly int SrvOpticalFlowInput = Shader.PropertyToID("r_optical_flow_input");
public static readonly int SrvOpticalFlowPreviousInput = Shader.PropertyToID("r_optical_flow_previous_input");
public static readonly int SrvOpticalFlow = Shader.PropertyToID("r_optical_flow");
public static readonly int SrvOpticalFlowPrevious = Shader.PropertyToID("r_optical_flow_previous");
// Unordered access views, i.e. random read/write bindings
public static readonly int UavOpticalFlowInput = Shader.PropertyToID("rw_optical_flow_input");
public static readonly int UavOpticalFlowInputLevel1 = Shader.PropertyToID("rw_optical_flow_input_level_1");
public static readonly int UavOpticalFlowInputLevel2 = Shader.PropertyToID("rw_optical_flow_input_level_2");
public static readonly int UavOpticalFlowInputLevel3 = Shader.PropertyToID("rw_optical_flow_input_level_3");
public static readonly int UavOpticalFlowInputLevel4 = Shader.PropertyToID("rw_optical_flow_input_level_4");
public static readonly int UavOpticalFlowInputLevel5 = Shader.PropertyToID("rw_optical_flow_input_level_5");
public static readonly int UavOpticalFlowInputLevel6 = Shader.PropertyToID("rw_optical_flow_input_level_6");
public static readonly int UavOpticalFlow = Shader.PropertyToID("rw_optical_flow");
public static readonly int UavOpticalFlowNextLevel = Shader.PropertyToID("rw_optical_flow_next_level");
public static readonly int UavOpticalFlowScdHistogram = Shader.PropertyToID("rw_optical_flow_scd_histogram"); // scene change detection histogram
public static readonly int UavOpticalFlowScdPreviousHistogram = Shader.PropertyToID("rw_optical_flow_scd_previous_histogram");
public static readonly int UavOpticalFlowScdTemp = Shader.PropertyToID("rw_optical_flow_scd_temp");
public static readonly int UavOpticalFlowScdOutput = Shader.PropertyToID("rw_optical_flow_scd_output");
// Constant buffer bindings
public static readonly int CbOpticalFlow = Shader.PropertyToID("cbOF");
public static readonly int CbSpd = Shader.PropertyToID("cbOF_SPD");
}
}

11
Runtime/OpticalFlow/OpticalFlowShaderIDs.cs.meta

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 12d00661151ef1b468cbe643922fc0cc
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

33
Shaders/ffx_frameinterpolation_compute_game_vector_field_inpainting_pyramid_pass.compute

@ -0,0 +1,33 @@
// Copyright (c) 2024 Nico de Poel
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#pragma only_renderers d3d11 playstation xboxone xboxseries vulkan metal switch
#pragma kernel CS
#pragma multi_compile_local __ FFX_FRAMEINTERPOLATION_OPTION_LOW_RES_MOTION_VECTORS
#pragma multi_compile_local __ FFX_FRAMEINTERPOLATION_OPTION_INVERTED_DEPTH
#pragma use_dxc
#pragma require WaveBasic
#include "ffx_unity_common.cginc"
#include "shaders/ffx_frameinterpolation_compute_game_vector_field_inpainting_pyramid_pass.hlsl"

8
Shaders/ffx_frameinterpolation_compute_game_vector_field_inpainting_pyramid_pass.compute.meta

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: e9b3faa41d2279344857aa1643c74c54
ComputeShaderImporter:
externalObjects: {}
preprocessorOverride: 0
userData:
assetBundleName:
assetBundleVariant:

33
Shaders/ffx_frameinterpolation_compute_inpainting_pyramid_pass.compute

@ -0,0 +1,33 @@
// Copyright (c) 2024 Nico de Poel
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#pragma only_renderers d3d11 playstation xboxone xboxseries vulkan metal switch
#pragma kernel CS
#pragma multi_compile_local __ FFX_FRAMEINTERPOLATION_OPTION_LOW_RES_MOTION_VECTORS
#pragma multi_compile_local __ FFX_FRAMEINTERPOLATION_OPTION_INVERTED_DEPTH
#pragma use_dxc
#pragma require WaveBasic
#include "ffx_unity_common.cginc"
#include "shaders/ffx_frameinterpolation_compute_inpainting_pyramid_pass.hlsl"

8
Shaders/ffx_frameinterpolation_compute_inpainting_pyramid_pass.compute.meta

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: b171a3b3146508a4ebe6ecf70d112568
ComputeShaderImporter:
externalObjects: {}
preprocessorOverride: 0
userData:
assetBundleName:
assetBundleVariant:

33
Shaders/ffx_frameinterpolation_debug_view_pass.compute

@ -0,0 +1,33 @@
// Copyright (c) 2024 Nico de Poel
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#pragma only_renderers d3d11 playstation xboxone xboxseries vulkan metal switch
#pragma kernel CS
#pragma multi_compile_local __ FFX_FRAMEINTERPOLATION_OPTION_LOW_RES_MOTION_VECTORS
#pragma multi_compile_local __ FFX_FRAMEINTERPOLATION_OPTION_INVERTED_DEPTH
#pragma use_dxc
#pragma require WaveBasic
#include "ffx_unity_common.cginc"
#include "shaders/ffx_frameinterpolation_debug_view_pass.hlsl"

8
Shaders/ffx_frameinterpolation_debug_view_pass.compute.meta

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 63512d6a875b7f749b69f1e1dab1db24
ComputeShaderImporter:
externalObjects: {}
preprocessorOverride: 0
userData:
assetBundleName:
assetBundleVariant:

33
Shaders/ffx_frameinterpolation_disocclusion_mask_pass.compute

@ -0,0 +1,33 @@
// Copyright (c) 2024 Nico de Poel
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#pragma only_renderers d3d11 playstation xboxone xboxseries vulkan metal switch
#pragma kernel CS
#pragma multi_compile_local __ FFX_FRAMEINTERPOLATION_OPTION_LOW_RES_MOTION_VECTORS
#pragma multi_compile_local __ FFX_FRAMEINTERPOLATION_OPTION_INVERTED_DEPTH
#pragma use_dxc
#pragma require WaveBasic
#include "ffx_unity_common.cginc"
#include "shaders/ffx_frameinterpolation_disocclusion_mask_pass.hlsl"

8
Shaders/ffx_frameinterpolation_disocclusion_mask_pass.compute.meta

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: eff2ebf6818194848a6bda41001d845a
ComputeShaderImporter:
externalObjects: {}
preprocessorOverride: 0
userData:
assetBundleName:
assetBundleVariant:

33
Shaders/ffx_frameinterpolation_game_motion_vector_field_pass.compute

@ -0,0 +1,33 @@
// Copyright (c) 2024 Nico de Poel
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#pragma only_renderers d3d11 playstation xboxone xboxseries vulkan metal switch
#pragma kernel CS
#pragma multi_compile_local __ FFX_FRAMEINTERPOLATION_OPTION_LOW_RES_MOTION_VECTORS
#pragma multi_compile_local __ FFX_FRAMEINTERPOLATION_OPTION_INVERTED_DEPTH
#pragma use_dxc
#pragma require WaveBasic
#include "ffx_unity_common.cginc"
#include "shaders/ffx_frameinterpolation_game_motion_vector_field_pass.hlsl"

8
Shaders/ffx_frameinterpolation_game_motion_vector_field_pass.compute.meta

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 71e44c470ff3d6346b75aaa5edc608b5
ComputeShaderImporter:
externalObjects: {}
preprocessorOverride: 0
userData:
assetBundleName:
assetBundleVariant:

33
Shaders/ffx_frameinterpolation_inpainting_pass.compute

@ -0,0 +1,33 @@
// Copyright (c) 2024 Nico de Poel
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#pragma only_renderers d3d11 playstation xboxone xboxseries vulkan metal switch
#pragma kernel CS
#pragma multi_compile_local __ FFX_FRAMEINTERPOLATION_OPTION_LOW_RES_MOTION_VECTORS
#pragma multi_compile_local __ FFX_FRAMEINTERPOLATION_OPTION_INVERTED_DEPTH
#pragma use_dxc
#pragma require WaveBasic
#include "ffx_unity_common.cginc"
#include "shaders/ffx_frameinterpolation_inpainting_pass.hlsl"

8
Shaders/ffx_frameinterpolation_inpainting_pass.compute.meta

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: d9affbaf53b13854898a7fd84c66e487
ComputeShaderImporter:
externalObjects: {}
preprocessorOverride: 0
userData:
assetBundleName:
assetBundleVariant:

33
Shaders/ffx_frameinterpolation_optical_flow_vector_field_pass.compute

@ -0,0 +1,33 @@
// Copyright (c) 2024 Nico de Poel
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#pragma only_renderers d3d11 playstation xboxone xboxseries vulkan metal switch
#pragma kernel CS
#pragma multi_compile_local __ FFX_FRAMEINTERPOLATION_OPTION_LOW_RES_MOTION_VECTORS
#pragma multi_compile_local __ FFX_FRAMEINTERPOLATION_OPTION_INVERTED_DEPTH
#pragma use_dxc
#pragma require WaveBasic
#include "ffx_unity_common.cginc"
#include "shaders/ffx_frameinterpolation_optical_flow_vector_field_pass.hlsl"

8
Shaders/ffx_frameinterpolation_optical_flow_vector_field_pass.compute.meta

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: b89c0efd0c4ccad468e76ded24ac4bdf
ComputeShaderImporter:
externalObjects: {}
preprocessorOverride: 0
userData:
assetBundleName:
assetBundleVariant:

33
Shaders/ffx_frameinterpolation_pass.compute

@ -0,0 +1,33 @@
// Copyright (c) 2024 Nico de Poel
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#pragma only_renderers d3d11 playstation xboxone xboxseries vulkan metal switch
#pragma kernel CS
#pragma multi_compile_local __ FFX_FRAMEINTERPOLATION_OPTION_LOW_RES_MOTION_VECTORS
#pragma multi_compile_local __ FFX_FRAMEINTERPOLATION_OPTION_INVERTED_DEPTH
#pragma use_dxc
#pragma require WaveBasic
#include "ffx_unity_common.cginc"
#include "shaders/ffx_frameinterpolation_pass.hlsl"

8
Shaders/ffx_frameinterpolation_pass.compute.meta

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 58d390c8d43f74c42832f68ef4597133
ComputeShaderImporter:
externalObjects: {}
preprocessorOverride: 0
userData:
assetBundleName:
assetBundleVariant:

34
Shaders/ffx_frameinterpolation_reconstruct_and_dilate_pass.compute

@ -0,0 +1,34 @@
// Copyright (c) 2024 Nico de Poel
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#pragma only_renderers d3d11 playstation xboxone xboxseries vulkan metal switch
#pragma kernel CS
#pragma multi_compile_local __ FFX_FRAMEINTERPOLATION_OPTION_LOW_RES_MOTION_VECTORS
#pragma multi_compile_local __ FFX_FRAMEINTERPOLATION_OPTION_JITTERED_MOTION_VECTORS
#pragma multi_compile_local __ FFX_FRAMEINTERPOLATION_OPTION_INVERTED_DEPTH
#pragma use_dxc
#pragma require WaveBasic
#include "ffx_unity_common.cginc"
#include "shaders/ffx_frameinterpolation_reconstruct_and_dilate_pass.hlsl"

8
Shaders/ffx_frameinterpolation_reconstruct_and_dilate_pass.compute.meta

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 8502d70e8836f5e4c818069fbc90a683
ComputeShaderImporter:
externalObjects: {}
preprocessorOverride: 0
userData:
assetBundleName:
assetBundleVariant:

33
Shaders/ffx_frameinterpolation_reconstruct_previous_depth_pass.compute

@ -0,0 +1,33 @@
// Copyright (c) 2024 Nico de Poel
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#pragma only_renderers d3d11 playstation xboxone xboxseries vulkan metal switch
#pragma kernel CS
#pragma multi_compile_local __ FFX_FRAMEINTERPOLATION_OPTION_LOW_RES_MOTION_VECTORS
#pragma multi_compile_local __ FFX_FRAMEINTERPOLATION_OPTION_INVERTED_DEPTH
#pragma use_dxc
#pragma require WaveBasic
#include "ffx_unity_common.cginc"
#include "shaders/ffx_frameinterpolation_reconstruct_previous_depth_pass.hlsl"

8
Shaders/ffx_frameinterpolation_reconstruct_previous_depth_pass.compute.meta

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: b665305f7d728ed478c661e3d0fa4d46
ComputeShaderImporter:
externalObjects: {}
preprocessorOverride: 0
userData:
assetBundleName:
assetBundleVariant:

33
Shaders/ffx_frameinterpolation_setup_pass.compute

@ -0,0 +1,33 @@
// Copyright (c) 2024 Nico de Poel
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#pragma only_renderers d3d11 playstation xboxone xboxseries vulkan metal switch
#pragma kernel CS
#pragma multi_compile_local __ FFX_FRAMEINTERPOLATION_OPTION_LOW_RES_MOTION_VECTORS
#pragma multi_compile_local __ FFX_FRAMEINTERPOLATION_OPTION_INVERTED_DEPTH
#pragma use_dxc
#pragma require WaveBasic
#include "ffx_unity_common.cginc"
#include "shaders/ffx_frameinterpolation_setup_pass.hlsl"

8
Shaders/ffx_frameinterpolation_setup_pass.compute.meta

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: b4821f6dac05a804e9ad78b957888248
ComputeShaderImporter:
externalObjects: {}
preprocessorOverride: 0
userData:
assetBundleName:
assetBundleVariant:

4
Shaders/ffx_fsr2_accumulate_pass.compute

@ -28,9 +28,9 @@
#pragma multi_compile_local __ FFX_FSR2_OPTION_INVERTED_DEPTH #pragma multi_compile_local __ FFX_FSR2_OPTION_INVERTED_DEPTH
#pragma multi_compile_local __ FFX_FSR2_OPTION_APPLY_SHARPENING #pragma multi_compile_local __ FFX_FSR2_OPTION_APPLY_SHARPENING
#pragma multi_compile __ UNITY_FSR_TEXTURE2D_X_ARRAY
#pragma multi_compile __ UNITY_FFX_TEXTURE2D_X_ARRAY
#include "ffx_fsr_unity_common.cginc"
#include "ffx_unity_common.cginc"
// Ensure the correct value is defined for this keyword, as it is used to select one of multiple sampler functions // Ensure the correct value is defined for this keyword, as it is used to select one of multiple sampler functions
#ifdef FFX_FSR2_OPTION_REPROJECT_USE_LANCZOS_TYPE #ifdef FFX_FSR2_OPTION_REPROJECT_USE_LANCZOS_TYPE

4
Shaders/ffx_fsr2_autogen_reactive_pass.compute

@ -25,8 +25,8 @@
#pragma multi_compile_local __ FFX_FSR2_OPTION_JITTERED_MOTION_VECTORS #pragma multi_compile_local __ FFX_FSR2_OPTION_JITTERED_MOTION_VECTORS
#pragma multi_compile_local __ FFX_FSR2_OPTION_INVERTED_DEPTH #pragma multi_compile_local __ FFX_FSR2_OPTION_INVERTED_DEPTH
#pragma multi_compile __ UNITY_FSR_TEXTURE2D_X_ARRAY
#pragma multi_compile __ UNITY_FFX_TEXTURE2D_X_ARRAY
#include "ffx_fsr_unity_common.cginc"
#include "ffx_unity_common.cginc"
#include "shaders/ffx_fsr2_autogen_reactive_pass.hlsl" #include "shaders/ffx_fsr2_autogen_reactive_pass.hlsl"

4
Shaders/ffx_fsr2_compute_luminance_pyramid_pass.compute

@ -25,9 +25,9 @@
#pragma multi_compile_local __ FFX_FSR2_OPTION_JITTERED_MOTION_VECTORS #pragma multi_compile_local __ FFX_FSR2_OPTION_JITTERED_MOTION_VECTORS
#pragma multi_compile_local __ FFX_FSR2_OPTION_INVERTED_DEPTH #pragma multi_compile_local __ FFX_FSR2_OPTION_INVERTED_DEPTH
#pragma multi_compile __ UNITY_FSR_TEXTURE2D_X_ARRAY
#pragma multi_compile __ UNITY_FFX_TEXTURE2D_X_ARRAY
#include "ffx_fsr_unity_common.cginc"
#include "ffx_unity_common.cginc"
// Wave operations require shader model 6.0; this can only be enabled when using DXC on D3D12 // Wave operations require shader model 6.0; this can only be enabled when using DXC on D3D12
// These pragmas are commented out by default as Unity will sometimes ignore the #if's and try to enable these features anyway. // These pragmas are commented out by default as Unity will sometimes ignore the #if's and try to enable these features anyway.

4
Shaders/ffx_fsr2_depth_clip_pass.compute

@ -25,8 +25,8 @@
#pragma multi_compile_local __ FFX_FSR2_OPTION_JITTERED_MOTION_VECTORS #pragma multi_compile_local __ FFX_FSR2_OPTION_JITTERED_MOTION_VECTORS
#pragma multi_compile_local __ FFX_FSR2_OPTION_INVERTED_DEPTH #pragma multi_compile_local __ FFX_FSR2_OPTION_INVERTED_DEPTH
#pragma multi_compile __ UNITY_FSR_TEXTURE2D_X_ARRAY
#pragma multi_compile __ UNITY_FFX_TEXTURE2D_X_ARRAY
#include "ffx_fsr_unity_common.cginc"
#include "ffx_unity_common.cginc"
#include "shaders/ffx_fsr2_depth_clip_pass.hlsl" #include "shaders/ffx_fsr2_depth_clip_pass.hlsl"

4
Shaders/ffx_fsr2_lock_pass.compute

@ -25,8 +25,8 @@
#pragma multi_compile_local __ FFX_FSR2_OPTION_JITTERED_MOTION_VECTORS #pragma multi_compile_local __ FFX_FSR2_OPTION_JITTERED_MOTION_VECTORS
#pragma multi_compile_local __ FFX_FSR2_OPTION_INVERTED_DEPTH #pragma multi_compile_local __ FFX_FSR2_OPTION_INVERTED_DEPTH
#pragma multi_compile __ UNITY_FSR_TEXTURE2D_X_ARRAY
#pragma multi_compile __ UNITY_FFX_TEXTURE2D_X_ARRAY
#include "ffx_fsr_unity_common.cginc"
#include "ffx_unity_common.cginc"
#include "shaders/ffx_fsr2_lock_pass.hlsl" #include "shaders/ffx_fsr2_lock_pass.hlsl"

4
Shaders/ffx_fsr2_rcas_pass.compute

@ -24,8 +24,8 @@
#pragma multi_compile_local __ FFX_FSR2_OPTION_JITTERED_MOTION_VECTORS #pragma multi_compile_local __ FFX_FSR2_OPTION_JITTERED_MOTION_VECTORS
#pragma multi_compile_local __ FFX_FSR2_OPTION_INVERTED_DEPTH #pragma multi_compile_local __ FFX_FSR2_OPTION_INVERTED_DEPTH
#pragma multi_compile __ UNITY_FSR_TEXTURE2D_X_ARRAY
#pragma multi_compile __ UNITY_FFX_TEXTURE2D_X_ARRAY
#include "ffx_fsr_unity_common.cginc"
#include "ffx_unity_common.cginc"
#include "shaders/ffx_fsr2_rcas_pass.hlsl" #include "shaders/ffx_fsr2_rcas_pass.hlsl"

4
Shaders/ffx_fsr2_reconstruct_previous_depth_pass.compute

@ -26,8 +26,8 @@
#pragma multi_compile_local __ FFX_FSR2_OPTION_JITTERED_MOTION_VECTORS #pragma multi_compile_local __ FFX_FSR2_OPTION_JITTERED_MOTION_VECTORS
#pragma multi_compile_local __ FFX_FSR2_OPTION_INVERTED_DEPTH #pragma multi_compile_local __ FFX_FSR2_OPTION_INVERTED_DEPTH
#pragma multi_compile __ UNITY_FSR_TEXTURE2D_X_ARRAY
#pragma multi_compile __ UNITY_FFX_TEXTURE2D_X_ARRAY
#include "ffx_fsr_unity_common.cginc"
#include "ffx_unity_common.cginc"
#include "shaders/ffx_fsr2_reconstruct_previous_depth_pass.hlsl" #include "shaders/ffx_fsr2_reconstruct_previous_depth_pass.hlsl"

4
Shaders/ffx_fsr2_tcr_autogen_pass.compute

@ -25,8 +25,8 @@
#pragma multi_compile_local __ FFX_FSR2_OPTION_JITTERED_MOTION_VECTORS #pragma multi_compile_local __ FFX_FSR2_OPTION_JITTERED_MOTION_VECTORS
#pragma multi_compile_local __ FFX_FSR2_OPTION_INVERTED_DEPTH #pragma multi_compile_local __ FFX_FSR2_OPTION_INVERTED_DEPTH
#pragma multi_compile __ UNITY_FSR_TEXTURE2D_X_ARRAY
#pragma multi_compile __ UNITY_FFX_TEXTURE2D_X_ARRAY
#include "ffx_fsr_unity_common.cginc"
#include "ffx_unity_common.cginc"
#include "shaders/ffx_fsr2_tcr_autogen_pass.hlsl" #include "shaders/ffx_fsr2_tcr_autogen_pass.hlsl"

4
Shaders/ffx_fsr3upscaler_accumulate_pass.compute

@ -26,9 +26,9 @@
#pragma multi_compile_local __ FFX_FSR3UPSCALER_OPTION_LOW_RESOLUTION_MOTION_VECTORS #pragma multi_compile_local __ FFX_FSR3UPSCALER_OPTION_LOW_RESOLUTION_MOTION_VECTORS
#pragma multi_compile_local __ FFX_FSR3UPSCALER_OPTION_APPLY_SHARPENING #pragma multi_compile_local __ FFX_FSR3UPSCALER_OPTION_APPLY_SHARPENING
#pragma multi_compile __ UNITY_FSR_TEXTURE2D_X_ARRAY
#pragma multi_compile __ UNITY_FFX_TEXTURE2D_X_ARRAY
#include "ffx_fsr_unity_common.cginc"
#include "ffx_unity_common.cginc"
// Ensure the correct value is defined for this keyword, as it is used to select one of multiple sampler functions // Ensure the correct value is defined for this keyword, as it is used to select one of multiple sampler functions
#ifdef FFX_FSR3UPSCALER_OPTION_REPROJECT_USE_LANCZOS_TYPE #ifdef FFX_FSR3UPSCALER_OPTION_REPROJECT_USE_LANCZOS_TYPE

4
Shaders/ffx_fsr3upscaler_autogen_reactive_pass.compute

@ -22,8 +22,8 @@
#pragma multi_compile_local __ FFX_HALF #pragma multi_compile_local __ FFX_HALF
#pragma multi_compile __ UNITY_FSR_TEXTURE2D_X_ARRAY
#pragma multi_compile __ UNITY_FFX_TEXTURE2D_X_ARRAY
#include "ffx_fsr_unity_common.cginc"
#include "ffx_unity_common.cginc"
#include "shaders/ffx_fsr3upscaler_autogen_reactive_pass.hlsl" #include "shaders/ffx_fsr3upscaler_autogen_reactive_pass.hlsl"

4
Shaders/ffx_fsr3upscaler_debug_view_pass.compute

@ -22,8 +22,8 @@
#pragma multi_compile_local __ FFX_HALF #pragma multi_compile_local __ FFX_HALF
#pragma multi_compile __ UNITY_FSR_TEXTURE2D_X_ARRAY
#pragma multi_compile __ UNITY_FFX_TEXTURE2D_X_ARRAY
#include "ffx_fsr_unity_common.cginc"
#include "ffx_unity_common.cginc"
#include "shaders/ffx_fsr3upscaler_debug_view_pass.hlsl" #include "shaders/ffx_fsr3upscaler_debug_view_pass.hlsl"

4
Shaders/ffx_fsr3upscaler_luma_instability_pass.compute

@ -22,8 +22,8 @@
#pragma multi_compile_local __ FFX_HALF #pragma multi_compile_local __ FFX_HALF
#pragma multi_compile __ UNITY_FSR_TEXTURE2D_X_ARRAY
#pragma multi_compile __ UNITY_FFX_TEXTURE2D_X_ARRAY
#include "ffx_fsr_unity_common.cginc"
#include "ffx_unity_common.cginc"
#include "shaders/ffx_fsr3upscaler_luma_instability_pass.hlsl" #include "shaders/ffx_fsr3upscaler_luma_instability_pass.hlsl"

4
Shaders/ffx_fsr3upscaler_luma_pyramid_pass.compute

@ -22,9 +22,9 @@
#pragma multi_compile_local __ FFX_HALF #pragma multi_compile_local __ FFX_HALF
#pragma multi_compile __ UNITY_FSR_TEXTURE2D_X_ARRAY
#pragma multi_compile __ UNITY_FFX_TEXTURE2D_X_ARRAY
#include "ffx_fsr_unity_common.cginc"
#include "ffx_unity_common.cginc"
// Wave operations require shader model 6.0; this can only be enabled when using DXC on D3D12 // Wave operations require shader model 6.0; this can only be enabled when using DXC on D3D12
// These pragmas are commented out by default as Unity will sometimes ignore the #if's and try to enable these features anyway. // These pragmas are commented out by default as Unity will sometimes ignore the #if's and try to enable these features anyway.

4
Shaders/ffx_fsr3upscaler_prepare_inputs_pass.compute

@ -24,8 +24,8 @@
#pragma multi_compile_local __ FFX_FSR3UPSCALER_OPTION_LOW_RESOLUTION_MOTION_VECTORS #pragma multi_compile_local __ FFX_FSR3UPSCALER_OPTION_LOW_RESOLUTION_MOTION_VECTORS
#pragma multi_compile_local __ FFX_FSR3UPSCALER_OPTION_INVERTED_DEPTH #pragma multi_compile_local __ FFX_FSR3UPSCALER_OPTION_INVERTED_DEPTH
#pragma multi_compile __ UNITY_FSR_TEXTURE2D_X_ARRAY
#pragma multi_compile __ UNITY_FFX_TEXTURE2D_X_ARRAY
#include "ffx_fsr_unity_common.cginc"
#include "ffx_unity_common.cginc"
#include "shaders/ffx_fsr3upscaler_prepare_inputs_pass.hlsl" #include "shaders/ffx_fsr3upscaler_prepare_inputs_pass.hlsl"

4
Shaders/ffx_fsr3upscaler_prepare_reactivity_pass.compute

@ -22,8 +22,8 @@
#pragma multi_compile_local __ FFX_HALF #pragma multi_compile_local __ FFX_HALF
#pragma multi_compile __ UNITY_FSR_TEXTURE2D_X_ARRAY
#pragma multi_compile __ UNITY_FFX_TEXTURE2D_X_ARRAY
#include "ffx_fsr_unity_common.cginc"
#include "ffx_unity_common.cginc"
#include "shaders/ffx_fsr3upscaler_prepare_reactivity_pass.hlsl" #include "shaders/ffx_fsr3upscaler_prepare_reactivity_pass.hlsl"

4
Shaders/ffx_fsr3upscaler_rcas_pass.compute

@ -20,8 +20,8 @@
#pragma kernel CS #pragma kernel CS
#pragma multi_compile __ UNITY_FSR_TEXTURE2D_X_ARRAY
#pragma multi_compile __ UNITY_FFX_TEXTURE2D_X_ARRAY
#include "ffx_fsr_unity_common.cginc"
#include "ffx_unity_common.cginc"
#include "shaders/ffx_fsr3upscaler_rcas_pass.hlsl" #include "shaders/ffx_fsr3upscaler_rcas_pass.hlsl"

4
Shaders/ffx_fsr3upscaler_shading_change_pass.compute

@ -22,8 +22,8 @@
#pragma multi_compile_local __ FFX_HALF #pragma multi_compile_local __ FFX_HALF
#pragma multi_compile __ UNITY_FSR_TEXTURE2D_X_ARRAY
#pragma multi_compile __ UNITY_FFX_TEXTURE2D_X_ARRAY
#include "ffx_fsr_unity_common.cginc"
#include "ffx_unity_common.cginc"
#include "shaders/ffx_fsr3upscaler_shading_change_pass.hlsl" #include "shaders/ffx_fsr3upscaler_shading_change_pass.hlsl"

4
Shaders/ffx_fsr3upscaler_shading_change_pyramid_pass.compute

@ -22,9 +22,9 @@
#pragma multi_compile_local __ FFX_HALF #pragma multi_compile_local __ FFX_HALF
#pragma multi_compile __ UNITY_FSR_TEXTURE2D_X_ARRAY
#pragma multi_compile __ UNITY_FFX_TEXTURE2D_X_ARRAY
#include "ffx_fsr_unity_common.cginc"
#include "ffx_unity_common.cginc"
// Wave operations require shader model 6.0; this can only be enabled when using DXC on D3D12 // Wave operations require shader model 6.0; this can only be enabled when using DXC on D3D12
#define FFX_SPD_NO_WAVE_OPERATIONS #define FFX_SPD_NO_WAVE_OPERATIONS

4
Shaders/ffx_fsr3upscaler_tcr_autogen_pass.compute

@ -23,8 +23,8 @@
#pragma multi_compile_local __ FFX_HALF #pragma multi_compile_local __ FFX_HALF
#pragma multi_compile_local __ FFX_FSR3UPSCALER_OPTION_JITTERED_MOTION_VECTORS #pragma multi_compile_local __ FFX_FSR3UPSCALER_OPTION_JITTERED_MOTION_VECTORS
#pragma multi_compile __ UNITY_FSR_TEXTURE2D_X_ARRAY
#pragma multi_compile __ UNITY_FFX_TEXTURE2D_X_ARRAY
#include "ffx_fsr_unity_common.cginc"
#include "ffx_unity_common.cginc"
#include "shaders/ffx_fsr3upscaler_tcr_autogen_pass.hlsl" #include "shaders/ffx_fsr3upscaler_tcr_autogen_pass.hlsl"

30
Shaders/ffx_opticalflow_compute_luminance_pyramid_pass.compute

@ -0,0 +1,30 @@
// Copyright (c) 2024 Nico de Poel
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#pragma only_renderers d3d11 playstation xboxone xboxseries vulkan metal switch
#pragma kernel CS
#pragma use_dxc
#pragma require WaveBasic
#include "ffx_unity_common.cginc"
#include "shaders/ffx_opticalflow_compute_luminance_pyramid_pass.hlsl"

8
Shaders/ffx_opticalflow_compute_luminance_pyramid_pass.compute.meta

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: b4c831117e9d7db4f904bd81e05f9def
ComputeShaderImporter:
externalObjects: {}
preprocessorOverride: 0
userData:
assetBundleName:
assetBundleVariant:

30
Shaders/ffx_opticalflow_compute_optical_flow_advanced_pass_v5.compute

@ -0,0 +1,30 @@
// Copyright (c) 2024 Nico de Poel
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#pragma only_renderers d3d11 playstation xboxone xboxseries vulkan metal switch
#pragma kernel CS
#pragma use_dxc
#pragma require WaveBasic
#include "ffx_unity_common.cginc"
#include "shaders/ffx_opticalflow_compute_optical_flow_advanced_pass_v5.hlsl"

8
Shaders/ffx_opticalflow_compute_optical_flow_advanced_pass_v5.compute.meta

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: f480a6ee4cca98544a6f72d0a57caa36
ComputeShaderImporter:
externalObjects: {}
preprocessorOverride: 0
userData:
assetBundleName:
assetBundleVariant:

30
Shaders/ffx_opticalflow_compute_scd_divergence_pass.compute

@ -0,0 +1,30 @@
// Copyright (c) 2024 Nico de Poel
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#pragma only_renderers d3d11 playstation xboxone xboxseries vulkan metal switch
#pragma kernel CS
#pragma use_dxc
#pragma require WaveBasic
#include "ffx_unity_common.cginc"
#include "shaders/ffx_opticalflow_compute_scd_divergence_pass.hlsl"

8
Shaders/ffx_opticalflow_compute_scd_divergence_pass.compute.meta

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 06c260b21c4db2c4c88629b23a249e32
ComputeShaderImporter:
externalObjects: {}
preprocessorOverride: 0
userData:
assetBundleName:
assetBundleVariant:

30
Shaders/ffx_opticalflow_filter_optical_flow_pass_v5.compute

@ -0,0 +1,30 @@
// Copyright (c) 2024 Nico de Poel
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#pragma only_renderers d3d11 playstation xboxone xboxseries vulkan metal switch
#pragma kernel CS
#pragma use_dxc
#pragma require WaveBasic
#include "ffx_unity_common.cginc"
#include "shaders/ffx_opticalflow_filter_optical_flow_pass_v5.hlsl"

8
Shaders/ffx_opticalflow_filter_optical_flow_pass_v5.compute.meta

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 067af02200e7be2469c7f23a8711fe3c
ComputeShaderImporter:
externalObjects: {}
preprocessorOverride: 0
userData:
assetBundleName:
assetBundleVariant:

30
Shaders/ffx_opticalflow_generate_scd_histogram_pass.compute

@ -0,0 +1,30 @@
// Copyright (c) 2024 Nico de Poel
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#pragma only_renderers d3d11 playstation xboxone xboxseries vulkan metal switch
#pragma kernel CS
#pragma use_dxc
#pragma require WaveBasic
#include "ffx_unity_common.cginc"
#include "shaders/ffx_opticalflow_generate_scd_histogram_pass.hlsl"

8
Shaders/ffx_opticalflow_generate_scd_histogram_pass.compute.meta

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: f20d1907c158bfe4d85b2f18d497a09f
ComputeShaderImporter:
externalObjects: {}
preprocessorOverride: 0
userData:
assetBundleName:
assetBundleVariant:

30
Shaders/ffx_opticalflow_prepare_luma_pass.compute

@ -0,0 +1,30 @@
// Copyright (c) 2024 Nico de Poel
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#pragma only_renderers d3d11 playstation xboxone xboxseries vulkan metal switch
#pragma kernel CS
#pragma use_dxc
#pragma require WaveBasic
#include "ffx_unity_common.cginc"
#include "shaders/ffx_opticalflow_prepare_luma_pass.hlsl"

8
Shaders/ffx_opticalflow_prepare_luma_pass.compute.meta

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 3b70bda1db8d2f74396241d4811241ed
ComputeShaderImporter:
externalObjects: {}
preprocessorOverride: 0
userData:
assetBundleName:
assetBundleVariant:

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save