diff --git a/Runtime/FSR2/Fsr2Context.cs b/Runtime/FSR2/Fsr2Context.cs index 782e700..e4c275c 100644 --- a/Runtime/FSR2/Fsr2Context.cs +++ b/Runtime/FSR2/Fsr2Context.cs @@ -213,12 +213,11 @@ namespace FidelityFX.FSR2 // Auto exposure always used to track luma changes in locking logic commandBuffer.SetRenderTarget(_resources.AutoExposure[frameIndex ^ 1]); commandBuffer.ClearRenderTarget(false, true, new Color(0f, 1e8f, 0f, 0f)); - - // Reset atomic counter to 0 - commandBuffer.SetRenderTarget(_resources.SpdAtomicCounter); - commandBuffer.ClearRenderTarget(false, true, Color.clear); } + // Reset atomic counter to 0 + commandBuffer.SetBufferCounterValue(_resources.SpdAtomicCounter, 0); + // FSR3: need to clear here since we need the content of this surface for frame interpolation, so clearing in the lock pass is not an option bool depthInverted = (_contextDescription.Flags & Fsr2.InitializationFlags.EnableDepthInverted) == Fsr2.InitializationFlags.EnableDepthInverted; commandBuffer.SetRenderTarget(Fsr2ShaderIDs.UavReconstructedPrevNearestDepth); diff --git a/Runtime/FSR2/Fsr2Pass.cs b/Runtime/FSR2/Fsr2Pass.cs index 7186c53..1b6ab02 100644 --- a/Runtime/FSR2/Fsr2Pass.cs +++ b/Runtime/FSR2/Fsr2Pass.cs @@ -129,7 +129,7 @@ namespace FidelityFX.FSR2 commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvInputColor, color.RenderTarget, color.MipLevel, color.SubElement); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.SrvAutoExposure, Resources.AutoExposure[frameIndex ^ 1]); - commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavSpdAtomicCount, Resources.SpdAtomicCounter); + commandBuffer.SetComputeBufferParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavSpdAtomicCount, Resources.SpdAtomicCounter); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavExposureMipLumaChange, Resources.SceneLuminance, ShadingChangeMipLevel); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavExposureMip5, Resources.SceneLuminance, 5); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr2ShaderIDs.UavAutoExposure, Resources.AutoExposure[frameIndex]); diff --git a/Runtime/FSR2/Fsr2Resources.cs b/Runtime/FSR2/Fsr2Resources.cs index 39a7120..04791d1 100644 --- a/Runtime/FSR2/Fsr2Resources.cs +++ b/Runtime/FSR2/Fsr2Resources.cs @@ -35,7 +35,7 @@ namespace FidelityFX.FSR2 public Texture2D DefaultReactive; public Texture2D LanczosLut; public Texture2D MaximumBiasLut; - public RenderTexture SpdAtomicCounter; + public ComputeBuffer SpdAtomicCounter; public RenderTexture SceneLuminance; public RenderTexture AutoReactive; public RenderTexture AutoComposition; @@ -87,9 +87,8 @@ namespace FidelityFX.FSR2 DefaultReactive.Apply(); // Resource FSR2_SpdAtomicCounter: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R32_UINT, FFX_RESOURCE_FLAGS_ALIASABLE - // Despite what the original FSR2 codebase says, this resource really isn't aliasable. Resetting this counter to 0 every frame breaks auto-exposure on MacOS Metal. - SpdAtomicCounter = new RenderTexture(1, 1, 0, GraphicsFormat.R32_UInt) { name = "FSR2_SpdAtomicCounter", enableRandomWrite = true }; - SpdAtomicCounter.Create(); + // Despite what the original FSR2 codebase says, this resource really isn't aliasable. + SpdAtomicCounter = new ComputeBuffer(1, sizeof(uint), ComputeBufferType.Counter, ComputeBufferMode.Dynamic); // Resource FSR2_ExposureMips: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R16_FLOAT, FFX_RESOURCE_FLAGS_ALIASABLE // This is a rather special case: it's an aliasable resource, but because we require a mipmap chain and bind specific mip levels per shader, we can't easily use temporary RTs for this. @@ -191,6 +190,7 @@ namespace FidelityFX.FSR2 DestroyResource(ref DefaultExposure); DestroyResource(ref MaximumBiasLut); DestroyResource(ref LanczosLut); + DestroyResource(ref SpdAtomicCounter); } public void DestroyTcrAutogenResources() @@ -225,6 +225,15 @@ namespace FidelityFX.FSR2 resource.Release(); resource = null; } + + private static void DestroyResource(ref ComputeBuffer resource) + { + if (resource == null) + return; + + resource.Release(); + resource = null; + } private static void DestroyResource(RenderTexture[] resource) { diff --git a/Runtime/FSR3/Fsr3UpscalerContext.cs b/Runtime/FSR3/Fsr3UpscalerContext.cs index bdbedbf..00cabdc 100644 --- a/Runtime/FSR3/Fsr3UpscalerContext.cs +++ b/Runtime/FSR3/Fsr3UpscalerContext.cs @@ -232,12 +232,11 @@ namespace FidelityFX.FSR3 // Auto exposure always used to track luma changes in locking logic commandBuffer.SetRenderTarget(_resources.FrameInfo[frameIndex ^ 1]); commandBuffer.ClearRenderTarget(false, true, new Color(0f, 1e8f, 0f, 0f)); - - // Reset atomic counter to 0 - commandBuffer.SetRenderTarget(_resources.SpdAtomicCounter); - commandBuffer.ClearRenderTarget(false, true, Color.clear); } + // Reset atomic counter to 0 + commandBuffer.SetBufferCounterValue(_resources.SpdAtomicCounter, 0); + // FSR3: need to clear here since we need the content of this surface for frame interpolation, so clearing in the lock pass is not an option bool depthInverted = (_contextDescription.Flags & Fsr3Upscaler.InitializationFlags.EnableDepthInverted) == Fsr3Upscaler.InitializationFlags.EnableDepthInverted; commandBuffer.SetRenderTarget(_resources.ReconstructedPrevNearestDepth); diff --git a/Runtime/FSR3/Fsr3UpscalerPass.cs b/Runtime/FSR3/Fsr3UpscalerPass.cs index 10d4583..f8f30be 100644 --- a/Runtime/FSR3/Fsr3UpscalerPass.cs +++ b/Runtime/FSR3/Fsr3UpscalerPass.cs @@ -157,7 +157,7 @@ namespace FidelityFX.FSR3 commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvFarthestDepth, Fsr3ShaderIDs.UavIntermediate); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvFrameInfo, Resources.FrameInfo[frameIndex ^ 1]); - commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavSpdAtomicCount, Resources.SpdAtomicCounter); + commandBuffer.SetComputeBufferParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavSpdAtomicCount, Resources.SpdAtomicCounter); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavFrameInfo, Resources.FrameInfo[frameIndex]); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavSpdMip0, Resources.SpdMips, 0); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavSpdMip1, Resources.SpdMips, 1); @@ -194,7 +194,7 @@ namespace FidelityFX.FSR3 commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvDilatedMotionVectors, Resources.DilatedVelocity); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.SrvInputExposure, exposure.RenderTarget, exposure.MipLevel, exposure.SubElement); - commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavSpdAtomicCount, Resources.SpdAtomicCounter); + commandBuffer.SetComputeBufferParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavSpdAtomicCount, Resources.SpdAtomicCounter); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavSpdMip0, Resources.SpdMips, 0); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavSpdMip1, Resources.SpdMips, 1); commandBuffer.SetComputeTextureParam(ComputeShader, KernelIndex, Fsr3ShaderIDs.UavSpdMip2, Resources.SpdMips, 2); diff --git a/Runtime/FSR3/Fsr3UpscalerResources.cs b/Runtime/FSR3/Fsr3UpscalerResources.cs index 203ad6e..4f54c8e 100644 --- a/Runtime/FSR3/Fsr3UpscalerResources.cs +++ b/Runtime/FSR3/Fsr3UpscalerResources.cs @@ -35,7 +35,7 @@ namespace FidelityFX.FSR3 public Texture2D DefaultExposure; public Texture2D DefaultReactive; - public RenderTexture SpdAtomicCounter; + public ComputeBuffer SpdAtomicCounter; public RenderTexture SpdMips; public RenderTexture DilatedVelocity; public RenderTexture DilatedDepth; @@ -83,9 +83,8 @@ namespace FidelityFX.FSR3 DefaultExposure.Apply(); // Resource FSR3UPSCALER_SpdAtomicCounter: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R32_UINT, FFX_RESOURCE_FLAGS_ALIASABLE - // Despite what the original FSR3 codebase says, this resource really isn't aliasable. Resetting this counter to 0 every frame breaks auto-exposure on MacOS Metal. - SpdAtomicCounter = new RenderTexture(1, 1, 0, GraphicsFormat.R32_UInt) { name = "FSR3UPSCALER_SpdAtomicCounter", enableRandomWrite = true }; - SpdAtomicCounter.Create(); + // Despite what the original FSR3 codebase says, this resource really isn't aliasable. + SpdAtomicCounter = new ComputeBuffer(1, sizeof(uint), ComputeBufferType.Counter, ComputeBufferMode.Dynamic); // Resource FSR3UPSCALER_SpdMips: FFX_RESOURCE_USAGE_UAV, FFX_SURFACE_FORMAT_R16G16_FLOAT, FFX_RESOURCE_FLAGS_ALIASABLE // This is a rather special case: it's an aliasable resource, but because we require a mipmap chain and bind specific mip levels per shader, we can't easily use temporary RTs for this. @@ -235,6 +234,15 @@ namespace FidelityFX.FSR3 resource = null; } + private static void DestroyResource(ref ComputeBuffer resource) + { + if (resource == null) + return; + + resource.Release(); + resource = null; + } + private static void DestroyResource(RenderTexture[] resource) { for (int i = 0; i < resource.Length; ++i) diff --git a/Shaders/ffx_fsr_unity_common.cginc b/Shaders/ffx_fsr_unity_common.cginc index 2129373..4ee6900 100644 --- a/Shaders/ffx_fsr_unity_common.cginc +++ b/Shaders/ffx_fsr_unity_common.cginc @@ -51,9 +51,7 @@ // #endif // Hack to work around the lack of texture atomics on Metal -// TODO: replace texture atomics with a compute buffer setup #if defined(SHADER_API_METAL) -#define InterlockedAdd(dest, val, orig) { (orig) = (dest); (dest) += (val); } #define InterlockedMin(dest, val) { (dest) = min((dest), (val)); } #define InterlockedMax(dest, val) { (dest) = max((dest), (val)); } #endif diff --git a/Shaders/shaders/fsr2/ffx_fsr2_callbacks_hlsl.h b/Shaders/shaders/fsr2/ffx_fsr2_callbacks_hlsl.h index 3dc9f3a..57ab3ad 100644 --- a/Shaders/shaders/fsr2/ffx_fsr2_callbacks_hlsl.h +++ b/Shaders/shaders/fsr2/ffx_fsr2_callbacks_hlsl.h @@ -467,7 +467,7 @@ SamplerState s_LinearClamp : register(s1); RWTexture2D rw_auto_exposure : FFX_FSR2_DECLARE_UAV(FSR2_BIND_UAV_AUTO_EXPOSURE); #endif #if defined FSR2_BIND_UAV_SPD_GLOBAL_ATOMIC - globallycoherent RWTexture2D rw_spd_global_atomic : FFX_FSR2_DECLARE_UAV(FSR2_BIND_UAV_SPD_GLOBAL_ATOMIC); + globallycoherent RWStructuredBuffer rw_spd_global_atomic : FFX_FSR2_DECLARE_UAV(FSR2_BIND_UAV_SPD_GLOBAL_ATOMIC); #endif #if defined FSR2_BIND_UAV_AUTOREACTIVE @@ -948,14 +948,14 @@ void SPD_SetMipmap(FfxInt32x2 iPxPos, FfxUInt32 slice, FfxFloat32 value) void SPD_IncreaseAtomicCounter(inout FfxUInt32 spdCounter) { #if defined FSR2_BIND_UAV_SPD_GLOBAL_ATOMIC - InterlockedAdd(rw_spd_global_atomic[FfxInt32x2(0, 0)], 1, spdCounter); + InterlockedAdd(rw_spd_global_atomic[0], 1, spdCounter); #endif // #if defined FSR2_BIND_UAV_SPD_GLOBAL_ATOMIC } void SPD_ResetAtomicCounter() { #if defined FSR2_BIND_UAV_SPD_GLOBAL_ATOMIC - rw_spd_global_atomic[FfxInt32x2(0, 0)] = 0; + rw_spd_global_atomic[0] = 0; #endif // #if defined FSR2_BIND_UAV_SPD_GLOBAL_ATOMIC } diff --git a/Shaders/shaders/fsr3upscaler/ffx_fsr3upscaler_callbacks_hlsl.h b/Shaders/shaders/fsr3upscaler/ffx_fsr3upscaler_callbacks_hlsl.h index c88ac2d..b31ab89 100644 --- a/Shaders/shaders/fsr3upscaler/ffx_fsr3upscaler_callbacks_hlsl.h +++ b/Shaders/shaders/fsr3upscaler/ffx_fsr3upscaler_callbacks_hlsl.h @@ -982,16 +982,16 @@ void StorePyramid(FFX_PARAMETER_IN FfxInt32x2 iPxPos, FFX_PARAMETER_IN FfxFloat3 #endif #if defined FSR3UPSCALER_BIND_UAV_SPD_GLOBAL_ATOMIC -globallycoherent RWTexture2D rw_spd_global_atomic : FFX_FSR3UPSCALER_DECLARE_UAV(FSR3UPSCALER_BIND_UAV_SPD_GLOBAL_ATOMIC); +globallycoherent RWStructuredBuffer rw_spd_global_atomic : FFX_FSR3UPSCALER_DECLARE_UAV(FSR3UPSCALER_BIND_UAV_SPD_GLOBAL_ATOMIC); void SPD_IncreaseAtomicCounter(inout FfxUInt32 spdCounter) { - InterlockedAdd(rw_spd_global_atomic[FfxInt32x2(0, 0)], 1, spdCounter); + InterlockedAdd(rw_spd_global_atomic[0], 1, spdCounter); } void SPD_ResetAtomicCounter() { - rw_spd_global_atomic[FfxInt32x2(0, 0)] = 0; + rw_spd_global_atomic[0] = 0; } #endif