Browse Source

Reworked the image effect integration, breaking up things and removing unnecessary parts to improve clarity and readability.

This makes it more effective as an example of how to integrate FSR2 into a render pipeline.
hdrp
Nico de Poel 3 years ago
parent
commit
d2e6eedf37
  1. 173
      Assets/Scripts/Fsr2ImageEffect.cs

173
Assets/Scripts/Fsr2ImageEffect.cs

@ -105,7 +105,8 @@ namespace FidelityFX
private Fsr2Context _context; private Fsr2Context _context;
private Vector2Int _renderSize; private Vector2Int _renderSize;
private Vector2Int _displaySize; private Vector2Int _displaySize;
private bool _reset;
private float _appliedBiasOffset;
private bool _resetHistory;
private readonly Fsr2.DispatchDescription _dispatchDescription = new Fsr2.DispatchDescription(); private readonly Fsr2.DispatchDescription _dispatchDescription = new Fsr2.DispatchDescription();
private readonly Fsr2.GenerateReactiveDescription _genReactiveDescription = new Fsr2.GenerateReactiveDescription(); private readonly Fsr2.GenerateReactiveDescription _genReactiveDescription = new Fsr2.GenerateReactiveDescription();
@ -119,8 +120,7 @@ namespace FidelityFX
private Fsr2.QualityMode _prevQualityMode; private Fsr2.QualityMode _prevQualityMode;
private Vector2Int _prevDisplaySize; private Vector2Int _prevDisplaySize;
private bool _prevGenReactiveMask;
private bool _prevGenTcrMasks;
private bool _prevAutoExposure;
private CommandBuffer _dispatchCommandBuffer; private CommandBuffer _dispatchCommandBuffer;
private CommandBuffer _opaqueInputCommandBuffer; private CommandBuffer _opaqueInputCommandBuffer;
@ -141,13 +141,6 @@ namespace FidelityFX
_displaySize = GetDisplaySize(); _displaySize = GetDisplaySize();
Fsr2.GetRenderResolutionFromQualityMode(out var renderWidth, out var renderHeight, _displaySize.x, _displaySize.y, qualityMode); Fsr2.GetRenderResolutionFromQualityMode(out var renderWidth, out var renderHeight, _displaySize.x, _displaySize.y, qualityMode);
_renderSize = new Vector2Int(renderWidth, renderHeight); _renderSize = new Vector2Int(renderWidth, renderHeight);
// Apply a mipmap bias so that textures retain their sharpness
float biasOffset = Fsr2.GetMipmapBiasOffset(_renderSize.x, _displaySize.x);
if (!float.IsNaN(biasOffset))
{
Callbacks.ApplyMipmapBias(biasOffset);
}
if (!SystemInfo.supportsComputeShaders) if (!SystemInfo.supportsComputeShaders)
{ {
@ -164,7 +157,30 @@ namespace FidelityFX
} }
_helper = GetComponent<Fsr2ImageEffectHelper>(); _helper = GetComponent<Fsr2ImageEffectHelper>();
_copyWithDepthMaterial = new Material(Shader.Find("Hidden/BlitCopyWithDepth"));
CreateFsrContext();
CreateCommandBuffers();
}
private void OnDisable()
{
DestroyCommandBuffers();
DestroyFsrContext();
if (_copyWithDepthMaterial != null)
{
Destroy(_copyWithDepthMaterial);
_copyWithDepthMaterial = null;
}
// Restore the camera's original state
_renderCamera.depthTextureMode = _originalDepthTextureMode;
_renderCamera.targetTexture = _originalRenderTarget;
}
private void CreateFsrContext()
{
// Initialize FSR2 context // Initialize FSR2 context
Fsr2.InitializationFlags flags = 0; Fsr2.InitializationFlags flags = 0;
if (_renderCamera.allowHDR) flags |= Fsr2.InitializationFlags.EnableHighDynamicRange; if (_renderCamera.allowHDR) flags |= Fsr2.InitializationFlags.EnableHighDynamicRange;
@ -173,41 +189,33 @@ namespace FidelityFX
_context = Fsr2.CreateContext(_displaySize, _renderSize, Callbacks, flags); _context = Fsr2.CreateContext(_displaySize, _renderSize, Callbacks, flags);
_dispatchCommandBuffer = new CommandBuffer { name = "FSR2 Dispatch" };
_opaqueInputCommandBuffer = new CommandBuffer { name = "FSR2 Opaque Input" };
if (autoGenerateReactiveMask || autoGenerateTransparencyAndComposition)
{
_renderCamera.AddCommandBuffer(CameraEvent.BeforeForwardAlpha, _opaqueInputCommandBuffer);
}
_copyWithDepthMaterial = new Material(Shader.Find("Hidden/BlitCopyWithDepth"));
_prevDisplaySize = _displaySize; _prevDisplaySize = _displaySize;
_prevQualityMode = qualityMode; _prevQualityMode = qualityMode;
_prevGenReactiveMask = autoGenerateReactiveMask;
_prevGenTcrMasks = autoGenerateTransparencyAndComposition;
_prevAutoExposure = enableAutoExposure;
ApplyMipmapBias();
} }
private void OnDisable()
private void DestroyFsrContext()
{ {
// Undo the current mipmap bias offset
float biasOffset = Fsr2.GetMipmapBiasOffset(_renderSize.x, _prevDisplaySize.x);
if (!float.IsNaN(biasOffset))
UndoMipmapBias();
if (_context != null)
{ {
Callbacks.ApplyMipmapBias(-biasOffset);
_context.Destroy();
_context = null;
} }
}
// Restore the camera's original state
_renderCamera.depthTextureMode = _originalDepthTextureMode;
_renderCamera.targetTexture = _originalRenderTarget;
private void CreateCommandBuffers()
{
_dispatchCommandBuffer = new CommandBuffer { name = "FSR2 Dispatch" };
_opaqueInputCommandBuffer = new CommandBuffer { name = "FSR2 Opaque Input" };
_renderCamera.AddCommandBuffer(CameraEvent.BeforeForwardAlpha, _opaqueInputCommandBuffer);
}
if (_copyWithDepthMaterial != null)
{
Destroy(_copyWithDepthMaterial);
_copyWithDepthMaterial = null;
}
private void DestroyCommandBuffers()
{
if (_opaqueInputCommandBuffer != null) if (_opaqueInputCommandBuffer != null)
{ {
_renderCamera.RemoveCommandBuffer(CameraEvent.BeforeForwardAlpha, _opaqueInputCommandBuffer); _renderCamera.RemoveCommandBuffer(CameraEvent.BeforeForwardAlpha, _opaqueInputCommandBuffer);
@ -220,39 +228,49 @@ namespace FidelityFX
_dispatchCommandBuffer.Release(); _dispatchCommandBuffer.Release();
_dispatchCommandBuffer = null; _dispatchCommandBuffer = null;
} }
}
private void ApplyMipmapBias()
{
// Apply a mipmap bias so that textures retain their sharpness
float biasOffset = Fsr2.GetMipmapBiasOffset(_renderSize.x, _displaySize.x);
if (!float.IsNaN(biasOffset) && !float.IsInfinity(biasOffset))
{
Callbacks.ApplyMipmapBias(biasOffset);
_appliedBiasOffset = biasOffset;
}
else
{
_appliedBiasOffset = 0f;
}
}
if (_context != null)
private void UndoMipmapBias()
{
// Undo the current mipmap bias offset
if (!float.IsNaN(_appliedBiasOffset) && !float.IsInfinity(_appliedBiasOffset) && _appliedBiasOffset != 0f)
{ {
_context.Destroy();
_context = null;
Callbacks.ApplyMipmapBias(-_appliedBiasOffset);
_appliedBiasOffset = 0f;
} }
} }
private void Update() private void Update()
{ {
// Monitor for any changes in parameters that require a reset of the FSR2 context
var displaySize = GetDisplaySize(); var displaySize = GetDisplaySize();
if (displaySize.x != _prevDisplaySize.x || displaySize.y != _prevDisplaySize.y || qualityMode != _prevQualityMode)
if (displaySize.x != _prevDisplaySize.x || displaySize.y != _prevDisplaySize.y || qualityMode != _prevQualityMode || enableAutoExposure != _prevAutoExposure)
{ {
// Force all resources to be destroyed and recreated with the new settings // Force all resources to be destroyed and recreated with the new settings
OnDisable(); OnDisable();
OnEnable(); OnEnable();
} }
if ((autoGenerateReactiveMask || autoGenerateTransparencyAndComposition) != (_prevGenReactiveMask || _prevGenTcrMasks))
{
if (autoGenerateReactiveMask || autoGenerateTransparencyAndComposition)
_renderCamera.AddCommandBuffer(CameraEvent.BeforeForwardAlpha, _opaqueInputCommandBuffer);
else
_renderCamera.RemoveCommandBuffer(CameraEvent.BeforeForwardAlpha, _opaqueInputCommandBuffer);
_prevGenReactiveMask = autoGenerateReactiveMask;
_prevGenTcrMasks = autoGenerateTransparencyAndComposition;
}
} }
public void Reset()
public void ResetHistory()
{ {
_reset = true;
// Reset the temporal accumulation, for when the camera cuts to a different location or angle
_resetHistory = true;
} }
private void LateUpdate() private void LateUpdate()
@ -278,21 +296,20 @@ namespace FidelityFX
_opaqueInputCommandBuffer.Blit(BuiltinRenderTextureType.CameraTarget, _colorOpaqueOnly); _opaqueInputCommandBuffer.Blit(BuiltinRenderTextureType.CameraTarget, _colorOpaqueOnly);
} }
// Set up the parameters to auto-generate a reactive mask
if (autoGenerateReactiveMask) if (autoGenerateReactiveMask)
{ {
_genReactiveDescription.ColorOpaqueOnly = _colorOpaqueOnly;
_genReactiveDescription.ColorPreUpscale = null;
_genReactiveDescription.OutReactive = null;
_genReactiveDescription.RenderSize = _renderSize;
_genReactiveDescription.Scale = generateReactiveParameters.scale;
_genReactiveDescription.CutoffThreshold = generateReactiveParameters.cutoffThreshold;
_genReactiveDescription.BinaryValue = generateReactiveParameters.binaryValue;
_genReactiveDescription.Flags = generateReactiveParameters.flags;
SetupAutoReactiveDescription();
} }
SetupDispatchDescription();
ApplyJitter();
}
private void SetupDispatchDescription()
{
// Set up the main FSR2 dispatch parameters // Set up the main FSR2 dispatch parameters
// The input and output textures are left blank here, as they are already being bound elsewhere in this source file
// The input and output textures are left blank here, as they get bound directly through SetGlobalTexture and GetTemporaryRT elsewhere in this source file
_dispatchDescription.Color = null; _dispatchDescription.Color = null;
_dispatchDescription.Depth = null; _dispatchDescription.Depth = null;
_dispatchDescription.MotionVectors = null; _dispatchDescription.MotionVectors = null;
@ -316,8 +333,8 @@ namespace FidelityFX
_dispatchDescription.CameraFar = _renderCamera.farClipPlane; _dispatchDescription.CameraFar = _renderCamera.farClipPlane;
_dispatchDescription.CameraFovAngleVertical = _renderCamera.fieldOfView * Mathf.Deg2Rad; _dispatchDescription.CameraFovAngleVertical = _renderCamera.fieldOfView * Mathf.Deg2Rad;
_dispatchDescription.ViewSpaceToMetersFactor = 1.0f; // 1 unit is 1 meter in Unity _dispatchDescription.ViewSpaceToMetersFactor = 1.0f; // 1 unit is 1 meter in Unity
_dispatchDescription.Reset = _reset;
_reset = false;
_dispatchDescription.Reset = _resetHistory;
_resetHistory = false;
// Set up the parameters for the optional experimental auto-TCR feature // Set up the parameters for the optional experimental auto-TCR feature
_dispatchDescription.EnableAutoReactive = autoGenerateTransparencyAndComposition; _dispatchDescription.EnableAutoReactive = autoGenerateTransparencyAndComposition;
@ -335,7 +352,23 @@ namespace FidelityFX
// Swap the near and far clip plane distances as FSR2 expects this when using inverted depth // Swap the near and far clip plane distances as FSR2 expects this when using inverted depth
(_dispatchDescription.CameraNear, _dispatchDescription.CameraFar) = (_dispatchDescription.CameraFar, _dispatchDescription.CameraNear); (_dispatchDescription.CameraNear, _dispatchDescription.CameraFar) = (_dispatchDescription.CameraFar, _dispatchDescription.CameraNear);
} }
}
private void SetupAutoReactiveDescription()
{
// Set up the parameters to auto-generate a reactive mask
_genReactiveDescription.ColorOpaqueOnly = _colorOpaqueOnly;
_genReactiveDescription.ColorPreUpscale = null;
_genReactiveDescription.OutReactive = null;
_genReactiveDescription.RenderSize = _renderSize;
_genReactiveDescription.Scale = generateReactiveParameters.scale;
_genReactiveDescription.CutoffThreshold = generateReactiveParameters.cutoffThreshold;
_genReactiveDescription.BinaryValue = generateReactiveParameters.binaryValue;
_genReactiveDescription.Flags = generateReactiveParameters.flags;
}
private void ApplyJitter()
{
// Perform custom jittering of the camera's projection matrix according to FSR2's recipe // Perform custom jittering of the camera's projection matrix according to FSR2's recipe
int jitterPhaseCount = Fsr2.GetJitterPhaseCount(_renderSize.x, _displaySize.x); int jitterPhaseCount = Fsr2.GetJitterPhaseCount(_renderSize.x, _displaySize.x);
Fsr2.GetJitterOffset(out float jitterX, out float jitterY, Time.frameCount, jitterPhaseCount); Fsr2.GetJitterOffset(out float jitterX, out float jitterY, Time.frameCount, jitterPhaseCount);
@ -367,13 +400,13 @@ namespace FidelityFX
if (autoGenerateReactiveMask) if (autoGenerateReactiveMask)
{ {
// The auto-reactive mask pass is executed separately from the main FSR2 passes
_dispatchCommandBuffer.GetTemporaryRT(Fsr2ShaderIDs.UavAutoReactive, _renderSize.x, _renderSize.y, 0, default, GraphicsFormat.R8_UNorm, 1, true); _dispatchCommandBuffer.GetTemporaryRT(Fsr2ShaderIDs.UavAutoReactive, _renderSize.x, _renderSize.y, 0, default, GraphicsFormat.R8_UNorm, 1, true);
_context.GenerateReactiveMask(_genReactiveDescription, _dispatchCommandBuffer); _context.GenerateReactiveMask(_genReactiveDescription, _dispatchCommandBuffer);
_dispatchDescription.Reactive = Fsr2ShaderIDs.UavAutoReactive; _dispatchDescription.Reactive = Fsr2ShaderIDs.UavAutoReactive;
} }
// We are rendering to the backbuffer, so we need a temporary render texture for FSR2 to output to
// The backbuffer is not set up to allow random-write access, so we need a temporary render texture for FSR2 to output to
_dispatchCommandBuffer.GetTemporaryRT(Fsr2ShaderIDs.UavUpscaledOutput, _displaySize.x, _displaySize.y, 0, default, GetDefaultFormat(), default, 1, true); _dispatchCommandBuffer.GetTemporaryRT(Fsr2ShaderIDs.UavUpscaledOutput, _displaySize.x, _displaySize.y, 0, default, GetDefaultFormat(), default, 1, true);
_context.Dispatch(_dispatchDescription, _dispatchCommandBuffer); _context.Dispatch(_dispatchDescription, _dispatchCommandBuffer);
@ -394,11 +427,7 @@ namespace FidelityFX
} }
_dispatchCommandBuffer.ReleaseTemporaryRT(Fsr2ShaderIDs.UavUpscaledOutput); _dispatchCommandBuffer.ReleaseTemporaryRT(Fsr2ShaderIDs.UavUpscaledOutput);
if (autoGenerateReactiveMask)
{
_dispatchCommandBuffer.ReleaseTemporaryRT(Fsr2ShaderIDs.UavAutoReactive);
}
_dispatchCommandBuffer.ReleaseTemporaryRT(Fsr2ShaderIDs.UavAutoReactive);
Graphics.ExecuteCommandBuffer(_dispatchCommandBuffer); Graphics.ExecuteCommandBuffer(_dispatchCommandBuffer);

Loading…
Cancel
Save