@ -5,29 +5,42 @@ using UnityEngine.Rendering;
namespace FidelityFX
namespace FidelityFX
{
{
/// <summary>
/// This class is responsible for hooking into various Unity events and translating them to the FSR2 subsystem.
/// This includes creation and destruction of the FSR2 context, as well as dispatching commands at the right time.
/// This class also exposes various FSR2 parameters to the Unity inspector.
/// </summary>
[RequireComponent(typeof(Camera))]
[RequireComponent(typeof(Camera))]
public class Fsr2Controller : MonoBehaviour
public class Fsr2Controller : MonoBehaviour
{
{
[SerializeField] private Fsr2 . QualityMode qualityMode ;
[SerializeField] private Fsr2 . QualityMode qualityMode ;
[SerializeField] private bool performSharpenPass = true ;
[SerializeField, Range(0, 1)] private float sharpness = 0.8f ;
private Fsr2Context _context ;
private Camera _renderCamera ;
private Camera _renderCamera ;
private RenderTexture _originalRenderTarget ;
private RenderTexture _originalRenderTarget ;
private DepthTextureMode _originalDepthTextureMode ;
private GameObject _displayCameraObject ;
private GameObject _displayCameraObject ;
private Camera _displayCamera ;
private Camera _displayCamera ;
private Fsr2Dispatcher _dispatcher ;
private Fsr2Dispatcher _dispatcher ;
private readonly Fsr2 . DispatchDescription _dispatchDescription = new Fsr2 . DispatchDescription ( ) ;
private Fsr2 . QualityMode _prevQualityMode ;
private Fsr2 . QualityMode _prevQualityMode ;
private Vector2Int _prevScreenSize ;
private Vector2Int _prevScreenSize ;
private CommandBuffer _opaqueOnlyCommandBuffer ;
private CommandBuffer _opaqueOnlyCommandBuffer ;
private CommandBuffer _inputsCommandBuffer ;
private CommandBuffer _inputsCommandBuffer ;
private void OnEnable ( )
private void OnEnable ( )
{
{
_renderCamera = GetComponent < Camera > ( ) ;
if ( _displayCameraObject = = null )
if ( _displayCameraObject = = null )
{
{
// Create a helper object with a camera that outputs at screen resolution
_displayCameraObject = new GameObject ( "FSR2 Camera Object" ) ;
_displayCameraObject = new GameObject ( "FSR2 Camera Object" ) ;
_displayCameraObject . transform . SetParent ( transform ) ;
_displayCameraObject . transform . SetParent ( transform ) ;
_displayCameraObject . transform . SetPositionAndRotation ( Vector3 . zero , Quaternion . identity ) ;
_displayCameraObject . transform . SetPositionAndRotation ( Vector3 . zero , Quaternion . identity ) ;
@ -45,15 +58,19 @@ namespace FidelityFX
_displayCamera . renderingPath = RenderingPath . Forward ;
_displayCamera . renderingPath = RenderingPath . Forward ;
_dispatcher = _displayCameraObject . AddComponent < Fsr2Dispatcher > ( ) ;
_dispatcher = _displayCameraObject . AddComponent < Fsr2Dispatcher > ( ) ;
_dispatcher . DispatchDescription = _dispatchDescription ;
}
}
Fsr2 . GetRenderResolutionFromQualityMode ( out var renderWidth , out var renderHeight , Screen . width , Screen . height , qualityMode ) ;
_context = Fsr2 . CreateContext ( new Vector2Int ( Screen . width , Screen . height ) , new Vector2Int ( renderWidth , renderHeight ) , Fsr2 . InitializationFlags . EnableMotionVectorsJitterCancellation ) ;
_dispatcher . renderCamera = _renderCamera ;
_dispatcher . renderScale = 1.0f / Fsr2 . GetUpscaleRatioFromQualityMode ( qualityMode ) ;
_dispatcher . Context = _context ;
_dispatcher . enabled = true ;
_dispatcher . enabled = true ;
Fsr2 . GetRenderResolutionFromQualityMode ( out var renderWidth , out var renderHeight , Screen . width , Screen . height , qualityMode ) ;
// Set up the original camera to output all of the required FSR2 input resources at the desired resolution
_renderCamera = GetComponent < Camera > ( ) ;
_originalRenderTarget = _renderCamera . targetTexture ; // TODO: if this isn't null, could maybe reuse this for the output texture?
_originalRenderTarget = _renderCamera . targetTexture ; // TODO: if this isn't null, could maybe reuse this for the output texture?
_originalDepthTextureMode = _renderCamera . depthTextureMode ;
_renderCamera . targetTexture = new RenderTexture (
_renderCamera . targetTexture = new RenderTexture (
renderWidth , renderHeight ,
renderWidth , renderHeight ,
@ -64,6 +81,7 @@ namespace FidelityFX
_renderCamera . depthTextureMode | = DepthTextureMode . Depth | DepthTextureMode . MotionVectors ;
_renderCamera . depthTextureMode | = DepthTextureMode . Depth | DepthTextureMode . MotionVectors ;
// Create command buffers to bind the camera's output at the right moments in the rendering pipeline
_opaqueOnlyCommandBuffer = new CommandBuffer { name = "FSR2 Opaque Input" } ;
_opaqueOnlyCommandBuffer = new CommandBuffer { name = "FSR2 Opaque Input" } ;
// TODO: may need to copy the opaque-only render buffer to a temp RT here, in which case we'll need an additional CommandBuffer to release the temp RT again
// TODO: may need to copy the opaque-only render buffer to a temp RT here, in which case we'll need an additional CommandBuffer to release the temp RT again
_opaqueOnlyCommandBuffer . SetGlobalTexture ( Fsr2Pipeline . SrvOpaqueOnly , BuiltinRenderTextureType . CameraTarget , RenderTextureSubElement . Color ) ;
_opaqueOnlyCommandBuffer . SetGlobalTexture ( Fsr2Pipeline . SrvOpaqueOnly , BuiltinRenderTextureType . CameraTarget , RenderTextureSubElement . Color ) ;
@ -99,9 +117,17 @@ namespace FidelityFX
_renderCamera . targetTexture . Release ( ) ;
_renderCamera . targetTexture . Release ( ) ;
_renderCamera . targetTexture = _originalRenderTarget ;
_renderCamera . targetTexture = _originalRenderTarget ;
_renderCamera . depthTextureMode = _originalDepthTextureMode ;
_dispatcher . Context = null ;
_dispatcher . enabled = false ;
_dispatcher . enabled = false ;
_displayCamera . enabled = false ;
_displayCamera . enabled = false ;
if ( _context ! = null )
{
_context . Destroy ( ) ;
_context = null ;
}
}
}
private void Update ( )
private void Update ( )
@ -116,21 +142,48 @@ namespace FidelityFX
}
}
}
}
private Rect _tempRect ;
public void Reset ( )
{
_reset = true ;
}
private Rect _tempRect ;
private bool _reset ;
private void OnPreRender ( )
private void OnPreRender ( )
{
{
_tempRect = _renderCamera . rect ;
_tempRect = _renderCamera . rect ;
_renderCamera . aspect = ( Screen . width * _tempRect . width ) / ( Screen . height * _tempRect . height ) ;
_renderCamera . aspect = ( Screen . width * _tempRect . width ) / ( Screen . height * _tempRect . height ) ;
_renderCamera . rect = new Rect ( 0 , 0 , 1 , 1 ) ;
_renderCamera . rect = new Rect ( 0 , 0 , 1 , 1 ) ;
var targetTexture = _renderCamera . targetTexture ;
_dispatchDescription . Color = null ;
_dispatchDescription . Depth = null ;
_dispatchDescription . MotionVectors = null ;
_dispatchDescription . Output = null ;
_dispatchDescription . Exposure = null ;
_dispatchDescription . Reactive = null ;
_dispatchDescription . PreExposure = 0 ;
_dispatchDescription . EnableSharpening = performSharpenPass ;
_dispatchDescription . Sharpness = sharpness ;
_dispatchDescription . MotionVectorScale . x = - _renderCamera . pixelWidth ;
_dispatchDescription . MotionVectorScale . y = - _renderCamera . pixelHeight ;
_dispatchDescription . RenderSize = new Vector2Int ( targetTexture . width , targetTexture . height ) ;
_dispatchDescription . FrameTimeDelta = Time . unscaledDeltaTime ;
_dispatchDescription . CameraNear = _renderCamera . nearClipPlane ;
_dispatchDescription . CameraFar = _renderCamera . farClipPlane ;
_dispatchDescription . CameraFovAngleVertical = _renderCamera . fieldOfView * Mathf . Deg2Rad ;
_dispatchDescription . ViewSpaceToMetersFactor = 1.0f ; // 1 unit is 1 meter in Unity
_dispatchDescription . Reset = _reset ;
_reset = false ;
// Perform custom jittering of the camera's projection matrix according to FSR2's instructions
// Perform custom jittering of the camera's projection matrix according to FSR2's instructions
int jitterPhaseCount = Fsr2 . GetJitterPhaseCount ( _renderCamera . targetTexture . width , Screen . width ) ;
int jitterPhaseCount = Fsr2 . GetJitterPhaseCount ( targetTexture . width , Screen . width ) ;
Fsr2 . GetJitterOffset ( out float jitterX , out float jitterY , Time . frameCount , jitterPhaseCount ) ;
Fsr2 . GetJitterOffset ( out float jitterX , out float jitterY , Time . frameCount , jitterPhaseCount ) ;
_dispatcher . SetJitterOffset ( new Vector2 ( jitterX , jitterY ) ) ;
_dispatchDescription . JitterOffset = new Vector2 ( jitterX , jitterY ) ;
var targetTexture = _renderCamera . targetTexture ;
jitterX = 2.0f * jitterX / targetTexture . width ;
jitterX = 2.0f * jitterX / targetTexture . width ;
jitterY = 2.0f * jitterY / targetTexture . height ;
jitterY = 2.0f * jitterY / targetTexture . height ;
@ -146,44 +199,17 @@ namespace FidelityFX
}
}
/// <summary>
/// <summary>
/// This class is responsible for hooking into various Unity events and translating them to the FSR2 subsystem.
/// This includes creation and destruction of the FSR2 context, as well as dispatching commands at the right time.
/// This class also exposes various FSR2 parameters to the Unity inspector.
/// Helper class to dispatch FSR2 commands on the display camera object, and render the final output texture.
/// </summary>
/// </summary>
internal class Fsr2Dispatcher : MonoBehaviour
internal class Fsr2Dispatcher : MonoBehaviour
{
{
[SerializeField] private bool performSharpenPass = true ;
[SerializeField, Range(0, 1)] private float sharpness = 0.8f ;
[SerializeField] private bool reset ;
[HideInInspector] public Camera renderCamera ;
[HideInInspector] public float renderScale ;
private bool _started ;
private Vector2Int DisplaySize = > new Vector2Int ( Screen . width , Screen . height ) ;
private Vector2Int RenderSize = > new Vector2Int ( Mathf . FloorToInt ( Screen . width * renderScale ) , Mathf . FloorToInt ( Screen . height * renderScale ) ) ;
private Fsr2Context _context ;
private readonly Fsr2 . DispatchDescription _dispatchDescription = new Fsr2 . DispatchDescription ( ) ;
public Fsr2Context Context ;
public Fsr2 . DispatchDescription DispatchDescription ;
private CommandBuffer _commandBuffer ;
private CommandBuffer _commandBuffer ;
private void Start ( )
{
_started = true ;
OnEnable ( ) ;
}
private void OnEnable ( )
private void OnEnable ( )
{
{
// Delay OnEnable until we're sure all fields and properties are set
if ( ! _started )
return ;
_context = Fsr2 . CreateContext ( DisplaySize , RenderSize , Fsr2 . InitializationFlags . EnableMotionVectorsJitterCancellation ) ;
_commandBuffer = new CommandBuffer { name = "FSR2 Dispatch" } ;
_commandBuffer = new CommandBuffer { name = "FSR2 Dispatch" } ;
}
}
@ -194,20 +220,8 @@ namespace FidelityFX
_commandBuffer . Release ( ) ;
_commandBuffer . Release ( ) ;
_commandBuffer = null ;
_commandBuffer = null ;
}
}
if ( _context ! = null )
{
_context . Destroy ( ) ;
_context = null ;
}
}
public void SetJitterOffset ( Vector2 jitterOffset )
{
_dispatchDescription . JitterOffset = jitterOffset ;
}
}
// For legacy built-in render pipeline
private void OnRenderImage ( RenderTexture src , RenderTexture dest )
private void OnRenderImage ( RenderTexture src , RenderTexture dest )
{
{
_commandBuffer . Clear ( ) ;
_commandBuffer . Clear ( ) ;
@ -221,30 +235,10 @@ namespace FidelityFX
else
else
{
{
// We are rendering to the backbuffer, so we need a temporary render texture for FSR2 to output to
// We are rendering to the backbuffer, so we need a temporary render texture for FSR2 to output to
_commandBuffer . GetTemporaryRT ( Fsr2Pipeline . UavUpscaledOutput , DisplaySize . x , DisplaySize . y , 0 , default , GraphicsFormat . R16G16B16A16_SFloat , 1 , true ) ;
_commandBuffer . GetTemporaryRT ( Fsr2Pipeline . UavUpscaledOutput , Screen . width , Screen . height , 0 , default , GraphicsFormat . R16G16B16A16_SFloat , 1 , true ) ;
}
}
_dispatchDescription . Color = null ;
_dispatchDescription . Depth = null ;
_dispatchDescription . MotionVectors = null ;
_dispatchDescription . Output = null ;
_dispatchDescription . Exposure = null ;
_dispatchDescription . Reactive = null ;
_dispatchDescription . PreExposure = 0 ;
_dispatchDescription . EnableSharpening = performSharpenPass ;
_dispatchDescription . Sharpness = sharpness ;
_dispatchDescription . MotionVectorScale . x = - renderCamera . pixelWidth ;
_dispatchDescription . MotionVectorScale . y = - renderCamera . pixelHeight ;
_dispatchDescription . RenderSize = RenderSize ;
_dispatchDescription . FrameTimeDelta = Time . unscaledDeltaTime ;
_dispatchDescription . CameraNear = renderCamera . nearClipPlane ;
_dispatchDescription . CameraFar = renderCamera . farClipPlane ;
_dispatchDescription . CameraFovAngleVertical = renderCamera . fieldOfView * Mathf . Deg2Rad ;
_dispatchDescription . ViewSpaceToMetersFactor = 1.0f ; // 1 unit is 1 meter in Unity
_dispatchDescription . Reset = reset ;
reset = false ;
_context . Dispatch ( _dispatchDescription , _commandBuffer ) ;
Context . Dispatch ( DispatchDescription , _commandBuffer ) ;
// Output upscaled image to screen
// Output upscaled image to screen
// TODO: if `dest` is null, we likely don't care about the depth & motion vectors anymore
// TODO: if `dest` is null, we likely don't care about the depth & motion vectors anymore