Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/amd-fsr2/ffx_fsr2.cpp
9896 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
#include <algorithm> // for max used inside SPD CPU code.
23
#include <cmath> // for fabs, abs, sinf, sqrt, etc.
24
#include <string.h> // for memset
25
#include <cfloat> // for FLT_EPSILON
26
#include "ffx_fsr2.h"
27
#define FFX_CPU
28
#include "shaders/ffx_core.h"
29
#include "shaders/ffx_fsr1.h"
30
#include "shaders/ffx_spd.h"
31
#include "shaders/ffx_fsr2_callbacks_hlsl.h"
32
33
#include "ffx_fsr2_maximum_bias.h"
34
35
#ifdef __clang__
36
#pragma clang diagnostic ignored "-Wunused-variable"
37
#endif
38
39
#ifndef _countof
40
#define _countof(array) (sizeof(array) / sizeof(array[0]))
41
#endif
42
43
#ifndef _MSC_VER
44
#include <wchar.h>
45
#define wcscpy_s wcscpy
46
#endif
47
48
// max queued frames for descriptor management
49
static const uint32_t FSR2_MAX_QUEUED_FRAMES = 16;
50
51
#include "ffx_fsr2_private.h"
52
53
// lists to map shader resource bindpoint name to resource identifier
54
typedef struct ResourceBinding
55
{
56
uint32_t index;
57
wchar_t name[64];
58
}ResourceBinding;
59
60
static const ResourceBinding srvResourceBindingTable[] =
61
{
62
{FFX_FSR2_RESOURCE_IDENTIFIER_INPUT_COLOR, L"r_input_color_jittered"},
63
{FFX_FSR2_RESOURCE_IDENTIFIER_INPUT_OPAQUE_ONLY, L"r_input_opaque_only"},
64
{FFX_FSR2_RESOURCE_IDENTIFIER_INPUT_MOTION_VECTORS, L"r_input_motion_vectors"},
65
{FFX_FSR2_RESOURCE_IDENTIFIER_INPUT_DEPTH, L"r_input_depth" },
66
{FFX_FSR2_RESOURCE_IDENTIFIER_INPUT_EXPOSURE, L"r_input_exposure"},
67
{FFX_FSR2_RESOURCE_IDENTIFIER_AUTO_EXPOSURE, L"r_auto_exposure"},
68
{FFX_FSR2_RESOURCE_IDENTIFIER_INPUT_REACTIVE_MASK, L"r_reactive_mask"},
69
{FFX_FSR2_RESOURCE_IDENTIFIER_INPUT_TRANSPARENCY_AND_COMPOSITION_MASK, L"r_transparency_and_composition_mask"},
70
{FFX_FSR2_RESOURCE_IDENTIFIER_RECONSTRUCTED_PREVIOUS_NEAREST_DEPTH, L"r_reconstructed_previous_nearest_depth"},
71
{FFX_FSR2_RESOURCE_IDENTIFIER_DILATED_MOTION_VECTORS, L"r_dilated_motion_vectors"},
72
{FFX_FSR2_RESOURCE_IDENTIFIER_PREVIOUS_DILATED_MOTION_VECTORS, L"r_previous_dilated_motion_vectors"},
73
{FFX_FSR2_RESOURCE_IDENTIFIER_DILATED_DEPTH, L"r_dilatedDepth"},
74
{FFX_FSR2_RESOURCE_IDENTIFIER_INTERNAL_UPSCALED_COLOR, L"r_internal_upscaled_color"},
75
{FFX_FSR2_RESOURCE_IDENTIFIER_LOCK_STATUS, L"r_lock_status"},
76
{FFX_FSR2_RESOURCE_IDENTIFIER_PREPARED_INPUT_COLOR, L"r_prepared_input_color"},
77
{FFX_FSR2_RESOURCE_IDENTIFIER_LUMA_HISTORY, L"r_luma_history" },
78
{FFX_FSR2_RESOURCE_IDENTIFIER_RCAS_INPUT, L"r_rcas_input"},
79
{FFX_FSR2_RESOURCE_IDENTIFIER_LANCZOS_LUT, L"r_lanczos_lut"},
80
{FFX_FSR2_RESOURCE_IDENTIFIER_SCENE_LUMINANCE, L"r_imgMips"},
81
{FFX_FSR2_RESOURCE_IDENTIFIER_SCENE_LUMINANCE_MIPMAP_SHADING_CHANGE, L"r_img_mip_shading_change"},
82
{FFX_FSR2_RESOURCE_IDENTIFIER_SCENE_LUMINANCE_MIPMAP_5, L"r_img_mip_5"},
83
{FFX_FSR2_RESOURCE_IDENTITIER_UPSAMPLE_MAXIMUM_BIAS_LUT, L"r_upsample_maximum_bias_lut"},
84
{FFX_FSR2_RESOURCE_IDENTIFIER_DILATED_REACTIVE_MASKS, L"r_dilated_reactive_masks"},
85
{FFX_FSR2_RESOURCE_IDENTIFIER_NEW_LOCKS, L"r_new_locks"},
86
{FFX_FSR2_RESOURCE_IDENTIFIER_LOCK_INPUT_LUMA, L"r_lock_input_luma"},
87
{FFX_FSR2_RESOURCE_IDENTIFIER_PREV_PRE_ALPHA_COLOR, L"r_input_prev_color_pre_alpha"},
88
{FFX_FSR2_RESOURCE_IDENTIFIER_PREV_POST_ALPHA_COLOR, L"r_input_prev_color_post_alpha"},
89
};
90
91
static const ResourceBinding uavResourceBindingTable[] =
92
{
93
{FFX_FSR2_RESOURCE_IDENTIFIER_RECONSTRUCTED_PREVIOUS_NEAREST_DEPTH, L"rw_reconstructed_previous_nearest_depth"},
94
{FFX_FSR2_RESOURCE_IDENTIFIER_DILATED_MOTION_VECTORS, L"rw_dilated_motion_vectors"},
95
{FFX_FSR2_RESOURCE_IDENTIFIER_DILATED_DEPTH, L"rw_dilatedDepth"},
96
{FFX_FSR2_RESOURCE_IDENTIFIER_INTERNAL_UPSCALED_COLOR, L"rw_internal_upscaled_color"},
97
{FFX_FSR2_RESOURCE_IDENTIFIER_LOCK_STATUS, L"rw_lock_status"},
98
{FFX_FSR2_RESOURCE_IDENTIFIER_PREPARED_INPUT_COLOR, L"rw_prepared_input_color"},
99
{FFX_FSR2_RESOURCE_IDENTIFIER_LUMA_HISTORY, L"rw_luma_history"},
100
{FFX_FSR2_RESOURCE_IDENTIFIER_UPSCALED_OUTPUT, L"rw_upscaled_output"},
101
{FFX_FSR2_RESOURCE_IDENTIFIER_SCENE_LUMINANCE_MIPMAP_SHADING_CHANGE, L"rw_img_mip_shading_change"},
102
{FFX_FSR2_RESOURCE_IDENTIFIER_SCENE_LUMINANCE_MIPMAP_5, L"rw_img_mip_5"},
103
{FFX_FSR2_RESOURCE_IDENTIFIER_DILATED_REACTIVE_MASKS, L"rw_dilated_reactive_masks"},
104
{FFX_FSR2_RESOURCE_IDENTIFIER_AUTO_EXPOSURE, L"rw_auto_exposure"},
105
{FFX_FSR2_RESOURCE_IDENTIFIER_SPD_ATOMIC_COUNT, L"rw_spd_global_atomic"},
106
{FFX_FSR2_RESOURCE_IDENTIFIER_NEW_LOCKS, L"rw_new_locks"},
107
{FFX_FSR2_RESOURCE_IDENTIFIER_LOCK_INPUT_LUMA, L"rw_lock_input_luma"},
108
{FFX_FSR2_RESOURCE_IDENTIFIER_AUTOREACTIVE, L"rw_output_autoreactive"},
109
{FFX_FSR2_RESOURCE_IDENTIFIER_AUTOCOMPOSITION, L"rw_output_autocomposition"},
110
{FFX_FSR2_RESOURCE_IDENTIFIER_PREV_PRE_ALPHA_COLOR, L"rw_output_prev_color_pre_alpha"},
111
{FFX_FSR2_RESOURCE_IDENTIFIER_PREV_POST_ALPHA_COLOR, L"rw_output_prev_color_post_alpha"},
112
};
113
114
static const ResourceBinding cbResourceBindingTable[] =
115
{
116
{FFX_FSR2_CONSTANTBUFFER_IDENTIFIER_FSR2, L"cbFSR2"},
117
{FFX_FSR2_CONSTANTBUFFER_IDENTIFIER_SPD, L"cbSPD"},
118
{FFX_FSR2_CONSTANTBUFFER_IDENTIFIER_RCAS, L"cbRCAS"},
119
{FFX_FSR2_CONSTANTBUFFER_IDENTIFIER_GENREACTIVE, L"cbGenerateReactive"},
120
};
121
122
// Broad structure of the root signature.
123
typedef enum Fsr2RootSignatureLayout {
124
125
FSR2_ROOT_SIGNATURE_LAYOUT_UAVS,
126
FSR2_ROOT_SIGNATURE_LAYOUT_SRVS,
127
FSR2_ROOT_SIGNATURE_LAYOUT_CONSTANTS,
128
FSR2_ROOT_SIGNATURE_LAYOUT_CONSTANTS_REGISTER_1,
129
FSR2_ROOT_SIGNATURE_LAYOUT_PARAMETER_COUNT
130
} Fsr2RootSignatureLayout;
131
132
typedef struct Fsr2RcasConstants {
133
134
uint32_t rcasConfig[4];
135
} FfxRcasConstants;
136
137
typedef struct Fsr2SpdConstants {
138
139
uint32_t mips;
140
uint32_t numworkGroups;
141
uint32_t workGroupOffset[2];
142
uint32_t renderSize[2];
143
} Fsr2SpdConstants;
144
145
typedef struct Fsr2GenerateReactiveConstants
146
{
147
float scale;
148
float threshold;
149
float binaryValue;
150
uint32_t flags;
151
152
} Fsr2GenerateReactiveConstants;
153
154
typedef struct Fsr2GenerateReactiveConstants2
155
{
156
float autoTcThreshold;
157
float autoTcScale;
158
float autoReactiveScale;
159
float autoReactiveMax;
160
161
} Fsr2GenerateReactiveConstants2;
162
163
typedef union Fsr2SecondaryUnion {
164
165
Fsr2RcasConstants rcas;
166
Fsr2SpdConstants spd;
167
Fsr2GenerateReactiveConstants2 autogenReactive;
168
} Fsr2SecondaryUnion;
169
170
typedef struct Fsr2ResourceDescription {
171
172
uint32_t id;
173
const wchar_t* name;
174
FfxResourceUsage usage;
175
FfxSurfaceFormat format;
176
uint32_t width;
177
uint32_t height;
178
uint32_t mipCount;
179
FfxResourceFlags flags;
180
uint32_t initDataSize;
181
void* initData;
182
} Fsr2ResourceDescription;
183
184
FfxConstantBuffer globalFsr2ConstantBuffers[4] = {
185
{ sizeof(Fsr2Constants) / sizeof(uint32_t) },
186
{ sizeof(Fsr2SpdConstants) / sizeof(uint32_t) },
187
{ sizeof(Fsr2RcasConstants) / sizeof(uint32_t) },
188
{ sizeof(Fsr2GenerateReactiveConstants) / sizeof(uint32_t) }
189
};
190
191
// Lanczos
192
static float lanczos2(float value)
193
{
194
return abs(value) < FFX_EPSILON ? 1.f : (sinf(FFX_PI * value) / (FFX_PI * value)) * (sinf(0.5f * FFX_PI * value) / (0.5f * FFX_PI * value));
195
}
196
197
// Calculate halton number for index and base.
198
static float halton(int32_t index, int32_t base)
199
{
200
float f = 1.0f, result = 0.0f;
201
202
for (int32_t currentIndex = index; currentIndex > 0;) {
203
204
f /= (float)base;
205
result = result + f * (float)(currentIndex % base);
206
currentIndex = (uint32_t)(floorf((float)(currentIndex) / (float)(base)));
207
}
208
209
return result;
210
}
211
212
static void fsr2DebugCheckDispatch(FfxFsr2Context_Private* context, const FfxFsr2DispatchDescription* params)
213
{
214
if (params->commandList == nullptr)
215
{
216
context->contextDescription.fpMessage(FFX_FSR2_MESSAGE_TYPE_ERROR, L"commandList is null");
217
}
218
219
if (params->color.resource == nullptr)
220
{
221
context->contextDescription.fpMessage(FFX_FSR2_MESSAGE_TYPE_ERROR, L"color resource is null");
222
}
223
224
if (params->depth.resource == nullptr)
225
{
226
context->contextDescription.fpMessage(FFX_FSR2_MESSAGE_TYPE_ERROR, L"depth resource is null");
227
}
228
229
if (params->motionVectors.resource == nullptr)
230
{
231
context->contextDescription.fpMessage(FFX_FSR2_MESSAGE_TYPE_ERROR, L"motionVectors resource is null");
232
}
233
234
if (params->exposure.resource != nullptr)
235
{
236
if ((context->contextDescription.flags & FFX_FSR2_ENABLE_AUTO_EXPOSURE) == FFX_FSR2_ENABLE_AUTO_EXPOSURE)
237
{
238
context->contextDescription.fpMessage(FFX_FSR2_MESSAGE_TYPE_WARNING, L"exposure resource provided, however auto exposure flag is present");
239
}
240
}
241
242
if (params->output.resource == nullptr)
243
{
244
context->contextDescription.fpMessage(FFX_FSR2_MESSAGE_TYPE_ERROR, L"output resource is null");
245
}
246
247
if (fabs(params->jitterOffset.x) > 1.0f || fabs(params->jitterOffset.y) > 1.0f)
248
{
249
context->contextDescription.fpMessage(FFX_FSR2_MESSAGE_TYPE_WARNING, L"jitterOffset contains value outside of expected range [-1.0, 1.0]");
250
}
251
252
if ((params->motionVectorScale.x > (float)context->contextDescription.maxRenderSize.width) ||
253
(params->motionVectorScale.y > (float)context->contextDescription.maxRenderSize.height))
254
{
255
context->contextDescription.fpMessage(FFX_FSR2_MESSAGE_TYPE_WARNING, L"motionVectorScale contains scale value greater than maxRenderSize");
256
}
257
if ((params->motionVectorScale.x == 0.0f) ||
258
(params->motionVectorScale.y == 0.0f))
259
{
260
context->contextDescription.fpMessage(FFX_FSR2_MESSAGE_TYPE_WARNING, L"motionVectorScale contains zero scale value");
261
}
262
263
if ((params->renderSize.width > context->contextDescription.maxRenderSize.width) ||
264
(params->renderSize.height > context->contextDescription.maxRenderSize.height))
265
{
266
context->contextDescription.fpMessage(FFX_FSR2_MESSAGE_TYPE_WARNING, L"renderSize is greater than context maxRenderSize");
267
}
268
if ((params->renderSize.width == 0) ||
269
(params->renderSize.height == 0))
270
{
271
context->contextDescription.fpMessage(FFX_FSR2_MESSAGE_TYPE_WARNING, L"renderSize contains zero dimension");
272
}
273
274
if (params->sharpness < 0.0f || params->sharpness > 1.0f)
275
{
276
context->contextDescription.fpMessage(FFX_FSR2_MESSAGE_TYPE_WARNING, L"sharpness contains value outside of expected range [0.0, 1.0]");
277
}
278
279
if (params->frameTimeDelta < 1.0f)
280
{
281
context->contextDescription.fpMessage(FFX_FSR2_MESSAGE_TYPE_WARNING, L"frameTimeDelta is less than 1.0f - this value should be milliseconds (~16.6f for 60fps)");
282
}
283
284
if (params->preExposure == 0.0f)
285
{
286
context->contextDescription.fpMessage(FFX_FSR2_MESSAGE_TYPE_ERROR, L"preExposure provided as 0.0f which is invalid");
287
}
288
289
bool infiniteDepth = (context->contextDescription.flags & FFX_FSR2_ENABLE_DEPTH_INFINITE) == FFX_FSR2_ENABLE_DEPTH_INFINITE;
290
bool inverseDepth = (context->contextDescription.flags & FFX_FSR2_ENABLE_DEPTH_INVERTED) == FFX_FSR2_ENABLE_DEPTH_INVERTED;
291
292
if (inverseDepth)
293
{
294
if (params->cameraNear < params->cameraFar)
295
{
296
context->contextDescription.fpMessage(FFX_FSR2_MESSAGE_TYPE_WARNING,
297
L"FFX_FSR2_ENABLE_DEPTH_INVERTED flag is present yet cameraNear is less than cameraFar");
298
}
299
if (infiniteDepth)
300
{
301
if (params->cameraNear != FLT_MAX)
302
{
303
context->contextDescription.fpMessage(FFX_FSR2_MESSAGE_TYPE_WARNING,
304
L"FFX_FSR2_ENABLE_DEPTH_INFINITE and FFX_FSR2_ENABLE_DEPTH_INVERTED present, yet cameraNear != FLT_MAX");
305
}
306
}
307
if (params->cameraFar < 0.075f)
308
{
309
context->contextDescription.fpMessage(FFX_FSR2_MESSAGE_TYPE_WARNING,
310
L"FFX_FSR2_ENABLE_DEPTH_INFINITE and FFX_FSR2_ENABLE_DEPTH_INVERTED present, cameraFar value is very low which may result in depth separation artefacting");
311
}
312
}
313
else
314
{
315
if (params->cameraNear > params->cameraFar)
316
{
317
context->contextDescription.fpMessage(FFX_FSR2_MESSAGE_TYPE_WARNING,
318
L"cameraNear is greater than cameraFar in non-inverted-depth context");
319
}
320
if (infiniteDepth)
321
{
322
if (params->cameraFar != FLT_MAX)
323
{
324
context->contextDescription.fpMessage(FFX_FSR2_MESSAGE_TYPE_WARNING,
325
L"FFX_FSR2_ENABLE_DEPTH_INFINITE and FFX_FSR2_ENABLE_DEPTH_INVERTED present, yet cameraFar != FLT_MAX");
326
}
327
}
328
if (params->cameraNear < 0.075f)
329
{
330
context->contextDescription.fpMessage(FFX_FSR2_MESSAGE_TYPE_WARNING,
331
L"FFX_FSR2_ENABLE_DEPTH_INFINITE and FFX_FSR2_ENABLE_DEPTH_INVERTED present, cameraNear value is very low which may result in depth separation artefacting");
332
}
333
}
334
335
if (params->cameraFovAngleVertical <= 0.0f)
336
{
337
context->contextDescription.fpMessage(FFX_FSR2_MESSAGE_TYPE_ERROR, L"cameraFovAngleVertical is 0.0f - this value should be > 0.0f");
338
}
339
if (params->cameraFovAngleVertical > FFX_PI)
340
{
341
context->contextDescription.fpMessage(FFX_FSR2_MESSAGE_TYPE_ERROR, L"cameraFovAngleVertical is greater than 180 degrees/PI");
342
}
343
}
344
345
static FfxErrorCode patchResourceBindings(FfxPipelineState* inoutPipeline)
346
{
347
for (uint32_t srvIndex = 0; srvIndex < inoutPipeline->srvCount; ++srvIndex)
348
{
349
int32_t mapIndex = 0;
350
for (mapIndex = 0; mapIndex < _countof(srvResourceBindingTable); ++mapIndex)
351
{
352
if (0 == wcscmp(srvResourceBindingTable[mapIndex].name, inoutPipeline->srvResourceBindings[srvIndex].name))
353
break;
354
}
355
if (mapIndex == _countof(srvResourceBindingTable))
356
return FFX_ERROR_INVALID_ARGUMENT;
357
358
inoutPipeline->srvResourceBindings[srvIndex].resourceIdentifier = srvResourceBindingTable[mapIndex].index;
359
}
360
361
for (uint32_t uavIndex = 0; uavIndex < inoutPipeline->uavCount; ++uavIndex)
362
{
363
int32_t mapIndex = 0;
364
for (mapIndex = 0; mapIndex < _countof(uavResourceBindingTable); ++mapIndex)
365
{
366
if (0 == wcscmp(uavResourceBindingTable[mapIndex].name, inoutPipeline->uavResourceBindings[uavIndex].name))
367
break;
368
}
369
if (mapIndex == _countof(uavResourceBindingTable))
370
return FFX_ERROR_INVALID_ARGUMENT;
371
372
inoutPipeline->uavResourceBindings[uavIndex].resourceIdentifier = uavResourceBindingTable[mapIndex].index;
373
}
374
375
for (uint32_t cbIndex = 0; cbIndex < inoutPipeline->constCount; ++cbIndex)
376
{
377
int32_t mapIndex = 0;
378
for (mapIndex = 0; mapIndex < _countof(cbResourceBindingTable); ++mapIndex)
379
{
380
if (0 == wcscmp(cbResourceBindingTable[mapIndex].name, inoutPipeline->cbResourceBindings[cbIndex].name))
381
break;
382
}
383
if (mapIndex == _countof(cbResourceBindingTable))
384
return FFX_ERROR_INVALID_ARGUMENT;
385
386
inoutPipeline->cbResourceBindings[cbIndex].resourceIdentifier = cbResourceBindingTable[mapIndex].index;
387
}
388
389
return FFX_OK;
390
}
391
392
393
static FfxErrorCode createPipelineStates(FfxFsr2Context_Private* context)
394
{
395
FFX_ASSERT(context);
396
397
const size_t samplerCount = 2;
398
FfxFilterType samplers[samplerCount];
399
samplers[0] = FFX_FILTER_TYPE_POINT;
400
samplers[1] = FFX_FILTER_TYPE_LINEAR;
401
402
const size_t rootConstantCount = 2;
403
uint32_t rootConstants[rootConstantCount];
404
rootConstants[0] = sizeof(Fsr2Constants) / sizeof(uint32_t);
405
rootConstants[1] = sizeof(Fsr2SecondaryUnion) / sizeof(uint32_t);
406
407
FfxPipelineDescription pipelineDescription;
408
pipelineDescription.contextFlags = context->contextDescription.flags;
409
pipelineDescription.samplerCount = samplerCount;
410
pipelineDescription.samplers = samplers;
411
pipelineDescription.rootConstantBufferCount = rootConstantCount;
412
pipelineDescription.rootConstantBufferSizes = rootConstants;
413
414
// New interface: will handle RootSignature in backend
415
// set up pipeline descriptor (basically RootSignature and binding)
416
FFX_VALIDATE(context->contextDescription.callbacks.fpCreatePipeline(&context->contextDescription.callbacks, FFX_FSR2_PASS_COMPUTE_LUMINANCE_PYRAMID, &pipelineDescription, &context->pipelineComputeLuminancePyramid));
417
FFX_VALIDATE(context->contextDescription.callbacks.fpCreatePipeline(&context->contextDescription.callbacks, FFX_FSR2_PASS_RCAS, &pipelineDescription, &context->pipelineRCAS));
418
FFX_VALIDATE(context->contextDescription.callbacks.fpCreatePipeline(&context->contextDescription.callbacks, FFX_FSR2_PASS_GENERATE_REACTIVE, &pipelineDescription, &context->pipelineGenerateReactive));
419
FFX_VALIDATE(context->contextDescription.callbacks.fpCreatePipeline(&context->contextDescription.callbacks, FFX_FSR2_PASS_TCR_AUTOGENERATE, &pipelineDescription, &context->pipelineTcrAutogenerate));
420
421
pipelineDescription.rootConstantBufferCount = 1;
422
FFX_VALIDATE(context->contextDescription.callbacks.fpCreatePipeline(&context->contextDescription.callbacks, FFX_FSR2_PASS_DEPTH_CLIP, &pipelineDescription, &context->pipelineDepthClip));
423
FFX_VALIDATE(context->contextDescription.callbacks.fpCreatePipeline(&context->contextDescription.callbacks, FFX_FSR2_PASS_RECONSTRUCT_PREVIOUS_DEPTH, &pipelineDescription, &context->pipelineReconstructPreviousDepth));
424
FFX_VALIDATE(context->contextDescription.callbacks.fpCreatePipeline(&context->contextDescription.callbacks, FFX_FSR2_PASS_LOCK, &pipelineDescription, &context->pipelineLock));
425
FFX_VALIDATE(context->contextDescription.callbacks.fpCreatePipeline(&context->contextDescription.callbacks, FFX_FSR2_PASS_ACCUMULATE, &pipelineDescription, &context->pipelineAccumulate));
426
FFX_VALIDATE(context->contextDescription.callbacks.fpCreatePipeline(&context->contextDescription.callbacks, FFX_FSR2_PASS_ACCUMULATE_SHARPEN, &pipelineDescription, &context->pipelineAccumulateSharpen));
427
428
// for each pipeline: re-route/fix-up IDs based on names
429
patchResourceBindings(&context->pipelineDepthClip);
430
patchResourceBindings(&context->pipelineReconstructPreviousDepth);
431
patchResourceBindings(&context->pipelineLock);
432
patchResourceBindings(&context->pipelineAccumulate);
433
patchResourceBindings(&context->pipelineComputeLuminancePyramid);
434
patchResourceBindings(&context->pipelineAccumulateSharpen);
435
patchResourceBindings(&context->pipelineRCAS);
436
patchResourceBindings(&context->pipelineGenerateReactive);
437
patchResourceBindings(&context->pipelineTcrAutogenerate);
438
439
return FFX_OK;
440
}
441
442
static FfxErrorCode generateReactiveMaskInternal(FfxFsr2Context_Private* contextPrivate, const FfxFsr2DispatchDescription* params);
443
444
static FfxErrorCode fsr2Create(FfxFsr2Context_Private* context, const FfxFsr2ContextDescription* contextDescription)
445
{
446
FFX_ASSERT(context);
447
FFX_ASSERT(contextDescription);
448
449
// Setup the data for implementation.
450
memset(context, 0, sizeof(FfxFsr2Context_Private));
451
context->device = contextDescription->device;
452
453
memcpy(&context->contextDescription, contextDescription, sizeof(FfxFsr2ContextDescription));
454
455
if ((context->contextDescription.flags & FFX_FSR2_ENABLE_DEBUG_CHECKING) == FFX_FSR2_ENABLE_DEBUG_CHECKING)
456
{
457
if (context->contextDescription.fpMessage == nullptr)
458
{
459
FFX_ASSERT(context->contextDescription.fpMessage != nullptr);
460
// remove the debug checking flag - we have no message function
461
context->contextDescription.flags &= ~FFX_FSR2_ENABLE_DEBUG_CHECKING;
462
}
463
}
464
465
// Create the device.
466
FfxErrorCode errorCode = context->contextDescription.callbacks.fpCreateBackendContext(&context->contextDescription.callbacks, context->device);
467
FFX_RETURN_ON_ERROR(errorCode == FFX_OK, errorCode);
468
469
// call out for device caps.
470
errorCode = context->contextDescription.callbacks.fpGetDeviceCapabilities(&context->contextDescription.callbacks, &context->deviceCapabilities, context->device);
471
FFX_RETURN_ON_ERROR(errorCode == FFX_OK, errorCode);
472
473
// set defaults
474
context->firstExecution = true;
475
context->resourceFrameIndex = 0;
476
477
context->constants.displaySize[0] = contextDescription->displaySize.width;
478
context->constants.displaySize[1] = contextDescription->displaySize.height;
479
480
// generate the data for the LUT.
481
const uint32_t lanczos2LutWidth = 128;
482
int16_t lanczos2Weights[lanczos2LutWidth] = { };
483
484
for (uint32_t currentLanczosWidthIndex = 0; currentLanczosWidthIndex < lanczos2LutWidth; currentLanczosWidthIndex++) {
485
486
const float x = 2.0f * currentLanczosWidthIndex / float(lanczos2LutWidth - 1);
487
const float y = lanczos2(x);
488
lanczos2Weights[currentLanczosWidthIndex] = int16_t(roundf(y * 32767.0f));
489
}
490
491
// upload path only supports R16_SNORM, let's go and convert
492
int16_t maximumBias[FFX_FSR2_MAXIMUM_BIAS_TEXTURE_WIDTH * FFX_FSR2_MAXIMUM_BIAS_TEXTURE_HEIGHT];
493
for (uint32_t i = 0; i < FFX_FSR2_MAXIMUM_BIAS_TEXTURE_WIDTH * FFX_FSR2_MAXIMUM_BIAS_TEXTURE_HEIGHT; ++i) {
494
495
maximumBias[i] = int16_t(roundf(ffxFsr2MaximumBias[i] / 2.0f * 32767.0f));
496
}
497
498
uint8_t defaultReactiveMaskData = 0U;
499
uint32_t atomicInitData = 0U;
500
float defaultExposure[] = { 0.0f, 0.0f };
501
const FfxResourceType texture1dResourceType = (context->contextDescription.flags & FFX_FSR2_ENABLE_TEXTURE1D_USAGE) ? FFX_RESOURCE_TYPE_TEXTURE1D : FFX_RESOURCE_TYPE_TEXTURE2D;
502
503
// declare internal resources needed
504
const Fsr2ResourceDescription internalSurfaceDesc[] = {
505
506
{ FFX_FSR2_RESOURCE_IDENTIFIER_PREPARED_INPUT_COLOR, L"FSR2_PreparedInputColor", FFX_RESOURCE_USAGE_UAV,
507
FFX_SURFACE_FORMAT_R16G16B16A16_FLOAT, contextDescription->maxRenderSize.width, contextDescription->maxRenderSize.height, 1, FFX_RESOURCE_FLAGS_ALIASABLE },
508
509
{ FFX_FSR2_RESOURCE_IDENTIFIER_RECONSTRUCTED_PREVIOUS_NEAREST_DEPTH, L"FSR2_ReconstructedPrevNearestDepth", FFX_RESOURCE_USAGE_UAV,
510
FFX_SURFACE_FORMAT_R32_UINT, contextDescription->maxRenderSize.width, contextDescription->maxRenderSize.height, 1, FFX_RESOURCE_FLAGS_ALIASABLE },
511
512
{ FFX_FSR2_RESOURCE_IDENTIFIER_INTERNAL_DILATED_MOTION_VECTORS_1, L"FSR2_InternalDilatedVelocity1", (FfxResourceUsage)(FFX_RESOURCE_USAGE_RENDERTARGET | FFX_RESOURCE_USAGE_UAV),
513
FFX_SURFACE_FORMAT_R16G16_FLOAT, contextDescription->maxRenderSize.width, contextDescription->maxRenderSize.height, 1, FFX_RESOURCE_FLAGS_NONE },
514
515
{ FFX_FSR2_RESOURCE_IDENTIFIER_INTERNAL_DILATED_MOTION_VECTORS_2, L"FSR2_InternalDilatedVelocity2", (FfxResourceUsage)(FFX_RESOURCE_USAGE_RENDERTARGET | FFX_RESOURCE_USAGE_UAV),
516
FFX_SURFACE_FORMAT_R16G16_FLOAT, contextDescription->maxRenderSize.width, contextDescription->maxRenderSize.height, 1, FFX_RESOURCE_FLAGS_NONE },
517
518
{ FFX_FSR2_RESOURCE_IDENTIFIER_DILATED_DEPTH, L"FSR2_DilatedDepth", (FfxResourceUsage)(FFX_RESOURCE_USAGE_RENDERTARGET | FFX_RESOURCE_USAGE_UAV),
519
FFX_SURFACE_FORMAT_R32_FLOAT, contextDescription->maxRenderSize.width, contextDescription->maxRenderSize.height, 1, FFX_RESOURCE_FLAGS_ALIASABLE },
520
521
{ FFX_FSR2_RESOURCE_IDENTIFIER_LOCK_STATUS_1, L"FSR2_LockStatus1", (FfxResourceUsage)(FFX_RESOURCE_USAGE_RENDERTARGET | FFX_RESOURCE_USAGE_UAV),
522
FFX_SURFACE_FORMAT_R16G16_FLOAT, contextDescription->displaySize.width, contextDescription->displaySize.height, 1, FFX_RESOURCE_FLAGS_NONE },
523
524
{ FFX_FSR2_RESOURCE_IDENTIFIER_LOCK_STATUS_2, L"FSR2_LockStatus2", (FfxResourceUsage)(FFX_RESOURCE_USAGE_RENDERTARGET | FFX_RESOURCE_USAGE_UAV),
525
FFX_SURFACE_FORMAT_R16G16_FLOAT, contextDescription->displaySize.width, contextDescription->displaySize.height, 1, FFX_RESOURCE_FLAGS_NONE },
526
527
{ FFX_FSR2_RESOURCE_IDENTIFIER_LOCK_INPUT_LUMA, L"FSR2_LockInputLuma", (FfxResourceUsage)(FFX_RESOURCE_USAGE_UAV),
528
FFX_SURFACE_FORMAT_R16_FLOAT, contextDescription->maxRenderSize.width, contextDescription->maxRenderSize.height, 1, FFX_RESOURCE_FLAGS_ALIASABLE },
529
530
{ FFX_FSR2_RESOURCE_IDENTIFIER_NEW_LOCKS, L"FSR2_NewLocks", (FfxResourceUsage)(FFX_RESOURCE_USAGE_UAV),
531
FFX_SURFACE_FORMAT_R8_UNORM, contextDescription->displaySize.width, contextDescription->displaySize.height, 1, FFX_RESOURCE_FLAGS_ALIASABLE },
532
533
{ FFX_FSR2_RESOURCE_IDENTIFIER_INTERNAL_UPSCALED_COLOR_1, L"FSR2_InternalUpscaled1", (FfxResourceUsage)(FFX_RESOURCE_USAGE_RENDERTARGET | FFX_RESOURCE_USAGE_UAV),
534
FFX_SURFACE_FORMAT_R16G16B16A16_FLOAT, contextDescription->displaySize.width, contextDescription->displaySize.height, 1, FFX_RESOURCE_FLAGS_NONE },
535
536
{ FFX_FSR2_RESOURCE_IDENTIFIER_INTERNAL_UPSCALED_COLOR_2, L"FSR2_InternalUpscaled2", (FfxResourceUsage)(FFX_RESOURCE_USAGE_RENDERTARGET | FFX_RESOURCE_USAGE_UAV),
537
FFX_SURFACE_FORMAT_R16G16B16A16_FLOAT, contextDescription->displaySize.width, contextDescription->displaySize.height, 1, FFX_RESOURCE_FLAGS_NONE },
538
539
{ FFX_FSR2_RESOURCE_IDENTIFIER_SCENE_LUMINANCE, L"FSR2_ExposureMips", FFX_RESOURCE_USAGE_UAV,
540
FFX_SURFACE_FORMAT_R16_FLOAT, contextDescription->maxRenderSize.width / 2, contextDescription->maxRenderSize.height / 2, 0, FFX_RESOURCE_FLAGS_ALIASABLE },
541
542
{ FFX_FSR2_RESOURCE_IDENTIFIER_LUMA_HISTORY_1, L"FSR2_LumaHistory1", (FfxResourceUsage)(FFX_RESOURCE_USAGE_RENDERTARGET | FFX_RESOURCE_USAGE_UAV),
543
FFX_SURFACE_FORMAT_R8G8B8A8_UNORM, contextDescription->displaySize.width, contextDescription->displaySize.height, 1, FFX_RESOURCE_FLAGS_NONE },
544
545
{ FFX_FSR2_RESOURCE_IDENTIFIER_LUMA_HISTORY_2, L"FSR2_LumaHistory2", (FfxResourceUsage)(FFX_RESOURCE_USAGE_RENDERTARGET | FFX_RESOURCE_USAGE_UAV),
546
FFX_SURFACE_FORMAT_R8G8B8A8_UNORM, contextDescription->displaySize.width, contextDescription->displaySize.height, 1, FFX_RESOURCE_FLAGS_NONE },
547
548
{ FFX_FSR2_RESOURCE_IDENTIFIER_SPD_ATOMIC_COUNT, L"FSR2_SpdAtomicCounter", (FfxResourceUsage)(FFX_RESOURCE_USAGE_UAV),
549
FFX_SURFACE_FORMAT_R32_UINT, 1, 1, 1, FFX_RESOURCE_FLAGS_ALIASABLE, sizeof(atomicInitData), &atomicInitData },
550
551
{ FFX_FSR2_RESOURCE_IDENTIFIER_DILATED_REACTIVE_MASKS, L"FSR2_DilatedReactiveMasks", FFX_RESOURCE_USAGE_UAV,
552
FFX_SURFACE_FORMAT_R8G8_UNORM, contextDescription->maxRenderSize.width, contextDescription->maxRenderSize.height, 1, FFX_RESOURCE_FLAGS_ALIASABLE },
553
554
{ FFX_FSR2_RESOURCE_IDENTIFIER_LANCZOS_LUT, L"FSR2_LanczosLutData", FFX_RESOURCE_USAGE_READ_ONLY,
555
FFX_SURFACE_FORMAT_R16_SNORM, lanczos2LutWidth, 1, 1, FFX_RESOURCE_FLAGS_NONE, sizeof(lanczos2Weights), lanczos2Weights },
556
557
{ FFX_FSR2_RESOURCE_IDENTIFIER_INTERNAL_DEFAULT_REACTIVITY, L"FSR2_DefaultReactiviyMask", FFX_RESOURCE_USAGE_READ_ONLY,
558
FFX_SURFACE_FORMAT_R8_UNORM, 1, 1, 1, FFX_RESOURCE_FLAGS_NONE, sizeof(defaultReactiveMaskData), &defaultReactiveMaskData },
559
560
{ FFX_FSR2_RESOURCE_IDENTITIER_UPSAMPLE_MAXIMUM_BIAS_LUT, L"FSR2_MaximumUpsampleBias", FFX_RESOURCE_USAGE_READ_ONLY,
561
FFX_SURFACE_FORMAT_R16_SNORM, FFX_FSR2_MAXIMUM_BIAS_TEXTURE_WIDTH, FFX_FSR2_MAXIMUM_BIAS_TEXTURE_HEIGHT, 1, FFX_RESOURCE_FLAGS_NONE, sizeof(maximumBias), maximumBias },
562
563
{ FFX_FSR2_RESOURCE_IDENTIFIER_INTERNAL_DEFAULT_EXPOSURE, L"FSR2_DefaultExposure", FFX_RESOURCE_USAGE_READ_ONLY,
564
FFX_SURFACE_FORMAT_R32G32_FLOAT, 1, 1, 1, FFX_RESOURCE_FLAGS_NONE, sizeof(defaultExposure), defaultExposure },
565
566
{ FFX_FSR2_RESOURCE_IDENTIFIER_AUTO_EXPOSURE, L"FSR2_AutoExposure", FFX_RESOURCE_USAGE_UAV,
567
FFX_SURFACE_FORMAT_R32G32_FLOAT, 1, 1, 1, FFX_RESOURCE_FLAGS_NONE },
568
569
570
// only one for now, will need pingpont to respect the motion vectors
571
{ FFX_FSR2_RESOURCE_IDENTIFIER_AUTOREACTIVE, L"FSR2_AutoReactive", FFX_RESOURCE_USAGE_UAV,
572
FFX_SURFACE_FORMAT_R8_UNORM, contextDescription->maxRenderSize.width, contextDescription->maxRenderSize.height, 1, FFX_RESOURCE_FLAGS_NONE },
573
{ FFX_FSR2_RESOURCE_IDENTIFIER_AUTOCOMPOSITION, L"FSR2_AutoComposition", FFX_RESOURCE_USAGE_UAV,
574
FFX_SURFACE_FORMAT_R8_UNORM, contextDescription->maxRenderSize.width, contextDescription->maxRenderSize.height, 1, FFX_RESOURCE_FLAGS_NONE },
575
{ FFX_FSR2_RESOURCE_IDENTIFIER_PREV_PRE_ALPHA_COLOR_1, L"FSR2_PrevPreAlpha0", FFX_RESOURCE_USAGE_UAV,
576
FFX_SURFACE_FORMAT_R11G11B10_FLOAT, contextDescription->maxRenderSize.width, contextDescription->maxRenderSize.height, 1, FFX_RESOURCE_FLAGS_NONE },
577
{ FFX_FSR2_RESOURCE_IDENTIFIER_PREV_POST_ALPHA_COLOR_1, L"FSR2_PrevPostAlpha0", FFX_RESOURCE_USAGE_UAV,
578
FFX_SURFACE_FORMAT_R11G11B10_FLOAT, contextDescription->maxRenderSize.width, contextDescription->maxRenderSize.height, 1, FFX_RESOURCE_FLAGS_NONE },
579
{ FFX_FSR2_RESOURCE_IDENTIFIER_PREV_PRE_ALPHA_COLOR_2, L"FSR2_PrevPreAlpha1", FFX_RESOURCE_USAGE_UAV,
580
FFX_SURFACE_FORMAT_R11G11B10_FLOAT, contextDescription->maxRenderSize.width, contextDescription->maxRenderSize.height, 1, FFX_RESOURCE_FLAGS_NONE },
581
{ FFX_FSR2_RESOURCE_IDENTIFIER_PREV_POST_ALPHA_COLOR_2, L"FSR2_PrevPostAlpha1", FFX_RESOURCE_USAGE_UAV,
582
FFX_SURFACE_FORMAT_R11G11B10_FLOAT, contextDescription->maxRenderSize.width, contextDescription->maxRenderSize.height, 1, FFX_RESOURCE_FLAGS_NONE },
583
584
};
585
586
// clear the SRV resources to NULL.
587
memset(context->srvResources, 0, sizeof(context->srvResources));
588
589
for (int32_t currentSurfaceIndex = 0; currentSurfaceIndex < FFX_ARRAY_ELEMENTS(internalSurfaceDesc); ++currentSurfaceIndex) {
590
591
const Fsr2ResourceDescription* currentSurfaceDescription = &internalSurfaceDesc[currentSurfaceIndex];
592
const FfxResourceType resourceType = currentSurfaceDescription->height > 1 ? FFX_RESOURCE_TYPE_TEXTURE2D : texture1dResourceType;
593
const FfxResourceDescription resourceDescription = { resourceType, currentSurfaceDescription->format, currentSurfaceDescription->width, currentSurfaceDescription->height, 1, currentSurfaceDescription->mipCount };
594
const FfxResourceStates initialState = (currentSurfaceDescription->usage == FFX_RESOURCE_USAGE_READ_ONLY) ? FFX_RESOURCE_STATE_COMPUTE_READ : FFX_RESOURCE_STATE_UNORDERED_ACCESS;
595
const FfxCreateResourceDescription createResourceDescription = { FFX_HEAP_TYPE_DEFAULT, resourceDescription, initialState, currentSurfaceDescription->initDataSize, currentSurfaceDescription->initData, currentSurfaceDescription->name, currentSurfaceDescription->usage, currentSurfaceDescription->id };
596
597
FFX_VALIDATE(context->contextDescription.callbacks.fpCreateResource(&context->contextDescription.callbacks, &createResourceDescription, &context->srvResources[currentSurfaceDescription->id]));
598
}
599
600
// copy resources to uavResrouces list
601
memcpy(context->uavResources, context->srvResources, sizeof(context->srvResources));
602
603
// avoid compiling pipelines on first render
604
{
605
context->refreshPipelineStates = false;
606
errorCode = createPipelineStates(context);
607
FFX_RETURN_ON_ERROR(errorCode == FFX_OK, errorCode);
608
}
609
return FFX_OK;
610
}
611
612
static void fsr2SafeReleasePipeline(FfxFsr2Context_Private* context, FfxPipelineState* pipeline)
613
{
614
FFX_ASSERT(pipeline);
615
616
context->contextDescription.callbacks.fpDestroyPipeline(&context->contextDescription.callbacks, pipeline);
617
}
618
619
static void fsr2SafeReleaseResource(FfxFsr2Context_Private* context, FfxResourceInternal resource)
620
{
621
context->contextDescription.callbacks.fpDestroyResource(&context->contextDescription.callbacks, resource);
622
}
623
624
static void fsr2SafeReleaseDevice(FfxFsr2Context_Private* context, FfxDevice* device)
625
{
626
if (*device == nullptr) {
627
return;
628
}
629
630
context->contextDescription.callbacks.fpDestroyBackendContext(&context->contextDescription.callbacks);
631
*device = nullptr;
632
}
633
634
static FfxErrorCode fsr2Release(FfxFsr2Context_Private* context)
635
{
636
FFX_ASSERT(context);
637
638
fsr2SafeReleasePipeline(context, &context->pipelineDepthClip);
639
fsr2SafeReleasePipeline(context, &context->pipelineReconstructPreviousDepth);
640
fsr2SafeReleasePipeline(context, &context->pipelineLock);
641
fsr2SafeReleasePipeline(context, &context->pipelineAccumulate);
642
fsr2SafeReleasePipeline(context, &context->pipelineAccumulateSharpen);
643
fsr2SafeReleasePipeline(context, &context->pipelineRCAS);
644
fsr2SafeReleasePipeline(context, &context->pipelineComputeLuminancePyramid);
645
fsr2SafeReleasePipeline(context, &context->pipelineGenerateReactive);
646
fsr2SafeReleasePipeline(context, &context->pipelineTcrAutogenerate);
647
648
// unregister resources not created internally
649
context->srvResources[FFX_FSR2_RESOURCE_IDENTIFIER_INPUT_OPAQUE_ONLY] = { FFX_FSR2_RESOURCE_IDENTIFIER_NULL };
650
context->srvResources[FFX_FSR2_RESOURCE_IDENTIFIER_INPUT_COLOR] = { FFX_FSR2_RESOURCE_IDENTIFIER_NULL };
651
context->srvResources[FFX_FSR2_RESOURCE_IDENTIFIER_INPUT_DEPTH] = { FFX_FSR2_RESOURCE_IDENTIFIER_NULL };
652
context->srvResources[FFX_FSR2_RESOURCE_IDENTIFIER_INPUT_MOTION_VECTORS] = { FFX_FSR2_RESOURCE_IDENTIFIER_NULL };
653
context->srvResources[FFX_FSR2_RESOURCE_IDENTIFIER_INPUT_EXPOSURE] = { FFX_FSR2_RESOURCE_IDENTIFIER_NULL };
654
context->srvResources[FFX_FSR2_RESOURCE_IDENTIFIER_INPUT_REACTIVE_MASK] = { FFX_FSR2_RESOURCE_IDENTIFIER_NULL };
655
context->srvResources[FFX_FSR2_RESOURCE_IDENTIFIER_INPUT_TRANSPARENCY_AND_COMPOSITION_MASK] = { FFX_FSR2_RESOURCE_IDENTIFIER_NULL };
656
context->srvResources[FFX_FSR2_RESOURCE_IDENTIFIER_LOCK_STATUS] = { FFX_FSR2_RESOURCE_IDENTIFIER_NULL };
657
context->srvResources[FFX_FSR2_RESOURCE_IDENTIFIER_INTERNAL_UPSCALED_COLOR] = { FFX_FSR2_RESOURCE_IDENTIFIER_NULL };
658
context->srvResources[FFX_FSR2_RESOURCE_IDENTIFIER_RCAS_INPUT] = { FFX_FSR2_RESOURCE_IDENTIFIER_NULL };
659
context->srvResources[FFX_FSR2_RESOURCE_IDENTIFIER_UPSCALED_OUTPUT] = { FFX_FSR2_RESOURCE_IDENTIFIER_NULL };
660
661
// release internal resources
662
for (int32_t currentResourceIndex = 0; currentResourceIndex < FFX_FSR2_RESOURCE_IDENTIFIER_COUNT; ++currentResourceIndex) {
663
664
fsr2SafeReleaseResource(context, context->srvResources[currentResourceIndex]);
665
}
666
667
fsr2SafeReleaseDevice(context, &context->device);
668
669
return FFX_OK;
670
}
671
672
static void setupDeviceDepthToViewSpaceDepthParams(FfxFsr2Context_Private* context, const FfxFsr2DispatchDescription* params)
673
{
674
const bool bInverted = (context->contextDescription.flags & FFX_FSR2_ENABLE_DEPTH_INVERTED) == FFX_FSR2_ENABLE_DEPTH_INVERTED;
675
const bool bInfinite = (context->contextDescription.flags & FFX_FSR2_ENABLE_DEPTH_INFINITE) == FFX_FSR2_ENABLE_DEPTH_INFINITE;
676
677
// make sure it has no impact if near and far plane values are swapped in dispatch params
678
// the flags "inverted" and "infinite" will decide what transform to use
679
float fMin = FFX_MINIMUM(params->cameraNear, params->cameraFar);
680
float fMax = FFX_MAXIMUM(params->cameraNear, params->cameraFar);
681
682
if (bInverted) {
683
float tmp = fMin;
684
fMin = fMax;
685
fMax = tmp;
686
}
687
688
// a 0 0 0 x
689
// 0 b 0 0 y
690
// 0 0 c d z
691
// 0 0 e 0 1
692
693
const float fQ = fMax / (fMin - fMax);
694
const float d = -1.0f; // for clarity
695
696
const float matrix_elem_c[2][2] = {
697
fQ, // non reversed, non infinite
698
-1.0f - FLT_EPSILON, // non reversed, infinite
699
fQ, // reversed, non infinite
700
0.0f + FLT_EPSILON // reversed, infinite
701
};
702
703
const float matrix_elem_e[2][2] = {
704
fQ * fMin, // non reversed, non infinite
705
-fMin - FLT_EPSILON, // non reversed, infinite
706
fQ * fMin, // reversed, non infinite
707
fMax, // reversed, infinite
708
};
709
710
context->constants.deviceToViewDepth[0] = d * matrix_elem_c[bInverted][bInfinite];
711
context->constants.deviceToViewDepth[1] = matrix_elem_e[bInverted][bInfinite];
712
713
// revert x and y coords
714
const float aspect = params->renderSize.width / float(params->renderSize.height);
715
const float cotHalfFovY = cosf(0.5f * params->cameraFovAngleVertical) / sinf(0.5f * params->cameraFovAngleVertical);
716
const float a = cotHalfFovY / aspect;
717
const float b = cotHalfFovY;
718
719
context->constants.deviceToViewDepth[2] = (1.0f / a);
720
context->constants.deviceToViewDepth[3] = (1.0f / b);
721
}
722
723
static void scheduleDispatch(FfxFsr2Context_Private* context, const FfxFsr2DispatchDescription* params, const FfxPipelineState* pipeline, uint32_t dispatchX, uint32_t dispatchY)
724
{
725
FfxComputeJobDescription jobDescriptor = {};
726
727
for (uint32_t currentShaderResourceViewIndex = 0; currentShaderResourceViewIndex < pipeline->srvCount; ++currentShaderResourceViewIndex) {
728
729
const uint32_t currentResourceId = pipeline->srvResourceBindings[currentShaderResourceViewIndex].resourceIdentifier;
730
const FfxResourceInternal currentResource = context->srvResources[currentResourceId];
731
jobDescriptor.srvs[currentShaderResourceViewIndex] = currentResource;
732
wcscpy_s(jobDescriptor.srvNames[currentShaderResourceViewIndex], pipeline->srvResourceBindings[currentShaderResourceViewIndex].name);
733
}
734
735
for (uint32_t currentUnorderedAccessViewIndex = 0; currentUnorderedAccessViewIndex < pipeline->uavCount; ++currentUnorderedAccessViewIndex) {
736
737
const uint32_t currentResourceId = pipeline->uavResourceBindings[currentUnorderedAccessViewIndex].resourceIdentifier;
738
wcscpy_s(jobDescriptor.uavNames[currentUnorderedAccessViewIndex], pipeline->uavResourceBindings[currentUnorderedAccessViewIndex].name);
739
740
if (currentResourceId >= FFX_FSR2_RESOURCE_IDENTIFIER_SCENE_LUMINANCE_MIPMAP_0 && currentResourceId <= FFX_FSR2_RESOURCE_IDENTIFIER_SCENE_LUMINANCE_MIPMAP_12)
741
{
742
const FfxResourceInternal currentResource = context->uavResources[FFX_FSR2_RESOURCE_IDENTIFIER_SCENE_LUMINANCE];
743
jobDescriptor.uavs[currentUnorderedAccessViewIndex] = currentResource;
744
jobDescriptor.uavMip[currentUnorderedAccessViewIndex] = currentResourceId - FFX_FSR2_RESOURCE_IDENTIFIER_SCENE_LUMINANCE_MIPMAP_0;
745
}
746
else
747
{
748
const FfxResourceInternal currentResource = context->uavResources[currentResourceId];
749
jobDescriptor.uavs[currentUnorderedAccessViewIndex] = currentResource;
750
jobDescriptor.uavMip[currentUnorderedAccessViewIndex] = 0;
751
}
752
}
753
754
jobDescriptor.dimensions[0] = dispatchX;
755
jobDescriptor.dimensions[1] = dispatchY;
756
jobDescriptor.dimensions[2] = 1;
757
jobDescriptor.pipeline = *pipeline;
758
759
for (uint32_t currentRootConstantIndex = 0; currentRootConstantIndex < pipeline->constCount; ++currentRootConstantIndex) {
760
wcscpy_s( jobDescriptor.cbNames[currentRootConstantIndex], pipeline->cbResourceBindings[currentRootConstantIndex].name);
761
jobDescriptor.cbs[currentRootConstantIndex] = globalFsr2ConstantBuffers[pipeline->cbResourceBindings[currentRootConstantIndex].resourceIdentifier];
762
jobDescriptor.cbSlotIndex[currentRootConstantIndex] = pipeline->cbResourceBindings[currentRootConstantIndex].slotIndex;
763
}
764
765
FfxGpuJobDescription dispatchJob = { FFX_GPU_JOB_COMPUTE };
766
dispatchJob.computeJobDescriptor = jobDescriptor;
767
768
context->contextDescription.callbacks.fpScheduleGpuJob(&context->contextDescription.callbacks, &dispatchJob);
769
}
770
771
static FfxErrorCode fsr2Dispatch(FfxFsr2Context_Private* context, const FfxFsr2DispatchDescription* params)
772
{
773
if ((context->contextDescription.flags & FFX_FSR2_ENABLE_DEBUG_CHECKING) == FFX_FSR2_ENABLE_DEBUG_CHECKING)
774
{
775
fsr2DebugCheckDispatch(context, params);
776
}
777
// take a short cut to the command list
778
FfxCommandList commandList = params->commandList;
779
780
// try and refresh shaders first. Early exit in case of error.
781
if (context->refreshPipelineStates) {
782
783
context->refreshPipelineStates = false;
784
785
const FfxErrorCode errorCode = createPipelineStates(context);
786
FFX_RETURN_ON_ERROR(errorCode == FFX_OK, errorCode);
787
}
788
789
if (context->firstExecution)
790
{
791
FfxGpuJobDescription clearJob = { FFX_GPU_JOB_CLEAR_FLOAT };
792
793
const float clearValuesToZeroFloat[]{ 0.f, 0.f, 0.f, 0.f };
794
memcpy(clearJob.clearJobDescriptor.color, clearValuesToZeroFloat, 4 * sizeof(float));
795
796
clearJob.clearJobDescriptor.target = context->srvResources[FFX_FSR2_RESOURCE_IDENTIFIER_LOCK_STATUS_1];
797
context->contextDescription.callbacks.fpScheduleGpuJob(&context->contextDescription.callbacks, &clearJob);
798
clearJob.clearJobDescriptor.target = context->srvResources[FFX_FSR2_RESOURCE_IDENTIFIER_LOCK_STATUS_2];
799
context->contextDescription.callbacks.fpScheduleGpuJob(&context->contextDescription.callbacks, &clearJob);
800
clearJob.clearJobDescriptor.target = context->srvResources[FFX_FSR2_RESOURCE_IDENTIFIER_PREPARED_INPUT_COLOR];
801
context->contextDescription.callbacks.fpScheduleGpuJob(&context->contextDescription.callbacks, &clearJob);
802
}
803
804
// Prepare per frame descriptor tables
805
const bool isOddFrame = !!(context->resourceFrameIndex & 1);
806
const uint32_t currentCpuOnlyTableBase = isOddFrame ? FFX_FSR2_RESOURCE_IDENTIFIER_COUNT : 0;
807
const uint32_t currentGpuTableBase = 2 * FFX_FSR2_RESOURCE_IDENTIFIER_COUNT * context->resourceFrameIndex;
808
const uint32_t lockStatusSrvResourceIndex = isOddFrame ? FFX_FSR2_RESOURCE_IDENTIFIER_LOCK_STATUS_2 : FFX_FSR2_RESOURCE_IDENTIFIER_LOCK_STATUS_1;
809
const uint32_t lockStatusUavResourceIndex = isOddFrame ? FFX_FSR2_RESOURCE_IDENTIFIER_LOCK_STATUS_1 : FFX_FSR2_RESOURCE_IDENTIFIER_LOCK_STATUS_2;
810
const uint32_t upscaledColorSrvResourceIndex = isOddFrame ? FFX_FSR2_RESOURCE_IDENTIFIER_INTERNAL_UPSCALED_COLOR_2 : FFX_FSR2_RESOURCE_IDENTIFIER_INTERNAL_UPSCALED_COLOR_1;
811
const uint32_t upscaledColorUavResourceIndex = isOddFrame ? FFX_FSR2_RESOURCE_IDENTIFIER_INTERNAL_UPSCALED_COLOR_1 : FFX_FSR2_RESOURCE_IDENTIFIER_INTERNAL_UPSCALED_COLOR_2;
812
const uint32_t dilatedMotionVectorsResourceIndex = isOddFrame ? FFX_FSR2_RESOURCE_IDENTIFIER_INTERNAL_DILATED_MOTION_VECTORS_2 : FFX_FSR2_RESOURCE_IDENTIFIER_INTERNAL_DILATED_MOTION_VECTORS_1;
813
const uint32_t previousDilatedMotionVectorsResourceIndex = isOddFrame ? FFX_FSR2_RESOURCE_IDENTIFIER_INTERNAL_DILATED_MOTION_VECTORS_1 : FFX_FSR2_RESOURCE_IDENTIFIER_INTERNAL_DILATED_MOTION_VECTORS_2;
814
const uint32_t lumaHistorySrvResourceIndex = isOddFrame ? FFX_FSR2_RESOURCE_IDENTIFIER_LUMA_HISTORY_2 : FFX_FSR2_RESOURCE_IDENTIFIER_LUMA_HISTORY_1;
815
const uint32_t lumaHistoryUavResourceIndex = isOddFrame ? FFX_FSR2_RESOURCE_IDENTIFIER_LUMA_HISTORY_1 : FFX_FSR2_RESOURCE_IDENTIFIER_LUMA_HISTORY_2;
816
817
const uint32_t prevPreAlphaColorSrvResourceIndex = isOddFrame ? FFX_FSR2_RESOURCE_IDENTIFIER_PREV_PRE_ALPHA_COLOR_2 : FFX_FSR2_RESOURCE_IDENTIFIER_PREV_PRE_ALPHA_COLOR_1;
818
const uint32_t prevPreAlphaColorUavResourceIndex = isOddFrame ? FFX_FSR2_RESOURCE_IDENTIFIER_PREV_PRE_ALPHA_COLOR_1 : FFX_FSR2_RESOURCE_IDENTIFIER_PREV_PRE_ALPHA_COLOR_2;
819
const uint32_t prevPostAlphaColorSrvResourceIndex = isOddFrame ? FFX_FSR2_RESOURCE_IDENTIFIER_PREV_POST_ALPHA_COLOR_2 : FFX_FSR2_RESOURCE_IDENTIFIER_PREV_POST_ALPHA_COLOR_1;
820
const uint32_t prevPostAlphaColorUavResourceIndex = isOddFrame ? FFX_FSR2_RESOURCE_IDENTIFIER_PREV_POST_ALPHA_COLOR_1 : FFX_FSR2_RESOURCE_IDENTIFIER_PREV_POST_ALPHA_COLOR_2;
821
822
const bool resetAccumulation = params->reset || context->firstExecution;
823
context->firstExecution = false;
824
825
context->contextDescription.callbacks.fpRegisterResource(&context->contextDescription.callbacks, &params->color, &context->srvResources[FFX_FSR2_RESOURCE_IDENTIFIER_INPUT_COLOR]);
826
context->contextDescription.callbacks.fpRegisterResource(&context->contextDescription.callbacks, &params->depth, &context->srvResources[FFX_FSR2_RESOURCE_IDENTIFIER_INPUT_DEPTH]);
827
context->contextDescription.callbacks.fpRegisterResource(&context->contextDescription.callbacks, &params->motionVectors, &context->srvResources[FFX_FSR2_RESOURCE_IDENTIFIER_INPUT_MOTION_VECTORS]);
828
829
// if auto exposure is enabled use the auto exposure SRV, otherwise what the app sends.
830
if (context->contextDescription.flags & FFX_FSR2_ENABLE_AUTO_EXPOSURE) {
831
context->srvResources[FFX_FSR2_RESOURCE_IDENTIFIER_INPUT_EXPOSURE] = context->srvResources[FFX_FSR2_RESOURCE_IDENTIFIER_AUTO_EXPOSURE];
832
} else {
833
if (ffxFsr2ResourceIsNull(params->exposure)) {
834
context->srvResources[FFX_FSR2_RESOURCE_IDENTIFIER_INPUT_EXPOSURE] = context->srvResources[FFX_FSR2_RESOURCE_IDENTIFIER_INTERNAL_DEFAULT_EXPOSURE];
835
} else {
836
context->contextDescription.callbacks.fpRegisterResource(&context->contextDescription.callbacks, &params->exposure, &context->srvResources[FFX_FSR2_RESOURCE_IDENTIFIER_INPUT_EXPOSURE]);
837
}
838
}
839
840
if (params->enableAutoReactive)
841
{
842
context->contextDescription.callbacks.fpRegisterResource(&context->contextDescription.callbacks, &params->colorOpaqueOnly, &context->srvResources[FFX_FSR2_RESOURCE_IDENTIFIER_PREV_PRE_ALPHA_COLOR]);
843
}
844
845
if (ffxFsr2ResourceIsNull(params->reactive)) {
846
context->srvResources[FFX_FSR2_RESOURCE_IDENTIFIER_INPUT_REACTIVE_MASK] = context->srvResources[FFX_FSR2_RESOURCE_IDENTIFIER_INTERNAL_DEFAULT_REACTIVITY];
847
}
848
else {
849
context->contextDescription.callbacks.fpRegisterResource(&context->contextDescription.callbacks, &params->reactive, &context->srvResources[FFX_FSR2_RESOURCE_IDENTIFIER_INPUT_REACTIVE_MASK]);
850
}
851
852
if (ffxFsr2ResourceIsNull(params->transparencyAndComposition)) {
853
context->srvResources[FFX_FSR2_RESOURCE_IDENTIFIER_INPUT_TRANSPARENCY_AND_COMPOSITION_MASK] = context->srvResources[FFX_FSR2_RESOURCE_IDENTIFIER_INTERNAL_DEFAULT_REACTIVITY];
854
} else {
855
context->contextDescription.callbacks.fpRegisterResource(&context->contextDescription.callbacks, &params->transparencyAndComposition, &context->srvResources[FFX_FSR2_RESOURCE_IDENTIFIER_INPUT_TRANSPARENCY_AND_COMPOSITION_MASK]);
856
}
857
858
context->contextDescription.callbacks.fpRegisterResource(&context->contextDescription.callbacks, &params->output, &context->uavResources[FFX_FSR2_RESOURCE_IDENTIFIER_UPSCALED_OUTPUT]);
859
context->srvResources[FFX_FSR2_RESOURCE_IDENTIFIER_LOCK_STATUS] = context->srvResources[lockStatusSrvResourceIndex];
860
context->srvResources[FFX_FSR2_RESOURCE_IDENTIFIER_INTERNAL_UPSCALED_COLOR] = context->srvResources[upscaledColorSrvResourceIndex];
861
context->uavResources[FFX_FSR2_RESOURCE_IDENTIFIER_LOCK_STATUS] = context->uavResources[lockStatusUavResourceIndex];
862
context->uavResources[FFX_FSR2_RESOURCE_IDENTIFIER_INTERNAL_UPSCALED_COLOR] = context->uavResources[upscaledColorUavResourceIndex];
863
context->srvResources[FFX_FSR2_RESOURCE_IDENTIFIER_RCAS_INPUT] = context->uavResources[upscaledColorUavResourceIndex];
864
865
context->srvResources[FFX_FSR2_RESOURCE_IDENTIFIER_DILATED_MOTION_VECTORS] = context->srvResources[dilatedMotionVectorsResourceIndex];
866
context->uavResources[FFX_FSR2_RESOURCE_IDENTIFIER_DILATED_MOTION_VECTORS] = context->uavResources[dilatedMotionVectorsResourceIndex];
867
context->srvResources[FFX_FSR2_RESOURCE_IDENTIFIER_PREVIOUS_DILATED_MOTION_VECTORS] = context->srvResources[previousDilatedMotionVectorsResourceIndex];
868
869
context->uavResources[FFX_FSR2_RESOURCE_IDENTIFIER_LUMA_HISTORY] = context->uavResources[lumaHistoryUavResourceIndex];
870
context->srvResources[FFX_FSR2_RESOURCE_IDENTIFIER_LUMA_HISTORY] = context->srvResources[lumaHistorySrvResourceIndex];
871
872
context->srvResources[FFX_FSR2_RESOURCE_IDENTIFIER_PREV_PRE_ALPHA_COLOR] = context->srvResources[prevPreAlphaColorSrvResourceIndex];
873
context->uavResources[FFX_FSR2_RESOURCE_IDENTIFIER_PREV_PRE_ALPHA_COLOR] = context->uavResources[prevPreAlphaColorUavResourceIndex];
874
context->srvResources[FFX_FSR2_RESOURCE_IDENTIFIER_PREV_POST_ALPHA_COLOR] = context->srvResources[prevPostAlphaColorSrvResourceIndex];
875
context->uavResources[FFX_FSR2_RESOURCE_IDENTIFIER_PREV_POST_ALPHA_COLOR] = context->uavResources[prevPostAlphaColorUavResourceIndex];
876
877
// actual resource size may differ from render/display resolution (e.g. due to Hw/API restrictions), so query the descriptor for UVs adjustment
878
const FfxResourceDescription resourceDescInputColor = context->contextDescription.callbacks.fpGetResourceDescription(&context->contextDescription.callbacks, context->srvResources[FFX_FSR2_RESOURCE_IDENTIFIER_INPUT_COLOR]);
879
const FfxResourceDescription resourceDescLockStatus = context->contextDescription.callbacks.fpGetResourceDescription(&context->contextDescription.callbacks, context->srvResources[lockStatusSrvResourceIndex]);
880
const FfxResourceDescription resourceDescReactiveMask = context->contextDescription.callbacks.fpGetResourceDescription(&context->contextDescription.callbacks, context->srvResources[FFX_FSR2_RESOURCE_IDENTIFIER_INPUT_REACTIVE_MASK]);
881
FFX_ASSERT(resourceDescInputColor.type == FFX_RESOURCE_TYPE_TEXTURE2D);
882
FFX_ASSERT(resourceDescLockStatus.type == FFX_RESOURCE_TYPE_TEXTURE2D);
883
884
context->constants.jitterOffset[0] = params->jitterOffset.x;
885
context->constants.jitterOffset[1] = params->jitterOffset.y;
886
context->constants.renderSize[0] = int32_t(params->renderSize.width ? params->renderSize.width : resourceDescInputColor.width);
887
context->constants.renderSize[1] = int32_t(params->renderSize.height ? params->renderSize.height : resourceDescInputColor.height);
888
context->constants.maxRenderSize[0] = int32_t(context->contextDescription.maxRenderSize.width);
889
context->constants.maxRenderSize[1] = int32_t(context->contextDescription.maxRenderSize.height);
890
context->constants.inputColorResourceDimensions[0] = resourceDescInputColor.width;
891
context->constants.inputColorResourceDimensions[1] = resourceDescInputColor.height;
892
893
// compute the horizontal FOV for the shader from the vertical one.
894
const float aspectRatio = (float)params->renderSize.width / (float)params->renderSize.height;
895
const float cameraAngleHorizontal = atan(tan(params->cameraFovAngleVertical / 2) * aspectRatio) * 2;
896
context->constants.tanHalfFOV = tanf(cameraAngleHorizontal * 0.5f);
897
context->constants.viewSpaceToMetersFactor = (params->viewSpaceToMetersFactor > 0.0f) ? params->viewSpaceToMetersFactor : 1.0f;
898
899
// compute params to enable device depth to view space depth computation in shader
900
setupDeviceDepthToViewSpaceDepthParams(context, params);
901
902
// To be updated if resource is larger than the actual image size
903
context->constants.downscaleFactor[0] = float(context->constants.renderSize[0]) / context->contextDescription.displaySize.width;
904
context->constants.downscaleFactor[1] = float(context->constants.renderSize[1]) / context->contextDescription.displaySize.height;
905
context->constants.previousFramePreExposure = context->constants.preExposure;
906
context->constants.preExposure = (params->preExposure != 0) ? params->preExposure : 1.0f;
907
908
// motion vector data
909
const int32_t* motionVectorsTargetSize = (context->contextDescription.flags & FFX_FSR2_ENABLE_DISPLAY_RESOLUTION_MOTION_VECTORS) ? context->constants.displaySize : context->constants.renderSize;
910
911
context->constants.motionVectorScale[0] = (params->motionVectorScale.x / motionVectorsTargetSize[0]);
912
context->constants.motionVectorScale[1] = (params->motionVectorScale.y / motionVectorsTargetSize[1]);
913
914
// compute jitter cancellation
915
if (context->contextDescription.flags & FFX_FSR2_ENABLE_MOTION_VECTORS_JITTER_CANCELLATION) {
916
917
context->constants.motionVectorJitterCancellation[0] = (context->previousJitterOffset[0] - context->constants.jitterOffset[0]) / motionVectorsTargetSize[0];
918
context->constants.motionVectorJitterCancellation[1] = (context->previousJitterOffset[1] - context->constants.jitterOffset[1]) / motionVectorsTargetSize[1];
919
920
context->previousJitterOffset[0] = context->constants.jitterOffset[0];
921
context->previousJitterOffset[1] = context->constants.jitterOffset[1];
922
}
923
924
// lock data, assuming jitter sequence length computation for now
925
const int32_t jitterPhaseCount = ffxFsr2GetJitterPhaseCount(params->renderSize.width, context->contextDescription.displaySize.width);
926
927
// init on first frame
928
if (resetAccumulation || context->constants.jitterPhaseCount == 0) {
929
context->constants.jitterPhaseCount = (float)jitterPhaseCount;
930
} else {
931
const int32_t jitterPhaseCountDelta = (int32_t)(jitterPhaseCount - context->constants.jitterPhaseCount);
932
if (jitterPhaseCountDelta > 0) {
933
context->constants.jitterPhaseCount++;
934
} else if (jitterPhaseCountDelta < 0) {
935
context->constants.jitterPhaseCount--;
936
}
937
}
938
939
// convert delta time to seconds and clamp to [0, 1].
940
context->constants.deltaTime = FFX_MAXIMUM(0.0f, FFX_MINIMUM(1.0f, params->frameTimeDelta / 1000.0f));
941
942
if (resetAccumulation) {
943
context->constants.frameIndex = 0;
944
} else {
945
context->constants.frameIndex++;
946
}
947
948
// shading change usage of the SPD mip levels.
949
context->constants.lumaMipLevelToUse = uint32_t(FFX_FSR2_SHADING_CHANGE_MIP_LEVEL);
950
951
const float mipDiv = float(2 << context->constants.lumaMipLevelToUse);
952
context->constants.lumaMipDimensions[0] = uint32_t(context->constants.maxRenderSize[0] / mipDiv);
953
context->constants.lumaMipDimensions[1] = uint32_t(context->constants.maxRenderSize[1] / mipDiv);
954
955
memcpy(context->constants.reprojectionMatrix, params->reprojectionMatrix, sizeof(context->constants.reprojectionMatrix));
956
957
// reactive mask bias
958
const int32_t threadGroupWorkRegionDim = 8;
959
const int32_t dispatchSrcX = (context->constants.renderSize[0] + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
960
const int32_t dispatchSrcY = (context->constants.renderSize[1] + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
961
const int32_t dispatchDstX = (context->contextDescription.displaySize.width + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
962
const int32_t dispatchDstY = (context->contextDescription.displaySize.height + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
963
964
// Clear reconstructed depth for max depth store.
965
if (resetAccumulation) {
966
967
FfxGpuJobDescription clearJob = { FFX_GPU_JOB_CLEAR_FLOAT };
968
969
// LockStatus resource has no sign bit, callback functions are compensating for this.
970
// Clearing the resource must follow the same logic.
971
float clearValuesLockStatus[4]{};
972
clearValuesLockStatus[LOCK_LIFETIME_REMAINING] = 0.0f;
973
clearValuesLockStatus[LOCK_TEMPORAL_LUMA] = 0.0f;
974
975
memcpy(clearJob.clearJobDescriptor.color, clearValuesLockStatus, 4 * sizeof(float));
976
clearJob.clearJobDescriptor.target = context->srvResources[lockStatusSrvResourceIndex];
977
context->contextDescription.callbacks.fpScheduleGpuJob(&context->contextDescription.callbacks, &clearJob);
978
979
const float clearValuesToZeroFloat[]{ 0.f, 0.f, 0.f, 0.f };
980
memcpy(clearJob.clearJobDescriptor.color, clearValuesToZeroFloat, 4 * sizeof(float));
981
clearJob.clearJobDescriptor.target = context->srvResources[upscaledColorSrvResourceIndex];
982
context->contextDescription.callbacks.fpScheduleGpuJob(&context->contextDescription.callbacks, &clearJob);
983
984
clearJob.clearJobDescriptor.target = context->srvResources[FFX_FSR2_RESOURCE_IDENTIFIER_SCENE_LUMINANCE];
985
context->contextDescription.callbacks.fpScheduleGpuJob(&context->contextDescription.callbacks, &clearJob);
986
987
//if (context->contextDescription.flags & FFX_FSR2_ENABLE_AUTO_EXPOSURE)
988
// Auto exposure always used to track luma changes in locking logic
989
{
990
const float clearValuesExposure[]{ -1.f, 1e8f, 0.f, 0.f };
991
memcpy(clearJob.clearJobDescriptor.color, clearValuesExposure, 4 * sizeof(float));
992
clearJob.clearJobDescriptor.target = context->srvResources[FFX_FSR2_RESOURCE_IDENTIFIER_AUTO_EXPOSURE];
993
context->contextDescription.callbacks.fpScheduleGpuJob(&context->contextDescription.callbacks, &clearJob);
994
}
995
}
996
997
// Auto exposure
998
uint32_t dispatchThreadGroupCountXY[2];
999
uint32_t workGroupOffset[2];
1000
uint32_t numWorkGroupsAndMips[2];
1001
uint32_t rectInfo[4] = { 0, 0, params->renderSize.width, params->renderSize.height };
1002
SpdSetup(dispatchThreadGroupCountXY, workGroupOffset, numWorkGroupsAndMips, rectInfo);
1003
1004
// downsample
1005
Fsr2SpdConstants luminancePyramidConstants;
1006
luminancePyramidConstants.numworkGroups = numWorkGroupsAndMips[0];
1007
luminancePyramidConstants.mips = numWorkGroupsAndMips[1];
1008
luminancePyramidConstants.workGroupOffset[0] = workGroupOffset[0];
1009
luminancePyramidConstants.workGroupOffset[1] = workGroupOffset[1];
1010
luminancePyramidConstants.renderSize[0] = params->renderSize.width;
1011
luminancePyramidConstants.renderSize[1] = params->renderSize.height;
1012
1013
// compute the constants.
1014
Fsr2RcasConstants rcasConsts = {};
1015
const float sharpenessRemapped = (-2.0f * params->sharpness) + 2.0f;
1016
FsrRcasCon(rcasConsts.rcasConfig, sharpenessRemapped);
1017
1018
Fsr2GenerateReactiveConstants2 genReactiveConsts = {};
1019
genReactiveConsts.autoTcThreshold = params->autoTcThreshold;
1020
genReactiveConsts.autoTcScale = params->autoTcScale;
1021
genReactiveConsts.autoReactiveScale = params->autoReactiveScale;
1022
genReactiveConsts.autoReactiveMax = params->autoReactiveMax;
1023
1024
// initialize constantBuffers data
1025
memcpy(&globalFsr2ConstantBuffers[FFX_FSR2_CONSTANTBUFFER_IDENTIFIER_FSR2].data, &context->constants, globalFsr2ConstantBuffers[FFX_FSR2_CONSTANTBUFFER_IDENTIFIER_FSR2].uint32Size * sizeof(uint32_t));
1026
memcpy(&globalFsr2ConstantBuffers[FFX_FSR2_CONSTANTBUFFER_IDENTIFIER_SPD].data, &luminancePyramidConstants, globalFsr2ConstantBuffers[FFX_FSR2_CONSTANTBUFFER_IDENTIFIER_SPD].uint32Size * sizeof(uint32_t));
1027
memcpy(&globalFsr2ConstantBuffers[FFX_FSR2_CONSTANTBUFFER_IDENTIFIER_RCAS].data, &rcasConsts, globalFsr2ConstantBuffers[FFX_FSR2_CONSTANTBUFFER_IDENTIFIER_RCAS].uint32Size * sizeof(uint32_t));
1028
memcpy(&globalFsr2ConstantBuffers[FFX_FSR2_CONSTANTBUFFER_IDENTIFIER_GENREACTIVE].data, &genReactiveConsts, globalFsr2ConstantBuffers[FFX_FSR2_CONSTANTBUFFER_IDENTIFIER_GENREACTIVE].uint32Size * sizeof(uint32_t));
1029
1030
// Auto reactive
1031
if (params->enableAutoReactive)
1032
{
1033
generateReactiveMaskInternal(context, params);
1034
context->srvResources[FFX_FSR2_RESOURCE_IDENTIFIER_INPUT_REACTIVE_MASK] = context->srvResources[FFX_FSR2_RESOURCE_IDENTIFIER_AUTOREACTIVE];
1035
context->srvResources[FFX_FSR2_RESOURCE_IDENTIFIER_INPUT_TRANSPARENCY_AND_COMPOSITION_MASK] = context->srvResources[FFX_FSR2_RESOURCE_IDENTIFIER_AUTOCOMPOSITION];
1036
}
1037
scheduleDispatch(context, params, &context->pipelineComputeLuminancePyramid, dispatchThreadGroupCountXY[0], dispatchThreadGroupCountXY[1]);
1038
scheduleDispatch(context, params, &context->pipelineReconstructPreviousDepth, dispatchSrcX, dispatchSrcY);
1039
scheduleDispatch(context, params, &context->pipelineDepthClip, dispatchSrcX, dispatchSrcY);
1040
1041
const bool sharpenEnabled = params->enableSharpening;
1042
1043
scheduleDispatch(context, params, &context->pipelineLock, dispatchSrcX, dispatchSrcY);
1044
scheduleDispatch(context, params, sharpenEnabled ? &context->pipelineAccumulateSharpen : &context->pipelineAccumulate, dispatchDstX, dispatchDstY);
1045
1046
// RCAS
1047
if (sharpenEnabled) {
1048
1049
// dispatch RCAS
1050
const int32_t threadGroupWorkRegionDimRCAS = 16;
1051
const int32_t dispatchX = (context->contextDescription.displaySize.width + (threadGroupWorkRegionDimRCAS - 1)) / threadGroupWorkRegionDimRCAS;
1052
const int32_t dispatchY = (context->contextDescription.displaySize.height + (threadGroupWorkRegionDimRCAS - 1)) / threadGroupWorkRegionDimRCAS;
1053
scheduleDispatch(context, params, &context->pipelineRCAS, dispatchX, dispatchY);
1054
}
1055
1056
context->resourceFrameIndex = (context->resourceFrameIndex + 1) % FSR2_MAX_QUEUED_FRAMES;
1057
1058
// Fsr2MaxQueuedFrames must be an even number.
1059
FFX_STATIC_ASSERT((FSR2_MAX_QUEUED_FRAMES & 1) == 0);
1060
1061
context->contextDescription.callbacks.fpExecuteGpuJobs(&context->contextDescription.callbacks, commandList);
1062
1063
// release dynamic resources
1064
context->contextDescription.callbacks.fpUnregisterResources(&context->contextDescription.callbacks);
1065
1066
return FFX_OK;
1067
}
1068
1069
FfxErrorCode ffxFsr2ContextCreate(FfxFsr2Context* context, const FfxFsr2ContextDescription* contextDescription)
1070
{
1071
// zero context memory
1072
memset(context, 0, sizeof(FfxFsr2Context));
1073
1074
// check pointers are valid.
1075
FFX_RETURN_ON_ERROR(
1076
context,
1077
FFX_ERROR_INVALID_POINTER);
1078
FFX_RETURN_ON_ERROR(
1079
contextDescription,
1080
FFX_ERROR_INVALID_POINTER);
1081
1082
// validate that all callbacks are set for the interface
1083
FFX_RETURN_ON_ERROR(contextDescription->callbacks.fpGetDeviceCapabilities, FFX_ERROR_INCOMPLETE_INTERFACE);
1084
FFX_RETURN_ON_ERROR(contextDescription->callbacks.fpCreateBackendContext, FFX_ERROR_INCOMPLETE_INTERFACE);
1085
FFX_RETURN_ON_ERROR(contextDescription->callbacks.fpDestroyBackendContext, FFX_ERROR_INCOMPLETE_INTERFACE);
1086
1087
// if a scratch buffer is declared, then we must have a size
1088
if (contextDescription->callbacks.scratchBuffer) {
1089
1090
FFX_RETURN_ON_ERROR(contextDescription->callbacks.scratchBufferSize, FFX_ERROR_INCOMPLETE_INTERFACE);
1091
}
1092
1093
// ensure the context is large enough for the internal context.
1094
FFX_STATIC_ASSERT(sizeof(FfxFsr2Context) >= sizeof(FfxFsr2Context_Private));
1095
1096
// create the context.
1097
FfxFsr2Context_Private* contextPrivate = (FfxFsr2Context_Private*)(context);
1098
const FfxErrorCode errorCode = fsr2Create(contextPrivate, contextDescription);
1099
1100
return errorCode;
1101
}
1102
1103
FfxErrorCode ffxFsr2ContextDestroy(FfxFsr2Context* context)
1104
{
1105
FFX_RETURN_ON_ERROR(
1106
context,
1107
FFX_ERROR_INVALID_POINTER);
1108
1109
// destroy the context.
1110
FfxFsr2Context_Private* contextPrivate = (FfxFsr2Context_Private*)(context);
1111
const FfxErrorCode errorCode = fsr2Release(contextPrivate);
1112
return errorCode;
1113
}
1114
1115
FfxErrorCode ffxFsr2ContextDispatch(FfxFsr2Context* context, const FfxFsr2DispatchDescription* dispatchParams)
1116
{
1117
FFX_RETURN_ON_ERROR(
1118
context,
1119
FFX_ERROR_INVALID_POINTER);
1120
FFX_RETURN_ON_ERROR(
1121
dispatchParams,
1122
FFX_ERROR_INVALID_POINTER);
1123
1124
FfxFsr2Context_Private* contextPrivate = (FfxFsr2Context_Private*)(context);
1125
1126
// validate that renderSize is within the maximum.
1127
FFX_RETURN_ON_ERROR(
1128
dispatchParams->renderSize.width <= contextPrivate->contextDescription.maxRenderSize.width,
1129
FFX_ERROR_OUT_OF_RANGE);
1130
FFX_RETURN_ON_ERROR(
1131
dispatchParams->renderSize.height <= contextPrivate->contextDescription.maxRenderSize.height,
1132
FFX_ERROR_OUT_OF_RANGE);
1133
FFX_RETURN_ON_ERROR(
1134
contextPrivate->device,
1135
FFX_ERROR_NULL_DEVICE);
1136
1137
// dispatch the FSR2 passes.
1138
const FfxErrorCode errorCode = fsr2Dispatch(contextPrivate, dispatchParams);
1139
return errorCode;
1140
}
1141
1142
float ffxFsr2GetUpscaleRatioFromQualityMode(FfxFsr2QualityMode qualityMode)
1143
{
1144
switch (qualityMode) {
1145
1146
case FFX_FSR2_QUALITY_MODE_QUALITY:
1147
return 1.5f;
1148
case FFX_FSR2_QUALITY_MODE_BALANCED:
1149
return 1.7f;
1150
case FFX_FSR2_QUALITY_MODE_PERFORMANCE:
1151
return 2.0f;
1152
case FFX_FSR2_QUALITY_MODE_ULTRA_PERFORMANCE:
1153
return 3.0f;
1154
default:
1155
return 0.0f;
1156
}
1157
}
1158
1159
FfxErrorCode ffxFsr2GetRenderResolutionFromQualityMode(
1160
uint32_t* renderWidth,
1161
uint32_t* renderHeight,
1162
uint32_t displayWidth,
1163
uint32_t displayHeight,
1164
FfxFsr2QualityMode qualityMode)
1165
{
1166
FFX_RETURN_ON_ERROR(
1167
renderWidth,
1168
FFX_ERROR_INVALID_POINTER);
1169
FFX_RETURN_ON_ERROR(
1170
renderHeight,
1171
FFX_ERROR_INVALID_POINTER);
1172
FFX_RETURN_ON_ERROR(
1173
FFX_FSR2_QUALITY_MODE_QUALITY <= qualityMode && qualityMode <= FFX_FSR2_QUALITY_MODE_ULTRA_PERFORMANCE,
1174
FFX_ERROR_INVALID_ENUM);
1175
1176
// scale by the predefined ratios in each dimension.
1177
const float ratio = ffxFsr2GetUpscaleRatioFromQualityMode(qualityMode);
1178
const uint32_t scaledDisplayWidth = (uint32_t)((float)displayWidth / ratio);
1179
const uint32_t scaledDisplayHeight = (uint32_t)((float)displayHeight / ratio);
1180
*renderWidth = scaledDisplayWidth;
1181
*renderHeight = scaledDisplayHeight;
1182
1183
return FFX_OK;
1184
}
1185
1186
FfxErrorCode ffxFsr2ContextEnqueueRefreshPipelineRequest(FfxFsr2Context* context)
1187
{
1188
FFX_RETURN_ON_ERROR(
1189
context,
1190
FFX_ERROR_INVALID_POINTER);
1191
1192
FfxFsr2Context_Private* contextPrivate = (FfxFsr2Context_Private*)context;
1193
contextPrivate->refreshPipelineStates = true;
1194
1195
return FFX_OK;
1196
}
1197
1198
int32_t ffxFsr2GetJitterPhaseCount(int32_t renderWidth, int32_t displayWidth)
1199
{
1200
const float basePhaseCount = 8.0f;
1201
const int32_t jitterPhaseCount = int32_t(basePhaseCount * pow((float(displayWidth) / renderWidth), 2.0f));
1202
return jitterPhaseCount;
1203
}
1204
1205
FfxErrorCode ffxFsr2GetJitterOffset(float* outX, float* outY, int32_t index, int32_t phaseCount)
1206
{
1207
FFX_RETURN_ON_ERROR(
1208
outX,
1209
FFX_ERROR_INVALID_POINTER);
1210
FFX_RETURN_ON_ERROR(
1211
outY,
1212
FFX_ERROR_INVALID_POINTER);
1213
FFX_RETURN_ON_ERROR(
1214
phaseCount > 0,
1215
FFX_ERROR_INVALID_ARGUMENT);
1216
1217
const float x = halton((index % phaseCount) + 1, 2) - 0.5f;
1218
const float y = halton((index % phaseCount) + 1, 3) - 0.5f;
1219
1220
*outX = x;
1221
*outY = y;
1222
return FFX_OK;
1223
}
1224
1225
FFX_API bool ffxFsr2ResourceIsNull(FfxResource resource)
1226
{
1227
return resource.resource == NULL;
1228
}
1229
1230
FfxErrorCode ffxFsr2ContextGenerateReactiveMask(FfxFsr2Context* context, const FfxFsr2GenerateReactiveDescription* params)
1231
{
1232
FFX_RETURN_ON_ERROR(
1233
context,
1234
FFX_ERROR_INVALID_POINTER);
1235
FFX_RETURN_ON_ERROR(
1236
params,
1237
FFX_ERROR_INVALID_POINTER);
1238
FFX_RETURN_ON_ERROR(
1239
params->commandList,
1240
FFX_ERROR_INVALID_POINTER);
1241
1242
FfxFsr2Context_Private* contextPrivate = (FfxFsr2Context_Private*)(context);
1243
1244
FFX_RETURN_ON_ERROR(
1245
contextPrivate->device,
1246
FFX_ERROR_NULL_DEVICE);
1247
1248
if (contextPrivate->refreshPipelineStates) {
1249
1250
createPipelineStates(contextPrivate);
1251
contextPrivate->refreshPipelineStates = false;
1252
}
1253
1254
// take a short cut to the command list
1255
FfxCommandList commandList = params->commandList;
1256
1257
FfxPipelineState* pipeline = &contextPrivate->pipelineGenerateReactive;
1258
1259
const int32_t threadGroupWorkRegionDim = 8;
1260
const int32_t dispatchSrcX = (params->renderSize.width + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
1261
const int32_t dispatchSrcY = (params->renderSize.height + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
1262
1263
// save internal reactive resource
1264
FfxResourceInternal internalReactive = contextPrivate->uavResources[FFX_FSR2_RESOURCE_IDENTIFIER_AUTOREACTIVE];
1265
1266
FfxComputeJobDescription jobDescriptor = {};
1267
contextPrivate->contextDescription.callbacks.fpRegisterResource(&contextPrivate->contextDescription.callbacks, &params->colorOpaqueOnly, &contextPrivate->srvResources[FFX_FSR2_RESOURCE_IDENTIFIER_INPUT_OPAQUE_ONLY]);
1268
contextPrivate->contextDescription.callbacks.fpRegisterResource(&contextPrivate->contextDescription.callbacks, &params->colorPreUpscale, &contextPrivate->srvResources[FFX_FSR2_RESOURCE_IDENTIFIER_INPUT_COLOR]);
1269
contextPrivate->contextDescription.callbacks.fpRegisterResource(&contextPrivate->contextDescription.callbacks, &params->outReactive, &contextPrivate->uavResources[FFX_FSR2_RESOURCE_IDENTIFIER_AUTOREACTIVE]);
1270
1271
jobDescriptor.uavs[0] = contextPrivate->uavResources[FFX_FSR2_RESOURCE_IDENTIFIER_AUTOREACTIVE];
1272
1273
wcscpy_s(jobDescriptor.srvNames[0], pipeline->srvResourceBindings[0].name);
1274
wcscpy_s(jobDescriptor.srvNames[1], pipeline->srvResourceBindings[1].name);
1275
wcscpy_s(jobDescriptor.uavNames[0], pipeline->uavResourceBindings[0].name);
1276
1277
jobDescriptor.dimensions[0] = dispatchSrcX;
1278
jobDescriptor.dimensions[1] = dispatchSrcY;
1279
jobDescriptor.dimensions[2] = 1;
1280
jobDescriptor.pipeline = *pipeline;
1281
1282
for (uint32_t currentShaderResourceViewIndex = 0; currentShaderResourceViewIndex < pipeline->srvCount; ++currentShaderResourceViewIndex) {
1283
1284
const uint32_t currentResourceId = pipeline->srvResourceBindings[currentShaderResourceViewIndex].resourceIdentifier;
1285
const FfxResourceInternal currentResource = contextPrivate->srvResources[currentResourceId];
1286
jobDescriptor.srvs[currentShaderResourceViewIndex] = currentResource;
1287
wcscpy_s(jobDescriptor.srvNames[currentShaderResourceViewIndex], pipeline->srvResourceBindings[currentShaderResourceViewIndex].name);
1288
}
1289
1290
Fsr2GenerateReactiveConstants constants = {};
1291
constants.scale = params->scale;
1292
constants.threshold = params->cutoffThreshold;
1293
constants.binaryValue = params->binaryValue;
1294
constants.flags = params->flags;
1295
1296
jobDescriptor.cbs[0].uint32Size = sizeof(constants);
1297
memcpy(&jobDescriptor.cbs[0].data, &constants, sizeof(constants));
1298
wcscpy_s(jobDescriptor.cbNames[0], pipeline->cbResourceBindings[0].name);
1299
1300
FfxGpuJobDescription dispatchJob = { FFX_GPU_JOB_COMPUTE };
1301
dispatchJob.computeJobDescriptor = jobDescriptor;
1302
1303
contextPrivate->contextDescription.callbacks.fpScheduleGpuJob(&contextPrivate->contextDescription.callbacks, &dispatchJob);
1304
1305
contextPrivate->contextDescription.callbacks.fpExecuteGpuJobs(&contextPrivate->contextDescription.callbacks, commandList);
1306
1307
// restore internal reactive
1308
contextPrivate->uavResources[FFX_FSR2_RESOURCE_IDENTIFIER_AUTOREACTIVE] = internalReactive;
1309
1310
return FFX_OK;
1311
}
1312
1313
static FfxErrorCode generateReactiveMaskInternal(FfxFsr2Context_Private* contextPrivate, const FfxFsr2DispatchDescription* params)
1314
{
1315
if (contextPrivate->refreshPipelineStates) {
1316
1317
createPipelineStates(contextPrivate);
1318
contextPrivate->refreshPipelineStates = false;
1319
}
1320
1321
// take a short cut to the command list
1322
FfxCommandList commandList = params->commandList;
1323
1324
FfxPipelineState* pipeline = &contextPrivate->pipelineTcrAutogenerate;
1325
1326
const int32_t threadGroupWorkRegionDim = 8;
1327
const int32_t dispatchSrcX = (params->renderSize.width + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
1328
const int32_t dispatchSrcY = (params->renderSize.height + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
1329
1330
FfxComputeJobDescription jobDescriptor = {};
1331
contextPrivate->contextDescription.callbacks.fpRegisterResource(&contextPrivate->contextDescription.callbacks, &params->colorOpaqueOnly, &contextPrivate->srvResources[FFX_FSR2_RESOURCE_IDENTIFIER_INPUT_OPAQUE_ONLY]);
1332
contextPrivate->contextDescription.callbacks.fpRegisterResource(&contextPrivate->contextDescription.callbacks, &params->color, &contextPrivate->srvResources[FFX_FSR2_RESOURCE_IDENTIFIER_INPUT_COLOR]);
1333
1334
jobDescriptor.uavs[0] = contextPrivate->uavResources[FFX_FSR2_RESOURCE_IDENTIFIER_AUTOREACTIVE];
1335
jobDescriptor.uavs[1] = contextPrivate->uavResources[FFX_FSR2_RESOURCE_IDENTIFIER_AUTOCOMPOSITION];
1336
jobDescriptor.uavs[2] = contextPrivate->uavResources[FFX_FSR2_RESOURCE_IDENTIFIER_PREV_PRE_ALPHA_COLOR];
1337
jobDescriptor.uavs[3] = contextPrivate->uavResources[FFX_FSR2_RESOURCE_IDENTIFIER_PREV_POST_ALPHA_COLOR];
1338
1339
wcscpy_s(jobDescriptor.uavNames[0], pipeline->uavResourceBindings[0].name);
1340
wcscpy_s(jobDescriptor.uavNames[1], pipeline->uavResourceBindings[1].name);
1341
wcscpy_s(jobDescriptor.uavNames[2], pipeline->uavResourceBindings[2].name);
1342
wcscpy_s(jobDescriptor.uavNames[3], pipeline->uavResourceBindings[3].name);
1343
1344
jobDescriptor.dimensions[0] = dispatchSrcX;
1345
jobDescriptor.dimensions[1] = dispatchSrcY;
1346
jobDescriptor.dimensions[2] = 1;
1347
jobDescriptor.pipeline = *pipeline;
1348
1349
for (uint32_t currentShaderResourceViewIndex = 0; currentShaderResourceViewIndex < pipeline->srvCount; ++currentShaderResourceViewIndex) {
1350
1351
const uint32_t currentResourceId = pipeline->srvResourceBindings[currentShaderResourceViewIndex].resourceIdentifier;
1352
const FfxResourceInternal currentResource = contextPrivate->srvResources[currentResourceId];
1353
jobDescriptor.srvs[currentShaderResourceViewIndex] = currentResource;
1354
wcscpy_s(jobDescriptor.srvNames[currentShaderResourceViewIndex], pipeline->srvResourceBindings[currentShaderResourceViewIndex].name);
1355
}
1356
1357
for (uint32_t currentRootConstantIndex = 0; currentRootConstantIndex < pipeline->constCount; ++currentRootConstantIndex) {
1358
wcscpy_s(jobDescriptor.cbNames[currentRootConstantIndex], pipeline->cbResourceBindings[currentRootConstantIndex].name);
1359
jobDescriptor.cbs[currentRootConstantIndex] = globalFsr2ConstantBuffers[pipeline->cbResourceBindings[currentRootConstantIndex].resourceIdentifier];
1360
jobDescriptor.cbSlotIndex[currentRootConstantIndex] = pipeline->cbResourceBindings[currentRootConstantIndex].slotIndex;
1361
}
1362
1363
FfxGpuJobDescription dispatchJob = { FFX_GPU_JOB_COMPUTE };
1364
dispatchJob.computeJobDescriptor = jobDescriptor;
1365
1366
contextPrivate->contextDescription.callbacks.fpScheduleGpuJob(&contextPrivate->contextDescription.callbacks, &dispatchJob);
1367
1368
return FFX_OK;
1369
}
1370
1371