Browse Source

Merge branch 'framework' into fsr3framegen

fsr3framegen
Nico de Poel 2 years ago
parent
commit
9d35022137
  1. 57
      Runtime/Common/FfxContextBase.cs
  2. 11
      Runtime/Common/FfxContextBase.cs.meta
  3. 63
      Runtime/Common/FfxPassBase.cs
  4. 11
      Runtime/Common/FfxPassBase.cs.meta
  5. 96
      Runtime/Common/FfxResourcesBase.cs
  6. 11
      Runtime/Common/FfxResourcesBase.cs.meta
  7. 46
      Runtime/Common/FfxSpd.cs
  8. 11
      Runtime/Common/FfxSpd.cs.meta
  9. 118
      Runtime/Common/FfxUtils.cs
  10. 11
      Runtime/Common/FfxUtils.cs.meta
  11. 49
      Runtime/FSR2/Fsr2.cs
  12. 221
      Runtime/FSR2/Fsr2Context.cs
  13. 197
      Runtime/FSR2/Fsr2Pass.cs
  14. 83
      Runtime/FSR2/Fsr2Resources.cs
  15. 49
      Runtime/FSR3/Fsr3Upscaler.cs
  16. 242
      Runtime/FSR3/Fsr3UpscalerContext.cs
  17. 248
      Runtime/FSR3/Fsr3UpscalerPass.cs
  18. 87
      Runtime/FSR3/Fsr3UpscalerResources.cs

57
Runtime/Common/FfxContextBase.cs

@ -0,0 +1,57 @@
using System;
using System.Runtime.InteropServices;
using UnityEngine;
using UnityEngine.Rendering;
namespace FidelityFX
{
public abstract class FfxContextBase
{
protected static void DestroyPass<TPass>(ref TPass pass)
where TPass: class, IDisposable
{
if (pass == null)
return;
pass.Dispose();
pass = null;
}
/// <summary>
/// Convenience class for handling a constants buffer containing a single struct item.
/// This wraps the compute buffer and the value array, as well as providing easy access to both.
/// </summary>
protected class ConstantsBuffer<TConst>
where TConst: struct
{
private ComputeBuffer _computeBuffer;
private readonly TConst[] _constArray = { new TConst() };
public ref TConst Value => ref _constArray[0];
public void Create()
{
_computeBuffer = new ComputeBuffer(1, Marshal.SizeOf<TConst>(), ComputeBufferType.Constant);
}
public void UpdateBufferData(CommandBuffer commandBuffer)
{
commandBuffer.SetBufferData(_computeBuffer, _constArray);
}
public void Destroy()
{
if (_computeBuffer == null)
return;
_computeBuffer.Release();
_computeBuffer = null;
}
public static implicit operator ComputeBuffer(ConstantsBuffer<TConst> constants)
{
return constants._computeBuffer;
}
}
}
}

11
Runtime/Common/FfxContextBase.cs.meta

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f4aeccbeb6e61434eb2e50b7190fda8d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

63
Runtime/Common/FfxPassBase.cs

@ -0,0 +1,63 @@
using System;
using UnityEngine;
using UnityEngine.Profiling;
using UnityEngine.Rendering;
namespace FidelityFX
{
internal abstract class FfxPassBase<TDispatch>: IDisposable
//where TDispatch: struct
{
private readonly string _techName;
protected ComputeShader ComputeShader;
protected int KernelIndex;
protected CustomSampler Sampler;
protected FfxPassBase(string techName)
{
_techName = techName;
}
public void ScheduleDispatch(CommandBuffer commandBuffer, in TDispatch dispatchParams, int bufferIndex, int dispatchX, int dispatchY, int dispatchZ = 1)
{
commandBuffer.BeginSample(Sampler);
DoScheduleDispatch(commandBuffer, dispatchParams, bufferIndex, dispatchX, dispatchY, dispatchZ);
commandBuffer.EndSample(Sampler);
}
protected abstract void DoScheduleDispatch(CommandBuffer commandBuffer, in TDispatch dispatchParams, int bufferIndex, int dispatchX, int dispatchY, int dispatchZ);
protected void InitComputeShader(string passName, ComputeShader shader, string kernelName = "CS")
{
if (shader == null)
{
throw new MissingReferenceException($"Shader for {_techName} pass '{passName}' could not be loaded! Please ensure it is included in the project correctly.");
}
ComputeShader = shader;
KernelIndex = ComputeShader.FindKernel(kernelName);
Sampler = CustomSampler.Create(passName);
}
public virtual void Dispose()
{
}
}
internal abstract class FfxPassWithFlags<TDispatch, TFlags> : FfxPassBase<TDispatch>
//where TDispatch: struct
where TFlags: Enum
{
protected FfxPassWithFlags(string techName): base(techName) { }
protected void InitComputeShader(string passName, ComputeShader shader, TFlags flags, string kernelName = "CS")
{
InitComputeShader(passName, shader, kernelName);
SetupShaderKeywords(flags);
}
protected abstract void SetupShaderKeywords(TFlags flags);
}
}

11
Runtime/Common/FfxPassBase.cs.meta

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: deac9cc5a4c6df64db05956030e79425
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

96
Runtime/Common/FfxResourcesBase.cs

@ -0,0 +1,96 @@
using System;
using System.Runtime.InteropServices;
using UnityEngine;
using UnityEngine.Experimental.Rendering;
namespace FidelityFX
{
internal abstract class FfxResourcesBase
{
protected static ComputeBuffer CreateBuffer<TElem>(string name, int count)
{
return new ComputeBuffer(count, Marshal.SizeOf<TElem>());
}
protected static Texture2D CreateLookup(string name, GraphicsFormat format, Color data)
{
var tex = new Texture2D(1, 1, format, TextureCreationFlags.None) { name = name };
tex.SetPixel(0, 0, data);
tex.Apply();
return tex;
}
protected static Texture2D CreateLookup<T>(string name, in Vector2Int size, GraphicsFormat format, T[] data)
{
var tex = new Texture2D(size.x, size.y, format, TextureCreationFlags.None) { name = name };
tex.SetPixelData(data, 0);
tex.Apply();
return tex;
}
protected static RenderTexture CreateResource(string name, in Vector2Int size, GraphicsFormat format)
{
var rt = new RenderTexture(size.x, size.y, 0, format) { name = name, enableRandomWrite = true };
rt.Create();
return rt;
}
protected static RenderTexture CreateResourceMips(string name, in Vector2Int size, GraphicsFormat format)
{
int mipCount = 1 + Mathf.FloorToInt(Mathf.Log(Math.Max(size.x, size.y), 2.0f));
var rt = new RenderTexture(size.x, size.y, 0, format, mipCount) { name = name, enableRandomWrite = true, useMipMap = true, autoGenerateMips = false };
rt.Create();
return rt;
}
protected static void CreateDoubleBufferedResource(RenderTexture[] resource, string name, in Vector2Int size, GraphicsFormat format, int numElements = 2)
{
numElements = Math.Min(resource.Length, numElements);
for (int i = 0; i < numElements; ++i)
{
resource[i] = new RenderTexture(size.x, size.y, 0, format) { name = name + (i + 1), enableRandomWrite = true };
resource[i].Create();
}
}
protected static void DestroyResource(ref Texture2D resource)
{
if (resource == null)
return;
#if UNITY_EDITOR
if (Application.isPlaying && !UnityEditor.EditorApplication.isPaused)
UnityEngine.Object.Destroy(resource);
else
UnityEngine.Object.DestroyImmediate(resource);
#else
UnityEngine.Object.Destroy(resource);
#endif
resource = null;
}
protected static void DestroyResource(ref RenderTexture resource)
{
if (resource == null)
return;
resource.Release();
resource = null;
}
protected static void DestroyResource(ref ComputeBuffer resource)
{
if (resource == null)
return;
resource.Release();
resource = null;
}
protected static void DestroyResource(RenderTexture[] resource)
{
for (int i = 0; i < resource.Length; ++i)
DestroyResource(ref resource[i]);
}
}
}

11
Runtime/Common/FfxResourcesBase.cs.meta

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2a46b97ac72c45545a80a896462e1112
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

46
Runtime/Common/FfxSpd.cs

@ -0,0 +1,46 @@
using System;
using System.Runtime.InteropServices;
using UnityEngine;
namespace FidelityFX
{
public static class FfxSpd
{
public static void SetupSpdConstants(Vector2Int resolution, ref SpdConstants spdConstants, out Vector2Int dispatchThreadGroupCount, int mips = -1)
{
RectInt rectInfo = new RectInt(0, 0, resolution.x, resolution.y);
SpdSetup(rectInfo, out dispatchThreadGroupCount, out Vector2Int workGroupOffset, out Vector2Int numWorkGroupsAndMips, mips);
spdConstants.numWorkGroups = (uint)numWorkGroupsAndMips.x;
spdConstants.mips = (uint)numWorkGroupsAndMips.y;
spdConstants.workGroupOffsetX = (uint)workGroupOffset.x;
spdConstants.workGroupOffsetY = (uint)workGroupOffset.y;
}
public static void SpdSetup(RectInt rectInfo, out Vector2Int dispatchThreadGroupCount, out Vector2Int workGroupOffset, out Vector2Int numWorkGroupsAndMips, int mips = -1)
{
workGroupOffset = new Vector2Int(rectInfo.x / 64, rectInfo.y / 64);
int endIndexX = (rectInfo.x + rectInfo.width - 1) / 64;
int endIndexY = (rectInfo.y + rectInfo.height - 1) / 64;
dispatchThreadGroupCount = new Vector2Int(endIndexX + 1 - workGroupOffset.x, endIndexY + 1 - workGroupOffset.y);
numWorkGroupsAndMips = new Vector2Int(dispatchThreadGroupCount.x * dispatchThreadGroupCount.y, mips);
if (mips < 0)
{
float resolution = Math.Max(rectInfo.width, rectInfo.height);
numWorkGroupsAndMips.y = Math.Min(Mathf.FloorToInt(Mathf.Log(resolution, 2.0f)), 12);
}
}
[Serializable, StructLayout(LayoutKind.Sequential)]
public struct SpdConstants
{
public uint mips;
public uint numWorkGroups;
public uint workGroupOffsetX;
public uint workGroupOffsetY;
}
}
}

11
Runtime/Common/FfxSpd.cs.meta

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: aee0f42dc1676ab4db5c01520b0b925a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

118
Runtime/Common/FfxUtils.cs

@ -0,0 +1,118 @@
using System;
using System.Runtime.InteropServices;
using UnityEngine;
using UnityEngine.Rendering;
namespace FidelityFX
{
public static class FfxUtils
{
public static float GetMipmapBiasOffset(int renderWidth, int displayWidth)
{
return Mathf.Log((float)renderWidth / displayWidth, 2.0f) - 1.0f;
}
public static int GetJitterPhaseCount(int renderWidth, int displayWidth)
{
const float basePhaseCount = 8.0f;
int jitterPhaseCount = (int)(basePhaseCount * Mathf.Pow((float)displayWidth / renderWidth, 2.0f));
return jitterPhaseCount;
}
public static void GetJitterOffset(out float outX, out float outY, int index, int phaseCount)
{
outX = Halton((index % phaseCount) + 1, 2) - 0.5f;
outY = Halton((index % phaseCount) + 1, 3) - 0.5f;
}
// Calculate halton number for index and base.
private static float Halton(int index, int @base)
{
float f = 1.0f, result = 0.0f;
for (int currentIndex = index; currentIndex > 0;) {
f /= @base;
result += f * (currentIndex % @base);
currentIndex = (int)Mathf.Floor((float)currentIndex / @base);
}
return result;
}
public static float Lanczos2(float value)
{
return Mathf.Abs(value) < Mathf.Epsilon ? 1.0f : Mathf.Sin(Mathf.PI * value) / (Mathf.PI * value) * (Mathf.Sin(0.5f * Mathf.PI * value) / (0.5f * Mathf.PI * value));
}
public static float[] GenerateLanczos2Table(int width)
{
float[] lanczos2Weights = new float[width];
for (int currentLanczosWidthIndex = 0; currentLanczosWidthIndex < width; ++currentLanczosWidthIndex)
{
float x = 2.0f * currentLanczosWidthIndex / (width - 1);
float y = Lanczos2(x);
lanczos2Weights[currentLanczosWidthIndex] = y;
}
return lanczos2Weights;
}
public static Vector4 SetupDeviceDepthToViewSpaceDepthParams(Vector2Int renderSize, float cameraNear, float cameraFar, float cameraFovAngleVertical, bool inverted, bool infinite)
{
// make sure it has no impact if near and far plane values are swapped in dispatch params
// the flags "inverted" and "infinite" will decide what transform to use
float min = Mathf.Min(cameraNear, cameraFar);
float max = Mathf.Max(cameraNear, cameraFar);
if (inverted)
{
(min, max) = (max, min);
}
float q = max / (min - max);
float d = -1.0f;
Vector4 matrixElemC = new Vector4(q, -1.0f - Mathf.Epsilon, q, 0.0f + Mathf.Epsilon);
Vector4 matrixElemE = new Vector4(q * min, -min - Mathf.Epsilon, q * min, max);
// Revert x and y coords
float aspect = (float)renderSize.x / renderSize.y;
float cotHalfFovY = Mathf.Cos(0.5f * cameraFovAngleVertical) / Mathf.Sin(0.5f * cameraFovAngleVertical);
int matrixIndex = (inverted ? 2 : 0) + (infinite ? 1 : 0);
return new Vector4(
d * matrixElemC[matrixIndex],
matrixElemE[matrixIndex],
aspect / cotHalfFovY,
1.0f / cotHalfFovY);
}
#if !UNITY_2021_1_OR_NEWER
internal static void SetBufferData(this CommandBuffer commandBuffer, ComputeBuffer computeBuffer, Array data)
{
commandBuffer.SetComputeBufferData(computeBuffer, data);
}
#endif
/// <summary>
/// Alternative for CommandBuffer.SetComputeTextureParam that guards against attempts to bind mip levels that don't exist.
/// </summary>
internal static void SetComputeTextureMipParam(this CommandBuffer commandBuffer, ComputeShader computeShader, int kernelIndex, int nameID, Texture texture, int mipLevel)
{
mipLevel = Math.Min(mipLevel, texture.mipmapCount - 1);
commandBuffer.SetComputeTextureParam(computeShader, kernelIndex, nameID, texture, mipLevel);
}
internal static void SetComputeResourceParam(this CommandBuffer commandBuffer, ComputeShader computeShader, int kernelIndex, int nameID, in ResourceView resource)
{
commandBuffer.SetComputeTextureParam(computeShader, kernelIndex, nameID, resource.RenderTarget, resource.MipLevel, resource.SubElement);
}
internal static void SetComputeConstantBufferParam<TBuf>(this CommandBuffer commandBuffer, ComputeShader computeShader, int nameID, ComputeBuffer buffer)
where TBuf: struct
{
commandBuffer.SetComputeConstantBufferParam(computeShader, nameID, buffer, 0, Marshal.SizeOf<TBuf>());
}
}
}

11
Runtime/Common/FfxUtils.cs.meta

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9c5c0f0b987cca64c8dfd8051e09962e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

49
Runtime/FSR2/Fsr2.cs

@ -89,51 +89,6 @@ namespace FidelityFX.FSR2
renderHeight = Mathf.RoundToInt(displayHeight / ratio); renderHeight = Mathf.RoundToInt(displayHeight / ratio);
} }
public static float GetMipmapBiasOffset(int renderWidth, int displayWidth)
{
return Mathf.Log((float)renderWidth / displayWidth, 2.0f) - 1.0f;
}
public static int GetJitterPhaseCount(int renderWidth, int displayWidth)
{
const float basePhaseCount = 8.0f;
int jitterPhaseCount = (int)(basePhaseCount * Mathf.Pow((float)displayWidth / renderWidth, 2.0f));
return jitterPhaseCount;
}
public static void GetJitterOffset(out float outX, out float outY, int index, int phaseCount)
{
outX = Halton((index % phaseCount) + 1, 2) - 0.5f;
outY = Halton((index % phaseCount) + 1, 3) - 0.5f;
}
// Calculate halton number for index and base.
private static float Halton(int index, int @base)
{
float f = 1.0f, result = 0.0f;
for (int currentIndex = index; currentIndex > 0;) {
f /= @base;
result += f * (currentIndex % @base);
currentIndex = (int)Mathf.Floor((float)currentIndex / @base);
}
return result;
}
public static float Lanczos2(float value)
{
return Mathf.Abs(value) < Mathf.Epsilon ? 1.0f : Mathf.Sin(Mathf.PI * value) / (Mathf.PI * value) * (Mathf.Sin(0.5f * Mathf.PI * value) / (0.5f * Mathf.PI * value));
}
#if !UNITY_2021_1_OR_NEWER
internal static void SetBufferData(this CommandBuffer commandBuffer, ComputeBuffer computeBuffer, Array data)
{
commandBuffer.SetComputeBufferData(computeBuffer, data);
}
#endif
public enum QualityMode public enum QualityMode
{ {
NativeAA = 0, NativeAA = 0,
@ -259,9 +214,7 @@ namespace FidelityFX.FSR2
[Serializable, StructLayout(LayoutKind.Sequential)] [Serializable, StructLayout(LayoutKind.Sequential)]
internal struct SpdConstants internal struct SpdConstants
{ {
public uint mips;
public uint numWorkGroups;
public uint workGroupOffsetX, workGroupOffsetY;
public FfxSpd.SpdConstants spd;
public uint renderSizeX, renderSizeY; public uint renderSizeX, renderSizeY;
} }

221
Runtime/FSR2/Fsr2Context.cs

@ -19,8 +19,8 @@
// THE SOFTWARE. // THE SOFTWARE.
using System; using System;
using System.Runtime.InteropServices;
using UnityEngine; using UnityEngine;
using UnityEngine.Profiling;
using UnityEngine.Rendering; using UnityEngine.Rendering;
namespace FidelityFX.FSR2 namespace FidelityFX.FSR2
@ -31,7 +31,7 @@ namespace FidelityFX.FSR2
/// Note that this class does not know anything about Unity render pipelines; all it knows is CommandBuffers and RenderTargetIdentifiers. /// Note that this class does not know anything about Unity render pipelines; all it knows is CommandBuffers and RenderTargetIdentifiers.
/// This should make it suitable for integration with any of the available Unity render pipelines. /// This should make it suitable for integration with any of the available Unity render pipelines.
/// </summary> /// </summary>
public class Fsr2Context
public class Fsr2Context: FfxContextBase
{ {
private const int MaxQueuedFrames = 16; private const int MaxQueuedFrames = 16;
@ -49,46 +49,34 @@ namespace FidelityFX.FSR2
private readonly Fsr2Resources _resources = new Fsr2Resources(); private readonly Fsr2Resources _resources = new Fsr2Resources();
private ComputeBuffer _upscalerConstantsBuffer;
private readonly Fsr2.UpscalerConstants[] _upscalerConstantsArray = { new Fsr2.UpscalerConstants() };
private ref Fsr2.UpscalerConstants UpscalerConsts => ref _upscalerConstantsArray[0];
private ComputeBuffer _spdConstantsBuffer;
private readonly Fsr2.SpdConstants[] _spdConstantsArray = { new Fsr2.SpdConstants() };
private ref Fsr2.SpdConstants SpdConsts => ref _spdConstantsArray[0];
private ComputeBuffer _rcasConstantsBuffer;
private readonly Fsr2.RcasConstants[] _rcasConstantsArray = new Fsr2.RcasConstants[1];
private ref Fsr2.RcasConstants RcasConsts => ref _rcasConstantsArray[0];
private ComputeBuffer _generateReactiveConstantsBuffer;
private readonly Fsr2.GenerateReactiveConstants[] _generateReactiveConstantsArray = { new Fsr2.GenerateReactiveConstants() };
private ref Fsr2.GenerateReactiveConstants GenReactiveConsts => ref _generateReactiveConstantsArray[0];
private ComputeBuffer _tcrAutogenerateConstantsBuffer;
private readonly Fsr2.GenerateReactiveConstants2[] _tcrAutogenerateConstantsArray = { new Fsr2.GenerateReactiveConstants2() };
private ref Fsr2.GenerateReactiveConstants2 TcrAutoGenConsts => ref _tcrAutogenerateConstantsArray[0];
private readonly ConstantsBuffer<Fsr2.UpscalerConstants> _upscalerConstants = new ConstantsBuffer<Fsr2.UpscalerConstants>();
private readonly ConstantsBuffer<Fsr2.SpdConstants> _spdConstants = new ConstantsBuffer<Fsr2.SpdConstants>();
private readonly ConstantsBuffer<Fsr2.RcasConstants> _rcasConstants = new ConstantsBuffer<Fsr2.RcasConstants>();
private readonly ConstantsBuffer<Fsr2.GenerateReactiveConstants> _generateReactiveConstants = new ConstantsBuffer<Fsr2.GenerateReactiveConstants>();
private readonly ConstantsBuffer<Fsr2.GenerateReactiveConstants2> _tcrAutogenerateConstants = new ConstantsBuffer<Fsr2.GenerateReactiveConstants2>();
private bool _firstExecution; private bool _firstExecution;
private Vector2 _previousJitterOffset; private Vector2 _previousJitterOffset;
private int _resourceFrameIndex; private int _resourceFrameIndex;
private readonly CustomSampler _sampler = CustomSampler.Create("FSR2");
public void Create(Fsr2.ContextDescription contextDescription) public void Create(Fsr2.ContextDescription contextDescription)
{ {
_contextDescription = contextDescription; _contextDescription = contextDescription;
_commandBuffer = new CommandBuffer { name = "FSR2" }; _commandBuffer = new CommandBuffer { name = "FSR2" };
_upscalerConstantsBuffer = CreateConstantBuffer<Fsr2.UpscalerConstants>();
_spdConstantsBuffer = CreateConstantBuffer<Fsr2.SpdConstants>();
_rcasConstantsBuffer = CreateConstantBuffer<Fsr2.RcasConstants>();
_generateReactiveConstantsBuffer = CreateConstantBuffer<Fsr2.GenerateReactiveConstants>();
_tcrAutogenerateConstantsBuffer = CreateConstantBuffer<Fsr2.GenerateReactiveConstants2>();
_upscalerConstants.Create();
_spdConstants.Create();
_rcasConstants.Create();
_generateReactiveConstants.Create();
_tcrAutogenerateConstants.Create();
// Set defaults // Set defaults
_firstExecution = true; _firstExecution = true;
_resourceFrameIndex = 0; _resourceFrameIndex = 0;
UpscalerConsts.displaySize = _contextDescription.DisplaySize;
_upscalerConstants.Value.displaySize = _contextDescription.DisplaySize;
_resources.Create(_contextDescription); _resources.Create(_contextDescription);
CreatePasses(); CreatePasses();
@ -96,14 +84,14 @@ namespace FidelityFX.FSR2
private void CreatePasses() private void CreatePasses()
{ {
_computeLuminancePyramidPass = new Fsr2ComputeLuminancePyramidPass(_contextDescription, _resources, _upscalerConstantsBuffer, _spdConstantsBuffer);
_reconstructPreviousDepthPass = new Fsr2ReconstructPreviousDepthPass(_contextDescription, _resources, _upscalerConstantsBuffer);
_depthClipPass = new Fsr2DepthClipPass(_contextDescription, _resources, _upscalerConstantsBuffer);
_lockPass = new Fsr2LockPass(_contextDescription, _resources, _upscalerConstantsBuffer);
_accumulatePass = new Fsr2AccumulatePass(_contextDescription, _resources, _upscalerConstantsBuffer);
_sharpenPass = new Fsr2SharpenPass(_contextDescription, _resources, _upscalerConstantsBuffer, _rcasConstantsBuffer);
_generateReactivePass = new Fsr2GenerateReactivePass(_contextDescription, _resources, _generateReactiveConstantsBuffer);
_tcrAutogeneratePass = new Fsr2TcrAutogeneratePass(_contextDescription, _resources, _upscalerConstantsBuffer, _tcrAutogenerateConstantsBuffer);
_computeLuminancePyramidPass = new Fsr2ComputeLuminancePyramidPass(_contextDescription, _resources, _upscalerConstants, _spdConstants);
_reconstructPreviousDepthPass = new Fsr2ReconstructPreviousDepthPass(_contextDescription, _resources, _upscalerConstants);
_depthClipPass = new Fsr2DepthClipPass(_contextDescription, _resources, _upscalerConstants);
_lockPass = new Fsr2LockPass(_contextDescription, _resources, _upscalerConstants);
_accumulatePass = new Fsr2AccumulatePass(_contextDescription, _resources, _upscalerConstants);
_sharpenPass = new Fsr2SharpenPass(_contextDescription, _resources, _upscalerConstants, _rcasConstants);
_generateReactivePass = new Fsr2GenerateReactivePass(_contextDescription, _resources, _generateReactiveConstants);
_tcrAutogeneratePass = new Fsr2TcrAutogeneratePass(_contextDescription, _resources, _upscalerConstants, _tcrAutogenerateConstants);
} }
public void Destroy() public void Destroy()
@ -119,11 +107,11 @@ namespace FidelityFX.FSR2
_resources.Destroy(); _resources.Destroy();
DestroyConstantBuffer(ref _tcrAutogenerateConstantsBuffer);
DestroyConstantBuffer(ref _generateReactiveConstantsBuffer);
DestroyConstantBuffer(ref _rcasConstantsBuffer);
DestroyConstantBuffer(ref _spdConstantsBuffer);
DestroyConstantBuffer(ref _upscalerConstantsBuffer);
_tcrAutogenerateConstants.Destroy();
_generateReactiveConstants.Destroy();
_rcasConstants.Destroy();
_spdConstants.Destroy();
_upscalerConstants.Destroy();
if (_commandBuffer != null) if (_commandBuffer != null)
{ {
@ -141,6 +129,8 @@ namespace FidelityFX.FSR2
public void Dispatch(Fsr2.DispatchDescription dispatchParams, CommandBuffer commandBuffer) public void Dispatch(Fsr2.DispatchDescription dispatchParams, CommandBuffer commandBuffer)
{ {
commandBuffer.BeginSample(_sampler);
if ((_contextDescription.Flags & Fsr2.InitializationFlags.EnableDebugChecking) != 0) if ((_contextDescription.Flags & Fsr2.InitializationFlags.EnableDebugChecking) != 0)
{ {
DebugCheckDispatch(dispatchParams); DebugCheckDispatch(dispatchParams);
@ -157,7 +147,7 @@ namespace FidelityFX.FSR2
commandBuffer.ClearRenderTarget(false, true, Color.clear); commandBuffer.ClearRenderTarget(false, true, Color.clear);
} }
int frameIndex = _resourceFrameIndex % 2;
int bufferIndex = _resourceFrameIndex % 2;
bool resetAccumulation = dispatchParams.Reset || _firstExecution; bool resetAccumulation = dispatchParams.Reset || _firstExecution;
_firstExecution = false; _firstExecution = false;
@ -176,7 +166,7 @@ namespace FidelityFX.FSR2
if (resetAccumulation) if (resetAccumulation)
{ {
RenderTargetIdentifier opaqueOnly = dispatchParams.ColorOpaqueOnly.IsValid ? dispatchParams.ColorOpaqueOnly.RenderTarget : Fsr2ShaderIDs.SrvOpaqueOnly; RenderTargetIdentifier opaqueOnly = dispatchParams.ColorOpaqueOnly.IsValid ? dispatchParams.ColorOpaqueOnly.RenderTarget : Fsr2ShaderIDs.SrvOpaqueOnly;
commandBuffer.Blit(_resources.PrevPreAlpha[frameIndex ^ 1], opaqueOnly);
commandBuffer.Blit(_resources.PrevPreAlpha[bufferIndex ^ 1], opaqueOnly);
} }
} }
else if (_resources.AutoReactive != null) else if (_resources.AutoReactive != null)
@ -193,18 +183,18 @@ namespace FidelityFX.FSR2
// Reactive mask bias // Reactive mask bias
const int threadGroupWorkRegionDim = 8; const int threadGroupWorkRegionDim = 8;
int dispatchSrcX = (UpscalerConsts.renderSize.x + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
int dispatchSrcY = (UpscalerConsts.renderSize.y + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
int dispatchSrcX = (_upscalerConstants.Value.renderSize.x + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
int dispatchSrcY = (_upscalerConstants.Value.renderSize.y + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
int dispatchDstX = (_contextDescription.DisplaySize.x + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim; int dispatchDstX = (_contextDescription.DisplaySize.x + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
int dispatchDstY = (_contextDescription.DisplaySize.y + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim; int dispatchDstY = (_contextDescription.DisplaySize.y + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
// Clear reconstructed depth for max depth store // Clear reconstructed depth for max depth store
if (resetAccumulation) if (resetAccumulation)
{ {
commandBuffer.SetRenderTarget(_resources.LockStatus[frameIndex ^ 1]);
commandBuffer.SetRenderTarget(_resources.LockStatus[bufferIndex ^ 1]);
commandBuffer.ClearRenderTarget(false, true, Color.clear); commandBuffer.ClearRenderTarget(false, true, Color.clear);
commandBuffer.SetRenderTarget(_resources.InternalUpscaled[frameIndex ^ 1]);
commandBuffer.SetRenderTarget(_resources.InternalUpscaled[bufferIndex ^ 1]);
commandBuffer.ClearRenderTarget(false, true, Color.clear); commandBuffer.ClearRenderTarget(false, true, Color.clear);
commandBuffer.SetRenderTarget(_resources.SceneLuminance); commandBuffer.SetRenderTarget(_resources.SceneLuminance);
@ -228,43 +218,43 @@ namespace FidelityFX.FSR2
SetupSpdConstants(dispatchParams, out var dispatchThreadGroupCount); SetupSpdConstants(dispatchParams, out var dispatchThreadGroupCount);
// Initialize constant buffers data // Initialize constant buffers data
commandBuffer.SetBufferData(_upscalerConstantsBuffer, _upscalerConstantsArray);
commandBuffer.SetBufferData(_spdConstantsBuffer, _spdConstantsArray);
_upscalerConstants.UpdateBufferData(commandBuffer);
_spdConstants.UpdateBufferData(commandBuffer);
// Auto reactive // Auto reactive
if (dispatchParams.EnableAutoReactive) if (dispatchParams.EnableAutoReactive)
{ {
GenerateTransparencyCompositionReactive(dispatchParams, commandBuffer, frameIndex);
GenerateTransparencyCompositionReactive(dispatchParams, commandBuffer, bufferIndex);
dispatchParams.Reactive = new ResourceView(_resources.AutoReactive); dispatchParams.Reactive = new ResourceView(_resources.AutoReactive);
dispatchParams.TransparencyAndComposition = new ResourceView(_resources.AutoComposition); dispatchParams.TransparencyAndComposition = new ResourceView(_resources.AutoComposition);
} }
// Compute luminance pyramid // Compute luminance pyramid
_computeLuminancePyramidPass.ScheduleDispatch(commandBuffer, dispatchParams, frameIndex, dispatchThreadGroupCount.x, dispatchThreadGroupCount.y);
_computeLuminancePyramidPass.ScheduleDispatch(commandBuffer, dispatchParams, bufferIndex, dispatchThreadGroupCount.x, dispatchThreadGroupCount.y);
// Reconstruct previous depth // Reconstruct previous depth
_reconstructPreviousDepthPass.ScheduleDispatch(commandBuffer, dispatchParams, frameIndex, dispatchSrcX, dispatchSrcY);
_reconstructPreviousDepthPass.ScheduleDispatch(commandBuffer, dispatchParams, bufferIndex, dispatchSrcX, dispatchSrcY);
// Depth clip // Depth clip
_depthClipPass.ScheduleDispatch(commandBuffer, dispatchParams, frameIndex, dispatchSrcX, dispatchSrcY);
_depthClipPass.ScheduleDispatch(commandBuffer, dispatchParams, bufferIndex, dispatchSrcX, dispatchSrcY);
// Create locks // Create locks
_lockPass.ScheduleDispatch(commandBuffer, dispatchParams, frameIndex, dispatchSrcX, dispatchSrcY);
_lockPass.ScheduleDispatch(commandBuffer, dispatchParams, bufferIndex, dispatchSrcX, dispatchSrcY);
// Accumulate // Accumulate
_accumulatePass.ScheduleDispatch(commandBuffer, dispatchParams, frameIndex, dispatchDstX, dispatchDstY);
_accumulatePass.ScheduleDispatch(commandBuffer, dispatchParams, bufferIndex, dispatchDstX, dispatchDstY);
if (dispatchParams.EnableSharpening) if (dispatchParams.EnableSharpening)
{ {
// Compute the constants // Compute the constants
SetupRcasConstants(dispatchParams); SetupRcasConstants(dispatchParams);
commandBuffer.SetBufferData(_rcasConstantsBuffer, _rcasConstantsArray);
_rcasConstants.UpdateBufferData(commandBuffer);
// Dispatch RCAS // Dispatch RCAS
const int threadGroupWorkRegionDimRcas = 16; const int threadGroupWorkRegionDimRcas = 16;
int threadGroupsX = (Screen.width + threadGroupWorkRegionDimRcas - 1) / threadGroupWorkRegionDimRcas; int threadGroupsX = (Screen.width + threadGroupWorkRegionDimRcas - 1) / threadGroupWorkRegionDimRcas;
int threadGroupsY = (Screen.height + threadGroupWorkRegionDimRcas - 1) / threadGroupWorkRegionDimRcas; int threadGroupsY = (Screen.height + threadGroupWorkRegionDimRcas - 1) / threadGroupWorkRegionDimRcas;
_sharpenPass.ScheduleDispatch(commandBuffer, dispatchParams, frameIndex, threadGroupsX, threadGroupsY);
_sharpenPass.ScheduleDispatch(commandBuffer, dispatchParams, bufferIndex, threadGroupsX, threadGroupsY);
} }
_resourceFrameIndex = (_resourceFrameIndex + 1) % MaxQueuedFrames; _resourceFrameIndex = (_resourceFrameIndex + 1) % MaxQueuedFrames;
@ -272,6 +262,7 @@ namespace FidelityFX.FSR2
Fsr2Resources.DestroyAliasableResources(commandBuffer); Fsr2Resources.DestroyAliasableResources(commandBuffer);
commandBuffer.DisableShaderKeyword("UNITY_FSR_TEXTURE2D_X_ARRAY"); commandBuffer.DisableShaderKeyword("UNITY_FSR_TEXTURE2D_X_ARRAY");
commandBuffer.EndSample(_sampler);
} }
public void GenerateReactiveMask(Fsr2.GenerateReactiveDescription dispatchParams) public void GenerateReactiveMask(Fsr2.GenerateReactiveDescription dispatchParams)
@ -287,11 +278,12 @@ namespace FidelityFX.FSR2
int dispatchSrcX = (dispatchParams.RenderSize.x + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim; int dispatchSrcX = (dispatchParams.RenderSize.x + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
int dispatchSrcY = (dispatchParams.RenderSize.y + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim; int dispatchSrcY = (dispatchParams.RenderSize.y + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
GenReactiveConsts.scale = dispatchParams.Scale;
GenReactiveConsts.threshold = dispatchParams.CutoffThreshold;
GenReactiveConsts.binaryValue = dispatchParams.BinaryValue;
GenReactiveConsts.flags = (uint)dispatchParams.Flags;
commandBuffer.SetBufferData(_generateReactiveConstantsBuffer, _generateReactiveConstantsArray);
ref var genReactiveConsts = ref _generateReactiveConstants.Value;
genReactiveConsts.scale = dispatchParams.Scale;
genReactiveConsts.threshold = dispatchParams.CutoffThreshold;
genReactiveConsts.binaryValue = dispatchParams.BinaryValue;
genReactiveConsts.flags = (uint)dispatchParams.Flags;
_generateReactiveConstants.UpdateBufferData(commandBuffer);
((Fsr2GenerateReactivePass)_generateReactivePass).ScheduleDispatch(commandBuffer, dispatchParams, dispatchSrcX, dispatchSrcY); ((Fsr2GenerateReactivePass)_generateReactivePass).ScheduleDispatch(commandBuffer, dispatchParams, dispatchSrcX, dispatchSrcY);
} }
@ -302,18 +294,19 @@ namespace FidelityFX.FSR2
int dispatchSrcX = (dispatchParams.RenderSize.x + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim; int dispatchSrcX = (dispatchParams.RenderSize.x + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
int dispatchSrcY = (dispatchParams.RenderSize.y + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim; int dispatchSrcY = (dispatchParams.RenderSize.y + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
TcrAutoGenConsts.autoTcThreshold = dispatchParams.AutoTcThreshold;
TcrAutoGenConsts.autoTcScale = dispatchParams.AutoTcScale;
TcrAutoGenConsts.autoReactiveScale = dispatchParams.AutoReactiveScale;
TcrAutoGenConsts.autoReactiveMax = dispatchParams.AutoReactiveMax;
commandBuffer.SetBufferData(_tcrAutogenerateConstantsBuffer, _tcrAutogenerateConstantsArray);
ref var tcrAutoGenConsts = ref _tcrAutogenerateConstants.Value;
tcrAutoGenConsts.autoTcThreshold = dispatchParams.AutoTcThreshold;
tcrAutoGenConsts.autoTcScale = dispatchParams.AutoTcScale;
tcrAutoGenConsts.autoReactiveScale = dispatchParams.AutoReactiveScale;
tcrAutoGenConsts.autoReactiveMax = dispatchParams.AutoReactiveMax;
_tcrAutogenerateConstants.UpdateBufferData(commandBuffer);
_tcrAutogeneratePass.ScheduleDispatch(commandBuffer, dispatchParams, frameIndex, dispatchSrcX, dispatchSrcY); _tcrAutogeneratePass.ScheduleDispatch(commandBuffer, dispatchParams, frameIndex, dispatchSrcX, dispatchSrcY);
} }
private void SetupConstants(Fsr2.DispatchDescription dispatchParams, bool resetAccumulation) private void SetupConstants(Fsr2.DispatchDescription dispatchParams, bool resetAccumulation)
{ {
ref Fsr2.UpscalerConstants constants = ref UpscalerConsts;
ref Fsr2.UpscalerConstants constants = ref _upscalerConstants.Value;
constants.jitterOffset = dispatchParams.JitterOffset; constants.jitterOffset = dispatchParams.JitterOffset;
constants.renderSize = dispatchParams.RenderSize; constants.renderSize = dispatchParams.RenderSize;
@ -327,7 +320,10 @@ namespace FidelityFX.FSR2
constants.viewSpaceToMetersFactor = (dispatchParams.ViewSpaceToMetersFactor > 0.0f) ? dispatchParams.ViewSpaceToMetersFactor : 1.0f; constants.viewSpaceToMetersFactor = (dispatchParams.ViewSpaceToMetersFactor > 0.0f) ? dispatchParams.ViewSpaceToMetersFactor : 1.0f;
// Compute params to enable device depth to view space depth computation in shader // Compute params to enable device depth to view space depth computation in shader
constants.deviceToViewDepth = SetupDeviceDepthToViewSpaceDepthParams(dispatchParams);
bool inverted = (_contextDescription.Flags & Fsr2.InitializationFlags.EnableDepthInverted) != 0;
bool infinite = (_contextDescription.Flags & Fsr2.InitializationFlags.EnableDepthInfinite) != 0;
constants.deviceToViewDepth = FfxUtils.SetupDeviceDepthToViewSpaceDepthParams(
dispatchParams.RenderSize, dispatchParams.CameraNear, dispatchParams.CameraFar, dispatchParams.CameraFovAngleVertical, inverted, infinite);
// To be updated if resource is larger than the actual image size // To be updated if resource is larger than the actual image size
constants.downscaleFactor = new Vector2((float)constants.renderSize.x / _contextDescription.DisplaySize.x, (float)constants.renderSize.y / _contextDescription.DisplaySize.y); constants.downscaleFactor = new Vector2((float)constants.renderSize.x / _contextDescription.DisplaySize.x, (float)constants.renderSize.y / _contextDescription.DisplaySize.y);
@ -345,7 +341,7 @@ namespace FidelityFX.FSR2
_previousJitterOffset = constants.jitterOffset; _previousJitterOffset = constants.jitterOffset;
} }
int jitterPhaseCount = Fsr2.GetJitterPhaseCount(dispatchParams.RenderSize.x, _contextDescription.DisplaySize.x);
int jitterPhaseCount = FfxUtils.GetJitterPhaseCount(dispatchParams.RenderSize.x, _contextDescription.DisplaySize.x);
if (resetAccumulation || constants.jitterPhaseCount == 0) if (resetAccumulation || constants.jitterPhaseCount == 0)
{ {
constants.jitterPhaseCount = jitterPhaseCount; constants.jitterPhaseCount = jitterPhaseCount;
@ -374,78 +370,22 @@ namespace FidelityFX.FSR2
constants.lumaMipDimensions.x = (int)(constants.maxRenderSize.x / mipDiv); constants.lumaMipDimensions.x = (int)(constants.maxRenderSize.x / mipDiv);
constants.lumaMipDimensions.y = (int)(constants.maxRenderSize.y / mipDiv); constants.lumaMipDimensions.y = (int)(constants.maxRenderSize.y / mipDiv);
} }
private Vector4 SetupDeviceDepthToViewSpaceDepthParams(Fsr2.DispatchDescription dispatchParams)
{
bool inverted = (_contextDescription.Flags & Fsr2.InitializationFlags.EnableDepthInverted) != 0;
bool infinite = (_contextDescription.Flags & Fsr2.InitializationFlags.EnableDepthInfinite) != 0;
// make sure it has no impact if near and far plane values are swapped in dispatch params
// the flags "inverted" and "infinite" will decide what transform to use
float min = Mathf.Min(dispatchParams.CameraNear, dispatchParams.CameraFar);
float max = Mathf.Max(dispatchParams.CameraNear, dispatchParams.CameraFar);
if (inverted)
{
(min, max) = (max, min);
}
float q = max / (min - max);
float d = -1.0f;
Vector4 matrixElemC = new Vector4(q, -1.0f - Mathf.Epsilon, q, 0.0f + Mathf.Epsilon);
Vector4 matrixElemE = new Vector4(q * min, -min - Mathf.Epsilon, q * min, max);
// Revert x and y coords
float aspect = (float)dispatchParams.RenderSize.x / dispatchParams.RenderSize.y;
float cotHalfFovY = Mathf.Cos(0.5f * dispatchParams.CameraFovAngleVertical) / Mathf.Sin(0.5f * dispatchParams.CameraFovAngleVertical);
int matrixIndex = (inverted ? 2 : 0) + (infinite ? 1 : 0);
return new Vector4(
d * matrixElemC[matrixIndex],
matrixElemE[matrixIndex],
aspect / cotHalfFovY,
1.0f / cotHalfFovY);
}
private void SetupRcasConstants(Fsr2.DispatchDescription dispatchParams) private void SetupRcasConstants(Fsr2.DispatchDescription dispatchParams)
{ {
int sharpnessIndex = Mathf.RoundToInt(Mathf.Clamp01(dispatchParams.Sharpness) * (RcasConfigs.Length - 1)); int sharpnessIndex = Mathf.RoundToInt(Mathf.Clamp01(dispatchParams.Sharpness) * (RcasConfigs.Length - 1));
RcasConsts = RcasConfigs[sharpnessIndex];
_rcasConstants.Value = RcasConfigs[sharpnessIndex];
} }
private void SetupSpdConstants(Fsr2.DispatchDescription dispatchParams, out Vector2Int dispatchThreadGroupCount) private void SetupSpdConstants(Fsr2.DispatchDescription dispatchParams, out Vector2Int dispatchThreadGroupCount)
{ {
RectInt rectInfo = new RectInt(0, 0, dispatchParams.RenderSize.x, dispatchParams.RenderSize.y);
SpdSetup(rectInfo, out dispatchThreadGroupCount, out var workGroupOffset, out var numWorkGroupsAndMips);
// Downsample // Downsample
ref Fsr2.SpdConstants spdConstants = ref SpdConsts;
spdConstants.numWorkGroups = (uint)numWorkGroupsAndMips.x;
spdConstants.mips = (uint)numWorkGroupsAndMips.y;
spdConstants.workGroupOffsetX = (uint)workGroupOffset.x;
spdConstants.workGroupOffsetY = (uint)workGroupOffset.y;
ref Fsr2.SpdConstants spdConstants = ref _spdConstants.Value;
FfxSpd.SetupSpdConstants(dispatchParams.RenderSize, ref spdConstants.spd, out dispatchThreadGroupCount);
spdConstants.renderSizeX = (uint)dispatchParams.RenderSize.x; spdConstants.renderSizeX = (uint)dispatchParams.RenderSize.x;
spdConstants.renderSizeY = (uint)dispatchParams.RenderSize.y; spdConstants.renderSizeY = (uint)dispatchParams.RenderSize.y;
} }
private static void SpdSetup(RectInt rectInfo, out Vector2Int dispatchThreadGroupCount, out Vector2Int workGroupOffset, out Vector2Int numWorkGroupsAndMips, int mips = -1)
{
workGroupOffset = new Vector2Int(rectInfo.x / 64, rectInfo.y / 64);
int endIndexX = (rectInfo.x + rectInfo.width - 1) / 64;
int endIndexY = (rectInfo.y + rectInfo.height - 1) / 64;
dispatchThreadGroupCount = new Vector2Int(endIndexX + 1 - workGroupOffset.x, endIndexY + 1 - workGroupOffset.y);
numWorkGroupsAndMips = new Vector2Int(dispatchThreadGroupCount.x * dispatchThreadGroupCount.y, mips);
if (mips < 0)
{
float resolution = Math.Max(rectInfo.width, rectInfo.height);
numWorkGroupsAndMips.y = Math.Min(Mathf.FloorToInt(Mathf.Log(resolution, 2.0f)), 12);
}
}
private void DebugCheckDispatch(Fsr2.DispatchDescription dispatchParams) private void DebugCheckDispatch(Fsr2.DispatchDescription dispatchParams)
{ {
if (!dispatchParams.Color.IsValid) if (!dispatchParams.Color.IsValid)
@ -591,28 +531,5 @@ namespace FidelityFX.FSR2
new Fsr2.RcasConstants(1064229695u, 997604214u), new Fsr2.RcasConstants(1064229695u, 997604214u),
new Fsr2.RcasConstants(1065353216u, 1006648320), new Fsr2.RcasConstants(1065353216u, 1006648320),
}; };
private static ComputeBuffer CreateConstantBuffer<TConstants>() where TConstants: struct
{
return new ComputeBuffer(1, Marshal.SizeOf<TConstants>(), ComputeBufferType.Constant);
}
private static void DestroyConstantBuffer(ref ComputeBuffer bufferRef)
{
if (bufferRef == null)
return;
bufferRef.Release();
bufferRef = null;
}
private static void DestroyPass(ref Fsr2Pass pass)
{
if (pass == null)
return;
pass.Dispose();
pass = null;
}
} }
} }

197
Runtime/FSR2/Fsr2Pass.cs

@ -18,10 +18,7 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. // THE SOFTWARE.
using System;
using System.Runtime.InteropServices;
using UnityEngine; using UnityEngine;
using UnityEngine.Profiling;
using UnityEngine.Rendering; using UnityEngine.Rendering;
namespace FidelityFX.FSR2 namespace FidelityFX.FSR2
@ -31,7 +28,7 @@ namespace FidelityFX.FSR2
/// This loosely matches the FfxPipelineState struct from the original FSR2 codebase, wrapped in an object-oriented blanket. /// This loosely matches the FfxPipelineState struct from the original FSR2 codebase, wrapped in an object-oriented blanket.
/// These classes are responsible for loading compute shaders, managing temporary resources, binding resources to shader kernels and dispatching said shaders. /// These classes are responsible for loading compute shaders, managing temporary resources, binding resources to shader kernels and dispatching said shaders.
/// </summary> /// </summary>
internal abstract class Fsr2Pass: IDisposable
internal abstract class Fsr2Pass: FfxPassWithFlags<Fsr2.DispatchDescription, Fsr2.InitializationFlags>
{ {
internal const int ShadingChangeMipLevel = 4; // This matches the FFX_FSR2_SHADING_CHANGE_MIP_LEVEL define internal const int ShadingChangeMipLevel = 4; // This matches the FFX_FSR2_SHADING_CHANGE_MIP_LEVEL define
@ -39,47 +36,21 @@ namespace FidelityFX.FSR2
protected readonly Fsr2Resources Resources; protected readonly Fsr2Resources Resources;
protected readonly ComputeBuffer Constants; protected readonly ComputeBuffer Constants;
protected ComputeShader ComputeShader;
protected int KernelIndex;
protected CustomSampler Sampler;
protected Fsr2Pass(Fsr2.ContextDescription contextDescription, Fsr2Resources resources, ComputeBuffer constants) protected Fsr2Pass(Fsr2.ContextDescription contextDescription, Fsr2Resources resources, ComputeBuffer constants)
: base("FSR2")
{ {
ContextDescription = contextDescription; ContextDescription = contextDescription;
Resources = resources; Resources = resources;
Constants = constants; Constants = constants;
} }
public virtual void Dispose()
{
}
public void ScheduleDispatch(CommandBuffer commandBuffer, Fsr2.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY)
{
commandBuffer.BeginSample(Sampler);
DoScheduleDispatch(commandBuffer, dispatchParams, frameIndex, dispatchX, dispatchY);
commandBuffer.EndSample(Sampler);
}
protected abstract void DoScheduleDispatch(CommandBuffer commandBuffer, Fsr2.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY);
protected void InitComputeShader(string passName, ComputeShader shader) protected void InitComputeShader(string passName, ComputeShader shader)
{ {
InitComputeShader(passName, shader, ContextDescription.Flags); InitComputeShader(passName, shader, ContextDescription.Flags);
} }
private void InitComputeShader(string passName, ComputeShader shader, Fsr2.InitializationFlags flags)
protected override void SetupShaderKeywords(Fsr2.InitializationFlags flags)
{ {
if (shader == null)
{
throw new MissingReferenceException($"Shader for FSR2 pass '{passName}' could not be loaded! Please ensure it is included in the project correctly.");
}
ComputeShader = shader;
KernelIndex = ComputeShader.FindKernel("CS");
Sampler = CustomSampler.Create(passName);
bool useLut = false; bool useLut = false;
#if UNITY_2022_1_OR_NEWER // This will also work in 2020.3.43+ and 2021.3.14+ #if UNITY_2022_1_OR_NEWER // This will also work in 2020.3.43+ and 2021.3.14+
if (SystemInfo.computeSubGroupSize == 64) if (SystemInfo.computeSubGroupSize == 64)
@ -110,20 +81,19 @@ namespace FidelityFX.FSR2
InitComputeShader("Compute Luminance Pyramid", contextDescription.Shaders.computeLuminancePyramidPass); InitComputeShader("Compute Luminance Pyramid", contextDescription.Shaders.computeLuminancePyramidPass);
} }
protected override void DoScheduleDispatch(CommandBuffer commandBuffer, Fsr2.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY)
protected override void DoScheduleDispatch(CommandBuffer commandBuffer, in Fsr2.DispatchDescription dispatchParams, int bufferIndex, int dispatchX, int dispatchY, int dispatchZ)
{ {
ref var color = ref dispatchParams.Color;
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputColor, color.RenderTarget, color.MipLevel, color.SubElement);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputColor, dispatchParams.Color);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavSpdAtomicCount, Resources.SpdAtomicCounter); commandBuffer.SetComputeTextureParam(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.SetComputeTextureMipParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavExposureMipLumaChange, Resources.SceneLuminance, ShadingChangeMipLevel);
commandBuffer.SetComputeTextureMipParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavExposureMip5, Resources.SceneLuminance, 5);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavAutoExposure, Resources.AutoExposure); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavAutoExposure, Resources.AutoExposure);
commandBuffer.SetComputeConstantBufferParam(ComputeShader, Fsr2ShaderIDs.CbFsr2, Constants, 0, Marshal.SizeOf<Fsr2.UpscalerConstants>());
commandBuffer.SetComputeConstantBufferParam(ComputeShader, Fsr2ShaderIDs.CbSpd, _spdConstants, 0, Marshal.SizeOf<Fsr2.SpdConstants>());
commandBuffer.SetComputeConstantBufferParam<Fsr2.UpscalerConstants>(ComputeShader, Fsr2ShaderIDs.CbFsr2, Constants);
commandBuffer.SetComputeConstantBufferParam<Fsr2.SpdConstants>(ComputeShader, Fsr2ShaderIDs.CbSpd, _spdConstants);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, 1);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, dispatchZ);
} }
} }
@ -135,23 +105,18 @@ namespace FidelityFX.FSR2
InitComputeShader("Reconstruct & Dilate", contextDescription.Shaders.reconstructPreviousDepthPass); InitComputeShader("Reconstruct & Dilate", contextDescription.Shaders.reconstructPreviousDepthPass);
} }
protected override void DoScheduleDispatch(CommandBuffer commandBuffer, Fsr2.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY)
protected override void DoScheduleDispatch(CommandBuffer commandBuffer, in Fsr2.DispatchDescription dispatchParams, int bufferIndex, int dispatchX, int dispatchY, int dispatchZ)
{ {
ref var color = ref dispatchParams.Color;
ref var depth = ref dispatchParams.Depth;
ref var motionVectors = ref dispatchParams.MotionVectors;
ref var exposure = ref dispatchParams.Exposure;
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputColor, color.RenderTarget, color.MipLevel, color.SubElement);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputDepth, depth.RenderTarget, depth.MipLevel, depth.SubElement);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputMotionVectors, motionVectors.RenderTarget, motionVectors.MipLevel, motionVectors.SubElement);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputExposure, exposure.RenderTarget, exposure.MipLevel, exposure.SubElement);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputColor, dispatchParams.Color);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputDepth, dispatchParams.Depth);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputMotionVectors, dispatchParams.MotionVectors);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputExposure, dispatchParams.Exposure);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavDilatedMotionVectors, Resources.DilatedMotionVectors[frameIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavDilatedMotionVectors, Resources.DilatedMotionVectors[bufferIndex]);
commandBuffer.SetComputeConstantBufferParam(ComputeShader, Fsr2ShaderIDs.CbFsr2, Constants, 0, Marshal.SizeOf<Fsr2.UpscalerConstants>());
commandBuffer.SetComputeConstantBufferParam<Fsr2.UpscalerConstants>(ComputeShader, Fsr2ShaderIDs.CbFsr2, Constants);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, 1);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, dispatchZ);
} }
} }
@ -163,30 +128,23 @@ namespace FidelityFX.FSR2
InitComputeShader("Depth Clip", contextDescription.Shaders.depthClipPass); InitComputeShader("Depth Clip", contextDescription.Shaders.depthClipPass);
} }
protected override void DoScheduleDispatch(CommandBuffer commandBuffer, Fsr2.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY)
protected override void DoScheduleDispatch(CommandBuffer commandBuffer, in Fsr2.DispatchDescription dispatchParams, int bufferIndex, int dispatchX, int dispatchY, int dispatchZ)
{ {
ref var color = ref dispatchParams.Color;
ref var depth = ref dispatchParams.Depth;
ref var motionVectors = ref dispatchParams.MotionVectors;
ref var exposure = ref dispatchParams.Exposure;
ref var reactive = ref dispatchParams.Reactive;
ref var tac = ref dispatchParams.TransparencyAndComposition;
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputColor, color.RenderTarget, color.MipLevel, color.SubElement);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputDepth, depth.RenderTarget, depth.MipLevel, depth.SubElement);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputMotionVectors, motionVectors.RenderTarget, motionVectors.MipLevel, motionVectors.SubElement);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputExposure, exposure.RenderTarget, exposure.MipLevel, exposure.SubElement);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvReactiveMask, reactive.RenderTarget, reactive.MipLevel, reactive.SubElement);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvTransparencyAndCompositionMask, tac.RenderTarget, tac.MipLevel, tac.SubElement);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputColor, dispatchParams.Color);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputDepth, dispatchParams.Depth);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputMotionVectors, dispatchParams.MotionVectors);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputExposure, dispatchParams.Exposure);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvReactiveMask, dispatchParams.Reactive);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvTransparencyAndCompositionMask, dispatchParams.TransparencyAndComposition);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvReconstructedPrevNearestDepth, Fsr2ShaderIDs.UavReconstructedPrevNearestDepth); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvReconstructedPrevNearestDepth, Fsr2ShaderIDs.UavReconstructedPrevNearestDepth);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvDilatedMotionVectors, Resources.DilatedMotionVectors[frameIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvDilatedMotionVectors, Resources.DilatedMotionVectors[bufferIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvDilatedDepth, Fsr2ShaderIDs.UavDilatedDepth); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvDilatedDepth, Fsr2ShaderIDs.UavDilatedDepth);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvPrevDilatedMotionVectors, Resources.DilatedMotionVectors[frameIndex ^ 1]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvPrevDilatedMotionVectors, Resources.DilatedMotionVectors[bufferIndex ^ 1]);
commandBuffer.SetComputeConstantBufferParam(ComputeShader, Fsr2ShaderIDs.CbFsr2, Constants, 0, Marshal.SizeOf<Fsr2.UpscalerConstants>());
commandBuffer.SetComputeConstantBufferParam<Fsr2.UpscalerConstants>(ComputeShader, Fsr2ShaderIDs.CbFsr2, Constants);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, 1);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, dispatchZ);
} }
} }
@ -198,12 +156,12 @@ namespace FidelityFX.FSR2
InitComputeShader("Create Locks", contextDescription.Shaders.lockPass); InitComputeShader("Create Locks", contextDescription.Shaders.lockPass);
} }
protected override void DoScheduleDispatch(CommandBuffer commandBuffer, Fsr2.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY)
protected override void DoScheduleDispatch(CommandBuffer commandBuffer, in Fsr2.DispatchDescription dispatchParams, int bufferIndex, int dispatchX, int dispatchY, int dispatchZ)
{ {
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvLockInputLuma, Fsr2ShaderIDs.UavLockInputLuma); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvLockInputLuma, Fsr2ShaderIDs.UavLockInputLuma);
commandBuffer.SetComputeConstantBufferParam(ComputeShader, Fsr2ShaderIDs.CbFsr2, Constants, 0, Marshal.SizeOf<Fsr2.UpscalerConstants>());
commandBuffer.SetComputeConstantBufferParam<Fsr2.UpscalerConstants>(ComputeShader, Fsr2ShaderIDs.CbFsr2, Constants);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, 1);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, dispatchZ);
} }
} }
@ -224,7 +182,7 @@ namespace FidelityFX.FSR2
#endif #endif
} }
protected override void DoScheduleDispatch(CommandBuffer commandBuffer, Fsr2.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY)
protected override void DoScheduleDispatch(CommandBuffer commandBuffer, in Fsr2.DispatchDescription dispatchParams, int bufferIndex, int dispatchX, int dispatchY, int dispatchZ)
{ {
#if UNITY_2021_2_OR_NEWER #if UNITY_2021_2_OR_NEWER
if (dispatchParams.EnableSharpening) if (dispatchParams.EnableSharpening)
@ -240,37 +198,34 @@ namespace FidelityFX.FSR2
if ((ContextDescription.Flags & Fsr2.InitializationFlags.EnableDisplayResolutionMotionVectors) == 0) if ((ContextDescription.Flags & Fsr2.InitializationFlags.EnableDisplayResolutionMotionVectors) == 0)
{ {
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvDilatedMotionVectors, Resources.DilatedMotionVectors[frameIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvDilatedMotionVectors, Resources.DilatedMotionVectors[bufferIndex]);
} }
else else
{ {
ref var motionVectors = ref dispatchParams.MotionVectors;
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputMotionVectors, motionVectors.RenderTarget, motionVectors.MipLevel, motionVectors.SubElement);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputMotionVectors, dispatchParams.MotionVectors);
} }
ref var exposure = ref dispatchParams.Exposure;
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputExposure, exposure.RenderTarget, exposure.MipLevel, exposure.SubElement);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputExposure, dispatchParams.Exposure);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvDilatedReactiveMasks, Fsr2ShaderIDs.UavDilatedReactiveMasks); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvDilatedReactiveMasks, Fsr2ShaderIDs.UavDilatedReactiveMasks);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInternalUpscaled, Resources.InternalUpscaled[frameIndex ^ 1]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvLockStatus, Resources.LockStatus[frameIndex ^ 1]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInternalUpscaled, Resources.InternalUpscaled[bufferIndex ^ 1]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvLockStatus, Resources.LockStatus[bufferIndex ^ 1]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvPreparedInputColor, Fsr2ShaderIDs.UavPreparedInputColor); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvPreparedInputColor, Fsr2ShaderIDs.UavPreparedInputColor);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvLanczosLut, Resources.LanczosLut); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvLanczosLut, Resources.LanczosLut);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvUpscaleMaximumBiasLut, Resources.MaximumBiasLut); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvUpscaleMaximumBiasLut, Resources.MaximumBiasLut);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvSceneLuminanceMips, Resources.SceneLuminance); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvSceneLuminanceMips, Resources.SceneLuminance);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvAutoExposure, Resources.AutoExposure); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvAutoExposure, Resources.AutoExposure);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvLumaHistory, Resources.LumaHistory[frameIndex ^ 1]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvLumaHistory, Resources.LumaHistory[bufferIndex ^ 1]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavInternalUpscaled, Resources.InternalUpscaled[frameIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavLockStatus, Resources.LockStatus[frameIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavLumaHistory, Resources.LumaHistory[frameIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavInternalUpscaled, Resources.InternalUpscaled[bufferIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavLockStatus, Resources.LockStatus[bufferIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavLumaHistory, Resources.LumaHistory[bufferIndex]);
ref var output = ref dispatchParams.Output;
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavUpscaledOutput, output.RenderTarget, output.MipLevel, output.SubElement);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavUpscaledOutput, dispatchParams.Output);
commandBuffer.SetComputeConstantBufferParam(ComputeShader, Fsr2ShaderIDs.CbFsr2, Constants, 0, Marshal.SizeOf<Fsr2.UpscalerConstants>());
commandBuffer.SetComputeConstantBufferParam<Fsr2.UpscalerConstants>(ComputeShader, Fsr2ShaderIDs.CbFsr2, Constants);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, 1);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, dispatchZ);
} }
} }
@ -286,19 +241,17 @@ namespace FidelityFX.FSR2
InitComputeShader("RCAS Sharpening", contextDescription.Shaders.sharpenPass); InitComputeShader("RCAS Sharpening", contextDescription.Shaders.sharpenPass);
} }
protected override void DoScheduleDispatch(CommandBuffer commandBuffer, Fsr2.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY)
protected override void DoScheduleDispatch(CommandBuffer commandBuffer, in Fsr2.DispatchDescription dispatchParams, int bufferIndex, int dispatchX, int dispatchY, int dispatchZ)
{ {
ref var exposure = ref dispatchParams.Exposure;
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputExposure, exposure.RenderTarget, exposure.MipLevel, exposure.SubElement);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvRcasInput, Resources.InternalUpscaled[frameIndex]);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputExposure, dispatchParams.Exposure);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvRcasInput, Resources.InternalUpscaled[bufferIndex]);
ref var output = ref dispatchParams.Output;
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavUpscaledOutput, output.RenderTarget, output.MipLevel, output.SubElement);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavUpscaledOutput, dispatchParams.Output);
commandBuffer.SetComputeConstantBufferParam(ComputeShader, Fsr2ShaderIDs.CbFsr2, Constants, 0, Marshal.SizeOf<Fsr2.UpscalerConstants>());
commandBuffer.SetComputeConstantBufferParam(ComputeShader, Fsr2ShaderIDs.CbRcas, _rcasConstants, 0, Marshal.SizeOf<Fsr2.RcasConstants>());
commandBuffer.SetComputeConstantBufferParam<Fsr2.UpscalerConstants>(ComputeShader, Fsr2ShaderIDs.CbFsr2, Constants);
commandBuffer.SetComputeConstantBufferParam<Fsr2.RcasConstants>(ComputeShader, Fsr2ShaderIDs.CbRcas, _rcasConstants);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, 1);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, dispatchZ);
} }
} }
@ -314,7 +267,7 @@ namespace FidelityFX.FSR2
InitComputeShader("Auto-Generate Reactive Mask", contextDescription.Shaders.autoGenReactivePass); InitComputeShader("Auto-Generate Reactive Mask", contextDescription.Shaders.autoGenReactivePass);
} }
protected override void DoScheduleDispatch(CommandBuffer commandBuffer, Fsr2.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY)
protected override void DoScheduleDispatch(CommandBuffer commandBuffer, in Fsr2.DispatchDescription dispatchParams, int bufferIndex, int dispatchX, int dispatchY, int dispatchZ)
{ {
} }
@ -322,15 +275,11 @@ namespace FidelityFX.FSR2
{ {
commandBuffer.BeginSample(Sampler); commandBuffer.BeginSample(Sampler);
ref var opaqueOnly = ref dispatchParams.ColorOpaqueOnly;
ref var color = ref dispatchParams.ColorPreUpscale;
ref var reactive = ref dispatchParams.OutReactive;
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvOpaqueOnly, dispatchParams.ColorOpaqueOnly);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputColor, dispatchParams.ColorPreUpscale);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavAutoReactive, dispatchParams.OutReactive);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvOpaqueOnly, opaqueOnly.RenderTarget, opaqueOnly.MipLevel, opaqueOnly.SubElement);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputColor, color.RenderTarget, color.MipLevel, color.SubElement);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavAutoReactive, reactive.RenderTarget, reactive.MipLevel, reactive.SubElement);
commandBuffer.SetComputeConstantBufferParam(ComputeShader, Fsr2ShaderIDs.CbGenReactive, _generateReactiveConstants, 0, Marshal.SizeOf<Fsr2.GenerateReactiveConstants>());
commandBuffer.SetComputeConstantBufferParam<Fsr2.GenerateReactiveConstants>(ComputeShader, Fsr2ShaderIDs.CbGenReactive, _generateReactiveConstants);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, 1); commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, 1);
@ -350,31 +299,25 @@ namespace FidelityFX.FSR2
InitComputeShader("Auto-Generate Transparency & Composition Mask", contextDescription.Shaders.tcrAutoGenPass); InitComputeShader("Auto-Generate Transparency & Composition Mask", contextDescription.Shaders.tcrAutoGenPass);
} }
protected override void DoScheduleDispatch(CommandBuffer commandBuffer, Fsr2.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY)
protected override void DoScheduleDispatch(CommandBuffer commandBuffer, in Fsr2.DispatchDescription dispatchParams, int bufferIndex, int dispatchX, int dispatchY, int dispatchZ)
{ {
ref var color = ref dispatchParams.Color;
ref var motionVectors = ref dispatchParams.MotionVectors;
ref var opaqueOnly = ref dispatchParams.ColorOpaqueOnly;
ref var reactive = ref dispatchParams.Reactive;
ref var tac = ref dispatchParams.TransparencyAndComposition;
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvOpaqueOnly, opaqueOnly.RenderTarget, opaqueOnly.MipLevel, opaqueOnly.SubElement);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputColor, color.RenderTarget, color.MipLevel, color.SubElement);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputMotionVectors, motionVectors.RenderTarget, motionVectors.MipLevel, motionVectors.SubElement);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvPrevColorPreAlpha, Resources.PrevPreAlpha[frameIndex ^ 1]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvPrevColorPostAlpha, Resources.PrevPostAlpha[frameIndex ^ 1]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvReactiveMask, reactive.RenderTarget, reactive.MipLevel, reactive.SubElement);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvTransparencyAndCompositionMask, tac.RenderTarget, tac.MipLevel, tac.SubElement);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvOpaqueOnly, dispatchParams.ColorOpaqueOnly);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputColor, dispatchParams.Color);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputMotionVectors, dispatchParams.MotionVectors);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvPrevColorPreAlpha, Resources.PrevPreAlpha[bufferIndex ^ 1]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvPrevColorPostAlpha, Resources.PrevPostAlpha[bufferIndex ^ 1]);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvReactiveMask, dispatchParams.Reactive);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvTransparencyAndCompositionMask, dispatchParams.TransparencyAndComposition);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavAutoReactive, Resources.AutoReactive); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavAutoReactive, Resources.AutoReactive);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavAutoComposition, Resources.AutoComposition); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavAutoComposition, Resources.AutoComposition);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavPrevColorPreAlpha, Resources.PrevPreAlpha[frameIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavPrevColorPostAlpha, Resources.PrevPostAlpha[frameIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavPrevColorPreAlpha, Resources.PrevPreAlpha[bufferIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavPrevColorPostAlpha, Resources.PrevPostAlpha[bufferIndex]);
commandBuffer.SetComputeConstantBufferParam(ComputeShader, Fsr2ShaderIDs.CbFsr2, Constants, 0, Marshal.SizeOf<Fsr2.UpscalerConstants>());
commandBuffer.SetComputeConstantBufferParam(ComputeShader, Fsr2ShaderIDs.CbGenReactive, _tcrAutogenerateConstants, 0, Marshal.SizeOf<Fsr2.GenerateReactiveConstants2>());
commandBuffer.SetComputeConstantBufferParam<Fsr2.UpscalerConstants>(ComputeShader, Fsr2ShaderIDs.CbFsr2, Constants);
commandBuffer.SetComputeConstantBufferParam<Fsr2.GenerateReactiveConstants2>(ComputeShader, Fsr2ShaderIDs.CbGenReactive, _tcrAutogenerateConstants);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, 1);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, dispatchZ);
} }
} }
} }

83
Runtime/FSR2/Fsr2Resources.cs

@ -29,7 +29,7 @@ namespace FidelityFX.FSR2
/// Helper class for bundling and managing persistent resources required by the FSR2 process. /// Helper class for bundling and managing persistent resources required by the FSR2 process.
/// This includes lookup tables, default fallback resources and double-buffered resources that get swapped between frames. /// This includes lookup tables, default fallback resources and double-buffered resources that get swapped between frames.
/// </summary> /// </summary>
internal class Fsr2Resources
internal class Fsr2Resources: FfxResourcesBase
{ {
public Texture2D DefaultExposure; public Texture2D DefaultExposure;
public Texture2D DefaultReactive; public Texture2D DefaultReactive;
@ -51,13 +51,7 @@ namespace FidelityFX.FSR2
{ {
// Generate the data for the LUT // Generate the data for the LUT
const int lanczos2LutWidth = 128; const int lanczos2LutWidth = 128;
float[] lanczos2Weights = new float[lanczos2LutWidth];
for (int currentLanczosWidthIndex = 0; currentLanczosWidthIndex < lanczos2LutWidth; ++currentLanczosWidthIndex)
{
float x = 2.0f * currentLanczosWidthIndex / (lanczos2LutWidth - 1);
float y = Fsr2.Lanczos2(x);
lanczos2Weights[currentLanczosWidthIndex] = y;
}
float[] lanczos2Weights = FfxUtils.GenerateLanczos2Table(lanczos2LutWidth);
float[] maximumBias = new float[MaximumBiasTextureWidth * MaximumBiasTextureHeight]; float[] maximumBias = new float[MaximumBiasTextureWidth * MaximumBiasTextureHeight];
for (int i = 0; i < maximumBias.Length; ++i) for (int i = 0; i < maximumBias.Length; ++i)
@ -67,40 +61,27 @@ namespace FidelityFX.FSR2
// Resource FSR2_LanczosLutData: FFX_RESOURCE_USAGE_READ_ONLY, FFX_SURFACE_FORMAT_R16_SNORM, FFX_RESOURCE_FLAGS_NONE // Resource FSR2_LanczosLutData: FFX_RESOURCE_USAGE_READ_ONLY, FFX_SURFACE_FORMAT_R16_SNORM, FFX_RESOURCE_FLAGS_NONE
// R16_SNorm textures are not supported by Unity on most platforms, strangely enough. So instead we use R32_SFloat and upload pre-normalized float data. // R16_SNorm textures are not supported by Unity on most platforms, strangely enough. So instead we use R32_SFloat and upload pre-normalized float data.
LanczosLut = new Texture2D(lanczos2LutWidth, 1, GraphicsFormat.R32_SFloat, TextureCreationFlags.None) { name = "FSR2_LanczosLutData" };
LanczosLut.SetPixelData(lanczos2Weights, 0);
LanczosLut.Apply();
LanczosLut = CreateLookup("FSR2_LanczosLutData", new Vector2Int(lanczos2LutWidth, 1), GraphicsFormat.R32_SFloat, lanczos2Weights);
// Resource FSR2_MaximumUpsampleBias: FFX_RESOURCE_USAGE_READ_ONLY, FFX_SURFACE_FORMAT_R16_SNORM, FFX_RESOURCE_FLAGS_NONE // Resource FSR2_MaximumUpsampleBias: FFX_RESOURCE_USAGE_READ_ONLY, FFX_SURFACE_FORMAT_R16_SNORM, FFX_RESOURCE_FLAGS_NONE
MaximumBiasLut = new Texture2D(MaximumBiasTextureWidth, MaximumBiasTextureHeight, GraphicsFormat.R32_SFloat, TextureCreationFlags.None) { name = "FSR2_MaximumUpsampleBias" };
MaximumBiasLut.SetPixelData(maximumBias, 0);
MaximumBiasLut.Apply();
MaximumBiasLut = CreateLookup("FSR2_MaximumUpsampleBias", new Vector2Int(MaximumBiasTextureWidth, MaximumBiasTextureHeight), GraphicsFormat.R32_SFloat, maximumBias);
// Resource FSR2_DefaultExposure: FFX_RESOURCE_USAGE_READ_ONLY, FFX_SURFACE_FORMAT_R32G32_FLOAT, FFX_RESOURCE_FLAGS_NONE // Resource FSR2_DefaultExposure: FFX_RESOURCE_USAGE_READ_ONLY, FFX_SURFACE_FORMAT_R32G32_FLOAT, FFX_RESOURCE_FLAGS_NONE
DefaultExposure = new Texture2D(1, 1, GraphicsFormat.R32G32_SFloat, TextureCreationFlags.None) { name = "FSR2_DefaultExposure" };
DefaultExposure.SetPixel(0, 0, Color.clear);
DefaultExposure.Apply();
DefaultExposure = CreateLookup("FSR2_DefaultExposure", GraphicsFormat.R32G32_SFloat, Color.clear);
// Resource FSR2_DefaultReactivityMask: FFX_RESOURCE_USAGE_READ_ONLY, FFX_SURFACE_FORMAT_R8_UNORM, FFX_RESOURCE_FLAGS_NONE // Resource FSR2_DefaultReactivityMask: FFX_RESOURCE_USAGE_READ_ONLY, FFX_SURFACE_FORMAT_R8_UNORM, FFX_RESOURCE_FLAGS_NONE
DefaultReactive = new Texture2D(1, 1, GraphicsFormat.R8_UNorm, TextureCreationFlags.None) { name = "FSR2_DefaultReactivityMask" };
DefaultReactive.SetPixel(0, 0, Color.clear);
DefaultReactive.Apply();
DefaultReactive = CreateLookup("FSR2_DefaultReactivityMask", GraphicsFormat.R8_UNorm, Color.clear);
// Resource FSR2_SpdAtomicCounter: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R32_UINT, FFX_RESOURCE_FLAGS_ALIASABLE // 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. // 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();
SpdAtomicCounter = CreateResource("FSR2_SpdAtomicCounter", Vector2Int.one, GraphicsFormat.R32_UInt);
// Resource FSR2_AutoExposure: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R32G32_FLOAT, FFX_RESOURCE_FLAGS_NONE // 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();
AutoExposure = CreateResource("FSR2_AutoExposure", Vector2Int.one, GraphicsFormat.R32G32_SFloat);
// Resource FSR2_ExposureMips: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R16_FLOAT, FFX_RESOURCE_FLAGS_ALIASABLE // 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. // 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.
int w = contextDescription.MaxRenderSize.x / 2, h = contextDescription.MaxRenderSize.y / 2;
int mipCount = 1 + Mathf.FloorToInt(Mathf.Log(Math.Max(w, h), 2.0f));
SceneLuminance = new RenderTexture(w, h, 0, GraphicsFormat.R16_SFloat, mipCount) { name = "FSR2_ExposureMips", enableRandomWrite = true, useMipMap = true, autoGenerateMips = false };
SceneLuminance.Create();
SceneLuminance = CreateResourceMips("FSR2_ExposureMips", contextDescription.MaxRenderSize / 2, GraphicsFormat.R16_SFloat);
// Resources FSR2_InternalDilatedVelocity1/2: FFX_RESOURCE_USAGE_RENDERTARGET | FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R16G16_FLOAT, FFX_RESOURCE_FLAGS_NONE // 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); CreateDoubleBufferedResource(DilatedMotionVectors, "FSR2_InternalDilatedVelocity", contextDescription.MaxRenderSize, GraphicsFormat.R16G16_SFloat);
@ -118,12 +99,10 @@ namespace FidelityFX.FSR2
public void CreateTcrAutogenResources(Fsr2.ContextDescription contextDescription) public void CreateTcrAutogenResources(Fsr2.ContextDescription contextDescription)
{ {
// Resource FSR2_AutoReactive: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R8_UNORM, FFX_RESOURCE_FLAGS_NONE // Resource FSR2_AutoReactive: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R8_UNORM, FFX_RESOURCE_FLAGS_NONE
AutoReactive = new RenderTexture(contextDescription.MaxRenderSize.x, contextDescription.MaxRenderSize.y, 0, GraphicsFormat.R8_UNorm) { name = "FSR2_AutoReactive", enableRandomWrite = true };
AutoReactive.Create();
AutoReactive = CreateResource("FSR2_AutoReactive", contextDescription.MaxRenderSize, GraphicsFormat.R8_UNorm);
// Resource FSR2_AutoComposition: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R8_UNORM, FFX_RESOURCE_FLAGS_NONE // Resource FSR2_AutoComposition: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R8_UNORM, FFX_RESOURCE_FLAGS_NONE
AutoComposition = new RenderTexture(contextDescription.MaxRenderSize.x, contextDescription.MaxRenderSize.y, 0, GraphicsFormat.R8_UNorm) { name = "FSR2_AutoComposition", enableRandomWrite = true };
AutoComposition.Create();
AutoComposition = CreateResource("FSR2_AutoComposition", contextDescription.MaxRenderSize, GraphicsFormat.R8_UNorm);
// Resources FSR2_PrevPreAlpha0/1: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R11G11B10_FLOAT, FFX_RESOURCE_FLAGS_NONE // Resources FSR2_PrevPreAlpha0/1: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R11G11B10_FLOAT, FFX_RESOURCE_FLAGS_NONE
CreateDoubleBufferedResource(PrevPreAlpha, "FSR2_PrevPreAlpha", contextDescription.MaxRenderSize, GraphicsFormat.B10G11R11_UFloatPack32); CreateDoubleBufferedResource(PrevPreAlpha, "FSR2_PrevPreAlpha", contextDescription.MaxRenderSize, GraphicsFormat.B10G11R11_UFloatPack32);
@ -169,15 +148,6 @@ namespace FidelityFX.FSR2
commandBuffer.ReleaseTemporaryRT(Fsr2ShaderIDs.UavNewLocks); commandBuffer.ReleaseTemporaryRT(Fsr2ShaderIDs.UavNewLocks);
} }
private static void CreateDoubleBufferedResource(RenderTexture[] resource, string name, Vector2Int size, GraphicsFormat format)
{
for (int i = 0; i < 2; ++i)
{
resource[i] = new RenderTexture(size.x, size.y, 0, format) { name = name + (i + 1), enableRandomWrite = true };
resource[i].Create();
}
}
public void Destroy() public void Destroy()
{ {
DestroyTcrAutogenResources(); DestroyTcrAutogenResources();
@ -201,37 +171,6 @@ namespace FidelityFX.FSR2
DestroyResource(ref AutoComposition); DestroyResource(ref AutoComposition);
DestroyResource(ref AutoReactive); DestroyResource(ref AutoReactive);
} }
private static void DestroyResource(ref Texture2D resource)
{
if (resource == null)
return;
#if UNITY_EDITOR
if (Application.isPlaying && !UnityEditor.EditorApplication.isPaused)
UnityEngine.Object.Destroy(resource);
else
UnityEngine.Object.DestroyImmediate(resource);
#else
UnityEngine.Object.Destroy(resource);
#endif
resource = null;
}
private static void DestroyResource(ref RenderTexture resource)
{
if (resource == null)
return;
resource.Release();
resource = null;
}
private static void DestroyResource(RenderTexture[] resource)
{
for (int i = 0; i < resource.Length; ++i)
DestroyResource(ref resource[i]);
}
private const int MaximumBiasTextureWidth = 16; private const int MaximumBiasTextureWidth = 16;
private const int MaximumBiasTextureHeight = 16; private const int MaximumBiasTextureHeight = 16;

49
Runtime/FSR3/Fsr3Upscaler.cs

@ -89,51 +89,6 @@ namespace FidelityFX.FSR3
renderHeight = Mathf.RoundToInt(displayHeight / ratio); renderHeight = Mathf.RoundToInt(displayHeight / ratio);
} }
public static float GetMipmapBiasOffset(int renderWidth, int displayWidth)
{
return Mathf.Log((float)renderWidth / displayWidth, 2.0f) - 1.0f;
}
public static int GetJitterPhaseCount(int renderWidth, int displayWidth)
{
const float basePhaseCount = 8.0f;
int jitterPhaseCount = (int)(basePhaseCount * Mathf.Pow((float)displayWidth / renderWidth, 2.0f));
return jitterPhaseCount;
}
public static void GetJitterOffset(out float outX, out float outY, int index, int phaseCount)
{
outX = Halton((index % phaseCount) + 1, 2) - 0.5f;
outY = Halton((index % phaseCount) + 1, 3) - 0.5f;
}
// Calculate halton number for index and base.
private static float Halton(int index, int @base)
{
float f = 1.0f, result = 0.0f;
for (int currentIndex = index; currentIndex > 0;) {
f /= @base;
result += f * (currentIndex % @base);
currentIndex = (int)Mathf.Floor((float)currentIndex / @base);
}
return result;
}
public static float Lanczos2(float value)
{
return Mathf.Abs(value) < Mathf.Epsilon ? 1.0f : Mathf.Sin(Mathf.PI * value) / (Mathf.PI * value) * (Mathf.Sin(0.5f * Mathf.PI * value) / (0.5f * Mathf.PI * value));
}
#if !UNITY_2021_1_OR_NEWER
internal static void SetBufferData(this CommandBuffer commandBuffer, ComputeBuffer computeBuffer, Array data)
{
commandBuffer.SetComputeBufferData(computeBuffer, data);
}
#endif
public enum QualityMode public enum QualityMode
{ {
NativeAA = 0, NativeAA = 0,
@ -270,9 +225,7 @@ namespace FidelityFX.FSR3
[Serializable, StructLayout(LayoutKind.Sequential)] [Serializable, StructLayout(LayoutKind.Sequential)]
internal struct SpdConstants internal struct SpdConstants
{ {
public uint mips;
public uint numWorkGroups;
public uint workGroupOffsetX, workGroupOffsetY;
public FfxSpd.SpdConstants spd;
public uint renderSizeX, renderSizeY; public uint renderSizeX, renderSizeY;
} }

242
Runtime/FSR3/Fsr3UpscalerContext.cs

@ -21,6 +21,7 @@
using System; using System;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using UnityEngine; using UnityEngine;
using UnityEngine.Profiling;
using UnityEngine.Rendering; using UnityEngine.Rendering;
namespace FidelityFX.FSR3 namespace FidelityFX.FSR3
@ -31,7 +32,7 @@ namespace FidelityFX.FSR3
/// Note that this class does not know anything about Unity render pipelines; all it knows is CommandBuffers and RenderTargetIdentifiers. /// Note that this class does not know anything about Unity render pipelines; all it knows is CommandBuffers and RenderTargetIdentifiers.
/// This should make it suitable for integration with any of the available Unity render pipelines. /// This should make it suitable for integration with any of the available Unity render pipelines.
/// </summary> /// </summary>
public class Fsr3UpscalerContext
public class Fsr3UpscalerContext: FfxContextBase
{ {
private const int MaxQueuedFrames = 16; private const int MaxQueuedFrames = 16;
@ -54,48 +55,36 @@ namespace FidelityFX.FSR3
private readonly Fsr3UpscalerResources _resources = new Fsr3UpscalerResources(); private readonly Fsr3UpscalerResources _resources = new Fsr3UpscalerResources();
private ComputeBuffer _upscalerConstantsBuffer;
private readonly Fsr3Upscaler.UpscalerConstants[] _upscalerConstantsArray = { new Fsr3Upscaler.UpscalerConstants() };
private ref Fsr3Upscaler.UpscalerConstants UpscalerConsts => ref _upscalerConstantsArray[0];
private ComputeBuffer _spdConstantsBuffer;
private readonly Fsr3Upscaler.SpdConstants[] _spdConstantsArray = { new Fsr3Upscaler.SpdConstants() };
private ref Fsr3Upscaler.SpdConstants SpdConsts => ref _spdConstantsArray[0];
private ComputeBuffer _rcasConstantsBuffer;
private readonly Fsr3Upscaler.RcasConstants[] _rcasConstantsArray = new Fsr3Upscaler.RcasConstants[1];
private ref Fsr3Upscaler.RcasConstants RcasConsts => ref _rcasConstantsArray[0];
private ComputeBuffer _generateReactiveConstantsBuffer;
private readonly Fsr3Upscaler.GenerateReactiveConstants[] _generateReactiveConstantsArray = { new Fsr3Upscaler.GenerateReactiveConstants() };
private ref Fsr3Upscaler.GenerateReactiveConstants GenReactiveConsts => ref _generateReactiveConstantsArray[0];
private ComputeBuffer _tcrAutogenerateConstantsBuffer;
private readonly Fsr3Upscaler.GenerateReactiveConstants2[] _tcrAutogenerateConstantsArray = { new Fsr3Upscaler.GenerateReactiveConstants2() };
private ref Fsr3Upscaler.GenerateReactiveConstants2 TcrAutoGenConsts => ref _tcrAutogenerateConstantsArray[0];
private readonly ConstantsBuffer<Fsr3Upscaler.UpscalerConstants> _upscalerConstants = new ConstantsBuffer<Fsr3Upscaler.UpscalerConstants>();
private readonly ConstantsBuffer<Fsr3Upscaler.SpdConstants> _spdConstants = new ConstantsBuffer<Fsr3Upscaler.SpdConstants>();
private readonly ConstantsBuffer<Fsr3Upscaler.RcasConstants> _rcasConstants = new ConstantsBuffer<Fsr3Upscaler.RcasConstants>();
private readonly ConstantsBuffer<Fsr3Upscaler.GenerateReactiveConstants> _generateReactiveConstants = new ConstantsBuffer<Fsr3Upscaler.GenerateReactiveConstants>();
private readonly ConstantsBuffer<Fsr3Upscaler.GenerateReactiveConstants2> _tcrAutogenerateConstants = new ConstantsBuffer<Fsr3Upscaler.GenerateReactiveConstants2>();
private bool _firstExecution; private bool _firstExecution;
private int _resourceFrameIndex; private int _resourceFrameIndex;
private Vector2 _previousJitterOffset; private Vector2 _previousJitterOffset;
private float _preExposure; private float _preExposure;
private float _previousFramePreExposure; private float _previousFramePreExposure;
private readonly CustomSampler _sampler = CustomSampler.Create("FSR3 Upscaler");
public void Create(Fsr3Upscaler.ContextDescription contextDescription) public void Create(Fsr3Upscaler.ContextDescription contextDescription)
{ {
_contextDescription = contextDescription; _contextDescription = contextDescription;
_commandBuffer = new CommandBuffer { name = "FSR3 Upscaler" }; _commandBuffer = new CommandBuffer { name = "FSR3 Upscaler" };
_upscalerConstantsBuffer = CreateConstantBuffer<Fsr3Upscaler.UpscalerConstants>();
_spdConstantsBuffer = CreateConstantBuffer<Fsr3Upscaler.SpdConstants>();
_rcasConstantsBuffer = CreateConstantBuffer<Fsr3Upscaler.RcasConstants>();
_generateReactiveConstantsBuffer = CreateConstantBuffer<Fsr3Upscaler.GenerateReactiveConstants>();
_tcrAutogenerateConstantsBuffer = CreateConstantBuffer<Fsr3Upscaler.GenerateReactiveConstants2>();
_upscalerConstants.Create();
_spdConstants.Create();
_rcasConstants.Create();
_generateReactiveConstants.Create();
_tcrAutogenerateConstants.Create();
// Set defaults // Set defaults
_firstExecution = true; _firstExecution = true;
_resourceFrameIndex = 0; _resourceFrameIndex = 0;
UpscalerConsts.maxUpscaleSize = _contextDescription.MaxUpscaleSize;
_upscalerConstants.Value.maxUpscaleSize = _contextDescription.MaxUpscaleSize;
_resources.Create(_contextDescription); _resources.Create(_contextDescription);
CreatePasses(); CreatePasses();
@ -103,18 +92,18 @@ namespace FidelityFX.FSR3
private void CreatePasses() private void CreatePasses()
{ {
_prepareInputsPass = new Fsr3UpscalerPrepareInputsPass(_contextDescription, _resources, _upscalerConstantsBuffer);
_lumaPyramidPass = new Fsr3UpscalerLumaPyramidPass(_contextDescription, _resources, _upscalerConstantsBuffer, _spdConstantsBuffer);
_shadingChangePyramidPass = new Fsr3UpscalerShadingChangePyramidPass(_contextDescription, _resources, _upscalerConstantsBuffer, _spdConstantsBuffer);
_shadingChangePass = new Fsr3UpscalerShadingChangePass(_contextDescription, _resources, _upscalerConstantsBuffer);
_prepareReactivityPass = new Fsr3UpscalerPrepareReactivityPass(_contextDescription, _resources, _upscalerConstantsBuffer);
_lumaInstabilityPass = new Fsr3UpscalerLumaInstabilityPass(_contextDescription, _resources, _upscalerConstantsBuffer);
_accumulatePass = new Fsr3UpscalerAccumulatePass(_contextDescription, _resources, _upscalerConstantsBuffer);
_sharpenPass = new Fsr3UpscalerSharpenPass(_contextDescription, _resources, _upscalerConstantsBuffer, _rcasConstantsBuffer);
_generateReactivePass = new Fsr3UpscalerGenerateReactivePass(_contextDescription, _resources, _generateReactiveConstantsBuffer);
_tcrAutogeneratePass = new Fsr3UpscalerTcrAutogeneratePass(_contextDescription, _resources, _upscalerConstantsBuffer, _tcrAutogenerateConstantsBuffer);
_prepareInputsPass = new Fsr3UpscalerPrepareInputsPass(_contextDescription, _resources, _upscalerConstants);
_lumaPyramidPass = new Fsr3UpscalerLumaPyramidPass(_contextDescription, _resources, _upscalerConstants, _spdConstants);
_shadingChangePyramidPass = new Fsr3UpscalerShadingChangePyramidPass(_contextDescription, _resources, _upscalerConstants, _spdConstants);
_shadingChangePass = new Fsr3UpscalerShadingChangePass(_contextDescription, _resources, _upscalerConstants);
_prepareReactivityPass = new Fsr3UpscalerPrepareReactivityPass(_contextDescription, _resources, _upscalerConstants);
_lumaInstabilityPass = new Fsr3UpscalerLumaInstabilityPass(_contextDescription, _resources, _upscalerConstants);
_accumulatePass = new Fsr3UpscalerAccumulatePass(_contextDescription, _resources, _upscalerConstants);
_sharpenPass = new Fsr3UpscalerSharpenPass(_contextDescription, _resources, _upscalerConstants, _rcasConstants);
_generateReactivePass = new Fsr3UpscalerGenerateReactivePass(_contextDescription, _resources, _upscalerConstants);
_tcrAutogeneratePass = new Fsr3UpscalerTcrAutogeneratePass(_contextDescription, _resources, _upscalerConstants, _tcrAutogenerateConstants);
#if UNITY_EDITOR || DEVELOPMENT_BUILD #if UNITY_EDITOR || DEVELOPMENT_BUILD
_debugViewPass = new Fsr3UpscalerDebugViewPass(_contextDescription, _resources, _upscalerConstantsBuffer);
_debugViewPass = new Fsr3UpscalerDebugViewPass(_contextDescription, _resources, _upscalerConstants);
#endif #endif
} }
@ -136,11 +125,11 @@ namespace FidelityFX.FSR3
_resources.Destroy(); _resources.Destroy();
DestroyConstantBuffer(ref _tcrAutogenerateConstantsBuffer);
DestroyConstantBuffer(ref _generateReactiveConstantsBuffer);
DestroyConstantBuffer(ref _rcasConstantsBuffer);
DestroyConstantBuffer(ref _spdConstantsBuffer);
DestroyConstantBuffer(ref _upscalerConstantsBuffer);
_tcrAutogenerateConstants.Destroy();
_generateReactiveConstants.Destroy();
_rcasConstants.Destroy();
_spdConstants.Destroy();
_upscalerConstants.Destroy();
if (_commandBuffer != null) if (_commandBuffer != null)
{ {
@ -158,6 +147,8 @@ namespace FidelityFX.FSR3
public void Dispatch(Fsr3Upscaler.DispatchDescription dispatchParams, CommandBuffer commandBuffer) public void Dispatch(Fsr3Upscaler.DispatchDescription dispatchParams, CommandBuffer commandBuffer)
{ {
commandBuffer.BeginSample(_sampler);
if ((_contextDescription.Flags & Fsr3Upscaler.InitializationFlags.EnableDebugChecking) != 0) if ((_contextDescription.Flags & Fsr3Upscaler.InitializationFlags.EnableDebugChecking) != 0)
{ {
DebugCheckDispatch(dispatchParams); DebugCheckDispatch(dispatchParams);
@ -178,7 +169,7 @@ namespace FidelityFX.FSR3
commandBuffer.ClearRenderTarget(false, true, Color.clear); commandBuffer.ClearRenderTarget(false, true, Color.clear);
} }
int frameIndex = _resourceFrameIndex % 2;
int bufferIndex = _resourceFrameIndex % 2;
bool resetAccumulation = dispatchParams.Reset || _firstExecution; bool resetAccumulation = dispatchParams.Reset || _firstExecution;
_firstExecution = false; _firstExecution = false;
@ -197,7 +188,7 @@ namespace FidelityFX.FSR3
if (resetAccumulation) if (resetAccumulation)
{ {
RenderTargetIdentifier opaqueOnly = dispatchParams.ColorOpaqueOnly.IsValid ? dispatchParams.ColorOpaqueOnly.RenderTarget : Fsr3ShaderIDs.SrvOpaqueOnly; RenderTargetIdentifier opaqueOnly = dispatchParams.ColorOpaqueOnly.IsValid ? dispatchParams.ColorOpaqueOnly.RenderTarget : Fsr3ShaderIDs.SrvOpaqueOnly;
commandBuffer.Blit(_resources.PrevPreAlpha[frameIndex ^ 1], opaqueOnly);
commandBuffer.Blit(_resources.PrevPreAlpha[bufferIndex ^ 1], opaqueOnly);
} }
} }
else if (_resources.AutoReactive != null) else if (_resources.AutoReactive != null)
@ -214,17 +205,19 @@ namespace FidelityFX.FSR3
// Reactive mask bias // Reactive mask bias
const int threadGroupWorkRegionDim = 8; const int threadGroupWorkRegionDim = 8;
int dispatchSrcX = (UpscalerConsts.renderSize.x + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
int dispatchSrcY = (UpscalerConsts.renderSize.y + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
int dispatchDstX = (UpscalerConsts.upscaleSize.x + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
int dispatchDstY = (UpscalerConsts.upscaleSize.y + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
int dispatchShadingChangePassX = ((UpscalerConsts.renderSize.x / 2) + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
int dispatchShadingChangePassY = ((UpscalerConsts.renderSize.y / 2) + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
var renderSize = _upscalerConstants.Value.renderSize;
var upscaleSize = _upscalerConstants.Value.upscaleSize;
int dispatchSrcX = (renderSize.x + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
int dispatchSrcY = (renderSize.y + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
int dispatchDstX = (upscaleSize.x + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
int dispatchDstY = (upscaleSize.y + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
int dispatchShadingChangePassX = ((renderSize.x / 2) + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
int dispatchShadingChangePassY = ((renderSize.y / 2) + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
// Clear reconstructed depth for max depth store // Clear reconstructed depth for max depth store
if (resetAccumulation) if (resetAccumulation)
{ {
commandBuffer.SetRenderTarget(_resources.Accumulation[frameIndex ^ 1]);
commandBuffer.SetRenderTarget(_resources.Accumulation[bufferIndex ^ 1]);
commandBuffer.ClearRenderTarget(false, true, Color.clear); commandBuffer.ClearRenderTarget(false, true, Color.clear);
commandBuffer.SetRenderTarget(_resources.SpdMips); commandBuffer.SetRenderTarget(_resources.SpdMips);
@ -248,43 +241,43 @@ namespace FidelityFX.FSR3
SetupSpdConstants(dispatchParams, out var dispatchThreadGroupCount); SetupSpdConstants(dispatchParams, out var dispatchThreadGroupCount);
// Initialize constant buffers data // Initialize constant buffers data
commandBuffer.SetBufferData(_upscalerConstantsBuffer, _upscalerConstantsArray);
commandBuffer.SetBufferData(_spdConstantsBuffer, _spdConstantsArray);
_upscalerConstants.UpdateBufferData(commandBuffer);
_spdConstants.UpdateBufferData(commandBuffer);
// Auto reactive // Auto reactive
if (dispatchParams.EnableAutoReactive) if (dispatchParams.EnableAutoReactive)
{ {
GenerateTransparencyCompositionReactive(dispatchParams, commandBuffer, frameIndex);
GenerateTransparencyCompositionReactive(dispatchParams, commandBuffer, bufferIndex);
dispatchParams.Reactive = new ResourceView(_resources.AutoReactive); dispatchParams.Reactive = new ResourceView(_resources.AutoReactive);
dispatchParams.TransparencyAndComposition = new ResourceView(_resources.AutoComposition); dispatchParams.TransparencyAndComposition = new ResourceView(_resources.AutoComposition);
} }
_prepareInputsPass.ScheduleDispatch(commandBuffer, dispatchParams, frameIndex, dispatchSrcX, dispatchSrcY);
_lumaPyramidPass.ScheduleDispatch(commandBuffer, dispatchParams, frameIndex, dispatchThreadGroupCount.x, dispatchThreadGroupCount.y);
_shadingChangePyramidPass.ScheduleDispatch(commandBuffer, dispatchParams, frameIndex, dispatchThreadGroupCount.x, dispatchThreadGroupCount.y);
_shadingChangePass.ScheduleDispatch(commandBuffer, dispatchParams, frameIndex, dispatchShadingChangePassX, dispatchShadingChangePassY);
_prepareReactivityPass.ScheduleDispatch(commandBuffer, dispatchParams, frameIndex, dispatchSrcX, dispatchSrcY);
_lumaInstabilityPass.ScheduleDispatch(commandBuffer, dispatchParams, frameIndex, dispatchSrcX, dispatchSrcY);
_prepareInputsPass.ScheduleDispatch(commandBuffer, dispatchParams, bufferIndex, dispatchSrcX, dispatchSrcY);
_lumaPyramidPass.ScheduleDispatch(commandBuffer, dispatchParams, bufferIndex, dispatchThreadGroupCount.x, dispatchThreadGroupCount.y);
_shadingChangePyramidPass.ScheduleDispatch(commandBuffer, dispatchParams, bufferIndex, dispatchThreadGroupCount.x, dispatchThreadGroupCount.y);
_shadingChangePass.ScheduleDispatch(commandBuffer, dispatchParams, bufferIndex, dispatchShadingChangePassX, dispatchShadingChangePassY);
_prepareReactivityPass.ScheduleDispatch(commandBuffer, dispatchParams, bufferIndex, dispatchSrcX, dispatchSrcY);
_lumaInstabilityPass.ScheduleDispatch(commandBuffer, dispatchParams, bufferIndex, dispatchSrcX, dispatchSrcY);
_accumulatePass.ScheduleDispatch(commandBuffer, dispatchParams, frameIndex, dispatchDstX, dispatchDstY);
_accumulatePass.ScheduleDispatch(commandBuffer, dispatchParams, bufferIndex, dispatchDstX, dispatchDstY);
if (dispatchParams.EnableSharpening) if (dispatchParams.EnableSharpening)
{ {
// Compute the constants // Compute the constants
SetupRcasConstants(dispatchParams); SetupRcasConstants(dispatchParams);
commandBuffer.SetBufferData(_rcasConstantsBuffer, _rcasConstantsArray);
_rcasConstants.UpdateBufferData(commandBuffer);
// Dispatch RCAS // Dispatch RCAS
const int threadGroupWorkRegionDimRcas = 16; const int threadGroupWorkRegionDimRcas = 16;
int threadGroupsX = (UpscalerConsts.upscaleSize.x + threadGroupWorkRegionDimRcas - 1) / threadGroupWorkRegionDimRcas;
int threadGroupsY = (UpscalerConsts.upscaleSize.y + threadGroupWorkRegionDimRcas - 1) / threadGroupWorkRegionDimRcas;
_sharpenPass.ScheduleDispatch(commandBuffer, dispatchParams, frameIndex, threadGroupsX, threadGroupsY);
int threadGroupsX = (upscaleSize.x + threadGroupWorkRegionDimRcas - 1) / threadGroupWorkRegionDimRcas;
int threadGroupsY = (upscaleSize.y + threadGroupWorkRegionDimRcas - 1) / threadGroupWorkRegionDimRcas;
_sharpenPass.ScheduleDispatch(commandBuffer, dispatchParams, bufferIndex, threadGroupsX, threadGroupsY);
} }
#if UNITY_EDITOR || DEVELOPMENT_BUILD #if UNITY_EDITOR || DEVELOPMENT_BUILD
if ((dispatchParams.Flags & Fsr3Upscaler.DispatchFlags.DrawDebugView) != 0) if ((dispatchParams.Flags & Fsr3Upscaler.DispatchFlags.DrawDebugView) != 0)
{ {
_debugViewPass.ScheduleDispatch(commandBuffer, dispatchParams, frameIndex, dispatchDstX, dispatchDstY);
_debugViewPass.ScheduleDispatch(commandBuffer, dispatchParams, bufferIndex, dispatchDstX, dispatchDstY);
} }
#endif #endif
@ -293,6 +286,7 @@ namespace FidelityFX.FSR3
Fsr3UpscalerResources.DestroyAliasableResources(commandBuffer); Fsr3UpscalerResources.DestroyAliasableResources(commandBuffer);
commandBuffer.DisableShaderKeyword("UNITY_FSR_TEXTURE2D_X_ARRAY"); commandBuffer.DisableShaderKeyword("UNITY_FSR_TEXTURE2D_X_ARRAY");
commandBuffer.EndSample(_sampler);
} }
public void GenerateReactiveMask(Fsr3Upscaler.GenerateReactiveDescription dispatchParams) public void GenerateReactiveMask(Fsr3Upscaler.GenerateReactiveDescription dispatchParams)
@ -308,11 +302,12 @@ namespace FidelityFX.FSR3
int dispatchSrcX = (dispatchParams.RenderSize.x + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim; int dispatchSrcX = (dispatchParams.RenderSize.x + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
int dispatchSrcY = (dispatchParams.RenderSize.y + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim; int dispatchSrcY = (dispatchParams.RenderSize.y + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
GenReactiveConsts.scale = dispatchParams.Scale;
GenReactiveConsts.threshold = dispatchParams.CutoffThreshold;
GenReactiveConsts.binaryValue = dispatchParams.BinaryValue;
GenReactiveConsts.flags = (uint)dispatchParams.Flags;
commandBuffer.SetBufferData(_generateReactiveConstantsBuffer, _generateReactiveConstantsArray);
ref var genReactiveConsts = ref _generateReactiveConstants.Value;
genReactiveConsts.scale = dispatchParams.Scale;
genReactiveConsts.threshold = dispatchParams.CutoffThreshold;
genReactiveConsts.binaryValue = dispatchParams.BinaryValue;
genReactiveConsts.flags = (uint)dispatchParams.Flags;
_generateReactiveConstants.UpdateBufferData(commandBuffer);
((Fsr3UpscalerGenerateReactivePass)_generateReactivePass).ScheduleDispatch(commandBuffer, dispatchParams, dispatchSrcX, dispatchSrcY); ((Fsr3UpscalerGenerateReactivePass)_generateReactivePass).ScheduleDispatch(commandBuffer, dispatchParams, dispatchSrcX, dispatchSrcY);
} }
@ -323,18 +318,19 @@ namespace FidelityFX.FSR3
int dispatchSrcX = (dispatchParams.RenderSize.x + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim; int dispatchSrcX = (dispatchParams.RenderSize.x + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
int dispatchSrcY = (dispatchParams.RenderSize.y + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim; int dispatchSrcY = (dispatchParams.RenderSize.y + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
TcrAutoGenConsts.autoTcThreshold = dispatchParams.AutoTcThreshold;
TcrAutoGenConsts.autoTcScale = dispatchParams.AutoTcScale;
TcrAutoGenConsts.autoReactiveScale = dispatchParams.AutoReactiveScale;
TcrAutoGenConsts.autoReactiveMax = dispatchParams.AutoReactiveMax;
commandBuffer.SetBufferData(_tcrAutogenerateConstantsBuffer, _tcrAutogenerateConstantsArray);
ref var tcrAutoGenConsts = ref _tcrAutogenerateConstants.Value;
tcrAutoGenConsts.autoTcThreshold = dispatchParams.AutoTcThreshold;
tcrAutoGenConsts.autoTcScale = dispatchParams.AutoTcScale;
tcrAutoGenConsts.autoReactiveScale = dispatchParams.AutoReactiveScale;
tcrAutoGenConsts.autoReactiveMax = dispatchParams.AutoReactiveMax;
_tcrAutogenerateConstants.UpdateBufferData(commandBuffer);
_tcrAutogeneratePass.ScheduleDispatch(commandBuffer, dispatchParams, frameIndex, dispatchSrcX, dispatchSrcY); _tcrAutogeneratePass.ScheduleDispatch(commandBuffer, dispatchParams, frameIndex, dispatchSrcX, dispatchSrcY);
} }
private void SetupConstants(Fsr3Upscaler.DispatchDescription dispatchParams, bool resetAccumulation) private void SetupConstants(Fsr3Upscaler.DispatchDescription dispatchParams, bool resetAccumulation)
{ {
ref Fsr3Upscaler.UpscalerConstants constants = ref UpscalerConsts;
ref Fsr3Upscaler.UpscalerConstants constants = ref _upscalerConstants.Value;
constants.previousFrameJitterOffset = constants.jitterOffset; constants.previousFrameJitterOffset = constants.jitterOffset;
constants.jitterOffset = dispatchParams.JitterOffset; constants.jitterOffset = dispatchParams.JitterOffset;
@ -350,7 +346,10 @@ namespace FidelityFX.FSR3
constants.viewSpaceToMetersFactor = (dispatchParams.ViewSpaceToMetersFactor > 0.0f) ? dispatchParams.ViewSpaceToMetersFactor : 1.0f; constants.viewSpaceToMetersFactor = (dispatchParams.ViewSpaceToMetersFactor > 0.0f) ? dispatchParams.ViewSpaceToMetersFactor : 1.0f;
// Compute params to enable device depth to view space depth computation in shader // Compute params to enable device depth to view space depth computation in shader
constants.deviceToViewDepth = SetupDeviceDepthToViewSpaceDepthParams(dispatchParams);
bool inverted = (_contextDescription.Flags & Fsr3Upscaler.InitializationFlags.EnableDepthInverted) != 0;
bool infinite = (_contextDescription.Flags & Fsr3Upscaler.InitializationFlags.EnableDepthInfinite) != 0;
constants.deviceToViewDepth = FfxUtils.SetupDeviceDepthToViewSpaceDepthParams(
dispatchParams.RenderSize, dispatchParams.CameraNear, dispatchParams.CameraFar, dispatchParams.CameraFovAngleVertical, inverted, infinite);
constants.previousFrameUpscaleSize = constants.upscaleSize; constants.previousFrameUpscaleSize = constants.upscaleSize;
if (dispatchParams.UpscaleSize.x == 0 && dispatchParams.UpscaleSize.y == 0) if (dispatchParams.UpscaleSize.x == 0 && dispatchParams.UpscaleSize.y == 0)
@ -386,7 +385,7 @@ namespace FidelityFX.FSR3
_previousJitterOffset = constants.jitterOffset; _previousJitterOffset = constants.jitterOffset;
} }
int jitterPhaseCount = Fsr3Upscaler.GetJitterPhaseCount(dispatchParams.RenderSize.x, _contextDescription.MaxUpscaleSize.x);
int jitterPhaseCount = FfxUtils.GetJitterPhaseCount(dispatchParams.RenderSize.x, _contextDescription.MaxUpscaleSize.x);
if (resetAccumulation || constants.jitterPhaseCount == 0) if (resetAccumulation || constants.jitterPhaseCount == 0)
{ {
constants.jitterPhaseCount = jitterPhaseCount; constants.jitterPhaseCount = jitterPhaseCount;
@ -408,78 +407,22 @@ namespace FidelityFX.FSR3
else else
constants.frameIndex += 1.0f; constants.frameIndex += 1.0f;
} }
private Vector4 SetupDeviceDepthToViewSpaceDepthParams(Fsr3Upscaler.DispatchDescription dispatchParams)
{
bool inverted = (_contextDescription.Flags & Fsr3Upscaler.InitializationFlags.EnableDepthInverted) != 0;
bool infinite = (_contextDescription.Flags & Fsr3Upscaler.InitializationFlags.EnableDepthInfinite) != 0;
// make sure it has no impact if near and far plane values are swapped in dispatch params
// the flags "inverted" and "infinite" will decide what transform to use
float min = Mathf.Min(dispatchParams.CameraNear, dispatchParams.CameraFar);
float max = Mathf.Max(dispatchParams.CameraNear, dispatchParams.CameraFar);
if (inverted)
{
(min, max) = (max, min);
}
float q = max / (min - max);
float d = -1.0f;
Vector4 matrixElemC = new Vector4(q, -1.0f - Mathf.Epsilon, q, 0.0f + Mathf.Epsilon);
Vector4 matrixElemE = new Vector4(q * min, -min - Mathf.Epsilon, q * min, max);
// Revert x and y coords
float aspect = (float)dispatchParams.RenderSize.x / dispatchParams.RenderSize.y;
float cotHalfFovY = Mathf.Cos(0.5f * dispatchParams.CameraFovAngleVertical) / Mathf.Sin(0.5f * dispatchParams.CameraFovAngleVertical);
int matrixIndex = (inverted ? 2 : 0) + (infinite ? 1 : 0);
return new Vector4(
d * matrixElemC[matrixIndex],
matrixElemE[matrixIndex],
aspect / cotHalfFovY,
1.0f / cotHalfFovY);
}
private void SetupRcasConstants(Fsr3Upscaler.DispatchDescription dispatchParams) private void SetupRcasConstants(Fsr3Upscaler.DispatchDescription dispatchParams)
{ {
int sharpnessIndex = Mathf.RoundToInt(Mathf.Clamp01(dispatchParams.Sharpness) * (RcasConfigs.Length - 1)); int sharpnessIndex = Mathf.RoundToInt(Mathf.Clamp01(dispatchParams.Sharpness) * (RcasConfigs.Length - 1));
RcasConsts = RcasConfigs[sharpnessIndex];
_rcasConstants.Value = RcasConfigs[sharpnessIndex];
} }
private void SetupSpdConstants(Fsr3Upscaler.DispatchDescription dispatchParams, out Vector2Int dispatchThreadGroupCount) private void SetupSpdConstants(Fsr3Upscaler.DispatchDescription dispatchParams, out Vector2Int dispatchThreadGroupCount)
{ {
RectInt rectInfo = new RectInt(0, 0, dispatchParams.RenderSize.x, dispatchParams.RenderSize.y);
SpdSetup(rectInfo, out dispatchThreadGroupCount, out var workGroupOffset, out var numWorkGroupsAndMips);
// Downsample // Downsample
ref Fsr3Upscaler.SpdConstants spdConstants = ref SpdConsts;
spdConstants.numWorkGroups = (uint)numWorkGroupsAndMips.x;
spdConstants.mips = (uint)numWorkGroupsAndMips.y;
spdConstants.workGroupOffsetX = (uint)workGroupOffset.x;
spdConstants.workGroupOffsetY = (uint)workGroupOffset.y;
ref Fsr3Upscaler.SpdConstants spdConstants = ref _spdConstants.Value;
FfxSpd.SetupSpdConstants(dispatchParams.RenderSize, ref spdConstants.spd, out dispatchThreadGroupCount);
spdConstants.renderSizeX = (uint)dispatchParams.RenderSize.x; spdConstants.renderSizeX = (uint)dispatchParams.RenderSize.x;
spdConstants.renderSizeY = (uint)dispatchParams.RenderSize.y; spdConstants.renderSizeY = (uint)dispatchParams.RenderSize.y;
} }
private static void SpdSetup(RectInt rectInfo, out Vector2Int dispatchThreadGroupCount, out Vector2Int workGroupOffset, out Vector2Int numWorkGroupsAndMips, int mips = -1)
{
workGroupOffset = new Vector2Int(rectInfo.x / 64, rectInfo.y / 64);
int endIndexX = (rectInfo.x + rectInfo.width - 1) / 64;
int endIndexY = (rectInfo.y + rectInfo.height - 1) / 64;
dispatchThreadGroupCount = new Vector2Int(endIndexX + 1 - workGroupOffset.x, endIndexY + 1 - workGroupOffset.y);
numWorkGroupsAndMips = new Vector2Int(dispatchThreadGroupCount.x * dispatchThreadGroupCount.y, mips);
if (mips < 0)
{
float resolution = Math.Max(rectInfo.width, rectInfo.height);
numWorkGroupsAndMips.y = Math.Min(Mathf.FloorToInt(Mathf.Log(resolution, 2.0f)), 12);
}
}
private void DebugCheckDispatch(Fsr3Upscaler.DispatchDescription dispatchParams) private void DebugCheckDispatch(Fsr3Upscaler.DispatchDescription dispatchParams)
{ {
if (!dispatchParams.Color.IsValid) if (!dispatchParams.Color.IsValid)
@ -630,28 +573,5 @@ namespace FidelityFX.FSR3
new Fsr3Upscaler.RcasConstants(1064229695u, 997604214u), new Fsr3Upscaler.RcasConstants(1064229695u, 997604214u),
new Fsr3Upscaler.RcasConstants(1065353216u, 1006648320), new Fsr3Upscaler.RcasConstants(1065353216u, 1006648320),
}; };
private static ComputeBuffer CreateConstantBuffer<TConstants>() where TConstants: struct
{
return new ComputeBuffer(1, Marshal.SizeOf<TConstants>(), ComputeBufferType.Constant);
}
private static void DestroyConstantBuffer(ref ComputeBuffer bufferRef)
{
if (bufferRef == null)
return;
bufferRef.Release();
bufferRef = null;
}
private static void DestroyPass(ref Fsr3UpscalerPass pass)
{
if (pass == null)
return;
pass.Dispose();
pass = null;
}
} }
} }

248
Runtime/FSR3/Fsr3UpscalerPass.cs

@ -18,10 +18,7 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. // THE SOFTWARE.
using System;
using System.Runtime.InteropServices;
using UnityEngine; using UnityEngine;
using UnityEngine.Profiling;
using UnityEngine.Rendering; using UnityEngine.Rendering;
namespace FidelityFX.FSR3 namespace FidelityFX.FSR3
@ -31,53 +28,27 @@ namespace FidelityFX.FSR3
/// This loosely matches the FfxPipelineState struct from the original FSR3 codebase, wrapped in an object-oriented blanket. /// This loosely matches the FfxPipelineState struct from the original FSR3 codebase, wrapped in an object-oriented blanket.
/// These classes are responsible for loading compute shaders, managing temporary resources, binding resources to shader kernels and dispatching said shaders. /// These classes are responsible for loading compute shaders, managing temporary resources, binding resources to shader kernels and dispatching said shaders.
/// </summary> /// </summary>
internal abstract class Fsr3UpscalerPass: IDisposable
internal abstract class Fsr3UpscalerPass: FfxPassWithFlags<Fsr3Upscaler.DispatchDescription, Fsr3Upscaler.InitializationFlags>
{ {
protected readonly Fsr3Upscaler.ContextDescription ContextDescription; protected readonly Fsr3Upscaler.ContextDescription ContextDescription;
protected readonly Fsr3UpscalerResources Resources; protected readonly Fsr3UpscalerResources Resources;
protected readonly ComputeBuffer Constants; protected readonly ComputeBuffer Constants;
protected ComputeShader ComputeShader;
protected int KernelIndex;
protected CustomSampler Sampler;
protected Fsr3UpscalerPass(Fsr3Upscaler.ContextDescription contextDescription, Fsr3UpscalerResources resources, ComputeBuffer constants) protected Fsr3UpscalerPass(Fsr3Upscaler.ContextDescription contextDescription, Fsr3UpscalerResources resources, ComputeBuffer constants)
: base("FSR3 Upscaler")
{ {
ContextDescription = contextDescription; ContextDescription = contextDescription;
Resources = resources; Resources = resources;
Constants = constants; Constants = constants;
} }
public virtual void Dispose()
{
}
public void ScheduleDispatch(CommandBuffer commandBuffer, Fsr3Upscaler.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY)
{
commandBuffer.BeginSample(Sampler);
DoScheduleDispatch(commandBuffer, dispatchParams, frameIndex, dispatchX, dispatchY);
commandBuffer.EndSample(Sampler);
}
protected abstract void DoScheduleDispatch(CommandBuffer commandBuffer, Fsr3Upscaler.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY);
protected void InitComputeShader(string passName, ComputeShader shader) protected void InitComputeShader(string passName, ComputeShader shader)
{ {
InitComputeShader(passName, shader, ContextDescription.Flags); InitComputeShader(passName, shader, ContextDescription.Flags);
} }
private void InitComputeShader(string passName, ComputeShader shader, Fsr3Upscaler.InitializationFlags flags)
protected override void SetupShaderKeywords(Fsr3Upscaler.InitializationFlags flags)
{ {
if (shader == null)
{
throw new MissingReferenceException($"Shader for FSR3 Upscaler pass '{passName}' could not be loaded! Please ensure it is included in the project correctly.");
}
ComputeShader = shader;
KernelIndex = ComputeShader.FindKernel("CS");
Sampler = CustomSampler.Create(passName);
bool useLut = false; bool useLut = false;
#if UNITY_2022_1_OR_NEWER // This will also work in 2020.3.43+ and 2021.3.14+ #if UNITY_2022_1_OR_NEWER // This will also work in 2020.3.43+ and 2021.3.14+
if (SystemInfo.computeSubGroupSize == 64) if (SystemInfo.computeSubGroupSize == 64)
@ -104,25 +75,21 @@ namespace FidelityFX.FSR3
InitComputeShader("Prepare Inputs", contextDescription.Shaders.prepareInputsPass); InitComputeShader("Prepare Inputs", contextDescription.Shaders.prepareInputsPass);
} }
protected override void DoScheduleDispatch(CommandBuffer commandBuffer, Fsr3Upscaler.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY)
protected override void DoScheduleDispatch(CommandBuffer commandBuffer, in Fsr3Upscaler.DispatchDescription dispatchParams, int bufferIndex, int dispatchX, int dispatchY, int dispatchZ)
{ {
ref var color = ref dispatchParams.Color;
ref var depth = ref dispatchParams.Depth;
ref var motionVectors = ref dispatchParams.MotionVectors;
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvInputColor, color.RenderTarget, color.MipLevel, color.SubElement);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvInputDepth, depth.RenderTarget, depth.MipLevel, depth.SubElement);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvInputMotionVectors, motionVectors.RenderTarget, motionVectors.MipLevel, motionVectors.SubElement);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvInputColor, dispatchParams.Color);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvInputDepth, dispatchParams.Depth);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvInputMotionVectors, dispatchParams.MotionVectors);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavDilatedMotionVectors, Resources.DilatedVelocity); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavDilatedMotionVectors, Resources.DilatedVelocity);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavDilatedDepth, Resources.DilatedDepth); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavDilatedDepth, Resources.DilatedDepth);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavReconstructedPrevNearestDepth, Resources.ReconstructedPrevNearestDepth); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavReconstructedPrevNearestDepth, Resources.ReconstructedPrevNearestDepth);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavFarthestDepth, Fsr3ShaderIDs.UavIntermediate); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavFarthestDepth, Fsr3ShaderIDs.UavIntermediate);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavCurrentLuma, Resources.Luma[frameIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavCurrentLuma, Resources.Luma[bufferIndex]);
commandBuffer.SetComputeConstantBufferParam(ComputeShader, Fsr3ShaderIDs.CbFsr3Upscaler, Constants, 0, Marshal.SizeOf<Fsr3Upscaler.UpscalerConstants>());
commandBuffer.SetComputeConstantBufferParam<Fsr3Upscaler.UpscalerConstants>(ComputeShader, Fsr3ShaderIDs.CbFsr3Upscaler, Constants);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, 1);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, dispatchZ);
} }
} }
@ -138,24 +105,24 @@ namespace FidelityFX.FSR3
InitComputeShader("Compute Luminance Pyramid", contextDescription.Shaders.lumaPyramidPass); InitComputeShader("Compute Luminance Pyramid", contextDescription.Shaders.lumaPyramidPass);
} }
protected override void DoScheduleDispatch(CommandBuffer commandBuffer, Fsr3Upscaler.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY)
protected override void DoScheduleDispatch(CommandBuffer commandBuffer, in Fsr3Upscaler.DispatchDescription dispatchParams, int bufferIndex, int dispatchX, int dispatchY, int dispatchZ)
{ {
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvCurrentLuma, Resources.Luma[frameIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvCurrentLuma, Resources.Luma[bufferIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvFarthestDepth, Fsr3ShaderIDs.UavIntermediate); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvFarthestDepth, Fsr3ShaderIDs.UavIntermediate);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavSpdAtomicCount, Resources.SpdAtomicCounter); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavSpdAtomicCount, Resources.SpdAtomicCounter);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavFrameInfo, Resources.FrameInfo); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavFrameInfo, Resources.FrameInfo);
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);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavSpdMip3, Resources.SpdMips, 3);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavSpdMip4, Resources.SpdMips, 4);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavSpdMip5, Resources.SpdMips, 5);
commandBuffer.SetComputeTextureMipParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavSpdMip0, Resources.SpdMips, 0);
commandBuffer.SetComputeTextureMipParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavSpdMip1, Resources.SpdMips, 1);
commandBuffer.SetComputeTextureMipParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavSpdMip2, Resources.SpdMips, 2);
commandBuffer.SetComputeTextureMipParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavSpdMip3, Resources.SpdMips, 3);
commandBuffer.SetComputeTextureMipParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavSpdMip4, Resources.SpdMips, 4);
commandBuffer.SetComputeTextureMipParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavSpdMip5, Resources.SpdMips, 5);
commandBuffer.SetComputeConstantBufferParam(ComputeShader, Fsr3ShaderIDs.CbFsr3Upscaler, Constants, 0, Marshal.SizeOf<Fsr3Upscaler.UpscalerConstants>());
commandBuffer.SetComputeConstantBufferParam(ComputeShader, Fsr3ShaderIDs.CbSpd, _spdConstants, 0, Marshal.SizeOf<Fsr3Upscaler.SpdConstants>());
commandBuffer.SetComputeConstantBufferParam<Fsr3Upscaler.UpscalerConstants>(ComputeShader, Fsr3ShaderIDs.CbFsr3Upscaler, Constants);
commandBuffer.SetComputeConstantBufferParam<Fsr3Upscaler.SpdConstants>(ComputeShader, Fsr3ShaderIDs.CbSpd, _spdConstants);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, 1);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, dispatchZ);
} }
} }
@ -171,27 +138,25 @@ namespace FidelityFX.FSR3
InitComputeShader("Compute Shading Change Pyramid", contextDescription.Shaders.shadingChangePyramidPass); InitComputeShader("Compute Shading Change Pyramid", contextDescription.Shaders.shadingChangePyramidPass);
} }
protected override void DoScheduleDispatch(CommandBuffer commandBuffer, Fsr3Upscaler.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY)
protected override void DoScheduleDispatch(CommandBuffer commandBuffer, in Fsr3Upscaler.DispatchDescription dispatchParams, int bufferIndex, int dispatchX, int dispatchY, int dispatchZ)
{ {
ref var exposure = ref dispatchParams.Exposure;
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvCurrentLuma, Resources.Luma[frameIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvPreviousLuma, Resources.Luma[frameIndex ^ 1]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvCurrentLuma, Resources.Luma[bufferIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvPreviousLuma, Resources.Luma[bufferIndex ^ 1]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvDilatedMotionVectors, Resources.DilatedVelocity); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvDilatedMotionVectors, Resources.DilatedVelocity);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvInputExposure, exposure.RenderTarget, exposure.MipLevel, exposure.SubElement);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvInputExposure, dispatchParams.Exposure);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavSpdAtomicCount, Resources.SpdAtomicCounter); commandBuffer.SetComputeTextureParam(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);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavSpdMip3, Resources.SpdMips, 3);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavSpdMip4, Resources.SpdMips, 4);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavSpdMip5, Resources.SpdMips, 5);
commandBuffer.SetComputeTextureMipParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavSpdMip0, Resources.SpdMips, 0);
commandBuffer.SetComputeTextureMipParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavSpdMip1, Resources.SpdMips, 1);
commandBuffer.SetComputeTextureMipParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavSpdMip2, Resources.SpdMips, 2);
commandBuffer.SetComputeTextureMipParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavSpdMip3, Resources.SpdMips, 3);
commandBuffer.SetComputeTextureMipParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavSpdMip4, Resources.SpdMips, 4);
commandBuffer.SetComputeTextureMipParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavSpdMip5, Resources.SpdMips, 5);
commandBuffer.SetComputeConstantBufferParam(ComputeShader, Fsr3ShaderIDs.CbFsr3Upscaler, Constants, 0, Marshal.SizeOf<Fsr3Upscaler.UpscalerConstants>());
commandBuffer.SetComputeConstantBufferParam(ComputeShader, Fsr3ShaderIDs.CbSpd, _spdConstants, 0, Marshal.SizeOf<Fsr3Upscaler.SpdConstants>());
commandBuffer.SetComputeConstantBufferParam<Fsr3Upscaler.UpscalerConstants>(ComputeShader, Fsr3ShaderIDs.CbFsr3Upscaler, Constants);
commandBuffer.SetComputeConstantBufferParam<Fsr3Upscaler.SpdConstants>(ComputeShader, Fsr3ShaderIDs.CbSpd, _spdConstants);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, 1);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, dispatchZ);
} }
} }
@ -203,13 +168,13 @@ namespace FidelityFX.FSR3
InitComputeShader("Compute Shading Change", contextDescription.Shaders.shadingChangePass); InitComputeShader("Compute Shading Change", contextDescription.Shaders.shadingChangePass);
} }
protected override void DoScheduleDispatch(CommandBuffer commandBuffer, Fsr3Upscaler.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY)
protected override void DoScheduleDispatch(CommandBuffer commandBuffer, in Fsr3Upscaler.DispatchDescription dispatchParams, int bufferIndex, int dispatchX, int dispatchY, int dispatchZ)
{ {
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvSpdMips, Resources.SpdMips); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvSpdMips, Resources.SpdMips);
commandBuffer.SetComputeConstantBufferParam(ComputeShader, Fsr3ShaderIDs.CbFsr3Upscaler, Constants, 0, Marshal.SizeOf<Fsr3Upscaler.UpscalerConstants>());
commandBuffer.SetComputeConstantBufferParam<Fsr3Upscaler.UpscalerConstants>(ComputeShader, Fsr3ShaderIDs.CbFsr3Upscaler, Constants);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, 1);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, dispatchZ);
} }
} }
@ -221,27 +186,23 @@ namespace FidelityFX.FSR3
InitComputeShader("Prepare Reactivity", contextDescription.Shaders.prepareReactivityPass); InitComputeShader("Prepare Reactivity", contextDescription.Shaders.prepareReactivityPass);
} }
protected override void DoScheduleDispatch(CommandBuffer commandBuffer, Fsr3Upscaler.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY)
protected override void DoScheduleDispatch(CommandBuffer commandBuffer, in Fsr3Upscaler.DispatchDescription dispatchParams, int bufferIndex, int dispatchX, int dispatchY, int dispatchZ)
{ {
ref var exposure = ref dispatchParams.Exposure;
ref var reactive = ref dispatchParams.Reactive;
ref var tac = ref dispatchParams.TransparencyAndComposition;
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvReconstructedPrevNearestDepth, Resources.ReconstructedPrevNearestDepth); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvReconstructedPrevNearestDepth, Resources.ReconstructedPrevNearestDepth);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvDilatedMotionVectors, Resources.DilatedVelocity); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvDilatedMotionVectors, Resources.DilatedVelocity);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvDilatedDepth, Resources.DilatedDepth); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvDilatedDepth, Resources.DilatedDepth);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvReactiveMask, reactive.RenderTarget, reactive.MipLevel, reactive.SubElement);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvTransparencyAndCompositionMask, tac.RenderTarget, tac.MipLevel, tac.SubElement);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvAccumulation, Resources.Accumulation[frameIndex ^ 1]);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvReactiveMask, dispatchParams.Reactive);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvTransparencyAndCompositionMask, dispatchParams.TransparencyAndComposition);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvAccumulation, Resources.Accumulation[bufferIndex ^ 1]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvShadingChange, Fsr3ShaderIDs.UavShadingChange); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvShadingChange, Fsr3ShaderIDs.UavShadingChange);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvCurrentLuma, Resources.Luma[frameIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvInputExposure, exposure.RenderTarget, exposure.MipLevel, exposure.SubElement);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvCurrentLuma, Resources.Luma[bufferIndex]);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvInputExposure, dispatchParams.Exposure);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavAccumulation, Resources.Accumulation[frameIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavAccumulation, Resources.Accumulation[bufferIndex]);
commandBuffer.SetComputeConstantBufferParam(ComputeShader, Fsr3ShaderIDs.CbFsr3Upscaler, Constants, 0, Marshal.SizeOf<Fsr3Upscaler.UpscalerConstants>());
commandBuffer.SetComputeConstantBufferParam<Fsr3Upscaler.UpscalerConstants>(ComputeShader, Fsr3ShaderIDs.CbFsr3Upscaler, Constants);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, 1);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, dispatchZ);
} }
} }
@ -253,24 +214,22 @@ namespace FidelityFX.FSR3
InitComputeShader("Compute Luminance Instability", contextDescription.Shaders.lumaInstabilityPass); InitComputeShader("Compute Luminance Instability", contextDescription.Shaders.lumaInstabilityPass);
} }
protected override void DoScheduleDispatch(CommandBuffer commandBuffer, Fsr3Upscaler.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY)
protected override void DoScheduleDispatch(CommandBuffer commandBuffer, in Fsr3Upscaler.DispatchDescription dispatchParams, int bufferIndex, int dispatchX, int dispatchY, int dispatchZ)
{ {
ref var exposure = ref dispatchParams.Exposure;
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvInputExposure, exposure.RenderTarget, exposure.MipLevel, exposure.SubElement);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvInputExposure, dispatchParams.Exposure);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvDilatedReactiveMasks, Fsr3ShaderIDs.UavDilatedReactiveMasks); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvDilatedReactiveMasks, Fsr3ShaderIDs.UavDilatedReactiveMasks);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvDilatedMotionVectors, Resources.DilatedVelocity); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvDilatedMotionVectors, Resources.DilatedVelocity);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvFrameInfo, Resources.FrameInfo); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvFrameInfo, Resources.FrameInfo);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvLumaHistory, Resources.LumaHistory[frameIndex ^ 1]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvLumaHistory, Resources.LumaHistory[bufferIndex ^ 1]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvFarthestDepthMip1, Fsr3ShaderIDs.UavFarthestDepthMip1); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvFarthestDepthMip1, Fsr3ShaderIDs.UavFarthestDepthMip1);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvCurrentLuma, Resources.Luma[frameIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvCurrentLuma, Resources.Luma[bufferIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavLumaHistory, Resources.LumaHistory[frameIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavLumaHistory, Resources.LumaHistory[bufferIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavLumaInstability, Fsr3ShaderIDs.UavIntermediate); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavLumaInstability, Fsr3ShaderIDs.UavIntermediate);
commandBuffer.SetComputeConstantBufferParam(ComputeShader, Fsr3ShaderIDs.CbFsr3Upscaler, Constants, 0, Marshal.SizeOf<Fsr3Upscaler.UpscalerConstants>());
commandBuffer.SetComputeConstantBufferParam<Fsr3Upscaler.UpscalerConstants>(ComputeShader, Fsr3ShaderIDs.CbFsr3Upscaler, Constants);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, 1);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, dispatchZ);
} }
} }
@ -291,7 +250,7 @@ namespace FidelityFX.FSR3
#endif #endif
} }
protected override void DoScheduleDispatch(CommandBuffer commandBuffer, Fsr3Upscaler.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY)
protected override void DoScheduleDispatch(CommandBuffer commandBuffer, in Fsr3Upscaler.DispatchDescription dispatchParams, int bufferIndex, int dispatchX, int dispatchY, int dispatchZ)
{ {
#if UNITY_2021_2_OR_NEWER #if UNITY_2021_2_OR_NEWER
if (dispatchParams.EnableSharpening) if (dispatchParams.EnableSharpening)
@ -305,11 +264,7 @@ namespace FidelityFX.FSR3
commandBuffer.DisableShaderKeyword(SharpeningKeyword); commandBuffer.DisableShaderKeyword(SharpeningKeyword);
#endif #endif
ref var color = ref dispatchParams.Color;
ref var exposure = ref dispatchParams.Exposure;
ref var output = ref dispatchParams.Output;
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvInputExposure, exposure.RenderTarget, exposure.MipLevel, exposure.SubElement);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvInputExposure, dispatchParams.Exposure);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvDilatedReactiveMasks, Fsr3ShaderIDs.UavDilatedReactiveMasks); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvDilatedReactiveMasks, Fsr3ShaderIDs.UavDilatedReactiveMasks);
if ((ContextDescription.Flags & Fsr3Upscaler.InitializationFlags.EnableDisplayResolutionMotionVectors) == 0) if ((ContextDescription.Flags & Fsr3Upscaler.InitializationFlags.EnableDisplayResolutionMotionVectors) == 0)
@ -318,23 +273,22 @@ namespace FidelityFX.FSR3
} }
else else
{ {
ref var motionVectors = ref dispatchParams.MotionVectors;
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvInputMotionVectors, motionVectors.RenderTarget, motionVectors.MipLevel, motionVectors.SubElement);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvInputMotionVectors, dispatchParams.MotionVectors);
} }
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvInternalUpscaled, Resources.InternalUpscaled[frameIndex ^ 1]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvInternalUpscaled, Resources.InternalUpscaled[bufferIndex ^ 1]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvLanczosLut, Resources.LanczosLut); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvLanczosLut, Resources.LanczosLut);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvFarthestDepthMip1, Fsr3ShaderIDs.UavFarthestDepthMip1); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvFarthestDepthMip1, Fsr3ShaderIDs.UavFarthestDepthMip1);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvCurrentLuma, Resources.Luma[frameIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvCurrentLuma, Resources.Luma[bufferIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvLumaInstability, Fsr3ShaderIDs.UavIntermediate); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvLumaInstability, Fsr3ShaderIDs.UavIntermediate);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvInputColor, color.RenderTarget, color.MipLevel, color.SubElement);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvInputColor, dispatchParams.Color);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavInternalUpscaled, Resources.InternalUpscaled[frameIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavUpscaledOutput, output.RenderTarget, output.MipLevel, output.SubElement);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavInternalUpscaled, Resources.InternalUpscaled[bufferIndex]);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavUpscaledOutput, dispatchParams.Output);
commandBuffer.SetComputeConstantBufferParam(ComputeShader, Fsr3ShaderIDs.CbFsr3Upscaler, Constants, 0, Marshal.SizeOf<Fsr3Upscaler.UpscalerConstants>());
commandBuffer.SetComputeConstantBufferParam<Fsr3Upscaler.UpscalerConstants>(ComputeShader, Fsr3ShaderIDs.CbFsr3Upscaler, Constants);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, 1);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, dispatchZ);
} }
} }
@ -350,19 +304,17 @@ namespace FidelityFX.FSR3
InitComputeShader("RCAS Sharpening", contextDescription.Shaders.sharpenPass); InitComputeShader("RCAS Sharpening", contextDescription.Shaders.sharpenPass);
} }
protected override void DoScheduleDispatch(CommandBuffer commandBuffer, Fsr3Upscaler.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY)
protected override void DoScheduleDispatch(CommandBuffer commandBuffer, in Fsr3Upscaler.DispatchDescription dispatchParams, int bufferIndex, int dispatchX, int dispatchY, int dispatchZ)
{ {
ref var exposure = ref dispatchParams.Exposure;
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvInputExposure, exposure.RenderTarget, exposure.MipLevel, exposure.SubElement);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvRcasInput, Resources.InternalUpscaled[frameIndex]);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvInputExposure, dispatchParams.Exposure);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvRcasInput, Resources.InternalUpscaled[bufferIndex]);
ref var output = ref dispatchParams.Output;
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavUpscaledOutput, output.RenderTarget, output.MipLevel, output.SubElement);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavUpscaledOutput, dispatchParams.Output);
commandBuffer.SetComputeConstantBufferParam(ComputeShader, Fsr3ShaderIDs.CbFsr3Upscaler, Constants, 0, Marshal.SizeOf<Fsr3Upscaler.UpscalerConstants>());
commandBuffer.SetComputeConstantBufferParam(ComputeShader, Fsr3ShaderIDs.CbRcas, _rcasConstants, 0, Marshal.SizeOf<Fsr3Upscaler.RcasConstants>());
commandBuffer.SetComputeConstantBufferParam<Fsr3Upscaler.UpscalerConstants>(ComputeShader, Fsr3ShaderIDs.CbFsr3Upscaler, Constants);
commandBuffer.SetComputeConstantBufferParam<Fsr3Upscaler.RcasConstants>(ComputeShader, Fsr3ShaderIDs.CbRcas, _rcasConstants);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, 1);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, dispatchZ);
} }
} }
@ -378,7 +330,7 @@ namespace FidelityFX.FSR3
InitComputeShader("Auto-Generate Reactive Mask", contextDescription.Shaders.autoGenReactivePass); InitComputeShader("Auto-Generate Reactive Mask", contextDescription.Shaders.autoGenReactivePass);
} }
protected override void DoScheduleDispatch(CommandBuffer commandBuffer, Fsr3Upscaler.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY)
protected override void DoScheduleDispatch(CommandBuffer commandBuffer, in Fsr3Upscaler.DispatchDescription dispatchParams, int bufferIndex, int dispatchX, int dispatchY, int dispatchZ)
{ {
} }
@ -386,15 +338,11 @@ namespace FidelityFX.FSR3
{ {
commandBuffer.BeginSample(Sampler); commandBuffer.BeginSample(Sampler);
ref var opaqueOnly = ref dispatchParams.ColorOpaqueOnly;
ref var color = ref dispatchParams.ColorPreUpscale;
ref var reactive = ref dispatchParams.OutReactive;
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvOpaqueOnly, dispatchParams.ColorOpaqueOnly);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvInputColor, dispatchParams.ColorPreUpscale);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavAutoReactive, dispatchParams.OutReactive);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvOpaqueOnly, opaqueOnly.RenderTarget, opaqueOnly.MipLevel, opaqueOnly.SubElement);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvInputColor, color.RenderTarget, color.MipLevel, color.SubElement);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavAutoReactive, reactive.RenderTarget, reactive.MipLevel, reactive.SubElement);
commandBuffer.SetComputeConstantBufferParam(ComputeShader, Fsr3ShaderIDs.CbGenReactive, _generateReactiveConstants, 0, Marshal.SizeOf<Fsr3Upscaler.GenerateReactiveConstants>());
commandBuffer.SetComputeConstantBufferParam<Fsr3Upscaler.GenerateReactiveConstants>(ComputeShader, Fsr3ShaderIDs.CbGenReactive, _generateReactiveConstants);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, 1); commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, 1);
@ -414,31 +362,25 @@ namespace FidelityFX.FSR3
InitComputeShader("Auto-Generate Transparency & Composition Mask", contextDescription.Shaders.tcrAutoGenPass); InitComputeShader("Auto-Generate Transparency & Composition Mask", contextDescription.Shaders.tcrAutoGenPass);
} }
protected override void DoScheduleDispatch(CommandBuffer commandBuffer, Fsr3Upscaler.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY)
protected override void DoScheduleDispatch(CommandBuffer commandBuffer, in Fsr3Upscaler.DispatchDescription dispatchParams, int bufferIndex, int dispatchX, int dispatchY, int dispatchZ)
{ {
ref var color = ref dispatchParams.Color;
ref var motionVectors = ref dispatchParams.MotionVectors;
ref var opaqueOnly = ref dispatchParams.ColorOpaqueOnly;
ref var reactive = ref dispatchParams.Reactive;
ref var tac = ref dispatchParams.TransparencyAndComposition;
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvOpaqueOnly, opaqueOnly.RenderTarget, opaqueOnly.MipLevel, opaqueOnly.SubElement);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvInputColor, color.RenderTarget, color.MipLevel, color.SubElement);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvInputMotionVectors, motionVectors.RenderTarget, motionVectors.MipLevel, motionVectors.SubElement);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvPrevColorPreAlpha, Resources.PrevPreAlpha[frameIndex ^ 1]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvPrevColorPostAlpha, Resources.PrevPostAlpha[frameIndex ^ 1]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvReactiveMask, reactive.RenderTarget, reactive.MipLevel, reactive.SubElement);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvTransparencyAndCompositionMask, tac.RenderTarget, tac.MipLevel, tac.SubElement);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvOpaqueOnly, dispatchParams.ColorOpaqueOnly);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvInputColor, dispatchParams.Color);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvInputMotionVectors, dispatchParams.MotionVectors);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvPrevColorPreAlpha, Resources.PrevPreAlpha[bufferIndex ^ 1]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvPrevColorPostAlpha, Resources.PrevPostAlpha[bufferIndex ^ 1]);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvReactiveMask, dispatchParams.Reactive);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvTransparencyAndCompositionMask, dispatchParams.TransparencyAndComposition);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavAutoReactive, Resources.AutoReactive); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavAutoReactive, Resources.AutoReactive);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavAutoComposition, Resources.AutoComposition); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavAutoComposition, Resources.AutoComposition);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavPrevColorPreAlpha, Resources.PrevPreAlpha[frameIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavPrevColorPostAlpha, Resources.PrevPostAlpha[frameIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavPrevColorPreAlpha, Resources.PrevPreAlpha[bufferIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavPrevColorPostAlpha, Resources.PrevPostAlpha[bufferIndex]);
commandBuffer.SetComputeConstantBufferParam(ComputeShader, Fsr3ShaderIDs.CbFsr3Upscaler, Constants, 0, Marshal.SizeOf<Fsr3Upscaler.UpscalerConstants>());
commandBuffer.SetComputeConstantBufferParam(ComputeShader, Fsr3ShaderIDs.CbGenReactive, _tcrAutogenerateConstants, 0, Marshal.SizeOf<Fsr3Upscaler.GenerateReactiveConstants2>());
commandBuffer.SetComputeConstantBufferParam<Fsr3Upscaler.UpscalerConstants>(ComputeShader, Fsr3ShaderIDs.CbFsr3Upscaler, Constants);
commandBuffer.SetComputeConstantBufferParam<Fsr3Upscaler.GenerateReactiveConstants2>(ComputeShader, Fsr3ShaderIDs.CbGenReactive, _tcrAutogenerateConstants);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, 1);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, dispatchZ);
} }
} }
@ -451,21 +393,19 @@ namespace FidelityFX.FSR3
InitComputeShader("Debug View", contextDescription.Shaders.debugViewPass); InitComputeShader("Debug View", contextDescription.Shaders.debugViewPass);
} }
protected override void DoScheduleDispatch(CommandBuffer commandBuffer, Fsr3Upscaler.DispatchDescription dispatchParams, int frameIndex, int dispatchX, int dispatchY)
protected override void DoScheduleDispatch(CommandBuffer commandBuffer, in Fsr3Upscaler.DispatchDescription dispatchParams, int bufferIndex, int dispatchX, int dispatchY, int dispatchZ)
{ {
ref var exposure = ref dispatchParams.Exposure;
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvDilatedReactiveMasks, Fsr3ShaderIDs.UavDilatedReactiveMasks); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvDilatedReactiveMasks, Fsr3ShaderIDs.UavDilatedReactiveMasks);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvDilatedMotionVectors, Resources.DilatedVelocity); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvDilatedMotionVectors, Resources.DilatedVelocity);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvDilatedDepth, Resources.DilatedDepth); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvDilatedDepth, Resources.DilatedDepth);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvInternalUpscaled, Resources.InternalUpscaled[frameIndex]);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvInputExposure, exposure.RenderTarget, exposure.MipLevel, exposure.SubElement);
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvInternalUpscaled, Resources.InternalUpscaled[bufferIndex]);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvInputExposure, dispatchParams.Exposure);
ref var output = ref dispatchParams.Output;
commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavUpscaledOutput, output.RenderTarget, output.MipLevel, output.SubElement);
commandBuffer.SetComputeResourceParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavUpscaledOutput, dispatchParams.Output);
commandBuffer.SetComputeConstantBufferParam(ComputeShader, Fsr3ShaderIDs.CbFsr3Upscaler, Constants, 0, Marshal.SizeOf<Fsr3Upscaler.UpscalerConstants>());
commandBuffer.SetComputeConstantBufferParam<Fsr3Upscaler.UpscalerConstants>(ComputeShader, Fsr3ShaderIDs.CbFsr3Upscaler, Constants);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, 1);
commandBuffer.DispatchCompute(ComputeShader, KernelIndex, dispatchX, dispatchY, dispatchZ);
} }
} }
#endif #endif

87
Runtime/FSR3/Fsr3UpscalerResources.cs

@ -29,7 +29,7 @@ namespace FidelityFX.FSR3
/// Helper class for bundling and managing persistent resources required by the FSR3 Upscaler process. /// Helper class for bundling and managing persistent resources required by the FSR3 Upscaler process.
/// This includes lookup tables, default fallback resources and double-buffered resources that get swapped between frames. /// This includes lookup tables, default fallback resources and double-buffered resources that get swapped between frames.
/// </summary> /// </summary>
internal class Fsr3UpscalerResources
internal class Fsr3UpscalerResources: FfxResourcesBase
{ {
public Texture2D LanczosLut; public Texture2D LanczosLut;
public Texture2D DefaultExposure; public Texture2D DefaultExposure;
@ -55,59 +55,40 @@ namespace FidelityFX.FSR3
{ {
// Generate the data for the LUT // Generate the data for the LUT
const int lanczos2LutWidth = 128; const int lanczos2LutWidth = 128;
float[] lanczos2Weights = new float[lanczos2LutWidth];
for (int currentLanczosWidthIndex = 0; currentLanczosWidthIndex < lanczos2LutWidth; ++currentLanczosWidthIndex)
{
float x = 2.0f * currentLanczosWidthIndex / (lanczos2LutWidth - 1);
float y = Fsr3Upscaler.Lanczos2(x);
lanczos2Weights[currentLanczosWidthIndex] = y;
}
float[] lanczos2Weights = FfxUtils.GenerateLanczos2Table(lanczos2LutWidth);
Vector2Int maxRenderSize = contextDescription.MaxRenderSize; Vector2Int maxRenderSize = contextDescription.MaxRenderSize;
Vector2Int maxRenderSizeDiv2 = maxRenderSize / 2; Vector2Int maxRenderSizeDiv2 = maxRenderSize / 2;
// Resource FSR3UPSCALER_LanczosLutData: FFX_RESOURCE_USAGE_READ_ONLY, FFX_SURFACE_FORMAT_R16_SNORM, FFX_RESOURCE_FLAGS_NONE // Resource FSR3UPSCALER_LanczosLutData: FFX_RESOURCE_USAGE_READ_ONLY, FFX_SURFACE_FORMAT_R16_SNORM, FFX_RESOURCE_FLAGS_NONE
// R16_SNorm textures are not supported by Unity on most platforms, strangely enough. So instead we use R32_SFloat and upload pre-normalized float data. // R16_SNorm textures are not supported by Unity on most platforms, strangely enough. So instead we use R32_SFloat and upload pre-normalized float data.
LanczosLut = new Texture2D(lanczos2LutWidth, 1, GraphicsFormat.R32_SFloat, TextureCreationFlags.None) { name = "FSR3UPSCALER_LanczosLutData" };
LanczosLut.SetPixelData(lanczos2Weights, 0);
LanczosLut.Apply();
LanczosLut = CreateLookup("FSR3UPSCALER_LanczosLutData", new Vector2Int(lanczos2LutWidth, 1), GraphicsFormat.R32_SFloat, lanczos2Weights);
// Resource FSR3UPSCALER_DefaultReactivityMask: FFX_RESOURCE_USAGE_READ_ONLY, FFX_SURFACE_FORMAT_R8_UNORM, FFX_RESOURCE_FLAGS_NONE // Resource FSR3UPSCALER_DefaultReactivityMask: FFX_RESOURCE_USAGE_READ_ONLY, FFX_SURFACE_FORMAT_R8_UNORM, FFX_RESOURCE_FLAGS_NONE
DefaultReactive = new Texture2D(1, 1, GraphicsFormat.R8_UNorm, TextureCreationFlags.None) { name = "FSR3UPSCALER_DefaultReactivityMask" };
DefaultReactive.SetPixel(0, 0, Color.clear);
DefaultReactive.Apply();
DefaultReactive = CreateLookup("FSR3UPSCALER_DefaultReactivityMask", GraphicsFormat.R8_UNorm, Color.clear);
// Resource FSR3UPSCALER_DefaultExposure: FFX_RESOURCE_USAGE_READ_ONLY, FFX_SURFACE_FORMAT_R32G32_FLOAT, FFX_RESOURCE_FLAGS_NONE // Resource FSR3UPSCALER_DefaultExposure: FFX_RESOURCE_USAGE_READ_ONLY, FFX_SURFACE_FORMAT_R32G32_FLOAT, FFX_RESOURCE_FLAGS_NONE
DefaultExposure = new Texture2D(1, 1, GraphicsFormat.R32G32_SFloat, TextureCreationFlags.None) { name = "FSR3UPSCALER_DefaultExposure" };
DefaultExposure.SetPixel(0, 0, Color.clear);
DefaultExposure.Apply();
DefaultExposure = CreateLookup("FSR3UPSCALER_DefaultExposure", GraphicsFormat.R32G32_SFloat, Color.clear);
// Resource FSR3UPSCALER_SpdAtomicCounter: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R32_UINT, FFX_RESOURCE_FLAGS_ALIASABLE // 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. // 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();
SpdAtomicCounter = CreateResource("FSR3UPSCALER_SpdAtomicCounter", Vector2Int.one, GraphicsFormat.R32_UInt);
// Resource FSR3UPSCALER_SpdMips: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R16G16_FLOAT, FFX_RESOURCE_FLAGS_ALIASABLE // 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. // 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.
int mipCount = 1 + Mathf.FloorToInt(Mathf.Log(Math.Max(maxRenderSizeDiv2.x, maxRenderSizeDiv2.y), 2.0f));
SpdMips = new RenderTexture(maxRenderSizeDiv2.x, maxRenderSizeDiv2.y, 0, GraphicsFormat.R16G16_SFloat, mipCount) { name = "FSR3UPSCALER_SpdMips", enableRandomWrite = true, useMipMap = true, autoGenerateMips = false };
SpdMips.Create();
SpdMips = CreateResourceMips("FSR3UPSCALER_SpdMips", maxRenderSizeDiv2, GraphicsFormat.R16G16_SFloat);
// Resource FSR3UPSCALER_DilatedVelocity: FFX_RESOURCE_USAGE_RENDERTARGET | FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R16G16_FLOAT, FFX_RESOURCE_FLAGS_NONE // Resource FSR3UPSCALER_DilatedVelocity: FFX_RESOURCE_USAGE_RENDERTARGET | FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R16G16_FLOAT, FFX_RESOURCE_FLAGS_NONE
DilatedVelocity = new RenderTexture(maxRenderSize.x, maxRenderSize.y, 0, GraphicsFormat.R16G16_SFloat) { name = "FSR3UPSCALER_DilatedVelocity", enableRandomWrite = true };
DilatedVelocity.Create();
DilatedVelocity = CreateResource("FSR3UPSCALER_DilatedVelocity", maxRenderSize, GraphicsFormat.R16G16_SFloat);
// Resource FSR3UPSCALER_DilatedDepth: FFX_RESOURCE_USAGE_RENDERTARGET | FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R32_FLOAT, FFX_RESOURCE_FLAGS_NONE // Resource FSR3UPSCALER_DilatedDepth: FFX_RESOURCE_USAGE_RENDERTARGET | FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R32_FLOAT, FFX_RESOURCE_FLAGS_NONE
DilatedDepth = new RenderTexture(maxRenderSize.x, maxRenderSize.y, 0, GraphicsFormat.R32_SFloat) { name = "FSR3UPSCALER_DilatedDepth", enableRandomWrite = true };
DilatedDepth.Create();
DilatedDepth = CreateResource("FSR3UPSCALER_DilatedDepth", maxRenderSize, GraphicsFormat.R32_SFloat);
// Resource FSR3UPSCALER_ReconstructedPrevNearestDepth: FFX_RESOURCE_USAGE_RENDERTARGET | FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R32_UINT, FFX_RESOURCE_FLAGS_NONE // Resource FSR3UPSCALER_ReconstructedPrevNearestDepth: FFX_RESOURCE_USAGE_RENDERTARGET | FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R32_UINT, FFX_RESOURCE_FLAGS_NONE
ReconstructedPrevNearestDepth = new RenderTexture(maxRenderSize.x, maxRenderSize.y, 0, GraphicsFormat.R32_UInt) { name = "FSR3UPSCALER_ReconstructedPrevNearestDepth", enableRandomWrite = true };
ReconstructedPrevNearestDepth.Create();
ReconstructedPrevNearestDepth = CreateResource("FSR3UPSCALER_ReconstructedPrevNearestDepth", maxRenderSize, GraphicsFormat.R32_UInt);
// Resource FSR3UPSCALER_FrameInfo: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R32G32B32A32_FLOAT, FFX_RESOURCE_FLAGS_NONE // 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();
FrameInfo = CreateResource("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 // 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); CreateDoubleBufferedResource(Accumulation, "FSR3UPSCALER_Accumulation", maxRenderSize, GraphicsFormat.R8_UNorm);
@ -125,12 +106,10 @@ namespace FidelityFX.FSR3
public void CreateTcrAutogenResources(Fsr3Upscaler.ContextDescription contextDescription) public void CreateTcrAutogenResources(Fsr3Upscaler.ContextDescription contextDescription)
{ {
// Resource FSR3UPSCALER_AutoReactive: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R8_UNORM, FFX_RESOURCE_FLAGS_NONE // Resource FSR3UPSCALER_AutoReactive: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R8_UNORM, FFX_RESOURCE_FLAGS_NONE
AutoReactive = new RenderTexture(contextDescription.MaxRenderSize.x, contextDescription.MaxRenderSize.y, 0, GraphicsFormat.R8_UNorm) { name = "FSR3UPSCALER_AutoReactive", enableRandomWrite = true };
AutoReactive.Create();
AutoReactive = CreateResource("FSR3UPSCALER_AutoReactive", contextDescription.MaxRenderSize, GraphicsFormat.R8_UNorm);
// Resource FSR3UPSCALER_AutoComposition: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R8_UNORM, FFX_RESOURCE_FLAGS_NONE // Resource FSR3UPSCALER_AutoComposition: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R8_UNORM, FFX_RESOURCE_FLAGS_NONE
AutoComposition = new RenderTexture(contextDescription.MaxRenderSize.x, contextDescription.MaxRenderSize.y, 0, GraphicsFormat.R8_UNorm) { name = "FSR3UPSCALER_AutoComposition", enableRandomWrite = true };
AutoComposition.Create();
AutoComposition = CreateResource("FSR3UPSCALER_AutoComposition", contextDescription.MaxRenderSize, GraphicsFormat.R8_UNorm);
// Resources FSR3UPSCALER_PrevPreAlpha0/1: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R11G11B10_FLOAT, FFX_RESOURCE_FLAGS_NONE // Resources FSR3UPSCALER_PrevPreAlpha0/1: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R11G11B10_FLOAT, FFX_RESOURCE_FLAGS_NONE
CreateDoubleBufferedResource(PrevPreAlpha, "FSR3UPSCALER_PrevPreAlpha", contextDescription.MaxRenderSize, GraphicsFormat.B10G11R11_UFloatPack32); CreateDoubleBufferedResource(PrevPreAlpha, "FSR3UPSCALER_PrevPreAlpha", contextDescription.MaxRenderSize, GraphicsFormat.B10G11R11_UFloatPack32);
@ -173,15 +152,6 @@ namespace FidelityFX.FSR3
commandBuffer.ReleaseTemporaryRT(Fsr3ShaderIDs.UavIntermediate); commandBuffer.ReleaseTemporaryRT(Fsr3ShaderIDs.UavIntermediate);
} }
private static void CreateDoubleBufferedResource(RenderTexture[] resource, string name, Vector2Int size, GraphicsFormat format)
{
for (int i = 0; i < 2; ++i)
{
resource[i] = new RenderTexture(size.x, size.y, 0, format) { name = name + (i + 1), enableRandomWrite = true };
resource[i].Create();
}
}
public void Destroy() public void Destroy()
{ {
DestroyTcrAutogenResources(); DestroyTcrAutogenResources();
@ -210,36 +180,5 @@ namespace FidelityFX.FSR3
DestroyResource(ref AutoComposition); DestroyResource(ref AutoComposition);
DestroyResource(ref AutoReactive); DestroyResource(ref AutoReactive);
} }
private static void DestroyResource(ref Texture2D resource)
{
if (resource == null)
return;
#if UNITY_EDITOR
if (Application.isPlaying && !UnityEditor.EditorApplication.isPaused)
UnityEngine.Object.Destroy(resource);
else
UnityEngine.Object.DestroyImmediate(resource);
#else
UnityEngine.Object.Destroy(resource);
#endif
resource = null;
}
private static void DestroyResource(ref RenderTexture resource)
{
if (resource == null)
return;
resource.Release();
resource = null;
}
private static void DestroyResource(RenderTexture[] resource)
{
for (int i = 0; i < resource.Length; ++i)
DestroyResource(ref resource[i]);
}
} }
} }
Loading…
Cancel
Save