Path: blob/master/thirdparty/amd-fsr2/shaders/ffx_fsr2_accumulate.h
9899 views
// This file is part of the FidelityFX SDK.1//2// Copyright (c) 2022-2023 Advanced Micro Devices, Inc. All rights reserved.3//4// Permission is hereby granted, free of charge, to any person obtaining a copy5// of this software and associated documentation files (the "Software"), to deal6// in the Software without restriction, including without limitation the rights7// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell8// copies of the Software, and to permit persons to whom the Software is9// furnished to do so, subject to the following conditions:10// The above copyright notice and this permission notice shall be included in11// all copies or substantial portions of the Software.12//13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR14// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,18// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN19// THE SOFTWARE.2021#ifndef FFX_FSR2_ACCUMULATE_H22#define FFX_FSR2_ACCUMULATE_H2324FfxFloat32 GetPxHrVelocity(FfxFloat32x2 fMotionVector)25{26return length(fMotionVector * DisplaySize());27}28#if FFX_HALF29FFX_MIN16_F GetPxHrVelocity(FFX_MIN16_F2 fMotionVector)30{31return length(fMotionVector * FFX_MIN16_F2(DisplaySize()));32}33#endif3435void Accumulate(const AccumulationPassCommonParams params, FFX_PARAMETER_INOUT FfxFloat32x3 fHistoryColor, FfxFloat32x3 fAccumulation, FFX_PARAMETER_IN FfxFloat32x4 fUpsampledColorAndWeight)36{37// Aviod invalid values when accumulation and upsampled weight is 038fAccumulation = ffxMax(FSR2_EPSILON.xxx, fAccumulation + fUpsampledColorAndWeight.www);3940#if FFX_FSR2_OPTION_HDR_COLOR_INPUT41//YCoCg -> RGB -> Tonemap -> YCoCg (Use RGB tonemapper to avoid color desaturation)42fUpsampledColorAndWeight.xyz = RGBToYCoCg(Tonemap(YCoCgToRGB(fUpsampledColorAndWeight.xyz)));43fHistoryColor = RGBToYCoCg(Tonemap(YCoCgToRGB(fHistoryColor)));44#endif4546const FfxFloat32x3 fAlpha = fUpsampledColorAndWeight.www / fAccumulation;47fHistoryColor = ffxLerp(fHistoryColor, fUpsampledColorAndWeight.xyz, fAlpha);4849fHistoryColor = YCoCgToRGB(fHistoryColor);5051#if FFX_FSR2_OPTION_HDR_COLOR_INPUT52fHistoryColor = InverseTonemap(fHistoryColor);53#endif54}5556void RectifyHistory(57const AccumulationPassCommonParams params,58RectificationBox clippingBox,59FFX_PARAMETER_INOUT FfxFloat32x3 fHistoryColor,60FFX_PARAMETER_INOUT FfxFloat32x3 fAccumulation,61FfxFloat32 fLockContributionThisFrame,62FfxFloat32 fTemporalReactiveFactor,63FfxFloat32 fLumaInstabilityFactor)64{65FfxFloat32 fScaleFactorInfluence = ffxMin(20.0f, ffxPow(FfxFloat32(1.0f / length(DownscaleFactor().x * DownscaleFactor().y)), 3.0f));6667const FfxFloat32 fVecolityFactor = ffxSaturate(params.fHrVelocity / 20.0f);68const FfxFloat32 fBoxScaleT = ffxMax(params.fDepthClipFactor, ffxMax(params.fAccumulationMask, fVecolityFactor));69FfxFloat32 fBoxScale = ffxLerp(fScaleFactorInfluence, 1.0f, fBoxScaleT);7071FfxFloat32x3 fScaledBoxVec = clippingBox.boxVec * fBoxScale;72FfxFloat32x3 boxMin = clippingBox.boxCenter - fScaledBoxVec;73FfxFloat32x3 boxMax = clippingBox.boxCenter + fScaledBoxVec;74FfxFloat32x3 boxCenter = clippingBox.boxCenter;75FfxFloat32 boxVecSize = length(clippingBox.boxVec);7677boxMin = ffxMax(clippingBox.aabbMin, boxMin);78boxMax = ffxMin(clippingBox.aabbMax, boxMax);7980if (any(FFX_GREATER_THAN(boxMin, fHistoryColor)) || any(FFX_GREATER_THAN(fHistoryColor, boxMax))) {8182const FfxFloat32x3 fClampedHistoryColor = clamp(fHistoryColor, boxMin, boxMax);8384FfxFloat32x3 fHistoryContribution = ffxMax(fLumaInstabilityFactor, fLockContributionThisFrame).xxx;8586const FfxFloat32 fReactiveFactor = params.fDilatedReactiveFactor;87const FfxFloat32 fReactiveContribution = 1.0f - ffxPow(fReactiveFactor, 1.0f / 2.0f);88fHistoryContribution *= fReactiveContribution;8990// Scale history color using rectification info, also using accumulation mask to avoid potential invalid color protection91fHistoryColor = ffxLerp(fClampedHistoryColor, fHistoryColor, ffxSaturate(fHistoryContribution));9293// Scale accumulation using rectification info94const FfxFloat32x3 fAccumulationMin = ffxMin(fAccumulation, FFX_BROADCAST_FLOAT32X3(0.1f));95fAccumulation = ffxLerp(fAccumulationMin, fAccumulation, ffxSaturate(fHistoryContribution));96}97}9899void WriteUpscaledOutput(FfxInt32x2 iPxHrPos, FfxFloat32x3 fUpscaledColor)100{101StoreUpscaledOutput(iPxHrPos, fUpscaledColor);102}103104void FinalizeLockStatus(const AccumulationPassCommonParams params, FfxFloat32x2 fLockStatus, FfxFloat32 fUpsampledWeight)105{106// we expect similar motion for next frame107// kill lock if that location is outside screen, avoid locks to be clamped to screen borders108FfxFloat32x2 fEstimatedUvNextFrame = params.fHrUv - params.fMotionVector;109if (IsUvInside(fEstimatedUvNextFrame) == false) {110KillLock(fLockStatus);111}112else {113// Decrease lock lifetime114const FfxFloat32 fLifetimeDecreaseLanczosMax = FfxFloat32(JitterSequenceLength()) * FfxFloat32(fAverageLanczosWeightPerFrame);115const FfxFloat32 fLifetimeDecrease = FfxFloat32(fUpsampledWeight / fLifetimeDecreaseLanczosMax);116fLockStatus[LOCK_LIFETIME_REMAINING] = ffxMax(FfxFloat32(0), fLockStatus[LOCK_LIFETIME_REMAINING] - fLifetimeDecrease);117}118119StoreLockStatus(params.iPxHrPos, fLockStatus);120}121122123FfxFloat32x3 ComputeBaseAccumulationWeight(const AccumulationPassCommonParams params, FfxFloat32 fThisFrameReactiveFactor, FfxBoolean bInMotionLastFrame, FfxFloat32 fUpsampledWeight, LockState lockState)124{125// Always assume max accumulation was reached126FfxFloat32 fBaseAccumulation = fMaxAccumulationLanczosWeight * FfxFloat32(params.bIsExistingSample) * (1.0f - fThisFrameReactiveFactor) * (1.0f - params.fDepthClipFactor);127128fBaseAccumulation = ffxMin(fBaseAccumulation, ffxLerp(fBaseAccumulation, fUpsampledWeight * 10.0f, ffxMax(FfxFloat32(bInMotionLastFrame), ffxSaturate(params.fHrVelocity * FfxFloat32(10)))));129130fBaseAccumulation = ffxMin(fBaseAccumulation, ffxLerp(fBaseAccumulation, fUpsampledWeight, ffxSaturate(params.fHrVelocity / FfxFloat32(20))));131132return fBaseAccumulation.xxx;133}134135FfxFloat32 ComputeLumaInstabilityFactor(const AccumulationPassCommonParams params, RectificationBox clippingBox, FfxFloat32 fThisFrameReactiveFactor, FfxFloat32 fLuminanceDiff)136{137const FfxFloat32 fUnormThreshold = 1.0f / 255.0f;138const FfxInt32 N_MINUS_1 = 0;139const FfxInt32 N_MINUS_2 = 1;140const FfxInt32 N_MINUS_3 = 2;141const FfxInt32 N_MINUS_4 = 3;142143FfxFloat32 fCurrentFrameLuma = clippingBox.boxCenter.x;144145#if FFX_FSR2_OPTION_HDR_COLOR_INPUT146fCurrentFrameLuma = fCurrentFrameLuma / (1.0f + ffxMax(0.0f, fCurrentFrameLuma));147#endif148149fCurrentFrameLuma = round(fCurrentFrameLuma * 255.0f) / 255.0f;150151const FfxBoolean bSampleLumaHistory = (ffxMax(ffxMax(params.fDepthClipFactor, params.fAccumulationMask), fLuminanceDiff) < 0.1f) && (params.bIsNewSample == false);152FfxFloat32x4 fCurrentFrameLumaHistory = bSampleLumaHistory ? SampleLumaHistory(params.fReprojectedHrUv) : FFX_BROADCAST_FLOAT32X4(0.0f);153154FfxFloat32 fLumaInstability = 0.0f;155FfxFloat32 fDiffs0 = (fCurrentFrameLuma - fCurrentFrameLumaHistory[N_MINUS_1]);156157FfxFloat32 fMin = abs(fDiffs0);158159if (fMin >= fUnormThreshold)160{161for (int i = N_MINUS_2; i <= N_MINUS_4; i++) {162FfxFloat32 fDiffs1 = (fCurrentFrameLuma - fCurrentFrameLumaHistory[i]);163164if (sign(fDiffs0) == sign(fDiffs1)) {165166// Scale difference to protect historically similar values167const FfxFloat32 fMinBias = 1.0f;168fMin = ffxMin(fMin, abs(fDiffs1) * fMinBias);169}170}171172const FfxFloat32 fBoxSize = clippingBox.boxVec.x;173const FfxFloat32 fBoxSizeFactor = ffxPow(ffxSaturate(fBoxSize / 0.1f), 6.0f);174175fLumaInstability = FfxFloat32(fMin != abs(fDiffs0)) * fBoxSizeFactor;176fLumaInstability = FfxFloat32(fLumaInstability > fUnormThreshold);177178fLumaInstability *= 1.0f - ffxMax(params.fAccumulationMask, ffxPow(fThisFrameReactiveFactor, 1.0f / 6.0f));179}180181//shift history182fCurrentFrameLumaHistory[N_MINUS_4] = fCurrentFrameLumaHistory[N_MINUS_3];183fCurrentFrameLumaHistory[N_MINUS_3] = fCurrentFrameLumaHistory[N_MINUS_2];184fCurrentFrameLumaHistory[N_MINUS_2] = fCurrentFrameLumaHistory[N_MINUS_1];185fCurrentFrameLumaHistory[N_MINUS_1] = fCurrentFrameLuma;186187StoreLumaHistory(params.iPxHrPos, fCurrentFrameLumaHistory);188189return fLumaInstability * FfxFloat32(fCurrentFrameLumaHistory[N_MINUS_4] != 0);190}191192FfxFloat32 ComputeTemporalReactiveFactor(const AccumulationPassCommonParams params, FfxFloat32 fTemporalReactiveFactor)193{194FfxFloat32 fNewFactor = ffxMin(0.99f, fTemporalReactiveFactor);195196fNewFactor = ffxMax(fNewFactor, ffxLerp(fNewFactor, 0.4f, ffxSaturate(params.fHrVelocity)));197198fNewFactor = ffxMax(fNewFactor * fNewFactor, ffxMax(params.fDepthClipFactor * 0.1f, params.fDilatedReactiveFactor));199200// Force reactive factor for new samples201fNewFactor = params.bIsNewSample ? 1.0f : fNewFactor;202203if (ffxSaturate(params.fHrVelocity * 10.0f) >= 1.0f) {204fNewFactor = ffxMax(FSR2_EPSILON, fNewFactor) * -1.0f;205}206207return fNewFactor;208}209210AccumulationPassCommonParams InitParams(FfxInt32x2 iPxHrPos)211{212AccumulationPassCommonParams params;213214params.iPxHrPos = iPxHrPos;215const FfxFloat32x2 fHrUv = (iPxHrPos + 0.5f) / DisplaySize();216params.fHrUv = fHrUv;217218const FfxFloat32x2 fLrUvJittered = fHrUv + Jitter() / RenderSize();219params.fLrUv_HwSampler = ClampUv(fLrUvJittered, RenderSize(), MaxRenderSize());220221params.fMotionVector = GetMotionVector(iPxHrPos, fHrUv);222params.fHrVelocity = GetPxHrVelocity(params.fMotionVector);223224ComputeReprojectedUVs(params, params.fReprojectedHrUv, params.bIsExistingSample);225226params.fDepthClipFactor = ffxSaturate(SampleDepthClip(params.fLrUv_HwSampler));227228const FfxFloat32x2 fDilatedReactiveMasks = SampleDilatedReactiveMasks(params.fLrUv_HwSampler);229params.fDilatedReactiveFactor = fDilatedReactiveMasks.x;230params.fAccumulationMask = fDilatedReactiveMasks.y;231params.bIsResetFrame = (0 == FrameIndex());232233params.bIsNewSample = (params.bIsExistingSample == false || params.bIsResetFrame);234235return params;236}237238void Accumulate(FfxInt32x2 iPxHrPos)239{240const AccumulationPassCommonParams params = InitParams(iPxHrPos);241242FfxFloat32x3 fHistoryColor = FfxFloat32x3(0, 0, 0);243FfxFloat32x2 fLockStatus;244InitializeNewLockSample(fLockStatus);245246FfxFloat32 fTemporalReactiveFactor = 0.0f;247FfxBoolean bInMotionLastFrame = FFX_FALSE;248LockState lockState = { FFX_FALSE , FFX_FALSE };249if (params.bIsExistingSample && !params.bIsResetFrame) {250ReprojectHistoryColor(params, fHistoryColor, fTemporalReactiveFactor, bInMotionLastFrame);251lockState = ReprojectHistoryLockStatus(params, fLockStatus);252}253254FfxFloat32 fThisFrameReactiveFactor = ffxMax(params.fDilatedReactiveFactor, fTemporalReactiveFactor);255256FfxFloat32 fLuminanceDiff = 0.0f;257FfxFloat32 fLockContributionThisFrame = 0.0f;258UpdateLockStatus(params, fThisFrameReactiveFactor, lockState, fLockStatus, fLockContributionThisFrame, fLuminanceDiff);259260// Load upsampled input color261RectificationBox clippingBox;262FfxFloat32x4 fUpsampledColorAndWeight = ComputeUpsampledColorAndWeight(params, clippingBox, fThisFrameReactiveFactor);263264const FfxFloat32 fLumaInstabilityFactor = ComputeLumaInstabilityFactor(params, clippingBox, fThisFrameReactiveFactor, fLuminanceDiff);265266267FfxFloat32x3 fAccumulation = ComputeBaseAccumulationWeight(params, fThisFrameReactiveFactor, bInMotionLastFrame, fUpsampledColorAndWeight.w, lockState);268269if (params.bIsNewSample) {270fHistoryColor = YCoCgToRGB(fUpsampledColorAndWeight.xyz);271}272else {273RectifyHistory(params, clippingBox, fHistoryColor, fAccumulation, fLockContributionThisFrame, fThisFrameReactiveFactor, fLumaInstabilityFactor);274275Accumulate(params, fHistoryColor, fAccumulation, fUpsampledColorAndWeight);276}277278fHistoryColor = UnprepareRgb(fHistoryColor, Exposure());279280FinalizeLockStatus(params, fLockStatus, fUpsampledColorAndWeight.w);281282// Get new temporal reactive factor283fTemporalReactiveFactor = ComputeTemporalReactiveFactor(params, fThisFrameReactiveFactor);284285StoreInternalColorAndWeight(iPxHrPos, FfxFloat32x4(fHistoryColor, fTemporalReactiveFactor));286287// Output final color when RCAS is disabled288#if FFX_FSR2_OPTION_APPLY_SHARPENING == 0289WriteUpscaledOutput(iPxHrPos, fHistoryColor);290#endif291StoreNewLocks(iPxHrPos, 0);292}293294#endif // FFX_FSR2_ACCUMULATE_H295296297