@ -50,7 +50,7 @@ public class FSR2Thing : MonoBehaviour
{
if ( _rcasComputeShader = = null )
{
// TODO: this is nasty, I don't like this. How do we manage/bind compute shaders best?
// TODO: this is nasty, I don't like this. How do we manage/bind compute shaders best? => make a Callbacks class/interface with overridable implementation
// GPUInstancer used Resources, we modified that to load stuff from asset bundles instead. Maybe provide a custom loader callback interface?
_rcasComputeShader = Resources . Load < ComputeShader > ( "Shaders/ffx_fsr2_rcas_pass" ) ;
}
@ -59,8 +59,11 @@ public class FSR2Thing : MonoBehaviour
}
}
private ComputeBuffer _rcasConstantBuffer ;
private RcasConfig [ ] _rcasConfig = new RcasConfig [ 1 ] ;
private ComputeBuffer _fsr2ConstantsBuffer ;
private readonly Fsr2Constants [ ] _fsr2ConstantsArray = { new Fsr2Constants ( ) } ;
private ComputeBuffer _rcasConstantsBuffer ;
private readonly RcasConstants [ ] _rcasConstantsArray = new RcasConstants [ 1 ] ;
private void OnEnable ( )
{
@ -77,16 +80,23 @@ public class FSR2Thing : MonoBehaviour
_exposure . name = "FSR2 Exposure" ;
_exposure . SetPixel ( 0 , 0 , Color . white ) ;
_exposure . Apply ( ) ;
_rcasConstantBuffer = new ComputeBuffer ( 1 , Marshal . SizeOf < RcasConfig > ( ) , ComputeBufferType . Constant ) ;
_fsr2ConstantsBuffer = new ComputeBuffer ( 1 , Marshal . SizeOf < Fsr2Constants > ( ) , ComputeBufferType . Constant ) ;
_rcasConstantsBuffer = new ComputeBuffer ( 1 , Marshal . SizeOf < RcasConstants > ( ) , ComputeBufferType . Constant ) ;
}
private void OnDisable ( )
{
if ( _rcasConstantBuffer ! = null )
if ( _rcasConstants Buffer ! = null )
{
_rcasConstantBuffer . Release ( ) ;
_rcasConstantBuffer = null ;
_rcasConstantsBuffer . Release ( ) ;
_rcasConstantsBuffer = null ;
}
if ( _fsr2ConstantsBuffer ! = null )
{
_fsr2ConstantsBuffer . Release ( ) ;
_fsr2ConstantsBuffer = null ;
}
if ( _exposure ! = null )
@ -122,20 +132,28 @@ public class FSR2Thing : MonoBehaviour
// Do a dumb upscale first
Graphics . Blit ( gameCamera . targetTexture , _upscaleRT , TestMaterial ) ;
_fsr2ConstantsArray [ 0 ] . preExposure = 1.0f ;
_fsr2ConstantsBuffer . SetData ( _fsr2ConstantsArray ) ;
if ( performSharpenPass )
{
int sharpnessIndex = Mathf . RoundToInt ( Mathf . Clamp01 ( sharpness ) * ( RcasConfigs . Count - 1 ) ) ;
_rcasConfig [ 0 ] = RcasConfigs [ sharpnessIndex ] ;
_rcasConstantBuffer . SetData ( _rcasConfig ) ;
_rcasConstantsArray [ 0 ] = RcasConfigs [ sharpnessIndex ] ;
_rcasConstants Buffer . SetData ( _rcasConstantsArray ) ;
// Run the RCAS sharpening filter on the upscaled image
int rcasKernel = RCASComputeShader . FindKernel ( "CS" ) ;
// TODO: create constant buffer (cbFSR2) with fPreExposure set to 1.0
RCASComputeShader . SetTexture ( rcasKernel , "r_exposure" , _exposure ) ;
RCASComputeShader . SetTexture ( rcasKernel , "r_rcas_input" , _upscaleRT ) ;
RCASComputeShader . SetTexture ( rcasKernel , "rw_upscaled_output" , _rcasOutput ) ;
RCASComputeShader . SetConstantBuffer ( "cbRCAS" , _rcasConstantBuffer , 0 , Marshal . SizeOf < RcasConfig > ( ) ) ;
RCASComputeShader . Dispatch ( rcasKernel , Screen . width , Screen . height , 1 ) ; // TODO: not sure how these thread groups work...
RCASComputeShader . SetConstantBuffer ( "cbFSR2" , _fsr2ConstantsBuffer , 0 , Marshal . SizeOf < Fsr2Constants > ( ) ) ;
RCASComputeShader . SetConstantBuffer ( "cbRCAS" , _rcasConstantsBuffer , 0 , Marshal . SizeOf < RcasConstants > ( ) ) ;
const int threadGroupWorkRegionDimRcas = 1 6 ;
int threadGroupsX = ( Screen . width + threadGroupWorkRegionDimRcas - 1 ) / threadGroupWorkRegionDimRcas ;
int threadGroupsY = ( Screen . height + threadGroupWorkRegionDimRcas - 1 ) / threadGroupWorkRegionDimRcas ;
RCASComputeShader . Dispatch ( rcasKernel , threadGroupsX , threadGroupsY , 1 ) ;
// Output sharpened image to screen
Graphics . Blit ( _rcasOutput , dest ) ;
@ -146,23 +164,50 @@ public class FSR2Thing : MonoBehaviour
}
}
[Serializable]
private struct RcasConfig
[Serializable, StructLayout(LayoutKind.Sequential) ]
private struct RcasConstants
{
public RcasConfig ( uint sharpness , uint halfSharp )
public RcasConstants ( uint sharpness , uint halfSharp )
{
this . sharpness = sharpness ;
this . halfSharp = halfSharp ;
dummy0 = dummy1 = 0 ;
}
public uint sharpness ;
public uint halfSharp ;
public uint dummy0 ;
public uint dummy1 ;
public readonly uint sharpness ;
public readonly uint halfSharp ;
public readonly uint dummy0 ;
public readonly uint dummy1 ;
}
private static readonly List < RcasConfig > RcasConfigs = new ( )
[Serializable, StructLayout(LayoutKind.Sequential)]
private struct Fsr2Constants
{
public Vector2Int renderSize ;
public Vector2Int displaySize ;
public uint lumaMipDimensionsX , lumaMipDimensionsY ;
public uint lumaMipLevelToUse ;
public uint frameIndex ;
public Vector2 displaySizeRcp ;
public Vector2 jitterOffset ;
public Vector4 deviceToViewDepth ;
public Vector2 depthClipUVScale ;
public Vector2 postLockStatusUVScale ;
public Vector2 reactiveMaskDimRcp ;
public Vector2 motionVectorScale ;
public Vector2 downscaleFactor ;
public float preExposure ;
public float tanHalfFOV ;
public Vector2 motionVectorJitterCancellation ;
public float jitterPhaseCount ;
public float lockInitialLifetime ;
public float lockTickDelta ;
public float deltaTime ;
public float dynamicResChangeFactor ;
public float lumaMipRcp ;
}
private static readonly List < 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 9 1 7 8 0 8 0 u , 8 7 7 2 1 2 7 4 5 u ) ,