You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
173 lines
8.6 KiB
173 lines
8.6 KiB
// 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 fVecolityFactor = ffxSaturate(params.f4KVelocity / 20.0f);
|
|
const FfxFloat32 fDistanceFactor = ffxSaturate(0.75f - params.fFarthestDepthInMeters / 20.0f);
|
|
const FfxFloat32 fAccumulationFactor = 1.0f - params.fAccumulation;
|
|
const FfxFloat32 fReactiveFactor = ffxPow(params.fReactiveMask, 1.0f / 2.0f);
|
|
const FfxFloat32 fShadingChangeFactor = params.fShadingChange;
|
|
const FfxFloat32 fBoxScaleT = ffxMax(fVecolityFactor, ffxMax(fDistanceFactor, ffxMax(fAccumulationFactor, ffxMax(fReactiveFactor, fShadingChangeFactor))));
|
|
|
|
const FfxFloat32 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, params.fReprojectedHrUv, params.bIsExistingSample);
|
|
|
|
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 = (AccumulationPassData)0;
|
|
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);
|
|
}
|