Compare commits

...

26 Commits
master ... srp

Author SHA1 Message Date
Nico de Poel d6ab273f8b Reworked SPD atomic counter to use a compute buffer (which has atomic operations available on Metal) instead of a one-pixel read/write texture. 4 weeks ago
Nico de Poel 931de52728 Replaced custom texture type macros with the appropriate TextureXR versions 4 weeks ago
Nico de Poel cb6efd6c74 Use Core SRP shader includes to define Texture XR macros, replacing the old ad-hoc solution 4 weeks ago
Nico de Poel d153e59498 Fixed a number of shader compiler warnings from using a more modern compiler 4 weeks ago
Nico de Poel ddd3e57daf Added Core SRP dependency, updated some code to Unity 6.7 standards, and updated copyright year for modified files. 4 weeks ago
Nico de Poel 89f8f0d71f FSR 2.3.4/3.1.5 update: Fix for possible negative rcas output. 1 year ago
Nico de Poel c31c462f7f Fixed Metal not getting compiled with texture array support, which broke HDRP support. 1 year ago
Nico de Poel 419c82668a Updated package version number 2 years ago
Nico de Poel ef8a19887b (FSR3) Clear new locks buffer ahead of the frame instead of at the end of the Accumulate pass. This makes more sense with NewLocks being an aliasable (temp RT) resource, and it avoids reading and writing to the same texture in the Accumulate pass. 2 years ago
Nico de Poel 5bb38aa76d (FSR2) Clear new locks buffer ahead of the frame instead of at the end of the Accumulate pass. This makes more sense with NewLocks being an aliasable (temp RT) resource, and it avoids reading and writing to the same texture in the Accumulate pass. 2 years ago
Nico de Poel fddefa8165 Changed auto-exposure texture into a double buffered resource (FSR3), to avoid issues with reading and writing to the same texture in the compute luminance pass. This allows fast exposure convergence without issues on OpenGL and Metal. 2 years ago
Nico de Poel 97af0d9d8a Changed auto-exposure texture into a double buffered resource (FSR2), to avoid issues with reading and writing to the same texture in the compute luminance pass. This allows fast exposure convergence without issues on OpenGL and Metal. 2 years ago
Nico de Poel 834abd0f0e Ported changes from FidelityFX 1.1.4 2 years ago
Nico de Poel a7d2635477 Updated FSR package version number to 1.0.1 2 years ago
Nico de Poel cb42842275 Reorganized profiler sampling to work around issues in non-development builds on Unity 2020.x 2 years ago
Nico de Poel c82e131ee8 Backported auto-exposure reset value from FSR3 as part of the OpenGL black screen fix 2 years ago
Nico de Poel a1a037a8ec Ported auto-exposure initialization fix from FSR 3.1 over to FSR 2.2. Fixes black screen flashes on history reset in OpenGL on Nvidia GPUs. 2 years ago
Nico de Poel a063074772 Optimized multi-compile keywords based on which are actually used in each pass 2 years ago
Nico de Poel be76c9a138 Fixed FSR2 auto-exposure issue with OpenGL Core on Nvidia GPUs, most likely due to reading uninitialized texture data. 2 years ago
Nico de Poel b014f056ed Use a constant to determine the highest mip level that SPD can use on OpenGL Core, and ensure storing the pyramid values use the correct mip level 2 years ago
Nico de Poel f8f5f9077d Reduced number of SPD mip levels used by luma pyramid and shading change pyramid passes by one for OpenGL Core, to ensure they stay within the limit of 8 UAV bindings. 2 years ago
Nico de Poel 3dd791eb84 Changed velocity factor integration in a way that isn't stupid 2 years ago
Nico de Poel c4f82f7da3 Disabled Xbox Series-specific optimizations, as I have no way to test those right now and most likely they won't matter in Unity anyway 2 years ago
Nico de Poel 922e89f9fe Updated shaders to FSR 3.1.3: 2 years ago
Nico de Poel f5ad170590 Ported velocity factor and exposure clear value from FSR 3.1.1 code 2 years ago
Nico de Poel 1d891ad702 Updated shaders to FSR 2.3.2 and FSR 3.1.1 from FidelityFX SDK 1.1.1 2 years ago
  1. 7
      Runtime/FSR2/Fsr2.cs
  2. 14
      Runtime/FSR2/Fsr2Context.cs
  3. 33
      Runtime/FSR2/Fsr2Pass.cs
  4. 28
      Runtime/FSR2/Fsr2Resources.cs
  5. 1
      Runtime/FSR2/Fsr2ShaderIDs.cs
  6. 18
      Runtime/FSR3/Fsr3Upscaler.cs
  7. 33
      Runtime/FSR3/Fsr3UpscalerContext.cs
  8. 39
      Runtime/FSR3/Fsr3UpscalerPass.cs
  9. 23
      Runtime/FSR3/Fsr3UpscalerResources.cs
  10. 4
      Runtime/FidelityFX.FSR.asmdef
  11. 3
      Shaders/ffx_fsr2_accumulate_pass.compute
  12. 5
      Shaders/ffx_fsr2_autogen_reactive_pass.compute
  13. 5
      Shaders/ffx_fsr2_compute_luminance_pyramid_pass.compute
  14. 2
      Shaders/ffx_fsr2_depth_clip_pass.compute
  15. 4
      Shaders/ffx_fsr2_lock_pass.compute
  16. 6
      Shaders/ffx_fsr2_rcas_pass.compute
  17. 2
      Shaders/ffx_fsr2_reconstruct_previous_depth_pass.compute
  18. 4
      Shaders/ffx_fsr2_tcr_autogen_pass.compute
  19. 5
      Shaders/ffx_fsr3upscaler_accumulate_pass.compute
  20. 4
      Shaders/ffx_fsr3upscaler_autogen_reactive_pass.compute
  21. 4
      Shaders/ffx_fsr3upscaler_debug_view_pass.compute
  22. 4
      Shaders/ffx_fsr3upscaler_luma_instability_pass.compute
  23. 4
      Shaders/ffx_fsr3upscaler_luma_pyramid_pass.compute
  24. 4
      Shaders/ffx_fsr3upscaler_prepare_inputs_pass.compute
  25. 4
      Shaders/ffx_fsr3upscaler_prepare_reactivity_pass.compute
  26. 4
      Shaders/ffx_fsr3upscaler_rcas_pass.compute
  27. 4
      Shaders/ffx_fsr3upscaler_shading_change_pass.compute
  28. 4
      Shaders/ffx_fsr3upscaler_shading_change_pyramid_pass.compute
  29. 4
      Shaders/ffx_fsr3upscaler_tcr_autogen_pass.compute
  30. 51
      Shaders/ffx_fsr_unity_common.cginc
  31. 8
      Shaders/shaders/ffx_core_gpu_common.h
  32. 8
      Shaders/shaders/ffx_core_gpu_common_half.h
  33. 4
      Shaders/shaders/ffx_fsr2_accumulate_pass.hlsl
  34. 1
      Shaders/shaders/ffx_fsr2_compute_luminance_pyramid_pass.hlsl
  35. 2
      Shaders/shaders/ffx_fsr3upscaler_accumulate_pass.hlsl
  36. 5
      Shaders/shaders/ffx_fsr3upscaler_luma_pyramid_pass.hlsl
  37. 2
      Shaders/shaders/ffx_fsr3upscaler_shading_change_pyramid_pass.hlsl
  38. 23
      Shaders/shaders/fsr1/ffx_fsr1.h
  39. 6
      Shaders/shaders/fsr2/ffx_fsr2_accumulate.h
  40. 87
      Shaders/shaders/fsr2/ffx_fsr2_callbacks_hlsl.h
  41. 28
      Shaders/shaders/fsr2/ffx_fsr2_common.h
  42. 3
      Shaders/shaders/fsr2/ffx_fsr2_compute_luminance_pyramid.h
  43. 75
      Shaders/shaders/fsr2/ffx_fsr2_rcas.h
  44. 2
      Shaders/shaders/fsr2/ffx_fsr2_reproject.h
  45. 66
      Shaders/shaders/fsr2/ffx_fsr2_sample.h
  46. 283
      Shaders/shaders/fsr2/ffx_fsr2_upsample.h
  47. 31
      Shaders/shaders/fsr3upscaler/ffx_fsr3upscaler_accumulate.h
  48. 106
      Shaders/shaders/fsr3upscaler/ffx_fsr3upscaler_callbacks_hlsl.h
  49. 4
      Shaders/shaders/fsr3upscaler/ffx_fsr3upscaler_common.h
  50. 14
      Shaders/shaders/fsr3upscaler/ffx_fsr3upscaler_luma_pyramid.h
  51. 27
      Shaders/shaders/fsr3upscaler/ffx_fsr3upscaler_prepare_reactivity.h
  52. 77
      Shaders/shaders/fsr3upscaler/ffx_fsr3upscaler_rcas.h
  53. 15
      Shaders/shaders/fsr3upscaler/ffx_fsr3upscaler_reproject.h
  54. 27
      Shaders/shaders/fsr3upscaler/ffx_fsr3upscaler_sample.h
  55. 8
      Shaders/shaders/fsr3upscaler/ffx_fsr3upscaler_shading_change_pyramid.h
  56. 10
      Shaders/shaders/fsr3upscaler/ffx_fsr3upscaler_tcr_autogen.h
  57. 470
      Shaders/shaders/fsr3upscaler/ffx_fsr3upscaler_upsample.h
  58. 2
      package.json

7
Runtime/FSR2/Fsr2.cs

@ -1,4 +1,4 @@
// Copyright (c) 2024 Nico de Poel
// Copyright (c) 2026 Nico de Poel
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@ -40,9 +40,8 @@ namespace FidelityFX.FSR2
else
flags &= ~InitializationFlags.EnableDepthInverted;
#if UNITY_EDITOR || DEVELOPMENT_BUILD
flags |= InitializationFlags.EnableDebugChecking;
#endif
if (Debug.isDebugBuild)
flags |= InitializationFlags.EnableDebugChecking;
Debug.Log($"Setting up FSR2 with render size: {maxRenderSize.x}x{maxRenderSize.y}, display size: {displaySize.x}x{displaySize.y}, flags: {flags}");

14
Runtime/FSR2/Fsr2Context.cs

@ -163,7 +163,7 @@ namespace FidelityFX.FSR2
// If auto exposure is enabled use the auto exposure SRV, otherwise what the app sends
if ((_contextDescription.Flags & Fsr2.InitializationFlags.EnableAutoExposure) != 0)
dispatchParams.Exposure = new ResourceView(_resources.AutoExposure);
dispatchParams.Exposure = new ResourceView(_resources.AutoExposure[frameIndex]);
else if (!dispatchParams.Exposure.IsValid)
dispatchParams.Exposure = new ResourceView(_resources.DefaultExposure);
@ -211,19 +211,21 @@ namespace FidelityFX.FSR2
commandBuffer.ClearRenderTarget(false, true, Color.clear);
// Auto exposure always used to track luma changes in locking logic
commandBuffer.SetRenderTarget(_resources.AutoExposure);
commandBuffer.SetRenderTarget(_resources.AutoExposure[frameIndex ^ 1]);
commandBuffer.ClearRenderTarget(false, true, new Color(0f, 1e8f, 0f, 0f));
// Reset atomic counter to 0
commandBuffer.SetRenderTarget(_resources.SpdAtomicCounter);
commandBuffer.ClearRenderTarget(false, true, Color.clear);
}
// Reset atomic counter to 0
commandBuffer.SetBufferCounterValue(_resources.SpdAtomicCounter, 0);
// FSR3: need to clear here since we need the content of this surface for frame interpolation, so clearing in the lock pass is not an option
bool depthInverted = (_contextDescription.Flags & Fsr2.InitializationFlags.EnableDepthInverted) == Fsr2.InitializationFlags.EnableDepthInverted;
commandBuffer.SetRenderTarget(Fsr2ShaderIDs.UavReconstructedPrevNearestDepth);
commandBuffer.ClearRenderTarget(false, true, depthInverted ? Color.clear : Color.white);
commandBuffer.SetRenderTarget(Fsr2ShaderIDs.UavNewLocks);
commandBuffer.ClearRenderTarget(false, true, Color.clear);
// Auto exposure
SetupSpdConstants(dispatchParams, out var dispatchThreadGroupCount);

33
Runtime/FSR2/Fsr2Pass.cs

@ -19,6 +19,7 @@
// THE SOFTWARE.
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using UnityEngine;
using UnityEngine.Profiling;
@ -42,7 +43,7 @@ namespace FidelityFX.FSR2
protected ComputeShader ComputeShader;
protected int KernelIndex;
protected CustomSampler Sampler;
private CustomSampler _sampler;
protected Fsr2Pass(Fsr2.ContextDescription contextDescription, Fsr2Resources resources, ComputeBuffer constants)
{
@ -57,9 +58,9 @@ namespace FidelityFX.FSR2
public void ScheduleDispatch(CommandBuffer commandBuffer, Fsr2.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY)
{
commandBuffer.BeginSample(Sampler);
BeginSample(commandBuffer);
DoScheduleDispatch(commandBuffer, dispatchParams, frameIndex, dispatchX, dispatchY);
commandBuffer.EndSample(Sampler);
EndSample(commandBuffer);
}
protected abstract void DoScheduleDispatch(CommandBuffer commandBuffer, Fsr2.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY);
@ -78,7 +79,7 @@ namespace FidelityFX.FSR2
ComputeShader = shader;
KernelIndex = ComputeShader.FindKernel("CS");
Sampler = CustomSampler.Create(passName);
_sampler = CustomSampler.Create(passName);
bool useLut = false;
#if UNITY_2022_1_OR_NEWER // This will also work in 2020.3.43+ and 2021.3.14+
@ -96,6 +97,18 @@ namespace FidelityFX.FSR2
if (useLut) ComputeShader.EnableKeyword("FFX_FSR2_OPTION_REPROJECT_USE_LANCZOS_TYPE");
if ((flags & Fsr2.InitializationFlags.EnableFP16Usage) != 0) ComputeShader.EnableKeyword("FFX_HALF");
}
[Conditional("ENABLE_PROFILER")]
protected void BeginSample(CommandBuffer cmd)
{
cmd.BeginSample(_sampler);
}
[Conditional("ENABLE_PROFILER")]
protected void EndSample(CommandBuffer cmd)
{
cmd.EndSample(_sampler);
}
}
internal class Fsr2ComputeLuminancePyramidPass : Fsr2Pass
@ -114,11 +127,12 @@ namespace FidelityFX.FSR2
{
ref var color = ref dispatchParams.Color;
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputColor, color.RenderTarget, color.MipLevel, color.SubElement);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvAutoExposure, Resources.AutoExposure[frameIndex ^ 1]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavSpdAtomicCount, Resources.SpdAtomicCounter);
commandBuffer.SetComputeBufferParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavSpdAtomicCount, Resources.SpdAtomicCounter);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavExposureMipLumaChange, Resources.SceneLuminance, ShadingChangeMipLevel);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavExposureMip5, Resources.SceneLuminance, 5);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavAutoExposure, Resources.AutoExposure);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavAutoExposure, Resources.AutoExposure[frameIndex]);
commandBuffer.SetComputeConstantBufferParam(ComputeShader, Fsr2ShaderIDs.CbFsr2, Constants, 0, Marshal.SizeOf<Fsr2.UpscalerConstants>());
commandBuffer.SetComputeConstantBufferParam(ComputeShader, Fsr2ShaderIDs.CbSpd, _spdConstants, 0, Marshal.SizeOf<Fsr2.SpdConstants>());
@ -258,8 +272,9 @@ namespace FidelityFX.FSR2
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvLanczosLut, Resources.LanczosLut);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvUpscaleMaximumBiasLut, Resources.MaximumBiasLut);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvSceneLuminanceMips, Resources.SceneLuminance);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvAutoExposure, Resources.AutoExposure);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvAutoExposure, Resources.AutoExposure[frameIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvLumaHistory, Resources.LumaHistory[frameIndex ^ 1]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvNewLocks, Fsr2ShaderIDs.UavNewLocks);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavInternalUpscaled, Resources.InternalUpscaled[frameIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavLockStatus, Resources.LockStatus[frameIndex]);
@ -320,7 +335,7 @@ namespace FidelityFX.FSR2
public void ScheduleDispatch(CommandBuffer commandBuffer, Fsr2.GenerateReactiveDescription dispatchParams, int dispatchX, int dispatchY)
{
commandBuffer.BeginSample(Sampler);
BeginSample(commandBuffer);
ref var opaqueOnly = ref dispatchParams.ColorOpaqueOnly;
ref var color = ref dispatchParams.ColorPreUpscale;
@ -334,7 +349,7 @@ namespace FidelityFX.FSR2
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, 1);
commandBuffer.EndSample(Sampler);
EndSample(commandBuffer);
}
}

28
Runtime/FSR2/Fsr2Resources.cs

@ -35,11 +35,11 @@ namespace FidelityFX.FSR2
public Texture2D DefaultReactive;
public Texture2D LanczosLut;
public Texture2D MaximumBiasLut;
public RenderTexture SpdAtomicCounter;
public RenderTexture AutoExposure;
public ComputeBuffer SpdAtomicCounter;
public RenderTexture SceneLuminance;
public RenderTexture AutoReactive;
public RenderTexture AutoComposition;
public readonly RenderTexture[] AutoExposure = new RenderTexture[2];
public readonly RenderTexture[] DilatedMotionVectors = new RenderTexture[2];
public readonly RenderTexture[] LockStatus = new RenderTexture[2];
public readonly RenderTexture[] InternalUpscaled = new RenderTexture[2];
@ -87,13 +87,8 @@ namespace FidelityFX.FSR2
DefaultReactive.Apply();
// Resource FSR2_SpdAtomicCounter: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R32_UINT, FFX_RESOURCE_FLAGS_ALIASABLE
// Despite what the original FSR2 codebase says, this resource really isn't aliasable. Resetting this counter to 0 every frame breaks auto-exposure on MacOS Metal.
SpdAtomicCounter = new RenderTexture(1, 1, 0, GraphicsFormat.R32_UInt) { name = "FSR2_SpdAtomicCounter", enableRandomWrite = true };
SpdAtomicCounter.Create();
// Resource FSR2_AutoExposure: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R32G32_FLOAT, FFX_RESOURCE_FLAGS_NONE
AutoExposure = new RenderTexture(1, 1, 0, GraphicsFormat.R32G32_SFloat) { name = "FSR2_AutoExposure", enableRandomWrite = true };
AutoExposure.Create();
// Despite what the original FSR2 codebase says, this resource really isn't aliasable.
SpdAtomicCounter = new ComputeBuffer(1, sizeof(uint), ComputeBufferType.Counter, ComputeBufferMode.Dynamic);
// Resource FSR2_ExposureMips: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R16_FLOAT, FFX_RESOURCE_FLAGS_ALIASABLE
// This is a rather special case: it's an aliasable resource, but because we require a mipmap chain and bind specific mip levels per shader, we can't easily use temporary RTs for this.
@ -102,6 +97,9 @@ namespace FidelityFX.FSR2
SceneLuminance = new RenderTexture(w, h, 0, GraphicsFormat.R16_SFloat, mipCount) { name = "FSR2_ExposureMips", enableRandomWrite = true, useMipMap = true, autoGenerateMips = false };
SceneLuminance.Create();
// Resource FSR2_AutoExposure: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R32G32_FLOAT, FFX_RESOURCE_FLAGS_NONE
CreateDoubleBufferedResource(AutoExposure, "FSR2_AutoExposure", Vector2Int.one, GraphicsFormat.R32G32_SFloat);
// Resources FSR2_InternalDilatedVelocity1/2: FFX_RESOURCE_USAGE_RENDERTARGET | FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R16G16_FLOAT, FFX_RESOURCE_FLAGS_NONE
CreateDoubleBufferedResource(DilatedMotionVectors, "FSR2_InternalDilatedVelocity", contextDescription.MaxRenderSize, GraphicsFormat.R16G16_SFloat);
@ -186,12 +184,13 @@ namespace FidelityFX.FSR2
DestroyResource(InternalUpscaled);
DestroyResource(LockStatus);
DestroyResource(DilatedMotionVectors);
DestroyResource(AutoExposure);
DestroyResource(ref SceneLuminance);
DestroyResource(ref AutoExposure);
DestroyResource(ref DefaultReactive);
DestroyResource(ref DefaultExposure);
DestroyResource(ref MaximumBiasLut);
DestroyResource(ref LanczosLut);
DestroyResource(ref SpdAtomicCounter);
}
public void DestroyTcrAutogenResources()
@ -227,6 +226,15 @@ namespace FidelityFX.FSR2
resource = null;
}
private static void DestroyResource(ref ComputeBuffer resource)
{
if (resource == null)
return;
resource.Release();
resource = null;
}
private static void DestroyResource(RenderTexture[] resource)
{
for (int i = 0; i < resource.Length; ++i)

1
Runtime/FSR2/Fsr2ShaderIDs.cs

@ -39,6 +39,7 @@ namespace FidelityFX.FSR2
public static readonly int SrvDilatedDepth = Shader.PropertyToID("r_dilatedDepth");
public static readonly int SrvInternalUpscaled = Shader.PropertyToID("r_internal_upscaled_color");
public static readonly int SrvLockStatus = Shader.PropertyToID("r_lock_status");
public static readonly int SrvNewLocks = Shader.PropertyToID("r_new_locks");
public static readonly int SrvLockInputLuma = Shader.PropertyToID("r_lock_input_luma");
public static readonly int SrvPreparedInputColor = Shader.PropertyToID("r_prepared_input_color");
public static readonly int SrvLumaHistory = Shader.PropertyToID("r_luma_history");

18
Runtime/FSR3/Fsr3Upscaler.cs

@ -1,4 +1,4 @@
// Copyright (c) 2024 Nico de Poel
// Copyright (c) 2026 Nico de Poel
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@ -40,9 +40,8 @@ namespace FidelityFX.FSR3
else
flags &= ~InitializationFlags.EnableDepthInverted;
#if UNITY_EDITOR || DEVELOPMENT_BUILD
flags |= InitializationFlags.EnableDebugChecking;
#endif
if (Debug.isDebugBuild)
flags |= InitializationFlags.EnableDebugChecking;
Debug.Log($"Setting up FSR3 Upscaler with render size: {maxRenderSize.x}x{maxRenderSize.y}, display size: {displaySize.x}x{displaySize.y}, flags: {flags}");
@ -200,6 +199,11 @@ namespace FidelityFX.FSR3
public float CameraFar;
public float CameraFovAngleVertical;
public float ViewSpaceToMetersFactor;
public float VelocityFactor = 1.0f;
public float ReactivenessScale = 1.0f;
public float ShadingChangeScale = 1.0f;
public float AccumulationAddedPerFrame = 1.0f / 3.0f;
public float MinDisocclusionAccumulation = -1.0f / 3.0f;
public DispatchFlags Flags;
public bool UseTextureArrays; // Enable texture array bindings, primarily used for HDRP and XR
@ -265,6 +269,12 @@ namespace FidelityFX.FSR3
public float deltaPreExposure;
public float viewSpaceToMetersFactor;
public float frameIndex;
public float velocityFactor;
public float reactivenessScale;
public float shadingChangeScale;
public float accumulationAddedPerFrame;
public float minDisocclusionAccumulation;
}
[Serializable, StructLayout(LayoutKind.Sequential)]

33
Runtime/FSR3/Fsr3UpscalerContext.cs

@ -48,9 +48,7 @@ namespace FidelityFX.FSR3
private Fsr3UpscalerPass _sharpenPass;
private Fsr3UpscalerPass _generateReactivePass;
private Fsr3UpscalerPass _tcrAutogeneratePass;
#if UNITY_EDITOR || DEVELOPMENT_BUILD
private Fsr3UpscalerPass _debugViewPass;
#endif
private readonly Fsr3UpscalerResources _resources = new Fsr3UpscalerResources();
@ -96,6 +94,11 @@ namespace FidelityFX.FSR3
_resourceFrameIndex = 0;
UpscalerConsts.maxUpscaleSize = _contextDescription.MaxUpscaleSize;
UpscalerConsts.velocityFactor = 1.0f;
UpscalerConsts.reactivenessScale = 1.0f;
UpscalerConsts.shadingChangeScale = 1.0f;
UpscalerConsts.accumulationAddedPerFrame = 1.0f / 3.0f;
UpscalerConsts.minDisocclusionAccumulation = -1.0f / 3.0f;
_resources.Create(_contextDescription);
CreatePasses();
@ -113,16 +116,12 @@ namespace FidelityFX.FSR3
_sharpenPass = new Fsr3UpscalerSharpenPass(_contextDescription, _resources, _upscalerConstantsBuffer, _rcasConstantsBuffer);
_generateReactivePass = new Fsr3UpscalerGenerateReactivePass(_contextDescription, _resources, _generateReactiveConstantsBuffer);
_tcrAutogeneratePass = new Fsr3UpscalerTcrAutogeneratePass(_contextDescription, _resources, _upscalerConstantsBuffer, _tcrAutogenerateConstantsBuffer);
#if UNITY_EDITOR || DEVELOPMENT_BUILD
_debugViewPass = new Fsr3UpscalerDebugViewPass(_contextDescription, _resources, _upscalerConstantsBuffer);
#endif
}
public void Destroy()
{
#if UNITY_EDITOR || DEVELOPMENT_BUILD
DestroyPass(ref _debugViewPass);
#endif
DestroyPass(ref _tcrAutogeneratePass);
DestroyPass(ref _generateReactivePass);
DestroyPass(ref _lumaPyramidPass);
@ -184,7 +183,7 @@ namespace FidelityFX.FSR3
// If auto exposure is enabled use the auto exposure SRV, otherwise what the app sends
if ((_contextDescription.Flags & Fsr3Upscaler.InitializationFlags.EnableAutoExposure) != 0)
dispatchParams.Exposure = new ResourceView(_resources.FrameInfo);
dispatchParams.Exposure = new ResourceView(_resources.FrameInfo[frameIndex]);
else if (!dispatchParams.Exposure.IsValid)
dispatchParams.Exposure = new ResourceView(_resources.DefaultExposure);
@ -231,19 +230,21 @@ namespace FidelityFX.FSR3
commandBuffer.ClearRenderTarget(false, true, Color.clear);
// Auto exposure always used to track luma changes in locking logic
commandBuffer.SetRenderTarget(_resources.FrameInfo);
commandBuffer.SetRenderTarget(_resources.FrameInfo[frameIndex ^ 1]);
commandBuffer.ClearRenderTarget(false, true, new Color(0f, 1e8f, 0f, 0f));
// Reset atomic counter to 0
commandBuffer.SetRenderTarget(_resources.SpdAtomicCounter);
commandBuffer.ClearRenderTarget(false, true, Color.clear);
}
// Reset atomic counter to 0
commandBuffer.SetBufferCounterValue(_resources.SpdAtomicCounter, 0);
// FSR3: need to clear here since we need the content of this surface for frame interpolation, so clearing in the lock pass is not an option
bool depthInverted = (_contextDescription.Flags & Fsr3Upscaler.InitializationFlags.EnableDepthInverted) == Fsr3Upscaler.InitializationFlags.EnableDepthInverted;
commandBuffer.SetRenderTarget(_resources.ReconstructedPrevNearestDepth);
commandBuffer.ClearRenderTarget(false, true, depthInverted ? Color.clear : Color.white);
commandBuffer.SetRenderTarget(Fsr3ShaderIDs.UavNewLocks);
commandBuffer.ClearRenderTarget(false, true, Color.clear);
// Auto exposure
SetupSpdConstants(dispatchParams, out var dispatchThreadGroupCount);
@ -281,12 +282,10 @@ namespace FidelityFX.FSR3
_sharpenPass.ScheduleDispatch(commandBuffer, dispatchParams, frameIndex, threadGroupsX, threadGroupsY);
}
#if UNITY_EDITOR || DEVELOPMENT_BUILD
if ((dispatchParams.Flags & Fsr3Upscaler.DispatchFlags.DrawDebugView) != 0)
{
_debugViewPass.ScheduleDispatch(commandBuffer, dispatchParams, frameIndex, dispatchDstX, dispatchDstY);
}
#endif
_resourceFrameIndex = (_resourceFrameIndex + 1) % MaxQueuedFrames;
@ -407,6 +406,12 @@ namespace FidelityFX.FSR3
constants.frameIndex = 0;
else
constants.frameIndex += 1.0f;
constants.velocityFactor = dispatchParams.VelocityFactor;
constants.reactivenessScale = dispatchParams.ReactivenessScale;
constants.shadingChangeScale = dispatchParams.ShadingChangeScale;
constants.accumulationAddedPerFrame = dispatchParams.AccumulationAddedPerFrame;
constants.minDisocclusionAccumulation = dispatchParams.MinDisocclusionAccumulation;
}
private Vector4 SetupDeviceDepthToViewSpaceDepthParams(Fsr3Upscaler.DispatchDescription dispatchParams)

39
Runtime/FSR3/Fsr3UpscalerPass.cs

@ -1,4 +1,4 @@
// Copyright (c) 2024 Nico de Poel
// Copyright (c) 2026 Nico de Poel
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@ -19,6 +19,7 @@
// THE SOFTWARE.
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using UnityEngine;
using UnityEngine.Profiling;
@ -40,7 +41,7 @@ namespace FidelityFX.FSR3
protected ComputeShader ComputeShader;
protected int KernelIndex;
protected CustomSampler Sampler;
private CustomSampler _sampler;
protected Fsr3UpscalerPass(Fsr3Upscaler.ContextDescription contextDescription, Fsr3UpscalerResources resources, ComputeBuffer constants)
{
@ -55,9 +56,9 @@ namespace FidelityFX.FSR3
public void ScheduleDispatch(CommandBuffer commandBuffer, Fsr3Upscaler.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY)
{
commandBuffer.BeginSample(Sampler);
BeginSample(commandBuffer);
DoScheduleDispatch(commandBuffer, dispatchParams, frameIndex, dispatchX, dispatchY);
commandBuffer.EndSample(Sampler);
EndSample(commandBuffer);
}
protected abstract void DoScheduleDispatch(CommandBuffer commandBuffer, Fsr3Upscaler.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY);
@ -76,7 +77,7 @@ namespace FidelityFX.FSR3
ComputeShader = shader;
KernelIndex = ComputeShader.FindKernel("CS");
Sampler = CustomSampler.Create(passName);
_sampler = CustomSampler.Create(passName);
bool useLut = false;
#if UNITY_2022_1_OR_NEWER // This will also work in 2020.3.43+ and 2021.3.14+
@ -94,6 +95,18 @@ namespace FidelityFX.FSR3
if (useLut) ComputeShader.EnableKeyword("FFX_FSR3UPSCALER_OPTION_REPROJECT_USE_LANCZOS_TYPE");
if ((flags & Fsr3Upscaler.InitializationFlags.EnableFP16Usage) != 0) ComputeShader.EnableKeyword("FFX_HALF");
}
[Conditional("ENABLE_PROFILER")]
protected void BeginSample(CommandBuffer cmd)
{
cmd.BeginSample(_sampler);
}
[Conditional("ENABLE_PROFILER")]
protected void EndSample(CommandBuffer cmd)
{
cmd.EndSample(_sampler);
}
}
internal class Fsr3UpscalerPrepareInputsPass : Fsr3UpscalerPass
@ -142,9 +155,10 @@ namespace FidelityFX.FSR3
{
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvCurrentLuma, Resources.Luma[frameIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvFarthestDepth, Fsr3ShaderIDs.UavIntermediate);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvFrameInfo, Resources.FrameInfo[frameIndex ^ 1]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavSpdAtomicCount, Resources.SpdAtomicCounter);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavFrameInfo, Resources.FrameInfo);
commandBuffer.SetComputeBufferParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavSpdAtomicCount, Resources.SpdAtomicCounter);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavFrameInfo, Resources.FrameInfo[frameIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavSpdMip0, Resources.SpdMips, 0);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavSpdMip1, Resources.SpdMips, 1);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavSpdMip2, Resources.SpdMips, 2);
@ -180,7 +194,7 @@ namespace FidelityFX.FSR3
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvDilatedMotionVectors, Resources.DilatedVelocity);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvInputExposure, exposure.RenderTarget, exposure.MipLevel, exposure.SubElement);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavSpdAtomicCount, Resources.SpdAtomicCounter);
commandBuffer.SetComputeBufferParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavSpdAtomicCount, Resources.SpdAtomicCounter);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavSpdMip0, Resources.SpdMips, 0);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavSpdMip1, Resources.SpdMips, 1);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavSpdMip2, Resources.SpdMips, 2);
@ -260,7 +274,7 @@ namespace FidelityFX.FSR3
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvInputExposure, exposure.RenderTarget, exposure.MipLevel, exposure.SubElement);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvDilatedReactiveMasks, Fsr3ShaderIDs.UavDilatedReactiveMasks);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvDilatedMotionVectors, Resources.DilatedVelocity);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvFrameInfo, Resources.FrameInfo);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvFrameInfo, Resources.FrameInfo[frameIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvLumaHistory, Resources.LumaHistory[frameIndex ^ 1]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvFarthestDepthMip1, Fsr3ShaderIDs.UavFarthestDepthMip1);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvCurrentLuma, Resources.Luma[frameIndex]);
@ -328,6 +342,7 @@ namespace FidelityFX.FSR3
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvCurrentLuma, Resources.Luma[frameIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvLumaInstability, Fsr3ShaderIDs.UavIntermediate);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvInputColor, color.RenderTarget, color.MipLevel, color.SubElement);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvNewLocks, Fsr3ShaderIDs.UavNewLocks);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavInternalUpscaled, Resources.InternalUpscaled[frameIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavUpscaledOutput, output.RenderTarget, output.MipLevel, output.SubElement);
@ -384,7 +399,7 @@ namespace FidelityFX.FSR3
public void ScheduleDispatch(CommandBuffer commandBuffer, Fsr3Upscaler.GenerateReactiveDescription dispatchParams, int dispatchX, int dispatchY)
{
commandBuffer.BeginSample(Sampler);
BeginSample(commandBuffer);
ref var opaqueOnly = ref dispatchParams.ColorOpaqueOnly;
ref var color = ref dispatchParams.ColorPreUpscale;
@ -398,7 +413,7 @@ namespace FidelityFX.FSR3
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, 1);
commandBuffer.EndSample(Sampler);
EndSample(commandBuffer);
}
}
@ -442,7 +457,6 @@ namespace FidelityFX.FSR3
}
}
#if UNITY_EDITOR || DEVELOPMENT_BUILD
internal class Fsr3UpscalerDebugViewPass : Fsr3UpscalerPass
{
public Fsr3UpscalerDebugViewPass(Fsr3Upscaler.ContextDescription contextDescription, Fsr3UpscalerResources resources, ComputeBuffer constants)
@ -468,5 +482,4 @@ namespace FidelityFX.FSR3
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, 1);
}
}
#endif
}

23
Runtime/FSR3/Fsr3UpscalerResources.cs

@ -35,15 +35,15 @@ namespace FidelityFX.FSR3
public Texture2D DefaultExposure;
public Texture2D DefaultReactive;
public RenderTexture SpdAtomicCounter;
public ComputeBuffer SpdAtomicCounter;
public RenderTexture SpdMips;
public RenderTexture DilatedVelocity;
public RenderTexture DilatedDepth;
public RenderTexture ReconstructedPrevNearestDepth;
public RenderTexture FrameInfo;
public RenderTexture AutoReactive;
public RenderTexture AutoComposition;
public readonly RenderTexture[] FrameInfo = new RenderTexture[2];
public readonly RenderTexture[] Accumulation = new RenderTexture[2];
public readonly RenderTexture[] Luma = new RenderTexture[2];
public readonly RenderTexture[] InternalUpscaled = new RenderTexture[2];
@ -83,9 +83,8 @@ namespace FidelityFX.FSR3
DefaultExposure.Apply();
// Resource FSR3UPSCALER_SpdAtomicCounter: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R32_UINT, FFX_RESOURCE_FLAGS_ALIASABLE
// Despite what the original FSR3 codebase says, this resource really isn't aliasable. Resetting this counter to 0 every frame breaks auto-exposure on MacOS Metal.
SpdAtomicCounter = new RenderTexture(1, 1, 0, GraphicsFormat.R32_UInt) { name = "FSR3UPSCALER_SpdAtomicCounter", enableRandomWrite = true };
SpdAtomicCounter.Create();
// Despite what the original FSR3 codebase says, this resource really isn't aliasable.
SpdAtomicCounter = new ComputeBuffer(1, sizeof(uint), ComputeBufferType.Counter, ComputeBufferMode.Dynamic);
// Resource FSR3UPSCALER_SpdMips: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R16G16_FLOAT, FFX_RESOURCE_FLAGS_ALIASABLE
// This is a rather special case: it's an aliasable resource, but because we require a mipmap chain and bind specific mip levels per shader, we can't easily use temporary RTs for this.
@ -106,8 +105,7 @@ namespace FidelityFX.FSR3
ReconstructedPrevNearestDepth.Create();
// Resource FSR3UPSCALER_FrameInfo: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R32G32B32A32_FLOAT, FFX_RESOURCE_FLAGS_NONE
FrameInfo = new RenderTexture(1, 1, 0, GraphicsFormat.R32G32B32A32_SFloat) { name = "FSR3UPSCALER_FrameInfo", enableRandomWrite = true };
FrameInfo.Create();
CreateDoubleBufferedResource(FrameInfo, "FSR3UPSCALER_FrameInfo", Vector2Int.one, GraphicsFormat.R32G32B32A32_SFloat);
// Resources FSR3UPSCALER_Accumulation1/2: FFX_RESOURCE_USAGE_RENDERTARGET | FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R8_UNORM, FFX_RESOURCE_FLAGS_NONE
CreateDoubleBufferedResource(Accumulation, "FSR3UPSCALER_Accumulation", maxRenderSize, GraphicsFormat.R8_UNorm);
@ -190,8 +188,8 @@ namespace FidelityFX.FSR3
DestroyResource(InternalUpscaled);
DestroyResource(Luma);
DestroyResource(Accumulation);
DestroyResource(FrameInfo);
DestroyResource(ref FrameInfo);
DestroyResource(ref ReconstructedPrevNearestDepth);
DestroyResource(ref DilatedDepth);
DestroyResource(ref DilatedVelocity);
@ -236,6 +234,15 @@ namespace FidelityFX.FSR3
resource = null;
}
private static void DestroyResource(ref ComputeBuffer resource)
{
if (resource == null)
return;
resource.Release();
resource = null;
}
private static void DestroyResource(RenderTexture[] resource)
{
for (int i = 0; i < resource.Length; ++i)

4
Runtime/FidelityFX.FSR.asmdef

@ -1,7 +1,9 @@
{
"name": "FidelityFX.FSR",
"rootNamespace": "FidelityFX",
"references": [],
"references": [
"GUID:df380645f10b7bc4b97d4f5eb6303d95"
],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,

3
Shaders/ffx_fsr2_accumulate_pass.compute

@ -1,4 +1,4 @@
// Copyright (c) 2024 Nico de Poel
// Copyright (c) 2026 Nico de Poel
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@ -25,7 +25,6 @@
#pragma multi_compile_local __ FFX_FSR2_OPTION_HDR_COLOR_INPUT
#pragma multi_compile_local __ FFX_FSR2_OPTION_LOW_RESOLUTION_MOTION_VECTORS
#pragma multi_compile_local __ FFX_FSR2_OPTION_JITTERED_MOTION_VECTORS
#pragma multi_compile_local __ FFX_FSR2_OPTION_INVERTED_DEPTH
#pragma multi_compile_local __ FFX_FSR2_OPTION_APPLY_SHARPENING
#pragma multi_compile __ UNITY_FSR_TEXTURE2D_X_ARRAY

5
Shaders/ffx_fsr2_autogen_reactive_pass.compute

@ -1,4 +1,4 @@
// Copyright (c) 2024 Nico de Poel
// Copyright (c) 2026 Nico de Poel
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@ -21,9 +21,6 @@
#pragma kernel CS
#pragma multi_compile_local __ FFX_HALF
#pragma multi_compile_local __ FFX_FSR2_OPTION_LOW_RESOLUTION_MOTION_VECTORS
#pragma multi_compile_local __ FFX_FSR2_OPTION_JITTERED_MOTION_VECTORS
#pragma multi_compile_local __ FFX_FSR2_OPTION_INVERTED_DEPTH
#pragma multi_compile __ UNITY_FSR_TEXTURE2D_X_ARRAY

5
Shaders/ffx_fsr2_compute_luminance_pyramid_pass.compute

@ -1,4 +1,4 @@
// Copyright (c) 2024 Nico de Poel
// Copyright (c) 2026 Nico de Poel
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@ -21,9 +21,6 @@
#pragma kernel CS
#pragma multi_compile_local __ FFX_HALF
#pragma multi_compile_local __ FFX_FSR2_OPTION_LOW_RESOLUTION_MOTION_VECTORS
#pragma multi_compile_local __ FFX_FSR2_OPTION_JITTERED_MOTION_VECTORS
#pragma multi_compile_local __ FFX_FSR2_OPTION_INVERTED_DEPTH
#pragma multi_compile __ UNITY_FSR_TEXTURE2D_X_ARRAY

2
Shaders/ffx_fsr2_depth_clip_pass.compute

@ -1,4 +1,4 @@
// Copyright (c) 2024 Nico de Poel
// Copyright (c) 2026 Nico de Poel
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal

4
Shaders/ffx_fsr2_lock_pass.compute

@ -1,4 +1,4 @@
// Copyright (c) 2024 Nico de Poel
// Copyright (c) 2026 Nico de Poel
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@ -21,8 +21,6 @@
#pragma kernel CS
#pragma multi_compile_local __ FFX_HALF
#pragma multi_compile_local __ FFX_FSR2_OPTION_LOW_RESOLUTION_MOTION_VECTORS
#pragma multi_compile_local __ FFX_FSR2_OPTION_JITTERED_MOTION_VECTORS
#pragma multi_compile_local __ FFX_FSR2_OPTION_INVERTED_DEPTH
#pragma multi_compile __ UNITY_FSR_TEXTURE2D_X_ARRAY

6
Shaders/ffx_fsr2_rcas_pass.compute

@ -1,4 +1,4 @@
// Copyright (c) 2024 Nico de Poel
// Copyright (c) 2026 Nico de Poel
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@ -20,10 +20,6 @@
#pragma kernel CS
#pragma multi_compile_local __ FFX_FSR2_OPTION_LOW_RESOLUTION_MOTION_VECTORS
#pragma multi_compile_local __ FFX_FSR2_OPTION_JITTERED_MOTION_VECTORS
#pragma multi_compile_local __ FFX_FSR2_OPTION_INVERTED_DEPTH
#pragma multi_compile __ UNITY_FSR_TEXTURE2D_X_ARRAY
#include "ffx_fsr_unity_common.cginc"

2
Shaders/ffx_fsr2_reconstruct_previous_depth_pass.compute

@ -1,4 +1,4 @@
// Copyright (c) 2024 Nico de Poel
// Copyright (c) 2026 Nico de Poel
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal

4
Shaders/ffx_fsr2_tcr_autogen_pass.compute

@ -1,4 +1,4 @@
// Copyright (c) 2024 Nico de Poel
// Copyright (c) 2026 Nico de Poel
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@ -21,9 +21,7 @@
#pragma kernel CS
#pragma multi_compile_local __ FFX_HALF
#pragma multi_compile_local __ FFX_FSR2_OPTION_LOW_RESOLUTION_MOTION_VECTORS
#pragma multi_compile_local __ FFX_FSR2_OPTION_JITTERED_MOTION_VECTORS
#pragma multi_compile_local __ FFX_FSR2_OPTION_INVERTED_DEPTH
#pragma multi_compile __ UNITY_FSR_TEXTURE2D_X_ARRAY

5
Shaders/ffx_fsr3upscaler_accumulate_pass.compute

@ -1,4 +1,4 @@
// Copyright (c) 2024 Nico de Poel
// Copyright (c) 2026 Nico de Poel
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@ -24,11 +24,12 @@
#pragma multi_compile_local __ FFX_FSR3UPSCALER_OPTION_REPROJECT_USE_LANCZOS_TYPE
#pragma multi_compile_local __ FFX_FSR3UPSCALER_OPTION_HDR_COLOR_INPUT
#pragma multi_compile_local __ FFX_FSR3UPSCALER_OPTION_LOW_RESOLUTION_MOTION_VECTORS
#pragma multi_compile_local __ FFX_FSR3UPSCALER_OPTION_JITTERED_MOTION_VECTORS
#pragma multi_compile_local __ FFX_FSR3UPSCALER_OPTION_APPLY_SHARPENING
#pragma multi_compile __ UNITY_FSR_TEXTURE2D_X_ARRAY
#include "ffx_fsr_unity_common.cginc"
#include_with_pragmas "ffx_fsr_unity_common.cginc"
// Ensure the correct value is defined for this keyword, as it is used to select one of multiple sampler functions
#ifdef FFX_FSR3UPSCALER_OPTION_REPROJECT_USE_LANCZOS_TYPE

4
Shaders/ffx_fsr3upscaler_autogen_reactive_pass.compute

@ -1,4 +1,4 @@
// Copyright (c) 2024 Nico de Poel
// Copyright (c) 2026 Nico de Poel
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@ -24,6 +24,6 @@
#pragma multi_compile __ UNITY_FSR_TEXTURE2D_X_ARRAY
#include "ffx_fsr_unity_common.cginc"
#include_with_pragmas "ffx_fsr_unity_common.cginc"
#include "shaders/ffx_fsr3upscaler_autogen_reactive_pass.hlsl"

4
Shaders/ffx_fsr3upscaler_debug_view_pass.compute

@ -1,4 +1,4 @@
// Copyright (c) 2024 Nico de Poel
// Copyright (c) 2026 Nico de Poel
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@ -24,6 +24,6 @@
#pragma multi_compile __ UNITY_FSR_TEXTURE2D_X_ARRAY
#include "ffx_fsr_unity_common.cginc"
#include_with_pragmas "ffx_fsr_unity_common.cginc"
#include "shaders/ffx_fsr3upscaler_debug_view_pass.hlsl"

4
Shaders/ffx_fsr3upscaler_luma_instability_pass.compute

@ -1,4 +1,4 @@
// Copyright (c) 2024 Nico de Poel
// Copyright (c) 2026 Nico de Poel
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@ -24,6 +24,6 @@
#pragma multi_compile __ UNITY_FSR_TEXTURE2D_X_ARRAY
#include "ffx_fsr_unity_common.cginc"
#include_with_pragmas "ffx_fsr_unity_common.cginc"
#include "shaders/ffx_fsr3upscaler_luma_instability_pass.hlsl"

4
Shaders/ffx_fsr3upscaler_luma_pyramid_pass.compute

@ -1,4 +1,4 @@
// Copyright (c) 2024 Nico de Poel
// Copyright (c) 2026 Nico de Poel
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@ -24,7 +24,7 @@
#pragma multi_compile __ UNITY_FSR_TEXTURE2D_X_ARRAY
#include "ffx_fsr_unity_common.cginc"
#include_with_pragmas "ffx_fsr_unity_common.cginc"
// Wave operations require shader model 6.0; this can only be enabled when using DXC on D3D12
// These pragmas are commented out by default as Unity will sometimes ignore the #if's and try to enable these features anyway.

4
Shaders/ffx_fsr3upscaler_prepare_inputs_pass.compute

@ -1,4 +1,4 @@
// Copyright (c) 2024 Nico de Poel
// Copyright (c) 2026 Nico de Poel
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@ -26,6 +26,6 @@
#pragma multi_compile __ UNITY_FSR_TEXTURE2D_X_ARRAY
#include "ffx_fsr_unity_common.cginc"
#include_with_pragmas "ffx_fsr_unity_common.cginc"
#include "shaders/ffx_fsr3upscaler_prepare_inputs_pass.hlsl"

4
Shaders/ffx_fsr3upscaler_prepare_reactivity_pass.compute

@ -1,4 +1,4 @@
// Copyright (c) 2024 Nico de Poel
// Copyright (c) 2026 Nico de Poel
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@ -24,6 +24,6 @@
#pragma multi_compile __ UNITY_FSR_TEXTURE2D_X_ARRAY
#include "ffx_fsr_unity_common.cginc"
#include_with_pragmas "ffx_fsr_unity_common.cginc"
#include "shaders/ffx_fsr3upscaler_prepare_reactivity_pass.hlsl"

4
Shaders/ffx_fsr3upscaler_rcas_pass.compute

@ -1,4 +1,4 @@
// Copyright (c) 2024 Nico de Poel
// Copyright (c) 2026 Nico de Poel
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@ -22,6 +22,6 @@
#pragma multi_compile __ UNITY_FSR_TEXTURE2D_X_ARRAY
#include "ffx_fsr_unity_common.cginc"
#include_with_pragmas "ffx_fsr_unity_common.cginc"
#include "shaders/ffx_fsr3upscaler_rcas_pass.hlsl"

4
Shaders/ffx_fsr3upscaler_shading_change_pass.compute

@ -1,4 +1,4 @@
// Copyright (c) 2024 Nico de Poel
// Copyright (c) 2026 Nico de Poel
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@ -24,6 +24,6 @@
#pragma multi_compile __ UNITY_FSR_TEXTURE2D_X_ARRAY
#include "ffx_fsr_unity_common.cginc"
#include_with_pragmas "ffx_fsr_unity_common.cginc"
#include "shaders/ffx_fsr3upscaler_shading_change_pass.hlsl"

4
Shaders/ffx_fsr3upscaler_shading_change_pyramid_pass.compute

@ -1,4 +1,4 @@
// Copyright (c) 2024 Nico de Poel
// Copyright (c) 2026 Nico de Poel
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@ -24,7 +24,7 @@
#pragma multi_compile __ UNITY_FSR_TEXTURE2D_X_ARRAY
#include "ffx_fsr_unity_common.cginc"
#include_with_pragmas "ffx_fsr_unity_common.cginc"
// Wave operations require shader model 6.0; this can only be enabled when using DXC on D3D12
#define FFX_SPD_NO_WAVE_OPERATIONS

4
Shaders/ffx_fsr3upscaler_tcr_autogen_pass.compute

@ -1,4 +1,4 @@
// Copyright (c) 2024 Nico de Poel
// Copyright (c) 2026 Nico de Poel
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@ -25,6 +25,6 @@
#pragma multi_compile __ UNITY_FSR_TEXTURE2D_X_ARRAY
#include "ffx_fsr_unity_common.cginc"
#include_with_pragmas "ffx_fsr_unity_common.cginc"
#include "shaders/ffx_fsr3upscaler_tcr_autogen_pass.hlsl"

51
Shaders/ffx_fsr_unity_common.cginc

@ -1,4 +1,4 @@
// Copyright (c) 2024 Nico de Poel
// Copyright (c) 2026 Nico de Poel
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@ -18,6 +18,13 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#if !defined(UNITY_FSR_TEXTURE2D_X_ARRAY)
#define DISABLE_TEXTURE2D_X_ARRAY
#endif
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/TextureXR.hlsl"
// Suppress a few warnings produced by FFX's HLSL code
#pragma warning(disable: 3078) // Loop control variable conflicts
#pragma warning(disable: 3203) // Signed/unsigned mismatch
@ -38,45 +45,13 @@
//#pragma require Native16Bit
//#endif
// Allow use of Xbox Series-specific optimizations
// #if defined(SHADER_API_GAMECORE_XBOXSERIES)
// #define __XBOX_SCARLETT
// #endif
// Hack to work around the lack of texture atomics on Metal
#if defined(SHADER_API_METAL)
#define InterlockedAdd(dest, val, orig) { (orig) = (dest); (dest) += (val); }
#define InterlockedMin(dest, val) { (dest) = min((dest), (val)); }
#define InterlockedMax(dest, val) { (dest) = max((dest), (val)); }
#endif
// Workaround for HDRP using texture arrays for its camera buffers on some platforms
// The below defines are adapted from: Packages/com.unity.render-pipelines.core/ShaderLibrary/TextureXR.hlsl
#if ((defined(SHADER_API_D3D11) || defined(SHADER_API_D3D12)) && !defined(SHADER_API_XBOXONE) && !defined(SHADER_API_GAMECORE)) || defined(SHADER_API_PSSL) || defined(SHADER_API_VULKAN)
#define UNITY_TEXTURE2D_X_ARRAY_SUPPORTED
#endif
// Control if TEXTURE2D_X macros will expand to texture arrays
#if defined(UNITY_TEXTURE2D_X_ARRAY_SUPPORTED) && defined(UNITY_FSR_TEXTURE2D_X_ARRAY)
#define USE_TEXTURE2D_X_AS_ARRAY
#endif
// Early defines for single-pass instancing
#if defined(STEREO_INSTANCING_ON) && defined(UNITY_TEXTURE2D_X_ARRAY_SUPPORTED)
#define UNITY_STEREO_INSTANCING_ENABLED
#endif
// Helper macros to handle XR single-pass with Texture2DArray
#if defined(USE_TEXTURE2D_X_AS_ARRAY)
// Only single-pass stereo instancing used array indexing
#if defined(UNITY_STEREO_INSTANCING_ENABLED)
static uint unity_StereoEyeIndex;
#define SLICE_ARRAY_INDEX unity_StereoEyeIndex
#else
#define SLICE_ARRAY_INDEX 0
#endif
// Declare and sample camera buffers as texture arrays
#define UNITY_FSR_TEX2D(type) Texture2DArray<type>
#define UNITY_FSR_RWTEX2D(type) RWTexture2DArray<type>
#define UNITY_FSR_POS(pxPos) FfxUInt32x3(pxPos, SLICE_ARRAY_INDEX)
#define UNITY_FSR_UV(uv) FfxFloat32x3(uv, SLICE_ARRAY_INDEX)
#define UNITY_FSR_GETDIMS(tex, w, h) { FfxUInt32 uElements; (tex).GetDimensions((w), (h), uElements); }
#endif

8
Shaders/shaders/ffx_core_gpu_common.h

@ -1,6 +1,6 @@
// This file is part of the FidelityFX SDK.
//
// Copyright (C) 2024 Advanced Micro Devices, Inc.
// Copyright (C) 2025 Advanced Micro Devices, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files(the "Software"), to deal
@ -2652,7 +2652,7 @@ FfxFloat32x3 ffxSrgbFromLinear(FfxFloat32x3 value)
/// @ingroup GPUCore
FfxFloat32 ffxLinearFromSrgb(FfxFloat32 value)
{
FfxFloat32x3 j = FfxFloat32x3(0.04045 / 12.92, 1.0 / 12.92, 2.4);
FfxFloat32x3 j = FfxFloat32x3(0.04045, 1.0 / 12.92, 2.4);;
FfxFloat32x2 k = FfxFloat32x2(1.0 / 1.055, 0.055 / 1.055);
return ffxZeroOneSelect(ffxZeroOneIsSigned(value - j.x), value * j.y, pow(value * k.x + k.y, j.z));
}
@ -2669,7 +2669,7 @@ FfxFloat32 ffxLinearFromSrgb(FfxFloat32 value)
/// @ingroup GPUCore
FfxFloat32x2 ffxLinearFromSrgb(FfxFloat32x2 value)
{
FfxFloat32x3 j = FfxFloat32x3(0.04045 / 12.92, 1.0 / 12.92, 2.4);
FfxFloat32x3 j = FfxFloat32x3(0.04045, 1.0 / 12.92, 2.4);;
FfxFloat32x2 k = FfxFloat32x2(1.0 / 1.055, 0.055 / 1.055);
return ffxZeroOneSelect(ffxZeroOneIsSigned(value - j.xx), value * j.yy, pow(value * k.xx + k.yy, j.zz));
}
@ -2686,7 +2686,7 @@ FfxFloat32x2 ffxLinearFromSrgb(FfxFloat32x2 value)
/// @ingroup GPUCore
FfxFloat32x3 ffxLinearFromSrgb(FfxFloat32x3 value)
{
FfxFloat32x3 j = FfxFloat32x3(0.04045 / 12.92, 1.0 / 12.92, 2.4);
FfxFloat32x3 j = FfxFloat32x3(0.04045, 1.0 / 12.92, 2.4);;
FfxFloat32x2 k = FfxFloat32x2(1.0 / 1.055, 0.055 / 1.055);
return ffxZeroOneSelect(ffxZeroOneIsSigned(value - j.xxx), value * j.yyy, pow(value * k.xxx + k.yyy, j.zzz));
}

8
Shaders/shaders/ffx_core_gpu_common_half.h

@ -1,6 +1,6 @@
// This file is part of the FidelityFX SDK.
//
// Copyright (C) 2024 Advanced Micro Devices, Inc.
// Copyright (C) 2025 Advanced Micro Devices, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files(the "Software"), to deal
@ -2895,7 +2895,7 @@ FfxFloat16x3 ffxLinearFromGammaHalf(FfxFloat16x3 c, FfxFloat16 x)
/// @ingroup GPUCore
FfxFloat16 ffxLinearFromSrgbHalf(FfxFloat16 c)
{
FfxFloat16x3 j = FfxFloat16x3(0.04045 / 12.92, 1.0 / 12.92, 2.4);
FfxFloat16x3 j = FfxFloat16x3(0.04045, 1.0 / 12.92, 2.4);
FfxFloat16x2 k = FfxFloat16x2(1.0 / 1.055, 0.055 / 1.055);
return ffxZeroOneSelectHalf(ffxZeroOneIsSignedHalf(c - j.x), c * j.y, pow(c * k.x + k.y, j.z));
}
@ -2912,7 +2912,7 @@ FfxFloat16 ffxLinearFromSrgbHalf(FfxFloat16 c)
/// @ingroup GPUCore
FfxFloat16x2 ffxLinearFromSrgbHalf(FfxFloat16x2 c)
{
FfxFloat16x3 j = FfxFloat16x3(0.04045 / 12.92, 1.0 / 12.92, 2.4);
FfxFloat16x3 j = FfxFloat16x3(0.04045, 1.0 / 12.92, 2.4);
FfxFloat16x2 k = FfxFloat16x2(1.0 / 1.055, 0.055 / 1.055);
return ffxZeroOneSelectHalf(ffxZeroOneIsSignedHalf(c - j.xx), c * j.yy, pow(c * k.xx + k.yy, j.zz));
}
@ -2929,7 +2929,7 @@ FfxFloat16x2 ffxLinearFromSrgbHalf(FfxFloat16x2 c)
/// @ingroup GPUCore
FfxFloat16x3 ffxLinearFromSrgbHalf(FfxFloat16x3 c)
{
FfxFloat16x3 j = FfxFloat16x3(0.04045 / 12.92, 1.0 / 12.92, 2.4);
FfxFloat16x3 j = FfxFloat16x3(0.04045, 1.0 / 12.92, 2.4);
FfxFloat16x2 k = FfxFloat16x2(1.0 / 1.055, 0.055 / 1.055);
return ffxZeroOneSelectHalf(ffxZeroOneIsSignedHalf(c - j.xxx), c * j.yyy, pow(c * k.xxx + k.yyy, j.zzz));
}

4
Shaders/shaders/ffx_fsr2_accumulate_pass.hlsl

@ -35,12 +35,12 @@
#define FSR2_BIND_SRV_SCENE_LUMINANCE_MIPS 8
#define FSR2_BIND_SRV_AUTO_EXPOSURE 9
#define FSR2_BIND_SRV_LUMA_HISTORY 10
#define FSR2_BIND_SRV_NEW_LOCKS 11
#define FSR2_BIND_UAV_INTERNAL_UPSCALED 0
#define FSR2_BIND_UAV_LOCK_STATUS 1
#define FSR2_BIND_UAV_UPSCALED_OUTPUT 2
#define FSR2_BIND_UAV_NEW_LOCKS 3
#define FSR2_BIND_UAV_LUMA_HISTORY 4
#define FSR2_BIND_UAV_LUMA_HISTORY 3
#define FSR2_BIND_CB_FSR2 0

1
Shaders/shaders/ffx_fsr2_compute_luminance_pyramid_pass.hlsl

@ -21,6 +21,7 @@
// THE SOFTWARE.
#define FSR2_BIND_SRV_INPUT_COLOR 0
#define FSR2_BIND_SRV_AUTO_EXPOSURE 1
#define FSR2_BIND_UAV_SPD_GLOBAL_ATOMIC 0
#define FSR2_BIND_UAV_EXPOSURE_MIP_LUMA_CHANGE 1

2
Shaders/shaders/ffx_fsr3upscaler_accumulate_pass.hlsl

@ -34,10 +34,10 @@
#define FSR3UPSCALER_BIND_SRV_CURRENT_LUMA 6
#define FSR3UPSCALER_BIND_SRV_LUMA_INSTABILITY 7
#define FSR3UPSCALER_BIND_SRV_INPUT_COLOR 8
#define FSR3UPSCALER_BIND_SRV_NEW_LOCKS 9
#define FSR3UPSCALER_BIND_UAV_INTERNAL_UPSCALED 0
#define FSR3UPSCALER_BIND_UAV_UPSCALED_OUTPUT 1
#define FSR3UPSCALER_BIND_UAV_NEW_LOCKS 2
#define FSR3UPSCALER_BIND_CB_FSR3UPSCALER 0

5
Shaders/shaders/ffx_fsr3upscaler_luma_pyramid_pass.hlsl

@ -22,6 +22,7 @@
#define FSR3UPSCALER_BIND_SRV_CURRENT_LUMA 0
#define FSR3UPSCALER_BIND_SRV_FARTHEST_DEPTH 1
#define FSR3UPSCALER_BIND_SRV_FRAME_INFO 2
#define FSR3UPSCALER_BIND_UAV_SPD_GLOBAL_ATOMIC 0
#define FSR3UPSCALER_BIND_UAV_FRAME_INFO 1
@ -30,8 +31,12 @@
#define FSR3UPSCALER_BIND_UAV_SPD_MIPS_LEVEL_2 4
#define FSR3UPSCALER_BIND_UAV_SPD_MIPS_LEVEL_3 5
#define FSR3UPSCALER_BIND_UAV_SPD_MIPS_LEVEL_4 6
#ifdef SHADER_API_GLCORE
#define FSR3UPSCALER_BIND_UAV_FARTHEST_DEPTH_MIP1 7
#else
#define FSR3UPSCALER_BIND_UAV_SPD_MIPS_LEVEL_5 7
#define FSR3UPSCALER_BIND_UAV_FARTHEST_DEPTH_MIP1 8
#endif
#define FSR3UPSCALER_BIND_CB_FSR3UPSCALER 0

2
Shaders/shaders/ffx_fsr3upscaler_shading_change_pyramid_pass.hlsl

@ -32,7 +32,9 @@
#define FSR3UPSCALER_BIND_UAV_SPD_MIPS_LEVEL_2 3
#define FSR3UPSCALER_BIND_UAV_SPD_MIPS_LEVEL_3 4
#define FSR3UPSCALER_BIND_UAV_SPD_MIPS_LEVEL_4 5
#ifndef SHADER_API_GLCORE
#define FSR3UPSCALER_BIND_UAV_SPD_MIPS_LEVEL_5 6
#endif
#define FSR3UPSCALER_BIND_CB_FSR3UPSCALER 0

23
Shaders/shaders/fsr1/ffx_fsr1.h

@ -1,6 +1,6 @@
// This file is part of the FidelityFX SDK.
//
// Copyright (C) 2024 Advanced Micro Devices, Inc.
// Copyright (C) 2025 Advanced Micro Devices, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files(the "Software"), to deal
@ -748,9 +748,10 @@ void FsrEasuH(
// Immediate constants for peak range.
FfxFloat32x2 peakC = FfxFloat32x2(1.0, -1.0 * 4.0);
// Limiters, these need to be high precision RCPs.
FfxFloat32 hitMinR = mn4R * ffxReciprocal(FfxFloat32(4.0) * mx4R);
FfxFloat32 hitMinG = mn4G * ffxReciprocal(FfxFloat32(4.0) * mx4G);
FfxFloat32 hitMinB = mn4B * ffxReciprocal(FfxFloat32(4.0) * mx4B);
const FfxFloat32 lowerLimiterMultiplier = ffxSaturate(eL / ffxMin(ffxMin3(bL, dL, fL), hL));
FfxFloat32 hitMinR = mn4R * ffxReciprocal(FfxFloat32(4.0) * mx4R) * lowerLimiterMultiplier;
FfxFloat32 hitMinG = mn4G * ffxReciprocal(FfxFloat32(4.0) * mx4G) * lowerLimiterMultiplier;
FfxFloat32 hitMinB = mn4B * ffxReciprocal(FfxFloat32(4.0) * mx4B) * lowerLimiterMultiplier;
FfxFloat32 hitMaxR = (peakC.x - mx4R) * ffxReciprocal(FfxFloat32(4.0) * mn4R + peakC.y);
FfxFloat32 hitMaxG = (peakC.x - mx4G) * ffxReciprocal(FfxFloat32(4.0) * mn4G + peakC.y);
FfxFloat32 hitMaxB = (peakC.x - mx4B) * ffxReciprocal(FfxFloat32(4.0) * mn4B + peakC.y);
@ -848,9 +849,10 @@ void FsrEasuH(
// Immediate constants for peak range.
FfxFloat16x2 peakC=FfxFloat16x2(1.0,-1.0*4.0);
// Limiters, these need to be high precision RCPs.
FfxFloat16 hitMinR=mn4R*ffxReciprocalHalf(FFX_BROADCAST_FLOAT16(4.0)*mx4R);
FfxFloat16 hitMinG=mn4G*ffxReciprocalHalf(FFX_BROADCAST_FLOAT16(4.0)*mx4G);
FfxFloat16 hitMinB=mn4B*ffxReciprocalHalf(FFX_BROADCAST_FLOAT16(4.0)*mx4B);
const FfxFloat16 lowerLimiterMultiplier = ffxSaturate(eL / min(ffxMin3Half(bL, dL, fL), hL));
FfxFloat16 hitMinR=mn4R*ffxReciprocalHalf(FFX_BROADCAST_FLOAT16(4.0)*mx4R) * lowerLimiterMultiplier;
FfxFloat16 hitMinG=mn4G*ffxReciprocalHalf(FFX_BROADCAST_FLOAT16(4.0)*mx4G) * lowerLimiterMultiplier;
FfxFloat16 hitMinB=mn4B*ffxReciprocalHalf(FFX_BROADCAST_FLOAT16(4.0)*mx4B) * lowerLimiterMultiplier;
FfxFloat16 hitMaxR=(peakC.x-mx4R)*ffxReciprocalHalf(FFX_BROADCAST_FLOAT16(4.0)*mn4R+peakC.y);
FfxFloat16 hitMaxG=(peakC.x-mx4G)*ffxReciprocalHalf(FFX_BROADCAST_FLOAT16(4.0)*mn4G+peakC.y);
FfxFloat16 hitMaxB=(peakC.x-mx4B)*ffxReciprocalHalf(FFX_BROADCAST_FLOAT16(4.0)*mn4B+peakC.y);
@ -967,9 +969,10 @@ void FsrEasuH(
// Immediate constants for peak range.
FfxFloat16x2 peakC=FfxFloat16x2(1.0,-1.0*4.0);
// Limiters, these need to be high precision RCPs.
FfxFloat16x2 hitMinR=mn4R*ffxReciprocalHalf(FFX_BROADCAST_FLOAT16X2(4.0)*mx4R);
FfxFloat16x2 hitMinG=mn4G*ffxReciprocalHalf(FFX_BROADCAST_FLOAT16X2(4.0)*mx4G);
FfxFloat16x2 hitMinB=mn4B*ffxReciprocalHalf(FFX_BROADCAST_FLOAT16X2(4.0)*mx4B);
const FfxFloat16x2 lowerLimiterMultiplier = ffxSaturate(eL / min(ffxMin3Half(bL, dL, fL), hL));
FfxFloat16x2 hitMinR=mn4R*ffxReciprocalHalf(FFX_BROADCAST_FLOAT16X2(4.0)*mx4R) * lowerLimiterMultiplier;
FfxFloat16x2 hitMinG=mn4G*ffxReciprocalHalf(FFX_BROADCAST_FLOAT16X2(4.0)*mx4G) * lowerLimiterMultiplier;
FfxFloat16x2 hitMinB=mn4B*ffxReciprocalHalf(FFX_BROADCAST_FLOAT16X2(4.0)*mx4B) * lowerLimiterMultiplier;
FfxFloat16x2 hitMaxR=(peakC.x-mx4R)*ffxReciprocalHalf(FFX_BROADCAST_FLOAT16X2(4.0)*mn4R+peakC.y);
FfxFloat16x2 hitMaxG=(peakC.x-mx4G)*ffxReciprocalHalf(FFX_BROADCAST_FLOAT16X2(4.0)*mn4G+peakC.y);
FfxFloat16x2 hitMaxB=(peakC.x-mx4B)*ffxReciprocalHalf(FFX_BROADCAST_FLOAT16X2(4.0)*mn4B+peakC.y);

6
Shaders/shaders/fsr2/ffx_fsr2_accumulate.h

@ -66,8 +66,8 @@ void RectifyHistory(
{
FfxFloat32 fScaleFactorInfluence = ffxMin(20.0f, ffxPow(FfxFloat32(1.0f / length(DownscaleFactor().x * DownscaleFactor().y)), 3.0f));
const FfxFloat32 fVecolityFactor = ffxSaturate(params.fHrVelocity / 20.0f);
const FfxFloat32 fBoxScaleT = ffxMax(params.fDepthClipFactor, ffxMax(params.fAccumulationMask, fVecolityFactor));
const FfxFloat32 fHrVelocityFactor = ffxSaturate(params.fHrVelocity / 20.0f);
const FfxFloat32 fBoxScaleT = ffxMax(params.fDepthClipFactor, ffxMax(params.fAccumulationMask, fHrVelocityFactor));
FfxFloat32 fBoxScale = ffxLerp(fScaleFactorInfluence, 1.0f, fBoxScaleT);
FfxFloat32x3 fScaledBoxVec = clippingBox.boxVec * fBoxScale;
@ -289,7 +289,7 @@ void Accumulate(FfxInt32x2 iPxHrPos)
#if FFX_FSR2_OPTION_APPLY_SHARPENING == 0
WriteUpscaledOutput(iPxHrPos, fHistoryColor);
#endif
StoreNewLocks(iPxHrPos, 0);
//StoreNewLocks(iPxHrPos, 0);
}
#endif // FFX_FSR2_ACCUMULATE_H

87
Shaders/shaders/fsr2/ffx_fsr2_callbacks_hlsl.h

@ -339,35 +339,21 @@ FfxUInt32x2 SPD_RenderSize()
}
#endif // #if defined(FSR2_BIND_CB_SPD)
// Declare and sample camera buffers as regular textures, unless overridden
#if !defined(UNITY_FSR_TEX2D)
#define UNITY_FSR_TEX2D(type) Texture2D<type>
#endif
#if !defined(UNITY_FSR_RWTEX2D)
#define UNITY_FSR_RWTEX2D(type) RWTexture2D<type>
#endif
#if !defined(UNITY_FSR_POS)
#define UNITY_FSR_POS(pxPos) (pxPos)
#endif
#if !defined(UNITY_FSR_UV)
#define UNITY_FSR_UV(uv) (uv)
#endif
SamplerState s_PointClamp : register(s0);
SamplerState s_LinearClamp : register(s1);
// SRVs
#if defined FSR2_BIND_SRV_INPUT_COLOR
UNITY_FSR_TEX2D(FfxFloat32x4) r_input_color_jittered : FFX_FSR2_DECLARE_SRV(FSR2_BIND_SRV_INPUT_COLOR);
TYPED_TEXTURE2D_X(FfxFloat32x4, r_input_color_jittered) : FFX_FSR2_DECLARE_SRV(FSR2_BIND_SRV_INPUT_COLOR);
#endif
#if defined FSR2_BIND_SRV_INPUT_OPAQUE_ONLY
UNITY_FSR_TEX2D(FfxFloat32x4) r_input_opaque_only : FFX_FSR2_DECLARE_SRV(FSR2_BIND_SRV_INPUT_OPAQUE_ONLY);
TYPED_TEXTURE2D_X(FfxFloat32x4, r_input_opaque_only) : FFX_FSR2_DECLARE_SRV(FSR2_BIND_SRV_INPUT_OPAQUE_ONLY);
#endif
#if defined FSR2_BIND_SRV_INPUT_MOTION_VECTORS
UNITY_FSR_TEX2D(FfxFloat32x4) r_input_motion_vectors : FFX_FSR2_DECLARE_SRV(FSR2_BIND_SRV_INPUT_MOTION_VECTORS);
TYPED_TEXTURE2D_X(FfxFloat32x4, r_input_motion_vectors) : FFX_FSR2_DECLARE_SRV(FSR2_BIND_SRV_INPUT_MOTION_VECTORS);
#endif
#if defined FSR2_BIND_SRV_INPUT_DEPTH
UNITY_FSR_TEX2D(FfxFloat32) r_input_depth : FFX_FSR2_DECLARE_SRV(FSR2_BIND_SRV_INPUT_DEPTH);
TYPED_TEXTURE2D_X(FfxFloat32, r_input_depth) : FFX_FSR2_DECLARE_SRV(FSR2_BIND_SRV_INPUT_DEPTH);
#endif
#if defined FSR2_BIND_SRV_INPUT_EXPOSURE
Texture2D<FfxFloat32x2> r_input_exposure : FFX_FSR2_DECLARE_SRV(FSR2_BIND_SRV_INPUT_EXPOSURE);
@ -376,10 +362,10 @@ SamplerState s_LinearClamp : register(s1);
Texture2D<FfxFloat32x2> r_auto_exposure : FFX_FSR2_DECLARE_SRV(FSR2_BIND_SRV_AUTO_EXPOSURE);
#endif
#if defined FSR2_BIND_SRV_REACTIVE_MASK
UNITY_FSR_TEX2D(FfxFloat32) r_reactive_mask : FFX_FSR2_DECLARE_SRV(FSR2_BIND_SRV_REACTIVE_MASK);
TYPED_TEXTURE2D_X(FfxFloat32, r_reactive_mask) : FFX_FSR2_DECLARE_SRV(FSR2_BIND_SRV_REACTIVE_MASK);
#endif
#if defined FSR2_BIND_SRV_TRANSPARENCY_AND_COMPOSITION_MASK
UNITY_FSR_TEX2D(FfxFloat32) r_transparency_and_composition_mask : FFX_FSR2_DECLARE_SRV(FSR2_BIND_SRV_TRANSPARENCY_AND_COMPOSITION_MASK);
TYPED_TEXTURE2D_X(FfxFloat32, r_transparency_and_composition_mask) : FFX_FSR2_DECLARE_SRV(FSR2_BIND_SRV_TRANSPARENCY_AND_COMPOSITION_MASK);
#endif
#if defined FSR2_BIND_SRV_RECONSTRUCTED_PREV_NEAREST_DEPTH
Texture2D<FfxUInt32> r_reconstructed_previous_nearest_depth : FFX_FSR2_DECLARE_SRV(FSR2_BIND_SRV_RECONSTRUCTED_PREV_NEAREST_DEPTH);
@ -406,7 +392,7 @@ SamplerState s_LinearClamp : register(s1);
Texture2D<unorm FfxFloat32> r_new_locks : FFX_FSR2_DECLARE_SRV(FSR2_BIND_SRV_NEW_LOCKS);
#endif
#if defined FSR2_BIND_SRV_PREPARED_INPUT_COLOR
Texture2D<FfxFloat32x4> r_prepared_input_color : FFX_FSR2_DECLARE_SRV(FSR2_BIND_SRV_PREPARED_INPUT_COLOR);
Texture2D<FfxFloat32x4> r_prepared_input_color : FFX_FSR2_DECLARE_SRV(FSR2_BIND_SRV_PREPARED_INPUT_COLOR);
#endif
#if defined FSR2_BIND_SRV_LUMA_HISTORY
Texture2D<unorm FfxFloat32x4> r_luma_history : FFX_FSR2_DECLARE_SRV(FSR2_BIND_SRV_LUMA_HISTORY);
@ -463,7 +449,7 @@ SamplerState s_LinearClamp : register(s1);
RWTexture2D<FfxFloat32x4> rw_luma_history : FFX_FSR2_DECLARE_UAV(FSR2_BIND_UAV_LUMA_HISTORY);
#endif
#if defined FSR2_BIND_UAV_UPSCALED_OUTPUT
UNITY_FSR_RWTEX2D(FfxFloat32x4) rw_upscaled_output : FFX_FSR2_DECLARE_UAV(FSR2_BIND_UAV_UPSCALED_OUTPUT);
RW_TEXTURE2D_X(FfxFloat32x4, rw_upscaled_output) : FFX_FSR2_DECLARE_UAV(FSR2_BIND_UAV_UPSCALED_OUTPUT);
#endif
#if defined FSR2_BIND_UAV_EXPOSURE_MIP_LUMA_CHANGE
globallycoherent RWTexture2D<FfxFloat32> rw_img_mip_shading_change : FFX_FSR2_DECLARE_UAV(FSR2_BIND_UAV_EXPOSURE_MIP_LUMA_CHANGE);
@ -481,7 +467,7 @@ SamplerState s_LinearClamp : register(s1);
RWTexture2D<FfxFloat32x2> rw_auto_exposure : FFX_FSR2_DECLARE_UAV(FSR2_BIND_UAV_AUTO_EXPOSURE);
#endif
#if defined FSR2_BIND_UAV_SPD_GLOBAL_ATOMIC
globallycoherent RWTexture2D<FfxUInt32> rw_spd_global_atomic : FFX_FSR2_DECLARE_UAV(FSR2_BIND_UAV_SPD_GLOBAL_ATOMIC);
globallycoherent RWStructuredBuffer<FfxUInt32> rw_spd_global_atomic : FFX_FSR2_DECLARE_UAV(FSR2_BIND_UAV_SPD_GLOBAL_ATOMIC);
#endif
#if defined FSR2_BIND_UAV_AUTOREACTIVE
@ -514,42 +500,42 @@ FfxFloat32 SampleMipLuma(FfxFloat32x2 fUV, FfxUInt32 mipLevel)
#if defined(FSR2_BIND_SRV_INPUT_DEPTH)
FfxFloat32 LoadInputDepth(FfxUInt32x2 iPxPos)
{
return r_input_depth[UNITY_FSR_POS(iPxPos)];
return r_input_depth[COORD_TEXTURE2D_X(iPxPos)];
}
#endif
#if defined(FSR2_BIND_SRV_INPUT_DEPTH)
FfxFloat32 SampleInputDepth(FfxFloat32x2 fUV)
{
return r_input_depth.SampleLevel(s_LinearClamp, UNITY_FSR_UV(fUV), 0).x;
return SAMPLE_TEXTURE2D_X_LOD(r_input_depth, s_LinearClamp, fUV, 0).x;
}
#endif
#if defined(FSR2_BIND_SRV_REACTIVE_MASK)
FfxFloat32 LoadReactiveMask(FfxUInt32x2 iPxPos)
{
return r_reactive_mask[UNITY_FSR_POS(iPxPos)];
return r_reactive_mask[COORD_TEXTURE2D_X(iPxPos)];
}
#endif
#if defined(FSR2_BIND_SRV_TRANSPARENCY_AND_COMPOSITION_MASK)
FfxFloat32 LoadTransparencyAndCompositionMask(FfxUInt32x2 iPxPos)
{
return r_transparency_and_composition_mask[UNITY_FSR_POS(iPxPos)];
return r_transparency_and_composition_mask[COORD_TEXTURE2D_X(iPxPos)];
}
#endif
#if defined(FSR2_BIND_SRV_INPUT_COLOR)
FfxFloat32x3 LoadInputColor(FfxUInt32x2 iPxPos)
{
return r_input_color_jittered[UNITY_FSR_POS(iPxPos)].rgb;
return r_input_color_jittered[COORD_TEXTURE2D_X(iPxPos)].rgb;
}
#endif
#if defined(FSR2_BIND_SRV_INPUT_COLOR)
FfxFloat32x3 SampleInputColor(FfxFloat32x2 fUV)
{
return r_input_color_jittered.SampleLevel(s_LinearClamp, UNITY_FSR_UV(fUV), 0).rgb;
return SAMPLE_TEXTURE2D_X_LOD(r_input_color_jittered, s_LinearClamp, fUV, 0).rgb;
}
#endif
@ -558,12 +544,20 @@ FfxFloat32x3 LoadPreparedInputColor(FfxUInt32x2 iPxPos)
{
return r_prepared_input_color[iPxPos].xyz;
}
#if FFX_HALF && defined(__XBOX_SCARLETT) && defined(__XBATG_EXTRA_16_BIT_OPTIMISATION) && (__XBATG_EXTRA_16_BIT_OPTIMISATION == 1)
FFX_MIN16_F3 LoadPreparedInputColorHalf(FfxUInt32x2 iPxPos)
{
return FFX_MIN16_F3(r_prepared_input_color[iPxPos].xyz);
}
#endif
#endif
#if defined(FSR2_BIND_SRV_INPUT_MOTION_VECTORS)
FfxFloat32x2 LoadInputMotionVector(FfxUInt32x2 iPxDilatedMotionVectorPos)
{
FfxFloat32x2 fSrcMotionVector = r_input_motion_vectors[UNITY_FSR_POS(iPxDilatedMotionVectorPos)].xy;
FfxFloat32x2 fSrcMotionVector = r_input_motion_vectors[COORD_TEXTURE2D_X(iPxDilatedMotionVectorPos)].xy;
FfxFloat32x2 fUvMotionVector = fSrcMotionVector * MotionVectorScale();
@ -622,7 +616,7 @@ void StoreInternalColorAndWeight(FfxUInt32x2 iPxPos, FfxFloat32x4 fColorAndWeigh
#if defined(FSR2_BIND_UAV_UPSCALED_OUTPUT)
void StoreUpscaledOutput(FfxUInt32x2 iPxPos, FfxFloat32x3 fColor)
{
rw_upscaled_output[UNITY_FSR_POS(iPxPos)] = FfxFloat32x4(fColor, 1.f);
rw_upscaled_output[COORD_TEXTURE2D_X(iPxPos)] = FfxFloat32x4(fColor, 1.f);
}
#endif
@ -801,6 +795,27 @@ FfxFloat32 SampleLanczos2Weight(FfxFloat32 x)
#endif
}
#if FFX_HALF && defined(__XBOX_SCARLETT) && defined(__XBATG_EXTRA_16_BIT_OPTIMISATION) && (__XBATG_EXTRA_16_BIT_OPTIMISATION == 1)
FFX_MIN16_F SampleLanczos2Weight_NoValu(FFX_MIN16_F x)
{
#if defined(FSR2_BIND_SRV_LANCZOS_LUT)
return FFX_MIN16_F(r_lanczos_lut.SampleLevel(s_LinearClamp, __XB_AsHalf(__XB_V_PACK_B32_F16(x, 0.5)), 0));
#else
return 0.0;
#endif
}
FFX_MIN16_F SampleLanczos2Weight_NoValuNoA16(FfxFloat32 x)
{
#if defined(FSR2_BIND_SRV_LANCZOS_LUT)
return FFX_MIN16_F(r_lanczos_lut.SampleLevel(s_LinearClamp, FfxFloat32x2(x, 0.5), 0));
#else
return 0.0;
#endif
}
#endif
#if defined(FSR2_BIND_SRV_UPSCALE_MAXIMUM_BIAS_LUT)
FfxFloat32 SampleUpsampleMaximumBias(FfxFloat32x2 uv)
{
@ -833,7 +848,7 @@ void StoreDilatedReactiveMasks(FFX_PARAMETER_IN FfxUInt32x2 iPxPos, FFX_PARAMETE
#if defined(FSR2_BIND_SRV_INPUT_OPAQUE_ONLY)
FfxFloat32x3 LoadOpaqueOnly(FFX_PARAMETER_IN FFX_MIN16_I2 iPxPos)
{
return r_input_opaque_only[UNITY_FSR_POS(iPxPos)].xyz;
return r_input_opaque_only[COORD_TEXTURE2D_X(iPxPos)].xyz;
}
#endif
@ -879,7 +894,9 @@ void StorePrevPostAlpha(FFX_PARAMETER_IN FFX_MIN16_I2 iPxPos, FFX_PARAMETER_IN F
FfxFloat32x2 SPD_LoadExposureBuffer()
{
#if defined FSR2_BIND_UAV_AUTO_EXPOSURE
#if defined FSR2_BIND_SRV_AUTO_EXPOSURE
return r_auto_exposure[FfxInt32x2(0, 0)];
#elif defined FSR2_BIND_UAV_AUTO_EXPOSURE
return rw_auto_exposure[FfxInt32x2(0, 0)];
#else
return FfxFloat32x2(0.f, 0.f);
@ -931,14 +948,14 @@ void SPD_SetMipmap(FfxInt32x2 iPxPos, FfxUInt32 slice, FfxFloat32 value)
void SPD_IncreaseAtomicCounter(inout FfxUInt32 spdCounter)
{
#if defined FSR2_BIND_UAV_SPD_GLOBAL_ATOMIC
InterlockedAdd(rw_spd_global_atomic[FfxInt32x2(0, 0)], 1, spdCounter);
InterlockedAdd(rw_spd_global_atomic[0], 1, spdCounter);
#endif // #if defined FSR2_BIND_UAV_SPD_GLOBAL_ATOMIC
}
void SPD_ResetAtomicCounter()
{
#if defined FSR2_BIND_UAV_SPD_GLOBAL_ATOMIC
rw_spd_global_atomic[FfxInt32x2(0, 0)] = 0;
rw_spd_global_atomic[0] = 0;
#endif // #if defined FSR2_BIND_UAV_SPD_GLOBAL_ATOMIC
}

28
Shaders/shaders/fsr2/ffx_fsr2_common.h

@ -54,7 +54,7 @@ FFX_STATIC const FfxFloat32 fAverageLanczosWeightPerFrame = 0.74f * fUpsampleLan
FFX_STATIC const FfxFloat32 fAccumulationMaxOnMotion = 3.0f * fUpsampleLanczosWeightScale;
// Auto exposure
FFX_STATIC const FfxFloat32 resetAutoExposureAverageSmoothing = 1e8f;
FFX_STATIC const FfxFloat32 resetAutoExposureAverageSmoothing = 1e4f;
struct AccumulationPassCommonParams
{
@ -509,6 +509,32 @@ FfxFloat32x3 UnprepareRgb(FfxFloat32x3 fRgb, FfxFloat32 fExposure)
return fRgb;
}
#if FFX_HALF && defined(__XBOX_SCARLETT) && defined(__XBATG_EXTRA_16_BIT_OPTIMISATION) && (__XBATG_EXTRA_16_BIT_OPTIMISATION == 1)
void PrepareRgbPaired(inout FFX_MIN16_F2 r, inout FFX_MIN16_F2 g, inout FFX_MIN16_F2 b, FfxFloat32 fExposure, FfxFloat32 fPreExposure)
{
FFX_MIN16_F ExposureOverPreExposureOver = FFX_MIN16_F(fExposure / fPreExposure);
r *= ExposureOverPreExposureOver;
g *= ExposureOverPreExposureOver;
b *= ExposureOverPreExposureOver;
r = ffxClampHalf(r, 0.0, FSR2_FP16_MAX);
g = ffxClampHalf(g, 0.0, FSR2_FP16_MAX);
b = ffxClampHalf(b, 0.0, FSR2_FP16_MAX);
}
void UnprepareRgbPaired(inout FFX_MIN16_F2 r, inout FFX_MIN16_F2 g, inout FFX_MIN16_F2 b, FfxFloat32 fExposure)
{
FFX_MIN16_F PreExposureOverExposure = FFX_MIN16_F(PreExposure() / fExposure);
r *= PreExposureOverExposure;
g *= PreExposureOverExposure;
b *= PreExposureOverExposure;
}
#endif
struct BilinearSamplingData
{

3
Shaders/shaders/fsr2/ffx_fsr2_compute_luminance_pyramid.h

@ -20,7 +20,7 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
FFX_GROUPSHARED FfxUInt32 spdCounter;
FFX_GROUPSHARED FfxUInt32 spdCounter = 0u;
void SpdIncreaseAtomicCounter(FfxUInt32 slice)
{
@ -83,6 +83,7 @@ void SpdStore(FfxInt32x2 pix, FfxFloat32x4 outValue, FfxUInt32 index, FfxUInt32
{
FfxFloat32 rate = 1.0f;
result = prev + (result - prev) * (1 - exp(-DeltaTime() * rate));
result = ffxMax(0.0f, result);
}
FfxFloat32x2 spdOutput = FfxFloat32x2(ComputeAutoExposureFromLavg(result), result);
SPD_SetExposureBuffer(spdOutput);

75
Shaders/shaders/fsr2/ffx_fsr2_rcas.h

@ -25,38 +25,80 @@
#include "../ffx_core.h"
#if FFX_HALF && defined(__XBOX_SCARLETT) && defined(__XBATG_EXTRA_16_BIT_OPTIMISATION) && (__XBATG_EXTRA_16_BIT_OPTIMISATION == 1)
#define FSR_RCAS_PREFER_PAIRED_VERSION 1
#else
#define FSR_RCAS_PREFER_PAIRED_VERSION 0
#endif
void WriteUpscaledOutput(FFX_MIN16_U2 iPxHrPos, FfxFloat32x3 fUpscaledColor)
{
StoreUpscaledOutput(FFX_MIN16_I2(iPxHrPos), fUpscaledColor);
}
#define FSR_RCAS_F 1
FfxFloat32x4 FsrRcasLoadF(FfxInt32x2 p)
{
FfxFloat32x4 fColor = LoadRCAS_Input(p);
#if FSR_RCAS_PREFER_PAIRED_VERSION
#define FSR_RCAS_HX2 1
fColor.rgb = PrepareRgb(fColor.rgb, Exposure(), PreExposure());
FfxFloat16x4 FsrRcasLoadHx2(FfxInt16x2 p)
{
return FfxFloat16x4(LoadRCAS_Input(p));
}
void FsrRcasInputHx2(inout FfxFloat16x2 r, inout FfxFloat16x2 g, inout FfxFloat16x2 b)
{
PrepareRgbPaired(r, g, b, Exposure(), PreExposure());
}
return fColor;
}
void FsrRcasInputF(inout FfxFloat32 r, inout FfxFloat32 g, inout FfxFloat32 b) {}
#include "../fsr1/ffx_fsr1.h"
#include "../fsr1/ffx_fsr1.h"
void CurrFilterPaired(FFX_MIN16_U2 pos)
{
FfxFloat16x2 cr;
FfxFloat16x2 cg;
FfxFloat16x2 cb;
FsrRcasHx2(cr, cg, cb, pos, RCASConfig());
void CurrFilter(FFX_MIN16_U2 pos)
{
FfxFloat32x3 c;
FsrRcasF(c.r, c.g, c.b, pos, RCASConfig());
UnprepareRgbPaired(cr, cg, cb, Exposure());
c = UnprepareRgb(c, Exposure());
WriteUpscaledOutput(pos, FfxFloat16x3(cr.x, cg.x, cb.x)); //TODO: fix type
pos.x += 8;
WriteUpscaledOutput(pos, FfxFloat16x3(cr.y, cg.y, cb.y)); //TODO: fix type
}
WriteUpscaledOutput(pos, c);
}
#else
#define FSR_RCAS_F 1
FfxFloat32x4 FsrRcasLoadF(FfxInt32x2 p)
{
FfxFloat32x4 fColor = LoadRCAS_Input(p);
fColor.rgb = PrepareRgb(fColor.rgb, Exposure(), PreExposure());
return fColor;
}
void FsrRcasInputF(inout FfxFloat32 r, inout FfxFloat32 g, inout FfxFloat32 b) {}
#include "../fsr1/ffx_fsr1.h"
void CurrFilter(FFX_MIN16_U2 pos)
{
FfxFloat32x3 c;
FsrRcasF(c.r, c.g, c.b, pos, RCASConfig());
c = UnprepareRgb(c, Exposure());
WriteUpscaledOutput(pos, c);
}
#endif // #if FSR_RCAS_PREFER_PAIRED_VERSION
void RCAS(FfxUInt32x3 LocalThreadId, FfxUInt32x3 WorkGroupId, FfxUInt32x3 Dtid)
{
// Do remapping of local xy in workgroup for a more PS-like swizzle pattern.
FfxUInt32x2 gxy = ffxRemapForQuad(LocalThreadId.x) + FfxUInt32x2(WorkGroupId.x << 4u, WorkGroupId.y << 4u);
#if FSR_RCAS_PREFER_PAIRED_VERSION
CurrFilterPaired(FFX_MIN16_U2(gxy));
gxy.y += 8u;
CurrFilterPaired(FFX_MIN16_U2(gxy));
#else
CurrFilter(FFX_MIN16_U2(gxy));
gxy.x += 8u;
CurrFilter(FFX_MIN16_U2(gxy));
@ -64,4 +106,5 @@ void RCAS(FfxUInt32x3 LocalThreadId, FfxUInt32x3 WorkGroupId, FfxUInt32x3 Dtid)
CurrFilter(FFX_MIN16_U2(gxy));
gxy.x -= 8u;
CurrFilter(FFX_MIN16_U2(gxy));
#endif
}

2
Shaders/shaders/fsr2/ffx_fsr2_reproject.h

@ -120,7 +120,7 @@ void ReprojectHistoryColor(const AccumulationPassCommonParams params, FFX_PARAME
LockState ReprojectHistoryLockStatus(const AccumulationPassCommonParams params, FFX_PARAMETER_OUT FfxFloat32x2 fReprojectedLockStatus)
{
LockState state = { FFX_FALSE, FFX_FALSE };
const FfxFloat32 fNewLockIntensity = LoadRwNewLocks(params.iPxHrPos);
const FfxFloat32 fNewLockIntensity = LoadNewLocks(params.iPxHrPos);
state.NewLock = fNewLockIntensity > (127.0f / 255.0f);
FfxFloat32 fInPlaceLockLifetime = state.NewLock ? fNewLockIntensity : 0;

66
Shaders/shaders/fsr2/ffx_fsr2_sample.h

@ -127,7 +127,6 @@ FFX_MIN16_F4 Bilinear(FetchedBilinearSamplesMin16 BilinearSamples, FFX_MIN16_F2
FfxFloat32 Lanczos2NoClamp(FfxFloat32 x)
{
const FfxFloat32 PI = 3.141592653589793f; // TODO: share SDK constants
return abs(x) < FSR2_EPSILON ? 1.f : (sin(PI * x) / (PI * x)) * (sin(0.5f * PI * x) / (0.5f * PI * x));
}
@ -139,14 +138,6 @@ FfxFloat32 Lanczos2(FfxFloat32 x)
#if FFX_HALF
#if 0
FFX_MIN16_F Lanczos2NoClamp(FFX_MIN16_F x)
{
const FFX_MIN16_F PI = FFX_MIN16_F(3.141592653589793f); // TODO: share SDK constants
return abs(x) < FFX_MIN16_F(FSR2_EPSILON) ? FFX_MIN16_F(1.f) : (sin(PI * x) / (PI * x)) * (sin(FFX_MIN16_F(0.5f) * PI * x) / (FFX_MIN16_F(0.5f) * PI * x));
}
#endif
FFX_MIN16_F Lanczos2(FFX_MIN16_F x)
{
x = ffxMin(abs(x), FFX_MIN16_F(2.0f));
@ -169,6 +160,26 @@ FFX_MIN16_F Lanczos2ApproxSqNoClamp(FFX_MIN16_F x2)
FFX_MIN16_F b = FFX_MIN16_F(1.0f / 4.0f) * x2 - FFX_MIN16_F(1);
return (FFX_MIN16_F(25.0f / 16.0f) * a * a - FFX_MIN16_F(25.0f / 16.0f - 1)) * (b * b);
}
#if defined(__XBOX_SCARLETT) && defined(__XBATG_EXTRA_16_BIT_OPTIMISATION) && (__XBATG_EXTRA_16_BIT_OPTIMISATION == 1)
FFX_MIN16_F2 PairedLanczos2ApproxSqNoClamp(FFX_MIN16_F2 x2)
{
// Xbox ATG (Pavel):
//
// 2.0 * x2 - 5.0 25.0 25.0 - 16.0 (2.0 * x2 - 5.0)^2 - (3.0)^2 (2.0 * x2 - 8.0) * (2.0 * x2 - 2.0) (x2 - 4.0) * (x2 - 1.0)
// a = -------------- ==> ---- * a^2 - -------------- = ----------------------------- = ---------------------------------- = ----------------------- = b * (x2 - 1.0)
// 5.0 16.0 16.0 16.0 16.0 4.0
//
// so we need to compute just (b * b) * (b * x2 - b), so we should get four packed instructions: 2 fma + 2 mul
//
FFX_MIN16_F2 b = (0.25 * x2 - 1.0);
return (b * b) * (b * x2 - b);
}
#endif
#endif //FFX_HALF
FfxFloat32 Lanczos2ApproxSq(FfxFloat32 x2)
@ -183,6 +194,15 @@ FFX_MIN16_F Lanczos2ApproxSq(FFX_MIN16_F x2)
x2 = ffxMin(x2, FFX_MIN16_F(4.0f));
return Lanczos2ApproxSqNoClamp(x2);
}
#if defined(__XBOX_SCARLETT) && defined(__XBATG_EXTRA_16_BIT_OPTIMISATION) && (__XBATG_EXTRA_16_BIT_OPTIMISATION == 1)
FFX_MIN16_F2 PairedLanczos2ApproxSq(FFX_MIN16_F2 x2)
{
x2 = ffxMin(x2, FFX_MIN16_F2(4.0, 4.0));
return PairedLanczos2ApproxSqNoClamp(x2);
}
#endif
#endif //FFX_HALF
FfxFloat32 Lanczos2ApproxNoClamp(FfxFloat32 x)
@ -219,6 +239,21 @@ FFX_MIN16_F Lanczos2_UseLUT(FFX_MIN16_F x)
{
return FFX_MIN16_F(SampleLanczos2Weight(abs(x)));
}
#if defined(__XBOX_SCARLETT) && defined(__XBATG_EXTRA_16_BIT_OPTIMISATION) && (__XBATG_EXTRA_16_BIT_OPTIMISATION == 1)
FFX_MIN16_F Lanczos2_UseLUTNoAbs(FFX_MIN16_F x)
{
return SampleLanczos2Weight_NoValu(x);
}
FFX_MIN16_F Lanczos2_UseLUTNoAbsNoA16(FfxFloat32 x)
{
return SampleLanczos2Weight_NoValuNoA16(x);
}
#endif
#endif //FFX_HALF
FfxFloat32x4 Lanczos2_UseLUT(FfxFloat32x4 fColor0, FfxFloat32x4 fColor1, FfxFloat32x4 fColor2, FfxFloat32x4 fColor3, FfxFloat32 t)
@ -364,6 +399,19 @@ FfxFloat32x4 Lanczos2LUT(FetchedBicubicSamples Samples, FfxFloat32x2 fPxFrac)
}
#if FFX_HALF
#if defined(__XBOX_SCARLETT) && defined(__XBATG_EXTRA_16_BIT_OPTIMISATION) && (__XBATG_EXTRA_16_BIT_OPTIMISATION == 1)
FFX_MIN16_F4 Lanczos2ApplyWeightX(FFX_MIN16_F4 fColor0, FFX_MIN16_F4 fColor1, FFX_MIN16_F4 fColor2, FFX_MIN16_F4 fColor3, FFX_MIN16_F2 fWeight0, FFX_MIN16_F2 fWeight1, FFX_MIN16_F2 fWeight2, FFX_MIN16_F2 fWeight3, FFX_MIN16_F2 fWeightSumInverted)
{
return (((fWeight0.x * fColor0) + fWeight1.x * fColor1) + ((fWeight2.x * fColor2) + fWeight3.x * fColor3)) * fWeightSumInverted.x;
}
FFX_MIN16_F4 Lanczos2ApplyWeightY(FFX_MIN16_F4 fColor0, FFX_MIN16_F4 fColor1, FFX_MIN16_F4 fColor2, FFX_MIN16_F4 fColor3, FFX_MIN16_F2 fWeight0, FFX_MIN16_F2 fWeight1, FFX_MIN16_F2 fWeight2, FFX_MIN16_F2 fWeight3, FFX_MIN16_F2 fWeightSumInverted)
{
return (((fWeight0.y * fColor0) + fWeight1.y * fColor1) + ((fWeight2.y * fColor2) + fWeight3.y * fColor3)) * fWeightSumInverted.y;
}
#endif
FFX_MIN16_F4 Lanczos2LUT(FetchedBicubicSamplesMin16 Samples, FFX_MIN16_F2 fPxFrac)
{
FFX_MIN16_F4 fColorX0 = Lanczos2_UseLUT(Samples.fColor00, Samples.fColor10, Samples.fColor20, Samples.fColor30, fPxFrac.x);

283
Shaders/shaders/fsr2/ffx_fsr2_upsample.h

@ -83,22 +83,167 @@ FfxFloat32 ComputeMaxKernelWeight() {
return ffxMin(FfxFloat32(1.99f), fKernelWeight);
}
#if FFX_HALF && (FFX_FSR2_OPTION_UPSAMPLE_USE_LANCZOS_TYPE == 2) && defined(__XBOX_SCARLETT) && defined(__XBATG_EXTRA_16_BIT_OPTIMISATION) && (__XBATG_EXTRA_16_BIT_OPTIMISATION == 1)
#define FFX_FSR2_USE_XBOX_PAIRED_16BIT_MATH_OPTIMIZATIONS 1
#else
#define FFX_FSR2_USE_XBOX_PAIRED_16BIT_MATH_OPTIMIZATIONS 0
#endif
#if FFX_FSR2_USE_XBOX_PAIRED_16BIT_MATH_OPTIMIZATIONS
FFX_MIN16_F2 Bool2ToFloat16x2(bool x, bool y)
{
uint lo = x ? 0x00003c00 : 0x00000000;
uint hi = y ? 0x3c000000 : 0x00000000;
return FFX_MIN16_F2(__XB_AsHalf(lo).x, __XB_AsHalf(hi).y);
}
struct PairedRectificationBoxAndAccumulatedColorAndWeight
{
FFX_MIN16_F2 aabbMinRG;
FFX_MIN16_F2 aabbMinB;
FFX_MIN16_F2 aabbMaxRG;
FFX_MIN16_F2 aabbMaxB;
FFX_MIN16_F2 boxCenterRG;
FFX_MIN16_F2 boxCenterB;
FFX_MIN16_F2 boxVecRG;
FFX_MIN16_F2 boxVecB;
FFX_MIN16_F2 fBoxCenterWeight;
FFX_MIN16_F2 fColorRG;
FFX_MIN16_F2 fColorB;
FFX_MIN16_F2 fWeight;
FFX_MIN16_F fKernelBiasSq;
FfxFloat32 fRectificationCurveBias;
void setKernelBiasAndRectificationCurveBias(FfxFloat32 kernelBias, FfxFloat32 rectificationCurveBias)
{
fKernelBiasSq = FFX_MIN16_F(kernelBias * kernelBias);
fRectificationCurveBias = rectificationCurveBias;
}
void init(FFX_MIN16_F fSrcSampleOffsetSq, bool sampleOnScreenX, bool sampleOnScreenY, FFX_MIN16_F3 colorSample)
{
// NOTE: make sure exp has 32-bit precision
const FFX_MIN16_F fBoxSampleWeight = FFX_MIN16_F(
exp(fRectificationCurveBias * FfxFloat32(fSrcSampleOffsetSq))
);
#if FFX_FSR2_OPTION_UPSAMPLE_USE_LANCZOS_TYPE == 2 // LANCZOS_TYPE_APPROXIMATE
const FFX_MIN16_F2 LanczosUpsampleWeight = PairedLanczos2ApproxSq(fSrcSampleOffsetSq * fKernelBiasSq);
#else
#error "Only LANCZOS_TYPE_APPROXIMATE is supported in paired version so far"
#endif
const FFX_MIN16_F2 fSampleWeight = FFX_MIN16_F2((sampleOnScreenX && sampleOnScreenY ? 1.0 : 0.0), 0.0) * LanczosUpsampleWeight;
aabbMinRG = colorSample.rg;
aabbMinB = colorSample.bb;
aabbMaxRG = colorSample.rg;
aabbMaxB = colorSample.bb;
boxCenterRG = colorSample.rg * fBoxSampleWeight.x;
boxCenterB = colorSample.bb * fBoxSampleWeight;
boxVecRG = colorSample.rg * boxCenterRG;
boxVecB = colorSample.bb * boxCenterB;
fBoxCenterWeight = fBoxSampleWeight;
fColorRG = colorSample.rg * fSampleWeight.x;
fColorB = colorSample.bb * fSampleWeight;
fWeight = fSampleWeight;
}
void addSample(FFX_MIN16_F2 fSrcSampleOffsetSq, bool sample0OnScreen, bool sample1OnScreen, bool sample01OnScreen, FFX_MIN16_F3 ColorSample0, FFX_MIN16_F3 ColorSample1)
{
// NOTE: make sure exp has 32-bit precision
const FFX_MIN16_F2 fBoxSampleWeight = FFX_MIN16_F2(
exp(fRectificationCurveBias * FfxFloat32(fSrcSampleOffsetSq.x)),
exp(fRectificationCurveBias * FfxFloat32(fSrcSampleOffsetSq.y))
);
#if FFX_FSR2_OPTION_UPSAMPLE_USE_LANCZOS_TYPE == 2 // LANCZOS_TYPE_APPROXIMATE
const FFX_MIN16_F2 LanczosUpsampleWeight = PairedLanczos2ApproxSq(fSrcSampleOffsetSq * fKernelBiasSq);
#else
#error "Only LANCZOS_TYPE_APPROXIMATE is supported in paired version so far"
#endif
const FFX_MIN16_F2 fSampleWeight = Bool2ToFloat16x2(sample0OnScreen && sample01OnScreen, sample1OnScreen && sample01OnScreen) * LanczosUpsampleWeight;
FFX_MIN16_F2 colorSampleB = FFX_MIN16_F2(ColorSample0.b, ColorSample1.b);
aabbMinRG = ffxMin(aabbMinRG, ColorSample0.rg);
aabbMinRG = ffxMin(aabbMinRG, ColorSample1.rg);
aabbMinB = ffxMin(aabbMinB, colorSampleB);
aabbMaxRG = ffxMax(aabbMaxRG, ColorSample0.rg);
aabbMaxRG = ffxMax(aabbMaxRG, ColorSample1.rg);
aabbMaxB = ffxMax(aabbMaxB, colorSampleB);
FFX_MIN16_F2 weightedColorSampleRG0 = ColorSample0.rg * fBoxSampleWeight.x;
FFX_MIN16_F2 weightedColorSampleRG1 = ColorSample1.rg * fBoxSampleWeight.y;
FFX_MIN16_F2 weightedColorSampleB = colorSampleB * fBoxSampleWeight;
boxCenterRG += weightedColorSampleRG0;
boxCenterRG += weightedColorSampleRG1;
boxCenterB += weightedColorSampleB;
boxVecRG += ColorSample0.rg * weightedColorSampleRG0;
boxVecRG += ColorSample1.rg * weightedColorSampleRG1;
boxVecB += colorSampleB * weightedColorSampleB;
fBoxCenterWeight += fBoxSampleWeight;
fWeight += fSampleWeight;
fColorRG += (ColorSample0.rg * fSampleWeight.x) + (ColorSample1.rg * fSampleWeight.y);
fColorB += colorSampleB * fSampleWeight;
}
void finalize(FFX_PARAMETER_INOUT RectificationBox rectificationBox, FFX_PARAMETER_INOUT FfxFloat32x4 outColorAndWeight)
{
rectificationBox.aabbMin.r = FfxFloat32(aabbMinRG.x);
rectificationBox.aabbMin.g = FfxFloat32(aabbMinRG.y);
rectificationBox.aabbMin.b = FfxFloat32(ffxMin(aabbMinB.x, aabbMinB.y));
rectificationBox.aabbMax.r = FfxFloat32(aabbMaxRG.x);
rectificationBox.aabbMax.g = FfxFloat32(aabbMaxRG.y);
rectificationBox.aabbMax.b = FfxFloat32(ffxMax(aabbMaxB.x, aabbMaxB.y));
rectificationBox.boxCenter.r = FfxFloat32(boxCenterRG.x);
rectificationBox.boxCenter.g = FfxFloat32(boxCenterRG.y);
rectificationBox.boxCenter.b = FfxFloat32(boxCenterB.x + boxCenterB.y);
rectificationBox.boxVec.r = FfxFloat32(boxVecRG.x);
rectificationBox.boxVec.g = FfxFloat32(boxVecRG.y);
rectificationBox.boxVec.b = FfxFloat32(boxVecB.x + boxVecB.y);
rectificationBox.fBoxCenterWeight = FfxFloat32(fBoxCenterWeight.x + fBoxCenterWeight.y);
outColorAndWeight = FfxFloat32x4(fColorRG, fColorB.x + fColorB.y, fWeight.x + fWeight.y);
}
};
#endif
FfxFloat32x4 ComputeUpsampledColorAndWeight(const AccumulationPassCommonParams params,
FFX_PARAMETER_INOUT RectificationBox clippingBox, FfxFloat32 fReactiveFactor)
{
#if FFX_FSR2_OPTION_UPSAMPLE_SAMPLERS_USE_DATA_HALF && FFX_HALF
#include "ffx_fsr2_force16_begin.h"
#endif
// We compute a sliced lanczos filter with 2 lobes (other slices are accumulated temporaly)
FfxFloat32x2 fDstOutputPos = FfxFloat32x2(params.iPxHrPos) + FFX_BROADCAST_FLOAT32X2(0.5f); // Destination resolution output pixel center position
FfxFloat32x2 fSrcOutputPos = fDstOutputPos * DownscaleFactor(); // Source resolution output pixel center position
FfxInt32x2 iSrcInputPos = FfxInt32x2(floor(fSrcOutputPos)); // TODO: what about weird upscale factors...
#if FFX_FSR2_OPTION_UPSAMPLE_SAMPLERS_USE_DATA_HALF && FFX_HALF
#include "ffx_fsr2_force16_end.h"
#endif
#if FFX_FSR2_USE_XBOX_PAIRED_16BIT_MATH_OPTIMIZATIONS
FFX_MIN16_F3 fSamples[iLanczos2SampleCount];
#else
FfxFloat32x3 fSamples[iLanczos2SampleCount];
#endif
FfxFloat32x2 fSrcUnjitteredPos = (FfxFloat32x2(iSrcInputPos) + FfxFloat32x2(0.5f, 0.5f)) - Jitter(); // This is the un-jittered position of the sample at offset 0,0
@ -113,6 +258,59 @@ FfxFloat32x4 ComputeUpsampledColorAndWeight(const AccumulationPassCommonParams p
const FfxBoolean bFlipRow = fSrcUnjitteredPos.y > fSrcOutputPos.y;
const FfxBoolean bFlipCol = fSrcUnjitteredPos.x > fSrcOutputPos.x;
#if FFX_FSR2_USE_XBOX_PAIRED_16BIT_MATH_OPTIMIZATIONS
// Unroll the loop to load samples on Scarlett to help the shader compiler
const FFX_MIN16_F2 fSampleOffsetX02 = __XB_AsHalf(bFlipCol ? __XB_AsUInt(FFX_MIN16_F2( 1, -1)) : __XB_AsUInt(FFX_MIN16_F2(-1, 1)));
const FFX_MIN16_F2 fSampleOffsetY02 = __XB_AsHalf(bFlipRow ? __XB_AsUInt(FFX_MIN16_F2( 1, -1)) : __XB_AsUInt(FFX_MIN16_F2(-1, 1)));
typedef FfxInt32 FfxTexCoordI;
typedef FfxInt32x2 FfxTexCoordI2;
const FfxTexCoordI2 iSrcSamplePosX01 = FfxTexCoordI2(iSrcInputPos.xx) + (bFlipCol ? FfxTexCoordI2( 1, 0) : FfxTexCoordI2(-1, 0));
const FfxTexCoordI2 iSrcSamplePosX23 = FfxTexCoordI2(iSrcInputPos.xx) + (bFlipCol ? FfxTexCoordI2(-1, -2) : FfxTexCoordI2( 1, 2));
const FfxTexCoordI2 iSrcSamplePosY01 = FfxTexCoordI2(iSrcInputPos.yy) + (bFlipRow ? FfxTexCoordI2( 1, 0) : FfxTexCoordI2(-1, 0));
const FfxTexCoordI2 iSrcSamplePosY23 = FfxTexCoordI2(iSrcInputPos.yy) + (bFlipRow ? FfxTexCoordI2(-1, -2) : FfxTexCoordI2( 1, 2));
const FfxTexCoordI2 renderSizeLastTexelCoord = FfxTexCoordI2(RenderSize()) - FfxTexCoordI2(1, 1);
const FfxTexCoordI2 iSrcSamplePosX01Clamped = FfxTexCoordI2(
__XB_Med3_I32(iSrcSamplePosX01.x, 0, renderSizeLastTexelCoord.x),
__XB_Med3_I32(iSrcSamplePosX01.y, 0, renderSizeLastTexelCoord.x)
);
const FfxTexCoordI2 iSrcSamplePosX23Clamped = FfxTexCoordI2(
__XB_Med3_I32(iSrcSamplePosX23.x, 0, renderSizeLastTexelCoord.x),
__XB_Med3_I32(iSrcSamplePosX23.y, 0, renderSizeLastTexelCoord.x)
);
const FfxTexCoordI2 iSrcSamplePosY01Clamped = FfxTexCoordI2(
__XB_Med3_I32(iSrcSamplePosY01.x, 0, renderSizeLastTexelCoord.y),
__XB_Med3_I32(iSrcSamplePosY01.y, 0, renderSizeLastTexelCoord.y)
);
const FfxTexCoordI2 iSrcSamplePosY23Clamped = FfxTexCoordI2(
__XB_Med3_I32(iSrcSamplePosY23.x, 0, renderSizeLastTexelCoord.y),
__XB_Med3_I32(iSrcSamplePosY23.y, 0, renderSizeLastTexelCoord.y)
);
fSamples[ 0] = LoadPreparedInputColorHalf(FfxTexCoordI2(iSrcSamplePosX01Clamped.x, iSrcSamplePosY01Clamped.x));
fSamples[ 1] = LoadPreparedInputColorHalf(FfxTexCoordI2(iSrcSamplePosX01Clamped.y, iSrcSamplePosY01Clamped.x));
fSamples[ 2] = LoadPreparedInputColorHalf(FfxTexCoordI2(iSrcSamplePosX23Clamped.x, iSrcSamplePosY01Clamped.x));
fSamples[4 + 0] = LoadPreparedInputColorHalf(FfxTexCoordI2(iSrcSamplePosX01Clamped.x, iSrcSamplePosY01Clamped.y));
fSamples[4 + 1] = LoadPreparedInputColorHalf(FfxTexCoordI2(iSrcSamplePosX01Clamped.y, iSrcSamplePosY01Clamped.y));
fSamples[4 + 2] = LoadPreparedInputColorHalf(FfxTexCoordI2(iSrcSamplePosX23Clamped.x, iSrcSamplePosY01Clamped.y));
fSamples[8 + 0] = LoadPreparedInputColorHalf(FfxTexCoordI2(iSrcSamplePosX01Clamped.x, iSrcSamplePosY23Clamped.x));
fSamples[8 + 1] = LoadPreparedInputColorHalf(FfxTexCoordI2(iSrcSamplePosX01Clamped.y, iSrcSamplePosY23Clamped.x));
fSamples[8 + 2] = LoadPreparedInputColorHalf(FfxTexCoordI2(iSrcSamplePosX23Clamped.x, iSrcSamplePosY23Clamped.x));
fSamples[12 + 0] = LoadPreparedInputColorHalf(FfxTexCoordI2(iSrcSamplePosX01Clamped.x, iSrcSamplePosY23Clamped.y));
fSamples[12 + 1] = LoadPreparedInputColorHalf(FfxTexCoordI2(iSrcSamplePosX01Clamped.y, iSrcSamplePosY23Clamped.y));
fSamples[12 + 2] = LoadPreparedInputColorHalf(FfxTexCoordI2(iSrcSamplePosX23Clamped.x, iSrcSamplePosY23Clamped.y));
#else
FfxFloat32x2 fOffsetTL = FfxFloat32x2(offsetTL);
FFX_UNROLL
@ -130,6 +328,7 @@ FfxFloat32x4 ComputeUpsampledColorAndWeight(const AccumulationPassCommonParams p
fSamples[iSampleIndex] = LoadPreparedInputColor(FfxInt32x2(sampleCoord));
}
}
#endif
FfxFloat32x4 fColorAndWeight = FfxFloat32x4(0.0f, 0.0f, 0.0f, 0.0f);
@ -145,6 +344,75 @@ FfxFloat32x4 ComputeUpsampledColorAndWeight(const AccumulationPassCommonParams p
const FfxFloat32 fRectificationCurveBias = ffxLerp(-2.0f, -3.0f, ffxSaturate(params.fHrVelocity / 50.0f));
#if FFX_FSR2_USE_XBOX_PAIRED_16BIT_MATH_OPTIMIZATIONS
// Unroll the loop to load samples on Scarlett to help the shader compiler
const bool coordX0OnScreen = iSrcSamplePosX01.x == iSrcSamplePosX01Clamped.x;
const bool coordX1OnScreen = iSrcSamplePosX01.y == iSrcSamplePosX01Clamped.y;
const bool coordX2OnScreen = iSrcSamplePosX23.x == iSrcSamplePosX23Clamped.x;
const bool coordY0OnScreen = iSrcSamplePosY01.x == iSrcSamplePosY01Clamped.x;
const bool coordY1OnScreen = iSrcSamplePosY01.y == iSrcSamplePosY01Clamped.y;
const bool coordY2OnScreen = iSrcSamplePosY23.x == iSrcSamplePosY23Clamped.x;
const FFX_MIN16_F2 fBaseSampleOffsetHalf = FFX_MIN16_F2(fBaseSampleOffset);
const FFX_MIN16_F2 fSrcSampleOffsetX_02 = fBaseSampleOffsetHalf.xx + fSampleOffsetX02;
const FFX_MIN16_F2 fSrcSampleOffsetY_02 = fBaseSampleOffsetHalf.yy + fSampleOffsetY02;
const FFX_MIN16_F2 fSrcSampleOffsetXSq_02 = fSrcSampleOffsetX_02 * fSrcSampleOffsetX_02;
const FFX_MIN16_F2 fSrcSampleOffsetYSq_02 = fSrcSampleOffsetY_02 * fSrcSampleOffsetY_02;
const FFX_MIN16_F2 fSrcSampleOffsetXYSq_11 = fBaseSampleOffsetHalf * fBaseSampleOffsetHalf;
PairedRectificationBoxAndAccumulatedColorAndWeight pairedBox;
pairedBox.setKernelBiasAndRectificationCurveBias(fKernelBias, fRectificationCurveBias);
// init by o o o
// o x o
// o o o
pairedBox.init(
fSrcSampleOffsetXYSq_11.x + fSrcSampleOffsetXYSq_11.y,
coordX1OnScreen, coordY1OnScreen,
fSamples[5]
);
// add remaining two samples from 1st row x o x
// o * o
// o o o
pairedBox.addSample(
fSrcSampleOffsetXSq_02 + fSrcSampleOffsetYSq_02.xx,
coordX0OnScreen, coordX2OnScreen, coordY0OnScreen,
fSamples[0 + 0], fSamples[0 + 2]
);
// add two samples from 2nd row * o *
// o * o
// x o x
pairedBox.addSample(
fSrcSampleOffsetXSq_02 + fSrcSampleOffsetYSq_02.yy,
coordX0OnScreen, coordX2OnScreen, coordY2OnScreen,
fSamples[8 + 0], fSamples[8 + 2]
);
// add two samples from 3rd row * o *
// x * x
// * o *
pairedBox.addSample(
fSrcSampleOffsetXSq_02 + fSrcSampleOffsetXYSq_11.yy,
coordX0OnScreen, coordX2OnScreen, coordY1OnScreen,
fSamples[4 + 0], fSamples[4 + 2]
);
// add remaining samples * x *
// * * *
// * x *
pairedBox.addSample(
fSrcSampleOffsetXYSq_11.xx + fSrcSampleOffsetYSq_02,
coordY0OnScreen, coordY2OnScreen, coordX1OnScreen,
fSamples[0 + 1], fSamples[8 + 1]
);
pairedBox.finalize(clippingBox, fColorAndWeight);
#else
FFX_UNROLL
for (FfxInt32 row = 0; row < 3; row++) {
FFX_UNROLL
@ -172,6 +440,7 @@ FfxFloat32x4 ComputeUpsampledColorAndWeight(const AccumulationPassCommonParams p
}
}
}
#endif
RectificationBoxComputeVarianceBoxData(clippingBox);

31
Shaders/shaders/fsr3upscaler/ffx_fsr3upscaler_accumulate.h

@ -46,27 +46,26 @@ void RectifyHistory(
FFX_PARAMETER_INOUT AccumulationPassData data
)
{
const FfxFloat32 fVecolityFactor = ffxSaturate(params.f4KVelocity / 20.0f);
const FfxFloat32 f4kVelocityFactor = ffxSaturate(params.f4KVelocity / 20.0f);
const FfxFloat32 fDistanceFactor = ffxSaturate(0.75f - params.fFarthestDepthInMeters / 20.0f);
const FfxFloat32 fAccumulationFactor = 1.0f - params.fAccumulation;
const FfxFloat32 fReactiveFactor = ffxPow(params.fReactiveMask, 1.0f / 2.0f);
const FfxFloat32 fShadingChangeFactor = params.fShadingChange;
const FfxFloat32 fBoxScaleT = ffxMax(fVecolityFactor, ffxMax(fDistanceFactor, ffxMax(fAccumulationFactor, ffxMax(fReactiveFactor, fShadingChangeFactor))));
const FfxFloat32 fBoxScaleT = ffxMax(f4kVelocityFactor, ffxMax(fDistanceFactor, ffxMax(fAccumulationFactor, ffxMax(fReactiveFactor, fShadingChangeFactor))));
const FfxFloat32 fBoxScale = ffxLerp(3.0f, 1.0f, fBoxScaleT);
const FfxFloat32 fBoxScale = ffxLerp(3.0f, 1.0f, fBoxScaleT);
const FfxFloat32x3 fScaledBoxVec = data.clippingBox.boxVec * FfxFloat32x3(1.7f, 1.0f, 1.0f) * fBoxScale;
const FfxFloat32x3 fScaledBoxVec = data.clippingBox.boxVec * fBoxScale;
const FfxFloat32x3 fBoxMin = data.clippingBox.boxCenter - fScaledBoxVec;
const FfxFloat32x3 fBoxMax = data.clippingBox.boxCenter + fScaledBoxVec;
const FfxFloat32x3 fClampedScaledBoxVec = ffxMax(fScaledBoxVec, FfxFloat32x3(1.193e-7f, 1.193e-7f, 1.193e-7f));
const FfxFloat32x3 fTransformedHistoryColor = (data.fHistoryColor - data.clippingBox.boxCenter) / fClampedScaledBoxVec;
if (any(FFX_GREATER_THAN(fBoxMin, data.fHistoryColor)) || any(FFX_GREATER_THAN(data.fHistoryColor, fBoxMax))) {
const FfxFloat32x3 fClampedHistoryColor = clamp(data.fHistoryColor, fBoxMin, fBoxMax);
const FfxFloat32 fHistoryContribution = ffxMax(params.fLumaInstabilityFactor, data.fLockContributionThisFrame) * params.fAccumulation * (1 - params.fDisocclusion);
if (length(fTransformedHistoryColor)>1.f) {
const FfxFloat32x3 fClampedHistoryColor = normalize(fTransformedHistoryColor);
const FfxFloat32x3 fFinalClampedHistoryColor = (fClampedHistoryColor * fScaledBoxVec) + data.clippingBox.boxCenter;
// Scale history color using rectification info, also using accumulation mask to avoid potential invalid color protection
data.fHistoryColor = ffxLerp(fClampedHistoryColor, data.fHistoryColor, ffxSaturate(fHistoryContribution));
const FfxFloat32 fHistoryContribution = ffxMax(params.fLumaInstabilityFactor, data.fLockContributionThisFrame) * params.fAccumulation * (1 - params.fDisocclusion);
data.fHistoryColor = ffxLerp(fFinalClampedHistoryColor, data.fHistoryColor, ffxSaturate(fHistoryContribution));
}
}
@ -80,7 +79,7 @@ void UpdateLockStatus(AccumulationPassCommonParams params, FFX_PARAMETER_INOUT A
// Compute this frame lock contribution
data.fLockContributionThisFrame = ffxSaturate(ffxSaturate(data.fLock - fLockThreshold) * (fLockMax - fLockThreshold));
const FfxFloat32 fNewLockIntensity = LoadRwNewLocks(params.iPxHrPos) * (1.0f - ffxMax(params.fShadingChange * 0, params.fReactiveMask));
const FfxFloat32 fNewLockIntensity = LoadNewLocks(params.iPxHrPos) * (1.0f - ffxMax(params.fShadingChange * 0, params.fReactiveMask));
data.fLock = ffxMax(0.0f, ffxMin(data.fLock + fNewLockIntensity, fLockMax));
// Preparing for next frame
@ -97,7 +96,7 @@ void ComputeBaseAccumulationWeight(const AccumulationPassCommonParams params, FF
{
FfxFloat32 fBaseAccumulation = params.fAccumulation;
fBaseAccumulation = ffxMin(fBaseAccumulation, ffxLerp(fBaseAccumulation, 0.15f, ffxSaturate(ffxMax(0.0f, params.f4KVelocity / 0.5f))));
fBaseAccumulation = ffxMin(fBaseAccumulation, ffxLerp(fBaseAccumulation, 0.15f, ffxSaturate(ffxMax(0.0f, (params.f4KVelocity * VelocityFactor()) / 0.5f))));
data.fHistoryWeight = fBaseAccumulation;
}
@ -162,11 +161,13 @@ void Accumulate(FfxInt32x2 iPxHrPos)
data.fHistoryColor /= Exposure();
data.fHistoryColor = ffxMax(data.fHistoryColor, FfxFloat32x3(0.0f, 0.0f, 0.0f));
StoreInternalColorAndWeight(iPxHrPos, FfxFloat32x4(data.fHistoryColor, data.fLock));
// Output final color when RCAS is disabled
#if FFX_FSR3UPSCALER_OPTION_APPLY_SHARPENING == 0
StoreUpscaledOutput(iPxHrPos, data.fHistoryColor);
#endif
StoreNewLocks(iPxHrPos, 0);
//StoreNewLocks(iPxHrPos, 0);
}

106
Shaders/shaders/fsr3upscaler/ffx_fsr3upscaler_callbacks_hlsl.h

@ -75,12 +75,18 @@ cbuffer cbFSR3Upscaler : FFX_FSR3UPSCALER_DECLARE_CB(FSR3UPSCALER_BIND_CB_FSR3UP
FfxFloat32 fDeltaPreExposure;
FfxFloat32 fViewSpaceToMetersFactor;
FfxFloat32 fFrameIndex;
FfxFloat32 fVelocityFactor;
FfxFloat32 fReactivenessScale;
FfxFloat32 fShadingChangeScale;
FfxFloat32 fAccumulationAddedPerFrame;
FfxFloat32 fMinDisocclusionAccumulation;
};
#define FFX_FSR3UPSCALER_CONSTANT_BUFFER_1_SIZE (sizeof(cbFSR3Upscaler) / 4) // Number of 32-bit values. This must be kept in sync with the cbFSR3Upscaler size.
/* Define getter functions in the order they are defined in the CB! */
FfxInt32x2 RenderSize()
FfxUInt32x2 RenderSize()
{
return iRenderSize;
}
@ -170,6 +176,21 @@ FfxFloat32 FrameIndex()
return fFrameIndex;
}
FfxFloat32 VelocityFactor()
{
return fVelocityFactor;
}
FfxFloat32 AccumulationAddedPerFrame()
{
return fAccumulationAddedPerFrame;
}
FfxFloat32 MinDisocclusionAccumulation()
{
return fMinDisocclusionAccumulation;
}
#endif // #if defined(FSR3UPSCALER_BIND_CB_FSR3UPSCALER)
#define FFX_FSR3UPSCALER_ROOTSIG_STRINGIFY(p) FFX_FSR3UPSCALER_ROOTSIG_STR(p)
@ -319,23 +340,6 @@ FfxUInt32x2 SPD_RenderSize()
}
#endif // #if defined(FSR3UPSCALER_BIND_CB_SPD)
// Declare and sample camera buffers as regular textures, unless overridden
#if !defined(UNITY_FSR_TEX2D)
#define UNITY_FSR_TEX2D(type) Texture2D<type>
#endif
#if !defined(UNITY_FSR_RWTEX2D)
#define UNITY_FSR_RWTEX2D(type) RWTexture2D<type>
#endif
#if !defined(UNITY_FSR_POS)
#define UNITY_FSR_POS(pxPos) (pxPos)
#endif
#if !defined(UNITY_FSR_UV)
#define UNITY_FSR_UV(uv) (uv)
#endif
#if !defined(UNITY_FSR_GETDIMS)
#define UNITY_FSR_GETDIMS(tex, w, h) (tex).GetDimensions((w), (h))
#endif
SamplerState s_PointClamp : register(s0);
SamplerState s_LinearClamp : register(s1);
@ -359,85 +363,85 @@ FfxFloat32x2 SampleSPDMipLevel(FfxFloat32x2 fUV, FfxUInt32 mipLevel)
#endif
#if defined(FSR3UPSCALER_BIND_SRV_INPUT_DEPTH)
UNITY_FSR_TEX2D(FfxFloat32) r_input_depth : FFX_FSR3UPSCALER_DECLARE_SRV(FSR3UPSCALER_BIND_SRV_INPUT_DEPTH);
TYPED_TEXTURE2D_X(FfxFloat32, r_input_depth) : FFX_FSR3UPSCALER_DECLARE_SRV(FSR3UPSCALER_BIND_SRV_INPUT_DEPTH);
FfxFloat32 LoadInputDepth(FfxUInt32x2 iPxPos)
{
return r_input_depth[UNITY_FSR_POS(iPxPos)];
return r_input_depth[COORD_TEXTURE2D_X(iPxPos)];
}
FfxFloat32 SampleInputDepth(FfxFloat32x2 fUV)
{
return r_input_depth.SampleLevel(s_LinearClamp, UNITY_FSR_UV(fUV), 0).x;
return SAMPLE_TEXTURE2D_X_LOD(r_input_depth, s_LinearClamp, fUV, 0).x;
}
#endif
#if defined(FSR3UPSCALER_BIND_SRV_REACTIVE_MASK)
UNITY_FSR_TEX2D(FfxFloat32) r_reactive_mask : FFX_FSR3UPSCALER_DECLARE_SRV(FSR3UPSCALER_BIND_SRV_REACTIVE_MASK);
TYPED_TEXTURE2D_X(FfxFloat32, r_reactive_mask) : FFX_FSR3UPSCALER_DECLARE_SRV(FSR3UPSCALER_BIND_SRV_REACTIVE_MASK);
FfxFloat32 LoadReactiveMask(FfxUInt32x2 iPxPos)
{
return r_reactive_mask[UNITY_FSR_POS(iPxPos)];
return r_reactive_mask[COORD_TEXTURE2D_X(iPxPos)] * fReactivenessScale;
}
FfxInt32x2 GetReactiveMaskResourceDimensions()
{
FfxUInt32 uWidth;
FfxUInt32 uHeight;
UNITY_FSR_GETDIMS(r_reactive_mask, uWidth, uHeight);
GET_TEXTURE2D_X_SIZE(r_reactive_mask, uWidth, uHeight);
return FfxInt32x2(uWidth, uHeight);
}
FfxFloat32 SampleReactiveMask(FfxFloat32x2 fUV)
{
return r_reactive_mask.SampleLevel(s_LinearClamp, UNITY_FSR_UV(fUV), 0).x;
return SAMPLE_TEXTURE2D_X_LOD(r_reactive_mask, s_LinearClamp, fUV, 0).x * fReactivenessScale;
}
#endif
#if defined(FSR3UPSCALER_BIND_SRV_TRANSPARENCY_AND_COMPOSITION_MASK)
UNITY_FSR_TEX2D(FfxFloat32) r_transparency_and_composition_mask : FFX_FSR3UPSCALER_DECLARE_SRV(FSR3UPSCALER_BIND_SRV_TRANSPARENCY_AND_COMPOSITION_MASK);
TYPED_TEXTURE2D_X(FfxFloat32, r_transparency_and_composition_mask) : FFX_FSR3UPSCALER_DECLARE_SRV(FSR3UPSCALER_BIND_SRV_TRANSPARENCY_AND_COMPOSITION_MASK);
FfxFloat32 LoadTransparencyAndCompositionMask(FfxUInt32x2 iPxPos)
{
return r_transparency_and_composition_mask[UNITY_FSR_POS(iPxPos)];
return r_transparency_and_composition_mask[COORD_TEXTURE2D_X(iPxPos)];
}
FfxInt32x2 GetTransparencyAndCompositionMaskResourceDimensions()
{
FfxUInt32 uWidth;
FfxUInt32 uHeight;
UNITY_FSR_GETDIMS(r_transparency_and_composition_mask, uWidth, uHeight);
GET_TEXTURE2D_X_SIZE(r_transparency_and_composition_mask, uWidth, uHeight);
return FfxInt32x2(uWidth, uHeight);
}
FfxFloat32 SampleTransparencyAndCompositionMask(FfxFloat32x2 fUV)
{
return r_transparency_and_composition_mask.SampleLevel(s_LinearClamp, UNITY_FSR_UV(fUV), 0).x;
return SAMPLE_TEXTURE2D_X_LOD(r_transparency_and_composition_mask, s_LinearClamp, fUV, 0).x;
}
#endif
#if defined(FSR3UPSCALER_BIND_SRV_INPUT_COLOR)
UNITY_FSR_TEX2D(FfxFloat32x4) r_input_color_jittered : FFX_FSR3UPSCALER_DECLARE_SRV(FSR3UPSCALER_BIND_SRV_INPUT_COLOR);
TYPED_TEXTURE2D_X(FfxFloat32x4, r_input_color_jittered) : FFX_FSR3UPSCALER_DECLARE_SRV(FSR3UPSCALER_BIND_SRV_INPUT_COLOR);
FfxFloat32x3 LoadInputColor(FfxUInt32x2 iPxPos)
{
return r_input_color_jittered[UNITY_FSR_POS(iPxPos)].rgb;
return r_input_color_jittered[COORD_TEXTURE2D_X(iPxPos)].rgb;
}
FfxFloat32x3 SampleInputColor(FfxFloat32x2 fUV)
{
return r_input_color_jittered.SampleLevel(s_LinearClamp, UNITY_FSR_UV(fUV), 0).rgb;
return SAMPLE_TEXTURE2D_X_LOD(r_input_color_jittered, s_LinearClamp, fUV, 0).rgb;
}
#endif
#if defined(FSR3UPSCALER_BIND_SRV_INPUT_MOTION_VECTORS)
UNITY_FSR_TEX2D(FfxFloat32x4) r_input_motion_vectors : FFX_FSR3UPSCALER_DECLARE_SRV(FSR3UPSCALER_BIND_SRV_INPUT_MOTION_VECTORS);
TYPED_TEXTURE2D_X(FfxFloat32x4, r_input_motion_vectors) : FFX_FSR3UPSCALER_DECLARE_SRV(FSR3UPSCALER_BIND_SRV_INPUT_MOTION_VECTORS);
FfxFloat32x2 LoadInputMotionVector(FfxUInt32x2 iPxDilatedMotionVectorPos)
{
FfxFloat32x2 fSrcMotionVector = r_input_motion_vectors[UNITY_FSR_POS(iPxDilatedMotionVectorPos)].xy;
FfxFloat32x2 fSrcMotionVector = r_input_motion_vectors[COORD_TEXTURE2D_X(iPxDilatedMotionVectorPos)].xy;
FfxFloat32x2 fUvMotionVector = fSrcMotionVector * MotionVectorScale();
@ -515,11 +519,11 @@ void StoreInternalColorAndWeight(FfxUInt32x2 iPxPos, FfxFloat32x4 fColorAndWeigh
#endif
#if defined(FSR3UPSCALER_BIND_UAV_UPSCALED_OUTPUT)
UNITY_FSR_RWTEX2D(FfxFloat32x4) rw_upscaled_output : FFX_FSR3UPSCALER_DECLARE_UAV(FSR3UPSCALER_BIND_UAV_UPSCALED_OUTPUT);
RW_TEXTURE2D_X(FfxFloat32x4, rw_upscaled_output) : FFX_FSR3UPSCALER_DECLARE_UAV(FSR3UPSCALER_BIND_UAV_UPSCALED_OUTPUT);
void StoreUpscaledOutput(FfxUInt32x2 iPxPos, FfxFloat32x3 fColor)
{
rw_upscaled_output[UNITY_FSR_POS(iPxPos)] = FfxFloat32x4(fColor, 1.f);
rw_upscaled_output[COORD_TEXTURE2D_X(iPxPos)] = FfxFloat32x4(fColor, 1.f);
}
#endif
@ -546,12 +550,12 @@ Texture2D<FfxFloat32> r_shading_change : FFX_FSR3UPSCALER_DECLARE_SRV(FSR3UPSCAL
FfxFloat32 LoadShadingChange(FfxUInt32x2 iPxPos)
{
return r_shading_change[iPxPos];
return r_shading_change[iPxPos] * fShadingChangeScale;
}
FfxFloat32 SampleShadingChange(FfxFloat32x2 fUV)
{
return r_shading_change.SampleLevel(s_LinearClamp, fUV, 0);
return r_shading_change.SampleLevel(s_LinearClamp, fUV, 0) * fShadingChangeScale;
}
#endif
@ -788,9 +792,15 @@ FfxFloat32 Exposure()
{
FfxFloat32 exposure = r_input_exposure[FfxUInt32x2(0, 0)].x;
#if defined(__XBOX_SCARLETT)
if (exposure < 0.000030517578/** 2^-15 */) {
exposure = 1.0f;
}
#else
if (exposure == 0.0f) {
exposure = 1.0f;
}
#endif // #if defined(__XBOX_SCARLETT)
return exposure;
}
@ -830,11 +840,11 @@ void StoreDilatedReactiveMasks(FFX_PARAMETER_IN FfxUInt32x2 iPxPos, FFX_PARAMETE
#endif
#if defined(FSR3UPSCALER_BIND_SRV_INPUT_OPAQUE_ONLY)
UNITY_FSR_TEX2D(FfxFloat32x4) r_input_opaque_only : FFX_FSR3UPSCALER_DECLARE_SRV(FSR3UPSCALER_BIND_SRV_INPUT_OPAQUE_ONLY);
TYPED_TEXTURE2D_X(FfxFloat32x4, r_input_opaque_only) : FFX_FSR3UPSCALER_DECLARE_SRV(FSR3UPSCALER_BIND_SRV_INPUT_OPAQUE_ONLY);
FfxFloat32x3 LoadOpaqueOnly(FFX_PARAMETER_IN FFX_MIN16_I2 iPxPos)
{
return r_input_opaque_only[UNITY_FSR_POS(iPxPos)].xyz;
return r_input_opaque_only[COORD_TEXTURE2D_X(iPxPos)].xyz;
}
#endif
@ -916,14 +926,18 @@ FfxFloat32x4 FrameInfo()
defined(FSR3UPSCALER_BIND_UAV_SPD_MIPS_LEVEL_2) && \
defined(FSR3UPSCALER_BIND_UAV_SPD_MIPS_LEVEL_3) && \
defined(FSR3UPSCALER_BIND_UAV_SPD_MIPS_LEVEL_4) && \
defined(FSR3UPSCALER_BIND_UAV_SPD_MIPS_LEVEL_5)
(defined(FSR3UPSCALER_BIND_UAV_SPD_MIPS_LEVEL_5) || defined(SHADER_API_GLCORE))
RWTexture2D<FfxFloat32x2> rw_spd_mip0 : FFX_DECLARE_UAV(FSR3UPSCALER_BIND_UAV_SPD_MIPS_LEVEL_0);
RWTexture2D<FfxFloat32x2> rw_spd_mip1 : FFX_DECLARE_UAV(FSR3UPSCALER_BIND_UAV_SPD_MIPS_LEVEL_1);
RWTexture2D<FfxFloat32x2> rw_spd_mip2 : FFX_DECLARE_UAV(FSR3UPSCALER_BIND_UAV_SPD_MIPS_LEVEL_2);
RWTexture2D<FfxFloat32x2> rw_spd_mip3 : FFX_DECLARE_UAV(FSR3UPSCALER_BIND_UAV_SPD_MIPS_LEVEL_3);
#ifdef SHADER_API_GLCORE
globallycoherent RWTexture2D<FfxFloat32x2> rw_spd_mip4 : FFX_DECLARE_UAV(FSR3UPSCALER_BIND_UAV_SPD_MIPS_LEVEL_4);
#else
RWTexture2D<FfxFloat32x2> rw_spd_mip4 : FFX_DECLARE_UAV(FSR3UPSCALER_BIND_UAV_SPD_MIPS_LEVEL_4);
globallycoherent RWTexture2D<FfxFloat32x2> rw_spd_mip5 : FFX_DECLARE_UAV(FSR3UPSCALER_BIND_UAV_SPD_MIPS_LEVEL_5);
#endif
FfxFloat32x2 RWLoadPyramid(FFX_PARAMETER_IN FfxInt32x2 iPxPos, FFX_PARAMETER_IN FfxUInt32 index)
{
@ -937,7 +951,9 @@ FfxFloat32x2 RWLoadPyramid(FFX_PARAMETER_IN FfxInt32x2 iPxPos, FFX_PARAMETER_IN
LOAD(2);
LOAD(3);
LOAD(4);
#ifndef SHADER_API_GLCORE
LOAD(5);
#endif
return 0;
@ -957,23 +973,25 @@ void StorePyramid(FFX_PARAMETER_IN FfxInt32x2 iPxPos, FFX_PARAMETER_IN FfxFloat3
STORE(2);
STORE(3);
STORE(4);
#ifndef SHADER_API_GLCORE
STORE(5);
#endif
#undef STORE
}
#endif
#if defined FSR3UPSCALER_BIND_UAV_SPD_GLOBAL_ATOMIC
globallycoherent RWTexture2D<FfxUInt32> rw_spd_global_atomic : FFX_FSR3UPSCALER_DECLARE_UAV(FSR3UPSCALER_BIND_UAV_SPD_GLOBAL_ATOMIC);
globallycoherent RWStructuredBuffer<FfxUInt32> rw_spd_global_atomic : FFX_FSR3UPSCALER_DECLARE_UAV(FSR3UPSCALER_BIND_UAV_SPD_GLOBAL_ATOMIC);
void SPD_IncreaseAtomicCounter(inout FfxUInt32 spdCounter)
{
InterlockedAdd(rw_spd_global_atomic[FfxInt32x2(0, 0)], 1, spdCounter);
InterlockedAdd(rw_spd_global_atomic[0], 1, spdCounter);
}
void SPD_ResetAtomicCounter()
{
rw_spd_global_atomic[FfxInt32x2(0, 0)] = 0;
rw_spd_global_atomic[0] = 0;
}
#endif

4
Shaders/shaders/fsr3upscaler/ffx_fsr3upscaler_common.h

@ -49,7 +49,7 @@ FFX_STATIC const FfxFloat32 fAverageLanczosWeightPerFrame = 0.74f * fUpsampleL
FFX_STATIC const FfxFloat32 fAccumulationMaxOnMotion = 3.0f * fUpsampleLanczosWeightScale;
#define SHADING_CHANGE_SET_SIZE 5
FFX_STATIC const FfxInt32 iShadingChangeMipStart = 0;
FFX_STATIC const FfxUInt32 iShadingChangeMipStart = 0;
FFX_STATIC const FfxFloat32 fShadingChangeSamplePow = 1.0f / 1.0f;
@ -99,7 +99,7 @@ FfxFloat32 SceneAverageLuma()
#endif
// Auto exposure
FFX_STATIC const FfxFloat32 resetAutoExposureAverageSmoothing = 1e8f;
FFX_STATIC const FfxFloat32 resetAutoExposureAverageSmoothing = 1e4f;
struct AccumulationPassCommonParams
{

14
Shaders/shaders/fsr3upscaler/ffx_fsr3upscaler_luma_pyramid.h

@ -20,7 +20,7 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
FFX_GROUPSHARED FfxUInt32 spdCounter;
FFX_GROUPSHARED FfxUInt32 spdCounter = 0u;
void SpdIncreaseAtomicCounter(FfxUInt32 slice)
{
@ -47,6 +47,12 @@ FFX_STATIC const FfxInt32 LOG_LUMA = 0;
FFX_STATIC const FfxInt32 LUMA = 1;
FFX_STATIC const FfxInt32 DEPTH_IN_METERS = 2;
#ifdef SHADER_API_GLCORE
FFX_STATIC const FfxUInt32 MAX_MIP = 4;
#else
FFX_STATIC const FfxUInt32 MAX_MIP = 5;
#endif
FfxFloat32x4 SpdLoadSourceImage(FfxFloat32x2 iPxPos, FfxUInt32 slice)
{
//We assume linear data. if non-linear input (sRGB, ...),
@ -67,7 +73,7 @@ FfxFloat32x4 SpdLoadSourceImage(FfxFloat32x2 iPxPos, FfxUInt32 slice)
FfxFloat32x4 SpdLoad(FfxInt32x2 tex, FfxUInt32 slice)
{
return FfxFloat32x4(RWLoadPyramid(tex, 5), 0, 0);
return FfxFloat32x4(RWLoadPyramid(tex, MAX_MIP), 0, 0);
}
FfxFloat32x4 SpdReduce4(FfxFloat32x4 v0, FfxFloat32x4 v1, FfxFloat32x4 v2, FfxFloat32x4 v3)
@ -77,7 +83,7 @@ FfxFloat32x4 SpdReduce4(FfxFloat32x4 v0, FfxFloat32x4 v1, FfxFloat32x4 v2, FfxFl
void SpdStore(FfxInt32x2 pix, FfxFloat32x4 outValue, FfxUInt32 index, FfxUInt32 slice)
{
if (index == 5)
if (index == MAX_MIP)
{
StorePyramid(pix, outValue.xy, index);
}
@ -89,7 +95,7 @@ void SpdStore(FfxInt32x2 pix, FfxFloat32x4 outValue, FfxUInt32 index, FfxUInt32
if (all(FFX_EQUAL(pix, FfxInt32x2(0, 0))))
{
FfxFloat32x4 frameInfo = LoadFrameInfo();
FfxFloat32x4 frameInfo = FrameInfo();
const FfxFloat32 fSceneAvgLuma = outValue[LUMA];
const FfxFloat32 fPrevLogLuma = frameInfo[FRAME_INFO_LOG_LUMA];
FfxFloat32 fLogLuma = outValue[LOG_LUMA];

27
Shaders/shaders/fsr3upscaler/ffx_fsr3upscaler_prepare_reactivity.h

@ -140,8 +140,10 @@ FfxFloat32 ComputeThinFeatureConfidence(FfxInt32x2 iPxPos)
FfxFloat32 fLumaMin = FSR3UPSCALER_FP32_MAX;
FfxFloat32 fLumaMax = FSR3UPSCALER_FP32_MIN;
FfxInt32 iSampleIndex;
FFX_UNROLL
for (FfxInt32 iSampleIndex = 0; iSampleIndex < iSampleCount; ++iSampleIndex) {
for (iSampleIndex = 0; iSampleIndex < iSampleCount; ++iSampleIndex) {
const FfxInt32x2 iPxSamplePos = ClampLoad(iPxPos, iSampleOffsets[iSampleIndex], FfxInt32x2(RenderSize()));
fSamples[iSampleIndex] = LoadCurrentLuma(iPxSamplePos) * Exposure();
@ -167,7 +169,7 @@ FfxFloat32 ComputeThinFeatureConfidence(FfxInt32x2 iPxPos)
FfxInt32 iBitIndex = 1;
FFX_UNROLL
for (FfxInt32 iSampleIndex = 1; iSampleIndex < iSampleCount; ++iSampleIndex, ++iBitIndex) {
for (iSampleIndex = 1; iSampleIndex < iSampleCount; ++iSampleIndex, ++iBitIndex) {
const FfxFloat32 fDifference = abs(fSamples[iSampleIndex] - fSamples[iNucleusIndex]) / (fLumaMax - fLumaMin);
@ -190,7 +192,7 @@ FfxFloat32 ComputeThinFeatureConfidence(FfxInt32x2 iPxPos)
}
FFX_UNROLL
for (FfxInt32 i = 0; i < uNumRejectionMasks; i++)
for (FfxUInt32 i = 0; i < uNumRejectionMasks; i++)
{
if ((uPatternMask & uRejectionMasks[i]) == uRejectionMasks[i])
{
@ -210,15 +212,28 @@ FfxFloat32 UpdateAccumulation(FfxInt32x2 iPxPos, FfxFloat32x2 fUv, FfxFloat32x2
const FfxFloat32x2 fReprojectedUv_HW = ClampUv(fReprojectedUv, PreviousFrameRenderSize(), MaxRenderSize());
fAccumulation = ffxSaturate(SampleAccumulation(fReprojectedUv_HW));
}
const FfxFloat32 fAccumulationAddedPerFrame= AccumulationAddedPerFrame(); //default is 0.333
// Assume at frame N+0 fShadingChange is 1.0, and all subsequent frames fShadingChange is 0.0 and fDisocclusion is 0.0. Then,
// frame N+0 fAccumulation will be 0.000
// frame N+2 fAccumulation will be 0.000 + 0.333 * 1 == 0.333
// frame N+3 fAccumulation will be 0.000 + 0.333 * 2 == 0.666
// frame N+4 fAccumulation will be 0.000 + 0.333 * 3 == 0.999
fAccumulation = ffxLerp(fAccumulation, 0.0f, fShadingChange);
fAccumulation = ffxLerp(fAccumulation, ffxMin(fAccumulation, 0.25f), fDisocclusion);
const FfxFloat32 fMinDisocclusionAccumulation = MinDisocclusionAccumulation(); //default is -0.333
// Assume at frame N+0 fDisocclusion is 1.0, and all subsequent frames fShadingChange is 0.0 and fDisocclusion is 0.0. Then,
// frame N+0 fAccumulation will be -0.333f (but normalized to store in unorm)
// frame N+1 fAccumulation will be -0.333f + 0.333 * 1 == 0.000
// frame N+2 fAccumulation will be -0.333f + 0.333 * 2 == 0.333
// frame N+3 fAccumulation will be -0.333f + 0.333 * 3 == 0.666
// frame N+4 fAccumulation will be -0.333f + 0.333 * 4 == 0.999
fAccumulation = ffxLerp(fAccumulation, ffxMin(fMinDisocclusionAccumulation, fAccumulation), fDisocclusion);
fAccumulation *= FfxFloat32(round(fAccumulation * 100.0f) > 1.0f);
// Update for next frame, normalize to store in unorm
const FfxFloat32 fAccumulatedFramesMax = 3.0f;
const FfxFloat32 fAccumulatedFramesToStore = ffxSaturate(fAccumulation + (1.0f / fAccumulatedFramesMax));
const FfxFloat32 fAccumulatedFramesToStore = ffxSaturate(fAccumulation + fAccumulationAddedPerFrame);
StoreAccumulation(iPxPos, fAccumulatedFramesToStore);
return fAccumulation;

77
Shaders/shaders/fsr3upscaler/ffx_fsr3upscaler_rcas.h

@ -25,38 +25,82 @@
#include "../ffx_core.h"
#if FFX_HALF && defined(__XBOX_SCARLETT) && defined(__XBATG_EXTRA_16_BIT_OPTIMISATION) && (__XBATG_EXTRA_16_BIT_OPTIMISATION == 1)
#define FSR_RCAS_PREFER_PAIRED_VERSION 1
#else
#define FSR_RCAS_PREFER_PAIRED_VERSION 0
#endif
void WriteUpscaledOutput(FFX_MIN16_U2 iPxHrPos, FfxFloat32x3 fUpscaledColor)
{
StoreUpscaledOutput(FFX_MIN16_I2(iPxHrPos), fUpscaledColor);
}
#define FSR_RCAS_F 1
FfxFloat32x4 FsrRcasLoadF(FfxInt32x2 p)
{
FfxFloat32x4 fColor = LoadRCAS_Input(p);
#if FSR_RCAS_PREFER_PAIRED_VERSION
#define FSR_RCAS_HX2 1
FfxFloat16x4 FsrRcasLoadHx2(FfxInt16x2 p)
{
return FfxFloat16x4(LoadRCAS_Input(p));
}
void FsrRcasInputHx2(inout FfxFloat16x2 r, inout FfxFloat16x2 g, inout FfxFloat16x2 b)
{
FfxFloat32 e = Exposure();
r = FfxFloat16x2(r * e);
g = FfxFloat16x2(g * e);
b = FfxFloat16x2(b * e);
}
fColor.rgb *= Exposure();
#include "../fsr1/ffx_fsr1.h"
return fColor;
}
void FsrRcasInputF(inout FfxFloat32 r, inout FfxFloat32 g, inout FfxFloat32 b) {}
void CurrFilterPaired(FFX_MIN16_U2 pos)
{
FfxFloat16x2 cr;
FfxFloat16x2 cg;
FfxFloat16x2 cb;
FsrRcasHx2(cr, cg, cb, pos, RCASConfig());
FfxFloat32 InvExposure = 1.0f / Exposure();
cr = FfxFloat16x2(cr * InvExposure);
cg = FfxFloat16x2(cg * InvExposure);
cb = FfxFloat16x2(cb * InvExposure);
WriteUpscaledOutput(pos, FfxFloat16x3(cr.x, cg.x, cb.x)); //TODO: fix type
pos.x += 8;
WriteUpscaledOutput(pos, FfxFloat16x3(cr.y, cg.y, cb.y)); //TODO: fix type
}
#else
#define FSR_RCAS_F 1
FfxFloat32x4 FsrRcasLoadF(FfxInt32x2 p)
{
FfxFloat32x4 fColor = LoadRCAS_Input(p);
#include "../fsr1/ffx_fsr1.h"
fColor.rgb *= Exposure();
void CurrFilter(FFX_MIN16_U2 pos)
{
FfxFloat32x3 c;
FsrRcasF(c.r, c.g, c.b, pos, RCASConfig());
return fColor;
}
void FsrRcasInputF(inout FfxFloat32 r, inout FfxFloat32 g, inout FfxFloat32 b) {}
c /= Exposure();
#include "../fsr1/ffx_fsr1.h"
WriteUpscaledOutput(pos, c);
}
void CurrFilter(FFX_MIN16_U2 pos)
{
FfxFloat32x3 c;
FsrRcasF(c.r, c.g, c.b, pos, RCASConfig());
c /= Exposure();
WriteUpscaledOutput(pos, c);
}
#endif // #if FSR_RCAS_PREFER_PAIRED_VERSION
void RCAS(FfxUInt32x3 LocalThreadId, FfxUInt32x3 WorkGroupId, FfxUInt32x3 Dtid)
{
// Do remapping of local xy in workgroup for a more PS-like swizzle pattern.
FfxUInt32x2 gxy = ffxRemapForQuad(LocalThreadId.x) + FfxUInt32x2(WorkGroupId.x << 4u, WorkGroupId.y << 4u);
#if FSR_RCAS_PREFER_PAIRED_VERSION
CurrFilterPaired(FFX_MIN16_U2(gxy));
gxy.y += 8u;
CurrFilterPaired(FFX_MIN16_U2(gxy));
#else
CurrFilter(FFX_MIN16_U2(gxy));
gxy.x += 8u;
CurrFilter(FFX_MIN16_U2(gxy));
@ -64,4 +108,5 @@ void RCAS(FfxUInt32x3 LocalThreadId, FfxUInt32x3 WorkGroupId, FfxUInt32x3 Dtid)
CurrFilter(FFX_MIN16_U2(gxy));
gxy.x -= 8u;
CurrFilter(FFX_MIN16_U2(gxy));
#endif
}

15
Shaders/shaders/fsr3upscaler/ffx_fsr3upscaler_reproject.h

@ -32,6 +32,16 @@ FfxFloat32x4 WrapHistory(FfxInt32x2 iPxSample)
DeclareCustomFetchBicubicSamples(FetchHistorySamples, WrapHistory)
DeclareCustomTextureSample(HistorySample, FFX_FSR3UPSCALER_GET_LANCZOS_SAMPLER1D(FFX_FSR3UPSCALER_OPTION_REPROJECT_USE_LANCZOS_TYPE), FetchHistorySamples)
#if FFX_HALF
FFX_MIN16_F4 WrapHistory16(FfxInt32x2 iPxSample)
{
return FFX_MIN16_F4(LoadHistory(iPxSample));
}
DeclareCustomFetchBicubicSamplesMin16(FetchHistorySamples16, WrapHistory16)
DeclareCustomTextureSampleMin16(HistorySample16, FFX_FSR3UPSCALER_GET_LANCZOS_SAMPLER1D(FFX_FSR3UPSCALER_OPTION_REPROJECT_USE_LANCZOS_TYPE), FetchHistorySamples16)
#endif
FfxFloat32x2 GetMotionVector(FfxInt32x2 iPxHrPos, FfxFloat32x2 fHrUv)
{
#if FFX_FSR3UPSCALER_OPTION_LOW_RESOLUTION_MOTION_VECTORS
@ -51,8 +61,13 @@ void ComputeReprojectedUVs(const AccumulationPassCommonParams params, FFX_PARAME
}
void ReprojectHistoryColor(const AccumulationPassCommonParams params, FFX_PARAMETER_INOUT AccumulationPassData data)
{
#if FFX_HALF && FFX_FSR3UPSCALER_OPTION_REPROJECT_SAMPLERS_USE_DATA_HALF
const FfxFloat32x4 fReprojectedHistory = FfxFloat32x4(HistorySample16(params.fReprojectedHrUv, UpscaleSize()));
#else
const FfxFloat32x4 fReprojectedHistory = HistorySample(params.fReprojectedHrUv, PreviousFrameUpscaleSize());
#endif
data.fHistoryColor = fReprojectedHistory.rgb;
data.fHistoryColor *= DeltaPreExposure();

27
Shaders/shaders/fsr3upscaler/ffx_fsr3upscaler_sample.h

@ -127,7 +127,6 @@ FFX_MIN16_F4 Bilinear(FetchedBilinearSamplesMin16 BilinearSamples, FFX_MIN16_F2
FfxFloat32 Lanczos2NoClamp(FfxFloat32 x)
{
const FfxFloat32 PI = 3.141592653589793f; // TODO: share SDK constants
return abs(x) < FSR3UPSCALER_EPSILON ? 1.f : (sin(PI * x) / (PI * x)) * (sin(0.5f * PI * x) / (0.5f * PI * x));
}
@ -169,6 +168,24 @@ FFX_MIN16_F Lanczos2ApproxSqNoClamp(FFX_MIN16_F x2)
FFX_MIN16_F b = FFX_MIN16_F(1.0f / 4.0f) * x2 - FFX_MIN16_F(1);
return (FFX_MIN16_F(25.0f / 16.0f) * a * a - FFX_MIN16_F(25.0f / 16.0f - 1)) * (b * b);
}
#if defined(__XBOX_SCARLETT) && defined(__XBATG_EXTRA_16_BIT_OPTIMISATION) && (__XBATG_EXTRA_16_BIT_OPTIMISATION == 1)
FFX_MIN16_F2 PairedLanczos2ApproxSqNoClamp(FFX_MIN16_F2 x2)
{
// Xbox ATG (Pavel):
//
// 2.0 * x2 - 5.0 25.0 25.0 - 16.0 (2.0 * x2 - 5.0)^2 - (3.0)^2 (2.0 * x2 - 8.0) * (2.0 * x2 - 2.0) (x2 - 4.0) * (x2 - 1.0)
// a = -------------- ==> ---- * a^2 - -------------- = ----------------------------- = ---------------------------------- = ----------------------- = b * (x2 - 1.0)
// 5.0 16.0 16.0 16.0 16.0 4.0
//
// so we need to compute just (b * b) * (b * x2 - b), so we should get four packed instructions: 2 fma + 2 mul
//
FFX_MIN16_F2 b = (0.25 * x2 - 1.0);
return (b * b) * (b * x2 - b);
}
#endif
#endif //FFX_HALF
FfxFloat32 Lanczos2ApproxSq(FfxFloat32 x2)
@ -183,6 +200,14 @@ FFX_MIN16_F Lanczos2ApproxSq(FFX_MIN16_F x2)
x2 = ffxMin(x2, FFX_MIN16_F(4.0f));
return Lanczos2ApproxSqNoClamp(x2);
}
#if defined(__XBOX_SCARLETT) && defined(__XBATG_EXTRA_16_BIT_OPTIMISATION) && (__XBATG_EXTRA_16_BIT_OPTIMISATION == 1)
FFX_MIN16_F2 PairedLanczos2ApproxSq(FFX_MIN16_F2 x2)
{
x2 = ffxMin(x2, FFX_MIN16_F2(4.0, 4.0));
return PairedLanczos2ApproxSqNoClamp(x2);
}
#endif
#endif //FFX_HALF
FfxFloat32 Lanczos2ApproxNoClamp(FfxFloat32 x)

8
Shaders/shaders/fsr3upscaler/ffx_fsr3upscaler_shading_change_pyramid.h

@ -47,6 +47,12 @@ FFX_STATIC const FfxInt32 DIFFERENCE = 0;
FFX_STATIC const FfxInt32 SIGN_SUM = 1;
FFX_STATIC const FfxInt32 MIP0_INDICATOR = 2;
#ifdef SHADER_API_GLCORE
FFX_STATIC const FfxInt32 MAX_MIP = 4;
#else
FFX_STATIC const FfxInt32 MAX_MIP = 5;
#endif
FfxFloat32x2 Sort2(FfxFloat32x2 v)
{
return FfxFloat32x2(ffxMin(v.x, v.y), ffxMax(v.x, v.y));
@ -200,7 +206,7 @@ FfxFloat32x4 SpdLoadSourceImage(FfxFloat32x2 iPxPos, FfxUInt32 slice)
FfxFloat32x4 SpdLoad(FfxInt32x2 tex, FfxUInt32 slice)
{
return FfxFloat32x4(RWLoadPyramid(tex, 5), 0, 0);
return FfxFloat32x4(RWLoadPyramid(tex, MAX_MIP), 0, 0);
}
FfxFloat32x4 SpdReduce4(FfxFloat32x4 v0, FfxFloat32x4 v1, FfxFloat32x4 v2, FfxFloat32x4 v3)

10
Shaders/shaders/fsr3upscaler/ffx_fsr3upscaler_tcr_autogen.h

@ -189,9 +189,11 @@ FFX_MIN16_F ComputeAabbOverlap(FFX_MIN16_I2 uDispatchThreadId, FFX_MIN16_I2 iPre
#endif
FfxFloat32x3 minPrev = FFX_MIN16_F3(+1000.f, +1000.f, +1000.f);
FfxFloat32x3 maxPrev = FFX_MIN16_F3(-1000.f, -1000.f, -1000.f);
for (int y = -1; y < 2; ++y)
int x, y;
for (y = -1; y < 2; ++y)
{
for (int x = -1; x < 2; ++x)
for (x = -1; x < 2; ++x)
{
FfxFloat32x3 W = LoadPrevPostAlpha(iPrevIdx + FFX_MIN16_I2(x, y));
@ -205,9 +207,9 @@ FFX_MIN16_F ComputeAabbOverlap(FFX_MIN16_I2 uDispatchThreadId, FFX_MIN16_I2 iPre
// instead of computing the overlap: simply count how many samples are outside
// set reactive based on that
FFX_MIN16_F count = FFX_MIN16_F(0.f);
for (int y = -1; y < 2; ++y)
for (y = -1; y < 2; ++y)
{
for (int x = -1; x < 2; ++x)
for (x = -1; x < 2; ++x)
{
FfxFloat32x3 Y = LoadInputColor(uDispatchThreadId + FFX_MIN16_I2(x, y));

470
Shaders/shaders/fsr3upscaler/ffx_fsr3upscaler_upsample.h

@ -44,6 +44,26 @@ FfxFloat32 GetUpsampleLanczosWeight(FfxFloat32x2 fSrcSampleOffset, FfxFloat32 fK
return fSampleWeight;
}
#if FFX_HALF
FFX_MIN16_F GetUpsampleLanczosWeight(FFX_MIN16_F2 fSrcSampleOffset, FFX_MIN16_F fKernelWeight)
{
FFX_MIN16_F2 fSrcSampleOffsetBiased = fSrcSampleOffset * fKernelWeight.xx;
#if FFX_FSR3UPSCALER_OPTION_UPSAMPLE_USE_LANCZOS_TYPE == 0 // LANCZOS_TYPE_REFERENCE
FFX_MIN16_F fSampleWeight = Lanczos2(length(fSrcSampleOffsetBiased));
#elif FFX_FSR3UPSCALER_OPTION_UPSAMPLE_USE_LANCZOS_TYPE == 1 // LANCZOS_TYPE_LUT
FFX_MIN16_F fSampleWeight = Lanczos2_UseLUT(length(fSrcSampleOffsetBiased));
#elif FFX_FSR3UPSCALER_OPTION_UPSAMPLE_USE_LANCZOS_TYPE == 2 // LANCZOS_TYPE_APPROXIMATE
FFX_MIN16_F fSampleWeight = Lanczos2ApproxSq(dot(fSrcSampleOffsetBiased, fSrcSampleOffsetBiased));
// To Test: Save reciproqual sqrt compute
// FfxFloat32 fSampleWeight = Lanczos2Sq_UseLUT(dot(fSrcSampleOffsetBiased, fSrcSampleOffsetBiased));
#else
#error "Invalid Lanczos type"
#endif
return fSampleWeight;
}
#endif
FfxFloat32 ComputeMaxKernelWeight(const AccumulationPassCommonParams params, FFX_PARAMETER_INOUT AccumulationPassData data) {
const FfxFloat32 fKernelSizeBias = 1.0f + (1.0f / FfxFloat32x2(DownscaleFactor()) - 1.0f).x;
@ -59,6 +79,225 @@ FfxFloat32x3 LoadPreparedColor(FfxInt32x2 iSamplePos)
return fPreparedYCoCg;
}
#if FFX_HALF && (FFX_FSR3UPSCALER_OPTION_UPSAMPLE_USE_LANCZOS_TYPE == 2) && defined(__XBOX_SCARLETT) && defined(__XBATG_EXTRA_16_BIT_OPTIMISATION) && (__XBATG_EXTRA_16_BIT_OPTIMISATION == 1)
#define FFX_FSR3UPSCALER_USE_XBOX_PAIRED_16BIT_MATH_OPTIMIZATIONS 1
#else
#define FFX_FSR3UPSCALER_USE_XBOX_PAIRED_16BIT_MATH_OPTIMIZATIONS 0
#endif
#if FFX_FSR3UPSCALER_USE_XBOX_PAIRED_16BIT_MATH_OPTIMIZATIONS
void LoadPreparedColorPairedRgb(FFX_PARAMETER_OUT FFX_MIN16_F2 r,
FFX_PARAMETER_OUT FFX_MIN16_F2 g,
FFX_PARAMETER_OUT FFX_MIN16_F2 b,
FfxInt32x2 iSamplePos0,
FfxInt32x2 iSamplePos1)
{
const FFX_MIN16_F3 sample0 = FFX_MIN16_F3(LoadInputColor(iSamplePos0));
const FFX_MIN16_F3 sample1 = FFX_MIN16_F3(LoadInputColor(iSamplePos1));
r = ffxMax(FFX_MIN16_F2(0, 0), FFX_MIN16_F2(sample0.r, sample1.r));
g = ffxMax(FFX_MIN16_F2(0, 0), FFX_MIN16_F2(sample0.g, sample1.g));
b = ffxMax(FFX_MIN16_F2(0, 0), FFX_MIN16_F2(sample0.b, sample1.b));
r = FFX_MIN16_F2(r * Exposure());
g = FFX_MIN16_F2(g * Exposure());
b = FFX_MIN16_F2(b * Exposure());
}
void TonemapPaired(FFX_PARAMETER_INOUT FFX_MIN16_F2 r, FFX_PARAMETER_INOUT FFX_MIN16_F2 g, FFX_PARAMETER_INOUT FFX_MIN16_F2 b)
{
FFX_MIN16_F2 denomF16 = ffxMax(ffxMax(ffxMax(0.0, r), g), b) + FFX_MIN16_F2(1.0, 1.0);
// NOTE: expect 2 x v_cvt_f32_f16
FfxFloat32x2 denomF32 = FfxFloat32x2(denomF16);
// NOTE: expect 2 x v_rcp_f32
FfxFloat32x2 normF32 = FfxFloat32x2(1.0, 1.0) / denomF32;
// NOTE: expect 2 x v_cvt_f16_f32
FFX_MIN16_F2 normF16 = FFX_MIN16_F2(normF32);
r *= normF16;
g *= normF16;
b *= normF16;
}
void RGBToYCoCgPaired(FFX_PARAMETER_INOUT FFX_MIN16_F2 r, FFX_PARAMETER_INOUT FFX_MIN16_F2 g, FFX_PARAMETER_INOUT FFX_MIN16_F2 b)
{
/**
* NOTE: given the following conversion
*
* fYCoCg = FfxFloat32x3(
* 0.25f * fRgb.r + 0.5f * fRgb.g + 0.25f * fRgb.b,
* 0.5f * fRgb.r - 0.5f * fRgb.b,
* -0.25f * fRgb.r + 0.5f * fRgb.g - 0.25f * fRgb.b);
*
* it's possible to notice that we can compute:
* RplusBdiv4 = 0.25 * (R + B)
*
* so everything else is computed in 3 instructions
* Y = G * 0.5 + RplusBdiv4
* Co = 2 * RplusBdiv4 - G
* Cg = G * 0.5 - RplusBdiv4
*/
// NOTE: expect v_pk_add_f32 + v_pk_mul_f32
FFX_MIN16_F2 RplusBdiv4 = (r + b) * 0.25;
FFX_MIN16_F2 G = g;
FFX_MIN16_F2 B = b;
// NOTE: expect 3x v_pk_fma_f32
r = G * 0.5 + RplusBdiv4;
g = RplusBdiv4 * 2.0 - B;
b = G * 0.5 - RplusBdiv4;
}
FFX_MIN16_F2 Compute3x3SamplesMinMaxPaired(FFX_PARAMETER_IN FFX_MIN16_F2 sampleCenter,
FFX_PARAMETER_IN FFX_MIN16_F2 sample0,
FFX_PARAMETER_IN FFX_MIN16_F2 sample1,
FFX_PARAMETER_IN FFX_MIN16_F2 sample2,
FFX_PARAMETER_IN FFX_MIN16_F2 sample3)
{
FFX_MIN16_F2 twoMinValues = ffxMin(ffxMin(sample0, sample1), ffxMin(sample2, sample3));
FFX_MIN16_F2 twoMaxValues = ffxMax(ffxMax(sample0, sample1), ffxMax(sample2, sample3));
return FFX_MIN16_F2(
ffxMin3Half(twoMinValues.x, twoMinValues.y, sampleCenter.x),
ffxMax3Half(twoMaxValues.x, twoMaxValues.y, sampleCenter.x)
);
}
FFX_MIN16_F2 Bool2ToFloat16x2(bool x, bool y)
{
uint lo = x ? 0x00003c00 : 0x00000000;
uint hi = y ? 0x3c000000 : 0x00000000;
return FFX_MIN16_F2(__XB_AsHalf(lo).x, __XB_AsHalf(hi).y);
}
struct PairedRectificationBoxAndAccumulatedColorAndWeight
{
FFX_MIN16_F2 boxCenterR;
FFX_MIN16_F2 boxCenterG;
FFX_MIN16_F2 boxCenterB;
FFX_MIN16_F2 boxVecR;
FFX_MIN16_F2 boxVecG;
FFX_MIN16_F2 boxVecB;
FFX_MIN16_F2 fBoxCenterWeight;
FFX_MIN16_F2 fColorR;
FFX_MIN16_F2 fColorG;
FFX_MIN16_F2 fColorB;
FFX_MIN16_F2 fWeight;
FFX_MIN16_F fKernelBiasSq;
FFX_MIN16_F fRectificationCurveBias;
void setKernelBiasAndRectificationCurveBias(FfxFloat32 kernelBias, FfxFloat32 rectificationCurveBias)
{
fKernelBiasSq = FFX_MIN16_F(kernelBias * kernelBias);
fRectificationCurveBias = FFX_MIN16_F(rectificationCurveBias);
}
void initUpscaledColor(FFX_MIN16_F fSrcSampleOffsetSq, FFX_MIN16_F fOnScreenWeight, FFX_MIN16_F2 sampleR, FFX_MIN16_F2 sampleG, FFX_MIN16_F2 sampleB)
{
#if FFX_FSR3UPSCALER_OPTION_UPSAMPLE_USE_LANCZOS_TYPE == 2 // LANCZOS_TYPE_APPROXIMATE
const FFX_MIN16_F2 LanczosUpsampleWeight = FFX_MIN16_F2(
PairedLanczos2ApproxSq(fSrcSampleOffsetSq * fKernelBiasSq).x,
0.0
);
#else
#error "Only LANCZOS_TYPE_APPROXIMATE is supported in paired version so far"
#endif
const FFX_MIN16_F2 fSampleWeight = fOnScreenWeight * LanczosUpsampleWeight;
fColorR = sampleR * fSampleWeight;
fColorG = sampleG * fSampleWeight;
fColorB = sampleB * fSampleWeight;
fWeight = fSampleWeight;
}
void initBox(FFX_MIN16_F fSrcSampleOffsetSq, FFX_MIN16_F fOnScreenWeight, FFX_MIN16_F2 sampleR, FFX_MIN16_F2 sampleG, FFX_MIN16_F2 sampleB)
{
const FFX_MIN16_F2 fBoxSampleWeight = FFX_MIN16_F2(
exp(fRectificationCurveBias * fSrcSampleOffsetSq) * fOnScreenWeight,
0.0
);
FFX_MIN16_F2 weightedSampleR = sampleR * fBoxSampleWeight;
FFX_MIN16_F2 weightedSampleG = sampleG * fBoxSampleWeight;
FFX_MIN16_F2 weightedSampleB = sampleB * fBoxSampleWeight;
boxCenterR = weightedSampleR;
boxCenterG = weightedSampleG;
boxCenterB = weightedSampleB;
boxVecR = sampleR * weightedSampleR;
boxVecG = sampleG * weightedSampleG;
boxVecB = sampleB * weightedSampleB;
fBoxCenterWeight = fBoxSampleWeight;
}
void addUpscaledColorSample(FFX_MIN16_F2 fSrcSampleOffsetSq, FFX_MIN16_F2 fOnScreenWeight, FFX_MIN16_F2 sampleR, FFX_MIN16_F2 sampleG, FFX_MIN16_F2 sampleB)
{
#if FFX_FSR3UPSCALER_OPTION_UPSAMPLE_USE_LANCZOS_TYPE == 2 // LANCZOS_TYPE_APPROXIMATE
const FFX_MIN16_F2 LanczosUpsampleWeight = PairedLanczos2ApproxSq(fSrcSampleOffsetSq * fKernelBiasSq);
#else
#error "Only LANCZOS_TYPE_APPROXIMATE is supported in paired version so far"
#endif
const FFX_MIN16_F2 fSampleWeight = fOnScreenWeight * LanczosUpsampleWeight;
fColorR += sampleR * fSampleWeight;
fColorG += sampleG * fSampleWeight;
fColorB += sampleB * fSampleWeight;
fWeight += fSampleWeight;
}
void addBoxSample(FFX_MIN16_F2 fSrcSampleOffsetSq, FFX_MIN16_F2 fOnScreenWeight, FFX_MIN16_F2 sampleR, FFX_MIN16_F2 sampleG, FFX_MIN16_F2 sampleB)
{
// NOTE: ideally expect here 2x v_fma_mix + 2x v_exp_f32 + 2x v_fma_mix
const FFX_MIN16_F2 fBoxSampleWeight = exp(fRectificationCurveBias * fSrcSampleOffsetSq) * fOnScreenWeight;
FFX_MIN16_F2 weightedSampleR = sampleR * fBoxSampleWeight;
FFX_MIN16_F2 weightedSampleG = sampleG * fBoxSampleWeight;
FFX_MIN16_F2 weightedSampleB = sampleB * fBoxSampleWeight;
boxCenterR += weightedSampleR;
boxCenterG += weightedSampleG;
boxCenterB += weightedSampleB;
boxVecR += sampleR * weightedSampleR;
boxVecG += sampleG * weightedSampleG;
boxVecB += sampleB * weightedSampleB;
fBoxCenterWeight += fBoxSampleWeight;
}
void finalizeUpscaledColor(FFX_PARAMETER_OUT FfxFloat32x4 upscaledColorAndWeight)
{
upscaledColorAndWeight.r = fColorR.x + fColorR.y;
upscaledColorAndWeight.g = fColorG.x + fColorG.y;
upscaledColorAndWeight.b = fColorB.x + fColorB.y;
upscaledColorAndWeight.a = fWeight.x + fWeight.y;
}
void finalizeBox(FFX_PARAMETER_OUT FfxFloat32x2 boxCenterAndVecR,
FFX_PARAMETER_OUT FfxFloat32x2 boxCenterAndVecG,
FFX_PARAMETER_OUT FfxFloat32x2 boxCenterAndVecB,
FFX_PARAMETER_OUT FfxFloat32 boxCenterWeight)
{
boxCenterAndVecR = FfxFloat32x2(boxCenterR.x + boxCenterR.y, boxVecR.x + boxVecR.y);
boxCenterAndVecG = FfxFloat32x2(boxCenterG.x + boxCenterG.y, boxVecG.x + boxVecG.y);
boxCenterAndVecB = FfxFloat32x2(boxCenterB.x + boxCenterB.y, boxVecB.x + boxVecB.y);
boxCenterWeight = fBoxCenterWeight.x + fBoxCenterWeight.y;
}
};
#endif // #if FFX_FSR3UPSCALER_USE_XBOX_PAIRED_16BIT_MATH_OPTIMIZATIONS
void ComputeUpsampledColorAndWeight(const AccumulationPassCommonParams params, FFX_PARAMETER_INOUT AccumulationPassData data)
{
// We compute a sliced lanczos filter with 2 lobes (other slices are accumulated temporaly)
@ -82,13 +321,99 @@ void ComputeUpsampledColorAndWeight(const AccumulationPassCommonParams params, F
const FfxBoolean bIsInitialSample = (params.fAccumulation == 0.0f);
#if FFX_FSR3UPSCALER_USE_XBOX_PAIRED_16BIT_MATH_OPTIMIZATIONS
// Unroll the loop to load samples on Scarlett to help the shader compiler
const FFX_MIN16_F2 fSampleOffsetX02 = __XB_AsHalf(bFlipCol ? __XB_AsUInt(FFX_MIN16_F2( 1, -1)) : __XB_AsUInt(FFX_MIN16_F2(-1, 1)));
const FFX_MIN16_F2 fSampleOffsetY02 = __XB_AsHalf(bFlipRow ? __XB_AsUInt(FFX_MIN16_F2( 1, -1)) : __XB_AsUInt(FFX_MIN16_F2(-1, 1)));
typedef FfxInt32 FfxTexCoordI;
typedef FfxInt32x2 FfxTexCoordI2;
const FfxTexCoordI2 iSrcSamplePosX01 = FfxTexCoordI2(iSrcInputPos.xx) + (bFlipCol ? FfxTexCoordI2( 1, 0) : FfxTexCoordI2(-1, 0));
const FfxTexCoordI2 iSrcSamplePosX23 = FfxTexCoordI2(iSrcInputPos.xx) + (bFlipCol ? FfxTexCoordI2(-1, -2) : FfxTexCoordI2( 1, 2));
const FfxTexCoordI2 iSrcSamplePosY01 = FfxTexCoordI2(iSrcInputPos.yy) + (bFlipRow ? FfxTexCoordI2( 1, 0) : FfxTexCoordI2(-1, 0));
const FfxTexCoordI2 iSrcSamplePosY23 = FfxTexCoordI2(iSrcInputPos.yy) + (bFlipRow ? FfxTexCoordI2(-1, -2) : FfxTexCoordI2( 1, 2));
const FfxTexCoordI2 renderSizeLastTexelCoord = FfxTexCoordI2(RenderSize()) - FfxTexCoordI2(1, 1);
const FfxTexCoordI2 iSrcSamplePosX01Clamped = FfxTexCoordI2(
__XB_Med3_I32(iSrcSamplePosX01.x, 0, renderSizeLastTexelCoord.x),
__XB_Med3_I32(iSrcSamplePosX01.y, 0, renderSizeLastTexelCoord.x)
);
const FfxTexCoordI2 iSrcSamplePosX23Clamped = FfxTexCoordI2(
__XB_Med3_I32(iSrcSamplePosX23.x, 0, renderSizeLastTexelCoord.x),
__XB_Med3_I32(iSrcSamplePosX23.y, 0, renderSizeLastTexelCoord.x)
);
const FfxTexCoordI2 iSrcSamplePosY01Clamped = FfxTexCoordI2(
__XB_Med3_I32(iSrcSamplePosY01.x, 0, renderSizeLastTexelCoord.y),
__XB_Med3_I32(iSrcSamplePosY01.y, 0, renderSizeLastTexelCoord.y)
);
const FfxTexCoordI2 iSrcSamplePosY23Clamped = FfxTexCoordI2(
__XB_Med3_I32(iSrcSamplePosY23.x, 0, renderSizeLastTexelCoord.y),
__XB_Med3_I32(iSrcSamplePosY23.y, 0, renderSizeLastTexelCoord.y)
);
FFX_MIN16_F2 TopCornerR, BotCornerR, HorzR, VertR, CenterR;
FFX_MIN16_F2 TopCornerG, BotCornerG, HorzG, VertG, CenterG;
FFX_MIN16_F2 TopCornerB, BotCornerB, HorzB, VertB, CenterB;
LoadPreparedColorPairedRgb(TopCornerR, TopCornerG, TopCornerB,
FfxTexCoordI2(iSrcSamplePosX01Clamped.x, iSrcSamplePosY01Clamped.x),
FfxTexCoordI2(iSrcSamplePosX23Clamped.x, iSrcSamplePosY01Clamped.x)
);
LoadPreparedColorPairedRgb(BotCornerR, BotCornerG, BotCornerB,
FfxTexCoordI2(iSrcSamplePosX01Clamped.x, iSrcSamplePosY23Clamped.x),
FfxTexCoordI2(iSrcSamplePosX23Clamped.x, iSrcSamplePosY23Clamped.x)
);
LoadPreparedColorPairedRgb(HorzR, HorzG, HorzB,
FfxTexCoordI2(iSrcSamplePosX01Clamped.x, iSrcSamplePosY01Clamped.y),
FfxTexCoordI2(iSrcSamplePosX23Clamped.x, iSrcSamplePosY01Clamped.y)
);
LoadPreparedColorPairedRgb(VertR, VertG, VertB,
FfxTexCoordI2(iSrcSamplePosX01Clamped.y, iSrcSamplePosY01Clamped.x),
FfxTexCoordI2(iSrcSamplePosX01Clamped.y, iSrcSamplePosY23Clamped.x)
);
// NOTE: duplicated data
LoadPreparedColorPairedRgb(CenterR, CenterG, CenterB,
FfxTexCoordI2(iSrcSamplePosX01Clamped.y, iSrcSamplePosY01Clamped.y),
FfxTexCoordI2(iSrcSamplePosX01Clamped.y, iSrcSamplePosY01Clamped.y)
);
#if FFX_FSR3UPSCALER_OPTION_HDR_COLOR_INPUT
if (bIsInitialSample)
{
TonemapPaired(TopCornerR, TopCornerG, TopCornerB);
TonemapPaired(BotCornerR, BotCornerG, BotCornerB);
TonemapPaired(HorzR, HorzG, HorzB);
TonemapPaired(VertR, VertG, VertB);
TonemapPaired(CenterR, CenterG, CenterB);
}
#endif
RGBToYCoCgPaired(TopCornerR, TopCornerG, TopCornerB);
RGBToYCoCgPaired(BotCornerR, BotCornerG, BotCornerB);
RGBToYCoCgPaired(HorzR, HorzG, HorzB);
RGBToYCoCgPaired(VertR, VertG, VertB);
RGBToYCoCgPaired(CenterR, CenterG, CenterB);
#else
FfxFloat32x3 fSamples[9];
FfxInt32 iSampleIndex = 0;
FfxInt32 row, col;
FFX_UNROLL
for (FfxInt32 row = 0; row < 3; row++) {
for (row = 0; row < 3; row++) {
FFX_UNROLL
for (FfxInt32 col = 0; col < 3; col++) {
for (col = 0; col < 3; col++) {
const FfxInt32x2 iSampleColRow = FfxInt32x2(bFlipCol ? (3 - col) : col, bFlipRow ? (3 - row) : row);
const FfxInt32x2 iSrcSamplePos = FfxInt32x2(iSrcInputPos) + offsetTL + iSampleColRow;
const FfxInt32x2 iSampleCoord = ClampLoad(iSrcSamplePos, FfxInt32x2(0, 0), FfxInt32x2(RenderSize()));
@ -110,6 +435,8 @@ void ComputeUpsampledColorAndWeight(const AccumulationPassCommonParams params, F
}
#endif
#endif // #if FFX_FSR3UPSCALER_USE_XBOX_PAIRED_16BIT_MATH_OPTIMIZATIONS
// Identify how much of each upsampled color to be used for this frame
const FfxFloat32 fKernelBiasMax = ComputeMaxKernelWeight(params, data);
const FfxFloat32 fKernelBiasMin = ffxMax(1.0f, ((1.0f + fKernelBiasMax) * 0.3f));
@ -122,14 +449,147 @@ void ComputeUpsampledColorAndWeight(const AccumulationPassCommonParams params, F
const FfxFloat32 fKernelBias = ffxLerp(fKernelBiasMin, fKernelBiasMax, fKernelBiasWeight);
#if FFX_FSR3UPSCALER_USE_XBOX_PAIRED_16BIT_MATH_OPTIMIZATIONS
// Unroll the loop to load samples on Scarlett to help the shader compiler
const bool coordX0OnScreen = iSrcSamplePosX01.x == iSrcSamplePosX01Clamped.x;
const bool coordX1OnScreen = iSrcSamplePosX01.y == iSrcSamplePosX01Clamped.y;
const bool coordX2OnScreen = iSrcSamplePosX23.x == iSrcSamplePosX23Clamped.x;
const bool coordY0OnScreen = iSrcSamplePosY01.x == iSrcSamplePosY01Clamped.x;
const bool coordY1OnScreen = iSrcSamplePosY01.y == iSrcSamplePosY01Clamped.y;
const bool coordY2OnScreen = iSrcSamplePosY23.x == iSrcSamplePosY23Clamped.x;
const FFX_MIN16_F2 fBaseSampleOffsetHalf = FFX_MIN16_F2(fBaseSampleOffset);
const FFX_MIN16_F2 fSrcSampleOffsetX_02 = fBaseSampleOffsetHalf.xx + fSampleOffsetX02;
const FFX_MIN16_F2 fSrcSampleOffsetY_02 = fBaseSampleOffsetHalf.yy + fSampleOffsetY02;
const FFX_MIN16_F2 fSrcSampleOffsetXSq_02 = fSrcSampleOffsetX_02 * fSrcSampleOffsetX_02;
const FFX_MIN16_F2 fSrcSampleOffsetYSq_02 = fSrcSampleOffsetY_02 * fSrcSampleOffsetY_02;
const FFX_MIN16_F2 fSrcSampleOffsetXYSq_11 = fBaseSampleOffsetHalf * fBaseSampleOffsetHalf;
const FfxFloat32 fRectificationCurveBias = -2.3f;
PairedRectificationBoxAndAccumulatedColorAndWeight pairedBox;
pairedBox.setKernelBiasAndRectificationCurveBias(fKernelBias, fRectificationCurveBias);
// init by o o o
// o x o
// o o o
pairedBox.initBox(
fSrcSampleOffsetXYSq_11.x + fSrcSampleOffsetXYSq_11.y,
Bool2ToFloat16x2(coordX1OnScreen && coordY1OnScreen, false).x,
CenterR, CenterG, CenterB
);
// add remaining two samples from 1st row x o x
// o * o
// o o o
pairedBox.addBoxSample(
fSrcSampleOffsetXSq_02 + fSrcSampleOffsetYSq_02.xx,
Bool2ToFloat16x2(coordX0OnScreen && coordY0OnScreen, coordX2OnScreen && coordY0OnScreen),
TopCornerR, TopCornerG, TopCornerB
);
// add two samples from 2nd row * o *
// o * o
// x o x
pairedBox.addBoxSample(
fSrcSampleOffsetXSq_02 + fSrcSampleOffsetYSq_02.yy,
Bool2ToFloat16x2(coordX0OnScreen && coordY2OnScreen, coordX2OnScreen && coordY2OnScreen),
BotCornerR, BotCornerG, BotCornerB
);
// add two samples from 3rd row * o *
// x * x
// * o *
pairedBox.addBoxSample(
fSrcSampleOffsetXSq_02 + fSrcSampleOffsetXYSq_11.yy,
Bool2ToFloat16x2(coordX0OnScreen && coordY1OnScreen, coordX2OnScreen && coordY1OnScreen),
HorzR, HorzG, HorzB
);
// add remaining samples * x *
// * * *
// * x *
pairedBox.addBoxSample(
fSrcSampleOffsetXYSq_11.xx + fSrcSampleOffsetYSq_02,
Bool2ToFloat16x2(coordX1OnScreen && coordY0OnScreen, coordX1OnScreen && coordY2OnScreen),
VertR, VertG, VertB
);
FfxFloat32x2 boxCenterAndVecR, boxCenterAndVecG, boxCenterAndVecB;
FfxFloat32 boxCenterWeight;
pairedBox.finalizeBox(boxCenterAndVecR, boxCenterAndVecG, boxCenterAndVecB, boxCenterWeight);
if (!bIsInitialSample)
{
pairedBox.initUpscaledColor(
fSrcSampleOffsetXYSq_11.x + fSrcSampleOffsetXYSq_11.y,
Bool2ToFloat16x2(coordX1OnScreen && coordY1OnScreen, false).x,
CenterR, CenterG, CenterB
);
// add remaining two samples from 1st row x o x
// o * o
// o o o
pairedBox.addUpscaledColorSample(
fSrcSampleOffsetXSq_02 + fSrcSampleOffsetYSq_02.xx,
Bool2ToFloat16x2(coordX0OnScreen && coordY0OnScreen, coordX2OnScreen && coordY0OnScreen),
TopCornerR, TopCornerG, TopCornerB
);
// add two samples from 2nd row * o *
// o * o
// x o x
pairedBox.addUpscaledColorSample(
fSrcSampleOffsetXSq_02 + fSrcSampleOffsetYSq_02.yy,
Bool2ToFloat16x2(coordX0OnScreen && coordY2OnScreen, coordX2OnScreen && coordY2OnScreen),
BotCornerR, BotCornerG, BotCornerB
);
// add two samples from 3rd row * o *
// x * x
// * o *
pairedBox.addUpscaledColorSample(
fSrcSampleOffsetXSq_02 + fSrcSampleOffsetXYSq_11.yy,
Bool2ToFloat16x2(coordX0OnScreen && coordY1OnScreen, coordX2OnScreen && coordY1OnScreen),
HorzR, HorzG, HorzB
);
// add remaining samples * x *
// * * *
// * x *
pairedBox.addUpscaledColorSample(
fSrcSampleOffsetXYSq_11.xx + fSrcSampleOffsetYSq_02,
Bool2ToFloat16x2(coordX1OnScreen && coordY0OnScreen, coordX1OnScreen && coordY2OnScreen),
VertR, VertG, VertB
);
FfxFloat32x4 upscaledColorAndWeight = 0.0;
pairedBox.finalizeUpscaledColor(upscaledColorAndWeight);
data.fUpsampledColor = FfxFloat32x3(upscaledColorAndWeight.rgb);
data.fUpsampledWeight = FfxFloat32(upscaledColorAndWeight.w);
}
FFX_MIN16_F2 aabbMinMaxR = Compute3x3SamplesMinMaxPaired(CenterR, TopCornerR, BotCornerR, HorzR, VertR);
FFX_MIN16_F2 aabbMinMaxG = Compute3x3SamplesMinMaxPaired(CenterG, TopCornerG, BotCornerG, HorzG, VertG);
FFX_MIN16_F2 aabbMinMaxB = Compute3x3SamplesMinMaxPaired(CenterB, TopCornerB, BotCornerB, HorzB, VertB);
data.clippingBox.boxCenter = FfxFloat32x3(boxCenterAndVecR.x, boxCenterAndVecG.x, boxCenterAndVecB.x);
data.clippingBox.boxVec = FfxFloat32x3(boxCenterAndVecR.y, boxCenterAndVecG.y, boxCenterAndVecB.y);
data.clippingBox.aabbMin = FfxFloat32x3(aabbMinMaxR.x, aabbMinMaxG.x, aabbMinMaxB.x);
data.clippingBox.aabbMax = FfxFloat32x3(aabbMinMaxR.y, aabbMinMaxG.y, aabbMinMaxB.y);
data.clippingBox.fBoxCenterWeight = FfxFloat32(boxCenterWeight);
#else
iSampleIndex = 0;
FFX_UNROLL
for (FfxInt32 row = 0; row < 3; row++)
for (row = 0; row < 3; row++)
{
FFX_UNROLL
for (FfxInt32 col = 0; col < 3; col++)
for (col = 0; col < 3; col++)
{
const FfxInt32x2 sampleColRow = FfxInt32x2(bFlipCol ? (3 - col) : col, bFlipRow ? (3 - row) : row);
const FfxFloat32x2 fOffset = fOffsetTL + FfxFloat32x2(sampleColRow);
@ -159,6 +619,8 @@ void ComputeUpsampledColorAndWeight(const AccumulationPassCommonParams params, F
}
}
#endif // #if FFX_FSR3UPSCALER_USE_XBOX_PAIRED_16BIT_MATH_OPTIMIZATIONS
RectificationBoxComputeVarianceBoxData(data.clippingBox);
data.fUpsampledWeight *= FfxFloat32(data.fUpsampledWeight > FSR3UPSCALER_EPSILON);

2
package.json

@ -1,6 +1,6 @@
{
"name": "fidelityfx.fsr",
"version": "1.0.0",
"version": "1.0.2",
"displayName": "FidelityFX FSR",
"description": "FidelityFX Super Resolution 2/3 Upscaler core assets",
"unity": "2020.1",

Loading…
Cancel
Save