Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/amd-fsr2/shaders/ffx_fsr2_accumulate.h
9899 views
1
// This file is part of the FidelityFX SDK.
2
//
3
// Copyright (c) 2022-2023 Advanced Micro Devices, Inc. All rights reserved.
4
//
5
// Permission is hereby granted, free of charge, to any person obtaining a copy
6
// of this software and associated documentation files (the "Software"), to deal
7
// in the Software without restriction, including without limitation the rights
8
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
// copies of the Software, and to permit persons to whom the Software is
10
// furnished to do so, subject to the following conditions:
11
// The above copyright notice and this permission notice shall be included in
12
// all copies or substantial portions of the Software.
13
//
14
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
// THE SOFTWARE.
21
22
#ifndef FFX_FSR2_ACCUMULATE_H
23
#define FFX_FSR2_ACCUMULATE_H
24
25
FfxFloat32 GetPxHrVelocity(FfxFloat32x2 fMotionVector)
26
{
27
return length(fMotionVector * DisplaySize());
28
}
29
#if FFX_HALF
30
FFX_MIN16_F GetPxHrVelocity(FFX_MIN16_F2 fMotionVector)
31
{
32
return length(fMotionVector * FFX_MIN16_F2(DisplaySize()));
33
}
34
#endif
35
36
void Accumulate(const AccumulationPassCommonParams params, FFX_PARAMETER_INOUT FfxFloat32x3 fHistoryColor, FfxFloat32x3 fAccumulation, FFX_PARAMETER_IN FfxFloat32x4 fUpsampledColorAndWeight)
37
{
38
// Aviod invalid values when accumulation and upsampled weight is 0
39
fAccumulation = ffxMax(FSR2_EPSILON.xxx, fAccumulation + fUpsampledColorAndWeight.www);
40
41
#if FFX_FSR2_OPTION_HDR_COLOR_INPUT
42
//YCoCg -> RGB -> Tonemap -> YCoCg (Use RGB tonemapper to avoid color desaturation)
43
fUpsampledColorAndWeight.xyz = RGBToYCoCg(Tonemap(YCoCgToRGB(fUpsampledColorAndWeight.xyz)));
44
fHistoryColor = RGBToYCoCg(Tonemap(YCoCgToRGB(fHistoryColor)));
45
#endif
46
47
const FfxFloat32x3 fAlpha = fUpsampledColorAndWeight.www / fAccumulation;
48
fHistoryColor = ffxLerp(fHistoryColor, fUpsampledColorAndWeight.xyz, fAlpha);
49
50
fHistoryColor = YCoCgToRGB(fHistoryColor);
51
52
#if FFX_FSR2_OPTION_HDR_COLOR_INPUT
53
fHistoryColor = InverseTonemap(fHistoryColor);
54
#endif
55
}
56
57
void RectifyHistory(
58
const AccumulationPassCommonParams params,
59
RectificationBox clippingBox,
60
FFX_PARAMETER_INOUT FfxFloat32x3 fHistoryColor,
61
FFX_PARAMETER_INOUT FfxFloat32x3 fAccumulation,
62
FfxFloat32 fLockContributionThisFrame,
63
FfxFloat32 fTemporalReactiveFactor,
64
FfxFloat32 fLumaInstabilityFactor)
65
{
66
FfxFloat32 fScaleFactorInfluence = ffxMin(20.0f, ffxPow(FfxFloat32(1.0f / length(DownscaleFactor().x * DownscaleFactor().y)), 3.0f));
67
68
const FfxFloat32 fVecolityFactor = ffxSaturate(params.fHrVelocity / 20.0f);
69
const FfxFloat32 fBoxScaleT = ffxMax(params.fDepthClipFactor, ffxMax(params.fAccumulationMask, fVecolityFactor));
70
FfxFloat32 fBoxScale = ffxLerp(fScaleFactorInfluence, 1.0f, fBoxScaleT);
71
72
FfxFloat32x3 fScaledBoxVec = clippingBox.boxVec * fBoxScale;
73
FfxFloat32x3 boxMin = clippingBox.boxCenter - fScaledBoxVec;
74
FfxFloat32x3 boxMax = clippingBox.boxCenter + fScaledBoxVec;
75
FfxFloat32x3 boxCenter = clippingBox.boxCenter;
76
FfxFloat32 boxVecSize = length(clippingBox.boxVec);
77
78
boxMin = ffxMax(clippingBox.aabbMin, boxMin);
79
boxMax = ffxMin(clippingBox.aabbMax, boxMax);
80
81
if (any(FFX_GREATER_THAN(boxMin, fHistoryColor)) || any(FFX_GREATER_THAN(fHistoryColor, boxMax))) {
82
83
const FfxFloat32x3 fClampedHistoryColor = clamp(fHistoryColor, boxMin, boxMax);
84
85
FfxFloat32x3 fHistoryContribution = ffxMax(fLumaInstabilityFactor, fLockContributionThisFrame).xxx;
86
87
const FfxFloat32 fReactiveFactor = params.fDilatedReactiveFactor;
88
const FfxFloat32 fReactiveContribution = 1.0f - ffxPow(fReactiveFactor, 1.0f / 2.0f);
89
fHistoryContribution *= fReactiveContribution;
90
91
// Scale history color using rectification info, also using accumulation mask to avoid potential invalid color protection
92
fHistoryColor = ffxLerp(fClampedHistoryColor, fHistoryColor, ffxSaturate(fHistoryContribution));
93
94
// Scale accumulation using rectification info
95
const FfxFloat32x3 fAccumulationMin = ffxMin(fAccumulation, FFX_BROADCAST_FLOAT32X3(0.1f));
96
fAccumulation = ffxLerp(fAccumulationMin, fAccumulation, ffxSaturate(fHistoryContribution));
97
}
98
}
99
100
void WriteUpscaledOutput(FfxInt32x2 iPxHrPos, FfxFloat32x3 fUpscaledColor)
101
{
102
StoreUpscaledOutput(iPxHrPos, fUpscaledColor);
103
}
104
105
void FinalizeLockStatus(const AccumulationPassCommonParams params, FfxFloat32x2 fLockStatus, FfxFloat32 fUpsampledWeight)
106
{
107
// we expect similar motion for next frame
108
// kill lock if that location is outside screen, avoid locks to be clamped to screen borders
109
FfxFloat32x2 fEstimatedUvNextFrame = params.fHrUv - params.fMotionVector;
110
if (IsUvInside(fEstimatedUvNextFrame) == false) {
111
KillLock(fLockStatus);
112
}
113
else {
114
// Decrease lock lifetime
115
const FfxFloat32 fLifetimeDecreaseLanczosMax = FfxFloat32(JitterSequenceLength()) * FfxFloat32(fAverageLanczosWeightPerFrame);
116
const FfxFloat32 fLifetimeDecrease = FfxFloat32(fUpsampledWeight / fLifetimeDecreaseLanczosMax);
117
fLockStatus[LOCK_LIFETIME_REMAINING] = ffxMax(FfxFloat32(0), fLockStatus[LOCK_LIFETIME_REMAINING] - fLifetimeDecrease);
118
}
119
120
StoreLockStatus(params.iPxHrPos, fLockStatus);
121
}
122
123
124
FfxFloat32x3 ComputeBaseAccumulationWeight(const AccumulationPassCommonParams params, FfxFloat32 fThisFrameReactiveFactor, FfxBoolean bInMotionLastFrame, FfxFloat32 fUpsampledWeight, LockState lockState)
125
{
126
// Always assume max accumulation was reached
127
FfxFloat32 fBaseAccumulation = fMaxAccumulationLanczosWeight * FfxFloat32(params.bIsExistingSample) * (1.0f - fThisFrameReactiveFactor) * (1.0f - params.fDepthClipFactor);
128
129
fBaseAccumulation = ffxMin(fBaseAccumulation, ffxLerp(fBaseAccumulation, fUpsampledWeight * 10.0f, ffxMax(FfxFloat32(bInMotionLastFrame), ffxSaturate(params.fHrVelocity * FfxFloat32(10)))));
130
131
fBaseAccumulation = ffxMin(fBaseAccumulation, ffxLerp(fBaseAccumulation, fUpsampledWeight, ffxSaturate(params.fHrVelocity / FfxFloat32(20))));
132
133
return fBaseAccumulation.xxx;
134
}
135
136
FfxFloat32 ComputeLumaInstabilityFactor(const AccumulationPassCommonParams params, RectificationBox clippingBox, FfxFloat32 fThisFrameReactiveFactor, FfxFloat32 fLuminanceDiff)
137
{
138
const FfxFloat32 fUnormThreshold = 1.0f / 255.0f;
139
const FfxInt32 N_MINUS_1 = 0;
140
const FfxInt32 N_MINUS_2 = 1;
141
const FfxInt32 N_MINUS_3 = 2;
142
const FfxInt32 N_MINUS_4 = 3;
143
144
FfxFloat32 fCurrentFrameLuma = clippingBox.boxCenter.x;
145
146
#if FFX_FSR2_OPTION_HDR_COLOR_INPUT
147
fCurrentFrameLuma = fCurrentFrameLuma / (1.0f + ffxMax(0.0f, fCurrentFrameLuma));
148
#endif
149
150
fCurrentFrameLuma = round(fCurrentFrameLuma * 255.0f) / 255.0f;
151
152
const FfxBoolean bSampleLumaHistory = (ffxMax(ffxMax(params.fDepthClipFactor, params.fAccumulationMask), fLuminanceDiff) < 0.1f) && (params.bIsNewSample == false);
153
FfxFloat32x4 fCurrentFrameLumaHistory = bSampleLumaHistory ? SampleLumaHistory(params.fReprojectedHrUv) : FFX_BROADCAST_FLOAT32X4(0.0f);
154
155
FfxFloat32 fLumaInstability = 0.0f;
156
FfxFloat32 fDiffs0 = (fCurrentFrameLuma - fCurrentFrameLumaHistory[N_MINUS_1]);
157
158
FfxFloat32 fMin = abs(fDiffs0);
159
160
if (fMin >= fUnormThreshold)
161
{
162
for (int i = N_MINUS_2; i <= N_MINUS_4; i++) {
163
FfxFloat32 fDiffs1 = (fCurrentFrameLuma - fCurrentFrameLumaHistory[i]);
164
165
if (sign(fDiffs0) == sign(fDiffs1)) {
166
167
// Scale difference to protect historically similar values
168
const FfxFloat32 fMinBias = 1.0f;
169
fMin = ffxMin(fMin, abs(fDiffs1) * fMinBias);
170
}
171
}
172
173
const FfxFloat32 fBoxSize = clippingBox.boxVec.x;
174
const FfxFloat32 fBoxSizeFactor = ffxPow(ffxSaturate(fBoxSize / 0.1f), 6.0f);
175
176
fLumaInstability = FfxFloat32(fMin != abs(fDiffs0)) * fBoxSizeFactor;
177
fLumaInstability = FfxFloat32(fLumaInstability > fUnormThreshold);
178
179
fLumaInstability *= 1.0f - ffxMax(params.fAccumulationMask, ffxPow(fThisFrameReactiveFactor, 1.0f / 6.0f));
180
}
181
182
//shift history
183
fCurrentFrameLumaHistory[N_MINUS_4] = fCurrentFrameLumaHistory[N_MINUS_3];
184
fCurrentFrameLumaHistory[N_MINUS_3] = fCurrentFrameLumaHistory[N_MINUS_2];
185
fCurrentFrameLumaHistory[N_MINUS_2] = fCurrentFrameLumaHistory[N_MINUS_1];
186
fCurrentFrameLumaHistory[N_MINUS_1] = fCurrentFrameLuma;
187
188
StoreLumaHistory(params.iPxHrPos, fCurrentFrameLumaHistory);
189
190
return fLumaInstability * FfxFloat32(fCurrentFrameLumaHistory[N_MINUS_4] != 0);
191
}
192
193
FfxFloat32 ComputeTemporalReactiveFactor(const AccumulationPassCommonParams params, FfxFloat32 fTemporalReactiveFactor)
194
{
195
FfxFloat32 fNewFactor = ffxMin(0.99f, fTemporalReactiveFactor);
196
197
fNewFactor = ffxMax(fNewFactor, ffxLerp(fNewFactor, 0.4f, ffxSaturate(params.fHrVelocity)));
198
199
fNewFactor = ffxMax(fNewFactor * fNewFactor, ffxMax(params.fDepthClipFactor * 0.1f, params.fDilatedReactiveFactor));
200
201
// Force reactive factor for new samples
202
fNewFactor = params.bIsNewSample ? 1.0f : fNewFactor;
203
204
if (ffxSaturate(params.fHrVelocity * 10.0f) >= 1.0f) {
205
fNewFactor = ffxMax(FSR2_EPSILON, fNewFactor) * -1.0f;
206
}
207
208
return fNewFactor;
209
}
210
211
AccumulationPassCommonParams InitParams(FfxInt32x2 iPxHrPos)
212
{
213
AccumulationPassCommonParams params;
214
215
params.iPxHrPos = iPxHrPos;
216
const FfxFloat32x2 fHrUv = (iPxHrPos + 0.5f) / DisplaySize();
217
params.fHrUv = fHrUv;
218
219
const FfxFloat32x2 fLrUvJittered = fHrUv + Jitter() / RenderSize();
220
params.fLrUv_HwSampler = ClampUv(fLrUvJittered, RenderSize(), MaxRenderSize());
221
222
params.fMotionVector = GetMotionVector(iPxHrPos, fHrUv);
223
params.fHrVelocity = GetPxHrVelocity(params.fMotionVector);
224
225
ComputeReprojectedUVs(params, params.fReprojectedHrUv, params.bIsExistingSample);
226
227
params.fDepthClipFactor = ffxSaturate(SampleDepthClip(params.fLrUv_HwSampler));
228
229
const FfxFloat32x2 fDilatedReactiveMasks = SampleDilatedReactiveMasks(params.fLrUv_HwSampler);
230
params.fDilatedReactiveFactor = fDilatedReactiveMasks.x;
231
params.fAccumulationMask = fDilatedReactiveMasks.y;
232
params.bIsResetFrame = (0 == FrameIndex());
233
234
params.bIsNewSample = (params.bIsExistingSample == false || params.bIsResetFrame);
235
236
return params;
237
}
238
239
void Accumulate(FfxInt32x2 iPxHrPos)
240
{
241
const AccumulationPassCommonParams params = InitParams(iPxHrPos);
242
243
FfxFloat32x3 fHistoryColor = FfxFloat32x3(0, 0, 0);
244
FfxFloat32x2 fLockStatus;
245
InitializeNewLockSample(fLockStatus);
246
247
FfxFloat32 fTemporalReactiveFactor = 0.0f;
248
FfxBoolean bInMotionLastFrame = FFX_FALSE;
249
LockState lockState = { FFX_FALSE , FFX_FALSE };
250
if (params.bIsExistingSample && !params.bIsResetFrame) {
251
ReprojectHistoryColor(params, fHistoryColor, fTemporalReactiveFactor, bInMotionLastFrame);
252
lockState = ReprojectHistoryLockStatus(params, fLockStatus);
253
}
254
255
FfxFloat32 fThisFrameReactiveFactor = ffxMax(params.fDilatedReactiveFactor, fTemporalReactiveFactor);
256
257
FfxFloat32 fLuminanceDiff = 0.0f;
258
FfxFloat32 fLockContributionThisFrame = 0.0f;
259
UpdateLockStatus(params, fThisFrameReactiveFactor, lockState, fLockStatus, fLockContributionThisFrame, fLuminanceDiff);
260
261
// Load upsampled input color
262
RectificationBox clippingBox;
263
FfxFloat32x4 fUpsampledColorAndWeight = ComputeUpsampledColorAndWeight(params, clippingBox, fThisFrameReactiveFactor);
264
265
const FfxFloat32 fLumaInstabilityFactor = ComputeLumaInstabilityFactor(params, clippingBox, fThisFrameReactiveFactor, fLuminanceDiff);
266
267
268
FfxFloat32x3 fAccumulation = ComputeBaseAccumulationWeight(params, fThisFrameReactiveFactor, bInMotionLastFrame, fUpsampledColorAndWeight.w, lockState);
269
270
if (params.bIsNewSample) {
271
fHistoryColor = YCoCgToRGB(fUpsampledColorAndWeight.xyz);
272
}
273
else {
274
RectifyHistory(params, clippingBox, fHistoryColor, fAccumulation, fLockContributionThisFrame, fThisFrameReactiveFactor, fLumaInstabilityFactor);
275
276
Accumulate(params, fHistoryColor, fAccumulation, fUpsampledColorAndWeight);
277
}
278
279
fHistoryColor = UnprepareRgb(fHistoryColor, Exposure());
280
281
FinalizeLockStatus(params, fLockStatus, fUpsampledColorAndWeight.w);
282
283
// Get new temporal reactive factor
284
fTemporalReactiveFactor = ComputeTemporalReactiveFactor(params, fThisFrameReactiveFactor);
285
286
StoreInternalColorAndWeight(iPxHrPos, FfxFloat32x4(fHistoryColor, fTemporalReactiveFactor));
287
288
// Output final color when RCAS is disabled
289
#if FFX_FSR2_OPTION_APPLY_SHARPENING == 0
290
WriteUpscaledOutput(iPxHrPos, fHistoryColor);
291
#endif
292
StoreNewLocks(iPxHrPos, 0);
293
}
294
295
#endif // FFX_FSR2_ACCUMULATE_H
296
297