193 lines
7.8 KiB
C
193 lines
7.8 KiB
C
|
// 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_FRAMEINTERPOLATION_H
|
||
|
#define FFX_FRAMEINTERPOLATION_H
|
||
|
|
||
|
struct InterpolationSourceColor
|
||
|
{
|
||
|
FfxFloat32x3 fRaw;
|
||
|
FfxFloat32x3 fLinear;
|
||
|
FfxFloat32 fBilinearWeightSum;
|
||
|
};
|
||
|
|
||
|
InterpolationSourceColor NewInterpolationSourceColor()
|
||
|
{
|
||
|
InterpolationSourceColor c;
|
||
|
c.fRaw = FfxFloat32x3(0.0, 0.0, 0.0);
|
||
|
c.fLinear = FfxFloat32x3(0.0, 0.0, 0.0);
|
||
|
c.fBilinearWeightSum = 0.0;
|
||
|
return c;
|
||
|
}
|
||
|
|
||
|
InterpolationSourceColor SampleTextureBilinear(FfxBoolean isCurrent, FfxFloat32x2 fUv, FfxFloat32x2 fMotionVector, FfxInt32x2 texSize)
|
||
|
{
|
||
|
InterpolationSourceColor result = NewInterpolationSourceColor();
|
||
|
|
||
|
FfxFloat32x2 fReprojectedUv = fUv + fMotionVector;
|
||
|
BilinearSamplingData bilinearInfo = GetBilinearSamplingData(fReprojectedUv, texSize);
|
||
|
|
||
|
FfxFloat32x3 fColor = FfxFloat32x3(0.0, 0.0, 0.0);
|
||
|
FfxFloat32 fWeightSum = 0.0f;
|
||
|
for (FfxInt32 iSampleIndex = 0; iSampleIndex < 4; iSampleIndex++) {
|
||
|
|
||
|
const FfxInt32x2 iOffset = bilinearInfo.iOffsets[iSampleIndex];
|
||
|
const FfxInt32x2 iSamplePos = bilinearInfo.iBasePos + iOffset;
|
||
|
|
||
|
if (IsInRect(iSamplePos, InterpolationRectBase(), InterpolationRectSize()))
|
||
|
{
|
||
|
FfxFloat32 fWeight = bilinearInfo.fWeights[iSampleIndex];
|
||
|
|
||
|
if (isCurrent)
|
||
|
fColor += LoadCurrentBackbuffer(iSamplePos).rgb * fWeight;
|
||
|
else
|
||
|
fColor += LoadPreviousBackbuffer(iSamplePos).rgb * fWeight;
|
||
|
fWeightSum += fWeight;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//normalize colors
|
||
|
fColor = (fWeightSum != 0.0f) ? fColor / fWeightSum : FfxFloat32x3(0.0f, 0.0f, 0.0f);
|
||
|
|
||
|
result.fRaw = fColor;
|
||
|
result.fLinear = RawRGBToLinear(fColor);
|
||
|
result.fBilinearWeightSum = fWeightSum;
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
void updateInPaintingWeight(inout FfxFloat32 fInPaintingWeight, FfxFloat32 fFactor)
|
||
|
{
|
||
|
fInPaintingWeight = ffxSaturate(ffxMax(fInPaintingWeight, fFactor));
|
||
|
}
|
||
|
|
||
|
void computeInterpolatedColor(FfxUInt32x2 iPxPos, out FfxFloat32x3 fInterpolatedColor, inout FfxFloat32 fInPaintingWeight)
|
||
|
{
|
||
|
const FfxFloat32x2 fUvInInterpolationRect = (FfxFloat32x2(iPxPos - InterpolationRectBase()) + 0.5f) / InterpolationRectSize();
|
||
|
const FfxFloat32x2 fUvInScreenSpace = (FfxFloat32x2(iPxPos) + 0.5f) / DisplaySize();
|
||
|
const FfxFloat32x2 fLrUvInInterpolationRect = fUvInInterpolationRect * (FfxFloat32x2(RenderSize()) / GetMaxRenderSize());
|
||
|
|
||
|
const FfxFloat32x2 fUvLetterBoxScale = FfxFloat32x2(InterpolationRectSize()) / DisplaySize();
|
||
|
|
||
|
// game MV are top left aligned, the function scales them to render res UV
|
||
|
VectorFieldEntry gameMv;
|
||
|
LoadInpaintedGameFieldMv(fUvInInterpolationRect, gameMv);
|
||
|
|
||
|
// OF is done on the back buffers which already have black bars
|
||
|
VectorFieldEntry ofMv;
|
||
|
SampleOpticalFlowMotionVectorField(fUvInScreenSpace, ofMv);
|
||
|
|
||
|
// Binarize disucclusion factor
|
||
|
FfxFloat32x2 fDisocclusionFactor = FfxFloat32x2(FFX_EQUAL(ffxSaturate(SampleDisocclusionMask(fLrUvInInterpolationRect).xy), FfxFloat32x2(1.0, 1.0)));
|
||
|
|
||
|
InterpolationSourceColor fPrevColorGame = SampleTextureBilinear(false, fUvInScreenSpace, +gameMv.fMotionVector * fUvLetterBoxScale, DisplaySize());
|
||
|
InterpolationSourceColor fCurrColorGame = SampleTextureBilinear(true, fUvInScreenSpace, -gameMv.fMotionVector * fUvLetterBoxScale, DisplaySize());
|
||
|
|
||
|
InterpolationSourceColor fPrevColorOF = SampleTextureBilinear(false, fUvInScreenSpace, +ofMv.fMotionVector * fUvLetterBoxScale, DisplaySize());
|
||
|
InterpolationSourceColor fCurrColorOF = SampleTextureBilinear(true, fUvInScreenSpace, -ofMv.fMotionVector * fUvLetterBoxScale, DisplaySize());
|
||
|
|
||
|
FfxFloat32 fBilinearWeightSum = 0.0f;
|
||
|
FfxFloat32 fDisoccludedFactor = 0.0f;
|
||
|
|
||
|
// Disocclusion logic
|
||
|
{
|
||
|
fDisocclusionFactor.x *= FfxFloat32(!gameMv.bNegOutside);
|
||
|
fDisocclusionFactor.y *= FfxFloat32(!gameMv.bPosOutside);
|
||
|
|
||
|
// Inpaint in bi-directional disocclusion areas
|
||
|
updateInPaintingWeight(fInPaintingWeight, FfxFloat32(length(fDisocclusionFactor) <= FFX_FRAMEINTERPOLATION_EPSILON));
|
||
|
|
||
|
FfxFloat32 t = 0.5f;
|
||
|
t += 0.5f * (1 - (fDisocclusionFactor.x));
|
||
|
t -= 0.5f * (1 - (fDisocclusionFactor.y));
|
||
|
|
||
|
fInterpolatedColor = ffxLerp(fPrevColorGame.fRaw, fCurrColorGame.fRaw, ffxSaturate(t));
|
||
|
fBilinearWeightSum = ffxLerp(fPrevColorGame.fBilinearWeightSum, fCurrColorGame.fBilinearWeightSum, ffxSaturate(t));
|
||
|
|
||
|
fDisoccludedFactor = ffxSaturate(1 - ffxMin(fDisocclusionFactor.x, fDisocclusionFactor.y));
|
||
|
|
||
|
if (fPrevColorGame.fBilinearWeightSum == 0.0f)
|
||
|
{
|
||
|
fInterpolatedColor = fCurrColorGame.fRaw;
|
||
|
fBilinearWeightSum = fCurrColorGame.fBilinearWeightSum;
|
||
|
}
|
||
|
else if (fCurrColorGame.fBilinearWeightSum == 0.0f)
|
||
|
{
|
||
|
fInterpolatedColor = fPrevColorGame.fRaw;
|
||
|
fBilinearWeightSum = fPrevColorGame.fBilinearWeightSum;
|
||
|
}
|
||
|
if (fPrevColorGame.fBilinearWeightSum == 0 && fCurrColorGame.fBilinearWeightSum == 0)
|
||
|
{
|
||
|
fInPaintingWeight = 1.0f;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
{
|
||
|
|
||
|
FfxFloat32 ofT = 0.5f;
|
||
|
|
||
|
if (fPrevColorOF.fBilinearWeightSum > 0 && fCurrColorOF.fBilinearWeightSum > 0)
|
||
|
{
|
||
|
ofT = 0.5f;
|
||
|
}
|
||
|
else if (fPrevColorOF.fBilinearWeightSum > 0)
|
||
|
{
|
||
|
ofT = 0;
|
||
|
} else {
|
||
|
ofT = 1;
|
||
|
}
|
||
|
|
||
|
const FfxFloat32x3 ofColor = ffxLerp(fPrevColorOF.fRaw, fCurrColorOF.fRaw, ofT);
|
||
|
|
||
|
FfxFloat32 fOF_Sim = NormalizedDot3(fPrevColorOF.fRaw, fCurrColorOF.fRaw);
|
||
|
FfxFloat32 fGame_Sim = NormalizedDot3(fPrevColorGame.fRaw, fCurrColorGame.fRaw);
|
||
|
|
||
|
fGame_Sim = ffxLerp(ffxMax(FFX_FRAMEINTERPOLATION_EPSILON, fGame_Sim), 1.0f, ffxSaturate(fDisoccludedFactor));
|
||
|
FfxFloat32 fGameMvBias = ffxPow(ffxSaturate(fGame_Sim / ffxMax(FFX_FRAMEINTERPOLATION_EPSILON, fOF_Sim)), 1.0f);
|
||
|
|
||
|
const FfxFloat32 fFrameIndexFactor = FfxFloat32(FrameIndexSinceLastReset() < 10);
|
||
|
fGameMvBias = ffxLerp(fGameMvBias, 1.0f, fFrameIndexFactor);
|
||
|
|
||
|
fInterpolatedColor = ffxLerp(ofColor, fInterpolatedColor, ffxSaturate(fGameMvBias));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void computeFrameinterpolation(FfxInt32x2 iPxPos)
|
||
|
{
|
||
|
FfxFloat32x3 fColor = FfxFloat32x3(0, 0, 0);
|
||
|
FfxFloat32 fInPaintingWeight = 0.0f;
|
||
|
|
||
|
if (IsInRect(iPxPos, InterpolationRectBase(), InterpolationRectSize()) == false || FrameIndexSinceLastReset() == 0)
|
||
|
{
|
||
|
// if we just reset or we are out of the interpolation rect, copy the current back buffer and don't interpolate
|
||
|
fColor = LoadCurrentBackbuffer(iPxPos);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
computeInterpolatedColor(iPxPos, fColor, fInPaintingWeight);
|
||
|
}
|
||
|
|
||
|
StoreFrameinterpolationOutput(FfxInt32x2(iPxPos), FfxFloat32x4(fColor, fInPaintingWeight));
|
||
|
}
|
||
|
|
||
|
#endif // FFX_FRAMEINTERPOLATION_H
|