@ -13,31 +13,31 @@ namespace FidelityFX
private Fsr2 . ContextDescription _contextDescription ;
private Fsr2 . ContextDescription _contextDescription ;
private CommandBuffer _commandBuffer ;
private CommandBuffer _commandBuffer ;
private ComputeShader _prepareInputColorShader ;
private ComputeShader _depthClipShader ;
private ComputeShader _reconstructPreviousDepthShader ;
private ComputeShader _lockShader ;
private ComputeShader _accumulateShader ;
private ComputeShader _generateReactiveShader ;
private ComputeShader _rcasShader ;
private ComputeShader _computeLuminancePyramidShader ;
private ComputeShader _tcrAutogenShader ;
private Fsr2Pipeline _depthClipPipeline ;
private Fsr2Pipeline _reconstructPreviousDepthPipeline ;
private Fsr2Pipeline _lockPipeline ;
private Fsr2Pipeline _accumulatePipeline ;
private Fsr2Pipeline _accumulateSharpenPipeline ;
private Fsr2Pipeline _rcasPipeline ;
private Fsr2Pipeline _computeLuminancePyramidPipeline ;
private Fsr2Pipeline _generateReactivePipeline ;
private Fsr2Pipeline _tcrAutogeneratePipeline ;
private ComputeBuffer _fsr2ConstantsBuffer ;
private ComputeBuffer _fsr2ConstantsBuffer ;
private readonly Fsr2Constants [ ] _fsr2ConstantsArray = { new Fsr2Constants ( ) } ;
private ref Fsr2Constants Constants = > ref _fsr2ConstantsArray [ 0 ] ;
private readonly Fsr2 . Fsr2 Constants[ ] _fsr2ConstantsArray = { new Fsr2 . Fsr2Constants ( ) } ;
private ref Fsr2 . Fsr2 Constants Constants = > ref _fsr2ConstantsArray [ 0 ] ;
private ComputeBuffer _spdConstantsBuffer ;
private ComputeBuffer _spdConstantsBuffer ;
private readonly SpdConstants [ ] _spdConstantsArray = { new SpdConstants ( ) } ;
private ref SpdConstants SpdConsts = > ref _spdConstantsArray [ 0 ] ;
private readonly Fsr2 . SpdConstants [ ] _spdConstantsArray = { new Fsr2 . SpdConstants ( ) } ;
private ref Fsr2 . SpdConstants SpdConsts = > ref _spdConstantsArray [ 0 ] ;
private ComputeBuffer _rcasConstantsBuffer ;
private ComputeBuffer _rcasConstantsBuffer ;
private readonly RcasConstants [ ] _rcasConstantsArray = new RcasConstants [ 1 ] ;
private ref RcasConstants RcasConsts = > ref _rcasConstantsArray [ 0 ] ;
private readonly Fsr2 . RcasConstants [ ] _rcasConstantsArray = new Fsr2 . RcasConstants [ 1 ] ;
private ref Fsr2 . RcasConstants RcasConsts = > ref _rcasConstantsArray [ 0 ] ;
private ComputeBuffer _generateReactiveConstantsBuffer ;
private ComputeBuffer _generateReactiveConstantsBuffer ;
private readonly GenerateReactiveConstants [ ] _generateReactiveConstantsArray = { new GenerateReactiveConstants ( ) } ;
private ref GenerateReactiveConstants GenReactiveConsts = > ref _generateReactiveConstantsArray [ 0 ] ;
private readonly Fsr2 . GenerateReactiveConstants [ ] _generateReactiveConstantsArray = { new Fsr2 . GenerateReactiveConstants ( ) } ;
private ref Fsr2 . GenerateReactiveConstants GenReactiveConsts = > ref _generateReactiveConstantsArray [ 0 ] ;
private bool _firstExecution ;
private bool _firstExecution ;
private Vector2 _previousJitterOffset ;
private Vector2 _previousJitterOffset ;
@ -48,9 +48,9 @@ namespace FidelityFX
_contextDescription = contextDescription ;
_contextDescription = contextDescription ;
_commandBuffer = new CommandBuffer { name = "FSR2" } ;
_commandBuffer = new CommandBuffer { name = "FSR2" } ;
_fsr2ConstantsBuffer = CreateConstantBuffer < Fsr2Constants > ( ) ;
_spdConstantsBuffer = CreateConstantBuffer < SpdConstants > ( ) ;
_rcasConstantsBuffer = CreateConstantBuffer < RcasConstants > ( ) ;
_fsr2ConstantsBuffer = CreateConstantBuffer < Fsr2 . Fsr2 Constants> ( ) ;
_spdConstantsBuffer = CreateConstantBuffer < Fsr2 . SpdConstants > ( ) ;
_rcasConstantsBuffer = CreateConstantBuffer < Fsr2 . RcasConstants > ( ) ;
// Set defaults
// Set defaults
_firstExecution = true ;
_firstExecution = true ;
@ -67,7 +67,7 @@ namespace FidelityFX
lanczos2Weights [ currentLanczosWidthIndex ] = ( short ) Mathf . Round ( y * 3 2 7 6 7.0f ) ;
lanczos2Weights [ currentLanczosWidthIndex ] = ( short ) Mathf . Round ( y * 3 2 7 6 7.0f ) ;
}
}
InitShader s ( ) ;
InitPipeline s ( ) ;
// TODO: create resources, i.e. render textures used for intermediate results.
// TODO: create resources, i.e. render textures used for intermediate results.
// Note that "aliasable" resources should be equivalent to GetTemporary render textures
// Note that "aliasable" resources should be equivalent to GetTemporary render textures
@ -76,17 +76,22 @@ namespace FidelityFX
// Unity doesn't do 1D textures so just default to Texture2D
// Unity doesn't do 1D textures so just default to Texture2D
}
}
private void InitShaders ( )
// private void InitShaders()
// {
// LoadComputeShader("FSR2/ffx_fsr2_compute_luminance_pyramid_pass", ref _computeLuminancePyramidShader, out _computeLuminancePyramidKernel);
// LoadComputeShader("FSR2/ffx_fsr2_rcas_pass", ref _rcasShader, out _rcasKernel);
// LoadComputeShader("FSR2/ffx_fsr2_prepare_input_color_pass", ref _prepareInputColorShader, out _prepareInputColorKernel);
// LoadComputeShader("FSR2/ffx_fsr2_depth_clip_pass", ref _depthClipShader, out _depthClipKernel);
// LoadComputeShader("FSR2/ffx_fsr2_reconstruct_previous_depth_pass", ref _reconstructPreviousDepthShader, out _reconstructPreviousDepthKernel);
// LoadComputeShader("FSR2/ffx_fsr2_lock_pass", ref _lockShader, out _lockKernel);
// LoadComputeShader("FSR2/ffx_fsr2_accumulate_pass", ref _accumulateShader, out _accumulateKernel);
// LoadComputeShader("FSR2/ffx_fsr2_autogen_reactive_pass", ref _generateReactiveShader, out _generateReactiveKernel);
// LoadComputeShader("FSR2/ffx_fsr2_tcr_autogen_pass", ref _tcrAutogenShader, out _tcrAutogenKernel);
// }
private void InitPipelines ( )
{
{
LoadComputeShader ( "FSR2/ffx_fsr2_compute_luminance_pyramid_pass" , ref _computeLuminancePyramidShader ) ;
LoadComputeShader ( "FSR2/ffx_fsr2_rcas_pass" , ref _rcasShader ) ;
LoadComputeShader ( "FSR2/ffx_fsr2_prepare_input_color_pass" , ref _prepareInputColorShader ) ;
LoadComputeShader ( "FSR2/ffx_fsr2_depth_clip_pass" , ref _depthClipShader ) ;
LoadComputeShader ( "FSR2/ffx_fsr2_reconstruct_previous_depth_pass" , ref _reconstructPreviousDepthShader ) ;
LoadComputeShader ( "FSR2/ffx_fsr2_lock_pass" , ref _lockShader ) ;
LoadComputeShader ( "FSR2/ffx_fsr2_accumulate_pass" , ref _accumulateShader ) ;
LoadComputeShader ( "FSR2/ffx_fsr2_autogen_reactive_pass" , ref _generateReactiveShader ) ;
LoadComputeShader ( "FSR2/ffx_fsr2_tcr_autogen_pass" , ref _tcrAutogenShader ) ;
_rcasPipeline = new Fsr2RcasPipeline ( _contextDescription . Callbacks , _fsr2ConstantsBuffer , _rcasConstantsBuffer ) ;
}
}
public void Dispatch ( Fsr2 . DispatchDescription dispatchParams )
public void Dispatch ( Fsr2 . DispatchDescription dispatchParams )
@ -125,25 +130,38 @@ namespace FidelityFX
}
}
// Auto exposure
// Auto exposure
SetupSpdConstants ( dispatchParams ) ;
SetupSpdConstants ( dispatchParams , out var dispatchThreadGroupCount ) ;
// Initialize constant buffers data
_fsr2ConstantsBuffer . SetData ( _fsr2ConstantsArray ) ;
_spdConstantsBuffer . SetData ( _spdConstantsArray ) ;
// // Compute luminance pyramid
// _commandBuffer.DispatchCompute(_computeLuminancePyramidShader, _computeLuminancePyramidKernel, dispatchThreadGroupCount.x, dispatchThreadGroupCount.y, 1);
//
// // Reconstruct previous depth
// _commandBuffer.DispatchCompute(_reconstructPreviousDepthShader, _reconstructPreviousDepthKernel, dispatchSrcX, dispatchSrcY, 1);
//
// // Depth clip
// _commandBuffer.DispatchCompute(_depthClipShader, _depthClipKernel, dispatchSrcX, dispatchSrcY, 1);
//
// // Lock
// _commandBuffer.DispatchCompute(_lockShader, _lockKernel, dispatchSrcX, dispatchSrcY, 1);
//
// // Accumulate
// _commandBuffer.DispatchCompute(_accumulateShader, _accumulateKernel, dispatchDstX, dispatchDstY, 1); // TODO: accumulate + sharpen
if ( dispatchParams . EnableSharpening )
if ( dispatchParams . EnableSharpening )
{
{
// Compute the constants
SetupRcasConstants ( dispatchParams ) ;
SetupRcasConstants ( dispatchParams ) ;
_rcasConstantsBuffer . SetData ( _rcasConstantsArray ) ;
// Run the RCAS sharpening filter on the upscaled image
int rcasKernel = _rcasShader . FindKernel ( "CS" ) ;
_rcasShader . SetTexture ( rcasKernel , "r_input_exposure" , dispatchParams . Exposure ) ;
_rcasShader . SetTexture ( rcasKernel , "r_rcas_input" , dispatchParams . Input ) ;
_rcasShader . SetTexture ( rcasKernel , "rw_upscaled_output" , dispatchParams . Output ) ;
_rcasShader . SetConstantBuffer ( "cbFSR2" , _fsr2ConstantsBuffer , 0 , Marshal . SizeOf < Fsr2Constants > ( ) ) ;
_rcasShader . SetConstantBuffer ( "cbRCAS" , _rcasConstantsBuffer , 0 , Marshal . SizeOf < RcasConstants > ( ) ) ;
// Dispatch RCAS
const int threadGroupWorkRegionDimRcas = 1 6 ;
const int threadGroupWorkRegionDimRcas = 1 6 ;
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 ;
_commandBuffer . DispatchCompute ( _rcasShader , rcasKernel , threadGroupsX , threadGroupsY , 1 ) ;
_rcasPipeline . ScheduleDispatch ( _commandBuffer , dispatchParams , threadGroupsX , threadGroupsY ) ;
}
}
else
else
{
{
@ -159,7 +177,7 @@ namespace FidelityFX
private void SetupConstants ( Fsr2 . DispatchDescription dispatchParams , bool resetAccumulation )
private void SetupConstants ( Fsr2 . DispatchDescription dispatchParams , bool resetAccumulation )
{
{
ref Fsr2Constants constants = ref Constants ;
ref Fsr2 . Fsr2 Constants constants = ref Constants ;
constants . jitterOffset = dispatchParams . JitterOffset ;
constants . jitterOffset = dispatchParams . JitterOffset ;
constants . renderSize = new Vector2Int (
constants . renderSize = new Vector2Int (
@ -229,8 +247,6 @@ namespace FidelityFX
float mipDiv = 2 < < constants . lumaMipLevelToUse ;
float mipDiv = 2 < < constants . lumaMipLevelToUse ;
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 ) ;
_fsr2ConstantsBuffer . SetData ( _fsr2ConstantsArray ) ;
}
}
private Vector4 SetupDeviceDepthToViewSpaceDepthParams ( Fsr2 . DispatchDescription dispatchParams )
private Vector4 SetupDeviceDepthToViewSpaceDepthParams ( Fsr2 . DispatchDescription dispatchParams )
@ -271,25 +287,21 @@ namespace FidelityFX
{
{
int sharpnessIndex = Mathf . RoundToInt ( Mathf . Clamp01 ( dispatchParams . Sharpness ) * ( RcasConfigs . Count - 1 ) ) ;
int sharpnessIndex = Mathf . RoundToInt ( Mathf . Clamp01 ( dispatchParams . Sharpness ) * ( RcasConfigs . Count - 1 ) ) ;
RcasConsts = RcasConfigs [ sharpnessIndex ] ;
RcasConsts = RcasConfigs [ sharpnessIndex ] ;
_rcasConstantsBuffer . SetData ( _rcasConstantsArray ) ;
}
}
private void SetupSpdConstants ( Fsr2 . DispatchDescription dispatchParams )
private void SetupSpdConstants ( Fsr2 . DispatchDescription dispatchParams , out Vector2Int dispatchThreadGroupCount )
{
{
RectInt rectInfo = new RectInt ( 0 , 0 , dispatchParams . RenderSize . x , dispatchParams . RenderSize . y ) ;
RectInt rectInfo = new RectInt ( 0 , 0 , dispatchParams . RenderSize . x , dispatchParams . RenderSize . y ) ;
SpdSetup ( rectInfo , out var dispatchThreadGroupCount , out var workGroupOffset , out var numWorkGroupsAndMips ) ;
SpdSetup ( rectInfo , out dispatchThreadGroupCount , out var workGroupOffset , out var numWorkGroupsAndMips ) ;
// Downsample
// Downsample
ref SpdConstants spdConstants = ref SpdConsts ;
ref Fsr2 . SpdConstants spdConstants = ref SpdConsts ;
spdConstants . numWorkGroups = ( uint ) numWorkGroupsAndMips . x ;
spdConstants . numWorkGroups = ( uint ) numWorkGroupsAndMips . x ;
spdConstants . mips = ( uint ) numWorkGroupsAndMips . y ;
spdConstants . mips = ( uint ) numWorkGroupsAndMips . y ;
spdConstants . workGroupOffsetX = ( uint ) workGroupOffset . x ;
spdConstants . workGroupOffsetX = ( uint ) workGroupOffset . x ;
spdConstants . workGroupOffsetY = ( uint ) workGroupOffset . y ;
spdConstants . workGroupOffsetY = ( uint ) workGroupOffset . y ;
spdConstants . renderSizeX = ( uint ) dispatchParams . RenderSize . x ;
spdConstants . renderSizeX = ( uint ) dispatchParams . RenderSize . x ;
spdConstants . renderSizeY = ( uint ) dispatchParams . RenderSize . y ;
spdConstants . renderSizeY = ( uint ) dispatchParams . RenderSize . y ;
_spdConstantsBuffer . SetData ( _spdConstantsArray ) ;
}
}
private static void SpdSetup ( RectInt rectInfo ,
private static void SpdSetup ( RectInt rectInfo ,
@ -312,88 +324,29 @@ namespace FidelityFX
public void Destroy ( )
public void Destroy ( )
{
{
DisposePipeline ( ref _tcrAutogeneratePipeline ) ;
DisposePipeline ( ref _generateReactivePipeline ) ;
DisposePipeline ( ref _computeLuminancePyramidPipeline ) ;
DisposePipeline ( ref _rcasPipeline ) ;
DisposePipeline ( ref _accumulateSharpenPipeline ) ;
DisposePipeline ( ref _accumulatePipeline ) ;
DisposePipeline ( ref _lockPipeline ) ;
DisposePipeline ( ref _reconstructPreviousDepthPipeline ) ;
DisposePipeline ( ref _depthClipPipeline ) ;
DestroyConstantBuffer ( ref _rcasConstantsBuffer ) ;
DestroyConstantBuffer ( ref _rcasConstantsBuffer ) ;
DestroyConstantBuffer ( ref _spdConstantsBuffer ) ;
DestroyConstantBuffer ( ref _spdConstantsBuffer ) ;
DestroyConstantBuffer ( ref _fsr2ConstantsBuffer ) ;
DestroyConstantBuffer ( ref _fsr2ConstantsBuffer ) ;
DestroyComputeShader ( ref _tcrAutogenShader ) ;
DestroyComputeShader ( ref _generateReactiveShader ) ;
DestroyComputeShader ( ref _accumulateShader ) ;
DestroyComputeShader ( ref _lockShader ) ;
DestroyComputeShader ( ref _reconstructPreviousDepthShader ) ;
DestroyComputeShader ( ref _depthClipShader ) ;
DestroyComputeShader ( ref _prepareInputColorShader ) ;
DestroyComputeShader ( ref _rcasShader ) ;
DestroyComputeShader ( ref _computeLuminancePyramidShader ) ;
_commandBuffer . Dispose ( ) ;
_commandBuffer . Dispose ( ) ;
_commandBuffer = null ;
_commandBuffer = null ;
}
}
[Serializable, StructLayout(LayoutKind.Sequential)]
private struct Fsr2Constants
{
public Vector2Int renderSize ;
public Vector2Int maxRenderSize ;
public Vector2Int displaySize ;
public Vector2Int inputColorResourceDimensions ;
public Vector2Int lumaMipDimensions ;
public int lumaMipLevelToUse ;
public int frameIndex ;
public Vector4 deviceToViewDepth ;
public Vector2 jitterOffset ;
public Vector2 motionVectorScale ;
public Vector2 downscaleFactor ;
public Vector2 motionVectorJitterCancellation ;
public float preExposure ;
public float previousFramePreExposure ;
public float tanHalfFOV ;
public float jitterPhaseCount ;
public float deltaTime ;
public float dynamicResChangeFactor ;
public float viewSpaceToMetersFactor ;
}
[Serializable, StructLayout(LayoutKind.Sequential)]
private struct SpdConstants
{
public uint mips ;
public uint numWorkGroups ;
public uint workGroupOffsetX , workGroupOffsetY ;
public uint renderSizeX , renderSizeY ;
}
[Serializable, StructLayout(LayoutKind.Sequential)]
private struct GenerateReactiveConstants
{
public float scale ;
public float threshold ;
public float binaryValue ;
public uint flags ;
}
[Serializable, StructLayout(LayoutKind.Sequential)]
private struct RcasConstants
{
public RcasConstants ( uint sharpness , uint halfSharp )
{
this . sharpness = sharpness ;
this . halfSharp = halfSharp ;
dummy0 = dummy1 = 0 ;
}
public readonly uint sharpness ;
public readonly uint halfSharp ;
public readonly uint dummy0 ;
public readonly uint dummy1 ;
}
/// <summary>
/// <summary>
/// The FSR2 C++ codebase uses floats bitwise converted to ints to pass sharpness parameters to the RCAS shader.
/// The FSR2 C++ codebase uses floats bitwise converted to ints to pass sharpness parameters to the RCAS shader.
/// This is not possible in C# without enabling unsafe code compilation, so to avoid that we instead use a table of precomputed values.
/// This is not possible in C# without enabling unsafe code compilation, so to avoid that we instead use a table of precomputed values.
/// </summary>
/// </summary>
private static readonly List < RcasConstants > RcasConfigs = new ( )
private static readonly List < Fsr2 . RcasConstants > RcasConfigs = new ( )
{
{
new ( 1 0 4 8 5 7 6 0 0 0 u , 8 7 2 4 2 8 5 4 4 u ) ,
new ( 1 0 4 8 5 7 6 0 0 0 u , 8 7 2 4 2 8 5 4 4 u ) ,
new ( 1 0 4 9 1 7 8 0 8 0 u , 8 7 7 2 1 2 7 4 5 u ) ,
new ( 1 0 4 9 1 7 8 0 8 0 u , 8 7 7 2 1 2 7 4 5 u ) ,
@ -423,12 +376,6 @@ namespace FidelityFX
return new ComputeBuffer ( 1 , Marshal . SizeOf < TConstants > ( ) , ComputeBufferType . Constant ) ;
return new ComputeBuffer ( 1 , Marshal . SizeOf < TConstants > ( ) , ComputeBufferType . Constant ) ;
}
}
private void LoadComputeShader ( string name , ref ComputeShader shaderRef )
{
if ( shaderRef = = null )
shaderRef = _contextDescription . Callbacks . LoadComputeShader ( name ) ;
}
private static void DestroyConstantBuffer ( ref ComputeBuffer bufferRef )
private static void DestroyConstantBuffer ( ref ComputeBuffer bufferRef )
{
{
if ( bufferRef = = null )
if ( bufferRef = = null )
@ -438,13 +385,13 @@ namespace FidelityFX
bufferRef = null ;
bufferRef = null ;
}
}
private void DestroyComputeShader ( ref ComputeShader shaderRef )
private static void DisposePipeline ( ref Fsr2Pipeline pipeline )
{
{
if ( shaderRef = = null )
if ( pipeline = = null )
return ;
return ;
_contextDescription . Callbacks . UnloadComputeShader ( shaderRef ) ;
shaderRef = null ;
pipeline . Dispose ( ) ;
pipeline = null ;
}
}
}
}
}
}