diff options
Diffstat (limited to 'externals/FidelityFX-SDK/include/FidelityFX/gpu/fsr3upscaler')
14 files changed, 4148 insertions, 0 deletions
diff --git a/externals/FidelityFX-SDK/include/FidelityFX/gpu/fsr3upscaler/ffx_fsr3upscaler_accumulate.h b/externals/FidelityFX-SDK/include/FidelityFX/gpu/fsr3upscaler/ffx_fsr3upscaler_accumulate.h new file mode 100644 index 0000000000..a8c6daa0e6 --- /dev/null +++ b/externals/FidelityFX-SDK/include/FidelityFX/gpu/fsr3upscaler/ffx_fsr3upscaler_accumulate.h @@ -0,0 +1,172 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and /or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +void Accumulate(const AccumulationPassCommonParams params, FFX_PARAMETER_INOUT AccumulationPassData data) +{ + // Avoid invalid values when accumulation and upsampled weight is 0 + data.fHistoryWeight *= FfxFloat32(data.fHistoryWeight > FSR3UPSCALER_FP16_MIN); + data.fHistoryWeight = ffxMax(FSR3UPSCALER_EPSILON, data.fHistoryWeight + data.fUpsampledWeight); + +#if FFX_FSR3UPSCALER_OPTION_HDR_COLOR_INPUT + //YCoCg -> RGB -> Tonemap -> YCoCg (Use RGB tonemapper to avoid color desaturation) + data.fUpsampledColor = RGBToYCoCg(Tonemap(YCoCgToRGB(data.fUpsampledColor))); + data.fHistoryColor = RGBToYCoCg(Tonemap(YCoCgToRGB(data.fHistoryColor))); +#endif + + const FfxFloat32 fAlpha = ffxSaturate(data.fUpsampledWeight / data.fHistoryWeight); + data.fHistoryColor = ffxLerp(data.fHistoryColor, data.fUpsampledColor, fAlpha); + data.fHistoryColor = YCoCgToRGB(data.fHistoryColor); + +#if FFX_FSR3UPSCALER_OPTION_HDR_COLOR_INPUT + data.fHistoryColor = InverseTonemap(data.fHistoryColor); +#endif +} + +void RectifyHistory( + const AccumulationPassCommonParams params, + FFX_PARAMETER_INOUT AccumulationPassData data +) +{ + const FfxFloat32 f4kVelocityFactor = ffxSaturate(params.f4KVelocity / 20.0f); + const FfxFloat32 fDistanceFactor = ffxSaturate(0.75f - params.fFarthestDepthInMeters / 20.0f); + const FfxFloat32 fAccumulationFactor = 1.0f - params.fAccumulation; + const FfxFloat32 fReactiveFactor = ffxPow(params.fReactiveMask, 1.0f / 2.0f); + const FfxFloat32 fShadingChangeFactor = params.fShadingChange; + const FfxFloat32 fBoxScaleT = ffxMax(f4kVelocityFactor, ffxMax(fDistanceFactor, ffxMax(fAccumulationFactor, ffxMax(fReactiveFactor, fShadingChangeFactor)))); + + const FfxFloat32 fBoxScale = ffxLerp(3.0f, 1.0f, fBoxScaleT); + const FfxFloat32x3 fScaledBoxVec = data.clippingBox.boxVec * FfxFloat32x3(1.7f, 1.0f, 1.0f) * fBoxScale; + + const FfxFloat32x3 fClampedScaledBoxVec = ffxMax(fScaledBoxVec, FfxFloat32x3(1.193e-7f, 1.193e-7f, 1.193e-7f)); + const FfxFloat32x3 fTransformedHistoryColor = (data.fHistoryColor - data.clippingBox.boxCenter) / fClampedScaledBoxVec; + + if (length(fTransformedHistoryColor)>1.f) { + const FfxFloat32x3 fClampedHistoryColor = normalize(fTransformedHistoryColor); + const FfxFloat32x3 fFinalClampedHistoryColor = (fClampedHistoryColor * fScaledBoxVec) + data.clippingBox.boxCenter; + + // Scale history color using rectification info, also using accumulation mask to avoid potential invalid color protection + const FfxFloat32 fHistoryContribution = ffxMax(params.fLumaInstabilityFactor, data.fLockContributionThisFrame) * params.fAccumulation * (1 - params.fDisocclusion); + data.fHistoryColor = ffxLerp(fFinalClampedHistoryColor, data.fHistoryColor, ffxSaturate(fHistoryContribution)); + } +} + +void UpdateLockStatus(AccumulationPassCommonParams params, FFX_PARAMETER_INOUT AccumulationPassData data) +{ + data.fLock *= FfxFloat32(params.bIsNewSample == false); + + const FfxFloat32 fLifetimeDecreaseFactor = ffxMax(ffxSaturate(params.fShadingChange), ffxMax(params.fReactiveMask, params.fDisocclusion)); + data.fLock = ffxMax(0.0f, data.fLock - fLifetimeDecreaseFactor * fLockMax); + + // Compute this frame lock contribution + data.fLockContributionThisFrame = ffxSaturate(ffxSaturate(data.fLock - fLockThreshold) * (fLockMax - fLockThreshold)); + + const FfxFloat32 fNewLockIntensity = LoadRwNewLocks(params.iPxHrPos) * (1.0f - ffxMax(params.fShadingChange * 0, params.fReactiveMask)); + data.fLock = ffxMax(0.0f, ffxMin(data.fLock + fNewLockIntensity, fLockMax)); + + // Preparing for next frame + const FfxFloat32 fLifetimeDecrease = (0.1f / JitterSequenceLength()) * (1.0f - fLifetimeDecreaseFactor); + data.fLock = ffxMax(0.0f, data.fLock - fLifetimeDecrease); + + // we expect similar motion for next frame + // kill lock if that location is outside screen, avoid locks to be clamped to screen borders + const FfxFloat32x2 fEstimatedUvNextFrame = params.fHrUv - params.fMotionVector; + data.fLock *= FfxFloat32(IsUvInside(fEstimatedUvNextFrame) == true); +} + +void ComputeBaseAccumulationWeight(const AccumulationPassCommonParams params, FFX_PARAMETER_INOUT AccumulationPassData data) +{ + FfxFloat32 fBaseAccumulation = params.fAccumulation; + + fBaseAccumulation = ffxMin(fBaseAccumulation, ffxLerp(fBaseAccumulation, 0.15f, ffxSaturate(ffxMax(0.0f, (params.f4KVelocity * VelocityFactor()) / 0.5f)))); + + data.fHistoryWeight = fBaseAccumulation; +} + +void InitPassData(FfxInt32x2 iPxHrPos, FFX_PARAMETER_INOUT AccumulationPassCommonParams params, FFX_PARAMETER_INOUT AccumulationPassData data) +{ + // Init constant params + params.iPxHrPos = iPxHrPos; + const FfxFloat32x2 fHrUv = (iPxHrPos + 0.5f) / UpscaleSize(); + params.fHrUv = fHrUv; + params.fLrUvJittered = fHrUv + Jitter() / RenderSize(); + params.fLrUv_HwSampler = ClampUv(params.fLrUvJittered, RenderSize(), MaxRenderSize()); + + params.fMotionVector = GetMotionVector(iPxHrPos, fHrUv); + params.f4KVelocity = Get4KVelocity(params.fMotionVector); + + ComputeReprojectedUVs(params); + + const FfxFloat32x2 fLumaInstabilityUv_HW = ClampUv(fHrUv, RenderSize(), MaxRenderSize()); + params.fLumaInstabilityFactor = SampleLumaInstability(fLumaInstabilityUv_HW); + + const FfxFloat32x2 fFarthestDepthUv = ClampUv(params.fLrUvJittered, RenderSize() / 2, GetFarthestDepthMip1ResourceDimensions()); + params.fFarthestDepthInMeters = SampleFarthestDepthMip1(fFarthestDepthUv); + params.bIsNewSample = (params.bIsExistingSample == false || 0 == FrameIndex()); + + const FfxFloat32x4 fDilatedReactiveMasks = SampleDilatedReactiveMasks(params.fLrUv_HwSampler); + params.fReactiveMask = ffxSaturate(fDilatedReactiveMasks[REACTIVE]); + params.fDisocclusion = ffxSaturate(fDilatedReactiveMasks[DISOCCLUSION]); + params.fShadingChange = ffxSaturate(fDilatedReactiveMasks[SHADING_CHANGE]); + params.fAccumulation = ffxSaturate(fDilatedReactiveMasks[ACCUMULAION]); + params.fAccumulation *= FfxFloat32(round(params.fAccumulation * 100.0f) > 1.0f); + + // Init variable data + data.fUpsampledColor = FfxFloat32x3(0.0f, 0.0f, 0.0f); + data.fHistoryColor = FfxFloat32x3(0.0f, 0.0f, 0.0f); + data.fHistoryWeight = 1.0f; + data.fUpsampledWeight = 0.0f; + data.fLock = 0.0f; + data.fLockContributionThisFrame = 0.0f; +} + +void Accumulate(FfxInt32x2 iPxHrPos) +{ + AccumulationPassCommonParams params; + AccumulationPassData data; + InitPassData(iPxHrPos, params, data); + + if (params.bIsExistingSample && !params.bIsNewSample) { + ReprojectHistoryColor(params, data); + } + + UpdateLockStatus(params, data); + + ComputeBaseAccumulationWeight(params, data); + + ComputeUpsampledColorAndWeight(params, data); + + RectifyHistory(params, data); + + Accumulate(params, data); + + data.fHistoryColor /= Exposure(); + + data.fHistoryColor = ffxMax(data.fHistoryColor, FfxFloat32x3(0.0f, 0.0f, 0.0f)); + + StoreInternalColorAndWeight(iPxHrPos, FfxFloat32x4(data.fHistoryColor, data.fLock)); + + // Output final color when RCAS is disabled +#if FFX_FSR3UPSCALER_OPTION_APPLY_SHARPENING == 0 + StoreUpscaledOutput(iPxHrPos, data.fHistoryColor); +#endif + StoreNewLocks(iPxHrPos, 0); +} diff --git a/externals/FidelityFX-SDK/include/FidelityFX/gpu/fsr3upscaler/ffx_fsr3upscaler_callbacks_glsl.h b/externals/FidelityFX-SDK/include/FidelityFX/gpu/fsr3upscaler/ffx_fsr3upscaler_callbacks_glsl.h new file mode 100644 index 0000000000..d0cbf9d32e --- /dev/null +++ b/externals/FidelityFX-SDK/include/FidelityFX/gpu/fsr3upscaler/ffx_fsr3upscaler_callbacks_glsl.h @@ -0,0 +1,903 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and /or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "ffx_fsr3upscaler_resources.h" + +#if defined(FFX_GPU) +#include "ffx_core.h" +#endif // #if defined(FFX_GPU) + +#if defined(FFX_GPU) +#ifndef FFX_PREFER_WAVE64 +#define FFX_PREFER_WAVE64 +#endif // FFX_PREFER_WAVE64 + +#if defined(FSR3UPSCALER_BIND_CB_FSR3UPSCALER) + layout (set = 0, binding = FSR3UPSCALER_BIND_CB_FSR3UPSCALER, std140) uniform cbFSR3UPSCALER_t + { + FfxInt32x2 iRenderSize; + FfxInt32x2 iPreviousFrameRenderSize; + + FfxInt32x2 iUpscaleSize; + FfxInt32x2 iPreviousFrameUpscaleSize; + + FfxInt32x2 iMaxRenderSize; + FfxInt32x2 iMaxUpscaleSize; + + FfxFloat32x4 fDeviceToViewDepth; + + FfxFloat32x2 fJitter; + FfxFloat32x2 fPreviousFrameJitter; + + FfxFloat32x2 fMotionVectorScale; + FfxFloat32x2 fDownscaleFactor; + + FfxFloat32x2 fMotionVectorJitterCancellation; + FfxFloat32 fTanHalfFOV; + FfxFloat32 fJitterSequenceLength; + + FfxFloat32 fDeltaTime; + FfxFloat32 fDeltaPreExposure; + FfxFloat32 fViewSpaceToMetersFactor; + FfxFloat32 fFrameIndex; + + FfxFloat32 fVelocityFactor; + FfxFloat32 fReactivenessScale; + FfxFloat32 fShadingChangeScale; + FfxFloat32 fAccumulationAddedPerFrame; + FfxFloat32 fMinDisocclusionAccumulation; + } cbFSR3Upscaler; + + +FfxInt32x2 RenderSize() +{ + return cbFSR3Upscaler.iRenderSize; +} + +FfxInt32x2 PreviousFrameRenderSize() +{ + return cbFSR3Upscaler.iPreviousFrameRenderSize; +} + +FfxInt32x2 MaxRenderSize() +{ + return cbFSR3Upscaler.iMaxRenderSize; +} + +FfxInt32x2 UpscaleSize() +{ + return cbFSR3Upscaler.iUpscaleSize; +} + +FfxInt32x2 PreviousFrameUpscaleSize() +{ + return cbFSR3Upscaler.iPreviousFrameUpscaleSize; +} + +FfxInt32x2 MaxUpscaleSize() +{ + return cbFSR3Upscaler.iMaxUpscaleSize; +} + +FfxFloat32x2 Jitter() +{ + return cbFSR3Upscaler.fJitter; +} + +FfxFloat32x2 PreviousFrameJitter() +{ + return cbFSR3Upscaler.fPreviousFrameJitter; +} + +FfxFloat32x4 DeviceToViewSpaceTransformFactors() +{ + return cbFSR3Upscaler.fDeviceToViewDepth; +} + +FfxFloat32x2 MotionVectorScale() +{ + return cbFSR3Upscaler.fMotionVectorScale; +} + +FfxFloat32x2 DownscaleFactor() +{ + return cbFSR3Upscaler.fDownscaleFactor; +} + +FfxFloat32x2 MotionVectorJitterCancellation() +{ + return cbFSR3Upscaler.fMotionVectorJitterCancellation; +} + +FfxFloat32 TanHalfFoV() +{ + return cbFSR3Upscaler.fTanHalfFOV; +} + +FfxFloat32 JitterSequenceLength() +{ + return cbFSR3Upscaler.fJitterSequenceLength; +} + +FfxFloat32 DeltaTime() +{ + return cbFSR3Upscaler.fDeltaTime; +} + +FfxFloat32 DeltaPreExposure() +{ + return cbFSR3Upscaler.fDeltaPreExposure; +} + +FfxFloat32 ViewSpaceToMetersFactor() +{ + return cbFSR3Upscaler.fViewSpaceToMetersFactor; +} + +FfxFloat32 FrameIndex() +{ + return cbFSR3Upscaler.fFrameIndex; +} + +FfxFloat32 VelocityFactor() +{ + return cbFSR3Upscaler.fVelocityFactor; +} + +FfxFloat32 AccumulationAddedPerFrame() +{ + return cbFSR3Upscaler.fAccumulationAddedPerFrame; +} + +FfxFloat32 MinDisocclusionAccumulation() +{ + return cbFSR3Upscaler.fMinDisocclusionAccumulation; +} + +#endif // #if defined(FSR3UPSCALER_BIND_CB_FSR3UPSCALER) + + +#if defined(FSR3UPSCALER_BIND_CB_AUTOREACTIVE) +layout(set = 0, binding = FSR3UPSCALER_BIND_CB_AUTOREACTIVE, std140) uniform cbGenerateReactive_t +{ + FfxFloat32 fTcThreshold; // 0.1 is a good starting value, lower will result in more TC pixels + FfxFloat32 fTcScale; + FfxFloat32 fReactiveScale; + FfxFloat32 fReactiveMax; +} cbGenerateReactive; + +FfxFloat32 TcThreshold() +{ + return cbGenerateReactive.fTcThreshold; +} + +FfxFloat32 TcScale() +{ + return cbGenerateReactive.fTcScale; +} + +FfxFloat32 ReactiveScale() +{ + return cbGenerateReactive.fReactiveScale; +} + +FfxFloat32 ReactiveMax() +{ + return cbGenerateReactive.fReactiveMax; +} +#endif // #if defined(FSR3UPSCALER_BIND_CB_AUTOREACTIVE) + +#if defined(FSR3UPSCALER_BIND_CB_RCAS) +layout(set = 0, binding = FSR3UPSCALER_BIND_CB_RCAS, std140) uniform cbRCAS_t +{ + FfxUInt32x4 rcasConfig; +} cbRCAS; + +FfxUInt32x4 RCASConfig() +{ + return cbRCAS.rcasConfig; +} +#endif // #if defined(FSR3UPSCALER_BIND_CB_RCAS) + + +#if defined(FSR3UPSCALER_BIND_CB_REACTIVE) +layout(set = 0, binding = FSR3UPSCALER_BIND_CB_REACTIVE, std140) uniform cbGenerateReactive_t +{ + FfxFloat32 gen_reactive_scale; + FfxFloat32 gen_reactive_threshold; + FfxFloat32 gen_reactive_binaryValue; + FfxUInt32 gen_reactive_flags; +} cbGenerateReactive; + +FfxFloat32 GenReactiveScale() +{ + return cbGenerateReactive.gen_reactive_scale; +} + +FfxFloat32 GenReactiveThreshold() +{ + return cbGenerateReactive.gen_reactive_threshold; +} + +FfxFloat32 GenReactiveBinaryValue() +{ + return cbGenerateReactive.gen_reactive_binaryValue; +} + +FfxUInt32 GenReactiveFlags() +{ + return cbGenerateReactive.gen_reactive_flags; +} +#endif // #if defined(FSR3UPSCALER_BIND_CB_REACTIVE) + + +#if defined(FSR3UPSCALER_BIND_CB_SPD) +layout(set = 0, binding = FSR3UPSCALER_BIND_CB_SPD, std140) uniform cbSPD_t +{ + FfxUInt32 mips; + FfxUInt32 numWorkGroups; + FfxUInt32x2 workGroupOffset; + FfxUInt32x2 renderSize; +} cbSPD; + +FfxUInt32 MipCount() +{ + return cbSPD.mips; +} + +FfxUInt32 NumWorkGroups() +{ + return cbSPD.numWorkGroups; +} + +FfxUInt32x2 WorkGroupOffset() +{ + return cbSPD.workGroupOffset; +} + +FfxUInt32x2 SPD_RenderSize() +{ + return cbSPD.renderSize; +} +#endif // #if defined(FSR3UPSCALER_BIND_CB_SPD) + +layout (set = 0, binding = 1000) uniform sampler s_PointClamp; +layout (set = 0, binding = 1001) uniform sampler s_LinearClamp; + +#if defined(FSR3UPSCALER_BIND_SRV_SPD_MIPS) +layout (set = 0, binding = FSR3UPSCALER_BIND_SRV_SPD_MIPS) uniform texture2D r_spd_mips; + +FfxInt32x2 GetSPDMipDimensions(FfxUInt32 uMipLevel) +{ + return textureSize(r_spd_mips, int(uMipLevel)).xy; +} + +FfxFloat32x2 SampleSPDMipLevel(FfxFloat32x2 fUV, FfxUInt32 mipLevel) +{ + return textureLod(sampler2D(r_spd_mips, s_LinearClamp), fUV, float(mipLevel)).rg; +} +#endif + +#if defined(FSR3UPSCALER_BIND_SRV_INPUT_DEPTH) +layout (set = 0, binding = FSR3UPSCALER_BIND_SRV_INPUT_DEPTH) uniform texture2D r_input_depth; + +FfxFloat32 LoadInputDepth(FfxInt32x2 iPxPos) +{ + return texelFetch(r_input_depth, iPxPos, 0).r; +} + +FfxFloat32 SampleInputDepth(FfxFloat32x2 fUV) +{ + return textureLod(sampler2D(r_input_depth, s_LinearClamp), fUV, 0.0).x; +} +#endif + +#if defined(FSR3UPSCALER_BIND_SRV_REACTIVE_MASK) +layout (set = 0, binding = FSR3UPSCALER_BIND_SRV_REACTIVE_MASK) uniform texture2D r_reactive_mask; + +FfxFloat32 LoadReactiveMask(FfxInt32x2 iPxPos) +{ + return texelFetch(r_reactive_mask, FfxInt32x2(iPxPos), 0).r * cbFSR3Upscaler.fReactivenessScale; +} + +FfxInt32x2 GetReactiveMaskResourceDimensions() +{ + return textureSize(r_reactive_mask, 0).xy; +} + +FfxFloat32 SampleReactiveMask(FfxFloat32x2 fUV) +{ + return textureLod(sampler2D(r_reactive_mask, s_LinearClamp), fUV, 0.0).x * cbFSR3Upscaler.fReactivenessScale; +} +#endif + +#if defined(FSR3UPSCALER_BIND_SRV_TRANSPARENCY_AND_COMPOSITION_MASK) +layout (set = 0, binding = FSR3UPSCALER_BIND_SRV_TRANSPARENCY_AND_COMPOSITION_MASK) uniform texture2D r_transparency_and_composition_mask; + +FfxFloat32 LoadTransparencyAndCompositionMask(FfxUInt32x2 iPxPos) +{ + return texelFetch(r_transparency_and_composition_mask, FfxInt32x2(iPxPos), 0).r; +} + +FfxInt32x2 GetTransparencyAndCompositionMaskResourceDimensions() +{ + return textureSize(r_transparency_and_composition_mask, 0).xy; +} + +FfxFloat32 SampleTransparencyAndCompositionMask(FfxFloat32x2 fUV) +{ + return textureLod(sampler2D(r_transparency_and_composition_mask, s_LinearClamp), fUV, 0.0).x; +} +#endif + +#if defined(FSR3UPSCALER_BIND_SRV_INPUT_COLOR) +layout (set = 0, binding = FSR3UPSCALER_BIND_SRV_INPUT_COLOR) uniform texture2D r_input_color_jittered; + +FfxFloat32x3 LoadInputColor(FfxInt32x2 iPxPos) +{ + return texelFetch(r_input_color_jittered, iPxPos, 0).rgb; +} + +FfxFloat32x3 SampleInputColor(FfxFloat32x2 fUV) +{ + return textureLod(sampler2D(r_input_color_jittered, s_LinearClamp), fUV, 0.0).rgb; +} +#endif + +#if defined(FSR3UPSCALER_BIND_SRV_INPUT_MOTION_VECTORS) +layout (set = 0, binding = FSR3UPSCALER_BIND_SRV_INPUT_MOTION_VECTORS) uniform texture2D r_input_motion_vectors; + +FfxFloat32x2 LoadInputMotionVector(FfxInt32x2 iPxDilatedMotionVectorPos) +{ + FfxFloat32x2 fSrcMotionVector = texelFetch(r_input_motion_vectors, iPxDilatedMotionVectorPos, 0).xy; + + FfxFloat32x2 fUvMotionVector = fSrcMotionVector * MotionVectorScale(); + +#if FFX_FSR3UPSCALER_OPTION_JITTERED_MOTION_VECTORS + fUvMotionVector -= MotionVectorJitterCancellation(); +#endif + + return fUvMotionVector; +} +#endif + +#if defined(FSR3UPSCALER_BIND_SRV_INTERNAL_UPSCALED) +layout (set = 0, binding = FSR3UPSCALER_BIND_SRV_INTERNAL_UPSCALED) uniform texture2D r_internal_upscaled_color; + +FfxFloat32x4 LoadHistory(FfxInt32x2 iPxHistory) +{ + return texelFetch(r_internal_upscaled_color, iPxHistory, 0); +} + +FfxFloat32x4 SampleHistory(FfxFloat32x2 fUV) +{ + return textureLod(sampler2D(r_internal_upscaled_color, s_LinearClamp), fUV, 0.0); +} +#endif + +#if defined(FSR3UPSCALER_BIND_UAV_LUMA_HISTORY) +layout (set = 0, binding = FSR3UPSCALER_BIND_UAV_LUMA_HISTORY, rgba8) uniform image2D rw_luma_history; + +void StoreLumaHistory(FfxInt32x2 iPxPos, FfxFloat32x4 fLumaHistory) +{ + imageStore(rw_luma_history, iPxPos, fLumaHistory); +} +#endif + +#if defined(FSR3UPSCALER_BIND_SRV_LUMA_HISTORY) +layout (set = 0, binding = FSR3UPSCALER_BIND_SRV_LUMA_HISTORY) uniform texture2D r_luma_history; + +FfxFloat32x4 LoadLumaHistory(FfxInt32x2 iPxPos) +{ + return texelFetch(r_luma_history, iPxPos, 0); +} + +FfxFloat32x4 SampleLumaHistory(FfxFloat32x2 fUV) +{ + return textureLod(sampler2D(r_luma_history, s_LinearClamp), fUV, 0.0); +} +#endif + +#if defined(FSR3UPSCALER_BIND_SRV_RCAS_INPUT) +layout (set = 0, binding = FSR3UPSCALER_BIND_SRV_RCAS_INPUT) uniform texture2D r_rcas_input; + +FfxFloat32x4 LoadRCAS_Input(FfxInt32x2 iPxPos) +{ + return texelFetch(r_rcas_input, iPxPos, 0); +} + +FfxFloat32x3 SampleRCAS_Input(FfxFloat32x2 fUV) +{ + return textureLod(sampler2D(r_rcas_input, s_LinearClamp), fUV, 0.0).rgb; +} +#endif + +#if defined(FSR3UPSCALER_BIND_UAV_INTERNAL_UPSCALED) +layout (set = 0, binding = FSR3UPSCALER_BIND_UAV_INTERNAL_UPSCALED, rgba16f) writeonly uniform image2D rw_internal_upscaled_color; + +void StoreReprojectedHistory(FfxInt32x2 iPxHistory, FfxFloat32x4 fHistory) +{ + imageStore(rw_internal_upscaled_color, iPxHistory, fHistory); +} + +void StoreInternalColorAndWeight(FfxInt32x2 iPxPos, FfxFloat32x4 fColorAndWeight) +{ + imageStore(rw_internal_upscaled_color, iPxPos, fColorAndWeight); +} +#endif + +#if defined(FSR3UPSCALER_BIND_UAV_UPSCALED_OUTPUT) +layout (set = 0, binding = FSR3UPSCALER_BIND_UAV_UPSCALED_OUTPUT /* app controlled format */) writeonly uniform image2D rw_upscaled_output; + +void StoreUpscaledOutput(FfxInt32x2 iPxPos, FfxFloat32x3 fColor) +{ + imageStore(rw_upscaled_output, iPxPos, FfxFloat32x4(fColor, 1.0)); +} +#endif + +#if defined(FSR3UPSCALER_BIND_SRV_ACCUMULATION) +layout(set = 0, binding = FSR3UPSCALER_BIND_SRV_ACCUMULATION) uniform texture2D r_accumulation; + +FfxFloat32 SampleAccumulation(FfxFloat32x2 fUV) +{ + return textureLod(sampler2D(r_accumulation, s_LinearClamp), fUV, 0.0).x; +} +#endif + +#if defined(FSR3UPSCALER_BIND_UAV_ACCUMULATION) +layout (set = 0, binding = FSR3UPSCALER_BIND_UAV_ACCUMULATION, r8) uniform image2D rw_accumulation; + +void StoreAccumulation(FfxInt32x2 iPxPos, FfxFloat32 fAccumulation) +{ + imageStore(rw_accumulation, iPxPos, vec4(fAccumulation, 0.0, 0.0, 0.0)); +} +#endif + +#if defined(FSR3UPSCALER_BIND_SRV_SHADING_CHANGE) +layout(set = 0, binding = FSR3UPSCALER_BIND_SRV_SHADING_CHANGE) uniform texture2D r_shading_change; + +FfxFloat32 LoadShadingChange(FfxInt32x2 iPxPos) +{ + return texelFetch(r_shading_change, iPxPos, 0).x * cbFSR3Upscaler.fShadingChangeScale; +} + +FfxFloat32 SampleShadingChange(FfxFloat32x2 fUV) +{ + return textureLod(sampler2D(r_shading_change, s_LinearClamp), fUV, 0.0).x * cbFSR3Upscaler.fShadingChangeScale; +} +#endif + +#if defined(FSR3UPSCALER_BIND_UAV_SHADING_CHANGE) +layout (set = 0, binding = FSR3UPSCALER_BIND_UAV_SHADING_CHANGE, r8) uniform image2D rw_shading_change; + +void StoreShadingChange(FfxInt32x2 iPxPos, FfxFloat32 fShadingChange) +{ + imageStore(rw_shading_change, iPxPos, vec4(fShadingChange, 0.0, 0.0, 0.0)); +} +#endif + +#if defined(FSR3UPSCALER_BIND_SRV_FARTHEST_DEPTH) +layout(set = 0, binding = FSR3UPSCALER_BIND_SRV_FARTHEST_DEPTH) uniform texture2D r_farthest_depth; + +FfxInt32x2 GetFarthestDepthResourceDimensions() +{ + return textureSize(r_farthest_depth, 0).xy; +} + +FfxFloat32 LoadFarthestDepth(FfxInt32x2 iPxPos) +{ + return texelFetch(r_farthest_depth, iPxPos, 0).x; +} + +FfxFloat32 SampleFarthestDepth(FfxFloat32x2 fUV) +{ + return textureLod(sampler2D(r_farthest_depth, s_LinearClamp), fUV, 0.0).x; +} +#endif + +#if defined(FSR3UPSCALER_BIND_UAV_FARTHEST_DEPTH) +layout (set = 0, binding = FSR3UPSCALER_BIND_UAV_FARTHEST_DEPTH, r16f) uniform image2D rw_farthest_depth; + +void StoreFarthestDepth(FfxInt32x2 iPxPos, FfxFloat32 fDepth) +{ + imageStore(rw_farthest_depth, iPxPos, vec4(fDepth, 0.0, 0.0, 0.0)); +} +#endif + +#if defined(FSR3UPSCALER_BIND_SRV_FARTHEST_DEPTH_MIP1) +layout(set = 0, binding = FSR3UPSCALER_BIND_SRV_FARTHEST_DEPTH_MIP1) uniform texture2D r_farthest_depth_mip1; + +FfxInt32x2 GetFarthestDepthMip1ResourceDimensions() +{ + return textureSize(r_farthest_depth_mip1, 0).xy; +} + +FfxFloat32 LoadFarthestDepthMip1(FfxInt32x2 iPxPos) +{ + return texelFetch(r_farthest_depth_mip1, iPxPos, 0).x; +} + +FfxFloat32 SampleFarthestDepthMip1(FfxFloat32x2 fUV) +{ + return textureLod(sampler2D(r_farthest_depth_mip1, s_LinearClamp), fUV, 0.0).x; +} +#endif + +#if defined(FSR3UPSCALER_BIND_UAV_FARTHEST_DEPTH_MIP1) +layout (set = 0, binding = FSR3UPSCALER_BIND_UAV_FARTHEST_DEPTH_MIP1, r16f) uniform image2D rw_farthest_depth_mip1; + +void StoreFarthestDepthMip1(FfxInt32x2 iPxPos, FfxFloat32 fDepth) +{ + imageStore(rw_farthest_depth_mip1, iPxPos, vec4(fDepth, 0.0, 0.0, 0.0)); +} +#endif + +#if defined(FSR3UPSCALER_BIND_SRV_CURRENT_LUMA) +layout(set = 0, binding = FSR3UPSCALER_BIND_SRV_CURRENT_LUMA) uniform texture2D r_current_luma; + +FfxFloat32 LoadCurrentLuma(FfxInt32x2 iPxPos) +{ + return texelFetch(r_current_luma, iPxPos, 0).r; +} + +FfxFloat32 SampleCurrentLuma(FfxFloat32x2 uv) +{ + return textureLod(sampler2D(r_current_luma, s_LinearClamp), uv, 0.0).r; +} +#endif + +#if defined(FSR3UPSCALER_BIND_UAV_CURRENT_LUMA) +layout (set = 0, binding = FSR3UPSCALER_BIND_UAV_CURRENT_LUMA, r16f) uniform image2D rw_current_luma; + +void StoreCurrentLuma(FfxInt32x2 iPxPos, FfxFloat32 fLuma) +{ + imageStore(rw_current_luma, iPxPos, vec4(fLuma, 0.0, 0.0, 0.0)); +} +#endif + +#if defined(FSR3UPSCALER_BIND_SRV_LUMA_INSTABILITY) +layout(set = 0, binding = FSR3UPSCALER_BIND_SRV_LUMA_INSTABILITY) uniform texture2D r_luma_instability; + +FfxFloat32 SampleLumaInstability(FfxFloat32x2 uv) +{ + return textureLod(sampler2D(r_luma_instability, s_LinearClamp), uv, 0.0).x; +} +#endif + +#if defined(FSR3UPSCALER_BIND_UAV_LUMA_INSTABILITY) +layout (set = 0, binding = FSR3UPSCALER_BIND_UAV_LUMA_INSTABILITY, r16f) uniform image2D rw_luma_instability; + +void StoreLumaInstability(FfxInt32x2 iPxPos, FfxFloat32 fLumaInstability) +{ + imageStore(rw_luma_instability, iPxPos, vec4(fLumaInstability, 0.0, 0.0, 0.0)); +} +#endif + +#if defined(FSR3UPSCALER_BIND_SRV_PREVIOUS_LUMA) +layout(set = 0, binding = FSR3UPSCALER_BIND_SRV_PREVIOUS_LUMA) uniform texture2D r_previous_luma; + +FfxFloat32 LoadPreviousLuma(FfxInt32x2 iPxPos) +{ + return texelFetch(r_previous_luma, iPxPos, 0).r; +} + +FfxFloat32 SamplePreviousLuma(FfxFloat32x2 uv) +{ + return textureLod(sampler2D(r_previous_luma, s_LinearClamp), uv, 0.0).r; +} +#endif + +#if defined(FSR3UPSCALER_BIND_SRV_NEW_LOCKS) +layout(set = 0, binding = FSR3UPSCALER_BIND_SRV_NEW_LOCKS) uniform texture2D r_new_locks; + +FfxFloat32 LoadNewLocks(FfxInt32x2 iPxPos) +{ + return texelFetch(r_new_locks, iPxPos, 0).r; +} +#endif + +#if defined(FSR3UPSCALER_BIND_UAV_NEW_LOCKS) +layout(set = 0, binding = FSR3UPSCALER_BIND_UAV_NEW_LOCKS, r8) uniform image2D rw_new_locks; + +FfxFloat32 LoadRwNewLocks(FfxInt32x2 iPxPos) +{ + return imageLoad(rw_new_locks, iPxPos).r; +} + +void StoreNewLocks(FfxInt32x2 iPxPos, FfxFloat32 newLock) +{ + imageStore(rw_new_locks, iPxPos, vec4(newLock, 0, 0, 0)); +} +#endif + +#if defined(FSR3UPSCALER_BIND_SRV_RECONSTRUCTED_PREV_NEAREST_DEPTH) +layout (set = 0, binding = FSR3UPSCALER_BIND_SRV_RECONSTRUCTED_PREV_NEAREST_DEPTH) uniform utexture2D r_reconstructed_previous_nearest_depth; + +FfxFloat32 LoadReconstructedPrevDepth(FfxInt32x2 iPxPos) +{ + return uintBitsToFloat(texelFetch(r_reconstructed_previous_nearest_depth, iPxPos, 0).r); +} +#endif + +#if defined(FSR3UPSCALER_BIND_UAV_RECONSTRUCTED_PREV_NEAREST_DEPTH) +layout (set = 0, binding = FSR3UPSCALER_BIND_UAV_RECONSTRUCTED_PREV_NEAREST_DEPTH, r32ui) uniform uimage2D rw_reconstructed_previous_nearest_depth; + +void StoreReconstructedDepth(FfxInt32x2 iPxSample, FfxFloat32 fDepth) +{ + FfxUInt32 uDepth = floatBitsToUint(fDepth); + + #if FFX_FSR3UPSCALER_OPTION_INVERTED_DEPTH + imageAtomicMax(rw_reconstructed_previous_nearest_depth, iPxSample, uDepth); + #else + imageAtomicMin(rw_reconstructed_previous_nearest_depth, iPxSample, uDepth); // min for standard, max for inverted depth + #endif +} + +void SetReconstructedDepth(FfxInt32x2 iPxSample, FfxUInt32 uValue) +{ + imageStore(rw_reconstructed_previous_nearest_depth, iPxSample, uvec4(uValue, 0, 0, 0)); +} +#endif + +#if defined(FSR3UPSCALER_BIND_UAV_DILATED_DEPTH) +layout (set = 0, binding = FSR3UPSCALER_BIND_UAV_DILATED_DEPTH, r32f) writeonly uniform image2D rw_dilated_depth; + +void StoreDilatedDepth(FFX_PARAMETER_IN FfxInt32x2 iPxPos, FFX_PARAMETER_IN FfxFloat32 fDepth) +{ + imageStore(rw_dilated_depth, iPxPos, vec4(fDepth, 0.0, 0.0, 0.0)); +} +#endif + +#if defined(FSR3UPSCALER_BIND_UAV_DILATED_MOTION_VECTORS) +layout (set = 0, binding = FSR3UPSCALER_BIND_UAV_DILATED_MOTION_VECTORS, rg16f) writeonly uniform image2D rw_dilated_motion_vectors; + +void StoreDilatedMotionVector(FFX_PARAMETER_IN FfxInt32x2 iPxPos, FFX_PARAMETER_IN FfxFloat32x2 fMotionVector) +{ + imageStore(rw_dilated_motion_vectors, iPxPos, vec4(fMotionVector, 0.0, 0.0)); +} +#endif + +#if defined(FSR3UPSCALER_BIND_SRV_DILATED_MOTION_VECTORS) +layout (set = 0, binding = FSR3UPSCALER_BIND_SRV_DILATED_MOTION_VECTORS) uniform texture2D r_dilated_motion_vectors; + +FfxFloat32x2 LoadDilatedMotionVector(FfxInt32x2 iPxInput) +{ + return texelFetch(r_dilated_motion_vectors, iPxInput, 0).xy; +} + +FfxFloat32x2 SampleDilatedMotionVector(FfxFloat32x2 fUV) +{ + return textureLod(sampler2D(r_dilated_motion_vectors, s_LinearClamp), fUV, 0.0).xy; +} +#endif + +#if defined(FSR3UPSCALER_BIND_SRV_DILATED_DEPTH) +layout (set = 0, binding = FSR3UPSCALER_BIND_SRV_DILATED_DEPTH) uniform texture2D r_dilated_depth; + +FfxFloat32 LoadDilatedDepth(FfxInt32x2 iPxInput) +{ + return texelFetch(r_dilated_depth, iPxInput, 0).r; +} + +FfxFloat32 SampleDilatedDepth(FfxFloat32x2 fUV) +{ + return textureLod(sampler2D(r_dilated_depth, s_LinearClamp), fUV, 0.0).r; +} +#endif + +#if defined(FSR3UPSCALER_BIND_SRV_INPUT_EXPOSURE) +layout (set = 0, binding = FSR3UPSCALER_BIND_SRV_INPUT_EXPOSURE) uniform texture2D r_input_exposure; + +FfxFloat32 Exposure() +{ + FfxFloat32 exposure = texelFetch(r_input_exposure, FfxInt32x2(0, 0), 0).x; + + if (exposure == 0.0) { + exposure = 1.0; + } + + return exposure; +} +#endif + +// BEGIN: FSR3UPSCALER_BIND_SRV_LANCZOS_LUT +#if defined(FSR3UPSCALER_BIND_SRV_LANCZOS_LUT) +layout (set = 0, binding = FSR3UPSCALER_BIND_SRV_LANCZOS_LUT) uniform texture2D r_lanczos_lut; +#endif + +FfxFloat32 SampleLanczos2Weight(FfxFloat32 x) +{ +#if defined(FSR3UPSCALER_BIND_SRV_LANCZOS_LUT) + return textureLod(sampler2D(r_lanczos_lut, s_LinearClamp), FfxFloat32x2(x / 2.0, 0.5), 0.0).x; +#else + return 0.f; +#endif +} +// END: FSR3UPSCALER_BIND_SRV_LANCZOS_LUT + +#if defined(FSR3UPSCALER_BIND_SRV_DILATED_REACTIVE_MASKS) +layout (set = 0, binding = FSR3UPSCALER_BIND_SRV_DILATED_REACTIVE_MASKS) uniform texture2D r_dilated_reactive_masks; + +FfxFloat32x4 SampleDilatedReactiveMasks(FfxFloat32x2 fUV) +{ + return textureLod(sampler2D(r_dilated_reactive_masks, s_LinearClamp), fUV, 0.0); +} +#endif + +#if defined(FSR3UPSCALER_BIND_UAV_DILATED_REACTIVE_MASKS) +layout (set = 0, binding = FSR3UPSCALER_BIND_UAV_DILATED_REACTIVE_MASKS, rgba8) writeonly uniform image2D rw_dilated_reactive_masks; + +void StoreDilatedReactiveMasks(FFX_PARAMETER_IN FfxInt32x2 iPxPos, FFX_PARAMETER_IN FfxFloat32x4 fDilatedReactiveMasks) +{ + imageStore(rw_dilated_reactive_masks, iPxPos, fDilatedReactiveMasks); +} +#endif + +#if defined(FSR3UPSCALER_BIND_SRV_INPUT_OPAQUE_ONLY) +layout (set = 0, binding = FSR3UPSCALER_BIND_SRV_INPUT_OPAQUE_ONLY) uniform texture2D r_input_opaque_only; + +FfxFloat32x3 LoadOpaqueOnly(FFX_PARAMETER_IN FFX_MIN16_I2 iPxPos) +{ + return texelFetch(r_input_opaque_only, iPxPos, 0).xyz; +} +#endif + +#if defined(FSR3UPSCALER_BIND_SRV_PREV_PRE_ALPHA_COLOR) +layout(set = 0, binding = FSR3UPSCALER_BIND_SRV_PREV_PRE_ALPHA_COLOR) uniform texture2D r_input_prev_color_pre_alpha; + +FfxFloat32x3 LoadPrevPreAlpha(FFX_PARAMETER_IN FFX_MIN16_I2 iPxPos) +{ + return texelFetch(r_input_prev_color_pre_alpha, iPxPos, 0).xyz; +} +#endif + +#if defined(FSR3UPSCALER_BIND_SRV_PREV_POST_ALPHA_COLOR) +layout(set = 0, binding = FSR3UPSCALER_BIND_SRV_PREV_POST_ALPHA_COLOR) uniform texture2D r_input_prev_color_post_alpha; + +FfxFloat32x3 LoadPrevPostAlpha(FFX_PARAMETER_IN FFX_MIN16_I2 iPxPos) +{ + return texelFetch(r_input_prev_color_post_alpha, iPxPos, 0).xyz; +} +#endif + +#if defined(FSR3UPSCALER_BIND_UAV_AUTOREACTIVE) && \ + defined(FSR3UPSCALER_BIND_UAV_AUTOCOMPOSITION) + +layout(set = 0, binding = FSR3UPSCALER_BIND_UAV_AUTOREACTIVE, r32f) uniform image2D rw_output_autoreactive; +layout(set = 0, binding = FSR3UPSCALER_BIND_UAV_AUTOCOMPOSITION, r32f) uniform image2D rw_output_autocomposition; + +void StoreAutoReactive(FFX_PARAMETER_IN FFX_MIN16_I2 iPxPos, FFX_PARAMETER_IN FFX_MIN16_F2 fReactive) +{ + imageStore(rw_output_autoreactive, iPxPos, FfxFloat32x4(FfxFloat32(fReactive.x), 0.0, 0.0, 0.0)); + + imageStore(rw_output_autocomposition, iPxPos, FfxFloat32x4(FfxFloat32(fReactive.y), 0.0, 0.0, 0.0)); +} +#endif + +#if defined(FSR3UPSCALER_BIND_UAV_PREV_PRE_ALPHA_COLOR) +layout(set = 0, binding = FSR3UPSCALER_BIND_UAV_PREV_PRE_ALPHA_COLOR, r11f_g11f_b10f) uniform image2D rw_output_prev_color_pre_alpha; + +void StorePrevPreAlpha(FFX_PARAMETER_IN FFX_MIN16_I2 iPxPos, FFX_PARAMETER_IN FFX_MIN16_F3 color) +{ + imageStore(rw_output_prev_color_pre_alpha, iPxPos, FfxFloat32x4(color, 0.0)); +} +#endif + +#if defined(FSR3UPSCALER_BIND_UAV_PREV_POST_ALPHA_COLOR) +layout(set = 0, binding = FSR3UPSCALER_BIND_UAV_PREV_POST_ALPHA_COLOR, r11f_g11f_b10f) uniform image2D rw_output_prev_color_post_alpha; + +void StorePrevPostAlpha(FFX_PARAMETER_IN FFX_MIN16_I2 iPxPos, FFX_PARAMETER_IN FFX_MIN16_F3 color) +{ + imageStore(rw_output_prev_color_post_alpha, iPxPos, FfxFloat32x4(color, 0.0)); +} +#endif + +#if defined(FSR3UPSCALER_BIND_UAV_FRAME_INFO) +layout (set = 0, binding = FSR3UPSCALER_BIND_UAV_FRAME_INFO, rgba32f) uniform image2D rw_frame_info; + +FfxFloat32x4 LoadFrameInfo() +{ + return imageLoad(rw_frame_info, ivec2(0, 0)); +} + +void StoreFrameInfo(FfxFloat32x4 fInfo) +{ + imageStore(rw_frame_info, ivec2(0, 0), fInfo); +} +#endif + +#if defined(FSR3UPSCALER_BIND_SRV_FRAME_INFO) +layout(set = 0, binding = FSR3UPSCALER_BIND_SRV_FRAME_INFO) uniform texture2D r_frame_info; + +FfxFloat32x4 FrameInfo() +{ + return texelFetch(r_frame_info, ivec2(0, 0), 0); +} +#endif + +#if defined(FSR3UPSCALER_BIND_UAV_SPD_MIPS_LEVEL_0) && \ + defined(FSR3UPSCALER_BIND_UAV_SPD_MIPS_LEVEL_1) && \ + defined(FSR3UPSCALER_BIND_UAV_SPD_MIPS_LEVEL_2) && \ + defined(FSR3UPSCALER_BIND_UAV_SPD_MIPS_LEVEL_3) && \ + defined(FSR3UPSCALER_BIND_UAV_SPD_MIPS_LEVEL_4) && \ + defined(FSR3UPSCALER_BIND_UAV_SPD_MIPS_LEVEL_5) + +layout (set = 0, binding = FSR3UPSCALER_BIND_UAV_SPD_MIPS_LEVEL_0, rg16f) uniform image2D rw_spd_mip0; +layout (set = 0, binding = FSR3UPSCALER_BIND_UAV_SPD_MIPS_LEVEL_1, rg16f) uniform image2D rw_spd_mip1; +layout (set = 0, binding = FSR3UPSCALER_BIND_UAV_SPD_MIPS_LEVEL_2, rg16f) uniform image2D rw_spd_mip2; +layout (set = 0, binding = FSR3UPSCALER_BIND_UAV_SPD_MIPS_LEVEL_3, rg16f) uniform image2D rw_spd_mip3; +layout (set = 0, binding = FSR3UPSCALER_BIND_UAV_SPD_MIPS_LEVEL_4, rg16f) uniform image2D rw_spd_mip4; +layout (set = 0, binding = FSR3UPSCALER_BIND_UAV_SPD_MIPS_LEVEL_5, rg16f) coherent uniform image2D rw_spd_mip5; + +FfxFloat32x2 RWLoadPyramid(FFX_PARAMETER_IN FfxInt32x2 iPxPos, FFX_PARAMETER_IN FfxUInt32 index) +{ +#define LOAD(idx) \ + if (index == idx) \ + { \ + return imageLoad(rw_spd_mip##idx, iPxPos).xy; \ + } + LOAD(0); + LOAD(1); + LOAD(2); + LOAD(3); + LOAD(4); + LOAD(5); + + return FfxFloat32x2(0.0, 0.0); + +#undef LOAD +} + +void StorePyramid(FFX_PARAMETER_IN FfxInt32x2 iPxPos, FFX_PARAMETER_IN FfxFloat32x2 outValue, FFX_PARAMETER_IN FfxUInt32 index) +{ +#define STORE(idx) \ + if (index == idx) \ + { \ + imageStore(rw_spd_mip##idx, iPxPos, vec4(outValue, 0.0, 0.0)); \ + } + + STORE(0); + STORE(1); + STORE(2); + STORE(3); + STORE(4); + STORE(5); + +#undef STORE +} +#endif + +#if defined FSR3UPSCALER_BIND_UAV_SPD_GLOBAL_ATOMIC +layout (set = 0, binding = FSR3UPSCALER_BIND_UAV_SPD_GLOBAL_ATOMIC, r32ui) coherent uniform uimage2D rw_spd_global_atomic; + +void SPD_IncreaseAtomicCounter(inout FfxUInt32 spdCounter) +{ + spdCounter = imageAtomicAdd(rw_spd_global_atomic, ivec2(0, 0), 1); +} + +void SPD_ResetAtomicCounter() +{ + imageStore(rw_spd_global_atomic, ivec2(0, 0), uvec4(0)); +} +#endif + +#endif // #if defined(FFX_GPU) diff --git a/externals/FidelityFX-SDK/include/FidelityFX/gpu/fsr3upscaler/ffx_fsr3upscaler_common.h b/externals/FidelityFX-SDK/include/FidelityFX/gpu/fsr3upscaler/ffx_fsr3upscaler_common.h new file mode 100644 index 0000000000..87aa596db4 --- /dev/null +++ b/externals/FidelityFX-SDK/include/FidelityFX/gpu/fsr3upscaler/ffx_fsr3upscaler_common.h @@ -0,0 +1,403 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and /or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#if !defined(FFX_FSR3UPSCALER_COMMON_H) +#define FFX_FSR3UPSCALER_COMMON_H + +#if defined(FFX_GPU) +#pragma warning(error : 3206) // treat vector truncation warnings as errors +#pragma warning(disable : 3205) // conversion from larger type to smaller +#pragma warning(disable : 3571) // in ffxPow(f, e), f could be negative + +FFX_STATIC const FfxFloat32 FSR3UPSCALER_FP16_MIN = 6.10e-05f; +FFX_STATIC const FfxFloat32 FSR3UPSCALER_FP16_MAX = 65504.0f; +FFX_STATIC const FfxFloat32 FSR3UPSCALER_EPSILON = FSR3UPSCALER_FP16_MIN; +FFX_STATIC const FfxFloat32 FSR3UPSCALER_TONEMAP_EPSILON = FSR3UPSCALER_FP16_MIN; +FFX_STATIC const FfxFloat32 FSR3UPSCALER_FP32_MAX = 3.402823466e+38f; +FFX_STATIC const FfxFloat32 FSR3UPSCALER_FP32_MIN = 1.175494351e-38f; + +// Reconstructed depth usage +FFX_STATIC const FfxFloat32 fReconstructedDepthBilinearWeightThreshold = FSR3UPSCALER_EPSILON * 10; + +FfxFloat32 ReconstructedDepthMvPxThreshold(FfxFloat32 fNearestDepthInMeters) +{ + return ffxLerp(0.25f, 0.75f, ffxSaturate(fNearestDepthInMeters / 100.0f)); +} + +// Accumulation +FFX_STATIC const FfxFloat32 fUpsampleLanczosWeightScale = 1.0f / 16.0f; +FFX_STATIC const FfxFloat32 fAverageLanczosWeightPerFrame = 0.74f * fUpsampleLanczosWeightScale; // Average lanczos weight for jitter accumulated samples +FFX_STATIC const FfxFloat32 fAccumulationMaxOnMotion = 3.0f * fUpsampleLanczosWeightScale; + +#define SHADING_CHANGE_SET_SIZE 5 +FFX_STATIC const FfxInt32 iShadingChangeMipStart = 0; +FFX_STATIC const FfxFloat32 fShadingChangeSamplePow = 1.0f / 1.0f; + + +FFX_STATIC const FfxFloat32 fLockThreshold = 1.0f; +FFX_STATIC const FfxFloat32 fLockMax = 2.0f; + +FFX_STATIC const FfxInt32 REACTIVE = 0; +FFX_STATIC const FfxInt32 DISOCCLUSION = 1; +FFX_STATIC const FfxInt32 SHADING_CHANGE = 2; +FFX_STATIC const FfxInt32 ACCUMULAION = 3; + +FFX_STATIC const FfxInt32 FRAME_INFO_EXPOSURE = 0; +FFX_STATIC const FfxInt32 FRAME_INFO_LOG_LUMA = 1; +FFX_STATIC const FfxInt32 FRAME_INFO_SCENE_AVERAGE_LUMA = 2; + +FfxBoolean TonemapFirstFrame() +{ + const FfxBoolean bEnabled = true; + return FrameIndex() == 0 && bEnabled; +} + +FfxFloat32 AverageLanczosWeightPerFrame() +{ + return 0.74f; +} + +FfxInt32x2 ShadingChangeRenderSize() +{ + return FfxInt32x2(RenderSize() * 0.5f); +} + +FfxInt32x2 ShadingChangeMaxRenderSize() +{ + return FfxInt32x2(MaxRenderSize() * 0.5f); +} + +FfxInt32x2 PreviousFrameShadingChangeRenderSize() +{ + return FfxInt32x2(PreviousFrameRenderSize() * 0.5f); +} + +#if defined(FSR3UPSCALER_BIND_SRV_FRAME_INFO) +FfxFloat32 SceneAverageLuma() +{ + return FrameInfo()[FRAME_INFO_SCENE_AVERAGE_LUMA]; +} +#endif + +// Auto exposure +FFX_STATIC const FfxFloat32 resetAutoExposureAverageSmoothing = 1e4f; + +struct AccumulationPassCommonParams +{ + FfxInt32x2 iPxHrPos; + FfxFloat32x2 fHrUv; + FfxFloat32x2 fLrUvJittered; + FfxFloat32x2 fLrUv_HwSampler; + FfxFloat32x2 fMotionVector; + FfxFloat32x2 fReprojectedHrUv; + FfxFloat32 f4KVelocity; + FfxFloat32 fDisocclusion; + FfxFloat32 fReactiveMask; + FfxFloat32 fShadingChange; + FfxFloat32 fAccumulation; + FfxFloat32 fLumaInstabilityFactor; + FfxFloat32 fFarthestDepthInMeters; + + FfxBoolean bIsExistingSample; + FfxBoolean bIsNewSample; +}; + +FfxFloat32 Get4KVelocity(FfxFloat32x2 fMotionVector) +{ + return length(fMotionVector * FfxFloat32x2(3840.0f, 2160.0f)); +} + +struct RectificationBox +{ + FfxFloat32x3 boxCenter; + FfxFloat32x3 boxVec; + FfxFloat32x3 aabbMin; + FfxFloat32x3 aabbMax; + FfxFloat32 fBoxCenterWeight; +}; + +struct AccumulationPassData +{ + RectificationBox clippingBox; + FfxFloat32x3 fUpsampledColor; + FfxFloat32 fUpsampledWeight; + FfxFloat32x3 fHistoryColor; + FfxFloat32 fHistoryWeight; + FfxFloat32 fLock; + FfxFloat32 fLockContributionThisFrame; +}; + +void RectificationBoxAddInitialSample(FFX_PARAMETER_INOUT RectificationBox rectificationBox, const FfxFloat32x3 colorSample, const FfxFloat32 fSampleWeight) +{ + rectificationBox.aabbMin = colorSample; + rectificationBox.aabbMax = colorSample; + + FfxFloat32x3 weightedSample = colorSample * fSampleWeight; + rectificationBox.boxCenter = weightedSample; + rectificationBox.boxVec = colorSample * weightedSample; + rectificationBox.fBoxCenterWeight = fSampleWeight; +} + +void RectificationBoxAddSample(FfxBoolean bInitialSample, FFX_PARAMETER_INOUT RectificationBox rectificationBox, const FfxFloat32x3 colorSample, const FfxFloat32 fSampleWeight) +{ + if (bInitialSample) { + RectificationBoxAddInitialSample(rectificationBox, colorSample, fSampleWeight); + } else { + rectificationBox.aabbMin = ffxMin(rectificationBox.aabbMin, colorSample); + rectificationBox.aabbMax = ffxMax(rectificationBox.aabbMax, colorSample); + + FfxFloat32x3 weightedSample = colorSample * fSampleWeight; + rectificationBox.boxCenter += weightedSample; + rectificationBox.boxVec += colorSample * weightedSample; + rectificationBox.fBoxCenterWeight += fSampleWeight; + } +} + +void RectificationBoxComputeVarianceBoxData(FFX_PARAMETER_INOUT RectificationBox rectificationBox) +{ + rectificationBox.fBoxCenterWeight = (abs(rectificationBox.fBoxCenterWeight) > FfxFloat32(FSR3UPSCALER_FP32_MIN) ? rectificationBox.fBoxCenterWeight : FfxFloat32(1.f)); + rectificationBox.boxCenter /= rectificationBox.fBoxCenterWeight; + rectificationBox.boxVec /= rectificationBox.fBoxCenterWeight; + FfxFloat32x3 stdDev = sqrt(abs(rectificationBox.boxVec - rectificationBox.boxCenter * rectificationBox.boxCenter)); + rectificationBox.boxVec = stdDev; +} + +FfxFloat32x3 SafeRcp3(FfxFloat32x3 v) +{ + return (all(FFX_NOT_EQUAL(v, FfxFloat32x3(0, 0, 0)))) ? (FfxFloat32x3(1, 1, 1) / v) : FfxFloat32x3(0, 0, 0); +} + +FfxFloat32 MinDividedByMax(const FfxFloat32 v0, const FfxFloat32 v1, const FfxFloat32 fOnZeroReturnValue) +{ + const FfxFloat32 m = ffxMax(v0, v1); + return m != 0 ? ffxMin(v0, v1) / m : fOnZeroReturnValue; +} + +FfxFloat32 MinDividedByMax(const FfxFloat32 v0, const FfxFloat32 v1) +{ + const FfxFloat32 m = ffxMax(v0, v1); + return m != 0 ? ffxMin(v0, v1) / m : 0; +} + +FfxFloat32x3 YCoCgToRGB(FfxFloat32x3 fYCoCg) +{ + FfxFloat32x3 fRgb; + + fRgb = FfxFloat32x3( + fYCoCg.x + fYCoCg.y - fYCoCg.z, + fYCoCg.x + fYCoCg.z, + fYCoCg.x - fYCoCg.y - fYCoCg.z); + + return fRgb; +} + +FfxFloat32x3 RGBToYCoCg(FfxFloat32x3 fRgb) +{ + FfxFloat32x3 fYCoCg; + + fYCoCg = FfxFloat32x3( + 0.25f * fRgb.r + 0.5f * fRgb.g + 0.25f * fRgb.b, + 0.5f * fRgb.r - 0.5f * fRgb.b, + -0.25f * fRgb.r + 0.5f * fRgb.g - 0.25f * fRgb.b); + + return fYCoCg; +} + +FfxFloat32 RGBToLuma(FfxFloat32x3 fLinearRgb) +{ + return dot(fLinearRgb, FfxFloat32x3(0.2126f, 0.7152f, 0.0722f)); +} + +FfxFloat32 RGBToPerceivedLuma(FfxFloat32x3 fLinearRgb) +{ + FfxFloat32 fLuminance = RGBToLuma(fLinearRgb); + + FfxFloat32 fPercievedLuminance = 0; + if (fLuminance <= 216.0f / 24389.0f) { + fPercievedLuminance = fLuminance * (24389.0f / 27.0f); + } + else { + fPercievedLuminance = ffxPow(fLuminance, 1.0f / 3.0f) * 116.0f - 16.0f; + } + + return fPercievedLuminance * 0.01f; +} + +FfxFloat32x3 Tonemap(FfxFloat32x3 fRgb) +{ + return fRgb / (ffxMax(ffxMax(0.f, fRgb.r), ffxMax(fRgb.g, fRgb.b)) + 1.f).xxx; +} + +FfxFloat32x3 InverseTonemap(FfxFloat32x3 fRgb) +{ + return fRgb / ffxMax(FSR3UPSCALER_TONEMAP_EPSILON, 1.f - ffxMax(fRgb.r, ffxMax(fRgb.g, fRgb.b))).xxx; +} + +FfxBoolean IsUvInside(FfxFloat32x2 fUv) +{ + return (fUv.x >= 0.0f && fUv.x <= 1.0f) && (fUv.y >= 0.0f && fUv.y <= 1.0f); +} + +FfxInt32x2 ClampLoad(FfxInt32x2 iPxSample, FfxInt32x2 iPxOffset, FfxInt32x2 iTextureSize) +{ + FfxInt32x2 result = iPxSample + iPxOffset; + result.x = ffxMax(0, ffxMin(result.x, iTextureSize.x - 1)); + result.y = ffxMax(0, ffxMin(result.y, iTextureSize.y - 1)); + return result; +} + +FfxFloat32x2 ClampUv(FfxFloat32x2 fUv, FfxInt32x2 iTextureSize, FfxInt32x2 iResourceSize) +{ + const FfxFloat32x2 fSampleLocation = fUv * iTextureSize; + const FfxFloat32x2 fClampedLocation = ffxMax(FfxFloat32x2(0.5f, 0.5f), ffxMin(fSampleLocation, FfxFloat32x2(iTextureSize) - FfxFloat32x2(0.5f, 0.5f))); + const FfxFloat32x2 fClampedUv = fClampedLocation / FfxFloat32x2(iResourceSize); + + return fClampedUv; +} + +FfxBoolean IsOnScreen(FfxInt32x2 pos, FfxInt32x2 size) +{ + return all(FFX_LESS_THAN(FfxUInt32x2(pos), FfxUInt32x2(size))); +} + +FfxFloat32 ComputeAutoExposureFromLavg(FfxFloat32 Lavg) +{ + Lavg = exp(Lavg); + + const FfxFloat32 S = 100.0f; //ISO arithmetic speed + const FfxFloat32 K = 12.5f; + FfxFloat32 ExposureISO100 = log2((Lavg * S) / K); + + const FfxFloat32 q = 0.65f; + FfxFloat32 Lmax = (78.0f / (q * S)) * ffxPow(2.0f, ExposureISO100); + + return 1.0f / Lmax; +} + +FfxInt32x2 ComputeHrPosFromLrPos(FfxInt32x2 iPxLrPos) +{ + FfxFloat32x2 fSrcJitteredPos = FfxFloat32x2(iPxLrPos) + 0.5f - Jitter(); + FfxFloat32x2 fLrPosInHr = (fSrcJitteredPos / RenderSize()) * UpscaleSize(); + FfxInt32x2 iPxHrPos = FfxInt32x2(floor(fLrPosInHr)); + return iPxHrPos; +} + +FfxFloat32x2 ComputeNdc(FfxFloat32x2 fPxPos, FfxInt32x2 iSize) +{ + return fPxPos / FfxFloat32x2(iSize) * FfxFloat32x2(2.0f, -2.0f) + FfxFloat32x2(-1.0f, 1.0f); +} + +FfxFloat32 GetViewSpaceDepth(FfxFloat32 fDeviceDepth) +{ + const FfxFloat32x4 fDeviceToViewDepth = DeviceToViewSpaceTransformFactors(); + + // fDeviceToViewDepth details found in ffx_fsr3upscaler.cpp + return (fDeviceToViewDepth[1] / (fDeviceDepth - fDeviceToViewDepth[0])); +} + +FfxFloat32 GetViewSpaceDepthInMeters(FfxFloat32 fDeviceDepth) +{ + return GetViewSpaceDepth(fDeviceDepth) * ViewSpaceToMetersFactor(); +} + +FfxFloat32x3 GetViewSpacePosition(FfxInt32x2 iViewportPos, FfxInt32x2 iViewportSize, FfxFloat32 fDeviceDepth) +{ + const FfxFloat32x4 fDeviceToViewDepth = DeviceToViewSpaceTransformFactors(); + + const FfxFloat32 Z = GetViewSpaceDepth(fDeviceDepth); + + const FfxFloat32x2 fNdcPos = ComputeNdc(iViewportPos, iViewportSize); + const FfxFloat32 X = fDeviceToViewDepth[2] * fNdcPos.x * Z; + const FfxFloat32 Y = fDeviceToViewDepth[3] * fNdcPos.y * Z; + + return FfxFloat32x3(X, Y, Z); +} + +FfxFloat32x3 GetViewSpacePositionInMeters(FfxInt32x2 iViewportPos, FfxInt32x2 iViewportSize, FfxFloat32 fDeviceDepth) +{ + return GetViewSpacePosition(iViewportPos, iViewportSize, fDeviceDepth) * ViewSpaceToMetersFactor(); +} + +FfxFloat32 GetMaxDistanceInMeters() +{ +#if FFX_FSR3UPSCALER_OPTION_INVERTED_DEPTH + return GetViewSpaceDepth(0.0f) * ViewSpaceToMetersFactor(); +#else + return GetViewSpaceDepth(1.0f) * ViewSpaceToMetersFactor(); +#endif +} + + +struct BilinearSamplingData +{ + FfxInt32x2 iOffsets[4]; + FfxFloat32 fWeights[4]; + FfxInt32x2 iBasePos; +}; + +BilinearSamplingData GetBilinearSamplingData(FfxFloat32x2 fUv, FfxInt32x2 iSize) +{ + BilinearSamplingData data; + + FfxFloat32x2 fPxSample = (fUv * iSize) - FfxFloat32x2(0.5f, 0.5f); + data.iBasePos = FfxInt32x2(floor(fPxSample)); + FfxFloat32x2 fPxFrac = ffxFract(fPxSample); + + data.iOffsets[0] = FfxInt32x2(0, 0); + data.iOffsets[1] = FfxInt32x2(1, 0); + data.iOffsets[2] = FfxInt32x2(0, 1); + data.iOffsets[3] = FfxInt32x2(1, 1); + + data.fWeights[0] = (1 - fPxFrac.x) * (1 - fPxFrac.y); + data.fWeights[1] = (fPxFrac.x) * (1 - fPxFrac.y); + data.fWeights[2] = (1 - fPxFrac.x) * (fPxFrac.y); + data.fWeights[3] = (fPxFrac.x) * (fPxFrac.y); + + return data; +} + +struct PlaneData +{ + FfxFloat32x3 fNormal; + FfxFloat32 fDistanceFromOrigin; +}; + +PlaneData GetPlaneFromPoints(FfxFloat32x3 fP0, FfxFloat32x3 fP1, FfxFloat32x3 fP2) +{ + PlaneData plane; + + FfxFloat32x3 v0 = fP0 - fP1; + FfxFloat32x3 v1 = fP0 - fP2; + plane.fNormal = normalize(cross(v0, v1)); + plane.fDistanceFromOrigin = -dot(fP0, plane.fNormal); + + return plane; +} + +FfxFloat32 PointToPlaneDistance(PlaneData plane, FfxFloat32x3 fPoint) +{ + return abs(dot(plane.fNormal, fPoint) + plane.fDistanceFromOrigin); +} + +#endif // #if defined(FFX_GPU) + +#endif //!defined(FFX_FSR3UPSCALER_COMMON_H) diff --git a/externals/FidelityFX-SDK/include/FidelityFX/gpu/fsr3upscaler/ffx_fsr3upscaler_luma_instability.h b/externals/FidelityFX-SDK/include/FidelityFX/gpu/fsr3upscaler/ffx_fsr3upscaler_luma_instability.h new file mode 100644 index 0000000000..624b7ca941 --- /dev/null +++ b/externals/FidelityFX-SDK/include/FidelityFX/gpu/fsr3upscaler/ffx_fsr3upscaler_luma_instability.h @@ -0,0 +1,115 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and /or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +struct LumaInstabilityFactorData +{ + FfxFloat32x4 fLumaHistory; + FfxFloat32 fLumaInstabilityFactor; +}; + +LumaInstabilityFactorData ComputeLumaInstabilityFactor(LumaInstabilityFactorData data, FfxFloat32 fCurrentFrameLuma, FfxFloat32 fFarthestDepthInMeters) +{ + const FfxInt32 N_MINUS_1 = 0; + const FfxInt32 N_MINUS_2 = 1; + const FfxInt32 N_MINUS_3 = 2; + const FfxInt32 N_MINUS_4 = 3; + + FfxFloat32 fLumaInstability = 0.0f; + const FfxFloat32 fDiffs0 = (fCurrentFrameLuma - data.fLumaHistory[N_MINUS_1]); + const FfxFloat32 fSimilarity0 = MinDividedByMax(fCurrentFrameLuma, data.fLumaHistory[N_MINUS_1], 1.0f); + + FfxFloat32 fMaxSimilarity = fSimilarity0; + + if (fSimilarity0 < 1.0f) { + for (int i = N_MINUS_2; i <= N_MINUS_4; i++) { + const FfxFloat32 fDiffs1 = (fCurrentFrameLuma - data.fLumaHistory[i]); + const FfxFloat32 fSimilarity1 = MinDividedByMax(fCurrentFrameLuma, data.fLumaHistory[i]); + + if (sign(fDiffs0) == sign(fDiffs1)) { + + fMaxSimilarity = ffxMax(fMaxSimilarity, fSimilarity1); + } + } + + fLumaInstability = FfxFloat32(fMaxSimilarity > fSimilarity0); + } + + // Shift history + data.fLumaHistory[N_MINUS_4] = data.fLumaHistory[N_MINUS_3]; + data.fLumaHistory[N_MINUS_3] = data.fLumaHistory[N_MINUS_2]; + data.fLumaHistory[N_MINUS_2] = data.fLumaHistory[N_MINUS_1]; + data.fLumaHistory[N_MINUS_1] = fCurrentFrameLuma; + + data.fLumaHistory /= Exposure(); + + data.fLumaInstabilityFactor = fLumaInstability * FfxFloat32(data.fLumaHistory[N_MINUS_4] != 0); + + return data; +} + +void LumaInstability(FfxInt32x2 iPxPos) +{ + LumaInstabilityFactorData data; + data.fLumaInstabilityFactor = 0.0f; + data.fLumaHistory = FfxFloat32x4(0.0f, 0.0f, 0.0f, 0.0f); + + const FfxFloat32x2 fDilatedMotionVector = LoadDilatedMotionVector(iPxPos); + const FfxFloat32x2 fUv = (iPxPos + 0.5f) / RenderSize(); + const FfxFloat32x2 fUvCurrFrameJittered = fUv + Jitter() / RenderSize(); + const FfxFloat32x2 fUvPrevFrameJittered = fUv + PreviousFrameJitter() / PreviousFrameRenderSize(); + const FfxFloat32x2 fReprojectedUv = fUvPrevFrameJittered + fDilatedMotionVector; + + if (IsUvInside(fReprojectedUv)) + { + const FfxFloat32x2 fUvReactive_HW = ClampUv(fUvCurrFrameJittered, RenderSize(), MaxRenderSize()); + + const FfxFloat32x4 fDilatedReactiveMasks = SampleDilatedReactiveMasks(fUvReactive_HW); + const FfxFloat32 fReactiveMask = ffxSaturate(fDilatedReactiveMasks[REACTIVE]); + const FfxFloat32 fDisocclusion = ffxSaturate(fDilatedReactiveMasks[DISOCCLUSION]); + const FfxFloat32 fShadingChange = ffxSaturate(fDilatedReactiveMasks[SHADING_CHANGE]); + const FfxFloat32 fAccumulation = ffxSaturate(fDilatedReactiveMasks[ACCUMULAION]); + + const FfxBoolean bAccumulationFactor = fAccumulation > 0.9f; + + const FfxBoolean bComputeInstability = bAccumulationFactor; + + if (bComputeInstability) { + + const FfxFloat32x2 fUv_HW = ClampUv(fUvCurrFrameJittered, RenderSize(), MaxRenderSize()); + const FfxFloat32 fCurrentFrameLuma = SampleCurrentLuma(fUv_HW) * Exposure(); + + const FfxFloat32x2 fReprojectedUv_HW = ClampUv(fReprojectedUv, PreviousFrameRenderSize(), MaxRenderSize()); + data.fLumaHistory = SampleLumaHistory(fReprojectedUv_HW) * DeltaPreExposure() * Exposure(); + + const FfxFloat32x2 fFarthestDepthUv_HW = ClampUv(fUvCurrFrameJittered, RenderSize() / 2, GetFarthestDepthMip1ResourceDimensions()); + const FfxFloat32 fFarthestDepthInMeters = SampleFarthestDepthMip1(fFarthestDepthUv_HW); + + data = ComputeLumaInstabilityFactor(data, fCurrentFrameLuma, fFarthestDepthInMeters); + + const FfxFloat32 fVelocityWeight = 1.0f - ffxSaturate(Get4KVelocity(fDilatedMotionVector) / 20.0f); + data.fLumaInstabilityFactor *= fVelocityWeight * (1.0f - fDisocclusion) * (1.0f - fReactiveMask) * (1.0f - fShadingChange); + } + } + + StoreLumaHistory(iPxPos, data.fLumaHistory); + StoreLumaInstability(iPxPos, data.fLumaInstabilityFactor); +} diff --git a/externals/FidelityFX-SDK/include/FidelityFX/gpu/fsr3upscaler/ffx_fsr3upscaler_luma_pyramid.h b/externals/FidelityFX-SDK/include/FidelityFX/gpu/fsr3upscaler/ffx_fsr3upscaler_luma_pyramid.h new file mode 100644 index 0000000000..41c5dc7f45 --- /dev/null +++ b/externals/FidelityFX-SDK/include/FidelityFX/gpu/fsr3upscaler/ffx_fsr3upscaler_luma_pyramid.h @@ -0,0 +1,192 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and /or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +FFX_GROUPSHARED FfxUInt32 spdCounter; + +void SpdIncreaseAtomicCounter(FfxUInt32 slice) +{ + SPD_IncreaseAtomicCounter(spdCounter); +} + +FfxUInt32 SpdGetAtomicCounter() +{ + return spdCounter; +} + +void SpdResetAtomicCounter(FfxUInt32 slice) +{ + SPD_ResetAtomicCounter(); +} + +#ifndef SPD_PACKED_ONLY +FFX_GROUPSHARED FfxFloat32 spdIntermediateR[16][16]; +FFX_GROUPSHARED FfxFloat32 spdIntermediateG[16][16]; +FFX_GROUPSHARED FfxFloat32 spdIntermediateB[16][16]; +FFX_GROUPSHARED FfxFloat32 spdIntermediateA[16][16]; + +FFX_STATIC const FfxInt32 LOG_LUMA = 0; +FFX_STATIC const FfxInt32 LUMA = 1; +FFX_STATIC const FfxInt32 DEPTH_IN_METERS = 2; + +FfxFloat32x4 SpdLoadSourceImage(FfxFloat32x2 iPxPos, FfxUInt32 slice) +{ + //We assume linear data. if non-linear input (sRGB, ...), + //then we should convert to linear first and back to sRGB on output. + const FfxInt32x2 iPxSamplePos = ClampLoad(FfxInt32x2(iPxPos), FfxInt32x2(0, 0), FfxInt32x2(RenderSize())); + + const FfxFloat32 fLuma = LoadCurrentLuma(iPxSamplePos); + const FfxFloat32 fLogLuma = ffxMax(FSR3UPSCALER_EPSILON, log(fLuma)); + const FfxFloat32 fFarthestDepthInMeters = LoadFarthestDepth(iPxSamplePos); + + FfxFloat32x4 fOutput = FfxFloat32x4(0.0f, 0.0f, 0.0f, 0.0f); + fOutput[LOG_LUMA] = fLogLuma; + fOutput[LUMA] = fLuma; + fOutput[DEPTH_IN_METERS] = fFarthestDepthInMeters; + + return fOutput; +} + +FfxFloat32x4 SpdLoad(FfxInt32x2 tex, FfxUInt32 slice) +{ + return FfxFloat32x4(RWLoadPyramid(tex, 5), 0, 0); +} + +FfxFloat32x4 SpdReduce4(FfxFloat32x4 v0, FfxFloat32x4 v1, FfxFloat32x4 v2, FfxFloat32x4 v3) +{ + return (v0 + v1 + v2 + v3) * 0.25f; +} + +void SpdStore(FfxInt32x2 pix, FfxFloat32x4 outValue, FfxUInt32 index, FfxUInt32 slice) +{ + if (index == 5) + { + StorePyramid(pix, outValue.xy, index); + } + else if (index == 0) { + StoreFarthestDepthMip1(pix, outValue[DEPTH_IN_METERS]); + } + + if (index == MipCount() - 1) { //accumulate on 1x1 level + + if (all(FFX_EQUAL(pix, FfxInt32x2(0, 0)))) + { + FfxFloat32x4 frameInfo = LoadFrameInfo(); + const FfxFloat32 fSceneAvgLuma = outValue[LUMA]; + const FfxFloat32 fPrevLogLuma = frameInfo[FRAME_INFO_LOG_LUMA]; + FfxFloat32 fLogLuma = outValue[LOG_LUMA]; + + if (fPrevLogLuma < resetAutoExposureAverageSmoothing) // Compare Lavg, so small or negative values + { + fLogLuma = fPrevLogLuma + (fLogLuma - fPrevLogLuma) * (1.0f - exp(-DeltaTime())); + fLogLuma = ffxMax(0.0f, fLogLuma); + } + + frameInfo[FRAME_INFO_EXPOSURE] = ComputeAutoExposureFromLavg(fLogLuma); + frameInfo[FRAME_INFO_LOG_LUMA] = fLogLuma; + frameInfo[FRAME_INFO_SCENE_AVERAGE_LUMA] = fSceneAvgLuma; + + StoreFrameInfo(frameInfo); + } + } +} + +FfxFloat32x4 SpdLoadIntermediate(FfxUInt32 x, FfxUInt32 y) +{ + return FfxFloat32x4( + spdIntermediateR[x][y], + spdIntermediateG[x][y], + spdIntermediateB[x][y], + spdIntermediateA[x][y]); +} +void SpdStoreIntermediate(FfxUInt32 x, FfxUInt32 y, FfxFloat32x4 value) +{ + spdIntermediateR[x][y] = value.x; + spdIntermediateG[x][y] = value.y; + spdIntermediateB[x][y] = value.z; + spdIntermediateA[x][y] = value.w; +} + +#endif + +// define fetch and store functions Packed +#if FFX_HALF + +FFX_GROUPSHARED FfxFloat16x2 spdIntermediateRG[16][16]; +FFX_GROUPSHARED FfxFloat16x2 spdIntermediateBA[16][16]; + +FfxFloat16x4 SpdLoadSourceImageH(FfxFloat32x2 tex, FfxUInt32 slice) +{ + return FfxFloat16x4(0, 0, 0, 0); +} + +FfxFloat16x4 SpdLoadH(FfxInt32x2 p, FfxUInt32 slice) +{ + return FfxFloat16x4(0, 0, 0, 0); +} + +void SpdStoreH(FfxInt32x2 p, FfxFloat16x4 value, FfxUInt32 mip, FfxUInt32 slice) +{ +} + +FfxFloat16x4 SpdLoadIntermediateH(FfxUInt32 x, FfxUInt32 y) +{ + return FfxFloat16x4( + spdIntermediateRG[x][y].x, + spdIntermediateRG[x][y].y, + spdIntermediateBA[x][y].x, + spdIntermediateBA[x][y].y); +} + +void SpdStoreIntermediateH(FfxUInt32 x, FfxUInt32 y, FfxFloat16x4 value) +{ + spdIntermediateRG[x][y] = value.xy; + spdIntermediateBA[x][y] = value.zw; +} + +FfxFloat16x4 SpdReduce4H(FfxFloat16x4 v0, FfxFloat16x4 v1, FfxFloat16x4 v2, FfxFloat16x4 v3) +{ + return (v0 + v1 + v2 + v3) * FfxFloat16(0.25); +} +#endif + +#include "spd/ffx_spd.h" + +void ComputeAutoExposure(FfxUInt32x3 WorkGroupId, FfxUInt32 LocalThreadIndex) +{ +#if FFX_HALF + SpdDownsampleH( + FfxUInt32x2(WorkGroupId.xy), + FfxUInt32(LocalThreadIndex), + FfxUInt32(MipCount()), + FfxUInt32(NumWorkGroups()), + FfxUInt32(WorkGroupId.z), + FfxUInt32x2(WorkGroupOffset())); +#else + SpdDownsample( + FfxUInt32x2(WorkGroupId.xy), + FfxUInt32(LocalThreadIndex), + FfxUInt32(MipCount()), + FfxUInt32(NumWorkGroups()), + FfxUInt32(WorkGroupId.z), + FfxUInt32x2(WorkGroupOffset())); +#endif +} diff --git a/externals/FidelityFX-SDK/include/FidelityFX/gpu/fsr3upscaler/ffx_fsr3upscaler_prepare_inputs.h b/externals/FidelityFX-SDK/include/FidelityFX/gpu/fsr3upscaler/ffx_fsr3upscaler_prepare_inputs.h new file mode 100644 index 0000000000..59c765b527 --- /dev/null +++ b/externals/FidelityFX-SDK/include/FidelityFX/gpu/fsr3upscaler/ffx_fsr3upscaler_prepare_inputs.h @@ -0,0 +1,152 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and /or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +void ReconstructPrevDepth(FfxInt32x2 iPxPos, FfxFloat32 fDepth, FfxFloat32x2 fMotionVector) +{ + const FfxFloat32 fNearestDepthInMeters = ffxMin(GetViewSpaceDepthInMeters(fDepth), FSR3UPSCALER_FP16_MAX); + const FfxFloat32 fReconstructedDeptMvThreshold = ReconstructedDepthMvPxThreshold(fNearestDepthInMeters); + + // Discard small mvs + fMotionVector *= FfxFloat32(Get4KVelocity(fMotionVector) > fReconstructedDeptMvThreshold); + + const FfxFloat32x2 fUv = (iPxPos + FfxFloat32(0.5)) / RenderSize(); + const FfxFloat32x2 fReprojectedUv = fUv + fMotionVector; + const BilinearSamplingData bilinearInfo = GetBilinearSamplingData(fReprojectedUv, RenderSize()); + + // Project current depth into previous frame locations. + // Push to all pixels having some contribution if reprojection is using bilinear logic. + for (FfxInt32 iSampleIndex = 0; iSampleIndex < 4; iSampleIndex++) { + + const FfxInt32x2 iOffset = bilinearInfo.iOffsets[iSampleIndex]; + const FfxFloat32 fWeight = bilinearInfo.fWeights[iSampleIndex]; + + if (fWeight > fReconstructedDepthBilinearWeightThreshold) { + + const FfxInt32x2 iStorePos = bilinearInfo.iBasePos + iOffset; + if (IsOnScreen(iStorePos, RenderSize())) { + StoreReconstructedDepth(iStorePos, fDepth); + } + } + } +} + +struct DepthExtents +{ + FfxFloat32 fNearest; + FfxInt32x2 fNearestCoord; + FfxFloat32 fFarthest; +}; + +DepthExtents FindDepthExtents(FFX_PARAMETER_IN FfxInt32x2 iPxPos) +{ + DepthExtents extents; + const FfxInt32 iSampleCount = 9; + const FfxInt32x2 iSampleOffsets[iSampleCount] = { + FfxInt32x2(+0, +0), + FfxInt32x2(+1, +0), + FfxInt32x2(+0, +1), + FfxInt32x2(+0, -1), + FfxInt32x2(-1, +0), + FfxInt32x2(-1, +1), + FfxInt32x2(+1, +1), + FfxInt32x2(-1, -1), + FfxInt32x2(+1, -1), + }; + + // pull out the depth loads to allow SC to batch them + FfxFloat32 depth[9]; + FfxInt32 iSampleIndex = 0; + FFX_UNROLL + for (iSampleIndex = 0; iSampleIndex < iSampleCount; ++iSampleIndex) { + + FfxInt32x2 iPos = iPxPos + iSampleOffsets[iSampleIndex]; + depth[iSampleIndex] = LoadInputDepth(iPos); + } + + // find closest depth + extents.fNearestCoord = iPxPos; + extents.fNearest = depth[0]; + extents.fFarthest = depth[0]; + FFX_UNROLL + for (iSampleIndex = 1; iSampleIndex < iSampleCount; ++iSampleIndex) { + + const FfxInt32x2 iPos = iPxPos + iSampleOffsets[iSampleIndex]; + if (IsOnScreen(iPos, RenderSize())) { + + FfxFloat32 fNdDepth = depth[iSampleIndex]; +#if FFX_FSR3UPSCALER_OPTION_INVERTED_DEPTH + if (fNdDepth > extents.fNearest) { + extents.fFarthest = ffxMin(extents.fFarthest, fNdDepth); +#else + if (fNdDepth < extents.fNearest) { + extents.fFarthest = ffxMax(extents.fFarthest, fNdDepth); +#endif + extents.fNearestCoord = iPos; + extents.fNearest = fNdDepth; + } + } + } + + return extents; +} + +FfxFloat32x2 DilateMotionVector(FfxInt32x2 iPxPos, const DepthExtents depthExtents) +{ +#if FFX_FSR3UPSCALER_OPTION_LOW_RESOLUTION_MOTION_VECTORS + const FfxInt32x2 iSamplePos = iPxPos; + const FfxInt32x2 iMotionVectorPos = depthExtents.fNearestCoord; +#else + const FfxInt32x2 iSamplePos = ComputeHrPosFromLrPos(iPxPos); + const FfxInt32x2 iMotionVectorPos = ComputeHrPosFromLrPos(depthExtents.fNearestCoord); +#endif + + const FfxFloat32x2 fDilatedMotionVector = LoadInputMotionVector(iMotionVectorPos); + + return fDilatedMotionVector; +} + +FfxFloat32 GetCurrentFrameLuma(FfxInt32x2 iPxPos) +{ + //We assume linear data. if non-linear input (sRGB, ...), + //then we should convert to linear first and back to sRGB on output. + const FfxFloat32x3 fRgb = ffxMax(FfxFloat32x3(0, 0, 0), LoadInputColor(iPxPos)); + const FfxFloat32 fLuma = RGBToLuma(fRgb); + + return fLuma; +} + +void PrepareInputs(FfxInt32x2 iPxPos) +{ + const DepthExtents depthExtents = FindDepthExtents(iPxPos); + const FfxFloat32x2 fDilatedMotionVector = DilateMotionVector(iPxPos, depthExtents); + + ReconstructPrevDepth(iPxPos, depthExtents.fNearest, fDilatedMotionVector); + + StoreDilatedMotionVector(iPxPos, fDilatedMotionVector); + StoreDilatedDepth(iPxPos, depthExtents.fNearest); + + const FfxFloat32 fFarthestDepthInMeters = ffxMin(GetViewSpaceDepthInMeters(depthExtents.fFarthest), FSR3UPSCALER_FP16_MAX); + StoreFarthestDepth(iPxPos, fFarthestDepthInMeters); + + const FfxFloat32 fLuma = GetCurrentFrameLuma(iPxPos); + StoreCurrentLuma(iPxPos, fLuma); +} diff --git a/externals/FidelityFX-SDK/include/FidelityFX/gpu/fsr3upscaler/ffx_fsr3upscaler_prepare_reactivity.h b/externals/FidelityFX-SDK/include/FidelityFX/gpu/fsr3upscaler/ffx_fsr3upscaler_prepare_reactivity.h new file mode 100644 index 0000000000..ae24545c80 --- /dev/null +++ b/externals/FidelityFX-SDK/include/FidelityFX/gpu/fsr3upscaler/ffx_fsr3upscaler_prepare_reactivity.h @@ -0,0 +1,283 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and /or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +FfxFloat32 ComputeDisocclusions(FfxFloat32x2 fUv, FfxFloat32x2 fMotionVector, FfxFloat32 fCurrentDepthViewSpace) +{ + const FfxFloat32 fNearestDepthInMeters = ffxMin(fCurrentDepthViewSpace * ViewSpaceToMetersFactor(), FSR3UPSCALER_FP16_MAX); + const FfxFloat32 fReconstructedDeptMvThreshold = ReconstructedDepthMvPxThreshold(fNearestDepthInMeters); + + fMotionVector *= FfxFloat32(Get4KVelocity(fMotionVector) > fReconstructedDeptMvThreshold); + + const FfxFloat32x2 fReprojectedUv = fUv + fMotionVector; + const BilinearSamplingData bilinearInfo = GetBilinearSamplingData(fReprojectedUv, RenderSize()); + + FfxFloat32 fDisocclusion = 0.0f; + FfxFloat32 fWeightSum = 0.0f; + FfxBoolean bPotentialDisocclusion = true; + + for (FfxInt32 iSampleIndex = 0; iSampleIndex < 4 && bPotentialDisocclusion; iSampleIndex++) + { + + const FfxInt32x2 iOffset = bilinearInfo.iOffsets[iSampleIndex]; + const FfxInt32x2 iSamplePos = ClampLoad(bilinearInfo.iBasePos, iOffset, FfxInt32x2(RenderSize())); + + if (IsOnScreen(iSamplePos, RenderSize())) { + const FfxFloat32 fWeight = bilinearInfo.fWeights[iSampleIndex]; + if (fWeight > fReconstructedDepthBilinearWeightThreshold) { + + const FfxFloat32 fPrevNearestDepthViewSpace = GetViewSpaceDepth(LoadReconstructedPrevDepth(iSamplePos)); + const FfxFloat32 fDepthDifference = fCurrentDepthViewSpace - fPrevNearestDepthViewSpace; + + bPotentialDisocclusion = bPotentialDisocclusion && (fDepthDifference > FSR3UPSCALER_FP32_MIN); + + if (bPotentialDisocclusion) { + const FfxFloat32 fHalfViewportWidth = length(FfxFloat32x2(RenderSize()) * 0.5f); + const FfxFloat32 fDepthThreshold = ffxMax(fCurrentDepthViewSpace, fPrevNearestDepthViewSpace); + + const FfxFloat32 Ksep = 1.37e-05f; + const FfxFloat32 fRequiredDepthSeparation = Ksep * fHalfViewportWidth * fDepthThreshold; + + fDisocclusion += ffxSaturate(FfxFloat32(fRequiredDepthSeparation / fDepthDifference)) * fWeight; + fWeightSum += fWeight; + } + } + } + } + + fDisocclusion = (bPotentialDisocclusion && fWeightSum > 0) ? ffxSaturate(1.0f - fDisocclusion / fWeightSum) : 0.0f; + + return fDisocclusion; +} + +FfxFloat32 ComputeMotionDivergence(FfxFloat32x2 fUv, FfxFloat32x2 fMotionVector, FfxFloat32 fCurrentDepthSample) +{ + const FfxInt32x2 iPxReprojectedPos = FfxInt32x2((fUv + fMotionVector) * RenderSize()); + const FfxFloat32 fReprojectedDepth = LoadDilatedDepth(iPxReprojectedPos); + const FfxFloat32x2 fReprojectedMotionVector = LoadDilatedMotionVector(iPxReprojectedPos); + + const FfxFloat32 fReprojectedVelocity = Get4KVelocity(fReprojectedMotionVector); + const FfxFloat32 f4KVelocity = Get4KVelocity(fMotionVector); + + const FfxFloat32 fMaxLen = max(length(fMotionVector), length(fReprojectedMotionVector)); + + const FfxFloat32 fNucleusDepthInMeters = GetViewSpaceDepthInMeters(fReprojectedDepth); + const FfxFloat32 fCurrentDepthInMeters = GetViewSpaceDepthInMeters(fCurrentDepthSample); + + const FfxFloat32 fDistanceFactor = MinDividedByMax(fNucleusDepthInMeters, fCurrentDepthInMeters); + const FfxFloat32 fVelocityFactor = ffxSaturate(f4KVelocity / 10.0f); + const FfxFloat32 fMotionVectorFieldConfidence = (1.0f - ffxSaturate(fReprojectedVelocity / f4KVelocity)) * fDistanceFactor * fVelocityFactor; + + return fMotionVectorFieldConfidence; +} + +FfxFloat32 DilateReactiveMasks(FfxInt32x2 iPxPos, FfxFloat32x2 fUv) +{ + FfxFloat32 fDilatedReactiveMasks = 0.0f; + + FFX_UNROLL + for (FfxInt32 y = -1; y <=1; y++) + { + FFX_UNROLL + for (FfxInt32 x = -1; x <= 1; x++) + { + const FfxInt32x2 sampleCoord = ClampLoad(iPxPos, FfxInt32x2(x, y), FfxInt32x2(RenderSize())); + fDilatedReactiveMasks = ffxMax(fDilatedReactiveMasks, LoadReactiveMask(sampleCoord)); + } + } + + return fDilatedReactiveMasks; +} + +FfxFloat32 DilateTransparencyAndCompositionMasks(FfxInt32x2 iPxPos, FfxFloat32x2 fUv) +{ + const FfxFloat32x2 fUvTransparencyAndCompositionMask = ClampUv(fUv, RenderSize(), GetTransparencyAndCompositionMaskResourceDimensions()); + return SampleTransparencyAndCompositionMask(fUvTransparencyAndCompositionMask); +} + +FfxFloat32 ComputeThinFeatureConfidence(FfxInt32x2 iPxPos) +{ + /* + 1 2 3 + 4 0 5 + 6 7 8 + */ + + const FfxInt32 iNucleusIndex = 0; + const FfxInt32 iSampleCount = 9; + const FfxInt32x2 iSampleOffsets[iSampleCount] = { + FfxInt32x2(+0, +0), + FfxInt32x2(-1, -1), + FfxInt32x2(+0, -1), + FfxInt32x2(+1, -1), + FfxInt32x2(-1, +0), + FfxInt32x2(+1, +0), + FfxInt32x2(-1, +1), + FfxInt32x2(+0, +1), + FfxInt32x2(+1, +1), + }; + + FfxFloat32 fSamples[iSampleCount]; + + FfxFloat32 fLumaMin = FSR3UPSCALER_FP32_MAX; + FfxFloat32 fLumaMax = FSR3UPSCALER_FP32_MIN; + + FFX_UNROLL + for (FfxInt32 iSampleIndex = 0; iSampleIndex < iSampleCount; ++iSampleIndex) { + const FfxInt32x2 iPxSamplePos = ClampLoad(iPxPos, iSampleOffsets[iSampleIndex], FfxInt32x2(RenderSize())); + fSamples[iSampleIndex] = LoadCurrentLuma(iPxSamplePos) * Exposure(); + + fLumaMin = ffxMin(fLumaMin, fSamples[iSampleIndex]); + fLumaMax = ffxMax(fLumaMax, fSamples[iSampleIndex]); + } + + const FfxFloat32 fThreshold = 0.9f; + FfxFloat32 fDissimilarLumaMin = FSR3UPSCALER_FP32_MAX; + FfxFloat32 fDissimilarLumaMax = 0; + +#define SETBIT(x) (1U << x) + + FfxUInt32 uPatternMask = SETBIT(iNucleusIndex); // Flag nucleus as similar + + const FfxUInt32 uNumRejectionMasks = 4; + const FfxUInt32 uRejectionMasks[uNumRejectionMasks] = { + SETBIT(1) | SETBIT(2) | SETBIT(4) | SETBIT(iNucleusIndex), // Upper left + SETBIT(2) | SETBIT(3) | SETBIT(5) | SETBIT(iNucleusIndex), // Upper right + SETBIT(4) | SETBIT(6) | SETBIT(7) | SETBIT(iNucleusIndex), // Lower left + SETBIT(5) | SETBIT(7) | SETBIT(8) | SETBIT(iNucleusIndex) // Lower right + }; + + FfxInt32 iBitIndex = 1; + FFX_UNROLL + for (FfxInt32 iSampleIndex = 1; iSampleIndex < iSampleCount; ++iSampleIndex, ++iBitIndex) { + + const FfxFloat32 fDifference = abs(fSamples[iSampleIndex] - fSamples[iNucleusIndex]) / (fLumaMax - fLumaMin); + + if (fDifference < fThreshold) + { + uPatternMask |= SETBIT(iBitIndex); + } + else + { + fDissimilarLumaMin = ffxMin(fDissimilarLumaMin, fSamples[iSampleIndex]); + fDissimilarLumaMax = ffxMax(fDissimilarLumaMax, fSamples[iSampleIndex]); + } + } + + const FfxBoolean bIsRidge = fSamples[iNucleusIndex] > fDissimilarLumaMax || fSamples[iNucleusIndex] < fDissimilarLumaMin; + + if (FFX_FALSE == bIsRidge) + { + return 0.0f; + } + + FFX_UNROLL + for (FfxInt32 i = 0; i < uNumRejectionMasks; i++) + { + if ((uPatternMask & uRejectionMasks[i]) == uRejectionMasks[i]) + { + return 0.0f; + } + } + + return 1.0f - fLumaMin / fLumaMax; +} + +FfxFloat32 UpdateAccumulation(FfxInt32x2 iPxPos, FfxFloat32x2 fUv, FfxFloat32x2 fMotionVector, FfxFloat32 fDisocclusion, FfxFloat32 fShadingChange) +{ + const FfxFloat32x2 fReprojectedUv = fUv + fMotionVector; + FfxFloat32 fAccumulation = 0.0f; + + if (IsUvInside(fReprojectedUv)) { + const FfxFloat32x2 fReprojectedUv_HW = ClampUv(fReprojectedUv, PreviousFrameRenderSize(), MaxRenderSize()); + fAccumulation = ffxSaturate(SampleAccumulation(fReprojectedUv_HW)); + } + const FfxFloat32 fAccumulationAddedPerFrame= AccumulationAddedPerFrame(); //default is 0.333 + + // Assume at frame N+0 fShadingChange is 1.0, and all subsequent frames fShadingChange is 0.0 and fDisocclusion is 0.0. Then, + // frame N+0 fAccumulation will be 0.000 + // frame N+2 fAccumulation will be 0.000 + 0.333 * 1 == 0.333 + // frame N+3 fAccumulation will be 0.000 + 0.333 * 2 == 0.666 + // frame N+4 fAccumulation will be 0.000 + 0.333 * 3 == 0.999 + fAccumulation = ffxLerp(fAccumulation, 0.0f, fShadingChange); + + const FfxFloat32 fMinDisocclusionAccumulation = MinDisocclusionAccumulation(); //default is -0.333 + // Assume at frame N+0 fDisocclusion is 1.0, and all subsequent frames fShadingChange is 0.0 and fDisocclusion is 0.0. Then, + // frame N+0 fAccumulation will be -0.333f (but normalized to store in unorm) + // frame N+1 fAccumulation will be -0.333f + 0.333 * 1 == 0.000 + // frame N+2 fAccumulation will be -0.333f + 0.333 * 2 == 0.333 + // frame N+3 fAccumulation will be -0.333f + 0.333 * 3 == 0.666 + // frame N+4 fAccumulation will be -0.333f + 0.333 * 4 == 0.999 + fAccumulation = ffxLerp(fAccumulation, ffxMin(fMinDisocclusionAccumulation, fAccumulation), fDisocclusion); + + fAccumulation *= FfxFloat32(round(fAccumulation * 100.0f) > 1.0f); + + // Update for next frame, normalize to store in unorm + const FfxFloat32 fAccumulatedFramesToStore = ffxSaturate(fAccumulation + fAccumulationAddedPerFrame); + StoreAccumulation(iPxPos, fAccumulatedFramesToStore); + + return fAccumulation; +} + +FfxFloat32 ComputeShadingChange(FfxFloat32x2 fUv) +{ + // NOTE: Here we re-apply jitter, will be reverted again when sampled in accumulation pass + const FfxFloat32x2 fShadingChangeUv = ClampUv(fUv - Jitter() / RenderSize(), ShadingChangeRenderSize(), ShadingChangeMaxRenderSize()); + const FfxFloat32 fShadingChange = ffxSaturate(SampleShadingChange(fShadingChangeUv)); + + return fShadingChange; +} + +void PrepareReactivity(FfxInt32x2 iPxPos) +{ + const FfxFloat32x2 fUv = (iPxPos + 0.5f) / RenderSize(); + const FfxFloat32x2 fMotionVector = LoadDilatedMotionVector(iPxPos); + + // Discard small mvs + const FfxFloat32 f4KVelocity = Get4KVelocity(fMotionVector); + + const FfxFloat32x2 fDilatedUv = fUv + fMotionVector; + const FfxFloat32 fDilatedDepth = LoadDilatedDepth(iPxPos); + const FfxFloat32 fDepthInMeters = GetViewSpaceDepthInMeters(fDilatedDepth); + + const FfxFloat32 fDisocclusion = ComputeDisocclusions(fUv, fMotionVector, GetViewSpaceDepth(fDilatedDepth)); + const FfxFloat32 fShadingChange = ffxMax(DilateReactiveMasks(iPxPos, fUv), ComputeShadingChange(fUv)); + + const FfxFloat32 fMotionDivergence = ComputeMotionDivergence(fUv, fMotionVector, fDilatedDepth); + const FfxFloat32 fDilatedTransparencyAndComposition = DilateTransparencyAndCompositionMasks(iPxPos, fUv); + const FfxFloat32 fFinalReactiveness = ffxMax(fMotionDivergence, fDilatedTransparencyAndComposition); + + const FfxFloat32 fAccumulation = UpdateAccumulation(iPxPos, fUv, fMotionVector, fDisocclusion, fShadingChange); + + FfxFloat32x4 fOutput; + fOutput[REACTIVE] = fFinalReactiveness; + fOutput[DISOCCLUSION] = fDisocclusion; + fOutput[SHADING_CHANGE] = fShadingChange; + fOutput[ACCUMULAION] = fAccumulation; + + StoreDilatedReactiveMasks(iPxPos, fOutput); + + const FfxFloat32 fLockStrength = ComputeThinFeatureConfidence(iPxPos); + if (fLockStrength > (1.0f / 100.0f)) + { + StoreNewLocks(ComputeHrPosFromLrPos(FfxInt32x2(iPxPos)), fLockStrength); + } +} diff --git a/externals/FidelityFX-SDK/include/FidelityFX/gpu/fsr3upscaler/ffx_fsr3upscaler_rcas.h b/externals/FidelityFX-SDK/include/FidelityFX/gpu/fsr3upscaler/ffx_fsr3upscaler_rcas.h new file mode 100644 index 0000000000..f48cffb93f --- /dev/null +++ b/externals/FidelityFX-SDK/include/FidelityFX/gpu/fsr3upscaler/ffx_fsr3upscaler_rcas.h @@ -0,0 +1,112 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and /or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#define GROUP_SIZE 8 +#define FSR_RCAS_DENOISE 1 + +#include "ffx_core.h" + +#if FFX_HALF && defined(__XBOX_SCARLETT) && defined(__XBATG_EXTRA_16_BIT_OPTIMISATION) && (__XBATG_EXTRA_16_BIT_OPTIMISATION == 1) + #define FSR_RCAS_PREFER_PAIRED_VERSION 1 +#else + #define FSR_RCAS_PREFER_PAIRED_VERSION 0 +#endif + +void WriteUpscaledOutput(FFX_MIN16_U2 iPxHrPos, FfxFloat32x3 fUpscaledColor) +{ + StoreUpscaledOutput(FFX_MIN16_I2(iPxHrPos), fUpscaledColor); +} + +#if FSR_RCAS_PREFER_PAIRED_VERSION + #define FSR_RCAS_HX2 1 + FfxFloat16x4 FsrRcasLoadHx2(FfxInt16x2 p) + { + return FfxFloat16x4(LoadRCAS_Input(p)); + } + void FsrRcasInputHx2(inout FfxFloat16x2 r, inout FfxFloat16x2 g, inout FfxFloat16x2 b) + { + FfxFloat32 e = Exposure(); + r = FfxFloat16x2(r * e); + g = FfxFloat16x2(g * e); + b = FfxFloat16x2(b * e); + } + + #include "fsr1/ffx_fsr1.h" + + void CurrFilterPaired(FFX_MIN16_U2 pos) + { + FfxFloat16x2 cr; + FfxFloat16x2 cg; + FfxFloat16x2 cb; + FsrRcasHx2(cr, cg, cb, pos, RCASConfig()); + FfxFloat32 InvExposure = 1.0f / Exposure(); + cr = FfxFloat16x2(cr * InvExposure); + cg = FfxFloat16x2(cg * InvExposure); + cb = FfxFloat16x2(cb * InvExposure); + WriteUpscaledOutput(pos, FfxFloat16x3(cr.x, cg.x, cb.x)); //TODO: fix type + pos.x += 8; + WriteUpscaledOutput(pos, FfxFloat16x3(cr.y, cg.y, cb.y)); //TODO: fix type + } +#else + #define FSR_RCAS_F 1 + FfxFloat32x4 FsrRcasLoadF(FfxInt32x2 p) + { + FfxFloat32x4 fColor = LoadRCAS_Input(p); + + fColor.rgb *= Exposure(); + + return fColor; + } + void FsrRcasInputF(inout FfxFloat32 r, inout FfxFloat32 g, inout FfxFloat32 b) {} + + #include "fsr1/ffx_fsr1.h" + + void CurrFilter(FFX_MIN16_U2 pos) + { + FfxFloat32x3 c; + FsrRcasF(c.r, c.g, c.b, pos, RCASConfig()); + + c /= Exposure(); + + WriteUpscaledOutput(pos, c); + } + +#endif // #if FSR_RCAS_PREFER_PAIRED_VERSION + +void RCAS(FfxUInt32x3 LocalThreadId, FfxUInt32x3 WorkGroupId, FfxUInt32x3 Dtid) +{ + // Do remapping of local xy in workgroup for a more PS-like swizzle pattern. + FfxUInt32x2 gxy = ffxRemapForQuad(LocalThreadId.x) + FfxUInt32x2(WorkGroupId.x << 4u, WorkGroupId.y << 4u); +#if FSR_RCAS_PREFER_PAIRED_VERSION + CurrFilterPaired(FFX_MIN16_U2(gxy)); + gxy.y += 8u; + CurrFilterPaired(FFX_MIN16_U2(gxy)); +#else + CurrFilter(FFX_MIN16_U2(gxy)); + gxy.x += 8u; + CurrFilter(FFX_MIN16_U2(gxy)); + gxy.y += 8u; + CurrFilter(FFX_MIN16_U2(gxy)); + gxy.x -= 8u; + CurrFilter(FFX_MIN16_U2(gxy)); +#endif +} diff --git a/externals/FidelityFX-SDK/include/FidelityFX/gpu/fsr3upscaler/ffx_fsr3upscaler_reproject.h b/externals/FidelityFX-SDK/include/FidelityFX/gpu/fsr3upscaler/ffx_fsr3upscaler_reproject.h new file mode 100644 index 0000000000..c72f40fb6f --- /dev/null +++ b/externals/FidelityFX-SDK/include/FidelityFX/gpu/fsr3upscaler/ffx_fsr3upscaler_reproject.h @@ -0,0 +1,79 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and /or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef FFX_FSR3UPSCALER_OPTION_REPROJECT_USE_LANCZOS_TYPE +#define FFX_FSR3UPSCALER_OPTION_REPROJECT_USE_LANCZOS_TYPE 0 // Reference +#endif + +FfxFloat32x4 WrapHistory(FfxInt32x2 iPxSample) +{ + return LoadHistory(iPxSample); +} + +DeclareCustomFetchBicubicSamples(FetchHistorySamples, WrapHistory) +DeclareCustomTextureSample(HistorySample, FFX_FSR3UPSCALER_GET_LANCZOS_SAMPLER1D(FFX_FSR3UPSCALER_OPTION_REPROJECT_USE_LANCZOS_TYPE), FetchHistorySamples) + +#if FFX_HALF +FFX_MIN16_F4 WrapHistory16(FfxInt32x2 iPxSample) +{ + return FFX_MIN16_F4(LoadHistory(iPxSample)); +} + +DeclareCustomFetchBicubicSamplesMin16(FetchHistorySamples16, WrapHistory16) +DeclareCustomTextureSampleMin16(HistorySample16, FFX_FSR3UPSCALER_GET_LANCZOS_SAMPLER1D(FFX_FSR3UPSCALER_OPTION_REPROJECT_USE_LANCZOS_TYPE), FetchHistorySamples16) +#endif + +FfxFloat32x2 GetMotionVector(FfxInt32x2 iPxHrPos, FfxFloat32x2 fHrUv) +{ +#if FFX_FSR3UPSCALER_OPTION_LOW_RESOLUTION_MOTION_VECTORS + const FfxFloat32x2 fDilatedMotionVector = LoadDilatedMotionVector(FFX_MIN16_I2(fHrUv * RenderSize())); +#else + const FfxFloat32x2 fDilatedMotionVector = LoadInputMotionVector(iPxHrPos); +#endif + + return fDilatedMotionVector; +} + +void ComputeReprojectedUVs(FFX_PARAMETER_INOUT AccumulationPassCommonParams params) +{ + params.fReprojectedHrUv = params.fHrUv + params.fMotionVector; + + params.bIsExistingSample = IsUvInside(params.fReprojectedHrUv); +} + +void ReprojectHistoryColor(const AccumulationPassCommonParams params, FFX_PARAMETER_INOUT AccumulationPassData data) + +{ +#if FFX_HALF && FFX_FSR3UPSCALER_OPTION_REPROJECT_SAMPLERS_USE_DATA_HALF + const FfxFloat32x4 fReprojectedHistory = FfxFloat32x4(HistorySample16(params.fReprojectedHrUv, UpscaleSize())); +#else + const FfxFloat32x4 fReprojectedHistory = HistorySample(params.fReprojectedHrUv, PreviousFrameUpscaleSize()); +#endif + + data.fHistoryColor = fReprojectedHistory.rgb; + data.fHistoryColor *= DeltaPreExposure(); + data.fHistoryColor *= Exposure(); + + data.fHistoryColor = RGBToYCoCg(data.fHistoryColor); + + data.fLock = fReprojectedHistory.w; +} diff --git a/externals/FidelityFX-SDK/include/FidelityFX/gpu/fsr3upscaler/ffx_fsr3upscaler_resources.h b/externals/FidelityFX-SDK/include/FidelityFX/gpu/fsr3upscaler/ffx_fsr3upscaler_resources.h new file mode 100644 index 0000000000..b3d8ddb17a --- /dev/null +++ b/externals/FidelityFX-SDK/include/FidelityFX/gpu/fsr3upscaler/ffx_fsr3upscaler_resources.h @@ -0,0 +1,100 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and /or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef FFX_FSR3UPSCALER_RESOURCES_H +#define FFX_FSR3UPSCALER_RESOURCES_H + +#if defined(FFX_CPU) || defined(FFX_GPU) +#define FFX_FSR3UPSCALER_RESOURCE_IDENTIFIER_NULL 0 +#define FFX_FSR3UPSCALER_RESOURCE_IDENTIFIER_INPUT_OPAQUE_ONLY 1 +#define FFX_FSR3UPSCALER_RESOURCE_IDENTIFIER_INPUT_COLOR 2 +#define FFX_FSR3UPSCALER_RESOURCE_IDENTIFIER_INPUT_MOTION_VECTORS 3 +#define FFX_FSR3UPSCALER_RESOURCE_IDENTIFIER_INPUT_DEPTH 4 +#define FFX_FSR3UPSCALER_RESOURCE_IDENTIFIER_INPUT_EXPOSURE 5 +#define FFX_FSR3UPSCALER_RESOURCE_IDENTIFIER_INPUT_REACTIVE_MASK 6 +#define FFX_FSR3UPSCALER_RESOURCE_IDENTIFIER_INPUT_TRANSPARENCY_AND_COMPOSITION_MASK 7 +#define FFX_FSR3UPSCALER_RESOURCE_IDENTIFIER_RECONSTRUCTED_PREVIOUS_NEAREST_DEPTH 8 +#define FFX_FSR3UPSCALER_RESOURCE_IDENTIFIER_DILATED_MOTION_VECTORS 9 +#define FFX_FSR3UPSCALER_RESOURCE_IDENTIFIER_DILATED_DEPTH 10 +#define FFX_FSR3UPSCALER_RESOURCE_IDENTIFIER_INTERNAL_UPSCALED_COLOR 11 +#define FFX_FSR3UPSCALER_RESOURCE_IDENTIFIER_ACCUMULATION 12 +#define FFX_FSR3UPSCALER_RESOURCE_IDENTIFIER_NEW_LOCKS 13 +#define FFX_FSR3UPSCALER_RESOURCE_IDENTIFIER_LUMA_HISTORY 14 +#define FFX_FSR3UPSCALER_RESOURCE_IDENTIFIER_DEBUG_OUTPUT 15 +#define FFX_FSR3UPSCALER_RESOURCE_IDENTIFIER_LANCZOS_LUT 16 +#define FFX_FSR3UPSCALER_RESOURCE_IDENTIFIER_SPD_ATOMIC_COUNT 17 +#define FFX_FSR3UPSCALER_RESOURCE_IDENTIFIER_UPSCALED_OUTPUT 18 +#define FFX_FSR3UPSCALER_RESOURCE_IDENTIFIER_RCAS_INPUT 19 +#define FFX_FSR3UPSCALER_RESOURCE_IDENTIFIER_ACCUMULATION_1 20 +#define FFX_FSR3UPSCALER_RESOURCE_IDENTIFIER_ACCUMULATION_2 21 +#define FFX_FSR3UPSCALER_RESOURCE_IDENTIFIER_INTERNAL_UPSCALED_COLOR_1 22 +#define FFX_FSR3UPSCALER_RESOURCE_IDENTIFIER_INTERNAL_UPSCALED_COLOR_2 23 +#define FFX_FSR3UPSCALER_RESOURCE_IDENTIFIER_INTERNAL_DEFAULT_REACTIVITY 24 +#define FFX_FSR3UPSCALER_RESOURCE_IDENTIFIER_INTERNAL_DEFAULT_TRANSPARENCY_AND_COMPOSITION 25 +#define FFX_FSR3UPSCALER_RESOURCE_IDENTIFIER_DILATED_REACTIVE_MASKS 26 +#define FFX_FSR3UPSCALER_RESOURCE_IDENTIFIER_SPD_MIPS 27 // same as FFX_FSR3UPSCALER_RESOURCE_IDENTIFIER_SPD_MIPS_LEVEL_0 +#define FFX_FSR3UPSCALER_RESOURCE_IDENTIFIER_SPD_MIPS_LEVEL_0 27 +#define FFX_FSR3UPSCALER_RESOURCE_IDENTIFIER_SPD_MIPS_LEVEL_1 28 +#define FFX_FSR3UPSCALER_RESOURCE_IDENTIFIER_SPD_MIPS_LEVEL_2 29 +#define FFX_FSR3UPSCALER_RESOURCE_IDENTIFIER_SPD_MIPS_LEVEL_3 30 +#define FFX_FSR3UPSCALER_RESOURCE_IDENTIFIER_SPD_MIPS_LEVEL_4 31 +#define FFX_FSR3UPSCALER_RESOURCE_IDENTIFIER_SPD_MIPS_LEVEL_5 32 + +#define FFX_FSR3UPSCALER_RESOURCE_IDENTIFIER_INTERNAL_DEFAULT_EXPOSURE 33 +#define FFX_FSR3UPSCALER_RESOURCE_IDENTIFIER_FRAME_INFO 34 +#define FFX_FSR3UPSCALER_RESOURCE_IDENTIFIER_AUTOREACTIVE 35 +#define FFX_FSR3UPSCALER_RESOURCE_IDENTIFIER_AUTOCOMPOSITION_DEPRECATED 36 + +#define FFX_FSR3UPSCALER_RESOURCE_IDENTIFIER_LUMA_HISTORY_1 37 +#define FFX_FSR3UPSCALER_RESOURCE_IDENTIFIER_LUMA_HISTORY_2 38 + +#define FFX_FSR3UPSCALER_RESOURCE_IDENTIFIER_LUMA_1 40 +#define FFX_FSR3UPSCALER_RESOURCE_IDENTIFIER_LUMA_2 41 +#define FFX_FSR3UPSCALER_RESOURCE_IDENTIFIER_SHADING_CHANGE 42 +#define FFX_FSR3UPSCALER_RESOURCE_IDENTIFIER_FARTHEST_DEPTH 43 +#define FFX_FSR3UPSCALER_RESOURCE_IDENTIFIER_FARTHEST_DEPTH_MIP1 44 +#define FFX_FSR3UPSCALER_RESOURCE_IDENTIFIER_CURRENT_LUMA 45 +#define FFX_FSR3UPSCALER_RESOURCE_IDENTIFIER_PREVIOUS_LUMA 46 +#define FFX_FSR3UPSCALER_RESOURCE_IDENTIFIER_LUMA_INSTABILITY 48 +#define FFX_FSR3UPSCALER_RESOURCE_IDENTIFIER_INTERMEDIATE_FP16x1 49 + + +// Shading change detection mip level setting, value must be in the range [FFX_FSR3UPSCALER_RESOURCE_IDENTIFIER_SCENE_LUMINANCE_MIPMAP_0, FFX_FSR3UPSCALER_RESOURCE_IDENTIFIER_SCENE_LUMINANCE_MIPMAP_12] +//#define FFX_FSR3UPSCALER_RESOURCE_IDENTIFIER_SCENE_LUMINANCE_MIPMAP_SHADING_CHANGE FFX_FSR3UPSCALER_RESOURCE_IDENTIFIER_SCENE_LUMINANCE_MIPMAP_4 +//#define FFX_FSR3UPSCALER_SHADING_CHANGE_MIP_LEVEL (FFX_FSR3UPSCALER_RESOURCE_IDENTIFIER_SCENE_LUMINANCE_MIPMAP_SHADING_CHANGE - FFX_FSR3UPSCALER_RESOURCE_IDENTIFIER_SCENE_LUMINANCE) + +#define FFX_FSR3UPSCALER_RESOURCE_IDENTIFIER_COUNT 60 + +#define FFX_FSR3UPSCALER_CONSTANTBUFFER_IDENTIFIER_FSR3UPSCALER 0 +#define FFX_FSR3UPSCALER_CONSTANTBUFFER_IDENTIFIER_SPD 1 +#define FFX_FSR3UPSCALER_CONSTANTBUFFER_IDENTIFIER_RCAS 2 +#define FFX_FSR3UPSCALER_CONSTANTBUFFER_IDENTIFIER_GENREACTIVE 3 +#define FFX_FSR3UPSCALER_CONSTANTBUFFER_COUNT 4 + +#define FFX_FSR3UPSCALER_AUTOREACTIVEFLAGS_APPLY_TONEMAP 1 +#define FFX_FSR3UPSCALER_AUTOREACTIVEFLAGS_APPLY_INVERSETONEMAP 2 +#define FFX_FSR3UPSCALER_AUTOREACTIVEFLAGS_APPLY_THRESHOLD 4 +#define FFX_FSR3UPSCALER_AUTOREACTIVEFLAGS_USE_COMPONENTS_MAX 8 + +#endif // #if defined(FFX_CPU) || defined(FFX_GPU) + +#endif //!defined( FFX_FSR3UPSCALER_RESOURCES_H ) diff --git a/externals/FidelityFX-SDK/include/FidelityFX/gpu/fsr3upscaler/ffx_fsr3upscaler_sample.h b/externals/FidelityFX-SDK/include/FidelityFX/gpu/fsr3upscaler/ffx_fsr3upscaler_sample.h new file mode 100644 index 0000000000..7a723d5562 --- /dev/null +++ b/externals/FidelityFX-SDK/include/FidelityFX/gpu/fsr3upscaler/ffx_fsr3upscaler_sample.h @@ -0,0 +1,628 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and /or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef FFX_FSR3UPSCALER_SAMPLE_H +#define FFX_FSR3UPSCALER_SAMPLE_H + +// suppress warnings +#ifdef FFX_HLSL +#pragma warning(disable: 4008) // potentially divide by zero +#endif //FFX_HLSL + +struct FetchedBilinearSamples { + + FfxFloat32x4 fColor00; + FfxFloat32x4 fColor10; + + FfxFloat32x4 fColor01; + FfxFloat32x4 fColor11; +}; + +struct FetchedBicubicSamples { + + FfxFloat32x4 fColor00; + FfxFloat32x4 fColor10; + FfxFloat32x4 fColor20; + FfxFloat32x4 fColor30; + + FfxFloat32x4 fColor01; + FfxFloat32x4 fColor11; + FfxFloat32x4 fColor21; + FfxFloat32x4 fColor31; + + FfxFloat32x4 fColor02; + FfxFloat32x4 fColor12; + FfxFloat32x4 fColor22; + FfxFloat32x4 fColor32; + + FfxFloat32x4 fColor03; + FfxFloat32x4 fColor13; + FfxFloat32x4 fColor23; + FfxFloat32x4 fColor33; +}; + +#if FFX_HALF +struct FetchedBilinearSamplesMin16 { + + FFX_MIN16_F4 fColor00; + FFX_MIN16_F4 fColor10; + + FFX_MIN16_F4 fColor01; + FFX_MIN16_F4 fColor11; +}; + +struct FetchedBicubicSamplesMin16 { + + FFX_MIN16_F4 fColor00; + FFX_MIN16_F4 fColor10; + FFX_MIN16_F4 fColor20; + FFX_MIN16_F4 fColor30; + + FFX_MIN16_F4 fColor01; + FFX_MIN16_F4 fColor11; + FFX_MIN16_F4 fColor21; + FFX_MIN16_F4 fColor31; + + FFX_MIN16_F4 fColor02; + FFX_MIN16_F4 fColor12; + FFX_MIN16_F4 fColor22; + FFX_MIN16_F4 fColor32; + + FFX_MIN16_F4 fColor03; + FFX_MIN16_F4 fColor13; + FFX_MIN16_F4 fColor23; + FFX_MIN16_F4 fColor33; +}; +#else //FFX_HALF +#define FetchedBicubicSamplesMin16 FetchedBicubicSamples +#define FetchedBilinearSamplesMin16 FetchedBilinearSamples +#endif //FFX_HALF + +FfxFloat32x4 Linear(FfxFloat32x4 A, FfxFloat32x4 B, FfxFloat32 t) +{ + return A + (B - A) * t; +} + +FfxFloat32x4 Bilinear(FetchedBilinearSamples BilinearSamples, FfxFloat32x2 fPxFrac) +{ + FfxFloat32x4 fColorX0 = Linear(BilinearSamples.fColor00, BilinearSamples.fColor10, fPxFrac.x); + FfxFloat32x4 fColorX1 = Linear(BilinearSamples.fColor01, BilinearSamples.fColor11, fPxFrac.x); + FfxFloat32x4 fColorXY = Linear(fColorX0, fColorX1, fPxFrac.y); + return fColorXY; +} + +#if FFX_HALF +FFX_MIN16_F4 Linear(FFX_MIN16_F4 A, FFX_MIN16_F4 B, FFX_MIN16_F t) +{ + return A + (B - A) * t; +} + +FFX_MIN16_F4 Bilinear(FetchedBilinearSamplesMin16 BilinearSamples, FFX_MIN16_F2 fPxFrac) +{ + FFX_MIN16_F4 fColorX0 = Linear(BilinearSamples.fColor00, BilinearSamples.fColor10, fPxFrac.x); + FFX_MIN16_F4 fColorX1 = Linear(BilinearSamples.fColor01, BilinearSamples.fColor11, fPxFrac.x); + FFX_MIN16_F4 fColorXY = Linear(fColorX0, fColorX1, fPxFrac.y); + return fColorXY; +} +#endif + +FfxFloat32 Lanczos2NoClamp(FfxFloat32 x) +{ + const FfxFloat32 PI = 3.141592653589793f; // TODO: share SDK constants + return abs(x) < FSR3UPSCALER_EPSILON ? 1.f : (sin(PI * x) / (PI * x)) * (sin(0.5f * PI * x) / (0.5f * PI * x)); +} + +FfxFloat32 Lanczos2(FfxFloat32 x) +{ + x = ffxMin(abs(x), 2.0f); + return Lanczos2NoClamp(x); +} + +#if FFX_HALF + +#if 0 +FFX_MIN16_F Lanczos2NoClamp(FFX_MIN16_F x) +{ + const FFX_MIN16_F PI = FFX_MIN16_F(3.141592653589793f); // TODO: share SDK constants + return abs(x) < FFX_MIN16_F(FSR3UPSCALER_EPSILON) ? FFX_MIN16_F(1.f) : (sin(PI * x) / (PI * x)) * (sin(FFX_MIN16_F(0.5f) * PI * x) / (FFX_MIN16_F(0.5f) * PI * x)); +} +#endif + +FFX_MIN16_F Lanczos2(FFX_MIN16_F x) +{ + x = ffxMin(abs(x), FFX_MIN16_F(2.0f)); + return FFX_MIN16_F(Lanczos2NoClamp(x)); +} +#endif //FFX_HALF + +// FSR1 lanczos approximation. Input is x*x and must be <= 4. +FfxFloat32 Lanczos2ApproxSqNoClamp(FfxFloat32 x2) +{ + FfxFloat32 a = (2.0f / 5.0f) * x2 - 1; + FfxFloat32 b = (1.0f / 4.0f) * x2 - 1; + return ((25.0f / 16.0f) * a * a - (25.0f / 16.0f - 1)) * (b * b); +} + +#if FFX_HALF +FFX_MIN16_F Lanczos2ApproxSqNoClamp(FFX_MIN16_F x2) +{ + FFX_MIN16_F a = FFX_MIN16_F(2.0f / 5.0f) * x2 - FFX_MIN16_F(1); + FFX_MIN16_F b = FFX_MIN16_F(1.0f / 4.0f) * x2 - FFX_MIN16_F(1); + return (FFX_MIN16_F(25.0f / 16.0f) * a * a - FFX_MIN16_F(25.0f / 16.0f - 1)) * (b * b); +} + +#if defined(__XBOX_SCARLETT) && defined(__XBATG_EXTRA_16_BIT_OPTIMISATION) && (__XBATG_EXTRA_16_BIT_OPTIMISATION == 1) +FFX_MIN16_F2 PairedLanczos2ApproxSqNoClamp(FFX_MIN16_F2 x2) +{ + // Xbox ATG (Pavel): + // + // 2.0 * x2 - 5.0 25.0 25.0 - 16.0 (2.0 * x2 - 5.0)^2 - (3.0)^2 (2.0 * x2 - 8.0) * (2.0 * x2 - 2.0) (x2 - 4.0) * (x2 - 1.0) + // a = -------------- ==> ---- * a^2 - -------------- = ----------------------------- = ---------------------------------- = ----------------------- = b * (x2 - 1.0) + // 5.0 16.0 16.0 16.0 16.0 4.0 + // + // so we need to compute just (b * b) * (b * x2 - b), so we should get four packed instructions: 2 fma + 2 mul + // + + FFX_MIN16_F2 b = (0.25 * x2 - 1.0); + return (b * b) * (b * x2 - b); +} +#endif + +#endif //FFX_HALF + +FfxFloat32 Lanczos2ApproxSq(FfxFloat32 x2) +{ + x2 = ffxMin(x2, 4.0f); + return Lanczos2ApproxSqNoClamp(x2); +} + +#if FFX_HALF +FFX_MIN16_F Lanczos2ApproxSq(FFX_MIN16_F x2) +{ + x2 = ffxMin(x2, FFX_MIN16_F(4.0f)); + return Lanczos2ApproxSqNoClamp(x2); +} + +#if defined(__XBOX_SCARLETT) && defined(__XBATG_EXTRA_16_BIT_OPTIMISATION) && (__XBATG_EXTRA_16_BIT_OPTIMISATION == 1) +FFX_MIN16_F2 PairedLanczos2ApproxSq(FFX_MIN16_F2 x2) +{ + x2 = ffxMin(x2, FFX_MIN16_F2(4.0, 4.0)); + return PairedLanczos2ApproxSqNoClamp(x2); +} +#endif +#endif //FFX_HALF + +FfxFloat32 Lanczos2ApproxNoClamp(FfxFloat32 x) +{ + return Lanczos2ApproxSqNoClamp(x * x); +} + +#if FFX_HALF +FFX_MIN16_F Lanczos2ApproxNoClamp(FFX_MIN16_F x) +{ + return Lanczos2ApproxSqNoClamp(x * x); +} +#endif //FFX_HALF + +FfxFloat32 Lanczos2Approx(FfxFloat32 x) +{ + return Lanczos2ApproxSq(x * x); +} + +#if FFX_HALF +FFX_MIN16_F Lanczos2Approx(FFX_MIN16_F x) +{ + return Lanczos2ApproxSq(x * x); +} +#endif //FFX_HALF + +FfxFloat32 Lanczos2_UseLUT(FfxFloat32 x) +{ + return SampleLanczos2Weight(abs(x)); +} + +#if FFX_HALF +FFX_MIN16_F Lanczos2_UseLUT(FFX_MIN16_F x) +{ + return FFX_MIN16_F(SampleLanczos2Weight(abs(x))); +} +#endif //FFX_HALF + +FfxFloat32x4 Lanczos2_UseLUT(FfxFloat32x4 fColor0, FfxFloat32x4 fColor1, FfxFloat32x4 fColor2, FfxFloat32x4 fColor3, FfxFloat32 t) +{ + FfxFloat32 fWeight0 = Lanczos2_UseLUT(-1.f - t); + FfxFloat32 fWeight1 = Lanczos2_UseLUT(-0.f - t); + FfxFloat32 fWeight2 = Lanczos2_UseLUT(+1.f - t); + FfxFloat32 fWeight3 = Lanczos2_UseLUT(+2.f - t); + return (fWeight0 * fColor0 + fWeight1 * fColor1 + fWeight2 * fColor2 + fWeight3 * fColor3) / (fWeight0 + fWeight1 + fWeight2 + fWeight3); +} +#if FFX_HALF +FFX_MIN16_F4 Lanczos2_UseLUT(FFX_MIN16_F4 fColor0, FFX_MIN16_F4 fColor1, FFX_MIN16_F4 fColor2, FFX_MIN16_F4 fColor3, FFX_MIN16_F t) +{ + FFX_MIN16_F fWeight0 = Lanczos2_UseLUT(FFX_MIN16_F(-1.f) - t); + FFX_MIN16_F fWeight1 = Lanczos2_UseLUT(FFX_MIN16_F(-0.f) - t); + FFX_MIN16_F fWeight2 = Lanczos2_UseLUT(FFX_MIN16_F(+1.f) - t); + FFX_MIN16_F fWeight3 = Lanczos2_UseLUT(FFX_MIN16_F(+2.f) - t); + return (fWeight0 * fColor0 + fWeight1 * fColor1 + fWeight2 * fColor2 + fWeight3 * fColor3) / (fWeight0 + fWeight1 + fWeight2 + fWeight3); +} +#endif + +FfxFloat32x4 Lanczos2(FfxFloat32x4 fColor0, FfxFloat32x4 fColor1, FfxFloat32x4 fColor2, FfxFloat32x4 fColor3, FfxFloat32 t) +{ + FfxFloat32 fWeight0 = Lanczos2(-1.f - t); + FfxFloat32 fWeight1 = Lanczos2(-0.f - t); + FfxFloat32 fWeight2 = Lanczos2(+1.f - t); + FfxFloat32 fWeight3 = Lanczos2(+2.f - t); + return (fWeight0 * fColor0 + fWeight1 * fColor1 + fWeight2 * fColor2 + fWeight3 * fColor3) / (fWeight0 + fWeight1 + fWeight2 + fWeight3); +} + +FfxFloat32x4 Lanczos2(FetchedBicubicSamples Samples, FfxFloat32x2 fPxFrac) +{ + FfxFloat32x4 fColorX0 = Lanczos2(Samples.fColor00, Samples.fColor10, Samples.fColor20, Samples.fColor30, fPxFrac.x); + FfxFloat32x4 fColorX1 = Lanczos2(Samples.fColor01, Samples.fColor11, Samples.fColor21, Samples.fColor31, fPxFrac.x); + FfxFloat32x4 fColorX2 = Lanczos2(Samples.fColor02, Samples.fColor12, Samples.fColor22, Samples.fColor32, fPxFrac.x); + FfxFloat32x4 fColorX3 = Lanczos2(Samples.fColor03, Samples.fColor13, Samples.fColor23, Samples.fColor33, fPxFrac.x); + FfxFloat32x4 fColorXY = Lanczos2(fColorX0, fColorX1, fColorX2, fColorX3, fPxFrac.y); + + // Deringing + + // TODO: only use 4 by checking jitter + const FfxInt32 iDeringingSampleCount = 4; + const FfxFloat32x4 fDeringingSamples[4] = { + Samples.fColor11, + Samples.fColor21, + Samples.fColor12, + Samples.fColor22, + }; + + FfxFloat32x4 fDeringingMin = fDeringingSamples[0]; + FfxFloat32x4 fDeringingMax = fDeringingSamples[0]; + + FFX_UNROLL + for (FfxInt32 iSampleIndex = 1; iSampleIndex < iDeringingSampleCount; ++iSampleIndex) { + + fDeringingMin = ffxMin(fDeringingMin, fDeringingSamples[iSampleIndex]); + fDeringingMax = ffxMax(fDeringingMax, fDeringingSamples[iSampleIndex]); + } + + fColorXY = clamp(fColorXY, fDeringingMin, fDeringingMax); + + return fColorXY; +} + +#if FFX_HALF +FFX_MIN16_F4 Lanczos2(FFX_MIN16_F4 fColor0, FFX_MIN16_F4 fColor1, FFX_MIN16_F4 fColor2, FFX_MIN16_F4 fColor3, FFX_MIN16_F t) +{ + FFX_MIN16_F fWeight0 = Lanczos2(FFX_MIN16_F(-1.f) - t); + FFX_MIN16_F fWeight1 = Lanczos2(FFX_MIN16_F(-0.f) - t); + FFX_MIN16_F fWeight2 = Lanczos2(FFX_MIN16_F(+1.f) - t); + FFX_MIN16_F fWeight3 = Lanczos2(FFX_MIN16_F(+2.f) - t); + return (fWeight0 * fColor0 + fWeight1 * fColor1 + fWeight2 * fColor2 + fWeight3 * fColor3) / (fWeight0 + fWeight1 + fWeight2 + fWeight3); +} + +FFX_MIN16_F4 Lanczos2(FetchedBicubicSamplesMin16 Samples, FFX_MIN16_F2 fPxFrac) +{ + FFX_MIN16_F4 fColorX0 = Lanczos2(Samples.fColor00, Samples.fColor10, Samples.fColor20, Samples.fColor30, fPxFrac.x); + FFX_MIN16_F4 fColorX1 = Lanczos2(Samples.fColor01, Samples.fColor11, Samples.fColor21, Samples.fColor31, fPxFrac.x); + FFX_MIN16_F4 fColorX2 = Lanczos2(Samples.fColor02, Samples.fColor12, Samples.fColor22, Samples.fColor32, fPxFrac.x); + FFX_MIN16_F4 fColorX3 = Lanczos2(Samples.fColor03, Samples.fColor13, Samples.fColor23, Samples.fColor33, fPxFrac.x); + FFX_MIN16_F4 fColorXY = Lanczos2(fColorX0, fColorX1, fColorX2, fColorX3, fPxFrac.y); + + // Deringing + + // TODO: only use 4 by checking jitter + const FfxInt32 iDeringingSampleCount = 4; + const FFX_MIN16_F4 fDeringingSamples[4] = { + Samples.fColor11, + Samples.fColor21, + Samples.fColor12, + Samples.fColor22, + }; + + FFX_MIN16_F4 fDeringingMin = fDeringingSamples[0]; + FFX_MIN16_F4 fDeringingMax = fDeringingSamples[0]; + + FFX_UNROLL + for (FfxInt32 iSampleIndex = 1; iSampleIndex < iDeringingSampleCount; ++iSampleIndex) + { + fDeringingMin = ffxMin(fDeringingMin, fDeringingSamples[iSampleIndex]); + fDeringingMax = ffxMax(fDeringingMax, fDeringingSamples[iSampleIndex]); + } + + fColorXY = clamp(fColorXY, fDeringingMin, fDeringingMax); + + return fColorXY; +} +#endif //FFX_HALF + + +FfxFloat32x4 Lanczos2LUT(FetchedBicubicSamples Samples, FfxFloat32x2 fPxFrac) +{ + FfxFloat32x4 fColorX0 = Lanczos2_UseLUT(Samples.fColor00, Samples.fColor10, Samples.fColor20, Samples.fColor30, fPxFrac.x); + FfxFloat32x4 fColorX1 = Lanczos2_UseLUT(Samples.fColor01, Samples.fColor11, Samples.fColor21, Samples.fColor31, fPxFrac.x); + FfxFloat32x4 fColorX2 = Lanczos2_UseLUT(Samples.fColor02, Samples.fColor12, Samples.fColor22, Samples.fColor32, fPxFrac.x); + FfxFloat32x4 fColorX3 = Lanczos2_UseLUT(Samples.fColor03, Samples.fColor13, Samples.fColor23, Samples.fColor33, fPxFrac.x); + FfxFloat32x4 fColorXY = Lanczos2_UseLUT(fColorX0, fColorX1, fColorX2, fColorX3, fPxFrac.y); + + // Deringing + + // TODO: only use 4 by checking jitter + const FfxInt32 iDeringingSampleCount = 4; + const FfxFloat32x4 fDeringingSamples[4] = { + Samples.fColor11, + Samples.fColor21, + Samples.fColor12, + Samples.fColor22, + }; + + FfxFloat32x4 fDeringingMin = fDeringingSamples[0]; + FfxFloat32x4 fDeringingMax = fDeringingSamples[0]; + + FFX_UNROLL + for (FfxInt32 iSampleIndex = 1; iSampleIndex < iDeringingSampleCount; ++iSampleIndex) { + + fDeringingMin = ffxMin(fDeringingMin, fDeringingSamples[iSampleIndex]); + fDeringingMax = ffxMax(fDeringingMax, fDeringingSamples[iSampleIndex]); + } + + fColorXY = clamp(fColorXY, fDeringingMin, fDeringingMax); + + return fColorXY; +} + +#if FFX_HALF +FFX_MIN16_F4 Lanczos2LUT(FetchedBicubicSamplesMin16 Samples, FFX_MIN16_F2 fPxFrac) +{ + FFX_MIN16_F4 fColorX0 = Lanczos2_UseLUT(Samples.fColor00, Samples.fColor10, Samples.fColor20, Samples.fColor30, fPxFrac.x); + FFX_MIN16_F4 fColorX1 = Lanczos2_UseLUT(Samples.fColor01, Samples.fColor11, Samples.fColor21, Samples.fColor31, fPxFrac.x); + FFX_MIN16_F4 fColorX2 = Lanczos2_UseLUT(Samples.fColor02, Samples.fColor12, Samples.fColor22, Samples.fColor32, fPxFrac.x); + FFX_MIN16_F4 fColorX3 = Lanczos2_UseLUT(Samples.fColor03, Samples.fColor13, Samples.fColor23, Samples.fColor33, fPxFrac.x); + FFX_MIN16_F4 fColorXY = Lanczos2_UseLUT(fColorX0, fColorX1, fColorX2, fColorX3, fPxFrac.y); + + // Deringing + + // TODO: only use 4 by checking jitter + const FfxInt32 iDeringingSampleCount = 4; + const FFX_MIN16_F4 fDeringingSamples[4] = { + Samples.fColor11, + Samples.fColor21, + Samples.fColor12, + Samples.fColor22, + }; + + FFX_MIN16_F4 fDeringingMin = fDeringingSamples[0]; + FFX_MIN16_F4 fDeringingMax = fDeringingSamples[0]; + + FFX_UNROLL + for (FfxInt32 iSampleIndex = 1; iSampleIndex < iDeringingSampleCount; ++iSampleIndex) + { + fDeringingMin = ffxMin(fDeringingMin, fDeringingSamples[iSampleIndex]); + fDeringingMax = ffxMax(fDeringingMax, fDeringingSamples[iSampleIndex]); + } + + fColorXY = clamp(fColorXY, fDeringingMin, fDeringingMax); + + return fColorXY; +} +#endif //FFX_HALF + + + +FfxFloat32x4 Lanczos2Approx(FfxFloat32x4 fColor0, FfxFloat32x4 fColor1, FfxFloat32x4 fColor2, FfxFloat32x4 fColor3, FfxFloat32 t) +{ + FfxFloat32 fWeight0 = Lanczos2ApproxNoClamp(-1.f - t); + FfxFloat32 fWeight1 = Lanczos2ApproxNoClamp(-0.f - t); + FfxFloat32 fWeight2 = Lanczos2ApproxNoClamp(+1.f - t); + FfxFloat32 fWeight3 = Lanczos2ApproxNoClamp(+2.f - t); + return (fWeight0 * fColor0 + fWeight1 * fColor1 + fWeight2 * fColor2 + fWeight3 * fColor3) / (fWeight0 + fWeight1 + fWeight2 + fWeight3); +} + +#if FFX_HALF +FFX_MIN16_F4 Lanczos2Approx(FFX_MIN16_F4 fColor0, FFX_MIN16_F4 fColor1, FFX_MIN16_F4 fColor2, FFX_MIN16_F4 fColor3, FFX_MIN16_F t) +{ + FFX_MIN16_F fWeight0 = Lanczos2ApproxNoClamp(FFX_MIN16_F(-1.f) - t); + FFX_MIN16_F fWeight1 = Lanczos2ApproxNoClamp(FFX_MIN16_F(-0.f) - t); + FFX_MIN16_F fWeight2 = Lanczos2ApproxNoClamp(FFX_MIN16_F(+1.f) - t); + FFX_MIN16_F fWeight3 = Lanczos2ApproxNoClamp(FFX_MIN16_F(+2.f) - t); + return (fWeight0 * fColor0 + fWeight1 * fColor1 + fWeight2 * fColor2 + fWeight3 * fColor3) / (fWeight0 + fWeight1 + fWeight2 + fWeight3); +} +#endif //FFX_HALF + +FfxFloat32x4 Lanczos2Approx(FetchedBicubicSamples Samples, FfxFloat32x2 fPxFrac) +{ + FfxFloat32x4 fColorX0 = Lanczos2Approx(Samples.fColor00, Samples.fColor10, Samples.fColor20, Samples.fColor30, fPxFrac.x); + FfxFloat32x4 fColorX1 = Lanczos2Approx(Samples.fColor01, Samples.fColor11, Samples.fColor21, Samples.fColor31, fPxFrac.x); + FfxFloat32x4 fColorX2 = Lanczos2Approx(Samples.fColor02, Samples.fColor12, Samples.fColor22, Samples.fColor32, fPxFrac.x); + FfxFloat32x4 fColorX3 = Lanczos2Approx(Samples.fColor03, Samples.fColor13, Samples.fColor23, Samples.fColor33, fPxFrac.x); + FfxFloat32x4 fColorXY = Lanczos2Approx(fColorX0, fColorX1, fColorX2, fColorX3, fPxFrac.y); + + // Deringing + + // TODO: only use 4 by checking jitter + const FfxInt32 iDeringingSampleCount = 4; + const FfxFloat32x4 fDeringingSamples[4] = { + Samples.fColor11, + Samples.fColor21, + Samples.fColor12, + Samples.fColor22, + }; + + FfxFloat32x4 fDeringingMin = fDeringingSamples[0]; + FfxFloat32x4 fDeringingMax = fDeringingSamples[0]; + + FFX_UNROLL + for (FfxInt32 iSampleIndex = 1; iSampleIndex < iDeringingSampleCount; ++iSampleIndex) + { + fDeringingMin = ffxMin(fDeringingMin, fDeringingSamples[iSampleIndex]); + fDeringingMax = ffxMax(fDeringingMax, fDeringingSamples[iSampleIndex]); + } + + fColorXY = clamp(fColorXY, fDeringingMin, fDeringingMax); + + return fColorXY; +} + +#if FFX_HALF +FFX_MIN16_F4 Lanczos2Approx(FetchedBicubicSamplesMin16 Samples, FFX_MIN16_F2 fPxFrac) +{ + FFX_MIN16_F4 fColorX0 = Lanczos2Approx(Samples.fColor00, Samples.fColor10, Samples.fColor20, Samples.fColor30, fPxFrac.x); + FFX_MIN16_F4 fColorX1 = Lanczos2Approx(Samples.fColor01, Samples.fColor11, Samples.fColor21, Samples.fColor31, fPxFrac.x); + FFX_MIN16_F4 fColorX2 = Lanczos2Approx(Samples.fColor02, Samples.fColor12, Samples.fColor22, Samples.fColor32, fPxFrac.x); + FFX_MIN16_F4 fColorX3 = Lanczos2Approx(Samples.fColor03, Samples.fColor13, Samples.fColor23, Samples.fColor33, fPxFrac.x); + FFX_MIN16_F4 fColorXY = Lanczos2Approx(fColorX0, fColorX1, fColorX2, fColorX3, fPxFrac.y); + + // Deringing + + // TODO: only use 4 by checking jitter + const FfxInt32 iDeringingSampleCount = 4; + const FFX_MIN16_F4 fDeringingSamples[4] = { + Samples.fColor11, + Samples.fColor21, + Samples.fColor12, + Samples.fColor22, + }; + + FFX_MIN16_F4 fDeringingMin = fDeringingSamples[0]; + FFX_MIN16_F4 fDeringingMax = fDeringingSamples[0]; + + FFX_UNROLL + for (FfxInt32 iSampleIndex = 1; iSampleIndex < iDeringingSampleCount; ++iSampleIndex) + { + fDeringingMin = ffxMin(fDeringingMin, fDeringingSamples[iSampleIndex]); + fDeringingMax = ffxMax(fDeringingMax, fDeringingSamples[iSampleIndex]); + } + + fColorXY = clamp(fColorXY, fDeringingMin, fDeringingMax); + + return fColorXY; +} +#endif + +// Clamp by offset direction. Assuming iPxSample is already in range and iPxOffset is compile time constant. +FfxInt32x2 ClampCoord(FfxInt32x2 iPxSample, FfxInt32x2 iPxOffset, FfxInt32x2 iTextureSize) +{ + FfxInt32x2 result = iPxSample + iPxOffset; + result.x = ffxMax(1, ffxMin(result.x, iTextureSize.x - 2)); + result.y = ffxMax(1, ffxMin(result.y, iTextureSize.y - 2)); + return result; +} +#if FFX_HALF +FFX_MIN16_I2 ClampCoord(FFX_MIN16_I2 iPxSample, FFX_MIN16_I2 iPxOffset, FFX_MIN16_I2 iTextureSize) +{ + FFX_MIN16_I2 result = iPxSample + iPxOffset; + result.x = ffxMax(FFX_MIN16_I(1), ffxMin(result.x, iTextureSize.x - FFX_MIN16_I(2))); + result.y = ffxMax(FFX_MIN16_I(1), ffxMin(result.y, iTextureSize.y - FFX_MIN16_I(2))); + return result; +} +#endif //FFX_HALF + + +#define DeclareCustomFetchBicubicSamplesWithType(SampleType, TextureType, AddrType, Name, LoadTexture) \ + SampleType Name(AddrType iPxSample, AddrType iTextureSize) \ + { \ + SampleType Samples; \ + \ + Samples.fColor00 = TextureType(LoadTexture(ClampCoord(iPxSample, AddrType(-1, -1), iTextureSize))); \ + Samples.fColor10 = TextureType(LoadTexture(ClampCoord(iPxSample, AddrType(+0, -1), iTextureSize))); \ + Samples.fColor20 = TextureType(LoadTexture(ClampCoord(iPxSample, AddrType(+1, -1), iTextureSize))); \ + Samples.fColor30 = TextureType(LoadTexture(ClampCoord(iPxSample, AddrType(+2, -1), iTextureSize))); \ + \ + Samples.fColor01 = TextureType(LoadTexture(ClampCoord(iPxSample, AddrType(-1, +0), iTextureSize))); \ + Samples.fColor11 = TextureType(LoadTexture(ClampCoord(iPxSample, AddrType(+0, +0), iTextureSize))); \ + Samples.fColor21 = TextureType(LoadTexture(ClampCoord(iPxSample, AddrType(+1, +0), iTextureSize))); \ + Samples.fColor31 = TextureType(LoadTexture(ClampCoord(iPxSample, AddrType(+2, +0), iTextureSize))); \ + \ + Samples.fColor02 = TextureType(LoadTexture(ClampCoord(iPxSample, AddrType(-1, +1), iTextureSize))); \ + Samples.fColor12 = TextureType(LoadTexture(ClampCoord(iPxSample, AddrType(+0, +1), iTextureSize))); \ + Samples.fColor22 = TextureType(LoadTexture(ClampCoord(iPxSample, AddrType(+1, +1), iTextureSize))); \ + Samples.fColor32 = TextureType(LoadTexture(ClampCoord(iPxSample, AddrType(+2, +1), iTextureSize))); \ + \ + Samples.fColor03 = TextureType(LoadTexture(ClampCoord(iPxSample, AddrType(-1, +2), iTextureSize))); \ + Samples.fColor13 = TextureType(LoadTexture(ClampCoord(iPxSample, AddrType(+0, +2), iTextureSize))); \ + Samples.fColor23 = TextureType(LoadTexture(ClampCoord(iPxSample, AddrType(+1, +2), iTextureSize))); \ + Samples.fColor33 = TextureType(LoadTexture(ClampCoord(iPxSample, AddrType(+2, +2), iTextureSize))); \ + \ + return Samples; \ + } + +#define DeclareCustomFetchBicubicSamples(Name, LoadTexture) \ + DeclareCustomFetchBicubicSamplesWithType(FetchedBicubicSamples, FfxFloat32x4, FfxInt32x2, Name, LoadTexture) + +#define DeclareCustomFetchBicubicSamplesMin16(Name, LoadTexture) \ + DeclareCustomFetchBicubicSamplesWithType(FetchedBicubicSamplesMin16, FFX_MIN16_F4, FfxInt32x2, Name, LoadTexture) + +#define DeclareCustomFetchBilinearSamplesWithType(SampleType, TextureType,AddrType, Name, LoadTexture) \ + SampleType Name(AddrType iPxSample, AddrType iTextureSize) \ + { \ + SampleType Samples; \ + Samples.fColor00 = TextureType(LoadTexture(ClampCoord(iPxSample, AddrType(+0, +0), iTextureSize))); \ + Samples.fColor10 = TextureType(LoadTexture(ClampCoord(iPxSample, AddrType(+1, +0), iTextureSize))); \ + Samples.fColor01 = TextureType(LoadTexture(ClampCoord(iPxSample, AddrType(+0, +1), iTextureSize))); \ + Samples.fColor11 = TextureType(LoadTexture(ClampCoord(iPxSample, AddrType(+1, +1), iTextureSize))); \ + return Samples; \ + } + +#define DeclareCustomFetchBilinearSamples(Name, LoadTexture) \ + DeclareCustomFetchBilinearSamplesWithType(FetchedBilinearSamples, FfxFloat32x4, FfxInt32x2, Name, LoadTexture) + +#define DeclareCustomFetchBilinearSamplesMin16(Name, LoadTexture) \ + DeclareCustomFetchBilinearSamplesWithType(FetchedBilinearSamplesMin16, FFX_MIN16_F4, FfxInt32x2, Name, LoadTexture) + +// BE CAREFUL: there is some precision issues and (3253, 125) leading to (3252.9989778, 125.001102) +// is common, so iPxSample can "jitter" +#define DeclareCustomTextureSample(Name, InterpolateSamples, FetchSamples) \ + FfxFloat32x4 Name(FfxFloat32x2 fUvSample, FfxInt32x2 iTextureSize) \ + { \ + FfxFloat32x2 fPxSample = (fUvSample * FfxFloat32x2(iTextureSize)) - FfxFloat32x2(0.5f, 0.5f); \ + FfxFloat32x2 fPxFrac = ffxFract(fPxSample); \ + /* Clamp base coords */ \ + fPxSample.x = ffxMax(0.0f, ffxMin(FfxFloat32(iTextureSize.x-1), fPxSample.x)); \ + fPxSample.y = ffxMax(0.0f, ffxMin(FfxFloat32(iTextureSize.y-1), fPxSample.y)); \ + /* */ \ + FfxInt32x2 iPxSample = FfxInt32x2(floor(fPxSample)); \ + FfxFloat32x4 fColorXY = FfxFloat32x4(InterpolateSamples(FetchSamples(iPxSample, iTextureSize), fPxFrac)); \ + return fColorXY; \ + } + +#define DeclareCustomTextureSampleMin16(Name, InterpolateSamples, FetchSamples) \ + FFX_MIN16_F4 Name(FfxFloat32x2 fUvSample, FfxInt32x2 iTextureSize) \ + { \ + FfxFloat32x2 fPxSample = (fUvSample * FfxFloat32x2(iTextureSize)) - FfxFloat32x2(0.5f, 0.5f); \ + FFX_MIN16_F2 fPxFrac = FFX_MIN16_F2(ffxFract(fPxSample)); \ + /* Clamp base coords */ \ + fPxSample.x = ffxMax(0.0f, ffxMin(FfxFloat32(iTextureSize.x), fPxSample.x)); \ + fPxSample.y = ffxMax(0.0f, ffxMin(FfxFloat32(iTextureSize.y), fPxSample.y)); \ + /* */ \ + FfxInt32x2 iPxSample = FfxInt32x2(floor(fPxSample)); \ + FFX_MIN16_F4 fColorXY = FFX_MIN16_F4(InterpolateSamples(FetchSamples(iPxSample, iTextureSize), fPxFrac)); \ + return fColorXY; \ + } + +#define FFX_FSR3UPSCALER_CONCAT_ID(x, y) x ## y +#define FFX_FSR3UPSCALER_CONCAT(x, y) FFX_FSR3UPSCALER_CONCAT_ID(x, y) +#define FFX_FSR3UPSCALER_SAMPLER_1D_0 Lanczos2 +#define FFX_FSR3UPSCALER_SAMPLER_1D_1 Lanczos2LUT +#define FFX_FSR3UPSCALER_SAMPLER_1D_2 Lanczos2Approx + +#define FFX_FSR3UPSCALER_GET_LANCZOS_SAMPLER1D(x) FFX_FSR3UPSCALER_CONCAT(FFX_FSR3UPSCALER_SAMPLER_1D_, x) + +#endif //!defined( FFX_FSR3UPSCALER_SAMPLE_H ) diff --git a/externals/FidelityFX-SDK/include/FidelityFX/gpu/fsr3upscaler/ffx_fsr3upscaler_shading_change.h b/externals/FidelityFX-SDK/include/FidelityFX/gpu/fsr3upscaler/ffx_fsr3upscaler_shading_change.h new file mode 100644 index 0000000000..2eb23aacdf --- /dev/null +++ b/externals/FidelityFX-SDK/include/FidelityFX/gpu/fsr3upscaler/ffx_fsr3upscaler_shading_change.h @@ -0,0 +1,68 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and /or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +FFX_STATIC const FfxInt32 s_MipLevelsToUse = 3; + +struct ShadingChangeLumaInfo +{ + FfxFloat32 fSamples[s_MipLevelsToUse]; +}; + +ShadingChangeLumaInfo ComputeShadingChangeLuma(FfxInt32x2 iPxPos, FfxFloat32x2 fUv, const FfxInt32x2 iCurrentSize) +{ + ShadingChangeLumaInfo info; + + const FfxFloat32x2 fMipUv = ClampUv(fUv, ShadingChangeRenderSize(), GetSPDMipDimensions(0)); + + FFX_UNROLL + for (FfxInt32 iMipLevel = iShadingChangeMipStart; iMipLevel < s_MipLevelsToUse; iMipLevel++) { + + const FfxFloat32x2 fSample = SampleSPDMipLevel(fMipUv, iMipLevel); + + info.fSamples[iMipLevel] = abs(fSample.x * fSample.y); + } + + return info; +} + +void ShadingChange(FfxInt32x2 iPxPos) +{ + if (IsOnScreen(FfxInt32x2(iPxPos), ShadingChangeRenderSize())) { + + const FfxFloat32x2 fUv = (iPxPos + 0.5f) / ShadingChangeRenderSize(); + const FfxFloat32x2 fUvJittered = fUv + Jitter() / RenderSize(); + + const ShadingChangeLumaInfo info = ComputeShadingChangeLuma(iPxPos, fUvJittered, ShadingChangeRenderSize()); + + const FfxFloat32 fScale = 1.0f + iShadingChangeMipStart / s_MipLevelsToUse; + FfxFloat32 fShadingChange = 0.0f; + FFX_UNROLL + for (int iMipLevel = iShadingChangeMipStart; iMipLevel < s_MipLevelsToUse; iMipLevel++) + { + if (info.fSamples[iMipLevel] > 0) { + fShadingChange = ffxMax(fShadingChange, info.fSamples[iMipLevel]) * fScale; + } + } + + StoreShadingChange(iPxPos, ffxSaturate(fShadingChange)); + } +} diff --git a/externals/FidelityFX-SDK/include/FidelityFX/gpu/fsr3upscaler/ffx_fsr3upscaler_shading_change_pyramid.h b/externals/FidelityFX-SDK/include/FidelityFX/gpu/fsr3upscaler/ffx_fsr3upscaler_shading_change_pyramid.h new file mode 100644 index 0000000000..63ca5d6d5f --- /dev/null +++ b/externals/FidelityFX-SDK/include/FidelityFX/gpu/fsr3upscaler/ffx_fsr3upscaler_shading_change_pyramid.h @@ -0,0 +1,297 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and /or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +FFX_GROUPSHARED FfxUInt32 spdCounter; + +void SpdIncreaseAtomicCounter(FfxUInt32 slice) +{ + SPD_IncreaseAtomicCounter(spdCounter); +} + +FfxUInt32 SpdGetAtomicCounter() +{ + return spdCounter; +} + +void SpdResetAtomicCounter(FfxUInt32 slice) +{ + SPD_ResetAtomicCounter(); +} + +#ifndef SPD_PACKED_ONLY +FFX_GROUPSHARED FfxFloat32 spdIntermediateR[16][16]; +FFX_GROUPSHARED FfxFloat32 spdIntermediateG[16][16]; +FFX_GROUPSHARED FfxFloat32 spdIntermediateB[16][16]; +FFX_GROUPSHARED FfxFloat32 spdIntermediateA[16][16]; + +FFX_STATIC const FfxInt32 DIFFERENCE = 0; +FFX_STATIC const FfxInt32 SIGN_SUM = 1; +FFX_STATIC const FfxInt32 MIP0_INDICATOR = 2; + +FfxFloat32x2 Sort2(FfxFloat32x2 v) +{ + return FfxFloat32x2(ffxMin(v.x, v.y), ffxMax(v.x, v.y)); +} + +struct SampleSet +{ + FfxFloat32 fSamples[SHADING_CHANGE_SET_SIZE]; +}; + +#define CompareSwap(i, j) \ +{ \ +FfxFloat32 fTmp = ffxMin(fSet.fSamples[i], fSet.fSamples[j]);\ +fSet.fSamples[j] = ffxMax(fSet.fSamples[i], fSet.fSamples[j]);\ +fSet.fSamples[i] = fTmp;\ +} + +#if SHADING_CHANGE_SET_SIZE == 5 +FFX_STATIC const FfxInt32x2 iSampleOffsets[5] = {FfxInt32x2(+0, +0), FfxInt32x2(-1, +0), FfxInt32x2(+1, +0), FfxInt32x2(+0, -1), FfxInt32x2(+0, +1)}; + +void SortSet(FFX_PARAMETER_INOUT SampleSet fSet) +{ + CompareSwap(0, 3); + CompareSwap(1, 4); + CompareSwap(0, 2); + CompareSwap(1, 3); + CompareSwap(0, 1); + CompareSwap(2, 4); + CompareSwap(1, 2); + CompareSwap(3, 4); + CompareSwap(2, 3); +} +#endif + +FfxFloat32 ComputeMinimumDifference(FfxInt32x2 iPxPos, SampleSet fSet0, SampleSet fSet1) +{ + FfxFloat32 fMinDiff = FSR3UPSCALER_FP16_MAX - 1; + FfxInt32 a = 0; + FfxInt32 b = 0; + + SortSet(fSet0); + SortSet(fSet1); + + const FfxFloat32 fMax = ffxMin(fSet0.fSamples[SHADING_CHANGE_SET_SIZE-1], fSet1.fSamples[SHADING_CHANGE_SET_SIZE-1]); + + if (fMax > FSR3UPSCALER_FP32_MIN) { + + FFX_UNROLL + for (FfxInt32 i = 0; i < SHADING_CHANGE_SET_SIZE && (fMinDiff < FSR3UPSCALER_FP16_MAX); i++) { + + FfxFloat32 fDiff = fSet0.fSamples[a] - fSet1.fSamples[b]; + + if (abs(fDiff) > FSR3UPSCALER_FP16_MIN) { + + fDiff = sign(fDiff) * (1.0f - MinDividedByMax(fSet0.fSamples[a], fSet1.fSamples[b])); + + fMinDiff = (abs(fDiff) < abs(fMinDiff)) ? fDiff : fMinDiff; + + a += FfxInt32(fSet0.fSamples[a] < fSet1.fSamples[b]); + b += FfxInt32(fSet0.fSamples[a] >= fSet1.fSamples[b]); + } + else + { + fMinDiff = FSR3UPSCALER_FP16_MAX; + } + } + } + + return fMinDiff * FfxFloat32(fMinDiff < (FSR3UPSCALER_FP16_MAX - 1)); +} + +SampleSet GetCurrentLumaBilinearSamples(FfxFloat32x2 fUv) +{ + const FfxFloat32x2 fUvJittered = fUv + Jitter() / RenderSize(); + const FfxInt32x2 iBasePos = FfxInt32x2(floor(fUvJittered * RenderSize())); + + SampleSet fSet; + + for (FfxInt32 iSampleIndex = 0; iSampleIndex < SHADING_CHANGE_SET_SIZE; iSampleIndex++) { + const FfxInt32x2 iSamplePos = ClampLoad(iBasePos, iSampleOffsets[iSampleIndex], RenderSize()); + fSet.fSamples[iSampleIndex] = LoadCurrentLuma(iSamplePos) * Exposure(); + fSet.fSamples[iSampleIndex] = ffxPow(fSet.fSamples[iSampleIndex], fShadingChangeSamplePow); + fSet.fSamples[iSampleIndex] = ffxMax(fSet.fSamples[iSampleIndex], FSR3UPSCALER_EPSILON); + } + + return fSet; +} + +struct PreviousLumaBilinearSamplesData +{ + SampleSet fSet; + FfxBoolean bIsExistingSample; +}; + +PreviousLumaBilinearSamplesData GetPreviousLumaBilinearSamples(FfxFloat32x2 fUv, FfxFloat32x2 fMotionVector) +{ + PreviousLumaBilinearSamplesData data; + + const FfxFloat32x2 fUvJittered = fUv + PreviousFrameJitter() / PreviousFrameRenderSize(); + const FfxFloat32x2 fReprojectedUv = fUvJittered + fMotionVector; + + data.bIsExistingSample = IsUvInside(fReprojectedUv); + + if (data.bIsExistingSample) { + + const FfxInt32x2 iBasePos = FfxInt32x2(floor(fReprojectedUv * PreviousFrameRenderSize())); + + for (FfxInt32 iSampleIndex = 0; iSampleIndex < SHADING_CHANGE_SET_SIZE; iSampleIndex++) { + + const FfxInt32x2 iSamplePos = ClampLoad(iBasePos, iSampleOffsets[iSampleIndex], PreviousFrameRenderSize()); + data.fSet.fSamples[iSampleIndex] = LoadPreviousLuma(iSamplePos) * DeltaPreExposure() * Exposure(); + data.fSet.fSamples[iSampleIndex] = ffxPow(data.fSet.fSamples[iSampleIndex], fShadingChangeSamplePow); + data.fSet.fSamples[iSampleIndex] = ffxMax(data.fSet.fSamples[iSampleIndex], FSR3UPSCALER_EPSILON); + } + } + + return data; +} + +FfxFloat32 ComputeDiff(FfxInt32x2 iPxPos, FfxFloat32x2 fUv, FfxFloat32x2 fMotionVector) +{ + FfxFloat32 fMinDiff = 0.0f; + + const SampleSet fCurrentSamples = GetCurrentLumaBilinearSamples(fUv); + const PreviousLumaBilinearSamplesData previousData = GetPreviousLumaBilinearSamples(fUv, fMotionVector); + + if (previousData.bIsExistingSample) { + fMinDiff = ComputeMinimumDifference(iPxPos, fCurrentSamples, previousData.fSet); + } + + return fMinDiff; +} + +FfxFloat32x4 SpdLoadSourceImage(FfxFloat32x2 iPxPos, FfxUInt32 slice) +{ + const FfxInt32x2 iPxSamplePos = ClampLoad(FfxInt32x2(iPxPos), FfxInt32x2(0, 0), FfxInt32x2(RenderSize())); + const FfxFloat32x2 fDilatedMotionVector = LoadDilatedMotionVector(iPxSamplePos); + const FfxFloat32x2 fUv = (iPxSamplePos + 0.5f) / RenderSize(); + + const FfxFloat32 fScaledAndSignedLumaDiff = ComputeDiff(iPxSamplePos, fUv, fDilatedMotionVector); + + FfxFloat32x4 fOutput = FfxFloat32x4(0.0f, 0.0f, 0.0f, 0.0f); + fOutput[DIFFERENCE] = fScaledAndSignedLumaDiff; + fOutput[SIGN_SUM] = (fScaledAndSignedLumaDiff != 0.0f) ? sign(fScaledAndSignedLumaDiff) : 0.0f; + fOutput[MIP0_INDICATOR] = 1.0f; + + return fOutput; +} + +FfxFloat32x4 SpdLoad(FfxInt32x2 tex, FfxUInt32 slice) +{ + return FfxFloat32x4(RWLoadPyramid(tex, 5), 0, 0); +} + +FfxFloat32x4 SpdReduce4(FfxFloat32x4 v0, FfxFloat32x4 v1, FfxFloat32x4 v2, FfxFloat32x4 v3) +{ + return (v0 + v1 + v2 + v3) * 0.25f; +} + +void SpdStore(FfxInt32x2 pix, FfxFloat32x4 outValue, FfxUInt32 index, FfxUInt32 slice) +{ + if (index >= iShadingChangeMipStart) + { + StorePyramid(pix, outValue.xy, index); + } +} + +FfxFloat32x4 SpdLoadIntermediate(FfxUInt32 x, FfxUInt32 y) +{ + return FfxFloat32x4( + spdIntermediateR[x][y], + spdIntermediateG[x][y], + spdIntermediateB[x][y], + spdIntermediateA[x][y]); +} +void SpdStoreIntermediate(FfxUInt32 x, FfxUInt32 y, FfxFloat32x4 value) +{ + spdIntermediateR[x][y] = value.x; + spdIntermediateG[x][y] = value.y; + spdIntermediateB[x][y] = value.z; + spdIntermediateA[x][y] = value.w; +} + +#endif + +// define fetch and store functions Packed +#if FFX_HALF + +FFX_GROUPSHARED FfxFloat16x2 spdIntermediateRG[16][16]; +FFX_GROUPSHARED FfxFloat16x2 spdIntermediateBA[16][16]; + +FfxFloat16x4 SpdLoadSourceImageH(FfxFloat32x2 tex, FfxUInt32 slice) +{ + return FfxFloat16x4(0, 0, 0, 0); +} + +FfxFloat16x4 SpdLoadH(FfxInt32x2 p, FfxUInt32 slice) +{ + return FfxFloat16x4(0, 0, 0, 0); +} + +void SpdStoreH(FfxInt32x2 p, FfxFloat16x4 value, FfxUInt32 mip, FfxUInt32 slice) +{ +} + +FfxFloat16x4 SpdLoadIntermediateH(FfxUInt32 x, FfxUInt32 y) +{ + return FfxFloat16x4( + spdIntermediateRG[x][y].x, + spdIntermediateRG[x][y].y, + spdIntermediateBA[x][y].x, + spdIntermediateBA[x][y].y); +} + +void SpdStoreIntermediateH(FfxUInt32 x, FfxUInt32 y, FfxFloat16x4 value) +{ + spdIntermediateRG[x][y] = value.xy; + spdIntermediateBA[x][y] = value.zw; +} + +FfxFloat16x4 SpdReduce4H(FfxFloat16x4 v0, FfxFloat16x4 v1, FfxFloat16x4 v2, FfxFloat16x4 v3) +{ + return (v0 + v1 + v2 + v3) * FfxFloat16(0.25); +} +#endif + +#include "spd/ffx_spd.h" + +void ComputeShadingChangePyramid(FfxUInt32x3 WorkGroupId, FfxUInt32 LocalThreadIndex) +{ +#if FFX_HALF + SpdDownsampleH( + FfxUInt32x2(WorkGroupId.xy), + FfxUInt32(LocalThreadIndex), + FfxUInt32(MipCount()), + FfxUInt32(NumWorkGroups()), + FfxUInt32(WorkGroupId.z), + FfxUInt32x2(WorkGroupOffset())); +#else + SpdDownsample( + FfxUInt32x2(WorkGroupId.xy), + FfxUInt32(LocalThreadIndex), + FfxUInt32(MipCount()), + FfxUInt32(NumWorkGroups()), + FfxUInt32(WorkGroupId.z), + FfxUInt32x2(WorkGroupOffset())); +#endif +} diff --git a/externals/FidelityFX-SDK/include/FidelityFX/gpu/fsr3upscaler/ffx_fsr3upscaler_upsample.h b/externals/FidelityFX-SDK/include/FidelityFX/gpu/fsr3upscaler/ffx_fsr3upscaler_upsample.h new file mode 100644 index 0000000000..801a0a907e --- /dev/null +++ b/externals/FidelityFX-SDK/include/FidelityFX/gpu/fsr3upscaler/ffx_fsr3upscaler_upsample.h @@ -0,0 +1,644 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and /or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +void Deringing(RectificationBox clippingBox, FFX_PARAMETER_INOUT FfxFloat32x3 fColor) +{ + fColor = clamp(fColor, clippingBox.aabbMin, clippingBox.aabbMax); +} + +#ifndef FFX_FSR3UPSCALER_OPTION_UPSAMPLE_USE_LANCZOS_TYPE +#define FFX_FSR3UPSCALER_OPTION_UPSAMPLE_USE_LANCZOS_TYPE 2 // Approximate +#endif + +FfxFloat32 GetUpsampleLanczosWeight(FfxFloat32x2 fSrcSampleOffset, FfxFloat32 fKernelWeight) +{ + FfxFloat32x2 fSrcSampleOffsetBiased = fSrcSampleOffset * fKernelWeight.xx; +#if FFX_FSR3UPSCALER_OPTION_UPSAMPLE_USE_LANCZOS_TYPE == 0 // LANCZOS_TYPE_REFERENCE + FfxFloat32 fSampleWeight = Lanczos2(length(fSrcSampleOffsetBiased)); +#elif FFX_FSR3UPSCALER_OPTION_UPSAMPLE_USE_LANCZOS_TYPE == 1 // LANCZOS_TYPE_LUT + FfxFloat32 fSampleWeight = Lanczos2_UseLUT(length(fSrcSampleOffsetBiased)); +#elif FFX_FSR3UPSCALER_OPTION_UPSAMPLE_USE_LANCZOS_TYPE == 2 // LANCZOS_TYPE_APPROXIMATE + FfxFloat32 fSampleWeight = Lanczos2ApproxSq(dot(fSrcSampleOffsetBiased, fSrcSampleOffsetBiased)); +#else +#error "Invalid Lanczos type" +#endif + return fSampleWeight; +} + +#if FFX_HALF +FFX_MIN16_F GetUpsampleLanczosWeight(FFX_MIN16_F2 fSrcSampleOffset, FFX_MIN16_F fKernelWeight) +{ + FFX_MIN16_F2 fSrcSampleOffsetBiased = fSrcSampleOffset * fKernelWeight.xx; +#if FFX_FSR3UPSCALER_OPTION_UPSAMPLE_USE_LANCZOS_TYPE == 0 // LANCZOS_TYPE_REFERENCE + FFX_MIN16_F fSampleWeight = Lanczos2(length(fSrcSampleOffsetBiased)); +#elif FFX_FSR3UPSCALER_OPTION_UPSAMPLE_USE_LANCZOS_TYPE == 1 // LANCZOS_TYPE_LUT + FFX_MIN16_F fSampleWeight = Lanczos2_UseLUT(length(fSrcSampleOffsetBiased)); +#elif FFX_FSR3UPSCALER_OPTION_UPSAMPLE_USE_LANCZOS_TYPE == 2 // LANCZOS_TYPE_APPROXIMATE + FFX_MIN16_F fSampleWeight = Lanczos2ApproxSq(dot(fSrcSampleOffsetBiased, fSrcSampleOffsetBiased)); + + // To Test: Save reciproqual sqrt compute + // FfxFloat32 fSampleWeight = Lanczos2Sq_UseLUT(dot(fSrcSampleOffsetBiased, fSrcSampleOffsetBiased)); +#else +#error "Invalid Lanczos type" +#endif + return fSampleWeight; +} +#endif + +FfxFloat32 ComputeMaxKernelWeight(const AccumulationPassCommonParams params, FFX_PARAMETER_INOUT AccumulationPassData data) { + + const FfxFloat32 fKernelSizeBias = 1.0f + (1.0f / FfxFloat32x2(DownscaleFactor()) - 1.0f).x; + + return ffxMin(FfxFloat32(1.99f), fKernelSizeBias); +} + +FfxFloat32x3 LoadPreparedColor(FfxInt32x2 iSamplePos) +{ + const FfxFloat32x3 fRgb = ffxMax(FfxFloat32x3(0, 0, 0), LoadInputColor(iSamplePos)) * Exposure(); + const FfxFloat32x3 fPreparedYCoCg = RGBToYCoCg(fRgb); + + return fPreparedYCoCg; +} + +#if FFX_HALF && (FFX_FSR3UPSCALER_OPTION_UPSAMPLE_USE_LANCZOS_TYPE == 2) && defined(__XBOX_SCARLETT) && defined(__XBATG_EXTRA_16_BIT_OPTIMISATION) && (__XBATG_EXTRA_16_BIT_OPTIMISATION == 1) +#define FFX_FSR3UPSCALER_USE_XBOX_PAIRED_16BIT_MATH_OPTIMIZATIONS 1 +#else +#define FFX_FSR3UPSCALER_USE_XBOX_PAIRED_16BIT_MATH_OPTIMIZATIONS 0 +#endif + +#if FFX_FSR3UPSCALER_USE_XBOX_PAIRED_16BIT_MATH_OPTIMIZATIONS + +void LoadPreparedColorPairedRgb(FFX_PARAMETER_OUT FFX_MIN16_F2 r, + FFX_PARAMETER_OUT FFX_MIN16_F2 g, + FFX_PARAMETER_OUT FFX_MIN16_F2 b, + FfxInt32x2 iSamplePos0, + FfxInt32x2 iSamplePos1) +{ + const FFX_MIN16_F3 sample0 = FFX_MIN16_F3(LoadInputColor(iSamplePos0)); + const FFX_MIN16_F3 sample1 = FFX_MIN16_F3(LoadInputColor(iSamplePos1)); + + r = ffxMax(FFX_MIN16_F2(0, 0), FFX_MIN16_F2(sample0.r, sample1.r)); + g = ffxMax(FFX_MIN16_F2(0, 0), FFX_MIN16_F2(sample0.g, sample1.g)); + b = ffxMax(FFX_MIN16_F2(0, 0), FFX_MIN16_F2(sample0.b, sample1.b)); + + r = FFX_MIN16_F2(r * Exposure()); + g = FFX_MIN16_F2(g * Exposure()); + b = FFX_MIN16_F2(b * Exposure()); +} + +void TonemapPaired(FFX_PARAMETER_INOUT FFX_MIN16_F2 r, FFX_PARAMETER_INOUT FFX_MIN16_F2 g, FFX_PARAMETER_INOUT FFX_MIN16_F2 b) +{ + FFX_MIN16_F2 denomF16 = ffxMax(ffxMax(ffxMax(0.0, r), g), b) + FFX_MIN16_F2(1.0, 1.0); + + // NOTE: expect 2 x v_cvt_f32_f16 + FfxFloat32x2 denomF32 = FfxFloat32x2(denomF16); + // NOTE: expect 2 x v_rcp_f32 + FfxFloat32x2 normF32 = FfxFloat32x2(1.0, 1.0) / denomF32; + // NOTE: expect 2 x v_cvt_f16_f32 + FFX_MIN16_F2 normF16 = FFX_MIN16_F2(normF32); + + r *= normF16; + g *= normF16; + b *= normF16; +} + +void RGBToYCoCgPaired(FFX_PARAMETER_INOUT FFX_MIN16_F2 r, FFX_PARAMETER_INOUT FFX_MIN16_F2 g, FFX_PARAMETER_INOUT FFX_MIN16_F2 b) +{ + /** + * NOTE: given the following conversion + * + * fYCoCg = FfxFloat32x3( + * 0.25f * fRgb.r + 0.5f * fRgb.g + 0.25f * fRgb.b, + * 0.5f * fRgb.r - 0.5f * fRgb.b, + * -0.25f * fRgb.r + 0.5f * fRgb.g - 0.25f * fRgb.b); + * + * it's possible to notice that we can compute: + * RplusBdiv4 = 0.25 * (R + B) + * + * so everything else is computed in 3 instructions + * Y = G * 0.5 + RplusBdiv4 + * Co = 2 * RplusBdiv4 - G + * Cg = G * 0.5 - RplusBdiv4 + */ + + // NOTE: expect v_pk_add_f32 + v_pk_mul_f32 + FFX_MIN16_F2 RplusBdiv4 = (r + b) * 0.25; + FFX_MIN16_F2 G = g; + FFX_MIN16_F2 B = b; + + // NOTE: expect 3x v_pk_fma_f32 + r = G * 0.5 + RplusBdiv4; + g = RplusBdiv4 * 2.0 - B; + b = G * 0.5 - RplusBdiv4; +} + +FFX_MIN16_F2 Compute3x3SamplesMinMaxPaired(FFX_PARAMETER_IN FFX_MIN16_F2 sampleCenter, + FFX_PARAMETER_IN FFX_MIN16_F2 sample0, + FFX_PARAMETER_IN FFX_MIN16_F2 sample1, + FFX_PARAMETER_IN FFX_MIN16_F2 sample2, + FFX_PARAMETER_IN FFX_MIN16_F2 sample3) +{ + FFX_MIN16_F2 twoMinValues = ffxMin(ffxMin(sample0, sample1), ffxMin(sample2, sample3)); + FFX_MIN16_F2 twoMaxValues = ffxMax(ffxMax(sample0, sample1), ffxMax(sample2, sample3)); + + return FFX_MIN16_F2( + ffxMin3Half(twoMinValues.x, twoMinValues.y, sampleCenter.x), + ffxMax3Half(twoMaxValues.x, twoMaxValues.y, sampleCenter.x) + ); +} + + +FFX_MIN16_F2 Bool2ToFloat16x2(bool x, bool y) +{ + uint lo = x ? 0x00003c00 : 0x00000000; + uint hi = y ? 0x3c000000 : 0x00000000; + return FFX_MIN16_F2(__XB_AsHalf(lo).x, __XB_AsHalf(hi).y); +} + +struct PairedRectificationBoxAndAccumulatedColorAndWeight +{ + FFX_MIN16_F2 boxCenterR; + FFX_MIN16_F2 boxCenterG; + FFX_MIN16_F2 boxCenterB; + + FFX_MIN16_F2 boxVecR; + FFX_MIN16_F2 boxVecG; + FFX_MIN16_F2 boxVecB; + + FFX_MIN16_F2 fBoxCenterWeight; + + FFX_MIN16_F2 fColorR; + FFX_MIN16_F2 fColorG; + FFX_MIN16_F2 fColorB; + FFX_MIN16_F2 fWeight; + + FFX_MIN16_F fKernelBiasSq; + FFX_MIN16_F fRectificationCurveBias; + + void setKernelBiasAndRectificationCurveBias(FfxFloat32 kernelBias, FfxFloat32 rectificationCurveBias) + { + fKernelBiasSq = FFX_MIN16_F(kernelBias * kernelBias); + fRectificationCurveBias = FFX_MIN16_F(rectificationCurveBias); + } + + void initUpscaledColor(FFX_MIN16_F fSrcSampleOffsetSq, FFX_MIN16_F fOnScreenWeight, FFX_MIN16_F2 sampleR, FFX_MIN16_F2 sampleG, FFX_MIN16_F2 sampleB) + { + #if FFX_FSR3UPSCALER_OPTION_UPSAMPLE_USE_LANCZOS_TYPE == 2 // LANCZOS_TYPE_APPROXIMATE + const FFX_MIN16_F2 LanczosUpsampleWeight = FFX_MIN16_F2( + PairedLanczos2ApproxSq(fSrcSampleOffsetSq * fKernelBiasSq).x, + 0.0 + ); + #else + #error "Only LANCZOS_TYPE_APPROXIMATE is supported in paired version so far" + #endif + const FFX_MIN16_F2 fSampleWeight = fOnScreenWeight * LanczosUpsampleWeight; + + fColorR = sampleR * fSampleWeight; + fColorG = sampleG * fSampleWeight; + fColorB = sampleB * fSampleWeight; + fWeight = fSampleWeight; + } + + void initBox(FFX_MIN16_F fSrcSampleOffsetSq, FFX_MIN16_F fOnScreenWeight, FFX_MIN16_F2 sampleR, FFX_MIN16_F2 sampleG, FFX_MIN16_F2 sampleB) + { + const FFX_MIN16_F2 fBoxSampleWeight = FFX_MIN16_F2( + exp(fRectificationCurveBias * fSrcSampleOffsetSq) * fOnScreenWeight, + 0.0 + ); + + FFX_MIN16_F2 weightedSampleR = sampleR * fBoxSampleWeight; + FFX_MIN16_F2 weightedSampleG = sampleG * fBoxSampleWeight; + FFX_MIN16_F2 weightedSampleB = sampleB * fBoxSampleWeight; + + boxCenterR = weightedSampleR; + boxCenterG = weightedSampleG; + boxCenterB = weightedSampleB; + + boxVecR = sampleR * weightedSampleR; + boxVecG = sampleG * weightedSampleG; + boxVecB = sampleB * weightedSampleB; + + fBoxCenterWeight = fBoxSampleWeight; + } + + void addUpscaledColorSample(FFX_MIN16_F2 fSrcSampleOffsetSq, FFX_MIN16_F2 fOnScreenWeight, FFX_MIN16_F2 sampleR, FFX_MIN16_F2 sampleG, FFX_MIN16_F2 sampleB) + { + #if FFX_FSR3UPSCALER_OPTION_UPSAMPLE_USE_LANCZOS_TYPE == 2 // LANCZOS_TYPE_APPROXIMATE + const FFX_MIN16_F2 LanczosUpsampleWeight = PairedLanczos2ApproxSq(fSrcSampleOffsetSq * fKernelBiasSq); + #else + #error "Only LANCZOS_TYPE_APPROXIMATE is supported in paired version so far" + #endif + const FFX_MIN16_F2 fSampleWeight = fOnScreenWeight * LanczosUpsampleWeight; + + fColorR += sampleR * fSampleWeight; + fColorG += sampleG * fSampleWeight; + fColorB += sampleB * fSampleWeight; + fWeight += fSampleWeight; + } + + void addBoxSample(FFX_MIN16_F2 fSrcSampleOffsetSq, FFX_MIN16_F2 fOnScreenWeight, FFX_MIN16_F2 sampleR, FFX_MIN16_F2 sampleG, FFX_MIN16_F2 sampleB) + { + // NOTE: ideally expect here 2x v_fma_mix + 2x v_exp_f32 + 2x v_fma_mix + const FFX_MIN16_F2 fBoxSampleWeight = exp(fRectificationCurveBias * fSrcSampleOffsetSq) * fOnScreenWeight; + + FFX_MIN16_F2 weightedSampleR = sampleR * fBoxSampleWeight; + FFX_MIN16_F2 weightedSampleG = sampleG * fBoxSampleWeight; + FFX_MIN16_F2 weightedSampleB = sampleB * fBoxSampleWeight; + + boxCenterR += weightedSampleR; + boxCenterG += weightedSampleG; + boxCenterB += weightedSampleB; + + boxVecR += sampleR * weightedSampleR; + boxVecG += sampleG * weightedSampleG; + boxVecB += sampleB * weightedSampleB; + + fBoxCenterWeight += fBoxSampleWeight; + } + + void finalizeUpscaledColor(FFX_PARAMETER_OUT FfxFloat32x4 upscaledColorAndWeight) + { + upscaledColorAndWeight.r = fColorR.x + fColorR.y; + upscaledColorAndWeight.g = fColorG.x + fColorG.y; + upscaledColorAndWeight.b = fColorB.x + fColorB.y; + + upscaledColorAndWeight.a = fWeight.x + fWeight.y; + } + + void finalizeBox(FFX_PARAMETER_OUT FfxFloat32x2 boxCenterAndVecR, + FFX_PARAMETER_OUT FfxFloat32x2 boxCenterAndVecG, + FFX_PARAMETER_OUT FfxFloat32x2 boxCenterAndVecB, + FFX_PARAMETER_OUT FfxFloat32 boxCenterWeight) + { + boxCenterAndVecR = FfxFloat32x2(boxCenterR.x + boxCenterR.y, boxVecR.x + boxVecR.y); + boxCenterAndVecG = FfxFloat32x2(boxCenterG.x + boxCenterG.y, boxVecG.x + boxVecG.y); + boxCenterAndVecB = FfxFloat32x2(boxCenterB.x + boxCenterB.y, boxVecB.x + boxVecB.y); + + boxCenterWeight = fBoxCenterWeight.x + fBoxCenterWeight.y; + } +}; +#endif // #if FFX_FSR3UPSCALER_USE_XBOX_PAIRED_16BIT_MATH_OPTIMIZATIONS + +void ComputeUpsampledColorAndWeight(const AccumulationPassCommonParams params, FFX_PARAMETER_INOUT AccumulationPassData data) +{ + // We compute a sliced lanczos filter with 2 lobes (other slices are accumulated temporaly) + const FfxFloat32x2 fDstOutputPos = FfxFloat32x2(params.iPxHrPos) + FFX_BROADCAST_FLOAT32X2(0.5f); + const FfxFloat32x2 fSrcOutputPos = fDstOutputPos * DownscaleFactor(); + const FfxInt32x2 iSrcInputPos = FfxInt32x2(floor(fSrcOutputPos)); + const FfxFloat32x2 fSrcUnjitteredPos = (FfxFloat32x2(iSrcInputPos) + FfxFloat32x2(0.5f, 0.5f)) - Jitter(); // This is the un-jittered position of the sample at offset 0,0 + const FfxFloat32x2 fBaseSampleOffset = FfxFloat32x2(fSrcUnjitteredPos - fSrcOutputPos); + + FfxInt32x2 offsetTL; + offsetTL.x = (fSrcUnjitteredPos.x > fSrcOutputPos.x) ? FfxInt32(-2) : FfxInt32(-1); + offsetTL.y = (fSrcUnjitteredPos.y > fSrcOutputPos.y) ? FfxInt32(-2) : FfxInt32(-1); + + //Load samples + // If fSrcUnjitteredPos.y > fSrcOutputPos.y, indicates offsetTL.y = -2, sample offset Y will be [-2, 1], clipbox will be rows [1, 3]. + // Flip row# for sampling offset in this case, so first 0~2 rows in the sampled array can always be used for computing the clipbox. + // This reduces branch or cmove on sampled colors, but moving this overhead to sample position / weight calculation time which apply to less values. + const FfxBoolean bFlipRow = fSrcUnjitteredPos.y > fSrcOutputPos.y; + const FfxBoolean bFlipCol = fSrcUnjitteredPos.x > fSrcOutputPos.x; + const FfxFloat32x2 fOffsetTL = FfxFloat32x2(offsetTL); + + const FfxBoolean bIsInitialSample = (params.fAccumulation == 0.0f); + +#if FFX_FSR3UPSCALER_USE_XBOX_PAIRED_16BIT_MATH_OPTIMIZATIONS + // Unroll the loop to load samples on Scarlett to help the shader compiler + const FFX_MIN16_F2 fSampleOffsetX02 = __XB_AsHalf(bFlipCol ? __XB_AsUInt(FFX_MIN16_F2( 1, -1)) : __XB_AsUInt(FFX_MIN16_F2(-1, 1))); + const FFX_MIN16_F2 fSampleOffsetY02 = __XB_AsHalf(bFlipRow ? __XB_AsUInt(FFX_MIN16_F2( 1, -1)) : __XB_AsUInt(FFX_MIN16_F2(-1, 1))); + + typedef FfxInt32 FfxTexCoordI; + typedef FfxInt32x2 FfxTexCoordI2; + + const FfxTexCoordI2 iSrcSamplePosX01 = FfxTexCoordI2(iSrcInputPos.xx) + (bFlipCol ? FfxTexCoordI2( 1, 0) : FfxTexCoordI2(-1, 0)); + const FfxTexCoordI2 iSrcSamplePosX23 = FfxTexCoordI2(iSrcInputPos.xx) + (bFlipCol ? FfxTexCoordI2(-1, -2) : FfxTexCoordI2( 1, 2)); + + const FfxTexCoordI2 iSrcSamplePosY01 = FfxTexCoordI2(iSrcInputPos.yy) + (bFlipRow ? FfxTexCoordI2( 1, 0) : FfxTexCoordI2(-1, 0)); + const FfxTexCoordI2 iSrcSamplePosY23 = FfxTexCoordI2(iSrcInputPos.yy) + (bFlipRow ? FfxTexCoordI2(-1, -2) : FfxTexCoordI2( 1, 2)); + + const FfxTexCoordI2 renderSizeLastTexelCoord = FfxTexCoordI2(RenderSize()) - FfxTexCoordI2(1, 1); + + const FfxTexCoordI2 iSrcSamplePosX01Clamped = FfxTexCoordI2( + __XB_Med3_I32(iSrcSamplePosX01.x, 0, renderSizeLastTexelCoord.x), + __XB_Med3_I32(iSrcSamplePosX01.y, 0, renderSizeLastTexelCoord.x) + ); + + const FfxTexCoordI2 iSrcSamplePosX23Clamped = FfxTexCoordI2( + __XB_Med3_I32(iSrcSamplePosX23.x, 0, renderSizeLastTexelCoord.x), + __XB_Med3_I32(iSrcSamplePosX23.y, 0, renderSizeLastTexelCoord.x) + ); + + const FfxTexCoordI2 iSrcSamplePosY01Clamped = FfxTexCoordI2( + __XB_Med3_I32(iSrcSamplePosY01.x, 0, renderSizeLastTexelCoord.y), + __XB_Med3_I32(iSrcSamplePosY01.y, 0, renderSizeLastTexelCoord.y) + ); + + const FfxTexCoordI2 iSrcSamplePosY23Clamped = FfxTexCoordI2( + __XB_Med3_I32(iSrcSamplePosY23.x, 0, renderSizeLastTexelCoord.y), + __XB_Med3_I32(iSrcSamplePosY23.y, 0, renderSizeLastTexelCoord.y) + ); + + FFX_MIN16_F2 TopCornerR, BotCornerR, HorzR, VertR, CenterR; + FFX_MIN16_F2 TopCornerG, BotCornerG, HorzG, VertG, CenterG; + FFX_MIN16_F2 TopCornerB, BotCornerB, HorzB, VertB, CenterB; + + LoadPreparedColorPairedRgb(TopCornerR, TopCornerG, TopCornerB, + FfxTexCoordI2(iSrcSamplePosX01Clamped.x, iSrcSamplePosY01Clamped.x), + FfxTexCoordI2(iSrcSamplePosX23Clamped.x, iSrcSamplePosY01Clamped.x) + ); + + LoadPreparedColorPairedRgb(BotCornerR, BotCornerG, BotCornerB, + FfxTexCoordI2(iSrcSamplePosX01Clamped.x, iSrcSamplePosY23Clamped.x), + FfxTexCoordI2(iSrcSamplePosX23Clamped.x, iSrcSamplePosY23Clamped.x) + ); + + LoadPreparedColorPairedRgb(HorzR, HorzG, HorzB, + FfxTexCoordI2(iSrcSamplePosX01Clamped.x, iSrcSamplePosY01Clamped.y), + FfxTexCoordI2(iSrcSamplePosX23Clamped.x, iSrcSamplePosY01Clamped.y) + ); + + LoadPreparedColorPairedRgb(VertR, VertG, VertB, + FfxTexCoordI2(iSrcSamplePosX01Clamped.y, iSrcSamplePosY01Clamped.x), + FfxTexCoordI2(iSrcSamplePosX01Clamped.y, iSrcSamplePosY23Clamped.x) + ); + + // NOTE: duplicated data + LoadPreparedColorPairedRgb(CenterR, CenterG, CenterB, + FfxTexCoordI2(iSrcSamplePosX01Clamped.y, iSrcSamplePosY01Clamped.y), + FfxTexCoordI2(iSrcSamplePosX01Clamped.y, iSrcSamplePosY01Clamped.y) + ); + + #if FFX_FSR3UPSCALER_OPTION_HDR_COLOR_INPUT + if (bIsInitialSample) + { + TonemapPaired(TopCornerR, TopCornerG, TopCornerB); + TonemapPaired(BotCornerR, BotCornerG, BotCornerB); + TonemapPaired(HorzR, HorzG, HorzB); + TonemapPaired(VertR, VertG, VertB); + TonemapPaired(CenterR, CenterG, CenterB); + } + #endif + + RGBToYCoCgPaired(TopCornerR, TopCornerG, TopCornerB); + RGBToYCoCgPaired(BotCornerR, BotCornerG, BotCornerB); + RGBToYCoCgPaired(HorzR, HorzG, HorzB); + RGBToYCoCgPaired(VertR, VertG, VertB); + RGBToYCoCgPaired(CenterR, CenterG, CenterB); + +#else + FfxFloat32x3 fSamples[9]; + FfxInt32 iSampleIndex = 0; + + FFX_UNROLL + for (FfxInt32 row = 0; row < 3; row++) { + FFX_UNROLL + for (FfxInt32 col = 0; col < 3; col++) { + const FfxInt32x2 iSampleColRow = FfxInt32x2(bFlipCol ? (3 - col) : col, bFlipRow ? (3 - row) : row); + const FfxInt32x2 iSrcSamplePos = FfxInt32x2(iSrcInputPos) + offsetTL + iSampleColRow; + const FfxInt32x2 iSampleCoord = ClampLoad(iSrcSamplePos, FfxInt32x2(0, 0), FfxInt32x2(RenderSize())); + + fSamples[iSampleIndex] = LoadPreparedColor(iSampleCoord); + + ++iSampleIndex; + } + } + +#if FFX_FSR3UPSCALER_OPTION_HDR_COLOR_INPUT + if (bIsInitialSample) + { + for (iSampleIndex = 0; iSampleIndex < 9; ++iSampleIndex) + { + //YCoCg -> RGB -> Tonemap -> YCoCg (Use RGB tonemapper to avoid color desaturation) + fSamples[iSampleIndex] = RGBToYCoCg(Tonemap(YCoCgToRGB(fSamples[iSampleIndex]))); + } + } +#endif + +#endif // #if FFX_FSR3UPSCALER_USE_XBOX_PAIRED_16BIT_MATH_OPTIMIZATIONS + + // Identify how much of each upsampled color to be used for this frame + const FfxFloat32 fKernelBiasMax = ComputeMaxKernelWeight(params, data); + const FfxFloat32 fKernelBiasMin = ffxMax(1.0f, ((1.0f + fKernelBiasMax) * 0.3f)); + + const FfxFloat32 fKernelBiasWeight = + ffxMin(1.0f - params.fDisocclusion * 0.5f, + ffxMin(1.0f - params.fShadingChange, + ffxSaturate(data.fHistoryWeight * 5.0f) + )); + + const FfxFloat32 fKernelBias = ffxLerp(fKernelBiasMin, fKernelBiasMax, fKernelBiasWeight); + +#if FFX_FSR3UPSCALER_USE_XBOX_PAIRED_16BIT_MATH_OPTIMIZATIONS + // Unroll the loop to load samples on Scarlett to help the shader compiler + const bool coordX0OnScreen = iSrcSamplePosX01.x == iSrcSamplePosX01Clamped.x; + const bool coordX1OnScreen = iSrcSamplePosX01.y == iSrcSamplePosX01Clamped.y; + const bool coordX2OnScreen = iSrcSamplePosX23.x == iSrcSamplePosX23Clamped.x; + + const bool coordY0OnScreen = iSrcSamplePosY01.x == iSrcSamplePosY01Clamped.x; + const bool coordY1OnScreen = iSrcSamplePosY01.y == iSrcSamplePosY01Clamped.y; + const bool coordY2OnScreen = iSrcSamplePosY23.x == iSrcSamplePosY23Clamped.x; + + const FFX_MIN16_F2 fBaseSampleOffsetHalf = FFX_MIN16_F2(fBaseSampleOffset); + + const FFX_MIN16_F2 fSrcSampleOffsetX_02 = fBaseSampleOffsetHalf.xx + fSampleOffsetX02; + const FFX_MIN16_F2 fSrcSampleOffsetY_02 = fBaseSampleOffsetHalf.yy + fSampleOffsetY02; + + const FFX_MIN16_F2 fSrcSampleOffsetXSq_02 = fSrcSampleOffsetX_02 * fSrcSampleOffsetX_02; + const FFX_MIN16_F2 fSrcSampleOffsetYSq_02 = fSrcSampleOffsetY_02 * fSrcSampleOffsetY_02; + const FFX_MIN16_F2 fSrcSampleOffsetXYSq_11 = fBaseSampleOffsetHalf * fBaseSampleOffsetHalf; + + const FfxFloat32 fRectificationCurveBias = -2.3f; + PairedRectificationBoxAndAccumulatedColorAndWeight pairedBox; + pairedBox.setKernelBiasAndRectificationCurveBias(fKernelBias, fRectificationCurveBias); + + // init by o o o + // o x o + // o o o + pairedBox.initBox( + fSrcSampleOffsetXYSq_11.x + fSrcSampleOffsetXYSq_11.y, + Bool2ToFloat16x2(coordX1OnScreen && coordY1OnScreen, false).x, + CenterR, CenterG, CenterB + ); + + // add remaining two samples from 1st row x o x + // o * o + // o o o + pairedBox.addBoxSample( + fSrcSampleOffsetXSq_02 + fSrcSampleOffsetYSq_02.xx, + Bool2ToFloat16x2(coordX0OnScreen && coordY0OnScreen, coordX2OnScreen && coordY0OnScreen), + TopCornerR, TopCornerG, TopCornerB + ); + + // add two samples from 2nd row * o * + // o * o + // x o x + pairedBox.addBoxSample( + fSrcSampleOffsetXSq_02 + fSrcSampleOffsetYSq_02.yy, + Bool2ToFloat16x2(coordX0OnScreen && coordY2OnScreen, coordX2OnScreen && coordY2OnScreen), + BotCornerR, BotCornerG, BotCornerB + ); + + // add two samples from 3rd row * o * + // x * x + // * o * + pairedBox.addBoxSample( + fSrcSampleOffsetXSq_02 + fSrcSampleOffsetXYSq_11.yy, + Bool2ToFloat16x2(coordX0OnScreen && coordY1OnScreen, coordX2OnScreen && coordY1OnScreen), + HorzR, HorzG, HorzB + ); + + // add remaining samples * x * + // * * * + // * x * + pairedBox.addBoxSample( + fSrcSampleOffsetXYSq_11.xx + fSrcSampleOffsetYSq_02, + Bool2ToFloat16x2(coordX1OnScreen && coordY0OnScreen, coordX1OnScreen && coordY2OnScreen), + VertR, VertG, VertB + ); + + FfxFloat32x2 boxCenterAndVecR, boxCenterAndVecG, boxCenterAndVecB; + FfxFloat32 boxCenterWeight; + pairedBox.finalizeBox(boxCenterAndVecR, boxCenterAndVecG, boxCenterAndVecB, boxCenterWeight); + + if (!bIsInitialSample) + { + pairedBox.initUpscaledColor( + fSrcSampleOffsetXYSq_11.x + fSrcSampleOffsetXYSq_11.y, + Bool2ToFloat16x2(coordX1OnScreen && coordY1OnScreen, false).x, + CenterR, CenterG, CenterB + ); + + // add remaining two samples from 1st row x o x + // o * o + // o o o + pairedBox.addUpscaledColorSample( + fSrcSampleOffsetXSq_02 + fSrcSampleOffsetYSq_02.xx, + Bool2ToFloat16x2(coordX0OnScreen && coordY0OnScreen, coordX2OnScreen && coordY0OnScreen), + TopCornerR, TopCornerG, TopCornerB + ); + + // add two samples from 2nd row * o * + // o * o + // x o x + pairedBox.addUpscaledColorSample( + fSrcSampleOffsetXSq_02 + fSrcSampleOffsetYSq_02.yy, + Bool2ToFloat16x2(coordX0OnScreen && coordY2OnScreen, coordX2OnScreen && coordY2OnScreen), + BotCornerR, BotCornerG, BotCornerB + ); + + // add two samples from 3rd row * o * + // x * x + // * o * + pairedBox.addUpscaledColorSample( + fSrcSampleOffsetXSq_02 + fSrcSampleOffsetXYSq_11.yy, + Bool2ToFloat16x2(coordX0OnScreen && coordY1OnScreen, coordX2OnScreen && coordY1OnScreen), + HorzR, HorzG, HorzB + ); + + // add remaining samples * x * + // * * * + // * x * + pairedBox.addUpscaledColorSample( + fSrcSampleOffsetXYSq_11.xx + fSrcSampleOffsetYSq_02, + Bool2ToFloat16x2(coordX1OnScreen && coordY0OnScreen, coordX1OnScreen && coordY2OnScreen), + VertR, VertG, VertB + ); + + FfxFloat32x4 upscaledColorAndWeight = 0.0; + pairedBox.finalizeUpscaledColor(upscaledColorAndWeight); + + data.fUpsampledColor = FfxFloat32x3(upscaledColorAndWeight.rgb); + data.fUpsampledWeight = FfxFloat32(upscaledColorAndWeight.w); + } + + FFX_MIN16_F2 aabbMinMaxR = Compute3x3SamplesMinMaxPaired(CenterR, TopCornerR, BotCornerR, HorzR, VertR); + FFX_MIN16_F2 aabbMinMaxG = Compute3x3SamplesMinMaxPaired(CenterG, TopCornerG, BotCornerG, HorzG, VertG); + FFX_MIN16_F2 aabbMinMaxB = Compute3x3SamplesMinMaxPaired(CenterB, TopCornerB, BotCornerB, HorzB, VertB); + + data.clippingBox.boxCenter = FfxFloat32x3(boxCenterAndVecR.x, boxCenterAndVecG.x, boxCenterAndVecB.x); + data.clippingBox.boxVec = FfxFloat32x3(boxCenterAndVecR.y, boxCenterAndVecG.y, boxCenterAndVecB.y); + data.clippingBox.aabbMin = FfxFloat32x3(aabbMinMaxR.x, aabbMinMaxG.x, aabbMinMaxB.x); + data.clippingBox.aabbMax = FfxFloat32x3(aabbMinMaxR.y, aabbMinMaxG.y, aabbMinMaxB.y); + data.clippingBox.fBoxCenterWeight = FfxFloat32(boxCenterWeight); +#else + + iSampleIndex = 0; + + FFX_UNROLL + for (FfxInt32 row = 0; row < 3; row++) + { + FFX_UNROLL + for (FfxInt32 col = 0; col < 3; col++) + { + const FfxInt32x2 sampleColRow = FfxInt32x2(bFlipCol ? (3 - col) : col, bFlipRow ? (3 - row) : row); + const FfxFloat32x2 fOffset = fOffsetTL + FfxFloat32x2(sampleColRow); + const FfxFloat32x2 fSrcSampleOffset = fBaseSampleOffset + fOffset; + + const FfxInt32x2 iSrcSamplePos = FfxInt32x2(iSrcInputPos) + FfxInt32x2(offsetTL) + sampleColRow; + const FfxFloat32 fOnScreenFactor = FfxFloat32(IsOnScreen(FfxInt32x2(iSrcSamplePos), FfxInt32x2(RenderSize()))); + + if (!bIsInitialSample) + { + const FfxFloat32 fSampleWeight = fOnScreenFactor * FfxFloat32(GetUpsampleLanczosWeight(fSrcSampleOffset, fKernelBias)); + + data.fUpsampledColor += fSamples[iSampleIndex] * fSampleWeight; + data.fUpsampledWeight += fSampleWeight; + } + + // Update rectification box + { + const FfxFloat32 fRectificationCurveBias = -2.3f; + const FfxFloat32 fSrcSampleOffsetSq = dot(fSrcSampleOffset, fSrcSampleOffset); + const FfxFloat32 fBoxSampleWeight = exp(fRectificationCurveBias * fSrcSampleOffsetSq) * fOnScreenFactor; + + const FfxBoolean bInitialSample = (row == 0) && (col == 0); + RectificationBoxAddSample(bInitialSample, data.clippingBox, fSamples[iSampleIndex], fBoxSampleWeight); + } + ++iSampleIndex; + } + } + +#endif // #if FFX_FSR3UPSCALER_USE_XBOX_PAIRED_16BIT_MATH_OPTIMIZATIONS + + RectificationBoxComputeVarianceBoxData(data.clippingBox); + + data.fUpsampledWeight *= FfxFloat32(data.fUpsampledWeight > FSR3UPSCALER_EPSILON); + + if (data.fUpsampledWeight > FSR3UPSCALER_EPSILON) { + // Normalize for deringing (we need to compare colors) + data.fUpsampledColor = data.fUpsampledColor / data.fUpsampledWeight; + data.fUpsampledWeight *= fAverageLanczosWeightPerFrame; + + Deringing(data.clippingBox, data.fUpsampledColor); + } + + // Initial samples using tonemapped upsampling + if (bIsInitialSample) { +#if FFX_FSR3UPSCALER_OPTION_HDR_COLOR_INPUT + data.fUpsampledColor = RGBToYCoCg(InverseTonemap(YCoCgToRGB(data.clippingBox.boxCenter))); +#else + data.fUpsampledColor = data.clippingBox.boxCenter; +#endif + data.fUpsampledWeight = 1.0f; + data.fHistoryWeight = 0.0f; + } +} |
