From 13eb24289eb9d673e7dd4b55b5d4a2374c3d4249 Mon Sep 17 00:00:00 2001 From: Nico de Poel Date: Fri, 24 Feb 2023 13:28:26 +0100 Subject: [PATCH] Initial implementation of accumulation pass. It's doing... something but it's definitely not correct yet. Changed scene luminance into a persistent RT, since that makes it easier to control mipmaps and bind specific mip levels. --- .../FSR2/ffx_fsr2_accumulate_pass.compute | 4 ++ Assets/Scripts/Fsr2Context.cs | 4 -- Assets/Scripts/Fsr2Pipeline.cs | 49 ++++++++++++++----- Assets/Scripts/Fsr2Resources.cs | 48 +++++++++++++++++- 4 files changed, 88 insertions(+), 17 deletions(-) diff --git a/Assets/Resources/FSR2/ffx_fsr2_accumulate_pass.compute b/Assets/Resources/FSR2/ffx_fsr2_accumulate_pass.compute index 6265645..39b76ba 100644 --- a/Assets/Resources/FSR2/ffx_fsr2_accumulate_pass.compute +++ b/Assets/Resources/FSR2/ffx_fsr2_accumulate_pass.compute @@ -17,4 +17,8 @@ #define FFX_FSR2_OPTION_REPROJECT_USE_LANCZOS_TYPE 1 #endif +// Monkey-patch SRV names to match the UAV names from the shaders that output them +#define r_dilated_reactive_masks rw_dilated_reactive_masks +#define r_prepared_input_color rw_prepared_input_color + #include "shaders/ffx_fsr2_accumulate_pass.hlsl" diff --git a/Assets/Scripts/Fsr2Context.cs b/Assets/Scripts/Fsr2Context.cs index 1cf085b..789b800 100644 --- a/Assets/Scripts/Fsr2Context.cs +++ b/Assets/Scripts/Fsr2Context.cs @@ -177,10 +177,6 @@ namespace FidelityFX int threadGroupsY = (Screen.height + threadGroupWorkRegionDimRcas - 1) / threadGroupWorkRegionDimRcas; _rcasPipeline.ScheduleDispatch(_commandBuffer, dispatchParams, frameIndex, threadGroupsX, threadGroupsY); } - else - { - _commandBuffer.Blit(dispatchParams.ColorDepth, dispatchParams.Output); - } _resourceFrameIndex = (_resourceFrameIndex + 1) % MaxQueuedFrames; diff --git a/Assets/Scripts/Fsr2Pipeline.cs b/Assets/Scripts/Fsr2Pipeline.cs index 0ad293b..182b4b2 100644 --- a/Assets/Scripts/Fsr2Pipeline.cs +++ b/Assets/Scripts/Fsr2Pipeline.cs @@ -28,6 +28,13 @@ namespace FidelityFX 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"); // Unordered access views, i.e. random read/write bindings @@ -43,6 +50,9 @@ namespace FidelityFX 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"); // Constant buffer bindings protected static readonly int CbFsr2 = Shader.PropertyToID("cbFSR2"); @@ -77,11 +87,6 @@ namespace FidelityFX // Resource FSR2_SpdAtomicCounter: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R32_UINT, FFX_RESOURCE_FLAGS_ALIASABLE commandBuffer.GetTemporaryRT(UavSpdAtomicCount, 1, 1, 0, FilterMode.Point, GraphicsFormat.R32_UInt, 1, true); - // Resource FSR2_ExposureMips: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R16_FLOAT, FFX_RESOURCE_FLAGS_ALIASABLE, has mipmap chain - const int lumaMip = ShadingChangeMipLevel + 1; - commandBuffer.GetTemporaryRT(UavExposureMipLumaChange, maxRenderSize.x >> lumaMip, maxRenderSize.y >> lumaMip, 0, FilterMode.Point, GraphicsFormat.R16_SFloat, 1, true); - commandBuffer.GetTemporaryRT(UavExposureMip5, maxRenderSize.x >> 6, maxRenderSize.y >> 6, 0, FilterMode.Point, GraphicsFormat.R16_SFloat, 1, true); - // FSR2_ReconstructedPrevNearestDepth: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R32_UINT, FFX_RESOURCE_FLAGS_ALIASABLE commandBuffer.GetTemporaryRT(UavReconstructedPrevNearestDepth, maxRenderSize.x, maxRenderSize.y, 0, FilterMode.Point, GraphicsFormat.R32_UInt, 1, true); @@ -106,8 +111,6 @@ namespace FidelityFX { // Release all of the aliasable resources used this frame commandBuffer.ReleaseTemporaryRT(UavSpdAtomicCount); - commandBuffer.ReleaseTemporaryRT(UavExposureMipLumaChange); - commandBuffer.ReleaseTemporaryRT(UavExposureMip5); commandBuffer.ReleaseTemporaryRT(UavReconstructedPrevNearestDepth); commandBuffer.ReleaseTemporaryRT(UavDilatedDepth); commandBuffer.ReleaseTemporaryRT(UavLockInputLuma); @@ -175,7 +178,11 @@ namespace FidelityFX // - Shouldn't we use a ComputeBuffer for resources that are one-dimensional and clearly not image data? e.g. SPD atomic counter & Lanczos LUT data 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); + commandBuffer.SetComputeConstantBufferParam(ComputeShader, CbFsr2, Constants, 0, Marshal.SizeOf()); commandBuffer.SetComputeConstantBufferParam(ComputeShader, CbSpd, _spdConstants, 0, Marshal.SizeOf()); @@ -218,7 +225,7 @@ namespace FidelityFX { commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, SrvDilatedMotionVectors, Resources.DilatedMotionVectors[frameIndex]); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, SrvReactiveMask, dispatchParams.Reactive); - commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, SrvTransparencyAndCompositionMask, dispatchParams.Reactive); // Default reactive mask, as we don't support TCR (yet) + 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); @@ -257,7 +264,28 @@ namespace FidelityFX public override void ScheduleDispatch(CommandBuffer commandBuffer, Fsr2.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY) { - //throw new NotImplementedException(); + commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, SrvInputExposure, dispatchParams.Exposure); + if ((ContextDescription.Flags & Fsr2.InitializationFlags.EnableDisplayResolutionMotionVectors) == 0) + commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, SrvDilatedMotionVectors, Resources.DilatedMotionVectors[frameIndex]); + else + commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, SrvInputMotionVectors, dispatchParams.MotionVectors); + + commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, SrvInternalUpscaled, Resources.InternalUpscaled[frameIndex ^ 1]); + commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, SrvLockStatus, Resources.LockStatus[frameIndex ^ 1]); + commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, SrvLanczosLut, Resources.LanczosLut); + commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, SrvUpscaleMaximumBiasLut, Resources.MaximumBiasLut); + commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, SrvSceneLuminanceMips, Resources.SceneLuminance); + commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, SrvAutoExposure, Resources.AutoExposure); + commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, SrvLumaHistory, Resources.LumaHistory[frameIndex ^ 1]); + + commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, UavInternalUpscaled, Resources.InternalUpscaled[frameIndex]); + commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, UavLockStatus, Resources.LockStatus[frameIndex]); + commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, UavUpscaledOutput, dispatchParams.Output); + commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, UavLumaHistory, Resources.LumaHistory[frameIndex]); + + commandBuffer.SetComputeConstantBufferParam(ComputeShader, CbFsr2, Constants, 0, Marshal.SizeOf()); + + commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, 1); } } @@ -309,9 +337,8 @@ namespace FidelityFX public override void ScheduleDispatch(CommandBuffer commandBuffer, Fsr2.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY) { - // Run the RCAS sharpening filter on the upscaled image commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, SrvInputExposure, dispatchParams.Exposure); - commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, SrvRcasInput, dispatchParams.ColorDepth, 0, RenderTextureSubElement.Color); // TODO: should be output from accumulate pass + commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, SrvRcasInput, Resources.InternalUpscaled[frameIndex]); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, UavUpscaledOutput, dispatchParams.Output); commandBuffer.SetComputeConstantBufferParam(ComputeShader, CbFsr2, Constants, 0, Marshal.SizeOf()); commandBuffer.SetComputeConstantBufferParam(ComputeShader, CbRcas, _rcasConstants, 0, Marshal.SizeOf()); diff --git a/Assets/Scripts/Fsr2Resources.cs b/Assets/Scripts/Fsr2Resources.cs index f5bf01c..59037c6 100644 --- a/Assets/Scripts/Fsr2Resources.cs +++ b/Assets/Scripts/Fsr2Resources.cs @@ -1,4 +1,5 @@ -using UnityEngine; +using System; +using UnityEngine; using UnityEngine.Experimental.Rendering; namespace FidelityFX @@ -8,7 +9,9 @@ namespace FidelityFX public Texture2D DefaultExposure; public Texture2D DefaultReactive; public Texture2D LanczosLut; + public Texture2D MaximumBiasLut; public RenderTexture AutoExposure; + public RenderTexture SceneLuminance; public readonly RenderTexture[] DilatedMotionVectors = new RenderTexture[2]; public readonly RenderTexture[] LockStatus = new RenderTexture[2]; public readonly RenderTexture[] InternalUpscaled = new RenderTexture[2]; @@ -25,6 +28,12 @@ namespace FidelityFX float y = Fsr2.Lanczos2(x); lanczos2Weights[currentLanczosWidthIndex] = y; } + + float[] maximumBias = new float[MaximumBiasTextureWidth * MaximumBiasTextureHeight]; + for (int i = 0; i < maximumBias.Length; ++i) + { + maximumBias[i] = MaximumBias[i] / 2.0f; + } // TODO: create resources, i.e. render textures used for intermediate results. // Note that "aliasable" resources should be equivalent to GetTemporary render textures @@ -38,6 +47,11 @@ namespace FidelityFX LanczosLut.SetPixelData(lanczos2Weights, 0); LanczosLut.Apply(); + // Resource FSR2_MaximumUpsampleBias: FFX_RESOURCE_USAGE_READ_ONLY, FFX_SURFACE_FORMAT_R16_SNORM, FFX_RESOURCE_FLAGS_NONE + MaximumBiasLut = new Texture2D(MaximumBiasTextureWidth, MaximumBiasTextureHeight, GraphicsFormat.R16_SFloat, TextureCreationFlags.None) { name = "FSR2_MaximumUpsampleBias" }; + MaximumBiasLut.SetPixelData(maximumBias, 0); + MaximumBiasLut.Apply(); + // 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.black); @@ -52,6 +66,13 @@ namespace FidelityFX AutoExposure = new RenderTexture(1, 1, 1, GraphicsFormat.R32G32_SFloat) { name = "FSR2_AutoExposure", enableRandomWrite = true }; AutoExposure.Create(); + // 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. + 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(); + // 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); @@ -80,6 +101,7 @@ namespace FidelityFX DestroyResource(InternalUpscaled); DestroyResource(LockStatus); DestroyResource(DilatedMotionVectors); + DestroyResource(ref SceneLuminance); DestroyResource(ref AutoExposure); DestroyResource(ref DefaultReactive); DestroyResource(ref DefaultExposure); @@ -90,7 +112,7 @@ namespace FidelityFX if (resource == null) return; - Object.Destroy(resource); + UnityEngine.Object.Destroy(resource); resource = null; } @@ -108,5 +130,27 @@ namespace FidelityFX for (int i = 0; i < resource.Length; ++i) DestroyResource(ref resource[i]); } + + private const int MaximumBiasTextureWidth = 16; + private const int MaximumBiasTextureHeight = 16; + private static readonly float[] MaximumBias = + { + 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 1.876f, 1.809f, 1.772f, 1.753f, 1.748f, + 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 1.869f, 1.801f, 1.764f, 1.745f, 1.739f, + 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 1.976f, 1.841f, 1.774f, 1.737f, 1.716f, 1.71f, + 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 1.914f, 1.784f, 1.716f, 1.673f, 1.649f, 1.641f, + 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 1.793f, 1.676f, 1.604f, 1.562f, 1.54f, 1.533f, + 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 1.802f, 1.619f, 1.536f, 1.492f, 1.467f, 1.454f, 1.449f, + 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 1.812f, 1.575f, 1.496f, 1.456f, 1.432f, 1.416f, 1.408f, 1.405f, + 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 1.555f, 1.479f, 1.438f, 1.413f, 1.398f, 1.387f, 1.381f, 1.379f, + 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 1.812f, 1.555f, 1.474f, 1.43f, 1.404f, 1.387f, 1.376f, 1.368f, 1.363f, 1.362f, + 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 1.802f, 1.575f, 1.479f, 1.43f, 1.401f, 1.382f, 1.369f, 1.36f, 1.354f, 1.351f, 1.35f, + 2.0f, 2.0f, 1.976f, 1.914f, 1.793f, 1.619f, 1.496f, 1.438f, 1.404f, 1.382f, 1.367f, 1.357f, 1.349f, 1.344f, 1.341f, 1.34f, + 1.876f, 1.869f, 1.841f, 1.784f, 1.676f, 1.536f, 1.456f, 1.413f, 1.387f, 1.369f, 1.357f, 1.347f, 1.341f, 1.336f, 1.333f, 1.332f, + 1.809f, 1.801f, 1.774f, 1.716f, 1.604f, 1.492f, 1.432f, 1.398f, 1.376f, 1.36f, 1.349f, 1.341f, 1.335f, 1.33f, 1.328f, 1.327f, + 1.772f, 1.764f, 1.737f, 1.673f, 1.562f, 1.467f, 1.416f, 1.387f, 1.368f, 1.354f, 1.344f, 1.336f, 1.33f, 1.326f, 1.323f, 1.323f, + 1.753f, 1.745f, 1.716f, 1.649f, 1.54f, 1.454f, 1.408f, 1.381f, 1.363f, 1.351f, 1.341f, 1.333f, 1.328f, 1.323f, 1.321f, 1.32f, + 1.748f, 1.739f, 1.71f, 1.641f, 1.533f, 1.449f, 1.405f, 1.379f, 1.362f, 1.35f, 1.34f, 1.332f, 1.327f, 1.323f, 1.32f, 1.319f, + }; } }