From 776700e8373f3f6278cbcf126bacf0cf30aa7fd6 Mon Sep 17 00:00:00 2001 From: Nico de Poel Date: Sun, 26 Feb 2023 22:55:32 +0100 Subject: [PATCH] Allow input textures to be set outside of FSR2 context dispatch, opening up new avenues for optimizations. Started with setting motion vectors and output RT directly from the Unity command buffer, blitting to the destination RT only when necessary. --- Assets/Scripts/Fsr2Controller.cs | 45 +++++++++++++++++++++++++------- Assets/Scripts/Fsr2Pipeline.cs | 43 ++++++++++++++++++++++-------- 2 files changed, 67 insertions(+), 21 deletions(-) diff --git a/Assets/Scripts/Fsr2Controller.cs b/Assets/Scripts/Fsr2Controller.cs index e80188f..682f2d2 100644 --- a/Assets/Scripts/Fsr2Controller.cs +++ b/Assets/Scripts/Fsr2Controller.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Linq; using FidelityFX; using UnityEngine; +using UnityEngine.Experimental.Rendering; using UnityEngine.Rendering; /// @@ -100,17 +101,32 @@ public class Fsr2Controller : MonoBehaviour private void OnRenderImage(RenderTexture src, RenderTexture dest) { var renderBuffer = gameCamera.targetTexture; + + var commandBuffer = new CommandBuffer { name = "FSR2" }; + + 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 - var motionVectors = RenderTexture.GetTemporary(renderBuffer.width, renderBuffer.height, 0, RenderTextureFormat.RGHalf); - Graphics.Blit(renderBuffer, motionVectors, CopyMotionVectorsMaterial); + // 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); - // TODO: if `dest` is null, we are rendering straight to the backbuffer and should use a temporary RT as the output buffer for FSR2 - // TODO: if `dest` it NOT null, we have more image effects lined up after this one, and we should be able to have FSR2 output straight to `dest` without an intermediary temp RT + if (dest != null) + { + // We have more image effects lined up after this, so FSR2 can output straight to the intermediate render texture + // TODO: we should probably use a shader to include depth & motion vectors into the output + commandBuffer.SetGlobalTexture(upscaledOutputId, dest); + } + else + { + // We are rendering to the backbuffer, so we need a temporary render texture for FSR2 to output to + commandBuffer.GetTemporaryRT(upscaledOutputId, DisplaySize.x, DisplaySize.y, 0, default, GraphicsFormat.R16G16B16A16_SFloat, 1, true); + } _dispatchDescription.ColorDepth = renderBuffer; - _dispatchDescription.MotionVectors = motionVectors; - _dispatchDescription.Output = _upscaledOutput; + _dispatchDescription.MotionVectors = null; + _dispatchDescription.Output = null; _dispatchDescription.Exposure = null; _dispatchDescription.Reactive = null; _dispatchDescription.PreExposure = 0; @@ -127,13 +143,22 @@ public class Fsr2Controller : MonoBehaviour _dispatchDescription.Reset = reset; reset = false; - _context.Dispatch(_dispatchDescription); + _context.Dispatch(_dispatchDescription, commandBuffer); // Output upscaled image to screen - // TODO: we should probably use a shader to include depth & motion vectors into the output // TODO: if `dest` is null, we likely don't care about the depth & motion vectors anymore - Graphics.Blit(_upscaledOutput, dest); + if (dest == null) + { + commandBuffer.Blit(upscaledOutputId, dest); + commandBuffer.ReleaseTemporaryRT(upscaledOutputId); + } + + commandBuffer.ReleaseTemporaryRT(motionVectorsId); + + Graphics.ExecuteCommandBuffer(commandBuffer); + commandBuffer.Release(); - RenderTexture.ReleaseTemporary(motionVectors); + // Shut up the Unity warning about not writing to the destination texture + Graphics.SetRenderTarget(dest); } } diff --git a/Assets/Scripts/Fsr2Pipeline.cs b/Assets/Scripts/Fsr2Pipeline.cs index f04bd10..e522bbe 100644 --- a/Assets/Scripts/Fsr2Pipeline.cs +++ b/Assets/Scripts/Fsr2Pipeline.cs @@ -181,8 +181,11 @@ namespace FidelityFX public override void ScheduleDispatch(CommandBuffer commandBuffer, Fsr2.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY) { - commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, SrvInputColor, dispatchParams.ColorDepth, 0, RenderTextureSubElement.Color); - + if (dispatchParams.ColorDepth != null) + { + commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, SrvInputColor, dispatchParams.ColorDepth, 0, RenderTextureSubElement.Color); + } + commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, UavExposureMipLumaChange, Resources.SceneLuminance, ShadingChangeMipLevel); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, UavExposureMip5, Resources.SceneLuminance, 5); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, UavAutoExposure, Resources.AutoExposure); @@ -204,9 +207,15 @@ namespace FidelityFX public override void ScheduleDispatch(CommandBuffer commandBuffer, Fsr2.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY) { - commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, SrvInputColor, dispatchParams.ColorDepth, 0, RenderTextureSubElement.Color); - commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, SrvInputDepth, dispatchParams.ColorDepth, 0, RenderTextureSubElement.Depth); - 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); + } + if (dispatchParams.MotionVectors != null) + { + commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, SrvInputMotionVectors, dispatchParams.MotionVectors); + } commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, SrvInputExposure, dispatchParams.Exposure); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, UavDilatedMotionVectors, Resources.DilatedMotionVectors[frameIndex]); @@ -231,9 +240,15 @@ namespace FidelityFX 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]); - commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, SrvInputMotionVectors, dispatchParams.MotionVectors); - 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); + } + 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()); @@ -274,7 +289,7 @@ namespace FidelityFX commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, SrvInputExposure, dispatchParams.Exposure); if ((ContextDescription.Flags & Fsr2.InitializationFlags.EnableDisplayResolutionMotionVectors) == 0) commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, SrvDilatedMotionVectors, Resources.DilatedMotionVectors[frameIndex]); - else + else if (dispatchParams.MotionVectors != null) commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, SrvInputMotionVectors, dispatchParams.MotionVectors); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, SrvInternalUpscaled, Resources.InternalUpscaled[frameIndex ^ 1]); @@ -287,7 +302,10 @@ namespace FidelityFX commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, UavInternalUpscaled, Resources.InternalUpscaled[frameIndex]); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, UavLockStatus, Resources.LockStatus[frameIndex]); - commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, UavUpscaledOutput, dispatchParams.Output); + if (dispatchParams.Output != null) + { + commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, UavUpscaledOutput, dispatchParams.Output); + } commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, UavLumaHistory, Resources.LumaHistory[frameIndex]); commandBuffer.SetComputeConstantBufferParam(ComputeShader, CbFsr2, Constants, 0, Marshal.SizeOf()); @@ -346,7 +364,10 @@ namespace FidelityFX { commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, SrvInputExposure, dispatchParams.Exposure); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, SrvRcasInput, Resources.InternalUpscaled[frameIndex]); - commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, UavUpscaledOutput, dispatchParams.Output); + if (dispatchParams.Output != null) + { + commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, UavUpscaledOutput, dispatchParams.Output); + } commandBuffer.SetComputeConstantBufferParam(ComputeShader, CbFsr2, Constants, 0, Marshal.SizeOf()); commandBuffer.SetComputeConstantBufferParam(ComputeShader, CbRcas, _rcasConstants, 0, Marshal.SizeOf());