From 86c16e36940f3a06c181d8d04d3d56714799c3fc Mon Sep 17 00:00:00 2001 From: Nico de Poel Date: Mon, 27 Feb 2023 11:52:15 +0100 Subject: [PATCH] - Replaced all input/output parameters with RenderTargetIdentifiers, allowing more flexibility in how these resources are assigned - Cleaned up main MonoBehaviour ahead of a big refactor, and added camera event-based command buffers to set opaque-only and motion vector resources --- Assets/Scripts/Fsr2.cs | 18 ++-- Assets/Scripts/Fsr2Context.cs | 13 +-- Assets/Scripts/Fsr2Controller.cs | 17 ++-- Assets/Scripts/Fsr2Pipeline.cs | 157 +++++++++++++++++-------------- Assets/Scripts/SubsampleTest.cs | 143 ++++++++++++++-------------- 5 files changed, 184 insertions(+), 164 deletions(-) diff --git a/Assets/Scripts/Fsr2.cs b/Assets/Scripts/Fsr2.cs index 256dbee..0045681 100644 --- a/Assets/Scripts/Fsr2.cs +++ b/Assets/Scripts/Fsr2.cs @@ -138,12 +138,12 @@ namespace FidelityFX public class DispatchDescription { - public Texture ColorDepth; - public Texture MotionVectors; - public Texture Exposure; - public Texture Reactive; - public Texture TransparencyAndComposition; - public RenderTexture Output; + public RenderTargetIdentifier? Color; + public RenderTargetIdentifier? Depth; + public RenderTargetIdentifier? MotionVectors; + public RenderTargetIdentifier? Exposure; + public RenderTargetIdentifier? Reactive; + public RenderTargetIdentifier? Output; public Vector2 JitterOffset; public Vector2 MotionVectorScale; public Vector2Int RenderSize; @@ -160,9 +160,9 @@ namespace FidelityFX public class GenerateReactiveDescription { - public Texture ColorOpaqueOnly; - public Texture ColorPreUpscale; - public RenderTexture OutReactive; + public RenderTargetIdentifier? ColorOpaqueOnly; + public RenderTargetIdentifier? ColorPreUpscale; + public RenderTargetIdentifier? OutReactive; public Vector2Int RenderSize; public float Scale; public float CutoffThreshold; diff --git a/Assets/Scripts/Fsr2Context.cs b/Assets/Scripts/Fsr2Context.cs index afc27a7..209b6ac 100644 --- a/Assets/Scripts/Fsr2Context.cs +++ b/Assets/Scripts/Fsr2Context.cs @@ -198,7 +198,12 @@ namespace FidelityFX public void GenerateReactiveMask(Fsr2.GenerateReactiveDescription dispatchParams) { _commandBuffer.Clear(); + GenerateReactiveMask(dispatchParams, _commandBuffer); + Graphics.ExecuteCommandBuffer(_commandBuffer); + } + public void GenerateReactiveMask(Fsr2.GenerateReactiveDescription dispatchParams, CommandBuffer commandBuffer) + { const int threadGroupWorkRegionDim = 8; int dispatchSrcX = (dispatchParams.RenderSize.x + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim; int dispatchSrcY = (dispatchParams.RenderSize.y + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim; @@ -210,8 +215,6 @@ namespace FidelityFX _generateReactiveConstantsBuffer.SetData(_generateReactiveConstantsArray); ((Fsr2GenerateReactivePipeline)_generateReactivePipeline).ScheduleDispatch(_commandBuffer, dispatchParams, dispatchSrcX, dispatchSrcY); - - Graphics.ExecuteCommandBuffer(_commandBuffer); } private void SetupConstants(Fsr2.DispatchDescription dispatchParams, bool resetAccumulation) @@ -219,11 +222,9 @@ namespace FidelityFX ref Fsr2.Fsr2Constants constants = ref Constants; constants.jitterOffset = dispatchParams.JitterOffset; - constants.renderSize = new Vector2Int( - dispatchParams.RenderSize.x > 0 ? dispatchParams.RenderSize.x : dispatchParams.ColorDepth.width, - dispatchParams.RenderSize.y > 0 ? dispatchParams.RenderSize.y : dispatchParams.ColorDepth.height); + constants.renderSize = dispatchParams.RenderSize; constants.maxRenderSize = _contextDescription.MaxRenderSize; - constants.inputColorResourceDimensions = new Vector2Int(dispatchParams.ColorDepth.width, dispatchParams.ColorDepth.height); + constants.inputColorResourceDimensions = dispatchParams.RenderSize; // We have no way to query the actual width & height of the input resources, so trust that it matches the render size // Compute the horizontal FOV for the shader from the vertical one float aspectRatio = (float)dispatchParams.RenderSize.x / dispatchParams.RenderSize.y; diff --git a/Assets/Scripts/Fsr2Controller.cs b/Assets/Scripts/Fsr2Controller.cs index 682f2d2..50d4f6d 100644 --- a/Assets/Scripts/Fsr2Controller.cs +++ b/Assets/Scripts/Fsr2Controller.cs @@ -12,7 +12,7 @@ using UnityEngine.Rendering; /// This includes creation and destruction of the FSR2 context, as well as dispatching commands at the right time. /// This class also exposes various FSR2 parameters to the Unity inspector. /// -public class Fsr2Controller : MonoBehaviour +public class Fsr2Controller : MonoBehaviour // TODO: rename this to Fsr2Dispatcher and move most of the functionality to Fsr2Controller (now SubsampleTest) { [SerializeField] private bool performSharpenPass = true; @@ -40,6 +40,8 @@ public class Fsr2Controller : MonoBehaviour private Fsr2Context _context; private readonly Fsr2.DispatchDescription _dispatchDescription = new Fsr2.DispatchDescription(); + public Fsr2Context Context => _context; + private RenderTexture _upscaledOutput; private Material _copyMotionMat; @@ -102,15 +104,15 @@ public class Fsr2Controller : MonoBehaviour { var renderBuffer = gameCamera.targetTexture; - var commandBuffer = new CommandBuffer { name = "FSR2" }; + var commandBuffer = new CommandBuffer { name = "FSR2 Main" }; - int motionVectorsId = Shader.PropertyToID("r_input_motion_vectors"); + // int motionVectorsId = Shader.PropertyToID("r_input_motion_vectors"); int upscaledOutputId = Shader.PropertyToID("rw_upscaled_output"); // I hate having to allocate extra RTs just to duplicate already existing Unity render buffers, but AFAIK there is no way to directly address motion vectors from code // TODO: or can we? Look at RenderTargetIdentifier.MotionVectors with SetGlobalTexture!! (Possibly in gameCamera OnRenderImage) - commandBuffer.GetTemporaryRT(motionVectorsId, renderBuffer.width, renderBuffer.height, 0, default, RenderTextureFormat.RGHalf); - commandBuffer.Blit(renderBuffer, motionVectorsId, CopyMotionVectorsMaterial); + // commandBuffer.GetTemporaryRT(motionVectorsId, renderBuffer.width, renderBuffer.height, 0, default, RenderTextureFormat.RGHalf); + // commandBuffer.Blit(renderBuffer, motionVectorsId, CopyMotionVectorsMaterial); if (dest != null) { @@ -124,7 +126,8 @@ public class Fsr2Controller : MonoBehaviour commandBuffer.GetTemporaryRT(upscaledOutputId, DisplaySize.x, DisplaySize.y, 0, default, GraphicsFormat.R16G16B16A16_SFloat, 1, true); } - _dispatchDescription.ColorDepth = renderBuffer; + _dispatchDescription.Color = null; + _dispatchDescription.Depth = null; _dispatchDescription.MotionVectors = null; _dispatchDescription.Output = null; _dispatchDescription.Exposure = null; @@ -153,7 +156,7 @@ public class Fsr2Controller : MonoBehaviour commandBuffer.ReleaseTemporaryRT(upscaledOutputId); } - commandBuffer.ReleaseTemporaryRT(motionVectorsId); + // commandBuffer.ReleaseTemporaryRT(motionVectorsId); Graphics.ExecuteCommandBuffer(commandBuffer); commandBuffer.Release(); diff --git a/Assets/Scripts/Fsr2Pipeline.cs b/Assets/Scripts/Fsr2Pipeline.cs index e522bbe..c40343f 100644 --- a/Assets/Scripts/Fsr2Pipeline.cs +++ b/Assets/Scripts/Fsr2Pipeline.cs @@ -18,41 +18,41 @@ namespace FidelityFX protected int KernelIndex; // Shader resource views, i.e. read-only bindings - protected static readonly int SrvInputColor = Shader.PropertyToID("r_input_color_jittered"); - protected static readonly int SrvOpaqueOnly = Shader.PropertyToID("r_input_opaque_only"); - protected static readonly int SrvInputMotionVectors = Shader.PropertyToID("r_input_motion_vectors"); - protected static readonly int SrvInputDepth = Shader.PropertyToID("r_input_depth"); - protected static readonly int SrvInputExposure = Shader.PropertyToID("r_input_exposure"); - protected static readonly int SrvDilatedMotionVectors = Shader.PropertyToID("r_dilated_motion_vectors"); - protected static readonly int SrvReactiveMask = Shader.PropertyToID("r_reactive_mask"); - protected static readonly int SrvTransparencyAndCompositionMask = Shader.PropertyToID("r_transparency_and_composition_mask"); - protected static readonly int SrvPrevDilatedMotionVectors = Shader.PropertyToID("r_previous_dilated_motion_vectors"); - protected static readonly int SrvInternalUpscaled = Shader.PropertyToID("r_internal_upscaled_color"); - protected static readonly int SrvLockStatus = Shader.PropertyToID("r_lock_status"); - protected static readonly int SrvLanczosLut = Shader.PropertyToID("r_lanczos_lut"); - protected static readonly int SrvUpscaleMaximumBiasLut = Shader.PropertyToID("r_upsample_maximum_bias_lut"); - protected static readonly int SrvSceneLuminanceMips = Shader.PropertyToID("r_imgMips"); - protected static readonly int SrvAutoExposure = Shader.PropertyToID("r_auto_exposure"); - protected static readonly int SrvLumaHistory = Shader.PropertyToID("r_luma_history"); - protected static readonly int SrvRcasInput = Shader.PropertyToID("r_rcas_input"); + internal static readonly int SrvInputColor = Shader.PropertyToID("r_input_color_jittered"); + internal static readonly int SrvOpaqueOnly = Shader.PropertyToID("r_input_opaque_only"); + internal static readonly int SrvInputMotionVectors = Shader.PropertyToID("r_input_motion_vectors"); + internal static readonly int SrvInputDepth = Shader.PropertyToID("r_input_depth"); + internal static readonly int SrvInputExposure = Shader.PropertyToID("r_input_exposure"); + internal static readonly int SrvDilatedMotionVectors = Shader.PropertyToID("r_dilated_motion_vectors"); + internal static readonly int SrvReactiveMask = Shader.PropertyToID("r_reactive_mask"); + internal static readonly int SrvTransparencyAndCompositionMask = Shader.PropertyToID("r_transparency_and_composition_mask"); + internal static readonly int SrvPrevDilatedMotionVectors = Shader.PropertyToID("r_previous_dilated_motion_vectors"); + internal static readonly int SrvInternalUpscaled = Shader.PropertyToID("r_internal_upscaled_color"); + internal static readonly int SrvLockStatus = Shader.PropertyToID("r_lock_status"); + internal static readonly int SrvLanczosLut = Shader.PropertyToID("r_lanczos_lut"); + internal static readonly int SrvUpscaleMaximumBiasLut = Shader.PropertyToID("r_upsample_maximum_bias_lut"); + internal static readonly int SrvSceneLuminanceMips = Shader.PropertyToID("r_imgMips"); + internal static readonly int SrvAutoExposure = Shader.PropertyToID("r_auto_exposure"); + internal static readonly int SrvLumaHistory = Shader.PropertyToID("r_luma_history"); + internal static readonly int SrvRcasInput = Shader.PropertyToID("r_rcas_input"); // Unordered access views, i.e. random read/write bindings - protected static readonly int UavUpscaledOutput = Shader.PropertyToID("rw_upscaled_output"); - protected static readonly int UavExposureMipLumaChange = Shader.PropertyToID("rw_img_mip_shading_change"); - protected static readonly int UavExposureMip5 = Shader.PropertyToID("rw_img_mip_5"); - protected static readonly int UavAutoExposure = Shader.PropertyToID("rw_auto_exposure"); - protected static readonly int UavSpdAtomicCount = Shader.PropertyToID("rw_spd_global_atomic"); - protected static readonly int UavReconstructedPrevNearestDepth = Shader.PropertyToID("rw_reconstructed_previous_nearest_depth"); - protected static readonly int UavDilatedMotionVectors = Shader.PropertyToID("rw_dilated_motion_vectors"); - protected static readonly int UavDilatedDepth = Shader.PropertyToID("rw_dilatedDepth"); - protected static readonly int UavLockInputLuma = Shader.PropertyToID("rw_lock_input_luma"); - protected static readonly int UavDilatedReactiveMasks = Shader.PropertyToID("rw_dilated_reactive_masks"); - protected static readonly int UavPreparedInputColor = Shader.PropertyToID("rw_prepared_input_color"); - protected static readonly int UavNewLocks = Shader.PropertyToID("rw_new_locks"); - protected static readonly int UavInternalUpscaled = Shader.PropertyToID("rw_internal_upscaled_color"); - protected static readonly int UavLockStatus = Shader.PropertyToID("rw_lock_status"); - protected static readonly int UavLumaHistory = Shader.PropertyToID("rw_luma_history"); - protected static readonly int UavAutoReactive = Shader.PropertyToID("rw_output_autoreactive"); + internal static readonly int UavUpscaledOutput = Shader.PropertyToID("rw_upscaled_output"); + internal static readonly int UavExposureMipLumaChange = Shader.PropertyToID("rw_img_mip_shading_change"); + internal static readonly int UavExposureMip5 = Shader.PropertyToID("rw_img_mip_5"); + internal static readonly int UavAutoExposure = Shader.PropertyToID("rw_auto_exposure"); + internal static readonly int UavSpdAtomicCount = Shader.PropertyToID("rw_spd_global_atomic"); + internal static readonly int UavReconstructedPrevNearestDepth = Shader.PropertyToID("rw_reconstructed_previous_nearest_depth"); + internal static readonly int UavDilatedMotionVectors = Shader.PropertyToID("rw_dilated_motion_vectors"); + internal static readonly int UavDilatedDepth = Shader.PropertyToID("rw_dilatedDepth"); + internal static readonly int UavLockInputLuma = Shader.PropertyToID("rw_lock_input_luma"); + internal static readonly int UavDilatedReactiveMasks = Shader.PropertyToID("rw_dilated_reactive_masks"); + internal static readonly int UavPreparedInputColor = Shader.PropertyToID("rw_prepared_input_color"); + internal static readonly int UavNewLocks = Shader.PropertyToID("rw_new_locks"); + internal static readonly int UavInternalUpscaled = Shader.PropertyToID("rw_internal_upscaled_color"); + internal static readonly int UavLockStatus = Shader.PropertyToID("rw_lock_status"); + internal static readonly int UavLumaHistory = Shader.PropertyToID("rw_luma_history"); + internal static readonly int UavAutoReactive = Shader.PropertyToID("rw_output_autoreactive"); // Constant buffer bindings protected static readonly int CbFsr2 = Shader.PropertyToID("cbFSR2"); @@ -181,10 +181,8 @@ namespace FidelityFX public override void ScheduleDispatch(CommandBuffer commandBuffer, Fsr2.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY) { - if (dispatchParams.ColorDepth != null) - { - commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, SrvInputColor, dispatchParams.ColorDepth, 0, RenderTextureSubElement.Color); - } + if (dispatchParams.Color.HasValue) + commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, SrvInputColor, dispatchParams.Color.Value, 0, RenderTextureSubElement.Color); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, UavExposureMipLumaChange, Resources.SceneLuminance, ShadingChangeMipLevel); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, UavExposureMip5, Resources.SceneLuminance, 5); @@ -207,16 +205,17 @@ namespace FidelityFX public override void ScheduleDispatch(CommandBuffer commandBuffer, Fsr2.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY) { - if (dispatchParams.ColorDepth != null) - { - commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, SrvInputColor, dispatchParams.ColorDepth, 0, RenderTextureSubElement.Color); - commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, SrvInputDepth, dispatchParams.ColorDepth, 0, RenderTextureSubElement.Depth); - } - if (dispatchParams.MotionVectors != null) - { - commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, SrvInputMotionVectors, dispatchParams.MotionVectors); - } - commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, SrvInputExposure, dispatchParams.Exposure); + if (dispatchParams.Color.HasValue) + commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, SrvInputColor, dispatchParams.Color.Value, 0, RenderTextureSubElement.Color); + + if (dispatchParams.Depth.HasValue) + commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, SrvInputDepth, dispatchParams.Depth.Value, 0, RenderTextureSubElement.Depth); + + if (dispatchParams.MotionVectors.HasValue) + commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, SrvInputMotionVectors, dispatchParams.MotionVectors.Value); + + if (dispatchParams.Exposure.HasValue) + commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, SrvInputExposure, dispatchParams.Exposure.Value); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, UavDilatedMotionVectors, Resources.DilatedMotionVectors[frameIndex]); @@ -236,20 +235,24 @@ namespace FidelityFX public override void ScheduleDispatch(CommandBuffer commandBuffer, Fsr2.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY) { + if (dispatchParams.Color.HasValue) + commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, SrvInputColor, dispatchParams.Color.Value, 0, RenderTextureSubElement.Color); + + if (dispatchParams.Depth.HasValue) + commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, SrvInputDepth, dispatchParams.Depth.Value, 0, RenderTextureSubElement.Depth); + + if (dispatchParams.MotionVectors.HasValue) + commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, SrvInputMotionVectors, dispatchParams.MotionVectors.Value); + + if (dispatchParams.Exposure.HasValue) + commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, SrvInputExposure, dispatchParams.Exposure.Value); + + if (dispatchParams.Reactive.HasValue) + commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, SrvReactiveMask, dispatchParams.Reactive.Value); + commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, SrvDilatedMotionVectors, Resources.DilatedMotionVectors[frameIndex]); - commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, SrvReactiveMask, dispatchParams.Reactive); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, SrvTransparencyAndCompositionMask, Resources.DefaultReactive); // Default reactive mask, as we don't support TCR (yet) commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, SrvPrevDilatedMotionVectors, Resources.DilatedMotionVectors[frameIndex ^ 1]); - if (dispatchParams.MotionVectors != null) - { - commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, SrvInputMotionVectors, dispatchParams.MotionVectors); - } - if (dispatchParams.ColorDepth != null) - { - commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, SrvInputColor, dispatchParams.ColorDepth, 0, RenderTextureSubElement.Color); - commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, SrvInputDepth, dispatchParams.ColorDepth, 0, RenderTextureSubElement.Depth); - } - commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, SrvInputExposure, dispatchParams.Exposure); commandBuffer.SetComputeConstantBufferParam(ComputeShader, CbFsr2, Constants, 0, Marshal.SizeOf()); @@ -286,11 +289,13 @@ namespace FidelityFX public override void ScheduleDispatch(CommandBuffer commandBuffer, Fsr2.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY) { - commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, SrvInputExposure, dispatchParams.Exposure); if ((ContextDescription.Flags & Fsr2.InitializationFlags.EnableDisplayResolutionMotionVectors) == 0) commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, SrvDilatedMotionVectors, Resources.DilatedMotionVectors[frameIndex]); - else if (dispatchParams.MotionVectors != null) - commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, SrvInputMotionVectors, dispatchParams.MotionVectors); + else if (dispatchParams.MotionVectors.HasValue) + commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, SrvInputMotionVectors, dispatchParams.MotionVectors.Value); + + if (dispatchParams.Exposure.HasValue) + commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, SrvInputExposure, dispatchParams.Exposure.Value); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, SrvInternalUpscaled, Resources.InternalUpscaled[frameIndex ^ 1]); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, SrvLockStatus, Resources.LockStatus[frameIndex ^ 1]); @@ -302,11 +307,10 @@ namespace FidelityFX commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, UavInternalUpscaled, Resources.InternalUpscaled[frameIndex]); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, UavLockStatus, Resources.LockStatus[frameIndex]); - if (dispatchParams.Output != null) - { - commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, UavUpscaledOutput, dispatchParams.Output); - } commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, UavLumaHistory, Resources.LumaHistory[frameIndex]); + + if (dispatchParams.Output.HasValue) + commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, UavUpscaledOutput, dispatchParams.Output.Value); commandBuffer.SetComputeConstantBufferParam(ComputeShader, CbFsr2, Constants, 0, Marshal.SizeOf()); @@ -362,12 +366,14 @@ namespace FidelityFX public override void ScheduleDispatch(CommandBuffer commandBuffer, Fsr2.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY) { - commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, SrvInputExposure, dispatchParams.Exposure); + if (dispatchParams.Exposure.HasValue) + commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, SrvInputExposure, dispatchParams.Exposure.Value); + commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, SrvRcasInput, Resources.InternalUpscaled[frameIndex]); - if (dispatchParams.Output != null) - { - commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, UavUpscaledOutput, dispatchParams.Output); - } + + if (dispatchParams.Output.HasValue) + commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, UavUpscaledOutput, dispatchParams.Output.Value); + commandBuffer.SetComputeConstantBufferParam(ComputeShader, CbFsr2, Constants, 0, Marshal.SizeOf()); commandBuffer.SetComputeConstantBufferParam(ComputeShader, CbRcas, _rcasConstants, 0, Marshal.SizeOf()); @@ -393,9 +399,14 @@ namespace FidelityFX public void ScheduleDispatch(CommandBuffer commandBuffer, Fsr2.GenerateReactiveDescription dispatchParams, int dispatchX, int dispatchY) { - commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, SrvOpaqueOnly, dispatchParams.ColorOpaqueOnly); - commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, SrvInputColor, dispatchParams.ColorPreUpscale); - commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, UavAutoExposure, dispatchParams.OutReactive); + if (dispatchParams.ColorOpaqueOnly.HasValue) + commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, SrvOpaqueOnly, dispatchParams.ColorOpaqueOnly.Value, 0, RenderTextureSubElement.Color); + + if (dispatchParams.ColorPreUpscale.HasValue) + commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, SrvInputColor, dispatchParams.ColorPreUpscale.Value, 0, RenderTextureSubElement.Color); + + if (dispatchParams.OutReactive.HasValue) + commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, UavAutoExposure, dispatchParams.OutReactive.Value); commandBuffer.SetComputeConstantBufferParam(ComputeShader, CbGenReactive, _generateReactiveConstants, 0, Marshal.SizeOf()); diff --git a/Assets/Scripts/SubsampleTest.cs b/Assets/Scripts/SubsampleTest.cs index 888aceb..72c1a3d 100644 --- a/Assets/Scripts/SubsampleTest.cs +++ b/Assets/Scripts/SubsampleTest.cs @@ -1,71 +1,82 @@ -using System; using System.Collections; -using System.Collections.Generic; -using System.IO; using FidelityFX; using UnityEngine; +using UnityEngine.Rendering; [RequireComponent(typeof(Camera))] -public class SubsampleTest : MonoBehaviour +public class SubsampleTest : MonoBehaviour // TODO: rename this to Fsr2Controller { - private Camera gameCamera; + private Camera _renderCamera; - private GameObject outputCameraObject; - private Camera outputCamera; + private GameObject _displayCameraObject; + private Camera _displayCamera; [SerializeField] private Fsr2.QualityMode qualityMode; - [SerializeField] - private bool enableJitter; - private Fsr2Controller _fsr2Controller; private float _renderScale; private Fsr2.QualityMode _prevQualityMode; private Vector2Int _prevScreenSize; + + private CommandBuffer _opaqueOnlyCommandBuffer; + private CommandBuffer _reactiveCommandBuffer; private void OnEnable() { _renderScale = 1.0f / Fsr2.GetUpscaleRatioFromQualityMode(qualityMode); - gameCamera = GetComponent(); - if (outputCameraObject == null) + _renderCamera = GetComponent(); + if (_displayCameraObject == null) { - outputCameraObject = new GameObject("FSR2 Camera Object"); - outputCameraObject.transform.SetParent(transform); - outputCameraObject.transform.SetPositionAndRotation(Vector3.zero, Quaternion.identity); + _displayCameraObject = new GameObject("FSR2 Camera Object"); + _displayCameraObject.transform.SetParent(transform); + _displayCameraObject.transform.SetPositionAndRotation(Vector3.zero, Quaternion.identity); //outputCameraObject.transform.hideFlags = HideFlags.HideInHierarchy | HideFlags.HideInInspector; - outputCamera = outputCameraObject.AddComponent(); - outputCamera.backgroundColor = Color.clear; - outputCamera.clearFlags = CameraClearFlags.Nothing; - outputCamera.eventMask = 0; - outputCamera.cullingMask = 0; - outputCamera.useOcclusionCulling = false; - outputCamera.orthographic = true; - outputCamera.allowMSAA = false; - outputCamera.renderingPath = RenderingPath.Forward; - - _fsr2Controller = outputCameraObject.AddComponent(); + // Create a camera that does nothing except output the upscaled image + _displayCamera = _displayCameraObject.AddComponent(); + _displayCamera.backgroundColor = Color.clear; + _displayCamera.clearFlags = CameraClearFlags.Nothing; + _displayCamera.eventMask = 0; + _displayCamera.cullingMask = 0; + _displayCamera.useOcclusionCulling = false; + _displayCamera.orthographic = true; + _displayCamera.allowMSAA = false; + _displayCamera.renderingPath = RenderingPath.Forward; + + _fsr2Controller = _displayCameraObject.AddComponent(); } - _fsr2Controller.gameCamera = gameCamera; - _fsr2Controller.outputCamera = outputCamera; + _fsr2Controller.gameCamera = _renderCamera; + _fsr2Controller.outputCamera = _displayCamera; _fsr2Controller.renderScale = _renderScale; _fsr2Controller.enabled = true; Fsr2.GetRenderResolutionFromQualityMode(out var renderWidth, out var renderHeight, Screen.width, Screen.height, qualityMode); - gameCamera.targetTexture = new RenderTexture( + // TODO: check if the camera doesn't already have a target texture + _renderCamera.targetTexture = new RenderTexture( renderWidth, renderHeight, 24, // Can we copy depth value from original camera? RenderTextureFormat.ARGBHalf); // Can we copy format from original camera? Or renderer quality settings? - gameCamera.depthTextureMode |= DepthTextureMode.Depth | DepthTextureMode.MotionVectors; + _renderCamera.depthTextureMode |= DepthTextureMode.Depth | DepthTextureMode.MotionVectors; - gameCamera.targetTexture.name = "FSR2 Input Texture"; - gameCamera.targetTexture.Create(); + _renderCamera.targetTexture.name = "FSR2 Input Texture"; + _renderCamera.targetTexture.Create(); + + _opaqueOnlyCommandBuffer = new CommandBuffer { name = "FSR2 Opaque Input" }; + // TODO: may need to copy the opaque-only render buffer to a temp RT here, in which case we'll need an additional CommandBuffer to release the temp RT again + _opaqueOnlyCommandBuffer.SetGlobalTexture(Fsr2Pipeline.SrvOpaqueOnly, BuiltinRenderTextureType.CameraTarget, RenderTextureSubElement.Color); + _renderCamera.AddCommandBuffer(CameraEvent.BeforeImageEffectsOpaque, _opaqueOnlyCommandBuffer); + + _reactiveCommandBuffer = new CommandBuffer { name = "FSR2 Inputs" }; + _reactiveCommandBuffer.SetGlobalTexture(Fsr2Pipeline.SrvInputColor, BuiltinRenderTextureType.CameraTarget, RenderTextureSubElement.Color); + _reactiveCommandBuffer.SetGlobalTexture(Fsr2Pipeline.SrvInputDepth, BuiltinRenderTextureType.CameraTarget, RenderTextureSubElement.Depth); + _reactiveCommandBuffer.SetGlobalTexture(Fsr2Pipeline.SrvInputMotionVectors, BuiltinRenderTextureType.MotionVectors); + _renderCamera.AddCommandBuffer(CameraEvent.BeforeImageEffects, _reactiveCommandBuffer); // Adjust texture mipmap LOD bias by log2(renderResolution/displayResolution) - 1.0; // May need to leave this to the game dev, as we don't know which textures do and don't belong to the 3D scene @@ -81,28 +92,30 @@ public class SubsampleTest : MonoBehaviour float biasOffset = Fsr2.GetMipmapBiasOffset(_renderScale); Fsr2.GlobalCallbacks.ApplyMipmapBias(-biasOffset); - gameCamera.targetTexture.Release(); - gameCamera.targetTexture = null; + _renderCamera.RemoveCommandBuffer(CameraEvent.BeforeImageEffectsOpaque, _opaqueOnlyCommandBuffer); + _opaqueOnlyCommandBuffer.Release(); + _opaqueOnlyCommandBuffer = null; + + _renderCamera.RemoveCommandBuffer(CameraEvent.BeforeImageEffects, _reactiveCommandBuffer); + _reactiveCommandBuffer.Release(); + _reactiveCommandBuffer = null; + + _renderCamera.targetTexture.Release(); + _renderCamera.targetTexture = null; _fsr2Controller.enabled = false; - outputCamera.enabled = false; + _displayCamera.enabled = false; } private void Update() { - if (Input.GetKeyDown(KeyCode.F12)) - { - string path = Path.Combine(Directory.GetCurrentDirectory(), $"screenshot-{DateTime.Now:yyyyMMdd-HHmmss}.png"); - ScreenCapture.CaptureScreenshot(path); - Debug.Log($"Screenshot saved to: {path}"); - } - - outputCamera.enabled = gameCamera.enabled; + _displayCamera.enabled = _renderCamera.enabled; if (Screen.width != _prevScreenSize.x || Screen.height != _prevScreenSize.y || qualityMode != _prevQualityMode) { - enabled = false; - enabled = true; + // Force all resources to be destroyed and recreated with the new settings + OnDisable(); + OnEnable(); } } @@ -110,35 +123,27 @@ public class SubsampleTest : MonoBehaviour private void OnPreRender() { - gameCamera.aspect = (Screen.width * gameCamera.rect.width) / (Screen.height * gameCamera.rect.height); + _tempRect = _renderCamera.rect; + _renderCamera.aspect = (Screen.width * _tempRect.width) / (Screen.height * _tempRect.height); + _renderCamera.rect = new Rect(0, 0, 1, 1); + + // Perform custom jittering of the camera's projection matrix according to FSR2's instructions + int jitterPhaseCount = Fsr2.GetJitterPhaseCount(_renderCamera.targetTexture.width, Screen.width); + Fsr2.GetJitterOffset(out float jitterX, out float jitterY, Time.frameCount, jitterPhaseCount); - _tempRect = gameCamera.rect; - gameCamera.rect = new Rect(0, 0, 1, 1); + _fsr2Controller.SetJitterOffset(new Vector2(jitterX, jitterY)); - if (enableJitter) - { - // Perform custom jittering of the camera's projection matrix according to FSR2's instructions - // Unity already does jittering behind the scenes for certain post-effects, so can we perhaps integrate with that? - int jitterPhaseCount = Fsr2.GetJitterPhaseCount(gameCamera.targetTexture.width, Screen.width); - Fsr2.GetJitterOffset(out float jitterX, out float jitterY, Time.frameCount, jitterPhaseCount); - - _fsr2Controller.SetJitterOffset(new Vector2(jitterX, jitterY)); - - jitterX = 2.0f * jitterX / gameCamera.targetTexture.width; - jitterY = 2.0f * jitterY / gameCamera.targetTexture.height; - - var jitterTranslationMatrix = Matrix4x4.Translate(new Vector3(jitterX, jitterY, 0)); - gameCamera.projectionMatrix = jitterTranslationMatrix * gameCamera.nonJitteredProjectionMatrix; - } - else - { - _fsr2Controller.SetJitterOffset(Vector2.zero); - } + var targetTexture = _renderCamera.targetTexture; + jitterX = 2.0f * jitterX / targetTexture.width; + jitterY = 2.0f * jitterY / targetTexture.height; + + var jitterTranslationMatrix = Matrix4x4.Translate(new Vector3(jitterX, jitterY, 0)); + _renderCamera.projectionMatrix = jitterTranslationMatrix * _renderCamera.nonJitteredProjectionMatrix; } private void OnPostRender() { - gameCamera.rect = _tempRect; - gameCamera.ResetProjectionMatrix(); + _renderCamera.rect = _tempRect; + _renderCamera.ResetProjectionMatrix(); } }