fsr2.cpp 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885
  1. /**************************************************************************/
  2. /* fsr2.cpp */
  3. /**************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /**************************************************************************/
  8. /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
  9. /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
  10. /* */
  11. /* Permission is hereby granted, free of charge, to any person obtaining */
  12. /* a copy of this software and associated documentation files (the */
  13. /* "Software"), to deal in the Software without restriction, including */
  14. /* without limitation the rights to use, copy, modify, merge, publish, */
  15. /* distribute, sublicense, and/or sell copies of the Software, and to */
  16. /* permit persons to whom the Software is furnished to do so, subject to */
  17. /* the following conditions: */
  18. /* */
  19. /* The above copyright notice and this permission notice shall be */
  20. /* included in all copies or substantial portions of the Software. */
  21. /* */
  22. /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
  23. /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
  24. /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
  25. /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
  26. /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
  27. /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
  28. /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
  29. /**************************************************************************/
  30. #include "fsr2.h"
  31. #include "../storage_rd/material_storage.h"
  32. #include "../uniform_set_cache_rd.h"
  33. using namespace RendererRD;
  34. #ifndef _MSC_VER
  35. #include <wchar.h>
  36. #define wcscpy_s wcscpy
  37. #endif
  38. static RD::TextureType ffx_resource_type_to_rd_texture_type(FfxResourceType p_type) {
  39. switch (p_type) {
  40. case FFX_RESOURCE_TYPE_TEXTURE1D:
  41. return RD::TEXTURE_TYPE_1D;
  42. case FFX_RESOURCE_TYPE_TEXTURE2D:
  43. return RD::TEXTURE_TYPE_2D;
  44. case FFX_RESOURCE_TYPE_TEXTURE3D:
  45. return RD::TEXTURE_TYPE_3D;
  46. default:
  47. return RD::TEXTURE_TYPE_MAX;
  48. }
  49. }
  50. static FfxResourceType rd_texture_type_to_ffx_resource_type(RD::TextureType p_type) {
  51. switch (p_type) {
  52. case RD::TEXTURE_TYPE_1D:
  53. return FFX_RESOURCE_TYPE_TEXTURE1D;
  54. case RD::TEXTURE_TYPE_2D:
  55. return FFX_RESOURCE_TYPE_TEXTURE2D;
  56. case RD::TEXTURE_TYPE_3D:
  57. return FFX_RESOURCE_TYPE_TEXTURE3D;
  58. default:
  59. return FFX_RESOURCE_TYPE_BUFFER;
  60. }
  61. }
  62. static RD::DataFormat ffx_surface_format_to_rd_format(FfxSurfaceFormat p_format) {
  63. switch (p_format) {
  64. case FFX_SURFACE_FORMAT_R32G32B32A32_TYPELESS:
  65. return RD::DATA_FORMAT_R32G32B32A32_SFLOAT;
  66. case FFX_SURFACE_FORMAT_R32G32B32A32_FLOAT:
  67. return RD::DATA_FORMAT_R32G32B32A32_SFLOAT;
  68. case FFX_SURFACE_FORMAT_R16G16B16A16_FLOAT:
  69. return RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
  70. case FFX_SURFACE_FORMAT_R16G16B16A16_UNORM:
  71. return RD::DATA_FORMAT_R16G16B16A16_UNORM;
  72. case FFX_SURFACE_FORMAT_R32G32_FLOAT:
  73. return RD::DATA_FORMAT_R32G32_SFLOAT;
  74. case FFX_SURFACE_FORMAT_R32_UINT:
  75. return RD::DATA_FORMAT_R32_UINT;
  76. case FFX_SURFACE_FORMAT_R8G8B8A8_TYPELESS:
  77. return RD::DATA_FORMAT_R8G8B8A8_UNORM;
  78. case FFX_SURFACE_FORMAT_R8G8B8A8_UNORM:
  79. return RD::DATA_FORMAT_R8G8B8A8_UNORM;
  80. case FFX_SURFACE_FORMAT_R11G11B10_FLOAT:
  81. return RD::DATA_FORMAT_B10G11R11_UFLOAT_PACK32;
  82. case FFX_SURFACE_FORMAT_R16G16_FLOAT:
  83. return RD::DATA_FORMAT_R16G16_SFLOAT;
  84. case FFX_SURFACE_FORMAT_R16G16_UINT:
  85. return RD::DATA_FORMAT_R16G16_UINT;
  86. case FFX_SURFACE_FORMAT_R16_FLOAT:
  87. return RD::DATA_FORMAT_R16_SFLOAT;
  88. case FFX_SURFACE_FORMAT_R16_UINT:
  89. return RD::DATA_FORMAT_R16_UINT;
  90. case FFX_SURFACE_FORMAT_R16_UNORM:
  91. return RD::DATA_FORMAT_R16_UNORM;
  92. case FFX_SURFACE_FORMAT_R16_SNORM:
  93. return RD::DATA_FORMAT_R16_SNORM;
  94. case FFX_SURFACE_FORMAT_R8_UNORM:
  95. return RD::DATA_FORMAT_R8_UNORM;
  96. case FFX_SURFACE_FORMAT_R8_UINT:
  97. return RD::DATA_FORMAT_R8_UINT;
  98. case FFX_SURFACE_FORMAT_R8G8_UNORM:
  99. return RD::DATA_FORMAT_R8G8_UNORM;
  100. case FFX_SURFACE_FORMAT_R32_FLOAT:
  101. return RD::DATA_FORMAT_R32_SFLOAT;
  102. default:
  103. return RD::DATA_FORMAT_MAX;
  104. }
  105. }
  106. static FfxSurfaceFormat rd_format_to_ffx_surface_format(RD::DataFormat p_format) {
  107. switch (p_format) {
  108. case RD::DATA_FORMAT_R32G32B32A32_SFLOAT:
  109. return FFX_SURFACE_FORMAT_R32G32B32A32_FLOAT;
  110. case RD::DATA_FORMAT_R16G16B16A16_SFLOAT:
  111. return FFX_SURFACE_FORMAT_R16G16B16A16_FLOAT;
  112. case RD::DATA_FORMAT_R16G16B16A16_UNORM:
  113. return FFX_SURFACE_FORMAT_R16G16B16A16_UNORM;
  114. case RD::DATA_FORMAT_R32G32_SFLOAT:
  115. return FFX_SURFACE_FORMAT_R32G32_FLOAT;
  116. case RD::DATA_FORMAT_R32_UINT:
  117. return FFX_SURFACE_FORMAT_R32_UINT;
  118. case RD::DATA_FORMAT_R8G8B8A8_UNORM:
  119. return FFX_SURFACE_FORMAT_R8G8B8A8_UNORM;
  120. case RD::DATA_FORMAT_B10G11R11_UFLOAT_PACK32:
  121. return FFX_SURFACE_FORMAT_R11G11B10_FLOAT;
  122. case RD::DATA_FORMAT_R16G16_SFLOAT:
  123. return FFX_SURFACE_FORMAT_R16G16_FLOAT;
  124. case RD::DATA_FORMAT_R16G16_UINT:
  125. return FFX_SURFACE_FORMAT_R16G16_UINT;
  126. case RD::DATA_FORMAT_R16_SFLOAT:
  127. return FFX_SURFACE_FORMAT_R16_FLOAT;
  128. case RD::DATA_FORMAT_R16_UINT:
  129. return FFX_SURFACE_FORMAT_R16_UINT;
  130. case RD::DATA_FORMAT_R16_UNORM:
  131. return FFX_SURFACE_FORMAT_R16_UNORM;
  132. case RD::DATA_FORMAT_R16_SNORM:
  133. return FFX_SURFACE_FORMAT_R16_SNORM;
  134. case RD::DATA_FORMAT_R8_UNORM:
  135. return FFX_SURFACE_FORMAT_R8_UNORM;
  136. case RD::DATA_FORMAT_R8_UINT:
  137. return FFX_SURFACE_FORMAT_R8_UINT;
  138. case RD::DATA_FORMAT_R8G8_UNORM:
  139. return FFX_SURFACE_FORMAT_R8G8_UNORM;
  140. case RD::DATA_FORMAT_R32_SFLOAT:
  141. return FFX_SURFACE_FORMAT_R32_FLOAT;
  142. default:
  143. return FFX_SURFACE_FORMAT_UNKNOWN;
  144. }
  145. }
  146. static uint32_t ffx_usage_to_rd_usage_flags(uint32_t p_flags) {
  147. uint32_t ret = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT;
  148. if (p_flags & FFX_RESOURCE_USAGE_RENDERTARGET) {
  149. ret |= RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
  150. }
  151. if (p_flags & FFX_RESOURCE_USAGE_UAV) {
  152. ret |= RD::TEXTURE_USAGE_STORAGE_BIT;
  153. ret |= RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT;
  154. ret |= RD::TEXTURE_USAGE_CAN_COPY_TO_BIT;
  155. }
  156. return ret;
  157. }
  158. static FfxErrorCode create_backend_context_rd(FfxFsr2Interface *p_backend_interface, FfxDevice p_device) {
  159. FSR2Context::Scratch &scratch = *reinterpret_cast<FSR2Context::Scratch *>(p_backend_interface->scratchBuffer);
  160. // Store pointer to the device common to all contexts.
  161. scratch.device = p_device;
  162. // Create a ring buffer of uniform buffers.
  163. // FIXME: This could be optimized to be a single memory block if it was possible for RD to create views into a particular memory range of a UBO.
  164. for (uint32_t i = 0; i < FSR2_UBO_RING_BUFFER_SIZE; i++) {
  165. scratch.ubo_ring_buffer[i] = RD::get_singleton()->uniform_buffer_create(FFX_MAX_CONST_SIZE * sizeof(uint32_t));
  166. ERR_FAIL_COND_V(scratch.ubo_ring_buffer[i].is_null(), FFX_ERROR_BACKEND_API_ERROR);
  167. }
  168. return FFX_OK;
  169. }
  170. static FfxErrorCode get_device_capabilities_rd(FfxFsr2Interface *p_backend_interface, FfxDeviceCapabilities *p_out_device_capabilities, FfxDevice p_device) {
  171. FSR2Effect::Device &effect_device = *reinterpret_cast<FSR2Effect::Device *>(p_device);
  172. *p_out_device_capabilities = effect_device.capabilities;
  173. return FFX_OK;
  174. }
  175. static FfxErrorCode destroy_backend_context_rd(FfxFsr2Interface *p_backend_interface) {
  176. FSR2Context::Scratch &scratch = *reinterpret_cast<FSR2Context::Scratch *>(p_backend_interface->scratchBuffer);
  177. for (uint32_t i = 0; i < FSR2_UBO_RING_BUFFER_SIZE; i++) {
  178. RD::get_singleton()->free(scratch.ubo_ring_buffer[i]);
  179. }
  180. return FFX_OK;
  181. }
  182. static FfxErrorCode create_resource_rd(FfxFsr2Interface *p_backend_interface, const FfxCreateResourceDescription *p_create_resource_description, FfxResourceInternal *p_out_resource) {
  183. // FSR2's base implementation won't issue a call to create a heap type that isn't just default on its own,
  184. // so we can safely ignore it as RD does not expose this concept.
  185. ERR_FAIL_COND_V(p_create_resource_description->heapType != FFX_HEAP_TYPE_DEFAULT, FFX_ERROR_INVALID_ARGUMENT);
  186. RenderingDevice *rd = RD::get_singleton();
  187. FSR2Context::Scratch &scratch = *reinterpret_cast<FSR2Context::Scratch *>(p_backend_interface->scratchBuffer);
  188. FfxResourceDescription res_desc = p_create_resource_description->resourceDescription;
  189. // FSR2's base implementation never requests buffer creation.
  190. ERR_FAIL_COND_V(res_desc.type != FFX_RESOURCE_TYPE_TEXTURE1D && res_desc.type != FFX_RESOURCE_TYPE_TEXTURE2D && res_desc.type != FFX_RESOURCE_TYPE_TEXTURE3D, FFX_ERROR_INVALID_ARGUMENT);
  191. if (res_desc.mipCount == 0) {
  192. // Mipmap count must be derived from the resource's dimensions.
  193. res_desc.mipCount = uint32_t(1 + floor(log2(MAX(MAX(res_desc.width, res_desc.height), res_desc.depth))));
  194. }
  195. Vector<PackedByteArray> initial_data;
  196. if (p_create_resource_description->initDataSize) {
  197. PackedByteArray byte_array;
  198. byte_array.resize(p_create_resource_description->initDataSize);
  199. memcpy(byte_array.ptrw(), p_create_resource_description->initData, p_create_resource_description->initDataSize);
  200. initial_data.push_back(byte_array);
  201. }
  202. RD::TextureFormat texture_format;
  203. texture_format.texture_type = ffx_resource_type_to_rd_texture_type(res_desc.type);
  204. texture_format.format = ffx_surface_format_to_rd_format(res_desc.format);
  205. texture_format.usage_bits = ffx_usage_to_rd_usage_flags(p_create_resource_description->usage);
  206. texture_format.width = res_desc.width;
  207. texture_format.height = res_desc.height;
  208. texture_format.depth = res_desc.depth;
  209. texture_format.mipmaps = res_desc.mipCount;
  210. RID texture = rd->texture_create(texture_format, RD::TextureView(), initial_data);
  211. ERR_FAIL_COND_V(texture.is_null(), FFX_ERROR_BACKEND_API_ERROR);
  212. rd->set_resource_name(texture, String(p_create_resource_description->name));
  213. // Add the resource to the storage and use the internal index to reference it.
  214. p_out_resource->internalIndex = scratch.resources.add(texture, false, p_create_resource_description->id, res_desc);
  215. return FFX_OK;
  216. }
  217. static FfxErrorCode register_resource_rd(FfxFsr2Interface *p_backend_interface, const FfxResource *p_in_resource, FfxResourceInternal *p_out_resource) {
  218. if (p_in_resource->resource == nullptr) {
  219. // Null resource case.
  220. p_out_resource->internalIndex = -1;
  221. return FFX_OK;
  222. }
  223. FSR2Context::Scratch &scratch = *reinterpret_cast<FSR2Context::Scratch *>(p_backend_interface->scratchBuffer);
  224. const RID &rid = *reinterpret_cast<const RID *>(p_in_resource->resource);
  225. ERR_FAIL_COND_V(rid.is_null(), FFX_ERROR_INVALID_ARGUMENT);
  226. // Add the resource to the storage and use the internal index to reference it.
  227. p_out_resource->internalIndex = scratch.resources.add(rid, true, FSR2Context::RESOURCE_ID_DYNAMIC, p_in_resource->description);
  228. return FFX_OK;
  229. }
  230. static FfxErrorCode unregister_resources_rd(FfxFsr2Interface *p_backend_interface) {
  231. FSR2Context::Scratch &scratch = *reinterpret_cast<FSR2Context::Scratch *>(p_backend_interface->scratchBuffer);
  232. LocalVector<uint32_t> dynamic_list_copy = scratch.resources.dynamic_list;
  233. for (uint32_t i : dynamic_list_copy) {
  234. scratch.resources.remove(i);
  235. }
  236. return FFX_OK;
  237. }
  238. static FfxResourceDescription get_resource_description_rd(FfxFsr2Interface *p_backend_interface, FfxResourceInternal p_resource) {
  239. if (p_resource.internalIndex != -1) {
  240. FSR2Context::Scratch &scratch = *reinterpret_cast<FSR2Context::Scratch *>(p_backend_interface->scratchBuffer);
  241. return scratch.resources.descriptions[p_resource.internalIndex];
  242. } else {
  243. return {};
  244. }
  245. }
  246. static FfxErrorCode destroy_resource_rd(FfxFsr2Interface *p_backend_interface, FfxResourceInternal p_resource) {
  247. if (p_resource.internalIndex != -1) {
  248. FSR2Context::Scratch &scratch = *reinterpret_cast<FSR2Context::Scratch *>(p_backend_interface->scratchBuffer);
  249. if (scratch.resources.rids[p_resource.internalIndex].is_valid()) {
  250. RD::get_singleton()->free(scratch.resources.rids[p_resource.internalIndex]);
  251. scratch.resources.remove(p_resource.internalIndex);
  252. }
  253. }
  254. return FFX_OK;
  255. }
  256. static FfxErrorCode create_pipeline_rd(FfxFsr2Interface *p_backend_interface, FfxFsr2Pass p_pass, const FfxPipelineDescription *p_pipeline_description, FfxPipelineState *p_out_pipeline) {
  257. FSR2Context::Scratch &scratch = *reinterpret_cast<FSR2Context::Scratch *>(p_backend_interface->scratchBuffer);
  258. FSR2Effect::Device &device = *reinterpret_cast<FSR2Effect::Device *>(scratch.device);
  259. FSR2Effect::Pass &effect_pass = device.passes[p_pass];
  260. if (effect_pass.pipeline.pipeline_rid.is_null()) {
  261. // Create pipeline for the device if it hasn't been created yet.
  262. effect_pass.root_signature.shader_rid = effect_pass.shader->version_get_shader(effect_pass.shader_version, effect_pass.shader_variant);
  263. ERR_FAIL_COND_V(effect_pass.root_signature.shader_rid.is_null(), FFX_ERROR_BACKEND_API_ERROR);
  264. effect_pass.pipeline.pipeline_rid = RD::get_singleton()->compute_pipeline_create(effect_pass.root_signature.shader_rid);
  265. ERR_FAIL_COND_V(effect_pass.pipeline.pipeline_rid.is_null(), FFX_ERROR_BACKEND_API_ERROR);
  266. }
  267. // While this is not their intended use, we use the pipeline and root signature pointers to store the
  268. // RIDs to the pipeline and shader that RD needs for the compute pipeline.
  269. p_out_pipeline->pipeline = reinterpret_cast<FfxPipeline>(&effect_pass.pipeline);
  270. p_out_pipeline->rootSignature = reinterpret_cast<FfxRootSignature>(&effect_pass.root_signature);
  271. p_out_pipeline->srvCount = effect_pass.sampled_bindings.size();
  272. ERR_FAIL_COND_V(p_out_pipeline->srvCount > FFX_MAX_NUM_SRVS, FFX_ERROR_OUT_OF_RANGE);
  273. memcpy(p_out_pipeline->srvResourceBindings, effect_pass.sampled_bindings.ptr(), sizeof(FfxResourceBinding) * p_out_pipeline->srvCount);
  274. p_out_pipeline->uavCount = effect_pass.storage_bindings.size();
  275. ERR_FAIL_COND_V(p_out_pipeline->uavCount > FFX_MAX_NUM_UAVS, FFX_ERROR_OUT_OF_RANGE);
  276. memcpy(p_out_pipeline->uavResourceBindings, effect_pass.storage_bindings.ptr(), sizeof(FfxResourceBinding) * p_out_pipeline->uavCount);
  277. p_out_pipeline->constCount = effect_pass.uniform_bindings.size();
  278. ERR_FAIL_COND_V(p_out_pipeline->constCount > FFX_MAX_NUM_CONST_BUFFERS, FFX_ERROR_OUT_OF_RANGE);
  279. memcpy(p_out_pipeline->cbResourceBindings, effect_pass.uniform_bindings.ptr(), sizeof(FfxResourceBinding) * p_out_pipeline->constCount);
  280. bool low_resolution_mvs = (p_pipeline_description->contextFlags & FFX_FSR2_ENABLE_DISPLAY_RESOLUTION_MOTION_VECTORS) == 0;
  281. if (p_pass == FFX_FSR2_PASS_ACCUMULATE || p_pass == FFX_FSR2_PASS_ACCUMULATE_SHARPEN) {
  282. // Change the binding for motion vectors in this particular pass if low resolution MVs are used.
  283. if (low_resolution_mvs) {
  284. FfxResourceBinding &binding = p_out_pipeline->srvResourceBindings[2];
  285. wcscpy_s(binding.name, L"r_dilated_motion_vectors");
  286. }
  287. }
  288. return FFX_OK;
  289. }
  290. static FfxErrorCode destroy_pipeline_rd(FfxFsr2Interface *p_backend_interface, FfxPipelineState *p_pipeline) {
  291. // We don't want to destroy pipelines when the FSR2 API deems it necessary as it'll do so whenever the context is destroyed.
  292. return FFX_OK;
  293. }
  294. static FfxErrorCode schedule_gpu_job_rd(FfxFsr2Interface *p_backend_interface, const FfxGpuJobDescription *p_job) {
  295. ERR_FAIL_NULL_V(p_backend_interface, FFX_ERROR_INVALID_ARGUMENT);
  296. ERR_FAIL_NULL_V(p_job, FFX_ERROR_INVALID_ARGUMENT);
  297. FSR2Context::Scratch &scratch = *reinterpret_cast<FSR2Context::Scratch *>(p_backend_interface->scratchBuffer);
  298. scratch.gpu_jobs.push_back(*p_job);
  299. return FFX_OK;
  300. }
  301. static FfxErrorCode execute_gpu_job_clear_float_rd(FSR2Context::Scratch &p_scratch, const FfxClearFloatJobDescription &p_job) {
  302. RID resource = p_scratch.resources.rids[p_job.target.internalIndex];
  303. FfxResourceDescription &desc = p_scratch.resources.descriptions[p_job.target.internalIndex];
  304. ERR_FAIL_COND_V(desc.type == FFX_RESOURCE_TYPE_BUFFER, FFX_ERROR_INVALID_ARGUMENT);
  305. Color color(p_job.color[0], p_job.color[1], p_job.color[2], p_job.color[3]);
  306. RD::get_singleton()->texture_clear(resource, color, 0, desc.mipCount, 0, 1);
  307. return FFX_OK;
  308. }
  309. static FfxErrorCode execute_gpu_job_copy_rd(FSR2Context::Scratch &p_scratch, const FfxCopyJobDescription &p_job) {
  310. RID src = p_scratch.resources.rids[p_job.src.internalIndex];
  311. RID dst = p_scratch.resources.rids[p_job.dst.internalIndex];
  312. FfxResourceDescription &src_desc = p_scratch.resources.descriptions[p_job.src.internalIndex];
  313. FfxResourceDescription &dst_desc = p_scratch.resources.descriptions[p_job.dst.internalIndex];
  314. ERR_FAIL_COND_V(src_desc.type == FFX_RESOURCE_TYPE_BUFFER, FFX_ERROR_INVALID_ARGUMENT);
  315. ERR_FAIL_COND_V(dst_desc.type == FFX_RESOURCE_TYPE_BUFFER, FFX_ERROR_INVALID_ARGUMENT);
  316. for (uint32_t mip_level = 0; mip_level < src_desc.mipCount; mip_level++) {
  317. RD::get_singleton()->texture_copy(src, dst, Vector3(0, 0, 0), Vector3(0, 0, 0), Vector3(src_desc.width, src_desc.height, src_desc.depth), mip_level, mip_level, 0, 0);
  318. }
  319. return FFX_OK;
  320. }
  321. static FfxErrorCode execute_gpu_job_compute_rd(FSR2Context::Scratch &p_scratch, const FfxComputeJobDescription &p_job) {
  322. UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
  323. ERR_FAIL_NULL_V(uniform_set_cache, FFX_ERROR_BACKEND_API_ERROR);
  324. FSR2Effect::RootSignature &root_signature = *reinterpret_cast<FSR2Effect::RootSignature *>(p_job.pipeline.rootSignature);
  325. ERR_FAIL_COND_V(root_signature.shader_rid.is_null(), FFX_ERROR_INVALID_ARGUMENT);
  326. FSR2Effect::Pipeline &backend_pipeline = *reinterpret_cast<FSR2Effect::Pipeline *>(p_job.pipeline.pipeline);
  327. ERR_FAIL_COND_V(backend_pipeline.pipeline_rid.is_null(), FFX_ERROR_INVALID_ARGUMENT);
  328. Vector<RD::Uniform> compute_uniforms;
  329. for (uint32_t i = 0; i < p_job.pipeline.srvCount; i++) {
  330. RID texture_rid = p_scratch.resources.rids[p_job.srvs[i].internalIndex];
  331. RD::Uniform texture_uniform(RD::UNIFORM_TYPE_TEXTURE, p_job.pipeline.srvResourceBindings[i].slotIndex, texture_rid);
  332. compute_uniforms.push_back(texture_uniform);
  333. }
  334. for (uint32_t i = 0; i < p_job.pipeline.uavCount; i++) {
  335. RID image_rid = p_scratch.resources.rids[p_job.uavs[i].internalIndex];
  336. RD::Uniform storage_uniform;
  337. storage_uniform.uniform_type = RD::UNIFORM_TYPE_IMAGE;
  338. storage_uniform.binding = p_job.pipeline.uavResourceBindings[i].slotIndex;
  339. if (p_job.uavMip[i] > 0) {
  340. LocalVector<RID> &mip_slice_rids = p_scratch.resources.mip_slice_rids[p_job.uavs[i].internalIndex];
  341. if (mip_slice_rids.is_empty()) {
  342. mip_slice_rids.resize(p_scratch.resources.descriptions[p_job.uavs[i].internalIndex].mipCount);
  343. }
  344. ERR_FAIL_COND_V(p_job.uavMip[i] >= mip_slice_rids.size(), FFX_ERROR_INVALID_ARGUMENT);
  345. if (mip_slice_rids[p_job.uavMip[i]].is_null()) {
  346. mip_slice_rids[p_job.uavMip[i]] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), image_rid, 0, p_job.uavMip[i]);
  347. }
  348. ERR_FAIL_COND_V(mip_slice_rids[p_job.uavMip[i]].is_null(), FFX_ERROR_BACKEND_API_ERROR);
  349. storage_uniform.append_id(mip_slice_rids[p_job.uavMip[i]]);
  350. } else {
  351. storage_uniform.append_id(image_rid);
  352. }
  353. compute_uniforms.push_back(storage_uniform);
  354. }
  355. for (uint32_t i = 0; i < p_job.pipeline.constCount; i++) {
  356. RID buffer_rid = p_scratch.ubo_ring_buffer[p_scratch.ubo_ring_buffer_index];
  357. p_scratch.ubo_ring_buffer_index = (p_scratch.ubo_ring_buffer_index + 1) % FSR2_UBO_RING_BUFFER_SIZE;
  358. RD::get_singleton()->buffer_update(buffer_rid, 0, p_job.cbs[i].uint32Size * sizeof(uint32_t), p_job.cbs[i].data);
  359. RD::Uniform buffer_uniform(RD::UNIFORM_TYPE_UNIFORM_BUFFER, p_job.pipeline.cbResourceBindings[i].slotIndex, buffer_rid);
  360. compute_uniforms.push_back(buffer_uniform);
  361. }
  362. FSR2Effect::Device &device = *reinterpret_cast<FSR2Effect::Device *>(p_scratch.device);
  363. RD::Uniform u_point_clamp_sampler(RD::UniformType::UNIFORM_TYPE_SAMPLER, 0, device.point_clamp_sampler);
  364. RD::Uniform u_linear_clamp_sampler(RD::UniformType::UNIFORM_TYPE_SAMPLER, 1, device.linear_clamp_sampler);
  365. RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
  366. RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, backend_pipeline.pipeline_rid);
  367. RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(root_signature.shader_rid, 0, u_point_clamp_sampler, u_linear_clamp_sampler), 0);
  368. RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache_vec(root_signature.shader_rid, 1, compute_uniforms), 1);
  369. RD::get_singleton()->compute_list_dispatch(compute_list, p_job.dimensions[0], p_job.dimensions[1], p_job.dimensions[2]);
  370. RD::get_singleton()->compute_list_end();
  371. return FFX_OK;
  372. }
  373. static FfxErrorCode execute_gpu_jobs_rd(FfxFsr2Interface *p_backend_interface, FfxCommandList p_command_list) {
  374. ERR_FAIL_NULL_V(p_backend_interface, FFX_ERROR_INVALID_ARGUMENT);
  375. FSR2Context::Scratch &scratch = *reinterpret_cast<FSR2Context::Scratch *>(p_backend_interface->scratchBuffer);
  376. FfxErrorCode error_code = FFX_OK;
  377. for (const FfxGpuJobDescription &job : scratch.gpu_jobs) {
  378. switch (job.jobType) {
  379. case FFX_GPU_JOB_CLEAR_FLOAT: {
  380. error_code = execute_gpu_job_clear_float_rd(scratch, job.clearJobDescriptor);
  381. } break;
  382. case FFX_GPU_JOB_COPY: {
  383. error_code = execute_gpu_job_copy_rd(scratch, job.copyJobDescriptor);
  384. } break;
  385. case FFX_GPU_JOB_COMPUTE: {
  386. error_code = execute_gpu_job_compute_rd(scratch, job.computeJobDescriptor);
  387. } break;
  388. default: {
  389. error_code = FFX_ERROR_INVALID_ARGUMENT;
  390. } break;
  391. }
  392. if (error_code != FFX_OK) {
  393. scratch.gpu_jobs.clear();
  394. return error_code;
  395. }
  396. }
  397. scratch.gpu_jobs.clear();
  398. return FFX_OK;
  399. }
  400. static FfxResource get_resource_rd(RID *p_rid, const wchar_t *p_name) {
  401. FfxResource res = {};
  402. if (p_rid->is_null()) {
  403. return res;
  404. }
  405. wcscpy_s(res.name, p_name);
  406. RD::TextureFormat texture_format = RD::get_singleton()->texture_get_format(*p_rid);
  407. res.description.type = rd_texture_type_to_ffx_resource_type(texture_format.texture_type);
  408. res.description.format = rd_format_to_ffx_surface_format(texture_format.format);
  409. res.description.width = texture_format.width;
  410. res.description.height = texture_format.height;
  411. res.description.depth = texture_format.depth;
  412. res.description.mipCount = texture_format.mipmaps;
  413. res.description.flags = FFX_RESOURCE_FLAGS_NONE;
  414. res.resource = reinterpret_cast<void *>(p_rid);
  415. res.isDepth = texture_format.usage_bits & RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
  416. return res;
  417. }
  418. FSR2Context::~FSR2Context() {
  419. ffxFsr2ContextDestroy(&fsr_context);
  420. }
  421. FSR2Effect::FSR2Effect() {
  422. FfxDeviceCapabilities &capabilities = device.capabilities;
  423. uint64_t default_subgroup_size = RD::get_singleton()->limit_get(RD::LIMIT_SUBGROUP_SIZE);
  424. capabilities.minimumSupportedShaderModel = FFX_SHADER_MODEL_5_1;
  425. capabilities.waveLaneCountMin = RD::get_singleton()->limit_get(RD::LIMIT_SUBGROUP_MIN_SIZE);
  426. capabilities.waveLaneCountMax = RD::get_singleton()->limit_get(RD::LIMIT_SUBGROUP_MAX_SIZE);
  427. capabilities.fp16Supported = RD::get_singleton()->has_feature(RD::Features::SUPPORTS_FSR_HALF_FLOAT);
  428. capabilities.raytracingSupported = false;
  429. bool force_wave_64 = default_subgroup_size == 32 && capabilities.waveLaneCountMax == 64;
  430. bool use_lut = force_wave_64 || default_subgroup_size == 64;
  431. String general_defines_base =
  432. "\n#define FFX_GPU\n"
  433. "\n#define FFX_GLSL 1\n"
  434. "\n#define FFX_FSR2_OPTION_LOW_RESOLUTION_MOTION_VECTORS 1\n"
  435. "\n#define FFX_FSR2_OPTION_HDR_COLOR_INPUT 1\n"
  436. "\n#define FFX_FSR2_OPTION_INVERTED_DEPTH 1\n"
  437. "\n#define FFX_FSR2_OPTION_GODOT_REACTIVE_MASK_CLAMP 1\n"
  438. "\n#define FFX_FSR2_OPTION_GODOT_DERIVE_INVALID_MOTION_VECTORS 1\n";
  439. if (use_lut) {
  440. general_defines_base += "\n#define FFX_FSR2_OPTION_REPROJECT_USE_LANCZOS_TYPE 1\n";
  441. }
  442. String general_defines = general_defines_base;
  443. if (capabilities.fp16Supported) {
  444. general_defines += "\n#define FFX_HALF 1\n";
  445. }
  446. Vector<String> modes;
  447. modes.push_back("");
  448. // Since Godot currently lacks a shader reflection mechanism to persist the name of the bindings in the shader cache and
  449. // there's also no mechanism to compile the shaders offline, the bindings are created manually by looking at the GLSL
  450. // files included in FSR2 and mapping the macro bindings (#define FSR2_BIND_*) to their respective implementation names.
  451. //
  452. // It is not guaranteed these will remain consistent at all between versions of FSR2, so it'll be necessary to keep these
  453. // bindings up to date whenever the library is updated. In such cases, it is very likely the validation layer will throw an
  454. // error if the bindings do not match.
  455. {
  456. Pass &pass = device.passes[FFX_FSR2_PASS_DEPTH_CLIP];
  457. pass.shader = &shaders.depth_clip;
  458. pass.shader->initialize(modes, general_defines);
  459. pass.shader_version = pass.shader->version_create();
  460. pass.sampled_bindings = {
  461. FfxResourceBinding{ 0, 0, L"r_reconstructed_previous_nearest_depth" },
  462. FfxResourceBinding{ 1, 0, L"r_dilated_motion_vectors" },
  463. FfxResourceBinding{ 2, 0, L"r_dilatedDepth" },
  464. FfxResourceBinding{ 3, 0, L"r_reactive_mask" },
  465. FfxResourceBinding{ 4, 0, L"r_transparency_and_composition_mask" },
  466. FfxResourceBinding{ 6, 0, L"r_previous_dilated_motion_vectors" },
  467. FfxResourceBinding{ 7, 0, L"r_input_motion_vectors" },
  468. FfxResourceBinding{ 8, 0, L"r_input_color_jittered" },
  469. FfxResourceBinding{ 9, 0, L"r_input_depth" },
  470. FfxResourceBinding{ 10, 0, L"r_input_exposure" }
  471. };
  472. pass.storage_bindings = {
  473. // FSR2_BIND_UAV_DEPTH_CLIP (11) does not point to anything.
  474. FfxResourceBinding{ 12, 0, L"rw_dilated_reactive_masks" },
  475. FfxResourceBinding{ 13, 0, L"rw_prepared_input_color" }
  476. };
  477. pass.uniform_bindings = {
  478. FfxResourceBinding{ 14, 0, L"cbFSR2" }
  479. };
  480. }
  481. {
  482. Pass &pass = device.passes[FFX_FSR2_PASS_RECONSTRUCT_PREVIOUS_DEPTH];
  483. pass.shader = &shaders.reconstruct_previous_depth;
  484. pass.shader->initialize(modes, general_defines);
  485. pass.shader_version = pass.shader->version_create();
  486. pass.sampled_bindings = {
  487. FfxResourceBinding{ 0, 0, L"r_input_motion_vectors" },
  488. FfxResourceBinding{ 1, 0, L"r_input_depth" },
  489. FfxResourceBinding{ 2, 0, L"r_input_color_jittered" },
  490. FfxResourceBinding{ 3, 0, L"r_input_exposure" },
  491. FfxResourceBinding{ 4, 0, L"r_luma_history" }
  492. };
  493. pass.storage_bindings = {
  494. FfxResourceBinding{ 5, 0, L"rw_reconstructed_previous_nearest_depth" },
  495. FfxResourceBinding{ 6, 0, L"rw_dilated_motion_vectors" },
  496. FfxResourceBinding{ 7, 0, L"rw_dilatedDepth" },
  497. FfxResourceBinding{ 8, 0, L"rw_prepared_input_color" },
  498. FfxResourceBinding{ 9, 0, L"rw_luma_history" },
  499. // FSR2_BIND_UAV_LUMA_INSTABILITY (10) does not point to anything.
  500. FfxResourceBinding{ 11, 0, L"rw_lock_input_luma" }
  501. };
  502. pass.uniform_bindings = {
  503. FfxResourceBinding{ 12, 0, L"cbFSR2" }
  504. };
  505. }
  506. {
  507. Pass &pass = device.passes[FFX_FSR2_PASS_LOCK];
  508. pass.shader = &shaders.lock;
  509. pass.shader->initialize(modes, general_defines);
  510. pass.shader_version = pass.shader->version_create();
  511. pass.sampled_bindings = {
  512. FfxResourceBinding{ 0, 0, L"r_lock_input_luma" }
  513. };
  514. pass.storage_bindings = {
  515. FfxResourceBinding{ 1, 0, L"rw_new_locks" },
  516. FfxResourceBinding{ 2, 0, L"rw_reconstructed_previous_nearest_depth" }
  517. };
  518. pass.uniform_bindings = {
  519. FfxResourceBinding{ 3, 0, L"cbFSR2" }
  520. };
  521. }
  522. {
  523. Vector<String> accumulate_modes;
  524. accumulate_modes.push_back("\n");
  525. accumulate_modes.push_back("\n#define FFX_FSR2_OPTION_APPLY_SHARPENING 1\n");
  526. String general_defines_accumulate;
  527. if (RD::get_singleton()->get_device_vendor_name() == "NVIDIA") {
  528. // Workaround: Disable FP16 path for the accumulate pass on NVIDIA due to reduced occupancy and high VRAM throughput.
  529. general_defines_accumulate = general_defines_base;
  530. } else {
  531. general_defines_accumulate = general_defines;
  532. }
  533. Pass &pass = device.passes[FFX_FSR2_PASS_ACCUMULATE];
  534. pass.shader = &shaders.accumulate;
  535. pass.shader->initialize(accumulate_modes, general_defines_accumulate);
  536. pass.shader_version = pass.shader->version_create();
  537. pass.sampled_bindings = {
  538. FfxResourceBinding{ 0, 0, L"r_input_exposure" },
  539. FfxResourceBinding{ 1, 0, L"r_dilated_reactive_masks" },
  540. FfxResourceBinding{ 2, 0, L"r_input_motion_vectors" },
  541. FfxResourceBinding{ 3, 0, L"r_internal_upscaled_color" },
  542. FfxResourceBinding{ 4, 0, L"r_lock_status" },
  543. FfxResourceBinding{ 5, 0, L"r_input_depth" },
  544. FfxResourceBinding{ 6, 0, L"r_prepared_input_color" },
  545. // FSR2_BIND_SRV_LUMA_INSTABILITY(7) does not point to anything.
  546. FfxResourceBinding{ 8, 0, L"r_lanczos_lut" },
  547. FfxResourceBinding{ 9, 0, L"r_upsample_maximum_bias_lut" },
  548. FfxResourceBinding{ 10, 0, L"r_imgMips" },
  549. FfxResourceBinding{ 11, 0, L"r_auto_exposure" },
  550. FfxResourceBinding{ 12, 0, L"r_luma_history" }
  551. };
  552. pass.storage_bindings = {
  553. FfxResourceBinding{ 13, 0, L"rw_internal_upscaled_color" },
  554. FfxResourceBinding{ 14, 0, L"rw_lock_status" },
  555. FfxResourceBinding{ 15, 0, L"rw_upscaled_output" },
  556. FfxResourceBinding{ 16, 0, L"rw_new_locks" },
  557. FfxResourceBinding{ 17, 0, L"rw_luma_history" }
  558. };
  559. pass.uniform_bindings = {
  560. FfxResourceBinding{ 18, 0, L"cbFSR2" }
  561. };
  562. // Sharpen pass is a clone of the accumulate pass.
  563. Pass &sharpen_pass = device.passes[FFX_FSR2_PASS_ACCUMULATE_SHARPEN];
  564. sharpen_pass = pass;
  565. sharpen_pass.shader_variant = 1;
  566. }
  567. {
  568. Pass &pass = device.passes[FFX_FSR2_PASS_RCAS];
  569. pass.shader = &shaders.rcas;
  570. pass.shader->initialize(modes, general_defines_base);
  571. pass.shader_version = pass.shader->version_create();
  572. pass.sampled_bindings = {
  573. FfxResourceBinding{ 0, 0, L"r_input_exposure" },
  574. FfxResourceBinding{ 1, 0, L"r_rcas_input" }
  575. };
  576. pass.storage_bindings = {
  577. FfxResourceBinding{ 2, 0, L"rw_upscaled_output" }
  578. };
  579. pass.uniform_bindings = {
  580. FfxResourceBinding{ 3, 0, L"cbFSR2" },
  581. FfxResourceBinding{ 4, 0, L"cbRCAS" }
  582. };
  583. }
  584. {
  585. Pass &pass = device.passes[FFX_FSR2_PASS_COMPUTE_LUMINANCE_PYRAMID];
  586. pass.shader = &shaders.compute_luminance_pyramid;
  587. pass.shader->initialize(modes, general_defines_base);
  588. pass.shader_version = pass.shader->version_create();
  589. pass.sampled_bindings = {
  590. FfxResourceBinding{ 0, 0, L"r_input_color_jittered" }
  591. };
  592. pass.storage_bindings = {
  593. FfxResourceBinding{ 1, 0, L"rw_spd_global_atomic" },
  594. FfxResourceBinding{ 2, 0, L"rw_img_mip_shading_change" },
  595. FfxResourceBinding{ 3, 0, L"rw_img_mip_5" },
  596. FfxResourceBinding{ 4, 0, L"rw_auto_exposure" }
  597. };
  598. pass.uniform_bindings = {
  599. FfxResourceBinding{ 5, 0, L"cbFSR2" },
  600. FfxResourceBinding{ 6, 0, L"cbSPD" }
  601. };
  602. }
  603. {
  604. Pass &pass = device.passes[FFX_FSR2_PASS_GENERATE_REACTIVE];
  605. pass.shader = &shaders.autogen_reactive;
  606. pass.shader->initialize(modes, general_defines);
  607. pass.shader_version = pass.shader->version_create();
  608. pass.sampled_bindings = {
  609. FfxResourceBinding{ 0, 0, L"r_input_opaque_only" },
  610. FfxResourceBinding{ 1, 0, L"r_input_color_jittered" }
  611. };
  612. pass.storage_bindings = {
  613. FfxResourceBinding{ 2, 0, L"rw_output_autoreactive" }
  614. };
  615. pass.uniform_bindings = {
  616. FfxResourceBinding{ 3, 0, L"cbGenerateReactive" },
  617. FfxResourceBinding{ 4, 0, L"cbFSR2" }
  618. };
  619. }
  620. {
  621. Pass &pass = device.passes[FFX_FSR2_PASS_TCR_AUTOGENERATE];
  622. pass.shader = &shaders.tcr_autogen;
  623. pass.shader->initialize(modes, general_defines);
  624. pass.shader_version = pass.shader->version_create();
  625. pass.sampled_bindings = {
  626. FfxResourceBinding{ 0, 0, L"r_input_opaque_only" },
  627. FfxResourceBinding{ 1, 0, L"r_input_color_jittered" },
  628. FfxResourceBinding{ 2, 0, L"r_input_motion_vectors" },
  629. FfxResourceBinding{ 3, 0, L"r_input_prev_color_pre_alpha" },
  630. FfxResourceBinding{ 4, 0, L"r_input_prev_color_post_alpha" },
  631. FfxResourceBinding{ 5, 0, L"r_reactive_mask" },
  632. FfxResourceBinding{ 6, 0, L"r_transparency_and_composition_mask" },
  633. FfxResourceBinding{ 13, 0, L"r_input_depth" }
  634. };
  635. pass.storage_bindings = {
  636. FfxResourceBinding{ 7, 0, L"rw_output_autoreactive" },
  637. FfxResourceBinding{ 8, 0, L"rw_output_autocomposition" },
  638. FfxResourceBinding{ 9, 0, L"rw_output_prev_color_pre_alpha" },
  639. FfxResourceBinding{ 10, 0, L"rw_output_prev_color_post_alpha" }
  640. };
  641. pass.uniform_bindings = {
  642. FfxResourceBinding{ 11, 0, L"cbFSR2" },
  643. FfxResourceBinding{ 12, 0, L"cbGenerateReactive" }
  644. };
  645. }
  646. RD::SamplerState state;
  647. state.mag_filter = RD::SAMPLER_FILTER_NEAREST;
  648. state.min_filter = RD::SAMPLER_FILTER_NEAREST;
  649. state.repeat_u = RD::SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE;
  650. state.repeat_v = RD::SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE;
  651. state.repeat_w = RD::SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE;
  652. state.min_lod = -1000.0f;
  653. state.max_lod = 1000.0f;
  654. state.anisotropy_max = 1.0;
  655. device.point_clamp_sampler = RD::get_singleton()->sampler_create(state);
  656. ERR_FAIL_COND(device.point_clamp_sampler.is_null());
  657. state.mag_filter = RD::SAMPLER_FILTER_LINEAR;
  658. state.min_filter = RD::SAMPLER_FILTER_LINEAR;
  659. device.linear_clamp_sampler = RD::get_singleton()->sampler_create(state);
  660. ERR_FAIL_COND(device.linear_clamp_sampler.is_null());
  661. }
  662. FSR2Effect::~FSR2Effect() {
  663. RD::get_singleton()->free(device.point_clamp_sampler);
  664. RD::get_singleton()->free(device.linear_clamp_sampler);
  665. for (uint32_t i = 0; i < FFX_FSR2_PASS_COUNT; i++) {
  666. device.passes[i].shader->version_free(device.passes[i].shader_version);
  667. }
  668. }
  669. FSR2Context *FSR2Effect::create_context(Size2i p_internal_size, Size2i p_target_size) {
  670. FSR2Context *context = memnew(RendererRD::FSR2Context);
  671. context->fsr_desc.flags = FFX_FSR2_ENABLE_HIGH_DYNAMIC_RANGE | FFX_FSR2_ENABLE_DEPTH_INVERTED;
  672. context->fsr_desc.maxRenderSize.width = p_internal_size.x;
  673. context->fsr_desc.maxRenderSize.height = p_internal_size.y;
  674. context->fsr_desc.displaySize.width = p_target_size.x;
  675. context->fsr_desc.displaySize.height = p_target_size.y;
  676. context->fsr_desc.device = &device;
  677. FfxFsr2Interface &functions = context->fsr_desc.callbacks;
  678. functions.fpCreateBackendContext = create_backend_context_rd;
  679. functions.fpGetDeviceCapabilities = get_device_capabilities_rd;
  680. functions.fpDestroyBackendContext = destroy_backend_context_rd;
  681. functions.fpCreateResource = create_resource_rd;
  682. functions.fpRegisterResource = register_resource_rd;
  683. functions.fpUnregisterResources = unregister_resources_rd;
  684. functions.fpGetResourceDescription = get_resource_description_rd;
  685. functions.fpDestroyResource = destroy_resource_rd;
  686. functions.fpCreatePipeline = create_pipeline_rd;
  687. functions.fpDestroyPipeline = destroy_pipeline_rd;
  688. functions.fpScheduleGpuJob = schedule_gpu_job_rd;
  689. functions.fpExecuteGpuJobs = execute_gpu_jobs_rd;
  690. functions.scratchBuffer = &context->scratch;
  691. functions.scratchBufferSize = sizeof(context->scratch);
  692. FfxErrorCode result = ffxFsr2ContextCreate(&context->fsr_context, &context->fsr_desc);
  693. if (result == FFX_OK) {
  694. return context;
  695. } else {
  696. memdelete(context);
  697. return nullptr;
  698. }
  699. }
  700. void FSR2Effect::upscale(const Parameters &p_params) {
  701. // TODO: Transparency & Composition mask is not implemented.
  702. FfxFsr2DispatchDescription dispatch_desc = {};
  703. RID color = p_params.color;
  704. RID depth = p_params.depth;
  705. RID velocity = p_params.velocity;
  706. RID reactive = p_params.reactive;
  707. RID exposure = p_params.exposure;
  708. RID output = p_params.output;
  709. dispatch_desc.commandList = nullptr;
  710. dispatch_desc.color = get_resource_rd(&color, L"color");
  711. dispatch_desc.depth = get_resource_rd(&depth, L"depth");
  712. dispatch_desc.motionVectors = get_resource_rd(&velocity, L"velocity");
  713. dispatch_desc.reactive = get_resource_rd(&reactive, L"reactive");
  714. dispatch_desc.exposure = get_resource_rd(&exposure, L"exposure");
  715. dispatch_desc.transparencyAndComposition = {};
  716. dispatch_desc.output = get_resource_rd(&output, L"output");
  717. dispatch_desc.colorOpaqueOnly = {};
  718. dispatch_desc.jitterOffset.x = p_params.jitter.x;
  719. dispatch_desc.jitterOffset.y = p_params.jitter.y;
  720. dispatch_desc.motionVectorScale.x = float(p_params.internal_size.width);
  721. dispatch_desc.motionVectorScale.y = float(p_params.internal_size.height);
  722. dispatch_desc.reset = p_params.reset_accumulation;
  723. dispatch_desc.renderSize.width = p_params.internal_size.width;
  724. dispatch_desc.renderSize.height = p_params.internal_size.height;
  725. dispatch_desc.enableSharpening = (p_params.sharpness > 1e-6f);
  726. dispatch_desc.sharpness = p_params.sharpness;
  727. dispatch_desc.frameTimeDelta = p_params.delta_time;
  728. dispatch_desc.preExposure = 1.0f;
  729. dispatch_desc.cameraNear = p_params.z_near;
  730. dispatch_desc.cameraFar = p_params.z_far;
  731. dispatch_desc.cameraFovAngleVertical = p_params.fovy;
  732. dispatch_desc.viewSpaceToMetersFactor = 1.0f;
  733. dispatch_desc.enableAutoReactive = false;
  734. dispatch_desc.autoTcThreshold = 1.0f;
  735. dispatch_desc.autoTcScale = 1.0f;
  736. dispatch_desc.autoReactiveScale = 1.0f;
  737. dispatch_desc.autoReactiveMax = 1.0f;
  738. RendererRD::MaterialStorage::store_camera(p_params.reprojection, dispatch_desc.reprojectionMatrix);
  739. FfxErrorCode result = ffxFsr2ContextDispatch(&p_params.context->fsr_context, &dispatch_desc);
  740. ERR_FAIL_COND(result != FFX_OK);
  741. }