ffx_fsr2.cpp 74 KB

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