FSR2 tests in Unity based on built-in render pipeline
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

378 lines
23 KiB

using System;
using System.Runtime.InteropServices;
using UnityEngine;
using UnityEngine.Experimental.Rendering;
using UnityEngine.Rendering;
namespace FidelityFX
{
internal abstract class Fsr2Pipeline: IDisposable
{
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 ComputeBuffer Constants;
protected ComputeShader ComputeShader;
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");
// 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");
// Constant buffer bindings
protected static readonly int CbFsr2 = Shader.PropertyToID("cbFSR2");
protected static readonly int CbSpd = Shader.PropertyToID("cbSPD");
protected static readonly int CbRcas = Shader.PropertyToID("cbRCAS");
protected static readonly int CbGenReactive = Shader.PropertyToID("cbGenerateReactive");
protected virtual bool AllowFP16 => true;
protected Fsr2Pipeline(Fsr2.ContextDescription contextDescription, Fsr2Resources resources, ComputeBuffer constants)
{
ContextDescription = contextDescription;
Resources = resources;
Constants = constants;
}
public virtual void Dispose()
{
UnloadComputeShader();
}
public abstract void ScheduleDispatch(CommandBuffer commandBuffer, Fsr2.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY);
public static void RegisterResources(CommandBuffer commandBuffer, Fsr2.ContextDescription contextDescription, Fsr2.DispatchDescription dispatchParams)
{
Vector2Int displaySize = contextDescription.DisplaySize;
Vector2Int maxRenderSize = contextDescription.MaxRenderSize;
// 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
// TODO: we could potentially gather *all* resource binding here, by using CommandBuffer.SetGlobalTexture for everything
// Resource FSR2_SpdAtomicCounter: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R32_UINT, FFX_RESOURCE_FLAGS_ALIASABLE
commandBuffer.GetTemporaryRT(UavSpdAtomicCount, 1, 1, 0, default(FilterMode), GraphicsFormat.R32_UInt, 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, default(FilterMode), GraphicsFormat.R32_UInt, 1, true);
// FSR2_DilatedDepth: FFX_RESOURCE_USAGE_RENDERTARGET | FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R32_FLOAT, FFX_RESOURCE_FLAGS_ALIASABLE
commandBuffer.GetTemporaryRT(UavDilatedDepth, maxRenderSize.x, maxRenderSize.y, 0, default(FilterMode), GraphicsFormat.R32_SFloat, 1, true);
// FSR2_LockInputLuma: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R16_FLOAT, FFX_RESOURCE_FLAGS_ALIASABLE
commandBuffer.GetTemporaryRT(UavLockInputLuma, maxRenderSize.x, maxRenderSize.y, 0, default(FilterMode), GraphicsFormat.R16_SFloat, 1, true);
// FSR2_DilatedReactiveMasks: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R8G8_UNORM, FFX_RESOURCE_FLAGS_ALIASABLE
commandBuffer.GetTemporaryRT(UavDilatedReactiveMasks, maxRenderSize.x, maxRenderSize.y, 0, default(FilterMode), GraphicsFormat.R8G8_UNorm, 1, true);
// FSR2_PreparedInputColor: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R16G16B16A16_FLOAT, FFX_RESOURCE_FLAGS_ALIASABLE
commandBuffer.GetTemporaryRT(UavPreparedInputColor, maxRenderSize.x, maxRenderSize.y, 0, default(FilterMode), GraphicsFormat.R16G16B16A16_SFloat, 1, true);
// FSR2_NewLocks: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R8_UNORM, FFX_RESOURCE_FLAGS_ALIASABLE
commandBuffer.GetTemporaryRT(UavNewLocks, displaySize.x, displaySize.y, 0, default(FilterMode), GraphicsFormat.R8_UNorm, 1, true);
}
public static void UnregisterResources(CommandBuffer commandBuffer)
{
// Release all of the aliasable resources used this frame
commandBuffer.ReleaseTemporaryRT(UavSpdAtomicCount);
commandBuffer.ReleaseTemporaryRT(UavReconstructedPrevNearestDepth);
commandBuffer.ReleaseTemporaryRT(UavDilatedDepth);
commandBuffer.ReleaseTemporaryRT(UavLockInputLuma);
commandBuffer.ReleaseTemporaryRT(UavDilatedReactiveMasks);
commandBuffer.ReleaseTemporaryRT(UavPreparedInputColor);
commandBuffer.ReleaseTemporaryRT(UavNewLocks);
}
protected void LoadComputeShader(string name)
{
LoadComputeShader(name, ContextDescription.Flags, ref ComputeShader, out KernelIndex);
}
private void LoadComputeShader(string name, Fsr2.InitializationFlags flags, ref ComputeShader shaderRef, out int kernelIndex)
{
if (shaderRef == null)
shaderRef = ContextDescription.Callbacks.LoadComputeShader(name);
kernelIndex = shaderRef.FindKernel("CS");
bool useLut = (SystemInfo.computeSubGroupSize == 64);
// Allow 16-bit floating point as a configuration option, except on passes that explicitly disable it
bool supportedFP16 = ((flags & Fsr2.InitializationFlags.EnableFP16Usage) != 0 && AllowFP16);
// This matches the permutation rules from the CreatePipeline* functions
if ((flags & Fsr2.InitializationFlags.EnableHighDynamicRange) != 0) shaderRef.EnableKeyword("FFX_FSR2_OPTION_HDR_COLOR_INPUT");
if ((flags & Fsr2.InitializationFlags.EnableDisplayResolutionMotionVectors) == 0) shaderRef.EnableKeyword("FFX_FSR2_OPTION_LOW_RESOLUTION_MOTION_VECTORS");
if ((flags & Fsr2.InitializationFlags.EnableMotionVectorsJitterCancellation) != 0) shaderRef.EnableKeyword("FFX_FSR2_OPTION_JITTERED_MOTION_VECTORS");
if ((flags & Fsr2.InitializationFlags.EnableDepthInverted) != 0) shaderRef.EnableKeyword("FFX_FSR2_OPTION_INVERTED_DEPTH");
if (useLut) shaderRef.EnableKeyword("FFX_FSR2_OPTION_REPROJECT_USE_LANCZOS_TYPE");
if (supportedFP16) shaderRef.EnableKeyword("FFX_HALF");
}
private void UnloadComputeShader()
{
UnloadComputeShader(ref ComputeShader);
}
private void UnloadComputeShader(ref ComputeShader shaderRef)
{
if (shaderRef == null)
return;
ContextDescription.Callbacks.UnloadComputeShader(shaderRef);
shaderRef = null;
}
}
internal class Fsr2ComputeLuminancePyramidPipeline : Fsr2Pipeline
{
private readonly ComputeBuffer _spdConstants;
public Fsr2ComputeLuminancePyramidPipeline(Fsr2.ContextDescription contextDescription, Fsr2Resources resources, ComputeBuffer constants, ComputeBuffer spdConstants)
: base(contextDescription, resources, constants)
{
_spdConstants = spdConstants;
LoadComputeShader("FSR2/ffx_fsr2_compute_luminance_pyramid_pass");
}
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, 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<Fsr2.Fsr2Constants>());
commandBuffer.SetComputeConstantBufferParam(ComputeShader, CbSpd, _spdConstants, 0, Marshal.SizeOf<Fsr2.SpdConstants>());
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, 1);
}
}
internal class Fsr2ReconstructPreviousDepthPipeline : Fsr2Pipeline
{
public Fsr2ReconstructPreviousDepthPipeline(Fsr2.ContextDescription contextDescription, Fsr2Resources resources, ComputeBuffer constants)
: base(contextDescription, resources, constants)
{
LoadComputeShader("FSR2/ffx_fsr2_reconstruct_previous_depth_pass");
}
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);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, SrvInputExposure, dispatchParams.Exposure);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, UavDilatedMotionVectors, Resources.DilatedMotionVectors[frameIndex]);
commandBuffer.SetComputeConstantBufferParam(ComputeShader, CbFsr2, Constants, 0, Marshal.SizeOf<Fsr2.Fsr2Constants>());
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, 1);
}
}
internal class Fsr2DepthClipPipeline : Fsr2Pipeline
{
public Fsr2DepthClipPipeline(Fsr2.ContextDescription contextDescription, Fsr2Resources resources, ComputeBuffer constants)
: base(contextDescription, resources, constants)
{
LoadComputeShader("FSR2/ffx_fsr2_depth_clip_pass");
}
public override void ScheduleDispatch(CommandBuffer commandBuffer, Fsr2.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY)
{
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]);
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);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, SrvInputExposure, dispatchParams.Exposure);
commandBuffer.SetComputeConstantBufferParam(ComputeShader, CbFsr2, Constants, 0, Marshal.SizeOf<Fsr2.Fsr2Constants>());
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, 1);
}
}
internal class Fsr2LockPipeline : Fsr2Pipeline
{
public Fsr2LockPipeline(Fsr2.ContextDescription contextDescription, Fsr2Resources resources, ComputeBuffer constants)
: base(contextDescription, resources, constants)
{
LoadComputeShader("FSR2/ffx_fsr2_lock_pass");
}
public override void ScheduleDispatch(CommandBuffer commandBuffer, Fsr2.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY)
{
commandBuffer.SetComputeConstantBufferParam(ComputeShader, CbFsr2, Constants, 0, Marshal.SizeOf<Fsr2.Fsr2Constants>());
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, 1);
}
}
internal class Fsr2AccumulatePipeline : Fsr2Pipeline
{
// Workaround: Disable FP16 path for the accumulate pass on NVIDIA due to reduced occupancy and high VRAM throughput.
protected override bool AllowFP16 => SystemInfo.graphicsDeviceVendorID != 0x10DE;
public Fsr2AccumulatePipeline(Fsr2.ContextDescription contextDescription, Fsr2Resources resources, ComputeBuffer constants)
: base(contextDescription, resources, constants)
{
LoadComputeShader("FSR2/ffx_fsr2_accumulate_pass");
}
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
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<Fsr2.Fsr2Constants>());
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, 1);
}
}
internal class Fsr2AccumulateSharpenPipeline : Fsr2AccumulatePipeline
{
private readonly ComputeShader _shaderCopy;
public Fsr2AccumulateSharpenPipeline(Fsr2.ContextDescription contextDescription, Fsr2Resources resources, ComputeBuffer constants)
: base(contextDescription, resources, constants)
{
// Simply loading the accumulate_pass compute shader will give us the same instance as the non-sharpen pipeline
// So we have to clone the shader instance and set the extra keyword on the new copy
_shaderCopy = UnityEngine.Object.Instantiate(ComputeShader);
foreach (var keyword in ComputeShader.enabledKeywords)
{
_shaderCopy.EnableKeyword(keyword.name);
}
_shaderCopy.EnableKeyword("FFX_FSR2_OPTION_APPLY_SHARPENING");
}
public override void ScheduleDispatch(CommandBuffer commandBuffer, Fsr2.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY)
{
// Temporarily swap around the shaders so that the dispatch will bind and execute the correct one
ComputeShader tmp = ComputeShader;
ComputeShader = _shaderCopy;
base.ScheduleDispatch(commandBuffer, dispatchParams, frameIndex, dispatchX, dispatchY);
ComputeShader = tmp;
}
public override void Dispose()
{
// Since we instantiated this copy, we have to destroy it instead of unloading the shader resource
UnityEngine.Object.Destroy(_shaderCopy);
base.Dispose();
}
}
internal class Fsr2RcasPipeline : Fsr2Pipeline
{
private readonly ComputeBuffer _rcasConstants;
public Fsr2RcasPipeline(Fsr2.ContextDescription contextDescription, Fsr2Resources resources, ComputeBuffer constants, ComputeBuffer rcasConstants)
: base(contextDescription, resources, constants)
{
_rcasConstants = rcasConstants;
LoadComputeShader("FSR2/ffx_fsr2_rcas_pass");
}
public override void ScheduleDispatch(CommandBuffer commandBuffer, Fsr2.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY)
{
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, SrvInputExposure, dispatchParams.Exposure);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, SrvRcasInput, Resources.InternalUpscaled[frameIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, UavUpscaledOutput, dispatchParams.Output);
commandBuffer.SetComputeConstantBufferParam(ComputeShader, CbFsr2, Constants, 0, Marshal.SizeOf<Fsr2.Fsr2Constants>());
commandBuffer.SetComputeConstantBufferParam(ComputeShader, CbRcas, _rcasConstants, 0, Marshal.SizeOf<Fsr2.RcasConstants>());
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, 1);
}
}
internal class Fsr2GenerateReactivePipeline : Fsr2Pipeline
{
private readonly ComputeBuffer _generateReactiveConstants;
public Fsr2GenerateReactivePipeline(Fsr2.ContextDescription contextDescription, Fsr2Resources resources, ComputeBuffer generateReactiveConstants)
: base(contextDescription, resources, null)
{
_generateReactiveConstants = generateReactiveConstants;
LoadComputeShader("FSR2/ffx_fsr2_autogen_reactive_pass");
}
public override void ScheduleDispatch(CommandBuffer commandBuffer, Fsr2.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY)
{
}
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);
commandBuffer.SetComputeConstantBufferParam(ComputeShader, CbGenReactive, _generateReactiveConstants, 0, Marshal.SizeOf<Fsr2.GenerateReactiveConstants>());
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, 1);
}
}
}