From 89acfcd0d2fc2aaffa45d8d2d912294e35c27703 Mon Sep 17 00:00:00 2001 From: BlueHeisenberg <2033896+BlueHeisenberg@users.noreply.github.com> Date: Sun, 8 Nov 2026 22:46:17 +0100 Subject: [PATCH 1/5] NVIDIA DLSS in place of the game's upscale, an Output resolution row, and a full-size 3D at 3840x2160 - DLSS (optional, RTX GPUs; gpu/vk/vk_dlss.cpp, the DLSS part of vk_draw.cpp, vk/shaders/dlss_*.comp): the gameplay upscale network's place in the frame taken by DLSS, which draws the 3D at the DLSS mode's size and scales it to the output with the game's depth and its camera's motion. Ported from zortos293/Lichii (its Streamline loader, camera motion and their shaders; Lichii credits Duck912's Eglantine work). NVIDIA Streamline v2.14.16's headers in third_party/streamline (MIT); its DLLs and nvngx_dlss.dll are loaded from a streamline folder beside the game exe (signatures checked), not shipped. Menu rows DLSS, DLSS mode (Ultra Performance .. DLAA) and DLSS preset (J..M); RX_DLSS, RX_DLSS_PRESET, RX_DLSS_DIR over them. - Output resolution (host/nn_applet.c, nx2/oot_patches.py apply_output_size): the game's whole frame at 2048x1152 (its own), 2560x1440 or 3840x2160, docked, after a restart (HOS_OUTPUT_RES over it). The display size, the docked size list, the 3D's largest size and the scene's size follow it; the widescreen picture is made at its height (host/hos_main.c). - 3840x2160 3D at the 4K output: the game's render targets' GPU pool (305 MB, for 2560x1440) ran out and the next target came back null. It grows with the output's pixels (687 MB at 4K; HOS_RT_POOL_MB over it), with the "Graphics" module heap that holds it, that heap's budget check counting its shipped use, and the leftover heap made from it kept at its shipped size. - Resolution: a fixed scale reaches the 3D (it kept the dynamic path's last one), sent in 1/10000 as the twelfth of the output the game draws at; the Resolution and DLSS mode rows show the 3D's size for the chosen output, and follow the Output resolution row at once. - Test switches: HOS_RES_LOG, RX_VK_SHOT_W/H, RX_VK_MENU_SCRIPT, RX_VK_MENU_DUMP, RX_DLSS_DEBUG. readme: the rows, where NVIDIA's files come from, the overrides. --- gpu/PROVENANCE.md | 6 + gpu/vk/shaders/dlss_color.comp | 19 + gpu/vk/shaders/dlss_color_comp_spv.h | 60 ++ gpu/vk/shaders/dlss_debug.comp | 33 + gpu/vk/shaders/dlss_debug_comp_spv.h | 119 +++ gpu/vk/shaders/dlss_motion.comp | 33 + gpu/vk/shaders/dlss_motion_comp_spv.h | 106 +++ gpu/vk/shaders/dlss_output.comp | 20 + gpu/vk/shaders/dlss_output_comp_spv.h | 69 ++ gpu/vk/vk_dlss.cpp | 589 +++++++++++++ gpu/vk/vk_dlss.h | 42 + gpu/vk/vk_draw.cpp | 383 ++++++++- gpu/vk/vk_main.cpp | 21 +- gpu/vk/vk_menu.cpp | 122 ++- gpu/vk/vk_menu.h | 7 + gpu/vk/vk_replay.cpp | 9 +- host/hos_main.c | 5 +- host/nn_applet.c | 55 +- host/nn_vi.c | 24 +- nx2/build.py | 7 +- nx2/oot_patches.py | 111 ++- readme.md | 21 +- third_party/streamline/include/sl.h | 46 ++ .../streamline/include/sl_appidentity.h | 20 + third_party/streamline/include/sl_consts.h | 260 ++++++ third_party/streamline/include/sl_core_api.h | 328 ++++++++ .../streamline/include/sl_core_types.h | 781 ++++++++++++++++++ third_party/streamline/include/sl_deepdvc.h | 103 +++ .../streamline/include/sl_device_wrappers.h | 20 + third_party/streamline/include/sl_directsr.h | 173 ++++ third_party/streamline/include/sl_dlss.h | 193 +++++ third_party/streamline/include/sl_dlss_d.h | 188 +++++ third_party/streamline/include/sl_dlss_g.h | 222 +++++ third_party/streamline/include/sl_helpers.h | 485 +++++++++++ .../streamline/include/sl_helpers_vk.h | 256 ++++++ third_party/streamline/include/sl_hooks.h | 115 +++ .../streamline/include/sl_matrix_helpers.h | 221 +++++ third_party/streamline/include/sl_nis.h | 102 +++ third_party/streamline/include/sl_nvperf.h | 70 ++ third_party/streamline/include/sl_pcl.h | 163 ++++ third_party/streamline/include/sl_reflex.h | 233 ++++++ third_party/streamline/include/sl_result.h | 77 ++ third_party/streamline/include/sl_security.h | 463 +++++++++++ third_party/streamline/include/sl_struct.h | 142 ++++ third_party/streamline/include/sl_template.h | 57 ++ third_party/streamline/include/sl_version.h | 99 +++ third_party/streamline/license.txt | 33 + 47 files changed, 6670 insertions(+), 41 deletions(-) create mode 100644 gpu/vk/shaders/dlss_color.comp create mode 100644 gpu/vk/shaders/dlss_color_comp_spv.h create mode 100644 gpu/vk/shaders/dlss_debug.comp create mode 100644 gpu/vk/shaders/dlss_debug_comp_spv.h create mode 100644 gpu/vk/shaders/dlss_motion.comp create mode 100644 gpu/vk/shaders/dlss_motion_comp_spv.h create mode 100644 gpu/vk/shaders/dlss_output.comp create mode 100644 gpu/vk/shaders/dlss_output_comp_spv.h create mode 100644 gpu/vk/vk_dlss.cpp create mode 100644 gpu/vk/vk_dlss.h create mode 100644 third_party/streamline/include/sl.h create mode 100644 third_party/streamline/include/sl_appidentity.h create mode 100644 third_party/streamline/include/sl_consts.h create mode 100644 third_party/streamline/include/sl_core_api.h create mode 100644 third_party/streamline/include/sl_core_types.h create mode 100644 third_party/streamline/include/sl_deepdvc.h create mode 100644 third_party/streamline/include/sl_device_wrappers.h create mode 100644 third_party/streamline/include/sl_directsr.h create mode 100644 third_party/streamline/include/sl_dlss.h create mode 100644 third_party/streamline/include/sl_dlss_d.h create mode 100644 third_party/streamline/include/sl_dlss_g.h create mode 100644 third_party/streamline/include/sl_helpers.h create mode 100644 third_party/streamline/include/sl_helpers_vk.h create mode 100644 third_party/streamline/include/sl_hooks.h create mode 100644 third_party/streamline/include/sl_matrix_helpers.h create mode 100644 third_party/streamline/include/sl_nis.h create mode 100644 third_party/streamline/include/sl_nvperf.h create mode 100644 third_party/streamline/include/sl_pcl.h create mode 100644 third_party/streamline/include/sl_reflex.h create mode 100644 third_party/streamline/include/sl_result.h create mode 100644 third_party/streamline/include/sl_security.h create mode 100644 third_party/streamline/include/sl_struct.h create mode 100644 third_party/streamline/include/sl_template.h create mode 100644 third_party/streamline/include/sl_version.h create mode 100644 third_party/streamline/license.txt diff --git a/gpu/PROVENANCE.md b/gpu/PROVENANCE.md index 3d90532e5..412ceebba 100644 --- a/gpu/PROVENANCE.md +++ b/gpu/PROVENANCE.md @@ -28,3 +28,9 @@ mkw-recomp's changes, for the Switch 2: `mkw_gpu.cpp` / `mkw_gpu.h` / `build-gpu.bat` are the earlier Vulkan stand-in (a window and a swapchain; no longer loaded). `shadertool.cpp` runs dumped NVN2 programs through Eglantine's recompiler offline (SPIR-V; it prints what each program reads from the constant banks). + +Hookshot's NVIDIA DLSS (`vk/vk_dlss.cpp`, the DLSS part of `vk/vk_draw.cpp`, `vk/shaders/dlss_*.comp`) is ported from Lichii +(zortos293/Lichii: `vulkan_common/streamline.cpp`, `renderer_vulkan/vk_streamline_dlss.cpp`, `vk_ocarina_camera_motion.cpp`, +`host_shaders/ocarina_*.comp`; Eden Emulator Project, GPL-3.0-or-later; Lichii credits Duck912's Eglantine work). +`third_party/streamline/` is NVIDIA Streamline v2.14.16's headers (MIT, `license.txt`); its DLLs and NVIDIA's DLSS are +loaded from the user's PC at run time and are not vendored. diff --git a/gpu/vk/shaders/dlss_color.comp b/gpu/vk/shaders/dlss_color.comp new file mode 100644 index 000000000..44e5cf83a --- /dev/null +++ b/gpu/vk/shaders/dlss_color.comp @@ -0,0 +1,19 @@ +#version 450 +// (hookshot) ported from Lichii (Eden lineage; Duck912's Eglantine work), GPL-3.0-or-later: vk_dlss.cpp + +layout(local_size_x = 8, local_size_y = 8) in; +layout(binding = 0) uniform sampler2D guest_color; +layout(binding = 1, rgba16f) uniform writeonly image2D dlss_color; +layout(push_constant) uniform P { int encode; } pc; + +void main() { + ivec2 pixel = ivec2(gl_GlobalInvocationID.xy); + if (any(greaterThanEqual(pixel, imageSize(dlss_color)))) { + return; + } + // The guest has already tonemapped this square-root-encoded color for LDR (the network's input, RGB9E5). (hookshot) encode = 1: + // the tonemapped scene, the network's first passes left out (vk_draw.cpp), square-root encoded here the same way. + // dlss_output.comp squares it back + const vec3 c = max(texelFetch(guest_color, pixel, 0).rgb, vec3(0.0)); + imageStore(dlss_color, pixel, vec4(pc.encode != 0 ? sqrt(c) : c, 1.0)); +} diff --git a/gpu/vk/shaders/dlss_color_comp_spv.h b/gpu/vk/shaders/dlss_color_comp_spv.h new file mode 100644 index 000000000..6ea3734c4 --- /dev/null +++ b/gpu/vk/shaders/dlss_color_comp_spv.h @@ -0,0 +1,60 @@ + // 1116.6.0 + #pragma once +const uint32_t DLSS_COLOR_COMP_SPV[] = { + 0x07230203,0x00010600,0x0008000b,0x0000004a,0x00000000,0x00020011,0x00000001,0x00020011, + 0x00000032,0x0006000b,0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e, + 0x00000000,0x00000001,0x0009000f,0x00000005,0x00000004,0x6e69616d,0x00000000,0x0000000d, + 0x00000016,0x00000026,0x00000035,0x00060010,0x00000004,0x00000011,0x00000008,0x00000008, + 0x00000001,0x00030003,0x00000002,0x000001c2,0x00040005,0x00000004,0x6e69616d,0x00000000, + 0x00040005,0x00000009,0x65786970,0x0000006c,0x00080005,0x0000000d,0x475f6c67,0x61626f6c, + 0x766e496c,0x7461636f,0x496e6f69,0x00000044,0x00050005,0x00000016,0x73736c64,0x6c6f635f, + 0x0000726f,0x00030005,0x00000022,0x00000063,0x00050005,0x00000026,0x73657567,0x6f635f74, + 0x00726f6c,0x00030005,0x00000033,0x00000050,0x00050006,0x00000033,0x00000000,0x6f636e65, + 0x00006564,0x00030005,0x00000035,0x00006370,0x00040047,0x0000000d,0x0000000b,0x0000001c, + 0x00030047,0x00000016,0x00000019,0x00040047,0x00000016,0x00000021,0x00000001,0x00040047, + 0x00000016,0x00000022,0x00000000,0x00040047,0x00000026,0x00000021,0x00000000,0x00040047, + 0x00000026,0x00000022,0x00000000,0x00030047,0x00000033,0x00000002,0x00050048,0x00000033, + 0x00000000,0x00000023,0x00000000,0x00020013,0x00000002,0x00030021,0x00000003,0x00000002, + 0x00040015,0x00000006,0x00000020,0x00000001,0x00040017,0x00000007,0x00000006,0x00000002, + 0x00040020,0x00000008,0x00000007,0x00000007,0x00040015,0x0000000a,0x00000020,0x00000000, + 0x00040017,0x0000000b,0x0000000a,0x00000003,0x00040020,0x0000000c,0x00000001,0x0000000b, + 0x0004003b,0x0000000c,0x0000000d,0x00000001,0x00040017,0x0000000e,0x0000000a,0x00000002, + 0x00030016,0x00000013,0x00000020,0x00090019,0x00000014,0x00000013,0x00000001,0x00000000, + 0x00000000,0x00000000,0x00000002,0x00000002,0x00040020,0x00000015,0x00000000,0x00000014, + 0x0004003b,0x00000015,0x00000016,0x00000000,0x00020014,0x00000019,0x00040017,0x0000001a, + 0x00000019,0x00000002,0x00040017,0x00000020,0x00000013,0x00000003,0x00040020,0x00000021, + 0x00000007,0x00000020,0x00090019,0x00000023,0x00000013,0x00000001,0x00000000,0x00000000, + 0x00000000,0x00000001,0x00000000,0x0003001b,0x00000024,0x00000023,0x00040020,0x00000025, + 0x00000000,0x00000024,0x0004003b,0x00000025,0x00000026,0x00000000,0x0004002b,0x00000006, + 0x00000029,0x00000000,0x00040017,0x0000002b,0x00000013,0x00000004,0x0004002b,0x00000013, + 0x0000002e,0x00000000,0x0006002c,0x00000020,0x0000002f,0x0000002e,0x0000002e,0x0000002e, + 0x0003001e,0x00000033,0x00000006,0x00040020,0x00000034,0x00000009,0x00000033,0x0004003b, + 0x00000034,0x00000035,0x00000009,0x00040020,0x00000036,0x00000009,0x00000006,0x0004002b, + 0x00000013,0x00000042,0x3f800000,0x0004002b,0x0000000a,0x00000047,0x00000008,0x0004002b, + 0x0000000a,0x00000048,0x00000001,0x0006002c,0x0000000b,0x00000049,0x00000047,0x00000047, + 0x00000048,0x00050036,0x00000002,0x00000004,0x00000000,0x00000003,0x000200f8,0x00000005, + 0x0004003b,0x00000008,0x00000009,0x00000007,0x0004003b,0x00000021,0x00000022,0x00000007, + 0x0004003b,0x00000021,0x0000003a,0x00000007,0x0004003d,0x0000000b,0x0000000f,0x0000000d, + 0x0007004f,0x0000000e,0x00000010,0x0000000f,0x0000000f,0x00000000,0x00000001,0x0004007c, + 0x00000007,0x00000011,0x00000010,0x0003003e,0x00000009,0x00000011,0x0004003d,0x00000007, + 0x00000012,0x00000009,0x0004003d,0x00000014,0x00000017,0x00000016,0x00040068,0x00000007, + 0x00000018,0x00000017,0x000500af,0x0000001a,0x0000001b,0x00000012,0x00000018,0x0004009a, + 0x00000019,0x0000001c,0x0000001b,0x000300f7,0x0000001e,0x00000000,0x000400fa,0x0000001c, + 0x0000001d,0x0000001e,0x000200f8,0x0000001d,0x000100fd,0x000200f8,0x0000001e,0x0004003d, + 0x00000024,0x00000027,0x00000026,0x0004003d,0x00000007,0x00000028,0x00000009,0x00040064, + 0x00000023,0x0000002a,0x00000027,0x0007005f,0x0000002b,0x0000002c,0x0000002a,0x00000028, + 0x00000002,0x00000029,0x0008004f,0x00000020,0x0000002d,0x0000002c,0x0000002c,0x00000000, + 0x00000001,0x00000002,0x0007000c,0x00000020,0x00000030,0x00000001,0x00000028,0x0000002d, + 0x0000002f,0x0003003e,0x00000022,0x00000030,0x0004003d,0x00000014,0x00000031,0x00000016, + 0x0004003d,0x00000007,0x00000032,0x00000009,0x00050041,0x00000036,0x00000037,0x00000035, + 0x00000029,0x0004003d,0x00000006,0x00000038,0x00000037,0x000500ab,0x00000019,0x00000039, + 0x00000038,0x00000029,0x000300f7,0x0000003c,0x00000000,0x000400fa,0x00000039,0x0000003b, + 0x0000003f,0x000200f8,0x0000003b,0x0004003d,0x00000020,0x0000003d,0x00000022,0x0006000c, + 0x00000020,0x0000003e,0x00000001,0x0000001f,0x0000003d,0x0003003e,0x0000003a,0x0000003e, + 0x000200f9,0x0000003c,0x000200f8,0x0000003f,0x0004003d,0x00000020,0x00000040,0x00000022, + 0x0003003e,0x0000003a,0x00000040,0x000200f9,0x0000003c,0x000200f8,0x0000003c,0x0004003d, + 0x00000020,0x00000041,0x0000003a,0x00050051,0x00000013,0x00000043,0x00000041,0x00000000, + 0x00050051,0x00000013,0x00000044,0x00000041,0x00000001,0x00050051,0x00000013,0x00000045, + 0x00000041,0x00000002,0x00070050,0x0000002b,0x00000046,0x00000043,0x00000044,0x00000045, + 0x00000042,0x00040063,0x00000031,0x00000032,0x00000046,0x000100fd,0x00010038 +}; diff --git a/gpu/vk/shaders/dlss_debug.comp b/gpu/vk/shaders/dlss_debug.comp new file mode 100644 index 000000000..220551e8d --- /dev/null +++ b/gpu/vk/shaders/dlss_debug.comp @@ -0,0 +1,33 @@ +#version 450 +// (hookshot) RX_DLSS_DEBUG=1..4: DLSS's inputs drawn into the network's target in place of DLSS's output (vk_draw.cpp). +// 1: motion, 0.5 grey = still, R/G = 0.5 + x/y render pixels / 64 (toward the previous frame); 2: depth^64; +// 3: |last frame's colour fetched along the motion - this frame's colour| x4; 4: the same without the motion (the baseline) + +layout(local_size_x = 8, local_size_y = 8) in; +layout(binding = 0) uniform sampler2D cur_color; +layout(binding = 1) uniform sampler2D motion; +layout(binding = 2) uniform sampler2D scene_depth; +layout(binding = 3) uniform sampler2D prev_color; +layout(binding = 4, r11f_g11f_b10f) uniform writeonly image2D target; +layout(push_constant) uniform P { int mode; } pc; + +void main() { + ivec2 pixel = ivec2(gl_GlobalInvocationID.xy); + ivec2 extent = imageSize(target); + if (any(greaterThanEqual(pixel, extent))) { + return; + } + vec2 uv = (vec2(pixel) + 0.5) / vec2(extent); + vec2 mv = textureLod(motion, uv, 0).xy; + vec3 c; + if (pc.mode == 1) { + c = vec3(clamp(0.5 + mv / 64.0, 0.0, 1.0), 0.5); + } else if (pc.mode == 2) { + c = vec3(pow(textureLod(scene_depth, uv, 0).r, 64.0)); + } else { + vec2 from = uv + (pc.mode == 3 ? mv / vec2(textureSize(cur_color, 0)) : vec2(0)); + vec3 d = abs(textureLod(prev_color, from, 0).rgb - textureLod(cur_color, uv, 0).rgb); + c = vec3(min((d.r + d.g + d.b) * (4.0 / 3.0), 1.0)); + } + imageStore(target, pixel, vec4(c, 1.0)); +} \ No newline at end of file diff --git a/gpu/vk/shaders/dlss_debug_comp_spv.h b/gpu/vk/shaders/dlss_debug_comp_spv.h new file mode 100644 index 000000000..df0335133 --- /dev/null +++ b/gpu/vk/shaders/dlss_debug_comp_spv.h @@ -0,0 +1,119 @@ + // 1116.5.0 + #pragma once +const uint32_t DLSS_DEBUG_COMP_SPV[] = { + 0x07230203,0x00010600,0x0008000b,0x0000009b,0x00000000,0x00020011,0x00000001,0x00020011, + 0x00000031,0x00020011,0x00000032,0x0006000b,0x00000001,0x4c534c47,0x6474732e,0x3035342e, + 0x00000000,0x0003000e,0x00000000,0x00000001,0x000c000f,0x00000005,0x00000004,0x6e69616d, + 0x00000000,0x0000000d,0x00000016,0x00000031,0x0000003a,0x0000005a,0x0000006d,0x00000078, + 0x00060010,0x00000004,0x00000011,0x00000008,0x00000008,0x00000001,0x00030003,0x00000002, + 0x000001c2,0x00040005,0x00000004,0x6e69616d,0x00000000,0x00040005,0x00000009,0x65786970, + 0x0000006c,0x00080005,0x0000000d,0x475f6c67,0x61626f6c,0x766e496c,0x7461636f,0x496e6f69, + 0x00000044,0x00040005,0x00000012,0x65747865,0x0000746e,0x00040005,0x00000016,0x67726174, + 0x00007465,0x00030005,0x00000024,0x00007675,0x00030005,0x0000002d,0x0000766d,0x00040005, + 0x00000031,0x69746f6d,0x00006e6f,0x00030005,0x00000038,0x00000050,0x00050006,0x00000038, + 0x00000000,0x65646f6d,0x00000000,0x00030005,0x0000003a,0x00006370,0x00030005,0x00000045, + 0x00000063,0x00050005,0x0000005a,0x6e656373,0x65645f65,0x00687470,0x00040005,0x00000063, + 0x6d6f7266,0x00000000,0x00050005,0x0000006d,0x5f727563,0x6f6c6f63,0x00000072,0x00030005, + 0x00000077,0x00000064,0x00050005,0x00000078,0x76657270,0x6c6f635f,0x0000726f,0x00040047, + 0x0000000d,0x0000000b,0x0000001c,0x00030047,0x00000016,0x00000019,0x00040047,0x00000016, + 0x00000021,0x00000004,0x00040047,0x00000016,0x00000022,0x00000000,0x00040047,0x00000031, + 0x00000021,0x00000001,0x00040047,0x00000031,0x00000022,0x00000000,0x00030047,0x00000038, + 0x00000002,0x00050048,0x00000038,0x00000000,0x00000023,0x00000000,0x00040047,0x0000005a, + 0x00000021,0x00000002,0x00040047,0x0000005a,0x00000022,0x00000000,0x00040047,0x0000006d, + 0x00000021,0x00000000,0x00040047,0x0000006d,0x00000022,0x00000000,0x00040047,0x00000078, + 0x00000021,0x00000003,0x00040047,0x00000078,0x00000022,0x00000000,0x00020013,0x00000002, + 0x00030021,0x00000003,0x00000002,0x00040015,0x00000006,0x00000020,0x00000001,0x00040017, + 0x00000007,0x00000006,0x00000002,0x00040020,0x00000008,0x00000007,0x00000007,0x00040015, + 0x0000000a,0x00000020,0x00000000,0x00040017,0x0000000b,0x0000000a,0x00000003,0x00040020, + 0x0000000c,0x00000001,0x0000000b,0x0004003b,0x0000000c,0x0000000d,0x00000001,0x00040017, + 0x0000000e,0x0000000a,0x00000002,0x00030016,0x00000013,0x00000020,0x00090019,0x00000014, + 0x00000013,0x00000001,0x00000000,0x00000000,0x00000000,0x00000002,0x00000008,0x00040020, + 0x00000015,0x00000000,0x00000014,0x0004003b,0x00000015,0x00000016,0x00000000,0x00020014, + 0x0000001b,0x00040017,0x0000001c,0x0000001b,0x00000002,0x00040017,0x00000022,0x00000013, + 0x00000002,0x00040020,0x00000023,0x00000007,0x00000022,0x0004002b,0x00000013,0x00000027, + 0x3f000000,0x00090019,0x0000002e,0x00000013,0x00000001,0x00000000,0x00000000,0x00000000, + 0x00000001,0x00000000,0x0003001b,0x0000002f,0x0000002e,0x00040020,0x00000030,0x00000000, + 0x0000002f,0x0004003b,0x00000030,0x00000031,0x00000000,0x0004002b,0x00000013,0x00000034, + 0x00000000,0x00040017,0x00000035,0x00000013,0x00000004,0x0003001e,0x00000038,0x00000006, + 0x00040020,0x00000039,0x00000009,0x00000038,0x0004003b,0x00000039,0x0000003a,0x00000009, + 0x0004002b,0x00000006,0x0000003b,0x00000000,0x00040020,0x0000003c,0x00000009,0x00000006, + 0x0004002b,0x00000006,0x0000003f,0x00000001,0x00040017,0x00000043,0x00000013,0x00000003, + 0x00040020,0x00000044,0x00000007,0x00000043,0x0004002b,0x00000013,0x00000047,0x42800000, + 0x0004002b,0x00000013,0x0000004c,0x3f800000,0x0004002b,0x00000006,0x00000056,0x00000002, + 0x0004003b,0x00000030,0x0000005a,0x00000000,0x0004002b,0x0000000a,0x0000005e,0x00000000, + 0x0004002b,0x00000006,0x00000067,0x00000003,0x0004003b,0x00000030,0x0000006d,0x00000000, + 0x0005002c,0x00000022,0x00000074,0x00000034,0x00000034,0x0004003b,0x00000030,0x00000078, + 0x00000000,0x00040020,0x00000083,0x00000007,0x00000013,0x0004002b,0x0000000a,0x00000086, + 0x00000001,0x0004002b,0x0000000a,0x0000008a,0x00000002,0x0004002b,0x00000013,0x0000008e, + 0x3faaaaab,0x0004002b,0x0000000a,0x00000099,0x00000008,0x0006002c,0x0000000b,0x0000009a, + 0x00000099,0x00000099,0x00000086,0x00050036,0x00000002,0x00000004,0x00000000,0x00000003, + 0x000200f8,0x00000005,0x0004003b,0x00000008,0x00000009,0x00000007,0x0004003b,0x00000008, + 0x00000012,0x00000007,0x0004003b,0x00000023,0x00000024,0x00000007,0x0004003b,0x00000023, + 0x0000002d,0x00000007,0x0004003b,0x00000044,0x00000045,0x00000007,0x0004003b,0x00000023, + 0x00000063,0x00000007,0x0004003b,0x00000023,0x00000069,0x00000007,0x0004003b,0x00000044, + 0x00000077,0x00000007,0x0004003d,0x0000000b,0x0000000f,0x0000000d,0x0007004f,0x0000000e, + 0x00000010,0x0000000f,0x0000000f,0x00000000,0x00000001,0x0004007c,0x00000007,0x00000011, + 0x00000010,0x0003003e,0x00000009,0x00000011,0x0004003d,0x00000014,0x00000017,0x00000016, + 0x00040068,0x00000007,0x00000018,0x00000017,0x0003003e,0x00000012,0x00000018,0x0004003d, + 0x00000007,0x00000019,0x00000009,0x0004003d,0x00000007,0x0000001a,0x00000012,0x000500af, + 0x0000001c,0x0000001d,0x00000019,0x0000001a,0x0004009a,0x0000001b,0x0000001e,0x0000001d, + 0x000300f7,0x00000020,0x00000000,0x000400fa,0x0000001e,0x0000001f,0x00000020,0x000200f8, + 0x0000001f,0x000100fd,0x000200f8,0x00000020,0x0004003d,0x00000007,0x00000025,0x00000009, + 0x0004006f,0x00000022,0x00000026,0x00000025,0x00050050,0x00000022,0x00000028,0x00000027, + 0x00000027,0x00050081,0x00000022,0x00000029,0x00000026,0x00000028,0x0004003d,0x00000007, + 0x0000002a,0x00000012,0x0004006f,0x00000022,0x0000002b,0x0000002a,0x00050088,0x00000022, + 0x0000002c,0x00000029,0x0000002b,0x0003003e,0x00000024,0x0000002c,0x0004003d,0x0000002f, + 0x00000032,0x00000031,0x0004003d,0x00000022,0x00000033,0x00000024,0x00070058,0x00000035, + 0x00000036,0x00000032,0x00000033,0x00000002,0x00000034,0x0007004f,0x00000022,0x00000037, + 0x00000036,0x00000036,0x00000000,0x00000001,0x0003003e,0x0000002d,0x00000037,0x00050041, + 0x0000003c,0x0000003d,0x0000003a,0x0000003b,0x0004003d,0x00000006,0x0000003e,0x0000003d, + 0x000500aa,0x0000001b,0x00000040,0x0000003e,0x0000003f,0x000300f7,0x00000042,0x00000000, + 0x000400fa,0x00000040,0x00000041,0x00000053,0x000200f8,0x00000041,0x0004003d,0x00000022, + 0x00000046,0x0000002d,0x00050050,0x00000022,0x00000048,0x00000047,0x00000047,0x00050088, + 0x00000022,0x00000049,0x00000046,0x00000048,0x00050050,0x00000022,0x0000004a,0x00000027, + 0x00000027,0x00050081,0x00000022,0x0000004b,0x0000004a,0x00000049,0x00050050,0x00000022, + 0x0000004d,0x00000034,0x00000034,0x00050050,0x00000022,0x0000004e,0x0000004c,0x0000004c, + 0x0008000c,0x00000022,0x0000004f,0x00000001,0x0000002b,0x0000004b,0x0000004d,0x0000004e, + 0x00050051,0x00000013,0x00000050,0x0000004f,0x00000000,0x00050051,0x00000013,0x00000051, + 0x0000004f,0x00000001,0x00060050,0x00000043,0x00000052,0x00000050,0x00000051,0x00000027, + 0x0003003e,0x00000045,0x00000052,0x000200f9,0x00000042,0x000200f8,0x00000053,0x00050041, + 0x0000003c,0x00000054,0x0000003a,0x0000003b,0x0004003d,0x00000006,0x00000055,0x00000054, + 0x000500aa,0x0000001b,0x00000057,0x00000055,0x00000056,0x000300f7,0x00000059,0x00000000, + 0x000400fa,0x00000057,0x00000058,0x00000062,0x000200f8,0x00000058,0x0004003d,0x0000002f, + 0x0000005b,0x0000005a,0x0004003d,0x00000022,0x0000005c,0x00000024,0x00070058,0x00000035, + 0x0000005d,0x0000005b,0x0000005c,0x00000002,0x00000034,0x00050051,0x00000013,0x0000005f, + 0x0000005d,0x00000000,0x0007000c,0x00000013,0x00000060,0x00000001,0x0000001a,0x0000005f, + 0x00000047,0x00060050,0x00000043,0x00000061,0x00000060,0x00000060,0x00000060,0x0003003e, + 0x00000045,0x00000061,0x000200f9,0x00000059,0x000200f8,0x00000062,0x0004003d,0x00000022, + 0x00000064,0x00000024,0x00050041,0x0000003c,0x00000065,0x0000003a,0x0000003b,0x0004003d, + 0x00000006,0x00000066,0x00000065,0x000500aa,0x0000001b,0x00000068,0x00000066,0x00000067, + 0x000300f7,0x0000006b,0x00000000,0x000400fa,0x00000068,0x0000006a,0x00000073,0x000200f8, + 0x0000006a,0x0004003d,0x00000022,0x0000006c,0x0000002d,0x0004003d,0x0000002f,0x0000006e, + 0x0000006d,0x00040064,0x0000002e,0x0000006f,0x0000006e,0x00050067,0x00000007,0x00000070, + 0x0000006f,0x0000003b,0x0004006f,0x00000022,0x00000071,0x00000070,0x00050088,0x00000022, + 0x00000072,0x0000006c,0x00000071,0x0003003e,0x00000069,0x00000072,0x000200f9,0x0000006b, + 0x000200f8,0x00000073,0x0003003e,0x00000069,0x00000074,0x000200f9,0x0000006b,0x000200f8, + 0x0000006b,0x0004003d,0x00000022,0x00000075,0x00000069,0x00050081,0x00000022,0x00000076, + 0x00000064,0x00000075,0x0003003e,0x00000063,0x00000076,0x0004003d,0x0000002f,0x00000079, + 0x00000078,0x0004003d,0x00000022,0x0000007a,0x00000063,0x00070058,0x00000035,0x0000007b, + 0x00000079,0x0000007a,0x00000002,0x00000034,0x0008004f,0x00000043,0x0000007c,0x0000007b, + 0x0000007b,0x00000000,0x00000001,0x00000002,0x0004003d,0x0000002f,0x0000007d,0x0000006d, + 0x0004003d,0x00000022,0x0000007e,0x00000024,0x00070058,0x00000035,0x0000007f,0x0000007d, + 0x0000007e,0x00000002,0x00000034,0x0008004f,0x00000043,0x00000080,0x0000007f,0x0000007f, + 0x00000000,0x00000001,0x00000002,0x00050083,0x00000043,0x00000081,0x0000007c,0x00000080, + 0x0006000c,0x00000043,0x00000082,0x00000001,0x00000004,0x00000081,0x0003003e,0x00000077, + 0x00000082,0x00050041,0x00000083,0x00000084,0x00000077,0x0000005e,0x0004003d,0x00000013, + 0x00000085,0x00000084,0x00050041,0x00000083,0x00000087,0x00000077,0x00000086,0x0004003d, + 0x00000013,0x00000088,0x00000087,0x00050081,0x00000013,0x00000089,0x00000085,0x00000088, + 0x00050041,0x00000083,0x0000008b,0x00000077,0x0000008a,0x0004003d,0x00000013,0x0000008c, + 0x0000008b,0x00050081,0x00000013,0x0000008d,0x00000089,0x0000008c,0x00050085,0x00000013, + 0x0000008f,0x0000008d,0x0000008e,0x0007000c,0x00000013,0x00000090,0x00000001,0x00000025, + 0x0000008f,0x0000004c,0x00060050,0x00000043,0x00000091,0x00000090,0x00000090,0x00000090, + 0x0003003e,0x00000045,0x00000091,0x000200f9,0x00000059,0x000200f8,0x00000059,0x000200f9, + 0x00000042,0x000200f8,0x00000042,0x0004003d,0x00000014,0x00000092,0x00000016,0x0004003d, + 0x00000007,0x00000093,0x00000009,0x0004003d,0x00000043,0x00000094,0x00000045,0x00050051, + 0x00000013,0x00000095,0x00000094,0x00000000,0x00050051,0x00000013,0x00000096,0x00000094, + 0x00000001,0x00050051,0x00000013,0x00000097,0x00000094,0x00000002,0x00070050,0x00000035, + 0x00000098,0x00000095,0x00000096,0x00000097,0x0000004c,0x00040063,0x00000092,0x00000093, + 0x00000098,0x000100fd,0x00010038 +}; diff --git a/gpu/vk/shaders/dlss_motion.comp b/gpu/vk/shaders/dlss_motion.comp new file mode 100644 index 000000000..eb8588918 --- /dev/null +++ b/gpu/vk/shaders/dlss_motion.comp @@ -0,0 +1,33 @@ +#version 450 +// (hookshot) ported from Lichii (Eden lineage; Duck912's Eglantine work), GPL-3.0-or-later: vk_dlss.cpp + +layout(local_size_x = 8, local_size_y = 8) in; +layout(binding = 0) uniform sampler2D scene_depth; +layout(binding = 1, rg16f) uniform writeonly image2D motion; + +layout(push_constant, row_major) uniform Parameters { + mat4 clip_to_previous_clip; +} params; + +void main() { + ivec2 pixel = ivec2(gl_GlobalInvocationID.xy); + ivec2 extent = imageSize(motion); + if (any(greaterThanEqual(pixel, extent))) { + return; + } + + vec2 size = vec2(extent); + float depth = texelFetch(scene_depth, pixel, 0).r; + vec2 screen = (vec2(pixel) + 0.5) / size; + // The captured Zelda path is unjittered, with [-1, 1] clip depth and negative viewport height. + vec4 clip = vec4(screen * vec2(2, -2) + vec2(-1, 1), depth * 2 - 1, 1); + vec4 previous = params.clip_to_previous_clip * clip; + vec2 pixels = vec2(0); + if (depth >= 0 && depth <= 1 && previous.w > 1e-6) { + vec2 displacement = (previous.xy / previous.w - clip.xy) * vec2(0.5, -0.5) * size; + if (all(lessThanEqual(abs(displacement), vec2(65504)))) { + pixels = displacement; + } + } + imageStore(motion, pixel, vec4(pixels, 0, 0)); +} diff --git a/gpu/vk/shaders/dlss_motion_comp_spv.h b/gpu/vk/shaders/dlss_motion_comp_spv.h new file mode 100644 index 000000000..129471ff3 --- /dev/null +++ b/gpu/vk/shaders/dlss_motion_comp_spv.h @@ -0,0 +1,106 @@ + // 1116.6.0 + #pragma once +const uint32_t DLSS_MOTION_COMP_SPV[] = { + 0x07230203,0x00010600,0x0008000b,0x0000008b,0x00000000,0x00020011,0x00000001,0x00020011, + 0x00000031,0x00020011,0x00000032,0x0006000b,0x00000001,0x4c534c47,0x6474732e,0x3035342e, + 0x00000000,0x0003000e,0x00000000,0x00000001,0x0009000f,0x00000005,0x00000004,0x6e69616d, + 0x00000000,0x0000000d,0x00000016,0x0000002c,0x00000052,0x00060010,0x00000004,0x00000011, + 0x00000008,0x00000008,0x00000001,0x00030003,0x00000002,0x000001c2,0x00040005,0x00000004, + 0x6e69616d,0x00000000,0x00040005,0x00000009,0x65786970,0x0000006c,0x00080005,0x0000000d, + 0x475f6c67,0x61626f6c,0x766e496c,0x7461636f,0x496e6f69,0x00000044,0x00040005,0x00000012, + 0x65747865,0x0000746e,0x00040005,0x00000016,0x69746f6d,0x00006e6f,0x00040005,0x00000024, + 0x657a6973,0x00000000,0x00040005,0x00000028,0x74706564,0x00000068,0x00050005,0x0000002c, + 0x6e656373,0x65645f65,0x00687470,0x00040005,0x00000035,0x65726373,0x00006e65,0x00040005, + 0x0000003e,0x70696c63,0x00000000,0x00050005,0x0000004e,0x76657270,0x73756f69,0x00000000, + 0x00050005,0x00000050,0x61726150,0x6574656d,0x00007372,0x00090006,0x00000050,0x00000000, + 0x70696c63,0x5f6f745f,0x76657270,0x73756f69,0x696c635f,0x00000070,0x00040005,0x00000052, + 0x61726170,0x0000736d,0x00040005,0x00000058,0x65786970,0x0000736c,0x00060005,0x0000006a, + 0x70736964,0x6563616c,0x746e656d,0x00000000,0x00040047,0x0000000d,0x0000000b,0x0000001c, + 0x00030047,0x00000016,0x00000019,0x00040047,0x00000016,0x00000021,0x00000001,0x00040047, + 0x00000016,0x00000022,0x00000000,0x00040047,0x0000002c,0x00000021,0x00000000,0x00040047, + 0x0000002c,0x00000022,0x00000000,0x00030047,0x00000050,0x00000002,0x00040048,0x00000050, + 0x00000000,0x00000004,0x00050048,0x00000050,0x00000000,0x00000007,0x00000010,0x00050048, + 0x00000050,0x00000000,0x00000023,0x00000000,0x00020013,0x00000002,0x00030021,0x00000003, + 0x00000002,0x00040015,0x00000006,0x00000020,0x00000001,0x00040017,0x00000007,0x00000006, + 0x00000002,0x00040020,0x00000008,0x00000007,0x00000007,0x00040015,0x0000000a,0x00000020, + 0x00000000,0x00040017,0x0000000b,0x0000000a,0x00000003,0x00040020,0x0000000c,0x00000001, + 0x0000000b,0x0004003b,0x0000000c,0x0000000d,0x00000001,0x00040017,0x0000000e,0x0000000a, + 0x00000002,0x00030016,0x00000013,0x00000020,0x00090019,0x00000014,0x00000013,0x00000001, + 0x00000000,0x00000000,0x00000000,0x00000002,0x00000007,0x00040020,0x00000015,0x00000000, + 0x00000014,0x0004003b,0x00000015,0x00000016,0x00000000,0x00020014,0x0000001b,0x00040017, + 0x0000001c,0x0000001b,0x00000002,0x00040017,0x00000022,0x00000013,0x00000002,0x00040020, + 0x00000023,0x00000007,0x00000022,0x00040020,0x00000027,0x00000007,0x00000013,0x00090019, + 0x00000029,0x00000013,0x00000001,0x00000000,0x00000000,0x00000000,0x00000001,0x00000000, + 0x0003001b,0x0000002a,0x00000029,0x00040020,0x0000002b,0x00000000,0x0000002a,0x0004003b, + 0x0000002b,0x0000002c,0x00000000,0x0004002b,0x00000006,0x0000002f,0x00000000,0x00040017, + 0x00000031,0x00000013,0x00000004,0x0004002b,0x0000000a,0x00000033,0x00000000,0x0004002b, + 0x00000013,0x00000038,0x3f000000,0x00040020,0x0000003d,0x00000007,0x00000031,0x0004002b, + 0x00000013,0x00000040,0x40000000,0x0004002b,0x00000013,0x00000041,0xc0000000,0x0005002c, + 0x00000022,0x00000042,0x00000040,0x00000041,0x0004002b,0x00000013,0x00000044,0xbf800000, + 0x0004002b,0x00000013,0x00000045,0x3f800000,0x0005002c,0x00000022,0x00000046,0x00000044, + 0x00000045,0x00040018,0x0000004f,0x00000031,0x00000004,0x0003001e,0x00000050,0x0000004f, + 0x00040020,0x00000051,0x00000009,0x00000050,0x0004003b,0x00000051,0x00000052,0x00000009, + 0x00040020,0x00000053,0x00000009,0x0000004f,0x0004002b,0x00000013,0x00000059,0x00000000, + 0x0005002c,0x00000022,0x0000005a,0x00000059,0x00000059,0x0004002b,0x0000000a,0x00000062, + 0x00000003,0x0004002b,0x00000013,0x00000065,0x358637bd,0x0004002b,0x00000013,0x00000074, + 0xbf000000,0x0005002c,0x00000022,0x00000075,0x00000038,0x00000074,0x0004002b,0x00000013, + 0x0000007b,0x477fe000,0x0005002c,0x00000022,0x0000007c,0x0000007b,0x0000007b,0x0004002b, + 0x0000000a,0x00000088,0x00000008,0x0004002b,0x0000000a,0x00000089,0x00000001,0x0006002c, + 0x0000000b,0x0000008a,0x00000088,0x00000088,0x00000089,0x00050036,0x00000002,0x00000004, + 0x00000000,0x00000003,0x000200f8,0x00000005,0x0004003b,0x00000008,0x00000009,0x00000007, + 0x0004003b,0x00000008,0x00000012,0x00000007,0x0004003b,0x00000023,0x00000024,0x00000007, + 0x0004003b,0x00000027,0x00000028,0x00000007,0x0004003b,0x00000023,0x00000035,0x00000007, + 0x0004003b,0x0000003d,0x0000003e,0x00000007,0x0004003b,0x0000003d,0x0000004e,0x00000007, + 0x0004003b,0x00000023,0x00000058,0x00000007,0x0004003b,0x00000023,0x0000006a,0x00000007, + 0x0004003d,0x0000000b,0x0000000f,0x0000000d,0x0007004f,0x0000000e,0x00000010,0x0000000f, + 0x0000000f,0x00000000,0x00000001,0x0004007c,0x00000007,0x00000011,0x00000010,0x0003003e, + 0x00000009,0x00000011,0x0004003d,0x00000014,0x00000017,0x00000016,0x00040068,0x00000007, + 0x00000018,0x00000017,0x0003003e,0x00000012,0x00000018,0x0004003d,0x00000007,0x00000019, + 0x00000009,0x0004003d,0x00000007,0x0000001a,0x00000012,0x000500af,0x0000001c,0x0000001d, + 0x00000019,0x0000001a,0x0004009a,0x0000001b,0x0000001e,0x0000001d,0x000300f7,0x00000020, + 0x00000000,0x000400fa,0x0000001e,0x0000001f,0x00000020,0x000200f8,0x0000001f,0x000100fd, + 0x000200f8,0x00000020,0x0004003d,0x00000007,0x00000025,0x00000012,0x0004006f,0x00000022, + 0x00000026,0x00000025,0x0003003e,0x00000024,0x00000026,0x0004003d,0x0000002a,0x0000002d, + 0x0000002c,0x0004003d,0x00000007,0x0000002e,0x00000009,0x00040064,0x00000029,0x00000030, + 0x0000002d,0x0007005f,0x00000031,0x00000032,0x00000030,0x0000002e,0x00000002,0x0000002f, + 0x00050051,0x00000013,0x00000034,0x00000032,0x00000000,0x0003003e,0x00000028,0x00000034, + 0x0004003d,0x00000007,0x00000036,0x00000009,0x0004006f,0x00000022,0x00000037,0x00000036, + 0x00050050,0x00000022,0x00000039,0x00000038,0x00000038,0x00050081,0x00000022,0x0000003a, + 0x00000037,0x00000039,0x0004003d,0x00000022,0x0000003b,0x00000024,0x00050088,0x00000022, + 0x0000003c,0x0000003a,0x0000003b,0x0003003e,0x00000035,0x0000003c,0x0004003d,0x00000022, + 0x0000003f,0x00000035,0x00050085,0x00000022,0x00000043,0x0000003f,0x00000042,0x00050081, + 0x00000022,0x00000047,0x00000043,0x00000046,0x0004003d,0x00000013,0x00000048,0x00000028, + 0x00050085,0x00000013,0x00000049,0x00000048,0x00000040,0x00050083,0x00000013,0x0000004a, + 0x00000049,0x00000045,0x00050051,0x00000013,0x0000004b,0x00000047,0x00000000,0x00050051, + 0x00000013,0x0000004c,0x00000047,0x00000001,0x00070050,0x00000031,0x0000004d,0x0000004b, + 0x0000004c,0x0000004a,0x00000045,0x0003003e,0x0000003e,0x0000004d,0x00050041,0x00000053, + 0x00000054,0x00000052,0x0000002f,0x0004003d,0x0000004f,0x00000055,0x00000054,0x0004003d, + 0x00000031,0x00000056,0x0000003e,0x00050091,0x00000031,0x00000057,0x00000055,0x00000056, + 0x0003003e,0x0000004e,0x00000057,0x0003003e,0x00000058,0x0000005a,0x0004003d,0x00000013, + 0x0000005b,0x00000028,0x000500be,0x0000001b,0x0000005c,0x0000005b,0x00000059,0x0004003d, + 0x00000013,0x0000005d,0x00000028,0x000500bc,0x0000001b,0x0000005e,0x0000005d,0x00000045, + 0x000500a7,0x0000001b,0x0000005f,0x0000005c,0x0000005e,0x000300f7,0x00000061,0x00000000, + 0x000400fa,0x0000005f,0x00000060,0x00000061,0x000200f8,0x00000060,0x00050041,0x00000027, + 0x00000063,0x0000004e,0x00000062,0x0004003d,0x00000013,0x00000064,0x00000063,0x000500ba, + 0x0000001b,0x00000066,0x00000064,0x00000065,0x000200f9,0x00000061,0x000200f8,0x00000061, + 0x000700f5,0x0000001b,0x00000067,0x0000005f,0x00000020,0x00000066,0x00000060,0x000300f7, + 0x00000069,0x00000000,0x000400fa,0x00000067,0x00000068,0x00000069,0x000200f8,0x00000068, + 0x0004003d,0x00000031,0x0000006b,0x0000004e,0x0007004f,0x00000022,0x0000006c,0x0000006b, + 0x0000006b,0x00000000,0x00000001,0x00050041,0x00000027,0x0000006d,0x0000004e,0x00000062, + 0x0004003d,0x00000013,0x0000006e,0x0000006d,0x00050050,0x00000022,0x0000006f,0x0000006e, + 0x0000006e,0x00050088,0x00000022,0x00000070,0x0000006c,0x0000006f,0x0004003d,0x00000031, + 0x00000071,0x0000003e,0x0007004f,0x00000022,0x00000072,0x00000071,0x00000071,0x00000000, + 0x00000001,0x00050083,0x00000022,0x00000073,0x00000070,0x00000072,0x00050085,0x00000022, + 0x00000076,0x00000073,0x00000075,0x0004003d,0x00000022,0x00000077,0x00000024,0x00050085, + 0x00000022,0x00000078,0x00000076,0x00000077,0x0003003e,0x0000006a,0x00000078,0x0004003d, + 0x00000022,0x00000079,0x0000006a,0x0006000c,0x00000022,0x0000007a,0x00000001,0x00000004, + 0x00000079,0x000500bc,0x0000001c,0x0000007d,0x0000007a,0x0000007c,0x0004009b,0x0000001b, + 0x0000007e,0x0000007d,0x000300f7,0x00000080,0x00000000,0x000400fa,0x0000007e,0x0000007f, + 0x00000080,0x000200f8,0x0000007f,0x0004003d,0x00000022,0x00000081,0x0000006a,0x0003003e, + 0x00000058,0x00000081,0x000200f9,0x00000080,0x000200f8,0x00000080,0x000200f9,0x00000069, + 0x000200f8,0x00000069,0x0004003d,0x00000014,0x00000082,0x00000016,0x0004003d,0x00000007, + 0x00000083,0x00000009,0x0004003d,0x00000022,0x00000084,0x00000058,0x00050051,0x00000013, + 0x00000085,0x00000084,0x00000000,0x00050051,0x00000013,0x00000086,0x00000084,0x00000001, + 0x00070050,0x00000031,0x00000087,0x00000085,0x00000086,0x00000059,0x00000059,0x00040063, + 0x00000082,0x00000083,0x00000087,0x000100fd,0x00010038 +}; diff --git a/gpu/vk/shaders/dlss_output.comp b/gpu/vk/shaders/dlss_output.comp new file mode 100644 index 000000000..7df27f33e --- /dev/null +++ b/gpu/vk/shaders/dlss_output.comp @@ -0,0 +1,20 @@ +#version 450 +// (hookshot) ported from Lichii (Eden lineage; Duck912's Eglantine work), GPL-3.0-or-later: vk_dlss.cpp + +layout(local_size_x = 8, local_size_y = 8) in; +layout(binding = 0) uniform sampler2D dlss_color; +layout(binding = 1, r11f_g11f_b10f) uniform writeonly image2D guest_color; + +void main() { + ivec2 pixel = ivec2(gl_GlobalInvocationID.xy); + ivec2 extent = imageSize(guest_color); + if (any(greaterThanEqual(pixel, extent))) { + return; + } + // The guest upscaler squares its encoded RGB before writing the linear target. + vec3 sampled = all(equal(textureSize(dlss_color, 0), extent)) + ? texelFetch(dlss_color, pixel, 0).rgb + : textureLod(dlss_color, (vec2(pixel) + 0.5) / vec2(extent), 0).rgb; + vec3 color = max(sampled, vec3(0.0)); + imageStore(guest_color, pixel, vec4(color * color, 1.0)); +} diff --git a/gpu/vk/shaders/dlss_output_comp_spv.h b/gpu/vk/shaders/dlss_output_comp_spv.h new file mode 100644 index 000000000..090f881d1 --- /dev/null +++ b/gpu/vk/shaders/dlss_output_comp_spv.h @@ -0,0 +1,69 @@ + // 1116.6.0 + #pragma once +const uint32_t DLSS_OUTPUT_COMP_SPV[] = { + 0x07230203,0x00010600,0x0008000b,0x00000059,0x00000000,0x00020011,0x00000001,0x00020011, + 0x00000031,0x00020011,0x00000032,0x0006000b,0x00000001,0x4c534c47,0x6474732e,0x3035342e, + 0x00000000,0x0003000e,0x00000000,0x00000001,0x0008000f,0x00000005,0x00000004,0x6e69616d, + 0x00000000,0x0000000d,0x00000016,0x00000028,0x00060010,0x00000004,0x00000011,0x00000008, + 0x00000008,0x00000001,0x00030003,0x00000002,0x000001c2,0x00040005,0x00000004,0x6e69616d, + 0x00000000,0x00040005,0x00000009,0x65786970,0x0000006c,0x00080005,0x0000000d,0x475f6c67, + 0x61626f6c,0x766e496c,0x7461636f,0x496e6f69,0x00000044,0x00040005,0x00000012,0x65747865, + 0x0000746e,0x00050005,0x00000016,0x73657567,0x6f635f74,0x00726f6c,0x00040005,0x00000024, + 0x706d6173,0x0064656c,0x00050005,0x00000028,0x73736c64,0x6c6f635f,0x0000726f,0x00040005, + 0x00000048,0x6f6c6f63,0x00000072,0x00040047,0x0000000d,0x0000000b,0x0000001c,0x00030047, + 0x00000016,0x00000019,0x00040047,0x00000016,0x00000021,0x00000001,0x00040047,0x00000016, + 0x00000022,0x00000000,0x00040047,0x00000028,0x00000021,0x00000000,0x00040047,0x00000028, + 0x00000022,0x00000000,0x00020013,0x00000002,0x00030021,0x00000003,0x00000002,0x00040015, + 0x00000006,0x00000020,0x00000001,0x00040017,0x00000007,0x00000006,0x00000002,0x00040020, + 0x00000008,0x00000007,0x00000007,0x00040015,0x0000000a,0x00000020,0x00000000,0x00040017, + 0x0000000b,0x0000000a,0x00000003,0x00040020,0x0000000c,0x00000001,0x0000000b,0x0004003b, + 0x0000000c,0x0000000d,0x00000001,0x00040017,0x0000000e,0x0000000a,0x00000002,0x00030016, + 0x00000013,0x00000020,0x00090019,0x00000014,0x00000013,0x00000001,0x00000000,0x00000000, + 0x00000000,0x00000002,0x00000008,0x00040020,0x00000015,0x00000000,0x00000014,0x0004003b, + 0x00000015,0x00000016,0x00000000,0x00020014,0x0000001b,0x00040017,0x0000001c,0x0000001b, + 0x00000002,0x00040017,0x00000022,0x00000013,0x00000003,0x00040020,0x00000023,0x00000007, + 0x00000022,0x00090019,0x00000025,0x00000013,0x00000001,0x00000000,0x00000000,0x00000000, + 0x00000001,0x00000000,0x0003001b,0x00000026,0x00000025,0x00040020,0x00000027,0x00000000, + 0x00000026,0x0004003b,0x00000027,0x00000028,0x00000000,0x0004002b,0x00000006,0x0000002a, + 0x00000000,0x00040017,0x00000036,0x00000013,0x00000004,0x00040017,0x0000003c,0x00000013, + 0x00000002,0x0004002b,0x00000013,0x0000003e,0x3f000000,0x0004002b,0x00000013,0x00000044, + 0x00000000,0x0006002c,0x00000022,0x0000004a,0x00000044,0x00000044,0x00000044,0x0004002b, + 0x00000013,0x00000051,0x3f800000,0x0004002b,0x0000000a,0x00000056,0x00000008,0x0004002b, + 0x0000000a,0x00000057,0x00000001,0x0006002c,0x0000000b,0x00000058,0x00000056,0x00000056, + 0x00000057,0x00050036,0x00000002,0x00000004,0x00000000,0x00000003,0x000200f8,0x00000005, + 0x0004003b,0x00000008,0x00000009,0x00000007,0x0004003b,0x00000008,0x00000012,0x00000007, + 0x0004003b,0x00000023,0x00000024,0x00000007,0x0004003b,0x00000023,0x00000030,0x00000007, + 0x0004003b,0x00000023,0x00000048,0x00000007,0x0004003d,0x0000000b,0x0000000f,0x0000000d, + 0x0007004f,0x0000000e,0x00000010,0x0000000f,0x0000000f,0x00000000,0x00000001,0x0004007c, + 0x00000007,0x00000011,0x00000010,0x0003003e,0x00000009,0x00000011,0x0004003d,0x00000014, + 0x00000017,0x00000016,0x00040068,0x00000007,0x00000018,0x00000017,0x0003003e,0x00000012, + 0x00000018,0x0004003d,0x00000007,0x00000019,0x00000009,0x0004003d,0x00000007,0x0000001a, + 0x00000012,0x000500af,0x0000001c,0x0000001d,0x00000019,0x0000001a,0x0004009a,0x0000001b, + 0x0000001e,0x0000001d,0x000300f7,0x00000020,0x00000000,0x000400fa,0x0000001e,0x0000001f, + 0x00000020,0x000200f8,0x0000001f,0x000100fd,0x000200f8,0x00000020,0x0004003d,0x00000026, + 0x00000029,0x00000028,0x00040064,0x00000025,0x0000002b,0x00000029,0x00050067,0x00000007, + 0x0000002c,0x0000002b,0x0000002a,0x0004003d,0x00000007,0x0000002d,0x00000012,0x000500aa, + 0x0000001c,0x0000002e,0x0000002c,0x0000002d,0x0004009b,0x0000001b,0x0000002f,0x0000002e, + 0x000300f7,0x00000032,0x00000000,0x000400fa,0x0000002f,0x00000031,0x00000039,0x000200f8, + 0x00000031,0x0004003d,0x00000026,0x00000033,0x00000028,0x0004003d,0x00000007,0x00000034, + 0x00000009,0x00040064,0x00000025,0x00000035,0x00000033,0x0007005f,0x00000036,0x00000037, + 0x00000035,0x00000034,0x00000002,0x0000002a,0x0008004f,0x00000022,0x00000038,0x00000037, + 0x00000037,0x00000000,0x00000001,0x00000002,0x0003003e,0x00000030,0x00000038,0x000200f9, + 0x00000032,0x000200f8,0x00000039,0x0004003d,0x00000026,0x0000003a,0x00000028,0x0004003d, + 0x00000007,0x0000003b,0x00000009,0x0004006f,0x0000003c,0x0000003d,0x0000003b,0x00050050, + 0x0000003c,0x0000003f,0x0000003e,0x0000003e,0x00050081,0x0000003c,0x00000040,0x0000003d, + 0x0000003f,0x0004003d,0x00000007,0x00000041,0x00000012,0x0004006f,0x0000003c,0x00000042, + 0x00000041,0x00050088,0x0000003c,0x00000043,0x00000040,0x00000042,0x00070058,0x00000036, + 0x00000045,0x0000003a,0x00000043,0x00000002,0x00000044,0x0008004f,0x00000022,0x00000046, + 0x00000045,0x00000045,0x00000000,0x00000001,0x00000002,0x0003003e,0x00000030,0x00000046, + 0x000200f9,0x00000032,0x000200f8,0x00000032,0x0004003d,0x00000022,0x00000047,0x00000030, + 0x0003003e,0x00000024,0x00000047,0x0004003d,0x00000022,0x00000049,0x00000024,0x0007000c, + 0x00000022,0x0000004b,0x00000001,0x00000028,0x00000049,0x0000004a,0x0003003e,0x00000048, + 0x0000004b,0x0004003d,0x00000014,0x0000004c,0x00000016,0x0004003d,0x00000007,0x0000004d, + 0x00000009,0x0004003d,0x00000022,0x0000004e,0x00000048,0x0004003d,0x00000022,0x0000004f, + 0x00000048,0x00050085,0x00000022,0x00000050,0x0000004e,0x0000004f,0x00050051,0x00000013, + 0x00000052,0x00000050,0x00000000,0x00050051,0x00000013,0x00000053,0x00000050,0x00000001, + 0x00050051,0x00000013,0x00000054,0x00000050,0x00000002,0x00070050,0x00000036,0x00000055, + 0x00000052,0x00000053,0x00000054,0x00000051,0x00040063,0x0000004c,0x0000004d,0x00000055, + 0x000100fd,0x00010038 +}; diff --git a/gpu/vk/vk_dlss.cpp b/gpu/vk/vk_dlss.cpp new file mode 100644 index 000000000..54c7d2006 --- /dev/null +++ b/gpu/vk/vk_dlss.cpp @@ -0,0 +1,589 @@ +// NVIDIA DLSS super resolution through NVIDIA Streamline, manual hooking (vk_dlss.h). Ported from Lichii (Eden lineage; +// Duck912's Eglantine work), GPL-3.0-or-later: video_core/vulkan_common/streamline.cpp (the loader) and +// renderer_vulkan/vk_streamline_dlss.cpp (the evaluation). Streamline's headers are MIT (third_party/streamline/license.txt). +#include "vk_dlss.h" +#include "vk_internal.h" + +#ifdef _WIN32 + +#include +#include +#include +#include +#include + +#include +#include +#include +#include // (its functions are defined in it: this file only) +#include +#include + +#include "vk_menu.h" + +namespace mkwvk { +namespace { + +namespace fs = std::filesystem; + +// (Lichii's: a custom engine names itself with its own project id; kept fixed, the driver may key behaviour off it) +constexpr const char* PROJECT_ID = "8d3e2f9a-6b41-4c7e-9a52-1f0c3b7d5e64"; +constexpr unsigned MIN_DLSS_MAJOR = 310; // (the first DLSS with preset K) +using Version = std::array; + +// the functions Streamline's manual hooking wants routed through its proxies +#define DLSS_HOOKED(X) \ + X(vkCreateSwapchainKHR) X(vkDestroySwapchainKHR) X(vkGetSwapchainImagesKHR) X(vkAcquireNextImageKHR) X(vkQueuePresentKHR) \ + X(vkDeviceWaitIdle) + +struct State { + HMODULE module = nullptr; + PFun_slInit* init = nullptr; + PFun_slShutdown* shutdown = nullptr; + PFun_slIsFeatureSupported* is_feature_supported = nullptr; + PFun_slGetFeatureRequirements* get_feature_requirements = nullptr; + PFun_slGetFeatureVersion* get_feature_version = nullptr; + PFun_slGetFeatureFunction* get_feature_function = nullptr; + PFun_slGetNewFrameToken* get_new_frame_token = nullptr; + PFun_slSetConstants* set_constants = nullptr; + PFun_slEvaluateFeature* evaluate_feature = nullptr; + PFun_slFreeResources* free_resources = nullptr; + PFun_slSetVulkanInfo* set_vulkan_info = nullptr; + PFun_slDLSSSetOptions* set_options = nullptr; + PFun_slDLSSGetOptimalSettings* get_optimal = nullptr; + std::wstring plugin_dir, model_dir; + std::vector inst_names, dev_names; + std::vector inst, devx; + bool tried = false, started = false, attached = false, failed = false, hooked = false; + const char* reason = "not started"; + struct { +#define DLSS_ORIG(f) PFN_##f f = nullptr; + DLSS_HOOKED(DLSS_ORIG) +#undef DLSS_ORIG + } orig; // (put back at stop) + bool options_set = false; + uint32_t rw = 0, rh = 0, ow = 0, oh = 0; // (the sizes the options were last set for) + sl::DLSSPreset preset{}; // (and the preset asked for) +}; +State st; + +int env_int(const char* name, int fallback) { + const char* v = getenv(name); + return v ? atoi(v) : fallback; +} + +std::string u8(const fs::path& p) { + const std::u8string s = p.u8string(); + return std::string(s.begin(), s.end()); +} + +// RX_DLSS_LOG=1: Streamline's info lines too, 2: verbose +void sl_log(sl::LogType type, const char* msg) { + std::string s = msg ? msg : ""; + while (!s.empty() && (s.back() == '\n' || s.back() == '\r')) s.pop_back(); + if (type == sl::LogType::eError || type == sl::LogType::eWarn || env_int("RX_DLSS_LOG", 0) > 0) + logf("vk: dlss: sl: %s", s.c_str()); +} + +bool off(const char* why) { + st.reason = why; + logf("vk: dlss: off: %s", why); + return false; +} + +template +bool resolve(const char* name, T*& f) { + f = reinterpret_cast(GetProcAddress(st.module, name)); + if (!f) logf("vk: dlss: sl.interposer.dll has no %s", name); + return f != nullptr; +} + +fs::path exe_dir() { + wchar_t b[4096]; + const DWORD n = GetModuleFileNameW(nullptr, b, (DWORD)std::size(b)); + return fs::path(std::wstring(b, n)).parent_path(); +} + +std::optional read_version(const fs::path& path) { + DWORD handle = 0; + const DWORD size = GetFileVersionInfoSizeW(path.c_str(), &handle); + if (!size) return std::nullopt; + std::vector data(size); + VS_FIXEDFILEINFO* info = nullptr; + UINT length = 0; + if (!GetFileVersionInfoW(path.c_str(), 0, size, data.data()) || + !VerQueryValueW(data.data(), L"\\", reinterpret_cast(&info), &length) || !info) + return std::nullopt; + return Version{HIWORD(info->dwFileVersionMS), LOWORD(info->dwFileVersionMS), HIWORD(info->dwFileVersionLS), + LOWORD(info->dwFileVersionLS)}; +} + +/// A valid Authenticode signature from NVIDIA Corporation (the DLSS models) +bool signed_by_nvidia(const fs::path& path) { + std::error_code ec; + const std::wstring file_path = fs::absolute(path, ec).wstring(); + WINTRUST_FILE_INFO file{}; + file.cbStruct = sizeof(file); + file.pcwszFilePath = file_path.c_str(); + WINTRUST_DATA data{}; + data.cbStruct = sizeof(data); + data.dwUIChoice = WTD_UI_NONE; + data.fdwRevocationChecks = WTD_REVOKE_NONE; + data.dwUnionChoice = WTD_CHOICE_FILE; + data.pFile = &file; + data.dwStateAction = WTD_STATEACTION_VERIFY; + data.dwProvFlags = WTD_CACHE_ONLY_URL_RETRIEVAL; + GUID action = WINTRUST_ACTION_GENERIC_VERIFY_V2; + bool valid = WinVerifyTrust(nullptr, &action, &data) == ERROR_SUCCESS; + if (valid) { + CRYPT_PROVIDER_DATA* provider = WTHelperProvDataFromStateData(data.hWVTStateData); + CRYPT_PROVIDER_SGNR* signer = provider ? WTHelperGetProvSignerFromChain(provider, 0, FALSE, 0) : nullptr; + CRYPT_PROVIDER_CERT* cert = signer ? WTHelperGetProvCertFromChain(signer, 0) : nullptr; + wchar_t name[128]{}; + valid = cert && + CertGetNameStringW(cert->pCert, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, nullptr, name, (DWORD)std::size(name)) > 1 && + std::wstring(name) == L"NVIDIA Corporation"; + } + data.dwStateAction = WTD_STATEACTION_CLOSE; + WinVerifyTrust(nullptr, &action, &data); + return valid; +} + +/// The NVIDIA app keeps every DLSS it downloads under ProgramData: the newest of major >= 310 +fs::path find_app_model() { + const wchar_t* program_data = _wgetenv(L"ProgramData"); + if (!program_data) return {}; + const fs::path root = fs::path(program_data) / L"NVIDIA" / L"NGX" / L"models" / L"dlss" / L"versions"; + fs::path best_path; + Version best{}; + std::error_code ec; + for (const auto& version_dir : fs::directory_iterator(root, ec)) { + std::error_code files_ec; + for (const auto& file : fs::directory_iterator(version_dir.path() / L"files", files_ec)) { + if (file.path().extension() != L".bin") continue; + const std::optional v = read_version(file.path()); + if (v && (*v)[0] >= MIN_DLSS_MAJOR && *v > best) best = *v, best_path = file.path(); + } + } + return best_path; +} + +/// The NVIDIA app's DLSS copied (signature checked) to \streamline\nvidia-app\nvngx_dlss.dll, the name +/// Streamline loads: that folder, or empty +fs::path use_app_model(const fs::path& app) { + const fs::path dir = exe_dir() / L"streamline" / L"nvidia-app", target = dir / L"nvngx_dlss.dll"; + std::error_code ec; + const bool current = fs::is_regular_file(target, ec) && fs::file_size(target, ec) == fs::file_size(app, ec) && + read_version(target) == read_version(app); + if (!current) { + if (!signed_by_nvidia(app)) { + logf("vk: dlss: the NVIDIA app's DLSS %s is not signed by NVIDIA", u8(app).c_str()); + return {}; + } + fs::create_directories(dir, ec); + fs::copy_file(app, target, fs::copy_options::overwrite_existing, ec); + if (ec) { + logf("vk: dlss: could not copy the NVIDIA app's DLSS to %s: %s", u8(target).c_str(), ec.message().c_str()); + return {}; + } + } + if (!signed_by_nvidia(target)) { + logf("vk: dlss: %s is not signed by NVIDIA", u8(target).c_str()); + return {}; + } + return dir; +} + +void unhook() { + if (!st.hooked) return; +#define DLSS_RESTORE(f) vkx::f = st.orig.f; + DLSS_HOOKED(DLSS_RESTORE) +#undef DLSS_RESTORE + st.hooked = false; +} + +/// Attach failed: Streamline stops, DLSS stays off +void shut(const char* why) { + unhook(); + st.shutdown(); + st.started = st.attached = false; + off(why); +} + +// DLSS checks the render size against the mode's range: the mode for this ratio +sl::DLSSMode mode_for(uint32_t render_w, uint32_t output_w) { + const float ratio = (float)render_w / (float)output_w; + return ratio >= 0.99f ? sl::DLSSMode::eDLAA : + ratio >= 0.65f ? sl::DLSSMode::eMaxQuality : + ratio >= 0.57f ? sl::DLSSMode::eBalanced : + ratio >= 0.49f ? sl::DLSSMode::eMaxPerformance : sl::DLSSMode::eUltraPerformance; +} + +// The menu's DLSS preset row, one preset for every mode: M by default (the owner's choice; Lichii kept K, as NVIDIA's own +// M and L for Performance/Ultra Performance drew thin horizontal lines there). RX_DLSS_PRESET=J|K|L|M sets the row +// (menu_init), =default: NVIDIA's choice per mode +sl::DLSSPreset preset_now() { + static const char* v = getenv("RX_DLSS_PRESET"); + if (v && !strcmp(v, "default")) return sl::DLSSPreset::eDefault; + return (sl::DLSSPreset)((uint32_t)sl::DLSSPreset::ePresetJ + (uint32_t)opts.dlss_preset); +} +std::string preset_name(sl::DLSSPreset p) { + return p == sl::DLSSPreset::eDefault ? "default" : std::string(1, (char)('A' + (uint32_t)p - 1)); +} + +sl::float4x4 identity() { + sl::float4x4 m; + m.setRow(0, {1.0f, 0.0f, 0.0f, 0.0f}); + m.setRow(1, {0.0f, 1.0f, 0.0f, 0.0f}); + m.setRow(2, {0.0f, 0.0f, 1.0f, 0.0f}); + m.setRow(3, {0.0f, 0.0f, 0.0f, 1.0f}); + return m; +} + +VkImageMemoryBarrier2 barrier(const DlssImage& i, VkAccessFlags2 src, VkAccessFlags2 dst, VkImageLayout from, VkImageLayout to) { + VkImageMemoryBarrier2 b{VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2}; + b.srcStageMask = b.dstStageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT; + b.srcAccessMask = src, b.dstAccessMask = dst; + b.oldLayout = from, b.newLayout = to; + b.srcQueueFamilyIndex = b.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + b.image = i.image; + b.subresourceRange = {i.aspect, 0, 1, 0, 1}; + return b; +} + +void barriers(VkCommandBuffer cmd, const std::array& b) { + VkDependencyInfo d{VK_STRUCTURE_TYPE_DEPENDENCY_INFO}; + d.imageMemoryBarrierCount = (uint32_t)b.size(); + d.pImageMemoryBarriers = b.data(); + vkCmdPipelineBarrier2(cmd, &d); +} + +sl::Resource resource(const DlssImage& i, VkImageLayout layout, VkImageUsageFlags usage) { + sl::Resource r{sl::ResourceType::eTex2d, (void*)i.image, nullptr, (void*)i.view, (uint32_t)layout}; + r.width = i.width, r.height = i.height; + r.nativeFormat = (uint32_t)i.format; + r.mipLevels = r.arrayLayers = 1; + r.flags = 0; + r.usage = usage; + return r; +} + +} // namespace + +bool dlss_start() { + if (st.tried) return st.started; + st.tried = true; + // where sl.interposer.dll may be: RX_DLSS_DIR, then \streamline + std::vector dirs; + if (const char* d = getenv("RX_DLSS_DIR"); d && *d) dirs.emplace_back(d); + dirs.push_back(exe_dir() / L"streamline"); + std::error_code ec; + fs::path dir; + for (const fs::path& d : dirs) + if (fs::is_regular_file(d / L"sl.interposer.dll", ec)) { + dir = fs::absolute(d, ec); + break; + } + if (dir.empty()) { + logf("vk: dlss: no sl.interposer.dll in %s", u8(dirs.back()).c_str()); + return off("no sl.interposer.dll"); + } + const fs::path interposer = dir / L"sl.interposer.dll", model = dir / L"nvngx_dlss.dll"; + const bool has_model = fs::is_regular_file(model, ec); + if (has_model && !signed_by_nvidia(model)) { + logf("vk: dlss: %s is not signed by NVIDIA", u8(model).c_str()); + return off("nvngx_dlss.dll not signed by NVIDIA"); + } + if (!sl::security::verifyEmbeddedSignature(interposer.c_str())) { + logf("vk: dlss: %s is not signed by NVIDIA; not loading it", u8(interposer).c_str()); + return off("sl.interposer.dll not signed by NVIDIA"); + } + st.module = LoadLibraryW(interposer.c_str()); + if (!st.module) { + logf("vk: dlss: could not load %s (error %lu)", u8(interposer).c_str(), GetLastError()); + return off("sl.interposer.dll did not load"); + } + if (!(resolve("slInit", st.init) && resolve("slShutdown", st.shutdown) && + resolve("slIsFeatureSupported", st.is_feature_supported) && + resolve("slGetFeatureRequirements", st.get_feature_requirements) && + resolve("slGetFeatureVersion", st.get_feature_version) && + resolve("slGetFeatureFunction", st.get_feature_function) && + resolve("slGetNewFrameToken", st.get_new_frame_token) && resolve("slSetConstants", st.set_constants) && + resolve("slEvaluateFeature", st.evaluate_feature) && resolve("slFreeResources", st.free_resources) && + resolve("slSetVulkanInfo", st.set_vulkan_info))) { + FreeLibrary(st.module); + st.module = nullptr; + return off("sl.interposer.dll incomplete"); + } + st.plugin_dir = dir.wstring(); + // the model: the folder's nvngx_dlss.dll, or the NVIDIA app's newest when it is newer still (a tie: the folder's) + const fs::path app = find_app_model(); + const fs::path app_dir = + !app.empty() && (!has_model || read_version(app) > read_version(model)) ? use_app_model(app) : fs::path(); + const fs::path used = !app_dir.empty() ? app : has_model ? model : fs::path(); + if (!app_dir.empty()) st.model_dir = app_dir.wstring(); + if (used.empty()) + logf("vk: dlss: no nvngx_dlss.dll in %s and no DLSS %u+ from the NVIDIA app", u8(dir).c_str(), MIN_DLSS_MAJOR); + + // the plugins from the interposer's folder or NVIDIA's downloads (OTA); the model from the NVIDIA app's copy first, when used + const wchar_t* plugin_paths[] = {st.model_dir.c_str(), st.plugin_dir.c_str()}; + const sl::Feature features[] = {sl::kFeatureDLSS}; + sl::Preferences pref{}; + pref.logLevel = env_int("RX_DLSS_LOG", 0) >= 2 ? sl::LogLevel::eVerbose : sl::LogLevel::eDefault; + pref.logMessageCallback = sl_log; + pref.pathsToPlugins = st.model_dir.empty() ? plugin_paths + 1 : plugin_paths; + pref.numPathsToPlugins = st.model_dir.empty() ? 1 : 2; + pref.flags = sl::PreferenceFlags::eDisableCLStateTracking | sl::PreferenceFlags::eUseManualHooking | + sl::PreferenceFlags::eAllowOTA | sl::PreferenceFlags::eLoadDownloadedPlugins; + pref.featuresToLoad = features; + pref.numFeaturesToLoad = 1; + pref.engine = sl::EngineType::eCustom; + pref.engineVersion = "1.0"; + pref.projectId = PROJECT_ID; + pref.renderAPI = sl::RenderAPI::eVulkan; + sl::Result r = st.init(pref, sl::kSDKVersion); + if (r != sl::Result::eOk) { + logf("vk: dlss: slInit failed (result %d)", (int)r); + return off("Streamline did not start"); + } + sl::FeatureRequirements req{}; + if ((r = st.get_feature_requirements(sl::kFeatureDLSS, req)) != sl::Result::eOk) { + logf("vk: dlss: no DLSS plugin (result %d): sl.dlss.dll and sl.common.dll beside sl.interposer.dll, or the NVIDIA app", + (int)r); + st.shutdown(); + return off("no DLSS plugin"); + } + if (req.vkNumComputeQueuesRequired || req.vkNumGraphicsQueuesRequired) { + logf("vk: dlss: DLSS wants %u compute and %u graphics queues of its own", req.vkNumComputeQueuesRequired, + req.vkNumGraphicsQueuesRequired); + st.shutdown(); + return off("DLSS wants extra queues"); + } + for (uint32_t i = 0; i < req.vkNumInstanceExtensions; i++) st.inst_names.emplace_back(req.vkInstanceExtensions[i]); + bool khr_bda = false; + for (uint32_t i = 0; i < req.vkNumDeviceExtensions; i++) + khr_bda |= !strcmp(req.vkDeviceExtensions[i], VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME); + for (uint32_t i = 0; i < req.vkNumDeviceExtensions; i++) // (the KHR and EXT buffer device address cannot both be on) + if (!khr_bda || strcmp(req.vkDeviceExtensions[i], VK_EXT_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME)) + st.dev_names.emplace_back(req.vkDeviceExtensions[i]); + for (const std::string& s : st.inst_names) st.inst.push_back(s.c_str()); + for (const std::string& s : st.dev_names) st.devx.push_back(s.c_str()); + sl::FeatureVersion version{}; + st.get_feature_version(sl::kFeatureDLSS, version); + const Version mv = read_version(used).value_or(Version{}); + logf("vk: dlss: Streamline %s started from %s (DLSS %u.%u.%u.%u: %s; Streamline reports %s), %zu instance and %zu device " + "extensions", version.versionSL.toStr().c_str(), u8(dir).c_str(), mv[0], mv[1], mv[2], mv[3], u8(used).c_str(), + version.versionNGX.toStr().c_str(), st.inst.size(), st.devx.size()); + st.started = true; + st.reason = "no device yet"; + return true; +} + +const std::vector& dlss_instance_exts() { + static const std::vector none; + return st.started ? st.inst : none; +} + +const std::vector& dlss_device_exts() { + static const std::vector none; + return st.started ? st.devx : none; +} + +void dlss_attach(VkInstance instance, VkPhysicalDevice physical, VkDevice device, uint32_t queue_family) { + if (!st.started || st.attached) return; + sl::VulkanInfo info{}; + info.device = device; + info.instance = instance; + info.physicalDevice = physical; + info.computeQueueFamily = info.graphicsQueueFamily = queue_family; // (one family for both, as Hookshot's queue) + sl::Result r = st.set_vulkan_info(info); + if (r != sl::Result::eOk) { + logf("vk: dlss: slSetVulkanInfo failed (result %d)", (int)r); + return shut("Streamline did not take the device"); + } + sl::AdapterInfo adapter{}; + adapter.vkPhysicalDevice = physical; + if ((r = st.is_feature_supported(sl::kFeatureDLSS, adapter)) != sl::Result::eOk) { + logf("vk: dlss: not supported on this GPU or driver (result %d)", (int)r); + return shut("GPU not supported"); + } + void* set_options = nullptr; + if ((r = st.get_feature_function(sl::kFeatureDLSS, "slDLSSSetOptions", set_options)) != sl::Result::eOk || !set_options) { + logf("vk: dlss: no slDLSSSetOptions (result %d)", (int)r); + return shut("no slDLSSSetOptions"); + } + st.set_options = reinterpret_cast(set_options); + void* get_optimal = nullptr; // (the menu's DLSS mode labels and render sizes; standard ratios without it) + if (st.get_feature_function(sl::kFeatureDLSS, "slDLSSGetOptimalSettings", get_optimal) == sl::Result::eOk) + st.get_optimal = reinterpret_cast(get_optimal); + // manual hooking: Streamline does its per-frame work in these. RX_DLSS_NO_HOOKS=1: not routed (does DLSS-SR need them?) + if (env_int("RX_DLSS_NO_HOOKS", 0) != 1) { +#define DLSS_HOOK(f) \ + st.orig.f = vkx::f; \ + if (FARPROC p = GetProcAddress(st.module, #f)) vkx::f = reinterpret_cast(p); \ + else logf("vk: dlss: sl.interposer.dll has no %s", #f); + DLSS_HOOKED(DLSS_HOOK) +#undef DLSS_HOOK + st.hooked = true; + } + st.attached = true; + st.reason = ""; + sl::FeatureVersion version{}; // (again with the device: NGX's own number, if it differs from the start's) + st.get_feature_version(sl::kFeatureDLSS, version); + logf("vk: dlss: available, DLSS %s%s", version.versionNGX.toStr().c_str(), + st.hooked ? "" : " (RX_DLSS_NO_HOOKS: swapchain calls not routed through Streamline)"); +} + +void dlss_render_size(int mode, uint32_t ow, uint32_t oh, uint32_t& w, uint32_t& h) { + static const sl::DLSSMode modes[] = {sl::DLSSMode::eUltraPerformance, sl::DLSSMode::eMaxPerformance, sl::DLSSMode::eBalanced, + sl::DLSSMode::eMaxQuality, sl::DLSSMode::eDLAA}; + static const float ratios[] = {1.0f / 3.0f, 0.5f, 0.58f, 2.0f / 3.0f, 1.0f}; + mode = std::min(std::max(mode, 0), 4); + w = (uint32_t)(ow * ratios[mode] + 0.5f), h = (uint32_t)(oh * ratios[mode] + 0.5f); + static uint32_t got_w[5], got_h[5], got_ow, got_oh; // (asked once per output size) + if (!st.get_optimal || !dlss_available()) return; + if (got_ow != ow || got_oh != oh) std::fill_n(got_w, 5, 0u), got_ow = ow, got_oh = oh; + if (!got_w[mode]) { + sl::DLSSOptions o{}; + o.mode = modes[mode], o.outputWidth = ow, o.outputHeight = oh; + sl::DLSSOptimalSettings s{}; + if (st.get_optimal(o, s) == sl::Result::eOk && s.optimalRenderWidth && s.optimalRenderHeight) + got_w[mode] = s.optimalRenderWidth, got_h[mode] = s.optimalRenderHeight; + else + got_w[mode] = w, got_h[mode] = h; + } + w = got_w[mode], h = got_h[mode]; +} + +bool dlss_available() { + return st.started && st.attached && !st.failed; +} + +const char* dlss_reason() { + return st.reason; +} + +void dlss_stop() { + if (!st.started) return; + if (st.attached) st.free_resources(sl::kFeatureDLSS, sl::ViewportHandle{0u}); + unhook(); + const sl::Result r = st.shutdown(); + st.started = st.attached = false; + if (!st.failed) st.reason = "stopped"; + logf("vk: dlss: stopped (result %d)", (int)r); +} + +bool dlss_evaluate(VkCommandBuffer cmd, const DlssImage& color, const DlssImage& depth, const DlssImage& motion, + const DlssImage& output, bool reset, uint32_t frame_index) { + if (!dlss_available()) return false; + const sl::DLSSPreset preset = preset_now(); // (the menu's row: a change applies at once, history reset) + static const char* const mode_names[] = {"off", "Performance", "Balanced", "Quality", "Ultra Performance", "Ultra Quality", "DLAA"}; + const sl::ViewportHandle viewport{0u}; + const bool changed = !st.options_set || st.preset != preset || st.rw != color.width || st.rh != color.height || + st.ow != output.width || st.oh != output.height; + reset = reset || changed; + sl::Result r = sl::Result::eOk; + const char* stage = nullptr; + if (changed) { + // LDR: the game's colour is tonemapped already, so no HDR and no auto exposure + sl::DLSSOptions o{}; + o.mode = mode_for(color.width, output.width); + o.outputWidth = output.width, o.outputHeight = output.height; + o.colorBuffersHDR = sl::Boolean::eFalse; + o.useAutoExposure = sl::Boolean::eFalse; + sl::DLSSPreset use = preset; + const auto set = [&] { + o.dlaaPreset = o.qualityPreset = o.balancedPreset = o.performancePreset = o.ultraPerformancePreset = + o.ultraQualityPreset = use; + return st.set_options(viewport, o); + }; + if ((r = set()) != sl::Result::eOk && use != sl::DLSSPreset::ePresetK) { // (K: in every DLSS from 310) + logf("vk: dlss: preset %s not accepted (result %d): K", preset_name(use).c_str(), (int)r); + use = sl::DLSSPreset::ePresetK; + r = set(); + } + logf("vk: dlss: %ux%u -> %ux%u, mode %s, preset %s", color.width, color.height, output.width, output.height, + mode_names[(uint32_t)o.mode], preset_name(use).c_str()); + if (r != sl::Result::eOk) stage = "slDLSSSetOptions"; + else st.options_set = true, st.preset = preset, st.rw = color.width, st.rh = color.height, st.ow = output.width, + st.oh = output.height; + } + sl::FrameToken* frame = nullptr; + if (!stage && ((r = st.get_new_frame_token(frame, &frame_index)) != sl::Result::eOk || !frame)) stage = "slGetNewFrameToken"; + if (!stage) { + constexpr VkImageUsageFlags out_usage = VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | + VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; + constexpr VkAccessFlags2 any = VK_ACCESS_2_MEMORY_READ_BIT | VK_ACCESS_2_MEMORY_WRITE_BIT; + constexpr VkAccessFlags2 dlss_out = VK_ACCESS_2_SHADER_READ_BIT | VK_ACCESS_2_SHADER_WRITE_BIT | VK_ACCESS_2_TRANSFER_WRITE_BIT; + constexpr VkImageLayout G = VK_IMAGE_LAYOUT_GENERAL, R = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + // the inputs as sampled images for DLSS; the output (GENERAL) waits for whatever used it last + barriers(cmd, {barrier(color, VK_ACCESS_2_MEMORY_WRITE_BIT, VK_ACCESS_2_SHADER_READ_BIT, G, R), + barrier(depth, VK_ACCESS_2_MEMORY_WRITE_BIT, VK_ACCESS_2_SHADER_READ_BIT, G, R), + barrier(motion, VK_ACCESS_2_MEMORY_WRITE_BIT, VK_ACCESS_2_SHADER_READ_BIT, G, R), + barrier(output, any, dlss_out, G, G)}); + + // DLSS-SR reads only the jitter, motion and depth conventions; the camera fields are frame generation's + const float rw = (float)color.width, rh = (float)color.height; + sl::Constants c{}; + c.cameraViewToClip = c.clipToCameraView = c.clipToLensClip = c.clipToPrevClip = c.prevClipToClip = identity(); + c.jitterOffset = {0.0f, 0.0f}; + c.mvecScale = {1.0f / rw, 1.0f / rh}; // (motion in render pixels; Streamline wants [-1,1] screen units) + c.cameraPinholeOffset = {0.0f, 0.0f}; + c.cameraPos = {0.0f, 0.0f, 0.0f}; + c.cameraUp = {0.0f, 1.0f, 0.0f}; + c.cameraRight = {1.0f, 0.0f, 0.0f}; + c.cameraFwd = {0.0f, 0.0f, 1.0f}; + c.cameraNear = 0.1f, c.cameraFar = 1000.0f, c.cameraFOV = 1.0f, c.cameraAspectRatio = rw / rh; + c.depthInverted = sl::Boolean::eFalse; + c.cameraMotionIncluded = sl::Boolean::eTrue; + c.motionVectors3D = sl::Boolean::eFalse; + c.reset = reset ? sl::Boolean::eTrue : sl::Boolean::eFalse; + c.motionVectorsJittered = sl::Boolean::eFalse; + if ((r = st.set_constants(c, *frame, viewport)) != sl::Result::eOk) { + stage = "slSetConstants"; + } else { + sl::Resource rc = resource(color, R, VK_IMAGE_USAGE_SAMPLED_BIT), rd = resource(depth, R, VK_IMAGE_USAGE_SAMPLED_BIT), + rm = resource(motion, R, VK_IMAGE_USAGE_SAMPLED_BIT), ro = resource(output, G, out_usage); + const sl::Extent render_area{0, 0, color.width, color.height}, output_area{0, 0, output.width, output.height}; + // local tags: everything stays put until the evaluation is recorded + sl::ResourceTag tc{&rc, sl::kBufferTypeScalingInputColor, sl::ResourceLifecycle::eValidUntilEvaluate, &render_area}, + td{&rd, sl::kBufferTypeDepth, sl::ResourceLifecycle::eValidUntilEvaluate, &render_area}, + tm{&rm, sl::kBufferTypeMotionVectors, sl::ResourceLifecycle::eValidUntilEvaluate, &render_area}, + to{&ro, sl::kBufferTypeScalingOutputColor, sl::ResourceLifecycle::eValidUntilEvaluate, &output_area}; + const sl::BaseStructure* inputs[] = {&viewport, &tc, &td, &tm, &to}; + if ((r = st.evaluate_feature(sl::kFeatureDLSS, *frame, inputs, (uint32_t)std::size(inputs), + reinterpret_cast(cmd))) != sl::Result::eOk) + stage = "slEvaluateFeature"; + } + // back to GENERAL, the output written (also when the evaluation failed: the caller's layouts hold) + barriers(cmd, {barrier(color, VK_ACCESS_2_SHADER_READ_BIT, any, R, G), barrier(depth, VK_ACCESS_2_SHADER_READ_BIT, any, R, G), + barrier(motion, VK_ACCESS_2_SHADER_READ_BIT, any, R, G), barrier(output, dlss_out, any, G, G)}); + } + if (stage) { + st.failed = true; + st.reason = "DLSS evaluation failed"; + logf("vk: dlss: %s failed (result %d): off from now on", stage, (int)r); + return false; + } + return true; +} + +} // namespace mkwvk + +#else // (Streamline is Windows only) + +namespace mkwvk { +bool dlss_start() { return false; } +const std::vector& dlss_instance_exts() { static const std::vector none; return none; } +const std::vector& dlss_device_exts() { static const std::vector none; return none; } +void dlss_attach(VkInstance, VkPhysicalDevice, VkDevice, uint32_t) {} +bool dlss_available() { return false; } +void dlss_render_size(int, uint32_t ow, uint32_t oh, uint32_t& w, uint32_t& h) { w = ow, h = oh; } +const char* dlss_reason() { return "Windows only"; } +void dlss_stop() {} +bool dlss_evaluate(VkCommandBuffer, const DlssImage&, const DlssImage&, const DlssImage&, const DlssImage&, bool, uint32_t) { + return false; +} +} // namespace mkwvk + +#endif diff --git a/gpu/vk/vk_dlss.h b/gpu/vk/vk_dlss.h new file mode 100644 index 000000000..8993fdf23 --- /dev/null +++ b/gpu/vk/vk_dlss.h @@ -0,0 +1,42 @@ +// NVIDIA DLSS super resolution through NVIDIA Streamline (vk_dlss.cpp), manual hooking. Only Streamline's MIT headers are +// built in (third_party/streamline); sl.interposer.dll and NVIDIA's DLSS are loaded from the user's PC at run time and none +// ship with Hookshot. Ported from Lichii (Eden lineage; Duck912's Eglantine work), GPL-3.0-or-later. +#pragma once + +#include +#include + +#include "vk_loader.h" + +namespace mkwvk { + +/// At start, before create_instance: sl.interposer.dll from RX_DLSS_DIR, else \streamline\ (signatures checked; +/// the NVIDIA app's newest DLSS when newer than the nvngx_dlss.dll there, or there is none), slInit with manual hooking. +/// True when started +bool dlss_start(); +const std::vector& dlss_instance_exts(); // (empty unless started) +const std::vector& dlss_device_exts(); // (empty unless started) +/// After vkCreateDevice + load_device: the device to Streamline, and the six swapchain/present/wait functions routed to +/// its proxies (RX_DLSS_NO_HOOKS=1: not). On failure Streamline stops and DLSS stays unavailable (dlss_reason) +void dlss_attach(VkInstance instance, VkPhysicalDevice physical, VkDevice device, uint32_t queue_family); +bool dlss_available(); // (started, attached, no evaluation failed) +/// The render size for the menu's DLSS mode (0 Ultra Performance, 1 Performance, 2 Balanced, 3 Quality, 4 DLAA) at an output of +/// ow x oh: slDLSSGetOptimalSettings's, else NVIDIA's standard ratios (1/3, 1/2, 0.58, 2/3, 1) +void dlss_render_size(int mode, uint32_t ow, uint32_t oh, uint32_t& w, uint32_t& h); +const char* dlss_reason(); // (why not, short: the menu and the log) +void dlss_stop(); // (before the device goes; safe when never started) + +struct DlssImage { + VkImage image; + VkImageView view; + VkFormat format; + uint32_t width, height; + VkImageAspectFlags aspect; +}; +/// Records one DLSS evaluation on cmd: color, depth and motion at the render size, output at the output size (STORAGE | +/// SAMPLED | TRANSFER_SRC | TRANSFER_DST, the caller's). All in GENERAL before and after. False when Streamline failed (then +/// never again: dlss_available() is false from then on) +bool dlss_evaluate(VkCommandBuffer cmd, const DlssImage& color, const DlssImage& depth, const DlssImage& motion, + const DlssImage& output, bool reset, uint32_t frame_index); + +} // namespace mkwvk diff --git a/gpu/vk/vk_draw.cpp b/gpu/vk/vk_draw.cpp index dbf192774..0a702f763 100644 --- a/gpu/vk/vk_draw.cpp +++ b/gpu/vk/vk_draw.cpp @@ -7,6 +7,8 @@ // // Pipelines persist in a VkPipelineCache next to the executable (mkw_vk_pipelines.bin). #include +#include +#include #include #include #include @@ -40,6 +42,12 @@ #include "shaders/clear_vert_spv.h" #include "shaders/taau_upscale_comp_spv.h" #include "shaders/movie_upscale_comp_spv.h" +#include "shaders/dlss_motion_comp_spv.h" +#include "shaders/dlss_color_comp_spv.h" +#include "shaders/dlss_output_comp_spv.h" +#include "shaders/dlss_debug_comp_spv.h" +#include "vk_dlss.h" +#include "vk_menu.h" #include "shader_recompiler/backend/spirv/mma_layout.h" #include "vk_work.h" // (after the others: counts the commands that do GPU work, for full_barrier) @@ -4453,6 +4461,8 @@ void bind_index(VkCommandBuffer cmd, VkBuffer buffer, VkDeviceSize offset, VkInd vkCmdBindIndexBuffer(cmd, buffer, offset, type); last_ib = {b, (uint64_t)offset, (uint32_t)type, true}; } +void dlss_note_camera(const NvnState& s, const Targets& at); // (below, with the DLSS frame code) +bool dlss_dispatch(VkCommandBuffer cmd, const NvnState& s, const Program& p); void draw(VkCommandBuffer cmd, NvnState& s, const DrawArgs& d) { PROF(PROF_DRAW); @@ -4467,6 +4477,7 @@ void draw(VkCommandBuffer cmd, NvnState& s, const DrawArgs& d) { } const Targets at = bare_targets(s, targets(s)); if (!at.width || !at.height) SKIP_HERE(); + dlss_note_camera(s, at); // (hookshot: the scene camera, for DLSS's motion) uint8_t types[8]; for (int i = 0; i < 8; i++) { const VkFormat f = i < at.n ? at.color_format[i] : VK_FORMAT_UNDEFINED; @@ -5410,6 +5421,362 @@ bool taau_stand_in(VkCommandBuffer cmd, const NvnState& s, const Program& p) { return typed_upscale(cmd, dw.imgs[0].imageView, dw.imgs[ntex].imageView, out, level, p.key, keys, true); } +// ---- (hookshot) NVIDIA DLSS in place of OoT's gameplay upscale (vk_dlss.cpp has Streamline; this, the frame's part) ---- +// Ported from Lichii (Eden lineage; Duck912's Eglantine work), GPL-3.0-or-later: vk_ocarina_camera_motion.cpp, TryOcarinaDlss. +// The game's chain after its tonemap draw (B10G11R11 at the render size: twelfths of 2048x1152, the Resolution row's or, with DLSS +// on, the DLSS mode's; 1536x864 at 75%), seen in +// frame dumps: 26fe0c70ab9fc547 (a quarter-size pass over the tonemapped scene) -> 685adb41edc19de7 -> 6637ac1d052d22d4 (the +// network's input: the scene square-root encoded, RGB9E5, over the scene's colour target) -> fd029a317a9a4b94 (the network: +// a 4/3 upscale with its sharpening, B10G11R11 at 2048x1152, under the HUD; then the HUD, and a plain copy into the window +// texture, whose 2048x1152 crop the present scales: no FSR, no other upscale or sharpening). What the first three write feeds only +// the next (their images alias depth targets the next frame draws first). On a DLSS frame none of the four runs: at the first, the +// tonemapped scene becomes DLSS's colour; at the last, DLSS (with depth and the camera's motion) writes the network's target. +// The fallback, with its reason logged: the game's whole chain (the decision is made at its first pass), or, when DLSS fails after +// that, a linear upscale for the frame. +namespace { +constexpr uint64_t kChainFirst = 0x26fe0c70ab9fc547ull, kChainMid1 = 0x685adb41edc19de7ull, kChainMid2 = 0x6637ac1d052d22d4ull, + kChainNet = 0xfd029a317a9a4b94ull; +// (the network has one variant per input size, all to the same 2048x1152 target; the game draws at twelfths of it: 2048x1152 +// 9dc98871eb7fc101, 1536x864 fd029a317a9a4b94, 1366x768 6676619641320ba7, 1195x672 f10782f9e58b6a7c, 1024x576 +// 72ba090c70fe2614, 683x384 0775215f8da720e6 (frame dumps at each scale). Any other dispatch right after the three prepasses +// that writes a B10G11R11 target of at least the render size is taken as the network too: the sizes not seen) +bool chain_net(uint64_t k) { + return k == kChainNet || k == 0x0775215f8da720e6ull || k == 0xf10782f9e58b6a7cull || k == 0x9dc98871eb7fc101ull || + k == 0x72ba090c70fe2614ull || k == 0x6676619641320ba7ull; +} +using Mat = std::array; +struct DlssCamera { + uint64_t frame = ~0ull; + Texture* depth = nullptr; + VkImageView depth_view = VK_NULL_HANDLE; + uint32_t w = 0, h = 0; + Mat cur{}, prev{}; +}; +struct DlssImg { + VkImage image = VK_NULL_HANDLE; + VmaAllocation mem = nullptr; + VkImageView view = VK_NULL_HANDLE; + uint32_t w = 0, h = 0; +}; +struct DlssState { + DlssCamera cam, used; // (the frame's camera, and the one the armed frame took) + bool armed = false; // (the chain's first pass was left out: its last must be replaced) + uint64_t last_frame = ~0ull; + Mat last_vp{}; + uint32_t evals = 0; + DlssImg color, motion, out, prev; // (prev: last frame's colour, RX_DLSS_DEBUG 3/4 only) + VkPipeline motion_pipe = VK_NULL_HANDLE, color_pipe = VK_NULL_HANDLE, output_pipe = VK_NULL_HANDLE, debug_pipe = VK_NULL_HANDLE; + VkPipelineLayout layout = VK_NULL_HANDLE, debug_layout = VK_NULL_HANDLE; + uint32_t resets = 0, cuts = 0; // (in the last 600 evaluations: history dropped, and of those the camera cuts) + VkSampler nearest = VK_NULL_HANDLE, linear = VK_NULL_HANDLE; + const char* reason = nullptr; // (the last fallback's) + uint64_t repeats = 0; + bool ready = false, made = false; +}; +DlssState ds; // ponytail: one set of images, no lock: the replay records one frame at a time (RX_VK_PARALLEL would need ParLock here) + +bool dlss_on() { return opts.dlss && dlss_available(); } +// RX_DLSS_DEBUG=1..4 (dlss_debug.comp): motion, depth, or the reprojection error with and without the motion, drawn in place of +// DLSS's output (DLSS still runs) +int dlss_debug() { static const int v = getenv("RX_DLSS_DEBUG") ? atoi(getenv("RX_DLSS_DEBUG")) : 0; return v; } // (the menu's Off takes effect at once; On needs the start's Streamline) + +/// Logged when the reason changes and every 600th repeat: the game's chain draws this frame +void dlss_fallback(const char* why) { + if (why != ds.reason || ++ds.repeats % 600 == 0) + logf("vk: dlss: the game's upscale draws frame %llu (%s)", (unsigned long long)texture_frame_no(), why); + if (why != ds.reason) ds.reason = why, ds.repeats = 0; +} + +/// (Lichii's ClipToPreviousClip) depth reprojected from the current clip space into the previous camera's +bool clip_to_previous(const Mat& current, const Mat& previous, Mat& out) { + double rows[4][8]{}; + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) rows[i][j] = current[i * 4 + j]; + rows[i][i + 4] = 1.0; + } + for (int col = 0; col < 4; col++) { + int pivot = col; + for (int r = col + 1; r < 4; r++) + if (std::abs(rows[r][col]) > std::abs(rows[pivot][col])) pivot = r; + std::swap(rows[col], rows[pivot]); + const double d = rows[col][col]; + if (!std::isfinite(d) || std::abs(d) < 1e-10) return false; + for (double& v : rows[col]) v /= d; + for (int r = 0; r < 4; r++) + if (r != col) { + const double k = rows[r][col]; + for (int i = 0; i < 8; i++) rows[r][i] -= k * rows[col][i]; + } + } + for (int r = 0; r < 4; r++) + for (int c = 0; c < 4; c++) { + double v = 0; + for (int i = 0; i < 4; i++) v += previous[r * 4 + i] * rows[i][c + 4]; + out[r * 4 + c] = (float)v; + if (!std::isfinite(out[r * 4 + c])) return false; + } + return true; +} + +bool dlss_image(DlssImg& im, uint32_t w, uint32_t h, VkFormat format, VkImageUsageFlags usage, VkCommandBuffer cmd) { + if (im.image && im.w == w && im.h == h) return true; + im = {}; // (the one before is kept: work in flight may still use it, and the sizes seldom change) + VkImageCreateInfo ic{VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO}; + ic.imageType = VK_IMAGE_TYPE_2D, ic.format = format, ic.extent = {w, h, 1}, ic.mipLevels = 1, ic.arrayLayers = 1; + ic.samples = VK_SAMPLE_COUNT_1_BIT, ic.tiling = VK_IMAGE_TILING_OPTIMAL, ic.usage = usage; + if (!create_image(ic, im.image, im.mem)) return im = {}, false; + VkImageViewCreateInfo vc{VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO}; + vc.image = im.image, vc.viewType = VK_IMAGE_VIEW_TYPE_2D, vc.format = format, vc.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}; + if (vkCreateImageView(dev.device, &vc, nullptr, &im.view) != VK_SUCCESS) return im = {}, false; + VkImageMemoryBarrier2 ib{VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2}; // (UNDEFINED -> GENERAL, once) + ib.srcStageMask = VK_PIPELINE_STAGE_2_NONE, ib.dstStageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT; + ib.dstAccessMask = VK_ACCESS_2_MEMORY_READ_BIT | VK_ACCESS_2_MEMORY_WRITE_BIT; + ib.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED, ib.newLayout = VK_IMAGE_LAYOUT_GENERAL; + ib.srcQueueFamilyIndex = ib.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + ib.image = im.image, ib.subresourceRange = vc.subresourceRange; + VkDependencyInfo di{VK_STRUCTURE_TYPE_DEPENDENCY_INFO}; + di.imageMemoryBarrierCount = 1, di.pImageMemoryBarriers = &ib; + vkCmdPipelineBarrier2(cmd, &di); + im.w = w, im.h = h; + return true; +} + +/// The three passes' pipelines (binding 0 a sampled image, 1 a storage image, 64 bytes pushed), once +bool dlss_pipelines() { + if (ds.made) return ds.ready; + ds.made = true; + if (!dev.push_descriptor || !vkCmdPushDescriptorSetKHR) return false; + VkDescriptorSetLayoutBinding b[2] = {{0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_COMPUTE_BIT, nullptr}, + {1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_COMPUTE_BIT, nullptr}}; + VkDescriptorSetLayoutCreateInfo li{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO}; + li.flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR, li.bindingCount = 2, li.pBindings = b; + VkDescriptorSetLayout set{}; + if (vkCreateDescriptorSetLayout(dev.device, &li, nullptr, &set) != VK_SUCCESS) return false; + const VkPushConstantRange pr{VK_SHADER_STAGE_COMPUTE_BIT, 0, 64}; + VkPipelineLayoutCreateInfo pi{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; + pi.setLayoutCount = 1, pi.pSetLayouts = &set, pi.pushConstantRangeCount = 1, pi.pPushConstantRanges = ≺ + if (vkCreatePipelineLayout(dev.device, &pi, nullptr, &ds.layout) != VK_SUCCESS) return false; + const auto make = [](const uint32_t* code, size_t bytes) { + VkShaderModuleCreateInfo mi{VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO}; + mi.codeSize = bytes, mi.pCode = code; + VkShaderModule m{}; + if (vkCreateShaderModule(dev.device, &mi, nullptr, &m) != VK_SUCCESS) return VkPipeline(VK_NULL_HANDLE); + VkComputePipelineCreateInfo ci{VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO}; + ci.stage = {VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, nullptr, 0, VK_SHADER_STAGE_COMPUTE_BIT, m, "main", nullptr}; + ci.layout = ds.layout; + VkPipeline pl = VK_NULL_HANDLE; + if (vkCreateComputePipelines(dev.device, VK_NULL_HANDLE, 1, &ci, nullptr, &pl) != VK_SUCCESS) pl = VK_NULL_HANDLE; + vkDestroyShaderModule(dev.device, m, nullptr); + return pl; + }; + ds.motion_pipe = make(DLSS_MOTION_COMP_SPV, sizeof DLSS_MOTION_COMP_SPV); + ds.color_pipe = make(DLSS_COLOR_COMP_SPV, sizeof DLSS_COLOR_COMP_SPV); + ds.output_pipe = make(DLSS_OUTPUT_COMP_SPV, sizeof DLSS_OUTPUT_COMP_SPV); + VkSamplerCreateInfo si{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; + si.addressModeU = si.addressModeV = si.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + vkCreateSampler(dev.device, &si, nullptr, &ds.nearest); + si.magFilter = si.minFilter = VK_FILTER_LINEAR; + vkCreateSampler(dev.device, &si, nullptr, &ds.linear); + ds.ready = ds.motion_pipe && ds.color_pipe && ds.output_pipe && ds.nearest && ds.linear; + if (ds.ready && dlss_debug()) { // (four sampled images and the target) + VkDescriptorSetLayoutBinding db[5]; + for (uint32_t i = 0; i < 5; i++) + db[i] = {i, i < 4 ? VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER : VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_COMPUTE_BIT, nullptr}; + li.bindingCount = 5, li.pBindings = db; + VkDescriptorSetLayout dset{}; + pi.pSetLayouts = &dset; + if (vkCreateDescriptorSetLayout(dev.device, &li, nullptr, &dset) == VK_SUCCESS && + vkCreatePipelineLayout(dev.device, &pi, nullptr, &ds.debug_layout) == VK_SUCCESS) { + std::swap(ds.layout, ds.debug_layout); + ds.debug_pipe = make(DLSS_DEBUG_COMP_SPV, sizeof DLSS_DEBUG_COMP_SPV); + std::swap(ds.layout, ds.debug_layout); + } + logf("vk: dlss: RX_DLSS_DEBUG=%d: %s", dlss_debug(), ds.debug_pipe ? "its view replaces DLSS's output" : "its pipeline was not made"); + } + if (!ds.ready) logf("vk: dlss: its passes' pipelines were not made"); + return ds.ready; +} + +void dlss_pass(VkCommandBuffer cmd, VkPipeline pipe, VkSampler sampler, VkImageView in, VkImageView out, uint32_t w, uint32_t h, + const void* push) { + const VkDescriptorImageInfo ii{sampler, in, VK_IMAGE_LAYOUT_GENERAL}, oi{VK_NULL_HANDLE, out, VK_IMAGE_LAYOUT_GENERAL}; + VkWriteDescriptorSet wr[2]{{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET}, {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET}}; + wr[0].dstBinding = 0, wr[0].descriptorCount = 1, wr[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, wr[0].pImageInfo = ⅈ + wr[1].dstBinding = 1, wr[1].descriptorCount = 1, wr[1].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, wr[1].pImageInfo = &oi; + vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); + vkCmdPushDescriptorSetKHR(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, ds.layout, 0, 2, wr); + if (push) vkCmdPushConstants(cmd, ds.layout, VK_SHADER_STAGE_COMPUTE_BIT, 0, 64, push); + vkCmdDispatch(cmd, (w + 7) / 8, (h + 7) / 8, 1); +} +/// RX_DLSS_DEBUG: its view into the network's target (out), then this frame's colour kept as the next one's previous +bool dlss_debug_pass(VkCommandBuffer cmd, VkImageView out, uint32_t w, uint32_t h, const DlssCamera& cam) { + if (!ds.debug_pipe || !dlss_image(ds.prev, ds.color.w, ds.color.h, VK_FORMAT_R16G16B16A16_SFLOAT, + VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, cmd)) + return false; + VkDescriptorImageInfo ii[5] = {{ds.nearest, ds.color.view, VK_IMAGE_LAYOUT_GENERAL}, {ds.nearest, ds.motion.view, VK_IMAGE_LAYOUT_GENERAL}, + {ds.nearest, cam.depth_view, VK_IMAGE_LAYOUT_GENERAL}, {ds.linear, ds.prev.view, VK_IMAGE_LAYOUT_GENERAL}, + {VK_NULL_HANDLE, out, VK_IMAGE_LAYOUT_GENERAL}}; + VkWriteDescriptorSet wr[5]; + for (uint32_t i = 0; i < 5; i++) { + wr[i] = {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET}; + wr[i].dstBinding = i, wr[i].descriptorCount = 1, wr[i].pImageInfo = &ii[i]; + wr[i].descriptorType = i < 4 ? VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER : VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; + } + const int32_t push[16] = {dlss_debug()}; + vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, ds.debug_pipe); + vkCmdPushDescriptorSetKHR(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, ds.debug_layout, 0, 5, wr); + vkCmdPushConstants(cmd, ds.debug_layout, VK_SHADER_STAGE_COMPUTE_BIT, 0, 64, push); + vkCmdDispatch(cmd, (w + 7) / 8, (h + 7) / 8, 1); + std::swap(ds.color, ds.prev); // (the next frame's colour goes into the other image) + return true; +} +} // namespace + +/// From draw(): the scene camera (Lichii's TrackOcarinaCamera): vertex constant buffer 3 of a draw into a B10G11R11 target of at +/// least 640x360 with D32 depth, whose +0x120/+0x124 are the target's size and +0xa8/+0xac -1 and 0; current view-projection at +/// +0x30, the previous frame's at +0x180. The largest such target of the frame +void dlss_note_camera(const NvnState& s, const Targets& at) { + if (!dlss_on() || at.n < 1 || !at.color[0] || at.color_format[0] != VK_FORMAT_B10G11R11_UFLOAT_PACK32 || at.width < 640 || + at.height < 360 || !at.depth || at.depth_format != VK_FORMAT_D32_SFLOAT || at.samples != VK_SAMPLE_COUNT_1_BIT || + at.depth_level || at.depth_layer || !at.depth_view) + return; + const uint64_t now = texture_frame_no(); + if (ds.cam.frame == now && (uint64_t)at.width * at.height <= (uint64_t)ds.cam.w * ds.cam.h) return; + const nvn_p_bind_buf& u = s.ubo[0][0]; // (Maxwell's cbuf 3 of the vertex stage) + float c[0x230 / 4]; + if (!u.addr || (u.size && u.size < sizeof c) || !ub_read(u.addr, c, sizeof c)) return; + if (c[0x120 / 4] != (float)at.width || c[0x124 / 4] != (float)at.height || c[0xa8 / 4] != -1.0f || c[0xac / 4] != 0.0f) return; + // (a sampled view: at.depth_view is the attachment's, made with only the depth-attachment usage, and read through it the + // depth came back 0 everywhere: every pixel at the near plane, so any camera move gave huge motion, the ghosting) + const VkImageView depth = texture_view(at.depth, s.rt.depth, s.rt.has_dview ? &s.rt.dview : nullptr, VK_IMAGE_VIEW_TYPE_2D, ViewUse::Sample); + if (!depth) return; + ds.cam.frame = now, ds.cam.depth = at.depth, ds.cam.depth_view = depth, ds.cam.w = at.width, ds.cam.h = at.height; + std::copy_n(c + 0x30 / 4, 16, ds.cam.cur.begin()); + std::copy_n(c + 0x180 / 4, 16, ds.cam.prev.begin()); +} + +/// DLSS's colour for this frame into ds.color (encode: square-root encode it, the tonemapped scene; else the network's own input, +/// encoded already), with the checks that decide the frame; ds.used the camera it goes with. False: the game's passes run +bool dlss_take_colour(VkCommandBuffer cmd, const Program& p, bool encode) { + if (ds.cam.frame != texture_frame_no()) return dlss_fallback("no scene camera this frame"), false; + const Texture* src = draw_sampled.empty() ? nullptr : draw_sampled[0]; + if (p.stages.empty() || p.stages[0].info.texture_descriptors.empty() || dw.imgs.empty() || !dw.imgs[0].imageView || !src || + src->format != VK_FORMAT_B10G11R11_UFLOAT_PACK32 || src->samples != VK_SAMPLE_COUNT_1_BIT) + return dlss_fallback("unexpected bindings"), false; + if (src->width != ds.cam.w || src->height != ds.cam.h) return dlss_fallback("the scene colour is not the camera's size"), false; + if (!ds.cam.depth || !ds.cam.depth->image || ds.cam.depth->width != ds.cam.w || ds.cam.depth->height != ds.cam.h) + return dlss_fallback("no scene depth at the camera's size"), false; + if (!dlss_pipelines()) return dlss_fallback("no pipelines"), false; + if (!dlss_image(ds.color, ds.cam.w, ds.cam.h, VK_FORMAT_R16G16B16A16_SFLOAT, VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, cmd) || + !dlss_image(ds.motion, ds.cam.w, ds.cam.h, VK_FORMAT_R16G16_SFLOAT, VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, cmd)) + return dlss_fallback("images not made"), false; + int32_t push[16] = {encode ? 1 : 0}; + gprof_begin(cmd); + full_barrier(cmd); + dlss_pass(cmd, ds.color_pipe, ds.nearest, dw.imgs[0].imageView, ds.color.view, ds.cam.w, ds.cam.h, push); + full_barrier(cmd); + gprof_end(cmd, "dlss: colour"); + descriptors_disturbed(); + ds.used = ds.cam; + return true; +} + +/// From dispatch(), the program's descriptors built: true when the dispatch is replaced (the network on a DLSS frame; with +/// unless RX_DLSS_KEEP_PREPASSES=1, the chain's first three passes too) +bool dlss_dispatch(VkCommandBuffer cmd, const NvnState& s, const Program& p) { + const bool pre = p.key == kChainFirst || p.key == kChainMid1 || p.key == kChainMid2; + const bool known = chain_net(p.key); + if ((!pre && !known && !ds.armed) || !dlss_on()) return false; + // (the first three prepare the network's input and feed nothing else: left out, DLSS takes the tonemapped scene, square-root + // encoded here as they do. The same picture as with them (means within 1% in the A/B, docs in the DLSS report). + // RX_DLSS_KEEP_PREPASSES=1: they run and DLSS takes the network's input, as Lichii does) + static const bool skip_pre = !(getenv("RX_DLSS_KEEP_PREPASSES") && atoi(getenv("RX_DLSS_KEEP_PREPASSES")) != 0); + if (pre) { + if (!skip_pre) return false; + if (p.key == kChainFirst) ds.armed = dlss_take_colour(cmd, p, true); + return ds.armed; + } + if (!known && !skip_pre) return false; // (unknown networks by their place only: with the prepasses left out) + const bool armed = ds.armed; // (the network's input was never made: whatever happens, the network cannot run) + if (skip_pre ? !armed : !dlss_take_colour(cmd, p, false)) return false; + const uint64_t now = texture_frame_no(); + // the network's target, as taau_stand_in finds it + const Stage& st = p.stages[0]; + size_t ntex = 0; + for (const auto& d : st.info.texture_descriptors) ntex += d.count; + Texture* out = nullptr; + uint32_t level = 0; + const uint32_t handle = st.info.image_descriptors.empty() ? 0 : handle_of(s, st, st.info.image_descriptors[0], 0); + if (handle) texture_view_of(handle, VK_IMAGE_VIEW_TYPE_2D, ViewUse::Storage, image_format(st.info.image_descriptors[0].format), &out, &level); + if (!out || level || dw.imgs.size() <= ntex || !dw.imgs[ntex].imageView || out->format != VK_FORMAT_B10G11R11_UFLOAT_PACK32 || + out->width < ds.used.w || out->height < ds.used.h) { + if (!known) return false; // (not the network after all: it runs, the chain stays armed) + ds.armed = false; + if (!armed) return dlss_fallback("the network's target is not the expected B10G11R11 image"), false; + logf("vk: dlss: frame %llu: the network's target is not the expected B10G11R11 image: left as it was", (unsigned long long)now); + return true; + } + ds.armed = false; + if (!known) { + static uint64_t logged; + if (logged != p.key) logged = p.key, logf("vk: dlss: network %016llx (not a known one) taken by its place in the chain", (unsigned long long)p.key); + } + const uint32_t ow = out->width, oh = out->height, rw = ds.used.w, rh = ds.used.h; + gprof_begin(cmd); + full_barrier(cmd); + bool ok = dlss_image(ds.out, ow, oh, VK_FORMAT_R16G16B16A16_SFLOAT, + VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, cmd); + Mat clip{}; + const bool have_motion = clip_to_previous(ds.used.cur, ds.used.prev, clip); + if (ok && have_motion) { + dlss_pass(cmd, ds.motion_pipe, ds.nearest, ds.used.depth_view, ds.motion.view, rw, rh, clip.data()); + full_barrier(cmd); + bool same_camera = true; // (a camera cut: the previous matrix is not last frame's current one) + for (int i = 0; i < 16; i++) same_camera = same_camera && std::abs(ds.used.prev[i] - ds.last_vp[i]) < 0.001f; + const bool reset = ds.last_frame == ~0ull || now != ds.last_frame + 1 || !same_camera; + ds.resets += reset, ds.cuts += reset && !same_camera; + if (dlss_debug() && ds.evals >= 1500 && ds.evals < 1512) { // (the camera of 12 frames: a jitter would move [0][3]/[1][3] by ~1/w) + const Mat& m = ds.used.cur; + logf("vk: dlss: debug: frame %llu camera %.6g %.6g %.6g %.6g | %.6g %.6g %.6g %.6g | %.6g %.6g %.6g %.6g | %.6g %.6g %.6g %.6g", + (unsigned long long)now, m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8], m[9], m[10], m[11], m[12], m[13], m[14], m[15]); + } + if (ds.evals % 600 == 599) { // (a cut every frame would mean +0x180 is not last frame's camera: no history, no ghosting) + logf("vk: dlss: the last 600 frames: %u history resets, %u of them camera cuts", ds.resets, ds.cuts); + ds.resets = ds.cuts = 0; + } + const DlssImage color{ds.color.image, ds.color.view, VK_FORMAT_R16G16B16A16_SFLOAT, rw, rh, VK_IMAGE_ASPECT_COLOR_BIT}; + const DlssImage depth{ds.used.depth->image, ds.used.depth_view, VK_FORMAT_D32_SFLOAT, rw, rh, VK_IMAGE_ASPECT_DEPTH_BIT}; + const DlssImage motion{ds.motion.image, ds.motion.view, VK_FORMAT_R16G16_SFLOAT, rw, rh, VK_IMAGE_ASPECT_COLOR_BIT}; + const DlssImage output{ds.out.image, ds.out.view, VK_FORMAT_R16G16B16A16_SFLOAT, ow, oh, VK_IMAGE_ASPECT_COLOR_BIT}; + ok = dlss_evaluate(cmd, color, depth, motion, output, reset, ds.evals++); + if (ok) { + if (ds.reason || ds.last_frame == ~0ull) + logf("vk: dlss: DLSS draws the upscale from frame %llu (%ux%u -> %ux%u)", (unsigned long long)now, rw, rh, ow, oh); + ds.reason = nullptr; + ds.last_frame = now, ds.last_vp = ds.used.cur; + } + } + full_barrier(cmd); + if (!ok && !armed) { // (the network's input is there: the game's network draws this frame) + dlss_fallback(have_motion ? "DLSS declined the frame" : "the camera matrix is not invertible"); + gprof_end(cmd, "dlss: declined"); + descriptors_disturbed(); + return false; + } + if (ok && dlss_debug() && dlss_debug_pass(cmd, dw.imgs[ntex].imageView, ow, oh, ds.used)) { + } else if (ok) { + dlss_pass(cmd, ds.output_pipe, ds.nearest, ds.out.view, dw.imgs[ntex].imageView, ow, oh, nullptr); // (squared back) + } else { // (DLSS failed with the first passes left out: a linear upscale of the square-rooted scene this frame) + dlss_fallback(have_motion ? "DLSS declined the frame: a linear upscale" : "the camera matrix is not invertible: a linear upscale"); + dlss_pass(cmd, ds.output_pipe, ds.linear, ds.color.view, dw.imgs[ntex].imageView, ow, oh, nullptr); + } + full_barrier(cmd); + gprof_end(cmd, ok ? "dlss: motion, DLSS, output" : "dlss: fallback upscale"); + texture_written(out); + descriptors_disturbed(); + return true; +} + bool precompile_wanted() { #if defined(HOOKSHOT_RELEASE) bool on = true; @@ -5933,17 +6300,25 @@ void dispatch(VkCommandBuffer cmd, NvnState& s, uint32_t x, uint32_t y, uint32_t work_since_barrier = true; if (!p.stages.empty() && p.stages[0].info.uses_cooperative_matrix) { // (the game's networks, once each: what they read and write) static std::mutex mu; - static std::unordered_map seen; + static std::unordered_map seen; // (key -> the sizes last logged: again when they change) + static int lines = 0; std::lock_guard lk(mu); - if (seen[p.key]++ == 0) { + uint64_t sig = 0; + for (const Texture* t : draw_sampled) + if (t) sig = sig * 1000003u + ((uint64_t)t->width << 32 | t->height); + auto it = seen.find(p.key); + if ((it == seen.end() || it->second != sig) && lines++ < 200) { + seen[p.key] = sig; char line[900]; - int n = snprintf(line, sizeof line, "vk: network %016llx: dispatch %ux%ux%u, %zu textures %zu images:", (unsigned long long)p.key, x, y, z, - p.stages[0].info.texture_descriptors.size(), p.stages[0].info.image_descriptors.size()); + int n = snprintf(line, sizeof line, "vk: network %016llx: dispatch %ux%ux%u, %zu textures %zu images (frame %llu):", (unsigned long long)p.key, x, y, z, + p.stages[0].info.texture_descriptors.size(), p.stages[0].info.image_descriptors.size(), + (unsigned long long)texture_frame_no()); for (const Texture* t : draw_sampled) if (t && n < 860) n += snprintf(line + n, sizeof line - n, " %ux%ux%u/%u", t->width, t->height, t->depth, (unsigned)t->format); logf("%s", line); } } + if (dlss_dispatch(cmd, s, p)) return void(st_dispatches++); // (hookshot: NVIDIA DLSS in place of the game's upscale chain) if (taau_stand_in(cmd, s, p)) return void(st_dispatches++); if (!p.compute_pipeline) SKIP_HERE(); dump_ssbos(cmd, p, "before"); diff --git a/gpu/vk/vk_main.cpp b/gpu/vk/vk_main.cpp index 908e29f63..9aba76b38 100644 --- a/gpu/vk/vk_main.cpp +++ b/gpu/vk/vk_main.cpp @@ -4,6 +4,7 @@ #include "vk_paths.h" #include "vk_loader.h" +#include #include #include #include @@ -15,6 +16,7 @@ #include "vk_api.h" #include "vk_draw.h" #include "vk_internal.h" +#include "vk_dlss.h" #include "gpu_choice.h" #include "vk_menu.h" @@ -87,8 +89,16 @@ bool create_instance() { return false; } #ifdef _WIN32 - const char* exts[] = {VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_WIN32_SURFACE_EXTENSION_NAME}; - const uint32_t n_exts = 2; + std::vector exts = {VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_WIN32_SURFACE_EXTENSION_NAME}; + { // (hookshot) what NVIDIA Streamline asks for (vk_dlss.cpp), those the loader has + uint32_t n = 0; + vkEnumerateInstanceExtensionProperties(nullptr, &n, nullptr); + std::vector all(n); + vkEnumerateInstanceExtensionProperties(nullptr, &n, all.data()); + for (const char* e : dlss_instance_exts()) + if (has_extension(all, e) && std::none_of(exts.begin(), exts.end(), [&](const char* x) { return !std::strcmp(x, e); })) exts.push_back(e); + } + const uint32_t n_exts = (uint32_t)exts.size(); #else // (linux: every window system's surface the loader has, for whichever one SDL's window is on: X11 or Wayland) const char* exts[4] = {VK_KHR_SURFACE_EXTENSION_NAME}; @@ -108,7 +118,7 @@ bool create_instance() { VkInstanceCreateInfo ci{VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO}; ci.pApplicationInfo = &app; ci.enabledExtensionCount = n_exts; - ci.ppEnabledExtensionNames = exts; + ci.ppEnabledExtensionNames = &exts[0]; // RX_VK_VALIDATION=1: the Khronos validation layer (when installed) const char* layer = "VK_LAYER_KHRONOS_validation"; if (getenv("RX_VK_VALIDATION")) ci.enabledLayerCount = 1, ci.ppEnabledLayerNames = &layer; @@ -228,6 +238,8 @@ bool create_device() { optional(VK_AMD_BUFFER_MARKER_EXTENSION_NAME, dev.buffer_marker); optional(VK_EXT_DEVICE_FAULT_EXTENSION_NAME, dev.device_fault); optional(VK_KHR_COOPERATIVE_MATRIX_EXTENSION_NAME, dev.coop_matrix); + for (const char* e : dlss_device_exts()) // (hookshot: NVIDIA Streamline's, vk_dlss.cpp) + if (has_extension(exts, e) && std::none_of(want.begin(), want.end(), [&](const char* x) { return !std::strcmp(x, e); })) want.push_back(e); // the queue: one family for graphics, compute and transfer vkGetPhysicalDeviceQueueFamilyProperties(dev.physical, &n, nullptr); @@ -370,6 +382,7 @@ bool create_device() { load_device(dev.device); vkGetDeviceQueue(dev.device, dev.queue_family, 0, &dev.queue); + dlss_attach(dev.instance, dev.physical, dev.device, dev.queue_family); // (before the first swapchain: Streamline's proxies make them) if (dev.buffer_marker) buffer_markers_init(); coopmat_init(); if (dev.push_descriptor) { @@ -670,6 +683,8 @@ const MkwVkRenderer* mkwvk_init(const MkwVkHost* h) { logf("vk: vulkan-1.dll not found"); return nullptr; } + menu_init(); // (hookshot: the DLSS row decides the instance and device extensions) + if (opts.dlss) dlss_start(); if (!create_instance() || !pick_device() || !create_device()) return nullptr; logf("vk: %s, Vulkan %u.%u, driver %#x; mesh shaders %s, host memory import %s, pipeline libraries %s", dev.props.deviceName, VK_VERSION_MAJOR(dev.props.apiVersion), VK_VERSION_MINOR(dev.props.apiVersion), diff --git a/gpu/vk/vk_menu.cpp b/gpu/vk/vk_menu.cpp index 0d23898c2..b15fac10b 100644 --- a/gpu/vk/vk_menu.cpp +++ b/gpu/vk/vk_menu.cpp @@ -14,6 +14,7 @@ #include "vk_paths.h" #include "vk_menu.h" +#include "vk_dlss.h" #include "vk_work.h" // (after the others: counts the commands that do GPU work, for full_barrier) #ifndef HOOKSHOT_VERSION // (nx2/build.py gives it to this file: nx2/version.py) #define HOOKSHOT_VERSION "unknown" @@ -62,8 +63,56 @@ const char* tx_percent(int v) { snprintf(b, sizeof b, "%d%%", v); return b; } +// The game's output: the crop of its window texture that the present scales (menu_note_output): the scale sent to the game is for it +std::atomic out_w{2048}, out_h{1152}; +// The output the menu's sizes are shown for: the Output resolution row's (applied at the next start), so the rows below follow a change +// at once; the handheld profile runs the game's own (1536x864) +struct Out { + uint32_t w, h; +}; +Out shown_output() { + static const Out t[] = {{2048, 1152}, {2560, 1440}, {3840, 2160}}; + return opts.handheld ? Out{1536, 864} : t[std::min(std::max(opts.output_res, 0), 2)]; +} +constexpr int kResPercent[] = {0, 100, 75, 67, 50}; +bool dlss_sets_size() { return opts.dlss && dlss_available(); } +// The size the game draws the 3D at for a fixed scale of its output, a twelfth of it: every twelfth asked came out exact at the three +// outputs (2048x1152: 0.58 drew 1195x672, 0.6667 1366x768). So the scale the game is given is the twelfth too: 0.67 drew 2615x1471 at +// 3840x2160, not the 2560x1440 of 8/12. +int twelfths(float scale) { return std::min(std::max((int)(scale * 12.0f + 0.5f), 1), 12); } +void game_size(float scale, uint32_t& w, uint32_t& h) { + const Out o = shown_output(); + const int k = twelfths(scale); + w = (o.w * k + 11) / 12, h = o.h * k / 12; +} +// The DLSS mode's scale: NVIDIA's optimal render width for the mode over the output's +float dlss_scale(int mode, Out o) { + uint32_t w, h; + dlss_render_size(mode, o.w, o.h, w, h); + return (float)w / o.w; +} const char* tx_resolution(int v) { - static const char* t[] = {"Auto", "100%", "75%", "67%", "50%"}; + static char b[48]; + if (dlss_sets_size()) return "Set by DLSS mode"; + if (v <= 0 || v > 4) return "Auto (dynamic)"; + uint32_t w, h; + game_size(kResPercent[v] / 100.0f, w, h); + snprintf(b, sizeof b, "%d%% (%ux%u)", kResPercent[v], w, h); + return b; +} +const char* tx_dlss_mode(int v) { + static const char* names[] = {"Ultra Performance", "Performance", "Balanced", "Quality", "DLAA"}; + static char b[64]; + if ((unsigned)v > 4) v = 3; + if (!dlss_sets_size()) return snprintf(b, sizeof b, "%s (DLSS off)", names[v]), b; + uint32_t w, h; + const float s = dlss_scale(v, shown_output()); + game_size(s, w, h); + snprintf(b, sizeof b, "%s (%d%%, %ux%u)", names[v], (int)(w * 100.0 / shown_output().w + 0.5), w, h); + return b; +} +const char* tx_output_res(int v) { + static const char* t[] = {"2048x1152 (game, restart)", "2560x1440 (restart)", "3840x2160 (restart)"}; return t[v]; } const char* tx_speed(int v) { return v ? "Real time" : "Per frame"; } @@ -73,6 +122,15 @@ const char* tx_text_speed(int v) { return t[v]; } const char* tx_handheld(int v) { return v ? "On (restart)" : "Off (restart)"; } +const char* tx_dlss(int v) { + if (v && !dlss_available()) return strcmp(dlss_reason(), "not started") ? "On (no NVIDIA DLSS found)" : "On (restart)"; + return v ? "On" : "Off"; +} +const char* tx_dlss_preset(int v) { + static char b[16]; + snprintf(b, sizeof b, opts.dlss && dlss_available() ? "%c" : "%c (DLSS off)", 'J' + v); + return b; +} const char* tx_ultrawide(int v) { return v ? "Monitor's shape (restart)" : "16:9 (restart)"; } int gpu_device_at_start = 0; // (the row's value the game started with: menu_set_gpu_count) const char* tx_gpu(int v) { @@ -148,7 +206,18 @@ Row rows[] = { "Shows each frame at an even interval instead of as soon as it is ready. Less stutter, at up to one frame of delay."}, {TAB_GRAPHICS, "Resolution", &opts.resolution, 0, 4, 1, tx_resolution, "How sharp the 3D is drawn. Auto lets the game lower it when the GPU is busy. A fixed percentage stays steady: lower is " - "faster."}, + "faster. With DLSS on, the DLSS mode sets it."}, + {TAB_GRAPHICS, "Output resolution", &opts.output_res, 0, 2, 1, tx_output_res, + "The size the game draws its whole frame at, HUD included, before it is scaled to your window. The 3D is drawn at the " + "Resolution percentage of it, and DLSS scales up to it. Docked only. Applies after a restart."}, + {TAB_GRAPHICS, "DLSS", &opts.dlss, 0, 1, 1, tx_dlss, + "NVIDIA DLSS in place of the game's own upscale. Needs an RTX GPU and NVIDIA's DLLs in the " + "streamline folder beside the game. Applies after a restart."}, + {TAB_GRAPHICS, "DLSS mode", &opts.dlss_mode, 0, 4, 1, tx_dlss_mode, nullptr}, // (help_of: the output's size in it) + {TAB_GRAPHICS, "DLSS preset", &opts.dlss_preset, 0, 3, 1, tx_dlss_preset, + "NVIDIA's DLSS model, changed at once. M: NVIDIA's pick for Performance, close to L's picture but nearer K's speed. L: its " + "pick for Ultra Performance, sharper and steadier, less ghosting, slower. K: its pick for Quality, Balanced and DLAA. J: " + "like K, slightly less ghosting, more flicker."}, {TAB_GRAPHICS, "Upscaling", &opts.upscale, 0, 2, 1, tx_upscale, "The filter that scales the picture to your window. Off is the plain copy. Catmull-Rom is sharper, Lanczos sharper still."}, {TAB_GRAPHICS, "Sharpness", &opts.sharpness, 0, 100, 10, tx_percent, @@ -193,6 +262,15 @@ Row rows[] = { "Which gamepad button and which keys press each of the Switch's buttons."}, }; constexpr int kRows = sizeof rows / sizeof rows[0]; +const char* help_of(const Row& r) { + if (r.help) return r.help; + static char b[400]; + const Out o = shown_output(); + snprintf(b, sizeof b, "The size DLSS draws the 3D at before upscaling it to the game's output (%ux%u), in place of Resolution, changed " + "at once. Quality is NVIDIA's default; Balanced, Performance and Ultra Performance are lighter on slower GPUs; DLAA draws at " + "full size.", o.w, o.h); + return b; +} constexpr int kMenuWidth = 480; // (at a scale of 1: 720 lines) int cur_tab = TAB_GRAPHICS; @@ -235,6 +313,7 @@ std::string ini_path() { return dir.substr(0, dir.find_last_of("\\/") + 1) + "hookshot_options.ini"; } const char* ini_key(const Row& r) { + if (r.value == &opts.output_res) return "output_res"; // (host/nn_applet.c reads it at the start) static char k[32]; size_t n = 0; for (const char* p = r.name; *p && n + 1 < sizeof k; p++) k[n++] = *p == ' ' ? '_' : (char)tolower(*p); @@ -428,6 +507,16 @@ void gdi_draw(Bitmap& out, uint32_t w, uint32_t h, void (*paint)(HDC, uint32_t, HGDIOBJ old = SelectObject(dc, bmp); paint(dc, w, h, scale); GdiFlush(); + if (const char* dir = &out == &menu_bmp ? getenv("RX_VK_MENU_DUMP") : nullptr) { // (test runs: each drawing of the menu, as menu_.bmp) + static int n = 0; + char path[MAX_PATH]; + snprintf(path, sizeof path, "%s\\menu_%03d.bmp", dir, n++); + if (FILE* f = fopen(path, "wb")) { + BITMAPFILEHEADER fh{0x4d42, (DWORD)(sizeof fh + sizeof bi.bmiHeader + w * h * 4), 0, 0, (DWORD)(sizeof fh + sizeof bi.bmiHeader)}; + fwrite(&fh, sizeof fh, 1, f), fwrite(&bi.bmiHeader, sizeof bi.bmiHeader, 1, f), fwrite(bits, 4, (size_t)w * h, f); + fclose(f); + } + } const bool rgba = dev.swap_format == VK_FORMAT_R8G8B8A8_UNORM || dev.swap_format == VK_FORMAT_R8G8B8A8_SRGB; std::lock_guard lk(bmp_mu); out.w = w, out.h = h; @@ -658,7 +747,7 @@ void paint_menu(HDC dc, uint32_t w, uint32_t h, int s) { HFONT help = font(14 * s, FW_NORMAL); SelectObject(dc, help); SetTextColor(dc, RGB(176, 186, 180)); - wrap_help(dc, rows[tab_row_to_global(cur_tab, tab_selected[cur_tab])].help, (int)w - 32 * s, 16 * s, help_top + 4 * s, true); + wrap_help(dc, help_of(rows[tab_row_to_global(cur_tab, tab_selected[cur_tab])]), (int)w - 32 * s, 16 * s, help_top + 4 * s, true); SelectObject(dc, body); SetTextColor(dc, RGB(140, 150, 144)); const char* hint = "Arrows change Q/E or LB/RB: tabs Insert, F1 or Home closes"; // (fits 448 px at 16 px) @@ -709,7 +798,7 @@ int measure_help(int s) { HFONT f = font(14 * s, FW_NORMAL); HGDIOBJ old = SelectObject(dc, f); int most = 0; - for (const Row& r : rows) most = std::max(most, wrap_help(dc, r.help, (kMenuWidth - 32) * s, 0, 0, false)); + for (const Row& r : rows) most = std::max(most, wrap_help(dc, help_of(r), (kMenuWidth - 32) * s, 0, 0, false)); SelectObject(dc, old); DeleteObject(f); DeleteDC(dc); @@ -807,6 +896,19 @@ void menu_init() { if (r.value == &opts.upscale) *r.value = std::min(std::max(atoi(e), r.lo), r.hi); if (const char* e = getenv("HOS_REALTIME_STEP")) opts.realtime = atoi(e) != 0; if (const char* e = getenv("HOS_DYNRES")) opts.resolution = atoi(e) != 0 ? 0 : 1; + if (const char* e = getenv("RX_DLSS")) opts.dlss = atoi(e) != 0; + if (const char* e = getenv("HOS_OUTPUT_RES")) opts.output_res = std::min(std::max(atoi(e), 0), 2); + if (const char* e = getenv("RX_DLSS_PRESET"); e && e[0] >= 'J' && e[0] <= 'M') opts.dlss_preset = e[0] - 'J'; +} + +void menu_note_output(uint32_t w, uint32_t h) { + if (w && h) out_w = w, out_h = h; +} +bool resolution_auto() { return opts.resolution == 0 && !dlss_sets_size(); } +int resolution_scale() { // (for the output the game runs at: the crop) + const Out o{out_w, out_h}; + float s = dlss_sets_size() ? dlss_scale(opts.dlss_mode, o) : opts.resolution > 0 && opts.resolution <= 4 ? kResPercent[opts.resolution] / 100.0f : 0; + return s > 0 ? (int)(twelfths(s) * 10000.0f / 12.0f + 0.5f) : 0; // (the twelfth game_size labels) } void menu_set_gpu_count(int count) { @@ -901,6 +1003,18 @@ void menu_tick() { press[1] |= pad(HOS_PAD_UP), press[2] |= pad(HOS_PAD_DOWN), press[3] |= pad(HOS_PAD_LEFT); press[4] |= pad(HOS_PAD_RIGHT), press[5] |= pad(HOS_PAD_EAST), press[7] |= pad(HOS_PAD_SOUTH); } + { // RX_VK_MENU_SCRIPT (test runs, which never have the focus): timed menu keys, ":,..." + static const char* next = getenv("RX_VK_MENU_SCRIPT"); + static const int64_t start = prof_now(); + double at; + char key[8]; + int n = 0; + if (next && sscanf(next, "%lf:%7[A-Z]%n", &at, key, &n) == 2 && (prof_now() - start) / 1e9 >= at) { + static const char* names[] = {"INS", "UP", "DOWN", "LEFT", "RIGHT", "ESC", "", "ENTER", "", "", "TABL", "TABR"}; + for (int i = 0; i < 12; i++) press[i] |= *names[i] && !strcmp(key, names[i]); + next = next[n] == ',' ? next + n + 1 : nullptr; + } + } bool tab_left = press[10] || pad(HOS_PAD_LSHOULDER) || pad(HOS_PAD_LTRIGGER); bool tab_right = press[11] || press[12] || pad(HOS_PAD_RSHOULDER) || pad(HOS_PAD_RTRIGGER); if (press[12] && (GetAsyncKeyState(VK_SHIFT) & 0x8000)) tab_left = true, tab_right = false; diff --git a/gpu/vk/vk_menu.h b/gpu/vk/vk_menu.h index ae7ad0bc9..6d2995b36 100644 --- a/gpu/vk/vk_menu.h +++ b/gpu/vk/vk_menu.h @@ -10,6 +10,7 @@ struct Options { int framegen = 0; // made frames: 0 off, or 2, 3, 4 times the game's frames int pace = 0; // frames shown on an even line (vk_framegen.cpp) int resolution = 0; // the 3D's: 0 Auto (the game's dynamic resolution), else 100%, 75%, 67%, 50% of its full scale (nx2/oot_patches.py) + int output_res = 0; // the game's whole frame, docked: 0 its 2048x1152, 1 2560x1440, 2 3840x2160; read once, at the start (host/nn_applet.c) int upscale = 0; // to the window: 0 off (the plain copy to the window), 1 Catmull-Rom, 2 Lanczos int sharpness = 0; // 0 to 100 int realtime = 1; // game time follows the clock (host/nn_vi.c); 0: per frame (slower frames, slower game) @@ -30,6 +31,9 @@ struct Options { int preset = 0; // quality preset: 0 Custom, 1 Minimum (4GB), 2 Low (6GB), 3 Balanced (8GB), 4 High (12GB), 5 Ultra (16GB+) int vram_mb = 0; // dynamic texture cache budget limit in MB int mirror_mb = 0; // staging mirror limit in MB + int dlss = 0; // the game's gameplay upscale through NVIDIA DLSS (vk_dlss.cpp); read once, at the start (RX_DLSS=0/1 over it) + int dlss_mode = 3; // the render size with DLSS on: 0 Ultra Performance .. 3 Quality, 4 DLAA (dlss_render_size) + int dlss_preset = 3; // DLSS's model: 0 J, 1 K, 2 L, 3 M; applies at once (RX_DLSS_PRESET=J..M over it) }; extern Options opts; /// (vk_memory.cpp) true when the quality preset's memory budgets (vram_mb, mirror_mb) are to be used: the card has no more @@ -41,6 +45,9 @@ void menu_init(); // (the options from the file, once) void menu_set_gpu_count(int count); void menu_tick(); // (each frame shown: the keys, while the game's window has the focus) bool menu_is_open(); +bool resolution_auto(); // (the game's dynamic resolution: Resolution Auto, and DLSS not setting the size) +void menu_note_output(uint32_t w, uint32_t h); // (each present: the game's output, its window crop) +int resolution_scale(); // (the fixed path's scale in 1/10000: the Resolution row's, or the DLSS mode's, as a twelfth of the output) void menu_option_set(int id, int value); // (from the game's side: 7 the mouse's sensitivity, the - and = keys) void menu_note_frame(bool game_frame); // (the frame rates the FPS counter shows) /// Over the window's image (TRANSFER_DST_OPTIMAL), w x h: the menu and the FPS counter. slot: the frame in flight, 0 to 2. diff --git a/gpu/vk/vk_replay.cpp b/gpu/vk/vk_replay.cpp index 4caafcc30..597681fec 100644 --- a/gpu/vk/vk_replay.cpp +++ b/gpu/vk/vk_replay.cpp @@ -2213,7 +2213,9 @@ VmaAllocation off_alloc = nullptr; VkBuffer shot_bufs[2] = {VK_NULL_HANDLE, VK_NULL_HANDLE}; VmaAllocation shot_allocs[2] = {nullptr, nullptr}; void* shot_maps[2] = {nullptr, nullptr}; -constexpr uint32_t kShotW = 1280, kShotH = 720; +// (RX_VK_SHOT_W / RX_VK_SHOT_H: another size, e.g. the game's output size for its own pixels) +const uint32_t kShotW = getenv("RX_VK_SHOT_W") ? (uint32_t)atoi(getenv("RX_VK_SHOT_W")) : 1280, + kShotH = getenv("RX_VK_SHOT_H") ? (uint32_t)atoi(getenv("RX_VK_SHOT_H")) : 720; VkImage shot_image = VK_NULL_HANDLE; VkBuffer made_buf = VK_NULL_HANDLE; // (RX_VK_SHOT_MADE: a made frame's readback) VmaAllocation made_buf_alloc = nullptr; @@ -2475,6 +2477,7 @@ void log_frame_stats() { uint64_t present_value = 0; // (the present job's value, handed out as it came; 0: the next one) void do_present(const nvn_tex* t, const int crop[4]) { + if (crop) menu_note_output((uint32_t)std::max(crop[2], 0), (uint32_t)std::max(crop[3], 0)); // (the menu's sizes) { // (hookshot, RX_VK_PASS_TRACE_AT=: the passes of the frames around these frame numbers, for finding what a frame is made of) static std::atomic seen{0}; static const int64_t at = getenv("RX_VK_PASS_TRACE_AT") ? atoll(getenv("RX_VK_PASS_TRACE_AT")) : 0; @@ -3539,8 +3542,8 @@ void fill_replay_table(MkwVkRenderer& t) { t.nvn_present = present; t.nvn_register_texture = register_texture_queued; t.nvn_event_signal = event_signal_queued; - t.option = [](int id) -> int { - return id == 0 ? opts.realtime : id == 1 ? menu_is_open() : id == 2 ? opts.resolution == 0 : id == 3 ? (opts.resolution == 1 ? 100 : opts.resolution == 2 ? 75 : opts.resolution == 3 ? 67 : opts.resolution == 4 ? 50 : 0) : id == 4 ? opts.pad_background : id == 5 ? opts.text_speed : id == 6 ? opts.mouse_native : + t.option = [](int id) -> int { // (3: the fixed path's scale in 1/10000, vk_menu.cpp) + return id == 0 ? opts.realtime : id == 1 ? menu_is_open() : id == 2 ? resolution_auto() : id == 3 ? resolution_scale() : id == 4 ? opts.pad_background : id == 5 ? opts.text_speed : id == 6 ? opts.mouse_native : id == 7 ? opts.mouse_sens : id == 8 ? opts.mouse_invert : id == 16 ? opts.invert_cam_x : id == 17 ? opts.invert_cam_y : 0; }; t.option_set = menu_option_set; diff --git a/host/hos_main.c b/host/hos_main.c index 8bca54d23..79f2038e6 100644 --- a/host/hos_main.c +++ b/host/hos_main.c @@ -543,8 +543,9 @@ static int game_main(int argc, char **argv) { const double game = 16.0 / 9.0; if (want > game * 1.01) { double r = want > 32.0 / 9.0 ? 32.0 / 9.0 : want; - const unsigned oh = 1440, ow = (unsigned)(oh * r / 8 + 0.5) * 8; /* (whole multiples of 8 pixels) */ - const unsigned sh = 1080, sw = (unsigned)(ow * 0.75 / 8 + 0.5) * 8; /* (the scene, 3/4 of the picture as shipped) */ + uint32_t hos_output_size(int height); /* (host/nn_applet.c: the Output resolution's height, 1440 as shipped) */ + const unsigned oh = hos_output_size(1), ow = (unsigned)(oh * r / 8 + 0.5) * 8; /* (whole multiples of 8 pixels) */ + const unsigned sh = oh * 3 / 4, sw = (unsigned)(ow * 0.75 / 8 + 0.5) * 8; /* (the scene, 3/4 of the picture as shipped) */ hos_wide_out = (uint64_t)oh << 32 | ow; hos_wide_scene = (uint64_t)sh << 32 | sw; hos_wide_ratio = (float)ow / (float)oh; diff --git a/host/nn_applet.c b/host/nn_applet.c index de6a9fb3b..894b54df8 100644 --- a/host/nn_applet.c +++ b/host/nn_applet.c @@ -85,28 +85,50 @@ HLE(_ZN2nn2oe18GetDesiredLanguageEv) { } /* HOS_HANDHELD=1: handheld (the 1080p screen: 1080p output and the game's handheld resolutions) instead of docked (MKW docked composes 3840 x 2160) */ +static int ini_option(const char *key, int otherwise) { /* (hookshot: the Insert menu's choice, gpu/vk/vk_menu.cpp) */ + char path[MAX_PATH]; + const DWORD n = hos_game_path_a(path, MAX_PATH); + char *slash = n ? (strrchr(path, 92) ? strrchr(path, 92) : strrchr(path, 47)) : NULL; /* (linux: '/'; the game folder's, not bin\\'s) */ + if (!slash) return otherwise; + snprintf(slash + 1, (size_t)(path + MAX_PATH - slash - 1), "hookshot_options.ini"); + FILE *f = fopen(path, "r"); + if (!f) return otherwise; + char line[80]; + const size_t len = strlen(key); + while (fgets(line, sizeof line, f)) + if (!strncmp(line, key, len) && line[len] == '=') otherwise = atoi(line + len + 1); + fclose(f); + return otherwise; +} static int handheld(void) { + static int v = -1; + if (v < 0) v = getenv("HOS_HANDHELD") ? atoi(getenv("HOS_HANDHELD")) != 0 : ini_option("handheld_profile", 0) != 0; + return v; +} +/* (hookshot) The Insert menu's Output resolution (output_res=, HOS_OUTPUT_RES over it), docked only: 0 the game's 2048 x 1152, + 1 2560 x 1440, 2 3840 x 2160. The game's frame is its display size (2560 x 1440 as shipped; nx2/oot_patches.py + apply_output_size asks hos_output_size) times its graphics scale (GetCurrentGraphicsScale: 0 x1, 1 x0.8, 2 x0.667). Here it + saw scale 1 (x0 left at the call before's answer), so 2048 x 1152; 1 and 2 ask for x1 of a 2560 x 1440 or 3840 x 2160 display. */ +static int output_mode(void) { static int v = -1; if (v < 0) { - v = getenv("HOS_HANDHELD") && atoi(getenv("HOS_HANDHELD")) != 0; - if (!getenv("HOS_HANDHELD")) { /* (hookshot: the Insert menu's choice, gpu/vk/vk_menu.cpp) */ - char path[MAX_PATH]; - const DWORD n = hos_game_path_a(path, MAX_PATH); - char *slash = n ? (strrchr(path, 92) ? strrchr(path, 92) : strrchr(path, 47)) : NULL; /* (linux: '/') */ - if (slash) { - snprintf(slash + 1, (size_t)(path + MAX_PATH - slash - 1), "hookshot_options.ini"); - FILE *f = fopen(path, "r"); - if (f) { - char line[80]; - while (fgets(line, sizeof line, f)) - if (!strncmp(line, "handheld_profile=", 17)) v = atoi(line + 17) != 0; - fclose(f); - } - } - } + v = getenv("HOS_OUTPUT_RES") ? atoi(getenv("HOS_OUTPUT_RES")) : ini_option("output_res", 0); + if (v < 0 || v > 2 || handheld()) v = 0; + hos_log("oe: output resolution %s", v == 2 ? "3840x2160" : v == 1 ? "2560x1440" : "2048x1152 (the game's)"); } return v; } +uint32_t hos_output_size(int height) { return output_mode() == 2 ? (height ? 2160 : 3840) : (height ? 1440 : 2560); } +/* (hookshot) The render targets' GPU pool (nx2/oot_patches.py), 0x13100000 bytes as shipped, for 2560 x 1440: a 3840x2160 3D at + the 4K output ran out of it. Scaled with the output's pixels; HOS_RT_POOL_MB= over it */ +uint64_t hos_rt_pool_size(uint64_t game) { + const char *e = getenv("HOS_RT_POOL_MB"); + const uint64_t px = (uint64_t)hos_output_size(0) * hos_output_size(1); + const uint64_t v = e ? strtoull(e, NULL, 0) << 20 : px > 2560 * 1440 ? (game * px / (2560 * 1440) + 0xfffff) & ~0xfffffULL : game; + static int logged; + if (!logged++) hos_log("applet: render target pool %llu MB (the game's %llu MB)", (unsigned long long)(v >> 20), (unsigned long long)(game >> 20)); + return v; +} HLE(_ZN2nn2oe16GetOperationModeEv) { RET(handheld() ? 0 : 1); } /* OperationMode_Handheld / _Console (docked) */ HLE(_ZN2nn2oe18GetPerformanceModeEv) { RET(handheld() ? 0 : 1); } /* PerformanceMode_Normal / _Boost (docked) */ HLE(_ZN2nn2oe20GetCurrentFocusStateEv) { RET(1); } /* FocusState_InFocus */ @@ -335,6 +357,7 @@ HLE(_ZN2nn2oe23GetCurrentGraphicsScaleEv) { uint32_t bits; memcpy(&bits, &one, 4); c->vreg[0][0] = bits, c->vreg[0][1] = 0; + c->x[0] = output_mode() ? 0 : 1; /* (the scale enum the game reads, w0: x1 for a chosen output, x0.8 as before) */ } HLE(_ZN2nn2oe42SetGraphicsScaleChangedNotificationEnabledEb) {} HLE(_ZN2nn2oe31EnterExitRequestHandlingSectionEv) {} diff --git a/host/nn_vi.c b/host/nn_vi.c index aeb015431..c26a483b6 100644 --- a/host/nn_vi.c +++ b/host/nn_vi.c @@ -192,6 +192,7 @@ static float text_scale(const char *env, int menu) { const int v = env && *env ? atoi(env) : menu; return v == 1 ? 2.0f : v == 2 ? 4.0f : v >= 3 ? 1e6f : 1.0f; } +volatile uint64_t hos_res_module = 0; /* (f_831f3200's object, whose +0xe5c is the 3D's scale: nx2/oot_patches.py) */ static void realtime_step(int64_t now) { int rx_option(int id, int otherwise); /* (Resolution 100% from the start: the fixed path skipped the dynamic block from the first frame, its fields stayed @@ -203,10 +204,11 @@ static void realtime_step(int64_t now) { if (!looked) looked = 1, env = getenv("HOS_TEXT_SPEED"); hos_text_scale = text_scale(env, rx_option(5, 0)); } - { /* (the Insert menu's Resolution: the fixed path's scale, live; HOS_RES_SCALE below stays over it) */ - const int percent = rx_option(3, 0); - if (percent > 0 && !getenv("HOS_RES_SCALE")) { - const float v = percent / 100.0f; + { /* (the Insert menu's Resolution, or the DLSS mode with DLSS on: the fixed path's scale in 1/10000, live; HOS_RES_SCALE + below stays over it) */ + const int scale = rx_option(3, 0); + if (scale > 0 && !getenv("HOS_RES_SCALE")) { + const float v = scale / 10000.0f; memcpy((void *)&hos_fixed_scale_bits, &v, 4); } } @@ -217,6 +219,20 @@ static void realtime_step(int64_t now) { if (getenv("HOS_RES_SCALE")) { float v = (float)atof(getenv("HOS_RES_SCALE")); memcpy((void *)&hos_fixed_scale_bits, &v, 4); } } } + { /* HOS_RES_LOG=1: the 3D's scale every 300 presents. +0xe20: flags (bit 3: 0.75, bit 4: 0.5 in place of the scale), + +0xe2c bit 3: recompute asked, +0xe50/+0xe54/+0xe58: the sizes the scale is taken against, +0xe5c: the scale */ + static int on = -1; + static long long n; + if (on < 0) on = getenv("HOS_RES_LOG") != NULL; + const uint64_t m = hos_res_module; + if (on && m && !(n++ % 300)) { + float f[4], s; + memcpy(f, GP(m + 0xe50), sizeof f); + memcpy(&s, (const void *)&hos_fixed_scale_bits, 4); + hos_log("vi: res: fixed %d (scale %.3f), +0xe20 %llx, +0xe2c %x, +0xe50 %.0f %.0f %.0f, 3D scale %.3f", hos_fixed_resolution, s, + (unsigned long long)*(uint64_t *)GP(m + 0xe20), *(uint32_t *)GP(m + 0xe2c), f[0], f[1], f[2], f[3]); + } + } const uint64_t mod = hos_gfx_module; if (!mod) return; { /* (hookshot) The frame limiter (f_8042cd20 sleeps to 1 / +0xfc). The engine's adaptive controller writes +0xfc when diff --git a/nx2/build.py b/nx2/build.py index 3d4b0f589..e95d9d972 100644 --- a/nx2/build.py +++ b/nx2/build.py @@ -710,7 +710,9 @@ def main(): "-I" + os.path.join(GPU, "third_party", "suyu"), "-I" + os.path.join(vk, "sirit", "include"), "-I" + os.path.join(vk, "sirit", "src"), "-I" + os.path.join(spirv_headers, "include"), "-I" + os.path.join(spirv_headers, "include", "spirv", "unified1"), - "-I" + os.path.join(vk_headers, "include"), "-I" + vk] + (["-I" + os.path.join(cpm_package("vulkanmemoryallocator"), "include")] if cpm_package("vulkanmemoryallocator") else []) + # (third_party/streamline: NVIDIA Streamline's MIT headers, vk_dlss.cpp's) + "-I" + os.path.join(vk_headers, "include"), "-I" + vk, + "-I" + os.path.join(kit.HERE, "..", "third_party", "streamline", "include")] + (["-I" + os.path.join(cpm_package("vulkanmemoryallocator"), "include")] if cpm_package("vulkanmemoryallocator") else []) # (Eden's recompiler and sirit see only their own headers: a change to the back end's vk_*.h does not # rebuild their ~500 files; the back end itself depends on everything, suyu's texture decoders included) vk_lib_deps = tree_headers(os.path.join(vk, "eden"), os.path.join(vk, "sirit"), os.path.join(vk, "compat"), @@ -872,7 +874,8 @@ def main(): "-static-libstdc++", "-static-libgcc", "@" + vrsp, "-ldl", "-lpthread", "-lm"] else: link = [cc] + toolchain.native_target() + toolchain.native_link() + \ - ["-shared", "-o", vdll, toolchain.link_opt("/map:" + vdll[:-4] + ".map"), "@" + vrsp, "-luser32", "-lgdi32"] + (["-lc++", "-lunwind"] if toolchain.mingw() else []) + ["-shared", "-o", vdll, toolchain.link_opt("/map:" + vdll[:-4] + ".map"), "@" + vrsp, "-luser32", "-lgdi32", + "-lversion", "-lwintrust", "-lcrypt32"] + (["-lc++", "-lunwind"] if toolchain.mingw() else []) r = subprocess.run(link, capture_output=True, text=True) if r.returncode: undefined = sorted({l.strip() for l in (r.stdout + r.stderr).splitlines() if "undefined symbol" in l}) diff --git a/nx2/oot_patches.py b/nx2/oot_patches.py index cd2f36866..b93aa3ee3 100644 --- a/nx2/oot_patches.py +++ b/nx2/oot_patches.py @@ -10,6 +10,12 @@ letters' clock (+0x60 += rate +0x4c * time, the rate from the message's speed tag) and the pauses' timer (+0x58 -= time); hos_text_scale multiplies it, 1.0 as shipped. The auto-advance timer (+0x5c, before) keeps the game's time. A huge scale shows a page at once (one frame per pause), as the game's own skip on A (+0x72 = 2, f_80794b00) without its flags. +- The fixed path's scale (hos_fixed_scale_bits: the Insert menu's Resolution) reaching the 3D, in the caller f_831f3200 + (main+0x31d3200). It recomputes the 3D's scale (+0xe5c = scale * +0xe58 / +0xe50) only while +0xe2c bit 3 is set. The dynamic + path sets it on a level change; the fixed path's flag 1 calls f_831f41d0, whose bit 3 the apply block clears in the same frame, + before any recompute. So the fixed path kept the dynamic path's last scale (0.75 docked: 1536x864 at every setting). Flag 1 now + also asks for the recompute, and on the fixed path the flags +0xe20 bits 3/4 (a hardcoded 0.75 / 0.5 in place of the scale) + are not looked at. """ import glob import os @@ -21,6 +27,19 @@ LABEL = "L_8082640c:;" SCALE_OLD = "c->x[9] = 0x3f800000ULL;" SCALE_NEW = "c->x[9] = hos_fixed_scale_bits;" # (the fixed path's scale, 1.0 as shipped) +DECL2 = "extern volatile int hos_fixed_resolution;\nextern volatile uint64_t hos_res_module;\nextern volatile uint32_t hos_fixed_scale_bits;\n" +APPLY_OLD = "L_831f3efc:;\n c->x[9]=recomp_load32(c,c->x[20] + 3628);" +APPLY_NEW = "L_831f3efc:;\n if (hos_fixed_resolution) { /* (only while +0xe5c is not the chosen scale: a recompute every frame remade the targets) */\n union { uint32_t u; float f; } now = {(uint32_t)recomp_load32(c,c->x[20] + 3676)}, want = {hos_fixed_scale_bits},\n e50 = {(uint32_t)recomp_load32(c,c->x[20] + 3664)}, e58 = {(uint32_t)recomp_load32(c,c->x[20] + 3672)};\n const float d = now.f - (e50.f != 0 ? want.f * e58.f / e50.f : want.f);\n if (d > 1e-4f || d < -1e-4f) c->x[8] |= 8;\n }\n c->x[9]=recomp_load32(c,c->x[20] + 3628);" +FLAGS_OLD = "L_831f3f08:;\n c->x[8]=recomp_load64(c,c->x[20] + 3616);\n" +FLAGS_NEW = FLAGS_OLD + " hos_res_module = c->x[20];\n if (hos_fixed_resolution) c->x[8] &= ~0x18ULL;\n" + + +def fixed_scale(t): + """The fixed path's scale reaching the 3D (the Resolution row, or the DLSS mode with DLSS on). (t, 1) when applied here""" + if APPLY_OLD not in t or FLAGS_OLD not in t: + return t, 0 + t = t.replace(APPLY_OLD, APPLY_NEW, 1).replace(FLAGS_OLD, FLAGS_NEW, 1) + return t.replace('#include "a64.h"\n', '#include "a64.h"\n' + DECL2, 1), 1 TEXT_DECL = "extern volatile float hos_text_scale;\n" TEXT_HEAD = "void f_80b1e140(Ctx *__restrict A64_NOESC c) {" @@ -50,6 +69,8 @@ def patch_text_speed(s): return None end = s.find("\nvoid f_", head + len(TEXT_HEAD)) body = s[head:end if end >= 0 else len(s)] + if TEXT_NEW in body: # (applied already: a second run) + return s if body.count(TEXT_OLD) != 1 or body.count("goto L_80b1e1b4;") != 1: return s at = head + body.index(TEXT_OLD) @@ -58,7 +79,7 @@ def patch_text_speed(s): def apply(gen): - done = {"dynamic resolution branch": 0, "text speed block": 0} + done = {"dynamic resolution branch": 0, "text speed block": 0, "fixed path's scale": 0} for path in sorted(glob.glob(os.path.join(gen, "code_*.c"))): with open(path, encoding="utf-8", newline="") as f: s = f.read() @@ -73,12 +94,100 @@ def apply(gen): out = t done["text speed block"] += 1 print("oot_patches: text speed scale in", os.path.basename(path)) + out, n = fixed_scale(out) + if n: + done["fixed path's scale"] += 1 + print("oot_patches: the fixed path's scale in", os.path.basename(path)) if out != s: with open(path, "w", encoding="utf-8", newline="") as f: f.write(out) for what, n in done.items(): if n != 1: print("oot_patches: WARNING: the %s was found %d times" % (what, n)) + apply_output_size(gen) + + +# Output size (host/nn_applet.c hos_output_size: the Insert menu's Output resolution, 2560 x 1440 as shipped): +# - nnMain (f_81222ce0) puts the display size in the framework's create arg (+20/+24, the framework's +156/+160); the window +# textures are made at it. +# - f_810a7b70 sets up the display-size object (B = [[0x84ca29c0]+216]) from a config (x1): its docked size list (+8, first +# 2560 x 1440) is the frame's base (B+244; the frame is the base times the graphics scale's factor, f_806702e0, capped by the +# scale's display class: docked 3840 x 2160 at scale 0). Its first entry asks the host when it differs. +OUT_DECL = "uint32_t hos_output_size(int height);\nuint64_t hos_rt_pool_size(uint64_t game);\n" +OUT_EDITS = [ + # (the picture's 2560 x 1440 at 0x81202ee4, not f_831f3200's copy at +0xb68; nx2/oot_wide.py's widescreen size, after it, + # stays over it: host/hos_main.c makes that one at this height) + (" c->x[8] = 0xa00ULL;\n c->x[8] = (c->x[8] & ~(0xFFFFULL<<32)) | (0x5a0ULL<<32);\n" + "{ extern volatile uint64_t hos_wide_out; const uint64_t _s = hos_wide_out; if (_s) c->x[8] = _s; } /* (nx2/oot_wide.py: hos_wide_out) */\n" + " { uint64_t _b=c->x[21]; int64_t _o=20; recomp_store64(c,(_b+_o),c->x[8]); }", + " c->x[8] = hos_output_size(0) | ((uint64_t)hos_output_size(1) << 32);\n" + "{ extern volatile uint64_t hos_wide_out; const uint64_t _s = hos_wide_out; if (_s) c->x[8] = _s; } /* (nx2/oot_wide.py: hos_wide_out) */\n" + " { uint64_t _b=c->x[21]; int64_t _o=20; recomp_store64(c,(_b+_o),c->x[8]); }"), + (" { uint64_t _a=c->x[0], _b=724ULL; uint64_t _r=_a+_b; c->x[21]=_r; }\n" + " { uint64_t _r = ((uint64_t)0 | ((c->x[1]) << 0)); c->x[20] = _r; }\n", + " { uint64_t _a=c->x[0], _b=724ULL; uint64_t _r=_a+_b; c->x[21]=_r; }\n" + " { uint64_t _r = ((uint64_t)0 | ((c->x[1]) << 0)); c->x[20] = _r; }\n" + " if (hos_output_size(0) != 2560 && recomp_load32(c, c->x[20] + 8) == 2560) { recomp_store32(c, c->x[20] + 8, hos_output_size(0)); recomp_store32(c, c->x[20] + 12, hos_output_size(1)); }\n"), + # - f_80ea2f30: the 3D's largest size, ResolutionParam's BaseResolution (or 1920 x 1080 as constants), 3/4 of 2560 x 1440; + # above it the game takes a smaller upscale network (1/3: 1280 x 720 at 4K). Scaled with the output. + ("c->x[30] = 0x80ea2ffcULL; f_831cca50(c);\n" + " { uint64_t _b=c->x[0]; int64_t _o=0; { uint64_t _p0,_p1; recomp_ldp32(c,(_b+_o),&_p0,&_p1); c->x[24]=_p0; c->x[25]=_p1; } }\n", + "c->x[30] = 0x80ea2ffcULL; f_831cca50(c);\n" + " { uint64_t _b=c->x[0]; int64_t _o=0; { uint64_t _p0,_p1; recomp_ldp32(c,(_b+_o),&_p0,&_p1); c->x[24]=_p0; c->x[25]=_p1; } }\n" + " if (hos_output_size(0) != 2560) { c->x[24] = (uint32_t)c->x[24] * hos_output_size(0) / 2560; c->x[25] = (uint32_t)c->x[25] * hos_output_size(1) / 1440; }\n"), + (" c->x[8] = 0x44f00000ULL;\n c->x[8] &= 0xFFFFFFFFULL;\n recomp_store32(c,c->x[19] + 3668,c->x[8]);\n" + " c->x[8] = 0x44870000ULL;\n c->x[8] &= 0xFFFFFFFFULL;\n", + " c->x[8] = hos_output_size(0) * 3 / 4;\n { float _f = (float)c->x[8]; uint32_t _u; memcpy(&_u, &_f, 4); c->x[8] = _u; }\n" + " recomp_store32(c,c->x[19] + 3668,c->x[8]);\n" + " c->x[8] = hos_output_size(1) * 3 / 4;\n { float _f = (float)c->x[8]; uint32_t _u; memcpy(&_u, &_f, 4); c->x[8] = _u; }\n"), + # - The render targets' GPU pool: 0x13100000 bytes (the graphics config's +1464, read in f_836ce9d0, which takes its storage from + # the "Graphics" heap and makes a physical pool and a virtual one over it: f_80c4a1c0 -> f_80c49070 -> f_80c49380 -> f_811c9ba0). + # Sized for 2560 x 1440: a 3840x2160 3D at the 4K output ran out of it and the next target came back null (crash in f_8005ed00, + # the pool's allocator, its +0x28 0x13100000). Scaled with the output's pixels (host/nn_applet.c + # hos_rt_pool_size: 687 MB at 3840 x 2160), at the config, so the storage and the pool agree. + ("L_836cea54:;\n", + "L_836cea54:;\n" + " if (recomp_load64(c, c->x[19] + 1464) == 0x13100000ULL) recomp_store64(c, c->x[19] + 1464, hos_rt_pool_size(0x13100000ULL));\n"), + # - The "Graphics" heap holds it, made by f_83b7b340 with the other module heaps (twice: 0x34900000 bytes in f_83b7a2c0's first + # pass, then the heap kept, 0x348ffe20; it had under 16 MB to spare): grown by as much as the pool. + ("c->x[30] = 0x83b7b440ULL; f_809df710(c);\n", + "if (c->x[0] == 0x34900000ULL || c->x[0] == 0x348ffe20ULL) c->x[0] += hos_rt_pool_size(0x13100000ULL) - 0x13100000ULL;\n" + "c->x[30] = 0x83b7b440ULL; f_809df710(c);\n"), + # - f_83b7b340 then takes each module heap's use (its vtable +120) off the module's budget (the configured size, a table of slots) + # and aborts below zero (f_8351c280): the Graphics heap's use counts as the shipped one. + ("{ uint64_t _t = c->x[8]; c->x[30] = 0x83b7b4e0ULL; A64_ICALL(c, _t); }\n", + "{ uint64_t _t = c->x[8]; c->x[30] = 0x83b7b4e0ULL; A64_ICALL(c, _t); }\n" + "{ const uint64_t _b = recomp_load64(c, c->x[21] + (c->x[22] << 3)), _g = hos_rt_pool_size(0x13100000ULL) - 0x13100000ULL; " + "if ((_b == 0x34900000ULL || _b == 0x348ffe20ULL) && c->x[0] > _g) c->x[0] -= _g; }\n"), + # - f_80b72340 (from the graphics init f_836cf4b0) makes a heap of what the Graphics heap can still give, which took the growth as + # well (0x1b6cb48 bytes as shipped, 0x1996cb48 grown) and left too little for the pool: it keeps its shipped size. + ("c->x[30] = 0x80b723acULL; f_809df700(c);\n", + "if (c->x[0] > hos_rt_pool_size(0x13100000ULL) - 0x13100000ULL) c->x[0] -= hos_rt_pool_size(0x13100000ULL) - 0x13100000ULL;\n" + "c->x[30] = 0x80b723acULL; f_809df700(c);\n"), +] + + +def apply_output_size(gen): + found = [0] * len(OUT_EDITS) + for path in sorted(glob.glob(os.path.join(gen, "code_*.c"))): + with open(path, encoding="utf-8", newline="") as f: + s = f.read() + hit = False + for i, (old, new) in enumerate(OUT_EDITS): + if new in s: # (applied already: a second run. Each new text holds its old one, which would be patched again) + found[i] += 1 + elif old in s: + found[i] += s.count(old) + s = s.replace(old, new) + hit = True + if hit: + if OUT_DECL not in s: + s = s.replace('#include "a64.h"\n', '#include "a64.h"\n' + OUT_DECL, 1) + with open(path, "w", encoding="utf-8", newline="") as f: + f.write(s) + print("oot_patches: output size in", os.path.basename(path)) + if found != [1] * len(OUT_EDITS): + print("oot_patches: WARNING: the output size places were found %s times" % found) if __name__ == "__main__": diff --git a/readme.md b/readme.md index 78f2bdf3b..3d4adfe47 100644 --- a/readme.md +++ b/readme.md @@ -187,7 +187,11 @@ and the right one closes the menu. Your choices are saved in `hookshot_options.i | | GPU device | Auto, or each graphics card by name (after a restart) | Auto | | | Frame generation | Off, 2x to 8x | Off | | | Frame pacing | Off, On | Off | -| | Resolution | Auto (the game's own dynamic resolution), 100%, 75%, 67%, 50% | Auto | +| | Resolution | Auto (the game's own dynamic resolution), 100%, 75%, 67%, 50% (each with its size); set by the DLSS mode while DLSS is on | Auto | +| | Output resolution | 2048x1152, 2560x1440, 3840x2160 (after a restart) | 2048x1152 | +| | DLSS | Off, On (after a restart) | Off | +| | DLSS mode | Ultra Performance, Performance, Balanced, Quality, DLAA | Quality | +| | DLSS preset | J, K, L, M | M | | | Upscaling | Off, Catmull-Rom, Lanczos | Off | | | Sharpness | 0 to 100%, in steps of 10 | 0% | | | Handheld profile | Off, On (after a restart) | Off | @@ -214,6 +218,8 @@ and the right one closes the menu. Your choices are saved in `hookshot_options.i over the menu. - **Frame generation** makes extra frames between the game's own. It adds a little input delay, and fast motion can show artifacts. **Frame pacing** shows frames at an even interval: less stutter, up to one frame of delay. +- **Output resolution** is the size of the game's whole frame, HUD included, before it is scaled to your window. + Resolution and the DLSS mode are a share of it, and their rows show the size for the output you chose. Docked only. - **Upscaling** and **Sharpness** also work when Frame generation is Off. - **Handheld profile** runs the game as if the console were undocked: lower resolution, lighter on the GPU. - **Robust buffers:** a read past a buffer's end is dropped instead of stopping the GPU. Auto is on, on every card; Off @@ -228,6 +234,17 @@ and the right one closes the menu. Your choices are saved in `hookshot_options.i - **Layout preset:** Nintendo has A on the right face button, Xbox / PC and Swap Face put A on the bottom one. Changing a button yourself sets it to Custom. +### NVIDIA DLSS + +DLSS is optional and needs an RTX card. It replaces the game's own upscale: the 3D is drawn at the DLSS mode's size and +DLSS scales it up to the output. Hookshot does not include NVIDIA's files. Put a `streamline` folder beside the game's +exe (`bin\hookshot.exe` with the launcher) holding `sl.interposer.dll`, `sl.common.dll` and `sl.dlss.dll` from +NVIDIA's [Streamline SDK](https://github.com/NVIDIA-RTX/Streamline) (2.14 or newer) and `nvngx_dlss.dll`. Without +`nvngx_dlss.dll`, the copy the NVIDIA app keeps is used if it is signed by NVIDIA. Without any of them the DLSS row says +so and the game runs as before. **DLSS preset** picks NVIDIA's model and changes at once. + +For one run: `RX_DLSS=0/1`, `RX_DLSS_PRESET=J..M`, `RX_DLSS_DIR=`, `HOS_OUTPUT_RES=0/1/2`. + ### Controls Use a controller, or the keyboard and mouse. On the keyboard, W A S D move @@ -402,7 +419,7 @@ Hookshot exists thanks to the work of many people: - **[EvilBoyce / evilmfkr](https://github.com/evilmfkr/Hookshot)** (EvilOOT): the GPU culling that brings back Kokiri's foliage (trees, ferns, grass, falling leaves, fireflies), the ambient light probes, the pond's water, the game's own fog, the freeze after Load (Horizon's mutex handoff) and the exposure flicker fix. -- **[zortos293/Lichii](https://github.com/zortos293/Lichii)**: reference for Ampere shader lowering, and its compare-exchange retry fix. +- **[zortos293/Lichii](https://github.com/zortos293/Lichii)**: reference for Ampere shader lowering, and its compare-exchange retry fix; the NVIDIA DLSS replacement of the game's upscale (Streamline loader, camera motion and its shaders), ported in `gpu/vk/vk_dlss.cpp` and `gpu/vk/vk_draw.cpp`, which Lichii credits to Duck912's work in Eglantine. NVIDIA Streamline's headers (MIT) are in `third_party/streamline`; NVIDIA's DLLs are not part of Hookshot. - **[mstorsjo/llvm-mingw](https://github.com/mstorsjo/llvm-mingw)**: the bundled Windows compiler (no Visual Studio needed). - **[kinnay/zbic](https://github.com/kinnay/zbic)**, **Opus** and **SDL**: decompression, audio and controllers. - **[sostenesfreitas/ocarina-recomp](https://github.com/sostenesfreitas/ocarina-recomp)**: this README's layout, and its notes diff --git a/third_party/streamline/include/sl.h b/third_party/streamline/include/sl.h new file mode 100644 index 000000000..0e8e010ea --- /dev/null +++ b/third_party/streamline/include/sl.h @@ -0,0 +1,46 @@ +/* +* Copyright (c) 2022-2023 NVIDIA CORPORATION. All rights reserved +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +#pragma once + +#include + +#include "sl_struct.h" +#include "sl_consts.h" +#include "sl_version.h" +#include "sl_result.h" +#include "sl_appidentity.h" +#include "sl_device_wrappers.h" + +#include "sl_core_api.h" +#include "sl_core_types.h" + +#define SL_FUN_DECL(name) PFun_##name* name{} +//! IMPORTANT: Macros which use `slGetFeatureFunction` can only be used AFTER device is set by calling either slSetD3DDevice or slSetVulkanInfo. +#define SL_FEATURE_FUN_IMPORT(feature, func) slGetFeatureFunction(feature, #func, (void*&) ##func) +#define SL_FEATURE_FUN_IMPORT_STATIC(feature, func) \ +static PFun_##func* s_ ##func{}; \ +if(!s_ ##func) { \ + sl::Result res = slGetFeatureFunction(feature, #func, (void*&) s_ ##func); \ + if(res != sl::Result::eOk) return res; \ +} \ + diff --git a/third_party/streamline/include/sl_appidentity.h b/third_party/streamline/include/sl_appidentity.h new file mode 100644 index 000000000..3f268fb65 --- /dev/null +++ b/third_party/streamline/include/sl_appidentity.h @@ -0,0 +1,20 @@ +#pragma once + +#include + +#include "sl_struct.h" + +namespace sl +{ + +//! Engine types +//! +enum class EngineType : uint32_t +{ + eCustom, + eUnreal, + eUnity, + eCount +}; + +} diff --git a/third_party/streamline/include/sl_consts.h b/third_party/streamline/include/sl_consts.h new file mode 100644 index 000000000..20f8850c3 --- /dev/null +++ b/third_party/streamline/include/sl_consts.h @@ -0,0 +1,260 @@ +/* +* Copyright (c) 2022-2023 NVIDIA CORPORATION. All rights reserved +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +#pragma once + +#include +#include +#include +#include "sl_struct.h" + +#define SL_ENUM_OPERATORS_64(T) \ +inline bool operator&(T a, T b) \ +{ \ + return ((uint64_t)a & (uint64_t)b) != 0; \ +} \ + \ +inline T& operator&=(T& a, T b) \ +{ \ + a = (T)((uint64_t)a & (uint64_t)b); \ + return a; \ +} \ + \ +inline T operator|(T a, T b) \ +{ \ + return (T)((uint64_t)a | (uint64_t)b); \ +} \ + \ +inline T& operator |= (T& lhs, T rhs) \ +{ \ + lhs = (T)((uint64_t)lhs | (uint64_t)rhs); \ + return lhs; \ +} \ + \ +inline T operator~(T a) \ +{ \ + return (T)~((uint64_t)a); \ +} + +#define SL_ENUM_OPERATORS_32(T) \ +inline bool operator&(T a, T b) \ +{ \ + return ((uint32_t)a & (uint32_t)b) != 0; \ +} \ + \ +inline T& operator&=(T& a, T b) \ +{ \ + a = (T)((uint32_t)a & (uint32_t)b); \ + return a; \ +} \ + \ +inline T operator|(T a, T b) \ +{ \ + return (T)((uint32_t)a | (uint32_t)b); \ +} \ + \ +inline T& operator |= (T& lhs, T rhs) \ +{ \ + lhs = (T)((uint32_t)lhs | (uint32_t)rhs); \ + return lhs; \ +} \ + \ +inline T operator~(T a) \ +{ \ + return (T)~((uint32_t)a); \ +} + +namespace sl +{ + +//! For cases when value has to be provided and we don't have good default +constexpr float INVALID_FLOAT = 3.40282346638528859811704183484516925440e38f; +constexpr uint32_t INVALID_UINT = 0xffffffff; + +//! Normally host would work with no more than 2 frames at the same time but sl.reflex sometimes +//! needs to send markers for previous and next frame so the total number of in-flight frames can be higher +constexpr uint32_t MAX_FRAMES_IN_FLIGHT = 6; + +struct uint2 +{ + uint32_t x; + uint32_t y; +}; + +struct uint3 +{ + uint32_t x; + uint32_t y; + uint32_t z; +}; + +struct float2 +{ + float2() : x(INVALID_FLOAT), y(INVALID_FLOAT) {} + float2(float _x, float _y) : x(_x), y(_y) {} + float x, y; +}; + +struct float3 +{ + float3() : x(INVALID_FLOAT), y(INVALID_FLOAT), z(INVALID_FLOAT) {} + float3(float _x, float _y, float _z) : x(_x), y(_y), z(_z) {} + float x, y, z; +}; + +struct float4 +{ + float4() : x(INVALID_FLOAT), y(INVALID_FLOAT), z(INVALID_FLOAT), w(INVALID_FLOAT) {} + float4(float _x, float _y, float _z, float _w) : x(_x), y(_y), z(_z), w(_w) {} + float x, y, z, w; +}; + +struct float4x4 +{ + //! All access points take row index as a parameter + inline float4& operator[](uint32_t i) { return row[i]; } + inline const float4& operator[](uint32_t i) const { return row[i]; } + inline void setRow(uint32_t i, const float4& v) { row[i] = v; } + inline const float4& getRow(uint32_t i) { return row[i]; } + + //! Row major matrix + float4 row[4]; +}; + +struct Extent +{ + uint32_t top{}; + uint32_t left{}; + uint32_t width{}; + uint32_t height{}; + + inline operator bool() const { return width != 0 && height != 0; } + inline bool operator==(const Extent& rhs) const + { + return top == rhs.top && left == rhs.left && + width == rhs.width && height == rhs.height; + } + inline bool operator!=(const Extent& rhs) const + { + return !operator==(rhs); + } + inline bool isSameRes(const Extent& rhs) const + { + return width == rhs.width && height == rhs.height; + } + +#if defined(_WINDEF_) + // Cast helper for sl::Extent->RECT when windef.h has been included + inline operator RECT() const { return RECT { (LONG)left, (LONG)top, (LONG)(left + width), (LONG)(top + height) }; } +#endif +}; + +//! For cases when value has to be provided and we don't have good default +enum Boolean : char +{ + eFalse, + eTrue, + eInvalid +}; + +//! Common constants, all parameters must be provided unless they are marked as optional +//! +//! {DCD35AD7-4E4A-4BAD-A90C-E0C49EB23AFE} +SL_STRUCT_BEGIN(Constants, StructType({ 0xdcd35ad7, 0x4e4a, 0x4bad, { 0xa9, 0xc, 0xe0, 0xc4, 0x9e, 0xb2, 0x3a, 0xfe } }), kStructVersion2) + //! IMPORTANT: All matrices are row major (see float4x4 definition) and + //! must NOT contain temporal AA jitter offset (if any). Any jitter offset + //! should be provided as the additional parameter Constants::jitterOffset (see below) + + //! Specifies matrix transformation from the camera view to the clip space. + float4x4 cameraViewToClip; + //! Specifies matrix transformation from the clip space to the camera view space. + float4x4 clipToCameraView; + //! Optional - Specifies matrix transformation describing lens distortion in clip space. + float4x4 clipToLensClip; + //! Specifies matrix transformation from the current clip to the previous clip space. + //! clipToPrevClip = clipToView * viewToViewPrev * viewToClipPrev + //! Sample code can be found in sl_matrix_helpers.h + float4x4 clipToPrevClip; + //! Specifies matrix transformation from the previous clip to the current clip space. + //! prevClipToClip = clipToPrevClip.inverse() + float4x4 prevClipToClip; + + //! Specifies pixel space jitter offset + float2 jitterOffset; + //! Specifies scale factors used to normalize motion vectors (so the values are in [-1,1] range) + float2 mvecScale; + //! Optional - Specifies camera pinhole offset if used. + float2 cameraPinholeOffset; + //! Specifies camera position in world space. + float3 cameraPos; + //! Specifies camera up vector in world space. + float3 cameraUp; + //! Specifies camera right vector in world space. + float3 cameraRight; + //! Specifies camera forward vector in world space. + float3 cameraFwd; + + //! Specifies camera near view plane distance. + float cameraNear = INVALID_FLOAT; + //! Specifies camera far view plane distance. + float cameraFar = INVALID_FLOAT; + //! Specifies camera field of view in radians. + float cameraFOV = INVALID_FLOAT; + //! Specifies camera aspect ratio defined as view space width divided by height. + float cameraAspectRatio = INVALID_FLOAT; + //! Specifies which value represents an invalid (un-initialized) value in the motion vectors buffer + //! NOTE: This is only required if `cameraMotionIncluded` is set to false and SL needs to compute it. + float motionVectorsInvalidValue = INVALID_FLOAT; + + //! Specifies if depth values are inverted (value closer to the camera is higher) or not. + Boolean depthInverted = Boolean::eInvalid; + //! Specifies if camera motion is included in the MVec buffer. + Boolean cameraMotionIncluded = Boolean::eInvalid; + //! Specifies if motion vectors are 3D or not. + Boolean motionVectors3D = Boolean::eInvalid; + //! Specifies if previous frame has no connection to the current one (i.e. motion vectors are invalid) + Boolean reset = Boolean::eInvalid; + //! Specifies if orthographic projection is used or not. + Boolean orthographicProjection = Boolean::eFalse; + //! Specifies if motion vectors are already dilated or not. + Boolean motionVectorsDilated = Boolean::eFalse; + //! Specifies if motion vectors are jittered or not. + Boolean motionVectorsJittered = Boolean::eFalse; + + //! Version 2 members: + //! + //! Optional heuristic that specifies the minimum depth difference between two objects in screen-space. + //! The units of the value are in linear depth units. + //! Linear depth is computed as: + //! if depthInverted is false: `lin_depth = 1 / (1 - depth)` + //! if depthInverted is true: `lin_depth = 1 / depth` + //! + //! Although unlikely to need to be modified, smaller thresholds are useful when depth units are + //! unusually compressed into a small dynamic range near 1. + //! + //! If not specified, the default value is 40.0f. + float minRelativeLinearDepthObjectSeparation = 40.0f; + + //! IMPORTANT: New members go here or if optional can be chained in a new struct, see sl_struct.h for details +SL_STRUCT_END() + +} diff --git a/third_party/streamline/include/sl_core_api.h b/third_party/streamline/include/sl_core_api.h new file mode 100644 index 000000000..bc256d6d9 --- /dev/null +++ b/third_party/streamline/include/sl_core_api.h @@ -0,0 +1,328 @@ +/* +* Copyright (c) 2022-2024 NVIDIA CORPORATION. All rights reserved +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +#pragma once + +#include + +#include "sl_struct.h" +#include "sl_consts.h" +#include "sl_version.h" +#include "sl_result.h" +#include "sl_appidentity.h" +#include "sl_device_wrappers.h" + +#include "sl_core_types.h" + +#if defined(SL_INTERPOSER) + #if defined(_WIN32) + #define SL_API extern "C" __declspec(dllexport) + #else + #error Unsupported Platform! + #endif +#else +#define SL_API extern "C" +#endif + +#pragma region SL_API + +//! Streamline core API functions (check feature specific headers for additional APIs) +//! +using PFun_slInit = sl::Result(const sl::Preferences& pref, uint64_t sdkVersion); +using PFun_slShutdown = sl::Result(); +using PFun_slIsFeatureSupported = sl::Result(sl::Feature feature, const sl::AdapterInfo& adapterInfo); +using PFun_slIsFeatureLoaded = sl::Result(sl::Feature feature, bool& loaded); +using PFun_slSetFeatureLoaded = sl::Result(sl::Feature feature, bool loaded); +using PFun_slEvaluateFeature = sl::Result(sl::Feature feature, const sl::FrameToken& frame, const sl::BaseStructure** inputs, uint32_t numInputs, sl::CommandBuffer* cmdBuffer); +using PFun_slAllocateResources = sl::Result(sl::CommandBuffer* cmdBuffer, sl::Feature feature, const sl::ViewportHandle& viewport); +using PFun_slFreeResources = sl::Result(sl::Feature feature, const sl::ViewportHandle& viewport); +using PFun_slSetTag +#if __cplusplus >= 201402L +[[deprecated("Use the version of this function that takes a sl::FrameToken instead - slSetTagForFrame and set sl::PreferenceFlags::eUseFrameBasedResourceTagging.")]] +#endif += sl::Result(const sl::ViewportHandle& viewport, const sl::ResourceTag* tags, uint32_t numTags, sl::CommandBuffer* cmdBuffer); +using PFun_slSetTagForFrame = sl::Result(const sl::FrameToken& frame, const sl::ViewportHandle& viewport, const sl::ResourceTag* tags, uint32_t numTags, sl::CommandBuffer* cmdBuffer); +using PFun_slGetFeatureRequirements = sl::Result(sl::Feature feature, sl::FeatureRequirements& requirements); +using PFun_slGetFeatureVersion = sl::Result(sl::Feature feature, sl::FeatureVersion& version); +using PFun_slUpgradeInterface = sl::Result(void** baseInterface); +using PFun_slSetConstants = sl::Result(const sl::Constants& values, const sl::FrameToken& frame, const sl::ViewportHandle& viewport); +using PFun_slGetNativeInterface = sl::Result(void* proxyInterface, void** baseInterface); +using PFun_slGetFeatureFunction = sl::Result(sl::Feature feature, const char* functionName, void*& function); +using PFun_slGetNewFrameToken = sl::Result(sl::FrameToken*& token, const uint32_t* frameIndex); +using PFun_slSetD3DDevice = sl::Result(void* d3dDevice); + + +//! Initializes the SL module +//! +//! Call this method when the game is initializing. +//! +//! @param pref Specifies preferred behavior for the SL library (SL will keep a copy) +//! @param sdkVersion Current SDK version +//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details) +//! +//! This method is NOT thread safe. +SL_API sl::Result slInit(const sl::Preferences &pref, uint64_t sdkVersion = sl::kSDKVersion); + +//! Shuts down the SL module +//! +//! Call this method when the game is shutting down. +//! +//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details) +//! +//! This method is NOT thread safe. +SL_API sl::Result slShutdown(); + +//! Checks if a specific feature is supported or not. +//! +//! Call this method to check if a certain e* (see above) is available. +//! +//! @param feature Specifies which feature to use +//! @param adapterInfo Adapter to check (optional) +//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details) +//! +//! NOTE: If adapter info is null SL will return general feature compatibility with the OS, +//! installed drivers or any other requirements not directly related to the adapter. +//! +//! This method is NOT thread safe. +SL_API sl::Result slIsFeatureSupported(sl::Feature feature, const sl::AdapterInfo& adapterInfo); + +//! Checks if specified feature is loaded or not. +//! +//! Call this method to check if feature is loaded. +//! All requested features are loaded by default and have to be unloaded explicitly if needed. +//! +//! @param feature Specifies which feature to check +//! @param loaded Value specifying if feature is loaded or unloaded. +//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details) +//! +//! This method is NOT thread safe and requires DX/VK device to be created before calling it. +SL_API sl::Result slIsFeatureLoaded(sl::Feature feature, bool& loaded); + +//! Sets the specified feature to either loaded or unloaded state. +//! +//! Call this method to load or unload certain e*. +//! +//! NOTE: All requested features are loaded by default and have to be unloaded explicitly if needed. +//! +//! @param feature Specifies which feature to check +//! @param loaded Value specifying if feature should be loaded or unloaded. +//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details) +//! +//! NOTE: When this method is called no other DXGI/D3D/Vulkan APIs should be invoked in parallel so +//! make sure to flush your pipeline before calling this method. +//! +//! This method is NOT thread safe and requires DX/VK device to be created before calling it. +SL_API sl::Result slSetFeatureLoaded(sl::Feature feature, bool loaded); + +//! NOTE: sl::PreferenceFlags::eUseFrameBasedResourceTagging must be set when using this API. +//! Tags resource globally +//! +//! Call this method to tag the appropriate buffers in global scope. +//! +//! @param frame Specifies the frame this tag applies to. Frame token can be obtained using slGetNewFrameToken API. +//! @param viewport Specifies viewport this tag applies to +//! @param tags Pointer to resources tags, set to null to remove the specified tag +//! @param numTags Number of resource tags in the provided list +//! @param cmdBuffer Command buffer to use (optional and can be null if ALL tags are null or have eValidUntilPresent life-cycle) +//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details) +//! +//! IMPORTANT: GPU payload that generates content for the provided tag(s) MUST be either already submitted to the provided command buffer +//! or some other command buffer which is guaranteed, by the host application, to be executed BEFORE the provided command buffer. +//! +//! This method is thread safe and requires DX/VK device to be created before calling it. +SL_API sl::Result slSetTagForFrame(const sl::FrameToken& frame, const sl::ViewportHandle& viewport, const sl::ResourceTag* resources, uint32_t numResources, sl::CommandBuffer* cmdBuffer); + +//! NOTE: This API has now been DEPRECATED in favor of the new slSetTagForFrame API above. +//! Tags resource globally +//! +//! Call this method to tag the appropriate buffers in global scope. +//! +//! @param viewport Specifies viewport this tag applies to +//! @param tags Pointer to resources tags, set to null to remove the specified tag +//! @param numTags Number of resource tags in the provided list +//! @param cmdBuffer Command buffer to use (optional and can be null if ALL tags are null or have eValidUntilPresent life-cycle) +//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details) +//! +//! IMPORTANT: GPU payload that generates content for the provided tag(s) MUST be either already submitted to the provided command buffer +//! or some other command buffer which is guaranteed, by the host application, to be executed BEFORE the provided command buffer. +//! +//! This method is thread safe and requires DX/VK device to be created before calling it. +SL_API +#if __cplusplus >= 201402L +[[deprecated("Use the version of this function that takes a sl::FrameToken instead - slSetTagForFrame and set sl::PreferenceFlags::eUseFrameBasedResourceTagging.")]] +#endif +sl::Result slSetTag(const sl::ViewportHandle& viewport, const sl::ResourceTag* tags, uint32_t numTags, sl::CommandBuffer* cmdBuffer); + +//! Sets common constants. +//! +//! Call this method to provide the required data (SL will keep a copy). +//! +//! @param values Common constants required by SL plugins (SL will keep a copy) +//! @param frame Index of the current frame +//! @param viewport Unique id (can be viewport id | instance id etc.) +//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details) +//! +//! This method is thread safe and requires DX/VK device to be created before calling it. +SL_API sl::Result slSetConstants(const sl::Constants& values, const sl::FrameToken& frame, const sl::ViewportHandle& viewport); + +//! Returns feature's requirements +//! +//! Call this method to check what is required to run certain eFeature* (see above). +//! This method must be called after init otherwise it will always return an error. +//! +//! @param feature Specifies which feature to check +//! @param requirements Data structure with feature's requirements +//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details) +//! +//! This method is NOT thread safe. +SL_API sl::Result slGetFeatureRequirements(sl::Feature feature, sl::FeatureRequirements& requirements); + +//! Returns feature's version +//! +//! Call this method to check version for a certain eFeature* (see above). +//! This method must be called after init otherwise it will always return an error. +//! +//! @param feature Specifies which feature to check +//! @param version Data structure with feature's version +//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details) +//! +//! This method is thread safe. +SL_API sl::Result slGetFeatureVersion(sl::Feature feature, sl::FeatureVersion& version); + +//! Allocates resources for the specified feature. +//! +//! Call this method to explicitly allocate resources +//! for an instance of the specified feature. +//! +//! @param cmdBuffer Command buffer to use (must be created on device where feature is supported but can be null if not needed) +//! @param feature Feature we are working with +//! @param viewport Unique id (viewport handle) +//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details) +//! +//! This method is NOT thread safe and requires DX/VK device to be created before calling it. +SL_API sl::Result slAllocateResources(sl::CommandBuffer* cmdBuffer, sl::Feature feature, const sl::ViewportHandle& viewport); + +//! Frees resources for the specified feature. +//! +//! Call this method to explicitly free resources +//! for an instance of the specified feature. +//! +//! @param feature Feature we are working with +//! @param viewport Unique id (viewport handle) +//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details) +//! +//! IMPORTANT: If slEvaluateFeature is pending on a command list, that command list must be flushed +//! before calling this method to prevent invalid resource access on the GPU. +//! +//! IMPORTANT: If slEvaluateFeature is pending on a command list, that command list must be flushed +//! before calling this method to prevent invalid resource access on the GPU. +//! +//! This method is NOT thread safe and requires DX/VK device to be created before calling it. +SL_API sl::Result slFreeResources(sl::Feature feature, const sl::ViewportHandle& viewport); + +//! NOTE: sl::PreferenceFlags::eUseFrameBasedResourceTagging must be set when using this API to do +//! frame-based resource tagging for multiple frames in flight at the same time. +//! Evaluates feature +//! +//! Use this method to mark the section in your rendering pipeline +//! where specific feature should be injected. +//! +//! @param feature Feature we are working with +//! @param frame Current frame handle obtained from SL +//! @param inputs The chained structures providing the input data (viewport, tags, constants etc) +//! @param numInputs Number of inputs +//! @param cmdBuffer Command buffer to use (must be created on device where feature is supported) +//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details) +//! +//! IMPORTANT: Frame and viewport must match whatever is used to set common and or feature options and constants (if any) +//! +//! NOTE: It is allowed to pass in buffer tags as inputs, they are considered to be a "local" tags and do NOT interact with +//! same tags sent in the global scope using slSetTag API. +//! +//! This method is NOT thread safe and requires DX/VK device to be created before calling it. +SL_API sl::Result slEvaluateFeature(sl::Feature feature, const sl::FrameToken& frame, const sl::BaseStructure** inputs, uint32_t numInputs, sl::CommandBuffer* cmdBuffer); + +//! Upgrade interface +//! +//! Use this method to upgrade basic D3D or DXGI interface to an SL proxy. +//! +//! @param baseInterface Pointer to a pointer to the base interface (for example ID3D12Device etc.) to be replaced in place. +//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details) +//! +//! IMPORTANT: This method should ONLY be used to support 3rd party SDKs like AMD AGS +//! which bypass SL or when using manual hooking. +//! +//! This method is NOT thread safe and should be called IMMEDIATELY after base interface is created. +SL_API sl::Result slUpgradeInterface(void** baseInterface); + +//! Obtain native interface +//! +//! Use this method to obtain underlying D3D or DXGI interface from an SL proxy. +//! +//! IMPORTANT: When calling NVAPI or other 3rd party SDKs from your application +//! it is recommended to provide native interfaces instead of SL proxies. +//! +//! @param proxyInterface Pointer to the SL proxy (D3D device, swap-chain etc) +//! @param baseInterface Pointer to a pointer to the base interface be returned. +//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details) +//! +//! This method is NOT thread safe +SL_API sl::Result slGetNativeInterface(void* proxyInterface, void** baseInterface); + +//! Gets specific feature's function +//! +//! Call this method to obtain various functions for the specified feature. See sl_$feature.h for details. +//! +//! @param feature Feature we are working with +//! @param functionName The name of the API to obtain (declared in sl_[$feature].h +//! @param function Pointer to the function to return +//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details) +//! +//! IMPORTANT: Must be called AFTER device is set by calling either slSetD3DDevice or slSetVulkanInfo. +//! +//! This method is thread safe. +SL_API sl::Result slGetFeatureFunction(sl::Feature feature, const char* functionName, void*& function); + +//! Gets unique frame token +//! +//! Call this method to obtain token for the unique frame identification. +//! +//! @param handle Frame token to return +//! @param frameIndex Frame index (optional, if not provided SL internal frame counting is used) +//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details) +//! +//! NOTE: Normally SL would not expect more that 3 frames in flight due to added latency. +//! +//! This method is thread safe. +SL_API sl::Result slGetNewFrameToken(sl::FrameToken*& token, const uint32_t* frameIndex = nullptr); + +//! Set D3D device to use +//! +//! Use this method to specify which D3D device should be used. +//! +//! @param d3dDevice D3D device to use +//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details) +//! +//! This method is NOT thread safe and should be called IMMEDIATELY after main device is created. +SL_API sl::Result slSetD3DDevice(void* d3dDevice); + +#pragma endregion SL_API diff --git a/third_party/streamline/include/sl_core_types.h b/third_party/streamline/include/sl_core_types.h new file mode 100644 index 000000000..aa38649a1 --- /dev/null +++ b/third_party/streamline/include/sl_core_types.h @@ -0,0 +1,781 @@ +/* +* Copyright (c) 2022-2024 NVIDIA CORPORATION. All rights reserved +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +#pragma once + +#include +#include + +#include "sl_struct.h" +#include "sl_consts.h" +#include "sl_version.h" +#include "sl_result.h" +#include "sl_appidentity.h" +#include "sl_device_wrappers.h" + +typedef struct ID3D11Resource ID3D11Resource; +typedef struct ID3D11Buffer ID3D11Buffer; +typedef struct ID3D11Texture2D ID3D11Texture2D; +typedef struct ID3D12Resource ID3D12Resource; + +// Forward declarations matching MS and VK specs +#ifdef VK_VERSION_1_0 +using SL_VKResult = VkResult; +#else +using SL_VKResult = int; +#endif +using HRESULT = long; + +namespace sl { + +using CommandBuffer = void; +using Device = void; + +//! Buffer types used for tagging +//! +//! IMPORTANT: Each tag must use the unique id +//! +using BufferType = uint32_t; + +// Friend function declaration to access private members for ABI validation static_asserts +namespace test +{ +constexpr void AbiValidation(); +} + +//! Depth buffer - IMPORTANT - Must be suitable to use with clipToPrevClip transformation (see Constants below) +constexpr BufferType kBufferTypeDepth = 0; +//! Object and optional camera motion vectors (see Constants below) +constexpr BufferType kBufferTypeMotionVectors = 1; +//! Color buffer with all post-processing effects applied but without any UI/HUD elements +constexpr BufferType kBufferTypeHUDLessColor = 2; +//! Color buffer containing jittered input data for the image scaling pass +constexpr BufferType kBufferTypeScalingInputColor = 3; +//! Color buffer containing results from the image scaling pass +constexpr BufferType kBufferTypeScalingOutputColor = 4; +//! Normals +constexpr BufferType kBufferTypeNormals = 5; +//! Roughness +constexpr BufferType kBufferTypeRoughness = 6; +//! Albedo +constexpr BufferType kBufferTypeAlbedo = 7; +//! Specular Albedo +constexpr BufferType kBufferTypeSpecularAlbedo = 8; +//! Indirect Albedo +constexpr BufferType kBufferTypeIndirectAlbedo = 9; +//! Specular Motion Vectors +constexpr BufferType kBufferTypeSpecularMotionVectors = 10; +//! Disocclusion Mask +constexpr BufferType kBufferTypeDisocclusionMask = 11; +//! Emissive +constexpr BufferType kBufferTypeEmissive = 12; +//! Exposure +constexpr BufferType kBufferTypeExposure = 13; +//! Buffer with normal and roughness in alpha channel +constexpr BufferType kBufferTypeNormalRoughness = 14; +//! Diffuse and camera ray length +constexpr BufferType kBufferTypeDiffuseHitNoisy = 15; +//! Diffuse denoised +constexpr BufferType kBufferTypeDiffuseHitDenoised = 16; +//! Specular and reflected ray length +constexpr BufferType kBufferTypeSpecularHitNoisy = 17; +//! Specular denoised +constexpr BufferType kBufferTypeSpecularHitDenoised = 18; +//! Shadow noisy +constexpr BufferType kBufferTypeShadowNoisy = 19; +//! Shadow denoised +constexpr BufferType kBufferTypeShadowDenoised = 20; +//! AO noisy +constexpr BufferType kBufferTypeAmbientOcclusionNoisy = 21; +//! AO denoised +constexpr BufferType kBufferTypeAmbientOcclusionDenoised = 22; +//! Optional - UI/HUD color and alpha +//! IMPORTANT: Please make sure that alpha channel has enough precision (for example do NOT use formats like R10G10B10A2) +constexpr BufferType kBufferTypeUIColorAndAlpha = 23; +//! Optional - Shadow pixels hint (set to 1 if a pixel belongs to the shadow area, 0 otherwise) +constexpr BufferType kBufferTypeShadowHint = 24; +//! Optional - Reflection pixels hint (set to 1 if a pixel belongs to the reflection area, 0 otherwise) +constexpr BufferType kBufferTypeReflectionHint = 25; +//! Optional - Particle pixels hint (set to 1 if a pixel represents a particle, 0 otherwise) +constexpr BufferType kBufferTypeParticleHint = 26; +//! Optional - Transparency pixels hint (set to 1 if a pixel belongs to the transparent area, 0 otherwise) +constexpr BufferType kBufferTypeTransparencyHint = 27; +//! Optional - Animated texture pixels hint (set to 1 if a pixel belongs to the animated texture area, 0 otherwise) +constexpr BufferType kBufferTypeAnimatedTextureHint = 28; +//! Optional - Bias for current color vs history hint - lerp(history, current, bias) (set to 1 to completely reject history) +constexpr BufferType kBufferTypeBiasCurrentColorHint = 29; +//! Optional - Ray-tracing distance (camera ray length) +constexpr BufferType kBufferTypeRaytracingDistance = 30; +//! Optional - Motion vectors for reflections +constexpr BufferType kBufferTypeReflectionMotionVectors = 31; +//! Optional - Position, in same space as eNormals +constexpr BufferType kBufferTypePosition = 32; +//! Optional - Indicates (via non-zero value) which pixels have motion/depth values that do not match the final color content at that pixel (e.g. overlaid, opaque Picture-in-Picture) +constexpr BufferType kBufferTypeInvalidDepthMotionHint = 33; +//! Alpha +constexpr BufferType kBufferTypeAlpha = 34; +//! Color buffer containing only opaque geometry +constexpr BufferType kBufferTypeOpaqueColor = 35; +//! Optional - Reduce reliance on history instead using current frame hint (0 if a pixel is not at all reactive and default composition should be used, 1 if fully reactive) +constexpr BufferType kBufferTypeReactiveMaskHint = 36; +//! Optional - Pixel lock adjustment hint (set to 1 if pixel lock should be completely removed, 0 otherwise) +constexpr BufferType kBufferTypeTransparencyAndCompositionMaskHint = 37; +//! Optional - Albedo of the reflection ray hit point. For multibounce reflections, this should be the albedo of the first non-specular bounce. +constexpr BufferType kBufferTypeReflectedAlbedo = 38; +//! Optional - Color buffer before particles are drawn. +constexpr BufferType kBufferTypeColorBeforeParticles = 39; +//! Optional - Color buffer before transparent objects are drawn. +constexpr BufferType kBufferTypeColorBeforeTransparency = 40; +//! Optional - Color buffer before fog is drawn. +constexpr BufferType kBufferTypeColorBeforeFog = 41; +//! Optional - Buffer containing the hit distance of a specular ray. +constexpr BufferType kBufferTypeSpecularHitDistance = 42; +//! Optional - Buffer that contains 3 components of a specular ray direction, and 1 component of specular hit distance. +constexpr BufferType kBufferTypeSpecularRayDirectionHitDistance = 43; +//! Optional - Buffer containing normalized direction of a specular ray. +constexpr BufferType kBufferTypeSpecularRayDirection = 44; +// !Optional - Buffer containing the hit distance of a diffuse ray. +constexpr BufferType kBufferTypeDiffuseHitDistance = 45; +//! Optional - Buffer that contains 3 components of a diffuse ray direction, and 1 component of diffuse hit distance. +constexpr BufferType kBufferTypeDiffuseRayDirectionHitDistance = 46; +//! Optional - Buffer containing normalized direction of a diffuse ray. +constexpr BufferType kBufferTypeDiffuseRayDirection = 47; +//! Optional - Buffer containing display resolution depth. +constexpr BufferType kBufferTypeHiResDepth = 48; +//! Required either this or kBufferTypeDepth - Buffer containing linear depth. +constexpr BufferType kBufferTypeLinearDepth = 49; +//! Optional - Bidirectional distortion field. 4 channels in normalized [0,1] pixel space. RG = distorted pixel to undistorted pixel displacement. BA = undistorted pixel to distorted pixel displacement. +constexpr BufferType kBufferTypeBidirectionalDistortionField = 50; +//!Optional - Buffer containing particles or other similar transparent effects rendered into it instead of passing it as part of the input color +constexpr BufferType kBufferTypeTransparencyLayer = 51; +//!Optional - Buffer to be used in addition to TransparencyLayer which allows 3-channels of Opacity versus 1-channel. +// In this case, TransparencyLayer represents Color (RcGcBc), TransparencyLayerOpacity represents alpha (RaGaBa)' +constexpr BufferType kBufferTypeTransparencyLayerOpacity = 52; +//! Optional - Swapchain buffer to be presented +constexpr BufferType kBufferTypeBackbuffer = 53; +//! Optional - Mask for pixels to skip warping +constexpr BufferType kBufferTypeNoWarpMask = 54; +//! Optional - Color buffer after particles are drawn (for research purposes) +constexpr BufferType kBufferTypeColorAfterParticles = 55; +//! Optional - Color buffer after transparent objects are drawn (for research purposes) +constexpr BufferType kBufferTypeColorAfterTransparency = 56; +//! Optional - Color buffer after fog is drawn (for research purposes) +constexpr BufferType kBufferTypeColorAfterFog = 57; +//! Optional - Subsurface scattering guide buffer +constexpr BufferType kBufferTypeScreenSpaceSubsurfaceScatteringGuide = 58; +//! Optional - Color buffer before subsurface scattering (for research purposes) +constexpr BufferType kBufferTypeColorBeforeScreenSpaceSubsurfaceScattering = 59; +//! Optional - Color buffer after subsurface scattering (for research purposes) +constexpr BufferType kBufferTypeColorAfterScreenSpaceSubsurfaceScattering = 60; +//! Optional - Refraction guide buffer (for research purposes) +constexpr BufferType kBufferTypeScreenSpaceRefractionGuide = 61; +//! Optional - Color buffer before refraction (for research purposes) +constexpr BufferType kBufferTypeColorBeforeScreenSpaceRefraction = 62; +//! Optional - Color buffer after refraction (for research purposes) +constexpr BufferType kBufferTypeColorAfterScreenSpaceRefraction = 63; +//! Optional - Depth of Field Buffer (for research purposes) +constexpr BufferType kBufferTypeDepthOfFieldGuide = 64; +//! Optional - Color buffer before Depth of Field (for research purposes) +constexpr BufferType kBufferTypeColorBeforeDepthOfField = 65; +//! Optional - Color buffer after Depth of Field (for research purposes) +constexpr BufferType kBufferTypeColorAfterDepthOfField = 66; +//! Optional - Color buffer that overrides the alpha channel of kBufferTypeScalingOutputColor +constexpr BufferType kBufferTypeScalingOutputAlpha = 67; +//! Optional buffer for responsivity mask +constexpr BufferType kBufferTypeResponsivityMask = 68; +//! Optional - UI Alpha +//! A 1 channel resource containing the alpha value of on-screen elements, between 0.0f and 1.0f inclusive. +//! Similar to kBufferTypeUIColorAndAlpha, but only the alpha channel for optimized run-time performance. +constexpr BufferType kBufferTypeUIAlpha = 69; +//! Input color for neural-net "uplift" passes +constexpr BufferType kBufferTypeUpliftInputColor = 70; +//! Output color for neural-net "uplift" passes +//! May alias kBufferTypeUpliftInputColor (in-place uplift); the feature transitions appropriately. +constexpr BufferType kBufferTypeUpliftOutputColor = 71; +//! Optional - 4-channel control mask consumed by uplift passes +constexpr BufferType kBufferTypeUpliftControlMask = 72; + +//! Features supported with this SDK +//! +//! IMPORTANT: Each feature must use a unique id +//! +using Feature = uint32_t; + +//! Deep Learning Super Sampling +constexpr Feature kFeatureDLSS = 0; + +//! Real-Time Denoiser (removed) +constexpr Feature kFeatureNRD_INVALID = 1; + +//! NVIDIA Image Scaling +constexpr Feature kFeatureNIS = 2; + +//! Reflex +constexpr Feature kFeatureReflex = 3; + +//! PC Latency +constexpr Feature kFeaturePCL = 4; + +//! DeepDVC +constexpr Feature kFeatureDeepDVC = 5; + +constexpr Feature kFeatureLatewarp = 6; + +//! DLSS Frame Generation +constexpr Feature kFeatureDLSS_G = 1000; + +//! DLSS Ray Reconstruction +constexpr Feature kFeatureDLSS_RR = 1001; + +constexpr Feature kFeatureNvPerf = 1002; + +constexpr Feature kFeatureDirectSR = 1003; + +constexpr Feature kFeatureDLSS_NR = 1004; + +// ImGUI +constexpr Feature kFeatureImGUI = 9999; + +#if defined(SL_UNITTEST_ONLY_CODE) +//! Dummy plugin for testing plugin.cpp functionality +constexpr Feature kFeatureDummyPlugin = 65534; +#endif + +//! Common feature, NOT intended to be used directly +constexpr Feature kFeatureCommon = UINT_MAX; + +//! Different levels for logging +enum class LogLevel : uint32_t +{ + //! No logging + eOff, + //! Default logging + eDefault, + //! Verbose logging + eVerbose, + //! Total count + eCount +}; + +//! Resource types +enum class ResourceType : char +{ + eTex2d, + eBuffer, + eCommandQueue, + eCommandBuffer, + eCommandPool, + eFence, + eSwapchain, + eHostFence, + // this type means that the only thing we know for sure about this resource is that it's castable to IUnknown + eUnknown, + eCount +}; + +//! Resource allocate information +//! +SL_STRUCT_BEGIN(ResourceAllocationDesc, StructType({ 0xbb57e5, 0x49a2, 0x4c23, { 0xa5, 0x19, 0xab, 0x92, 0x86, 0xe7, 0x40, 0x14 } }), kStructVersion1) + ResourceAllocationDesc(ResourceType _type, void* _desc, uint32_t _state, void* _heap) : BaseStructure(ResourceAllocationDesc::s_structType, kStructVersion1), type(_type),desc(_desc),state(_state),heap(_heap){}; + //! Indicates the type of resource + ResourceType type = ResourceType::eTex2d; + //! D3D12_RESOURCE_DESC/VkImageCreateInfo/VkBufferCreateInfo + void* desc{}; + //! Initial state as D3D12_RESOURCE_STATES or VkMemoryPropertyFlags + uint32_t state = 0; + //! CD3DX12_HEAP_PROPERTIES or nullptr + void* heap{}; + + //! IMPORTANT: New members go here or if optional can be chained in a new struct, see sl_struct.h for details +SL_STRUCT_END() + + +//! Subresource range information, for Vulkan resources +//! +//! {8D4C316C-D402-4524-89A7-14E79E638E3A} +SL_STRUCT_BEGIN(SubresourceRange, StructType({ 0x8d4c316c, 0xd402, 0x4524, { 0x89, 0xa7, 0x14, 0xe7, 0x9e, 0x63, 0x8e, 0x3a } }), kStructVersion1) + //! Vulkan subresource aspectMask + uint32_t aspectMask; + //! Vulkan subresource baseMipLevel + uint32_t baseMipLevel; + //! Vulkan subresource levelCount + uint32_t levelCount; + //! Vulkan subresource baseArrayLayer + uint32_t baseArrayLayer; + //! Vulkan subresource layerCount + uint32_t layerCount; +SL_STRUCT_END() + +//! Native resource +//! +//! {3A9D70CF-2418-4B72-8391-13F8721C7261} +SL_STRUCT_BEGIN(Resource, StructType({ 0x3a9d70cf, 0x2418, 0x4b72, { 0x83, 0x91, 0x13, 0xf8, 0x72, 0x1c, 0x72, 0x61 } }), kStructVersion1) + //! Constructors + //! + //! Resource type, native pointer are MANDATORY always + //! Resource state is MANDATORY unless using D3D11 + //! Resource view, description etc. are MANDATORY only when using Vulkan + //! + Resource(ResourceType _type, void* _native, void* _mem, void* _view, uint32_t _state = UINT_MAX) : BaseStructure(Resource::s_structType, kStructVersion1), type(_type), native(_native), memory(_mem), view(_view), state(_state){}; + Resource(ResourceType _type, void* _native, uint32_t _state = UINT_MAX) : BaseStructure(Resource::s_structType, kStructVersion1), type(_type), native(_native), state(_state) {}; + + //! Conversion helpers for D3D + inline operator ID3D12Resource* () { return reinterpret_cast(native); } + inline operator ID3D11Resource* () { return reinterpret_cast(native); } + inline operator ID3D11Buffer* () { return reinterpret_cast(native); } + inline operator ID3D11Texture2D* () { return reinterpret_cast(native); } + + //! Indicates the type of resource + ResourceType type = ResourceType::eTex2d; + //! ID3D11Resource/ID3D12Resource/VkBuffer/VkImage + void* native{}; + //! vkDeviceMemory or nullptr + void* memory{}; + //! VkImageView/VkBufferView or nullptr + void* view{}; + //! State as D3D12_RESOURCE_STATES or VkImageLayout + //! + //! IMPORTANT: State is MANDATORY and needs to be correct when tagged resources are actually used. + //! + uint32_t state = UINT_MAX; + //! Width in pixels + uint32_t width{}; + //! Height in pixels + uint32_t height{}; + //! Native format + uint32_t nativeFormat{}; + //! Number of mip-map levels + uint32_t mipLevels{}; + //! Number of arrays + uint32_t arrayLayers{}; + //! Virtual address on GPU (if applicable) + uint64_t gpuVirtualAddress{}; + //! VkImageCreateFlags + uint32_t flags; + //! VkImageUsageFlags + uint32_t usage{}; + //! Internal flags (bitfield) - do not modify + enum InternalFlags : uint16_t + { + eNone = 0, + //! Resource wraps a Vulkan swapchain image not allocated by SL or the host callback. + //! The release callback must not be invoked for such resources. + eVulkanSwapChainImage = 1 << 0, + }; + uint16_t internalFlags{}; + //! Reserved for future use + uint16_t reserved{}; + + //! IMPORTANT: New members go here or if optional can be chained in a new struct, see sl_struct.h for details +SL_STRUCT_END() + +//! Specifies life-cycle for the tagged resource +//! +//! IMPORTANT: Use 'eOnlyValidNow' and 'eValidUntilEvaluate' ONLY when really needed since it can result in wasting VRAM if SL ends up making unnecessary copies. +//! +//! If integrating features, like for example DLSS-G, which require tags to be 'eValidUntilPresent' please try to tag everything as 'eValidUntilPresent' first +//! and only make modifications if upon visual inspection you notice that tags are corrupted when used during the Present frame call. +enum ResourceLifecycle +{ + //! Resource can change, get destroyed or reused for other purposes after it is provided to SL + eOnlyValidNow, + //! Resource does NOT change, gets destroyed or reused for other purposes from the moment it is provided to SL until the frame is presented + eValidUntilPresent, + //! Resource does NOT change, gets destroyed or reused for other purposes from the moment it is provided to SL until after the slEvaluateFeature call has returned. + eValidUntilEvaluate +}; + +//! Tagged resource +//! +//! {4C6A5AAD-B445-496C-87FF-1AF3845BE653} +//! Extensions as part of the `next` ptr: +//! PrecisionInfo +SL_STRUCT_BEGIN(ResourceTag, StructType({ 0x4c6a5aad, 0xb445, 0x496c, { 0x87, 0xff, 0x1a, 0xf3, 0x84, 0x5b, 0xe6, 0x53 } }), kStructVersion1) + ResourceTag(Resource* r, BufferType t, ResourceLifecycle l, const Extent* e = nullptr) + : BaseStructure(ResourceTag::s_structType, kStructVersion1), resource(r), type(t), lifecycle(l) + { + if (e) extent = *e; + }; + + //! Resource description + Resource* resource{}; + //! Type of the tagged buffer + BufferType type{}; + //! The life-cycle for the tag, if resource is volatile a valid command buffer must be specified + ResourceLifecycle lifecycle{}; + //! The area of the tagged resource to use (if using the entire resource leave as null) + Extent extent{}; + + //! IMPORTANT: New members go here or if optional can be chained in a new struct, see sl_struct.h for details +SL_STRUCT_END() + +// +//! Precision info, optional extension for ResourceTag. +//! +//! {98F6E9BA-8D16-4831-A802-4D3B52FF26BF} +//! Extensions as part of the `next` ptr: +//! ResourceTag +SL_STRUCT_BEGIN(PrecisionInfo, StructType({ 0x98f6e9ba, 0x8d16, 0x4831, { 0xa8, 0x2, 0x4d, 0x3b, 0x52, 0xff, 0x26, 0xbf } }), kStructVersion1) + // Formula used to convert the low-precision data to high-precision + enum PrecisionFormula : uint32_t + { + eNoTransform = 0, // hi = lo, essentially no conversion is done + eLinearTransform, // hi = lo * scale + bias + }; + + PrecisionInfo(PrecisionInfo::PrecisionFormula formula, float bias, float scale) + : BaseStructure(PrecisionInfo::s_structType, kStructVersion1), conversionFormula(formula), bias(bias), scale(scale) {}; + + static std::string getPrecisionFormulaAsStr(PrecisionFormula formula) + { + switch (formula) + { + case eNoTransform: + return "eNoTransform"; + case eLinearTransform: + return "eLinearTransform"; + default: + assert("Invalid PrecisionFormula" && false); + return "Unknown"; + } + }; + + PrecisionFormula conversionFormula{ eNoTransform }; + float bias{ 0.0f }; + float scale{ 1.0f }; + + inline operator bool() const { return conversionFormula != eNoTransform; } + inline bool operator==(const PrecisionInfo& rhs) const + { + return conversionFormula == rhs.conversionFormula && bias == rhs.bias && scale == rhs.scale; + } + inline bool operator!=(const PrecisionInfo& rhs) const + { + return !operator==(rhs); + } +SL_STRUCT_END() + +//! Resource allocation/deallocation callbacks +//! +//! Use these callbacks to gain full control over +//! resource life cycle and memory allocation tracking. +//! +//! @param device - Device to be used (vkDevice or ID3D11Device or ID3D12Device) +//! +//! IMPORTANT: Textures must have the pixel shader resource +//! and the unordered access view flags set +using PFun_ResourceAllocateCallback = Resource(const ResourceAllocationDesc* desc, void* device); +using PFun_ResourceReleaseCallback = void(Resource* resource, void* device); + +//! Log type +enum class LogType : uint32_t +{ + //! Controlled by LogLevel, SL can show more information in eLogLevelVerbose mode + eInfo, + //! Always shown regardless of LogLevel + eWarn, + eError, + //! Total count + eCount +}; + +//! Logging callback +//! +//! Use these callbacks to track messages posted in the log. +//! If any of the SL methods returns false use eLogTypeError +//! type to track down what went wrong and why. +using PFun_LogMessageCallback = void(LogType type, const char* msg); + +struct APIError +{ + union + { + HRESULT hres; + SL_VKResult vkRes; + }; +}; +//! Returns an error returned by DXGI or Vulkan API calls 'vkQueuePresentKHR' and 'vkAcquireNextImageKHR' +using PFunOnAPIErrorCallback = void(const APIError& lastError); + +//! Optional flags +enum class PreferenceFlags : uint64_t +{ + //! Set by default - Disables command list state tracking - Host application is responsible for restoring CL state correctly after each 'slEvaluateFeature' call + eDisableCLStateTracking = 1 << 0, + //! Optional - Disables debug text on screen in development builds + eDisableDebugText = 1 << 1, + //! Optional - IMPORTANT: Only to be used in the advanced integration mode, see the 'manual hooking' programming guide for more details + eUseManualHooking = 1 << 2, + //! Optional - Enables downloading of Over The Air (OTA) updates for SL and NGX + //! This will invoke the OTA updater to look for new updates. A separate + //! flag below is used to control whether or not OTA-downloaded SL Plugins are + //! loaded. + eAllowOTA = 1 << 3, + //! Do not check OS version when deciding if feature is supported or not + //! + //! IMPORTANT: ONLY SET THIS FLAG IF YOU KNOW WHAT YOU ARE DOING. + //! + //! VARIOUS WIN APIs INCLUDING BUT NOT LIMITED TO `IsWindowsXXX`, `GetVersionX`, `rtlGetVersion` ARE KNOWN FOR RETURNING INCORRECT RESULTS. + eBypassOSVersionCheck = 1 << 4, + //! Optional - If specified SL will create DXGI factory proxy rather than modifying the v-table for the base interface. + //! + //! This can help with 3rd party overlays which are NOT integrated with the host application but rather operate via injection. + eUseDXGIFactoryProxy = 1 << 5, + //! Optional - Enables loading of plugins downloaded Over The Air (OTA), to + //! be used in conjunction with the eAllowOTA flag. + eLoadDownloadedPlugins = 1 << 6, + + //! Optional - allow tagging of resources for frame. This helps distinguish whether slEvaluateFeature needs to do frame-based tagging + //! of resources which wasn't the case earlier. + eUseFrameBasedResourceTagging = 1 << 7, + + //! All preference flags. This isn't expected to be used directly by integrations, but may be useful for e.g. writing helpers. + eAll = eDisableCLStateTracking | eDisableDebugText | eUseManualHooking | eAllowOTA | eBypassOSVersionCheck | eUseDXGIFactoryProxy | eLoadDownloadedPlugins | eUseFrameBasedResourceTagging +}; + +SL_ENUM_OPERATORS_64(PreferenceFlags) + +//! Application preferences +//! +//! {1CA10965-BF8E-432B-8DA1-6716D879FB14} +SL_STRUCT_BEGIN(Preferences, StructType({ 0x1ca10965, 0xbf8e, 0x432b, { 0x8d, 0xa1, 0x67, 0x16, 0xd8, 0x79, 0xfb, 0x14 } }), kStructVersion1) + //! Optional - In non-production builds it is useful to enable debugging console window + bool showConsole = false; + //! Optional - Various logging levels + LogLevel logLevel = LogLevel::eDefault; + //! Optional - Absolute paths to locations where to look for plugins, first path in the list has the highest priority + const wchar_t** pathsToPlugins{}; + //! Optional - Number of paths to search + uint32_t numPathsToPlugins = 0; + //! Optional - Absolute path to location where logs and other data should be stored + //! + //! NOTE: Set this to nullptr in order to disable logging to a file + const wchar_t* pathToLogsAndData{}; + //! Optional - Allows resource allocation tracking on the host side + PFun_ResourceAllocateCallback* allocateCallback{}; + //! Optional - Allows resource deallocation tracking on the host side + PFun_ResourceReleaseCallback* releaseCallback{}; + //! Optional - Allows log message tracking including critical errors if they occur + PFun_LogMessageCallback* logMessageCallback{}; + //! Optional - Flags used to enable or disable advanced options + PreferenceFlags flags = PreferenceFlags::eDisableCLStateTracking | PreferenceFlags::eAllowOTA | PreferenceFlags::eLoadDownloadedPlugins; + //! Required - Features to load (assuming appropriate plugins are found), if not specified NO features will be loaded by default + const Feature* featuresToLoad{}; + //! Required - Number of features to load, only used when list is not a null pointer + uint32_t numFeaturesToLoad{}; + //! Optional - Id provided by NVIDIA, if not specified then engine type and version are required + uint32_t applicationId{}; + //! Optional - Type of the rendering engine used, if not specified then applicationId is required + EngineType engine = EngineType::eCustom; + //! Optional - Version of the rendering engine used + const char* engineVersion{}; + //! Optional - GUID (like for example 'a0f57b54-1daf-4934-90ae-c4035c19df04') + const char* projectId{}; + //! Optional - Which rendering API host is planning to use + //! + //! NOTE: To ensure correct `slGetFeatureRequirements` behavior please specify if planning to use Vulkan. + RenderAPI renderAPI = RenderAPI::eD3D12; + + //! IMPORTANT: New members go here or if optional can be chained in a new struct, see sl_struct.h for details +SL_STRUCT_END() + +//! Frame tracking handle +//! +//! IMPORTANT: Use slGetNewFrameToken to obtain unique instance +//! +//! {830A0F35-DB84-4171-A804-59B206499B18} +SL_STRUCT_PROTECTED_BEGIN(FrameToken, StructType({ 0x830a0f35, 0xdb84, 0x4171, { 0xa8, 0x4, 0x59, 0xb2, 0x6, 0x49, 0x9b, 0x18 } }), kStructVersion1) + //! Helper operator to obtain current frame index + virtual operator uint32_t() const = 0; +SL_STRUCT_END() + +//! Handle for the unique viewport +//! +//! {171B6435-9B3C-4FC8-9994-FBE52569AAA4} +SL_STRUCT_BEGIN(ViewportHandle, StructType({ 0x171b6435, 0x9b3c, 0x4fc8, { 0x99, 0x94, 0xfb, 0xe5, 0x25, 0x69, 0xaa, 0xa4 } }), kStructVersion1) + ViewportHandle(uint32_t v) : BaseStructure(ViewportHandle::s_structType, kStructVersion1), value(v) {} + ViewportHandle(int32_t v) : BaseStructure(ViewportHandle::s_structType, kStructVersion1), value(v) {} + operator uint32_t() const { return value; } +private: + uint32_t value = UINT_MAX; + friend constexpr void sl::test::AbiValidation(); +SL_STRUCT_END() + +//! Specifies feature requirement flags +//! +enum class FeatureRequirementFlags : uint32_t +{ + //! Rendering APIs + eD3D11Supported = 1 << 0, + eD3D12Supported = 1 << 1, + eVulkanSupported = 1 << 2, + //! If set V-Sync must be disabled when feature is active + eVSyncOffRequired = 1 << 3, + //! If set GPU hardware scheduling OS feature must be turned on + eHardwareSchedulingRequired = 1 << 4, + + //! All feature requirement flags. This isn't expected to be used directly by integrations, but may be useful for e.g. writing helpers. + eAll = eD3D11Supported | eD3D12Supported | eVulkanSupported | eVSyncOffRequired | eHardwareSchedulingRequired +}; + +SL_ENUM_OPERATORS_32(FeatureRequirementFlags); + +//! Specifies feature requirements +//! +//! {66714097-AC6D-4BC6-8915-1E0F55A6B61F} +SL_STRUCT_BEGIN(FeatureRequirements, StructType({ 0x66714097, 0xac6d, 0x4bc6, { 0x89, 0x15, 0x1e, 0xf, 0x55, 0xa6, 0xb6, 0x1f } }), kStructVersion2) + //! Various Flags + FeatureRequirementFlags flags {}; + + //! Feature will create this many CPU threads + uint32_t maxNumCPUThreads{}; + + //! Feature supports only this many viewports + uint32_t maxNumViewports{}; + + //! Required buffer tags + uint32_t numRequiredTags{}; + const BufferType* requiredTags{}; + + //! OS and Driver versions + Version osVersionDetected{}; + Version osVersionRequired{}; + Version driverVersionDetected{}; + Version driverVersionRequired{}; + + //! Vulkan specific bits + + //! Command queues + uint32_t vkNumComputeQueuesRequired{}; + uint32_t vkNumGraphicsQueuesRequired{}; + + //! Device extensions + uint32_t vkNumDeviceExtensions{}; + const char** vkDeviceExtensions{}; + //! Instance extensions + uint32_t vkNumInstanceExtensions{}; + const char** vkInstanceExtensions{}; + //! 1.2 features + //! + //! NOTE: Use getVkPhysicalDeviceVulkan12Features from sl_helpers_vk.h + uint32_t vkNumFeatures12{}; + const char** vkFeatures12{}; + //! 1.3 features + //! + //! NOTE: Use getVkPhysicalDeviceVulkan13Features from sl_helpers_vk.h + uint32_t vkNumFeatures13{}; + const char** vkFeatures13{}; + + //! Vulkan optical flow feature + uint32_t vkNumOpticalFlowQueuesRequired{}; + + //! IMPORTANT: New members go here or if optional can be chained in a new struct, see sl_struct.h for details +SL_STRUCT_END() + +//! Specifies feature's version +//! +//! {6D5B51F0-076B-486D-9995-5A561043F5C1} +SL_STRUCT_BEGIN(FeatureVersion, StructType({ 0x6d5b51f0, 0x76b, 0x486d, { 0x99, 0x95, 0x5a, 0x56, 0x10, 0x43, 0xf5, 0xc1 } }), kStructVersion1) + //! SL version + Version versionSL{}; + //! NGX version (if feature is using NGX, null otherwise) + Version versionNGX{}; + + //! IMPORTANT: New members go here or if optional can be chained in a new struct, see sl_struct.h for details +SL_STRUCT_END() + +//! Specifies either DXGI adapter or VK physical device +//! +//! {0677315F-A746-4492-9F42-CB6142C9C3D4} +SL_STRUCT_BEGIN(AdapterInfo, StructType({ 0x677315f, 0xa746, 0x4492, { 0x9f, 0x42, 0xcb, 0x61, 0x42, 0xc9, 0xc3, 0xd4 } }), kStructVersion1) + //! Locally unique identifier + uint8_t* deviceLUID {}; + //! Size in bytes + uint32_t deviceLUIDSizeInBytes{}; + //! Vulkan Specific, if specified LUID will be ignored + void* vkPhysicalDevice{}; + + //! IMPORTANT: New members go here or if optional can be chained in a new struct, see sl_struct.h for details +SL_STRUCT_END() + +//! A simple array wrapper designed for safe use across DLL boundaries. +//! Since different DLLs may use different memory allocators, this class +//! relies on an IAllocator pointer to ensure that memory is allocated +//! and freed consistently within the same runtime. +struct IAllocator +{ + virtual ~IAllocator() = default; + virtual void *allocate(uint32_t nBytes) = 0; + virtual void free(void *p) = 0; +}; +template +struct Array +{ + inline Array() {} + inline ~Array() { destroy(); } + inline uint32_t size() const { return m_size; } + inline void copyFrom(IAllocator *pAllocator, const std::vector& src) + { + // if they give us data - we need the allocator + assert(pAllocator || src.size() == 0); + destroy(); + if (src.size() == 0) return; + m_pAllocator = pAllocator; + m_size = static_cast(src.size()); + m_pData = (T*)m_pAllocator->allocate(m_size * sizeof(T)); + for (uint32_t i = 0; i < m_size; ++i) + m_pData[i] = src[i]; + } + inline void copyTo(std::vector& dst) + { + dst.resize(m_size); + for (uint32_t i = 0; i < m_size; ++i) + dst[i] = m_pData[i]; + } + inline T& operator[](uint32_t index) + { + assert(index < m_size); + return m_pData[index]; + } + inline const T& operator[](uint32_t index) const + { + assert(index < m_size); + return m_pData[index]; + } + inline void destroy() + { + if (m_pData) m_pAllocator->free(m_pData); + m_pAllocator = nullptr; + m_pData = nullptr; + m_size = 0; + } + // Prevent copying + Array(const Array&) = delete; + Array& operator=(const Array&) = delete; + private: + T* m_pData{}; + uint32_t m_size{}; + // the allocator that was used to allocate memory + IAllocator *m_pAllocator{}; +}; + +} diff --git a/third_party/streamline/include/sl_deepdvc.h b/third_party/streamline/include/sl_deepdvc.h new file mode 100644 index 000000000..755cd95e6 --- /dev/null +++ b/third_party/streamline/include/sl_deepdvc.h @@ -0,0 +1,103 @@ +/* +* Copyright (c) 2022-2023 NVIDIA CORPORATION. All rights reserved +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +#pragma once + +#include "sl.h" +#include "sl_helpers.h" + +namespace sl +{ + +enum class DeepDVCMode : uint32_t +{ + eOff, + eOn, + eCount +}; + +// {23288AAD-7E7E-BE2A-916F-27DA30A3046B} +SL_STRUCT_BEGIN(DeepDVCOptions, StructType({ 0x23288aad, 0x7e7e, 0xbe2a, { 0x91, 0x67, 0x27, 0xda, 0x30, 0xa3, 0x04, 0x6b } }), kStructVersion1) + //! Specifies which mode should be used + DeepDVCMode mode = DeepDVCMode::eOff; + //! Specifies intensity level in range [0,1]. Default 0.5 + float intensity = 0.5f; + //! Specifies saturation boost in range [0,1]. Default 0.25 + float saturationBoost = 0.25f; +SL_STRUCT_END() + +//! Returned by the DeepDVC plugin +//! +// {934FD3D3-B34C-70A7-A139-F19FE04D91D3} +SL_STRUCT_BEGIN(DeepDVCState, StructType({ 0x934fd3d3, 0xb34c, 0x70a7, { 0xa1, 0x39, 0xf1, 0x9f, 0xe0, 0x4d, 0x91, 0xd3 } }), kStructVersion1) + //! Specified the amount of memory expected to be used + uint64_t estimatedVRAMUsageInBytes {}; +SL_STRUCT_END() + +} + +//! Sets DeepDVC options +//! +//! Call this method to turn DeepDVC on/off, change mode etc. +//! +//! @param viewport Specified viewport we are working with +//! @param options Specifies DeepDVC options to use +//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details) +//! +//! This method is NOT thread safe. +using PFun_slDeepDVCSetOptions = sl::Result(const sl::ViewportHandle& viewport, const sl::DeepDVCOptions& options); + +//! Provides DeepDVC state for the given viewport +//! +//! Call this method to obtain VRAM usage and other information. +//! +//! @param viewport Specified viewport we are working with +//! @param state Reference to a structure where state is to be returned +//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details) +//! +//! This method is NOT thread safe. +using PFun_slDeepDVCGetState = sl::Result(const sl::ViewportHandle& viewport, sl::DeepDVCState& state); + +//! HELPERS +//! +inline sl::Result slDeepDVCSetOptions(const sl::ViewportHandle& viewport, const sl::DeepDVCOptions& options) +{ + SL_FEATURE_FUN_IMPORT_STATIC(sl::kFeatureDeepDVC, slDeepDVCSetOptions); + return s_slDeepDVCSetOptions(viewport, options); +} + +inline sl::Result slDeepDVCGetState(const sl::ViewportHandle& viewport, sl::DeepDVCState& state) +{ + SL_FEATURE_FUN_IMPORT_STATIC(sl::kFeatureDeepDVC, slDeepDVCGetState); + return s_slDeepDVCGetState(viewport, state); +} +//#define SL_CASE_STR(a) case a : return #a; + +inline const char* getDeepDVCModeAsStr(sl::DeepDVCMode v) +{ + switch (v) + { + SL_CASE_STR(sl::DeepDVCMode::eOff); + SL_CASE_STR(sl::DeepDVCMode::eOn); + }; + return "Unknown"; +} diff --git a/third_party/streamline/include/sl_device_wrappers.h b/third_party/streamline/include/sl_device_wrappers.h new file mode 100644 index 000000000..74d3f9372 --- /dev/null +++ b/third_party/streamline/include/sl_device_wrappers.h @@ -0,0 +1,20 @@ +#pragma once + +#include + +#include "sl_struct.h" + +namespace sl +{ + +//! Rendering API +//! +enum class RenderAPI : uint32_t +{ + eD3D11, + eD3D12, + eVulkan, + eCount +}; + +} diff --git a/third_party/streamline/include/sl_directsr.h b/third_party/streamline/include/sl_directsr.h new file mode 100644 index 000000000..5655beb35 --- /dev/null +++ b/third_party/streamline/include/sl_directsr.h @@ -0,0 +1,173 @@ +/* +* Copyright (c) 2024 NVIDIA CORPORATION. All rights reserved +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +#pragma once + +#include "sl_struct.h" +#include + +struct ID3D12CommandQueue; +namespace sl +{ + +enum class DirectSROptimizationType : uint32_t +{ + eBalanced, + eHighQuality, + eMaxQuality, + eHighPerformance, + eMaxPerformance, + ePowerSaving, + eMaxPowerSaving, + + eCount +}; + +enum class DirectSRVariantFlags : uint32_t +{ + eNone = 0x0, + eSupportsExposureScaleTexture = 0x1, + eSupportsIgnoreHistoryMask = 0x2, + eNative = 0x4, + eSupportsReactiveMask = 0x8, + eSupportsSharpness = 0x10, + eDisallowsRegionOffsets = 0x20, + + eAll = eSupportsExposureScaleTexture | eSupportsIgnoreHistoryMask | eNative | eSupportsReactiveMask | eSupportsSharpness | eDisallowsRegionOffsets +}; + +// {1AD87504-774E-4BF3-9633-A44D1F7F9CB8} +SL_STRUCT_BEGIN(DirectSROptions, StructType({ 0x1ad87504, 0x774e, 0x4bf3, { 0x96, 0x33, 0xa4, 0x4d, 0x1f, 0x7f, 0x9c, 0xb8 } }), kStructVersion1) + // DirectSR variant index as enumerated + uint32_t variantIndex; + + // D3D12 command queue to execute work on + ID3D12CommandQueue *pCommandQueue; + + //! Specifies which mode should be used + DirectSROptimizationType optType; + + //! Specifies output (final) target width + uint32_t outputWidth = INVALID_UINT; + + //! Specifies output (final) target height + uint32_t outputHeight = INVALID_UINT; + + //! Specifies sharpening level in range [0,1] + float sharpness = 0.0f; + + //! Specifies pre-exposure value + float preExposure = 1.0f; + + //! Specifies exposure scale value + float exposureScale = 1.0f; + + //! Specifies if tagged color buffers are full HDR or not (DLSS in HDR pipeline or not) + Boolean colorBuffersHDR = Boolean::eTrue; + + //! IMPORTANT: New members go here or if optional can be chained in a new struct, see sl_struct.h for details +SL_STRUCT_END() + +//! Returned by DirectSR plugin +//! +//! {1BD0C637-A28F-41F2-BC91-B421FAEE8E1E} +SL_STRUCT_BEGIN(DirectSROptimalSettings, StructType({ 0x1bd0c637, 0xa28f, 0x41f2, { 0xbc, 0x91, 0xb4, 0x21, 0xfa, 0xee, 0x8e, 0x1e } }), kStructVersion1) +//! Specifies render area width + uint32_t optimalRenderWidth{}; + //! Specifies render area height + uint32_t optimalRenderHeight{}; + //! Specifies minimal render area width + uint32_t renderWidthMin{}; + //! Specifies minimal render area height + uint32_t renderHeightMin{}; + //! Specifies maximal render area width + uint32_t renderWidthMax{}; + //! Specifies maximal render area height + uint32_t renderHeightMax{}; + + // optimal color format + DXGI_FORMAT optimalColorFormat; + + // optimal depth format + DXGI_FORMAT optimalDepthFormat; + + //! IMPORTANT: New members go here or if optional can be chained in a new struct, see sl_struct.h for details +SL_STRUCT_END() + +//! Returned by DirectSR plugin +//! +//! {38216184-79ba-48cb-93f5-7a8a59382fdf} +SL_STRUCT_BEGIN(DirectSRVariantInfo, StructType({ 0x38216184, 0x79ba, 0x48cb, { 0x93, 0xf5, 0x7a, 0x8a, 0x59, 0x38, 0x2f, 0xdf } }), kStructVersion1) + char name[128]; + sl::DirectSRVariantFlags flags; + sl::DirectSROptimizationType optimizationRankings[7]; + DXGI_FORMAT optimalTargetFormat; + //! IMPORTANT: New members go here or if optional can be chained in a new struct, see sl_struct.h for details +SL_STRUCT_END() + +} + +//! Provides optimal DirectSR settings +//! +//! Call this method to obtain optimal render target size and other DirectSR related settings. +//! +//! @param options Specifies DirectSR options to use +//! @param settings Reference to a structure where settings are returned +//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details) +//! +//! This method is NOT thread safe. +using PFun_slDirectSRGetOptimalSettings = sl::Result(const sl::DirectSROptions & options, sl::DirectSROptimalSettings & settings); + +//! Retrive information about the available DirectSR variants. +using PFun_slDirectSRGetVariantInfo = sl::Result(uint32_t *numVariants, sl::DirectSRVariantInfo *variantInfo); + +//! Sets DirectSR options +//! +//! Call this method to turn DirectSR on/off, change mode etc. +//! +//! @param viewport Specified viewport we are working with +//! @param options Specifies DirectSR options to use +//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details) +//! +//! This method is NOT thread safe. +using PFun_slDirectSRSetOptions = sl::Result(const sl::ViewportHandle& viewport, const sl::DirectSROptions& options); + +//! HELPERS +//! +inline sl::Result slDirectSRGetOptimalSettings(const sl::DirectSROptions& options, sl::DirectSROptimalSettings& settings) +{ + SL_FEATURE_FUN_IMPORT_STATIC(sl::kFeatureDirectSR, slDirectSRGetOptimalSettings); + return s_slDirectSRGetOptimalSettings(options, settings); +} + +inline sl::Result slDirectSRGetVariantInfo(uint32_t *numVariants, sl::DirectSRVariantInfo *variantInfo) +{ + SL_FEATURE_FUN_IMPORT_STATIC(sl::kFeatureDirectSR, slDirectSRGetVariantInfo); + return s_slDirectSRGetVariantInfo(numVariants, variantInfo); +} + +inline sl::Result slDirectSRSetOptions(const sl::ViewportHandle& viewport, const sl::DirectSROptions& options) +{ + SL_FEATURE_FUN_IMPORT_STATIC(sl::kFeatureDirectSR, slDirectSRSetOptions); + return s_slDirectSRSetOptions(viewport, options); +} + diff --git a/third_party/streamline/include/sl_dlss.h b/third_party/streamline/include/sl_dlss.h new file mode 100644 index 000000000..3aac47be6 --- /dev/null +++ b/third_party/streamline/include/sl_dlss.h @@ -0,0 +1,193 @@ +/* +* Copyright (c) 2022-2023 NVIDIA CORPORATION. All rights reserved +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +#pragma once + +#if __cplusplus >= 201402L +#define SR_DEPRECATED_SHARPENING [[deprecated("Sharpness is not supported")]] +#else +#define SR_DEPRECATED_SHARPENING +#endif + +namespace sl +{ + +enum class DLSSMode : uint32_t +{ + eOff, + eMaxPerformance, + eBalanced, + eMaxQuality, + eUltraPerformance, + eUltraQuality, + eDLAA, + eCount, +}; + +enum class DLSSPreset : uint32_t +{ + //! Default behavior, may or may not change after an OTA + eDefault, + //! Fixed DL models + // ePresetA removed, use presets J or K + // ePresetB removed, use presets J or K + // ePresetC removed, use presets J or K + // ePresetD removed, use presets J or K + ePresetE = 5, // Deprecated + ePresetF = 6, // Deprecated + ePresetG = 7, // Reverts to default, not recommended to use + ePresetH = 8, // Reverts to default, not recommended to use + ePresetI = 9, // Reverts to default, not recommended to use + ePresetJ = 10, // Similar to preset K. Preset J might exhibit slightly less ghosting at the cost of extra flickering. Preset K is generally recommended over preset J + ePresetK = 11, // Default preset for DLAA/Balanced/Quality modes that is transformer based. Best image quality preset at a higher performance cost + ePresetL = 12, // Default preset for UltraPerformance mode. Delivers a sharper, more stable image with less ghosting than Preset J, K but are more expensive performance wise + ePresetM = 13, // Default preset for Performance mode. Delivers similar image quality improvements as Preset L but closer in speed to Presets J, K + ePresetN = 14, // Reverts to default, not recommended to use + ePresetO = 15, // Reverts to default, not recommended to use + + eCount +}; + +// {6AC826E4-4C61-4101-A92D-638D421057B8} +SL_STRUCT_BEGIN(DLSSOptions, StructType({ 0x6ac826e4, 0x4c61, 0x4101, { 0xa9, 0x2d, 0x63, 0x8d, 0x42, 0x10, 0x57, 0xb8 } }), kStructVersion3) + //! Specifies which mode should be used + DLSSMode mode = DLSSMode::eOff; + //! Specifies output (final) target width + uint32_t outputWidth = INVALID_UINT; + //! Specifies output (final) target height + uint32_t outputHeight = INVALID_UINT; + //! Specifies sharpening level in range [0,1] this is a deprecated field + float sharpness SR_DEPRECATED_SHARPENING = 0.0f; + //! Specifies pre-exposure value + float preExposure = 1.0f; + //! Specifies exposure scale value + float exposureScale = 1.0f; + //! Specifies if tagged color buffers are full HDR or not (DLSS in HDR pipeline or not) + Boolean colorBuffersHDR = Boolean::eTrue; + //! Specifies if indicator on screen should invert axis + Boolean indicatorInvertAxisX = Boolean::eFalse; + //! Specifies if indicator on screen should invert axis + Boolean indicatorInvertAxisY = Boolean::eFalse; + //! Presets + DLSSPreset dlaaPreset = DLSSPreset::eDefault; + DLSSPreset qualityPreset = DLSSPreset::eDefault; + DLSSPreset balancedPreset = DLSSPreset::eDefault; + DLSSPreset performancePreset = DLSSPreset::eDefault; + DLSSPreset ultraPerformancePreset = DLSSPreset::eDefault; + DLSSPreset ultraQualityPreset = DLSSPreset::eDefault; + + //! Specifies if the setting for AutoExposure is used + Boolean useAutoExposure = Boolean::eFalse; + + //! Whether or not the alpha channel should be upscaled (if false, only RGB is upscaled) + //! Enabling alpha upscaling may impact performance + Boolean alphaUpscalingEnabled = Boolean::eFalse; + + //! IMPORTANT: New members go here or if optional can be chained in a new struct, see sl_struct.h for details +SL_STRUCT_END() + +//! Returned by DLSS plugin +//! +//! {EF1D0957-FD58-4DF7-B504-8B69D8AA6B76} +SL_STRUCT_BEGIN(DLSSOptimalSettings, StructType({ 0xef1d0957, 0xfd58, 0x4df7, { 0xb5, 0x4, 0x8b, 0x69, 0xd8, 0xaa, 0x6b, 0x76 } }), kStructVersion1) + //! Specifies render area width + uint32_t optimalRenderWidth{}; + //! Specifies render area height + uint32_t optimalRenderHeight{}; + //! Specifies the optimal sharpness value + float optimalSharpness{}; + //! Specifies minimal render area width + uint32_t renderWidthMin{}; + //! Specifies minimal render area height + uint32_t renderHeightMin{}; + //! Specifies maximal render area width + uint32_t renderWidthMax{}; + //! Specifies maximal render area height + uint32_t renderHeightMax{}; + + //! IMPORTANT: New members go here or if optional can be chained in a new struct, see sl_struct.h for details +SL_STRUCT_END() + +//! Returned by DLSS plugin +//! +//! {9366B056-8C01-463C-BB91-E68782636CE9} +SL_STRUCT_BEGIN(DLSSState, StructType({ 0x9366b056, 0x8c01, 0x463c, { 0xbb, 0x91, 0xe6, 0x87, 0x82, 0x63, 0x6c, 0xe9 } }), kStructVersion1) + //! Specified the amount of memory expected to be used + uint64_t estimatedVRAMUsageInBytes{}; + + //! IMPORTANT: New members go here or if optional can be chained in a new struct, see sl_struct.h for details +SL_STRUCT_END() + +} + +//! Provides optimal DLSS settings +//! +//! Call this method to obtain optimal render target size and other DLSS related settings. +//! +//! @param options Specifies DLSS options to use +//! @param settings Reference to a structure where settings are returned +//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details) +//! +//! This method is NOT thread safe. +using PFun_slDLSSGetOptimalSettings = sl::Result(const sl::DLSSOptions & options, sl::DLSSOptimalSettings & settings); + +//! Provides DLSS state for the given viewport +//! +//! Call this method to obtain optimal render target size and other DLSS related settings. +//! +//! @param viewport Specified viewport we are working with +//! @param state Reference to a structure where state is to be returned +//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details) +//! +//! This method is NOT thread safe. +using PFun_slDLSSGetState = sl::Result(const sl::ViewportHandle & viewport, sl::DLSSState & state); + +//! Sets DLSS options +//! +//! Call this method to turn DLSS on/off, change mode etc. +//! +//! @param viewport Specified viewport we are working with +//! @param options Specifies DLSS options to use +//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details) +//! +//! This method is NOT thread safe. +using PFun_slDLSSSetOptions = sl::Result(const sl::ViewportHandle& viewport, const sl::DLSSOptions& options); + +//! HELPERS +//! +inline sl::Result slDLSSGetOptimalSettings(const sl::DLSSOptions& options, sl::DLSSOptimalSettings& settings) +{ + SL_FEATURE_FUN_IMPORT_STATIC(sl::kFeatureDLSS, slDLSSGetOptimalSettings); + return s_slDLSSGetOptimalSettings(options, settings); +} + +inline sl::Result slDLSSGetState(const sl::ViewportHandle& viewport, sl::DLSSState& state) +{ + SL_FEATURE_FUN_IMPORT_STATIC(sl::kFeatureDLSS, slDLSSGetState); + return s_slDLSSGetState(viewport, state); +} + +inline sl::Result slDLSSSetOptions(const sl::ViewportHandle& viewport, const sl::DLSSOptions& options) +{ + SL_FEATURE_FUN_IMPORT_STATIC(sl::kFeatureDLSS, slDLSSSetOptions); + return s_slDLSSSetOptions(viewport, options); +} diff --git a/third_party/streamline/include/sl_dlss_d.h b/third_party/streamline/include/sl_dlss_d.h new file mode 100644 index 000000000..e5ec8ec85 --- /dev/null +++ b/third_party/streamline/include/sl_dlss_d.h @@ -0,0 +1,188 @@ +/* +* Copyright (c) 2023 NVIDIA CORPORATION. All rights reserved +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +#pragma once + +#include "sl_dlss.h" + +namespace sl +{ + +enum class DLSSDPreset : uint32_t +{ + //! Default behavior, may or may not change after an OTA + eDefault, + // ePresetA removed, use preset D, E or F + // ePresetB removed, use preset D, E or F + // ePresetC removed, use preset D, E or F + ePresetD = 4, // Transformer model + ePresetE = 5, // Transformer model + ePresetF = 6, // Latest and default transformer model + ePresetG = 7, // Reverts to default + ePresetH = 8, // Reverts to default + ePresetI = 9, // Reverts to default + ePresetJ = 10, // Reverts to default + ePresetK = 11, // Reverts to default + ePresetL = 12, // Reverts to default + ePresetM = 13, // Reverts to default. Not recommended to use + ePresetN = 14, // Reverts to default. Not recommended to use + ePresetO = 15, // Reverts to default. Not recommended to use + + eCount +}; + +enum class DLSSDNormalRoughnessMode : uint32_t +{ + eUnpacked, // App needs to provide Normal resource and Roughness resource separately. + ePacked, // App needs to write Roughness to w channel of Normal resource. + + eCount +}; + +// {0AD87504-774E-4BF3-9633-A44D1F7F9CB8} +SL_STRUCT_BEGIN(DLSSDOptions, StructType({ 0x0ad87504, 0x774e, 0x4bf3, { 0x96, 0x33, 0xa4, 0x4d, 0x1f, 0x7f, 0x9c, 0xb8 } }), kStructVersion3) + //! Specifies which mode should be used + DLSSMode mode = DLSSMode::eOff; + //! Specifies output (final) target width + uint32_t outputWidth = INVALID_UINT; + //! Specifies output (final) target height + uint32_t outputHeight = INVALID_UINT; + //! Specifies sharpening level in range [0,1] + float sharpness = 0.0f; + //! Specifies pre-exposure value + float preExposure = 1.0f; + //! Specifies exposure scale value + float exposureScale = 1.0f; + //! Specifies if tagged color buffers are full HDR or not (DLSS in HDR pipeline or not) + Boolean colorBuffersHDR = Boolean::eTrue; + //! Specifies if indicator on screen should invert axis + Boolean indicatorInvertAxisX = Boolean::eFalse; + //! Specifies if indicator on screen should invert axis + Boolean indicatorInvertAxisY = Boolean::eFalse; + //! Specifies which mode should be used for roughness resource + DLSSDNormalRoughnessMode normalRoughnessMode = DLSSDNormalRoughnessMode::eUnpacked; + //! Specifies matrix transformation from the world space to the camera view space. + float4x4 worldToCameraView; + //! Specifies matrix transformation from the camera view space to the world space. + //! cameraViewToWorld = worldToCameraView.inverse() + float4x4 cameraViewToWorld; + //! Whether or not the alpha channel should be upscaled (if false, only RGB is upscaled) + //! Enabling alpha upscaling may impact performance + Boolean alphaUpscalingEnabled = Boolean::eFalse; + + //! Presets + DLSSDPreset dlaaPreset = DLSSDPreset::eDefault; + DLSSDPreset qualityPreset = DLSSDPreset::eDefault; + DLSSDPreset balancedPreset = DLSSDPreset::eDefault; + DLSSDPreset performancePreset = DLSSDPreset::eDefault; + DLSSDPreset ultraPerformancePreset = DLSSDPreset::eDefault; + DLSSDPreset ultraQualityPreset = DLSSDPreset::eDefault; + + //! IMPORTANT: New members go here or if optional can be chained in a new struct, see sl_struct.h for details +SL_STRUCT_END() + +//! Returned by DLSSD plugin +//! +//! {FBD0C637-A28F-41F2-BC91-B421FAEE8E1E} +SL_STRUCT_BEGIN(DLSSDOptimalSettings, StructType({ 0xfbd0c637, 0xa28f, 0x41f2, { 0xbc, 0x91, 0xb4, 0x21, 0xfa, 0xee, 0x8e, 0x1e } }), kStructVersion1) +//! Specifies render area width + uint32_t optimalRenderWidth{}; + //! Specifies render area height + uint32_t optimalRenderHeight{}; + //! Specifies the optimal sharpness value + float optimalSharpness{}; + //! Specifies minimal render area width + uint32_t renderWidthMin{}; + //! Specifies minimal render area height + uint32_t renderHeightMin{}; + //! Specifies maximal render area width + uint32_t renderWidthMax{}; + //! Specifies maximal render area height + uint32_t renderHeightMax{}; + + //! IMPORTANT: New members go here or if optional can be chained in a new struct, see sl_struct.h for details +SL_STRUCT_END() + +//! Returned by DLSSD plugin +//! +//! {71873C14-F8CA-4767-9EAF-3B4393EA98FA} +SL_STRUCT_BEGIN(DLSSDState, StructType({ 0x71873c14, 0xf8ca, 0x4767, { 0x9e, 0xaf, 0x3b, 0x43, 0x93, 0xea, 0x98, 0xfa } }), kStructVersion1) +//! Specified the amount of memory expected to be used + uint64_t estimatedVRAMUsageInBytes {}; + + //! IMPORTANT: New members go here or if optional can be chained in a new struct, see sl_struct.h for details +SL_STRUCT_END() + +} + +//! Provides optimal DLSSD settings +//! +//! Call this method to obtain optimal render target size and other DLSSD related settings. +//! +//! @param options Specifies DLSSD options to use +//! @param settings Reference to a structure where settings are returned +//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details) +//! +//! This method is NOT thread safe. +using PFun_slDLSSDGetOptimalSettings = sl::Result(const sl::DLSSDOptions & options, sl::DLSSDOptimalSettings & settings); + +//! Provides DLSSD state for the given viewport +//! +//! Call this method to obtain optimal render target size and other DLSSD related settings. +//! +//! @param viewport Specified viewport we are working with +//! @param state Reference to a structure where state is to be returned +//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details) +//! +//! This method is NOT thread safe. +using PFun_slDLSSDGetState = sl::Result(const sl::ViewportHandle & viewport, sl::DLSSDState & state); + +//! Sets DLSSD options +//! +//! Call this method to turn DLSSD on/off, change mode etc. +//! +//! @param viewport Specified viewport we are working with +//! @param options Specifies DLSSD options to use +//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details) +//! +//! This method is NOT thread safe. +using PFun_slDLSSDSetOptions = sl::Result(const sl::ViewportHandle& viewport, const sl::DLSSDOptions& options); + +//! HELPERS +//! +inline sl::Result slDLSSDGetOptimalSettings(const sl::DLSSDOptions& options, sl::DLSSDOptimalSettings& settings) +{ + SL_FEATURE_FUN_IMPORT_STATIC(sl::kFeatureDLSS_RR, slDLSSDGetOptimalSettings); + return s_slDLSSDGetOptimalSettings(options, settings); +} + +inline sl::Result slDLSSDGetState(const sl::ViewportHandle& viewport, sl::DLSSDState& state) +{ + SL_FEATURE_FUN_IMPORT_STATIC(sl::kFeatureDLSS_RR, slDLSSDGetState); + return s_slDLSSDGetState(viewport, state); +} + +inline sl::Result slDLSSDSetOptions(const sl::ViewportHandle& viewport, const sl::DLSSDOptions& options) +{ + SL_FEATURE_FUN_IMPORT_STATIC(sl::kFeatureDLSS_RR, slDLSSDSetOptions); + return s_slDLSSDSetOptions(viewport, options); +} diff --git a/third_party/streamline/include/sl_dlss_g.h b/third_party/streamline/include/sl_dlss_g.h new file mode 100644 index 000000000..34e54cea1 --- /dev/null +++ b/third_party/streamline/include/sl_dlss_g.h @@ -0,0 +1,222 @@ +/* +* Copyright (c) 2022-2023 NVIDIA CORPORATION. All rights reserved +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +#pragma once + +#include "sl.h" +#include "sl_consts.h" +#include "sl_core_types.h" +#include + + +namespace sl +{ + +enum class DLSSGMode : uint32_t +{ + eOff, + eOn, + eAuto, + eDynamic, + eCount +}; + +enum class DLSSGFlags : uint32_t +{ + eShowOnlyInterpolatedFrame = 1 << 0, + eDynamicResolutionEnabled = 1 << 1, + eRequestVRAMEstimate = 1 << 2, + eRetainResourcesWhenOff = 1 << 3, + eEnableFullscreenMenuDetection = 1 << 4, + + //! All DLSS-FG flags. This isn't expected to be used directly by integrations, but may be useful for e.g. writing helpers. + eAll = eShowOnlyInterpolatedFrame | eDynamicResolutionEnabled | eRequestVRAMEstimate | eRetainResourcesWhenOff | eEnableFullscreenMenuDetection +}; + +enum class DLSSGQueueParallelismMode : uint32_t +{ + //! Default mode in which client's presenting queue is blocked until DLSSG workload execution completes. + eBlockPresentingClientQueue, + //! This mode is only supported on Vulkan presently. Even if set by any D3D client, it would default to + //! eBlockPresentingClientQueue as before. eBlockNoClientQueues mode helps achieve maximum performance benefit + //! from queue-level paralleism in Vulkan during DLSS-G processing. In this mode, client must must wait on + //! DLSSGState::inputsProcessingCompletionFence and associated value, before it can modify or destroy the tagged + //! resources input to DLSS-G enabled for the corresponding previously presented frame on any client queue. + eBlockNoClientQueues, + eCount +}; + +// Adds various useful operators for our enum +SL_ENUM_OPERATORS_32(DLSSGFlags) + +// {FAC5F1CB-2DFD-4F36-A1E6-3A9E865256C5} +SL_STRUCT_BEGIN(DLSSGOptions, StructType({ 0xfac5f1cb, 0x2dfd, 0x4f36, { 0xa1, 0xe6, 0x3a, 0x9e, 0x86, 0x52, 0x56, 0xc5 } }), kStructVersion5) + //! Specifies which mode should be used. + DLSSGMode mode = DLSSGMode::eOff; + //! Number of frames to generate inbetween fully rendered frames. Cannot exceed DLSSGState::numFramesToGenerateMax. + //! For 2x frame multiplier, numFramesToGenerate is 1. + //! For 3x frame multiplier, numFramesToGenerate is 2. + //! For 4x frame multiplier, numFramesToGenerate is 3. + uint32_t numFramesToGenerate = 1; + //! Optional - Flags used to enable or disable certain functionality + DLSSGFlags flags{}; + //! Optional - Dynamic resolution optimal width (used only if eDynamicResolutionEnabled is set) + uint32_t dynamicResWidth{}; + //! Optional - Dynamic resolution optimal height (used only if eDynamicResolutionEnabled is set) + uint32_t dynamicResHeight{}; + //! Optional - Expected number of buffers in the swap-chain + uint32_t numBackBuffers{}; + //! Optional - Expected width of the input render targets (depth, motion-vector buffers etc) + uint32_t mvecDepthWidth{}; + //! Optional - Expected height of the input render targets (depth, motion-vector buffers etc) + uint32_t mvecDepthHeight{}; + //! Optional - Expected width of the back buffers in the swap-chain + uint32_t colorWidth{}; + //! Optional - Expected height of the back buffers in the swap-chain + uint32_t colorHeight{}; + //! Optional - Indicates native format used for the swap-chain back buffers + uint32_t colorBufferFormat{}; + //! Optional - Indicates native format used for eMotionVectors + uint32_t mvecBufferFormat{}; + //! Optional - Indicates native format used for eDepth + uint32_t depthBufferFormat{}; + //! Optional - Indicates native format used for eHUDLessColor + uint32_t hudLessBufferFormat{}; + //! Optional - Indicates native format used for eUIColorAndAlpha + uint32_t uiBufferFormat{}; + //! Optional - if specified DLSSG will return any errors which occur when calling underlying API (DXGI or Vulkan) + PFunOnAPIErrorCallback* onErrorCallback{}; + // kStructVersion2 + Boolean bReserved15 = eInvalid; + // kStructVersion3 + //! Optional - determines the level of client and DLSSG queue parallelism to use for performance gain - must be same for all viewports. + DLSSGQueueParallelismMode queueParallelismMode{}; + // kStructVersion4 + //! Optional - if true, DLSSG will allocate a codepath that supports interpolating 'HUDless' and 'UI Color & Alpha' separately than the Color Backbuffer. + //! this property can be overridden by Nvidia App. See the programming guide for more details. + Boolean enableUserInterfaceRecomposition = Boolean::eFalse; + // kStructVersion5 + //! Optional - Target frame rate for dynamic frame generation when enabled. + //! If set to 0.0f (default), auto-detects the display refresh rate. + float dynamicTargetFrameRate{}; + //! IMPORTANT: New members go here or if optional can be chained in a new struct, see sl_struct.h for details +SL_STRUCT_END() + + +enum class DLSSGStatus : uint32_t +{ + //! Everything is working as expected + eOk = 0, + //! Output resolution (size of the back buffers in the swap-chain) is too low + eFailResolutionTooLow = 1 << 0, + //! Reflex is not active while DLSS-G is running, Reflex must be turned on when DLSS-G is on + eFailReflexNotDetectedAtRuntime = 1 << 1, + //! HDR format not supported, see DLSS-G programming guide for more details + eFailHDRFormatNotSupported = 1 << 2, + //! Some constants are invalid, see programming guide for more details + eFailCommonConstantsInvalid = 1 << 3, + //! D3D integrations must use SwapChain::GetCurrentBackBufferIndex API + eFailGetCurrentBackBufferIndexNotCalled = 1 << 4, + //! Reserved for future use, do not use + eReserved5 = 1 << 5, + + eAll = eFailResolutionTooLow | eFailReflexNotDetectedAtRuntime | eFailHDRFormatNotSupported | eFailCommonConstantsInvalid | eFailGetCurrentBackBufferIndexNotCalled | eReserved5 +}; + +// Adds various useful operators for our enum +SL_ENUM_OPERATORS_32(DLSSGStatus) + +// {CC8AC8E1-A179-44F5-97FA-E74112F9BC61} +SL_STRUCT_BEGIN(DLSSGState, StructType({ 0xcc8ac8e1, 0xa179, 0x44f5, { 0x97, 0xfa, 0xe7, 0x41, 0x12, 0xf9, 0xbc, 0x61 } }), kStructVersion4) + //! Specifies the amount of memory expected to be used + uint64_t estimatedVRAMUsageInBytes{}; + //! Specifies current status of DLSS-G + DLSSGStatus status{}; + //! Specifies minimum supported dimension + uint32_t minWidthOrHeight{}; + //! Number of frames presented since the last 'slDLSSGGetState' call + uint32_t numFramesActuallyPresented{}; + // kStructVersion2 + //! The maximum number of interpolated frames the current system can generate per real frame. + //! This value represents the upper bound for 'numFramesToGenerate'. + //! Examples: + //! - On devices supporting up to a 2x multiplier: numFramesToGenerateMax is 1. + //! - On devices supporting up to a 6x multiplier: numFramesToGenerateMax is 5. + uint32_t numFramesToGenerateMax{}; + //! Reserved for future use, do not use + sl::Boolean bReserved4{}; + //! Hint to the application to display VSync support in the user interface + sl::Boolean bIsVsyncSupportAvailable{}; + + //! SL client must wait on SL DLSS-G plugin-internal fence and associated value, before it can modify or destroy the tagged resources input + //! to DLSS-G enabled for the corresponding previously presented frame on a non-presenting queue. + //! If modified on client's presenting queue, then it's recommended but not required. + //! However, if DLSSGQueueParallelismMode::eBlockNoClientQueues is set, then it's always required. + //! It must call slDLSSGGetState on the present thread to retrieve the fence value for the inputs consumed by FG, on which client would + //! wait in the frame it would modify those inputs. + void* inputsProcessingCompletionFence{}; + uint64_t lastPresentInputsProcessingCompletionFenceValue{}; + // kStructVersion4 + //! Whether or not Dynamic Multi Frame Generation (DLSSGMode::eDynamic) is + //! supported + sl::Boolean bIsDynamicMFGSupported{}; + //! IMPORTANT: New members go here or if optional can be chained in a new struct, see sl_struct.h for details +SL_STRUCT_END() + +} + +//! Provides DLSS-G state +//! +//! Call this method to obtain current state of DLSS-G +//! +//! @param viewport Specified viewport we are working with +//! @param state Reference to a structure where state is returned +//! @param options Specifies DLSS-G options to use (can be null if not needed) +//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details) +//! +//! This method is NOT thread safe. +using PFun_slDLSSGGetState = sl::Result(const sl::ViewportHandle& viewport, sl::DLSSGState& state, const sl::DLSSGOptions* options); + +//! Sets DLSS-G options +//! +//! Call this method to turn DLSS-G on/off, change modes etc. +//! +//! @param viewport Specified viewport we are working with +//! @param options Specifies DLSS-G options to use +//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details) +//! +//! This method is NOT thread safe. +using PFun_slDLSSGSetOptions = sl::Result(const sl::ViewportHandle& viewport, const sl::DLSSGOptions& options); + +//! HELPERS +//! +inline sl::Result slDLSSGGetState(const sl::ViewportHandle& viewport, sl::DLSSGState& state, const sl::DLSSGOptions* options) +{ + SL_FEATURE_FUN_IMPORT_STATIC(sl::kFeatureDLSS_G, slDLSSGGetState); + return s_slDLSSGGetState(viewport, state, options); +} + +inline sl::Result slDLSSGSetOptions(const sl::ViewportHandle& viewport, const sl::DLSSGOptions& options) +{ + SL_FEATURE_FUN_IMPORT_STATIC(sl::kFeatureDLSS_G, slDLSSGSetOptions); + return s_slDLSSGSetOptions(viewport, options); +} diff --git a/third_party/streamline/include/sl_helpers.h b/third_party/streamline/include/sl_helpers.h new file mode 100644 index 000000000..d56ceec2b --- /dev/null +++ b/third_party/streamline/include/sl_helpers.h @@ -0,0 +1,485 @@ +/* +* Copyright (c) 2022-2025 NVIDIA CORPORATION. All rights reserved +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +#pragma once + +#include +#include + +#define FEATURE_SPECIFIC_BUFFER_TYPE_ID(feature, number) feature << 16 | number + +#include "sl.h" +#include "sl_consts.h" +#include "sl_reflex.h" +#include "sl_pcl.h" +#include "sl_dlss.h" +#include "sl_nis.h" +#include "sl_dlss_d.h" +#include "sl_dlss_g.h" + +#if defined(__clang__) + #define SL_DISABLE_DEPRECATED_WARNINGS \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") + #define SL_RESTORE_DEPRECATED_WARNINGS \ + _Pragma("clang diagnostic pop") + +#elif defined(_MSC_VER) + #define SL_DISABLE_DEPRECATED_WARNINGS \ + __pragma(warning(push)) \ + __pragma(warning(disable: 4996)) + #define SL_RESTORE_DEPRECATED_WARNINGS \ + __pragma(warning(pop)) + +#else + #define SL_DISABLE_DEPRECATED_WARNINGS + #define SL_RESTORE_DEPRECATED_WARNINGS +#endif + + +namespace sl +{ + +inline float4x4 transpose(const float4x4& m) +{ + float4x4 r; + r[0] = { m[0].x, m[1].x, m[2].x, m[3].x }; + r[1] = { m[0].y, m[1].y, m[2].y, m[3].y }; + r[2] = { m[0].z, m[1].z, m[2].z, m[3].z }; + r[3] = { m[0].w, m[1].w, m[2].w, m[3].w }; + return r; +}; + +#define SL_CASE_STR(a) case a : return #a; + +// Check for c++17 features +#if __cplusplus >= 201703L + #define SL_FALLTHROUGH [[fallthrough]]; +#else + #define SL_FALLTHROUGH +#endif + +inline const char* getResultAsStr(Result v) +{ + switch (v) + { + SL_CASE_STR(Result::eOk); + SL_CASE_STR(Result::eErrorIO); + SL_CASE_STR(Result::eErrorDriverOutOfDate); + SL_CASE_STR(Result::eErrorOSOutOfDate); + SL_CASE_STR(Result::eErrorOSDisabledHWS); + SL_CASE_STR(Result::eErrorDeviceNotCreated); + SL_CASE_STR(Result::eErrorNoSupportedAdapterFound); + SL_CASE_STR(Result::eErrorAdapterNotSupported); + SL_CASE_STR(Result::eErrorNoPlugins); + SL_CASE_STR(Result::eErrorVulkanAPI); + SL_CASE_STR(Result::eErrorDXGIAPI); + SL_CASE_STR(Result::eErrorD3DAPI); + SL_CASE_STR(Result::eErrorNRDAPI); + SL_CASE_STR(Result::eErrorNVAPI); + SL_CASE_STR(Result::eErrorReflexAPI); + SL_CASE_STR(Result::eErrorNGXFailed); + SL_CASE_STR(Result::eErrorJSONParsing); + SL_CASE_STR(Result::eErrorMissingProxy); + SL_CASE_STR(Result::eErrorMissingResourceState); + SL_CASE_STR(Result::eErrorInvalidIntegration); + SL_CASE_STR(Result::eErrorMissingInputParameter); + SL_CASE_STR(Result::eErrorNotInitialized); + SL_CASE_STR(Result::eErrorComputeFailed); + SL_CASE_STR(Result::eErrorInitNotCalled); + SL_CASE_STR(Result::eErrorExceptionHandler); + SL_CASE_STR(Result::eErrorInvalidParameter); + SL_CASE_STR(Result::eErrorMissingConstants); + SL_CASE_STR(Result::eErrorDuplicatedConstants); + SL_CASE_STR(Result::eErrorMissingOrInvalidAPI); + SL_CASE_STR(Result::eErrorCommonConstantsMissing); + SL_CASE_STR(Result::eErrorUnsupportedInterface); + SL_CASE_STR(Result::eErrorFeatureMissing); + SL_CASE_STR(Result::eErrorFeatureNotSupported); + SL_CASE_STR(Result::eErrorFeatureMissingHooks); + SL_CASE_STR(Result::eErrorFeatureFailedToLoad); + SL_CASE_STR(Result::eErrorFeatureWrongPriority); + SL_CASE_STR(Result::eErrorFeatureMissingDependency); + SL_CASE_STR(Result::eErrorFeatureManagerInvalidState); + SL_CASE_STR(Result::eErrorInvalidState); + SL_CASE_STR(Result::eWarnOutOfVRAM); + }; + return "Unknown"; +} + +inline const char* getNISModeAsStr(NISMode v) +{ + switch (v) + { + SL_CASE_STR(NISMode::eOff); + SL_CASE_STR(NISMode::eScaler); + SL_CASE_STR(NISMode::eSharpen); + case NISMode::eCount: break; + }; + return "Unknown"; +} + +inline const char* getNISHDRAsStr(NISHDR v) +{ + switch (v) + { + SL_CASE_STR(NISHDR::eNone); + SL_CASE_STR(NISHDR::eLinear); + SL_CASE_STR(NISHDR::ePQ); + case NISHDR::eCount: break; + }; + return "Unknown"; +} + +inline const char* getReflexModeAsStr(ReflexMode mode) +{ + switch (mode) + { + SL_CASE_STR(ReflexMode::eOff); + SL_CASE_STR(ReflexMode::eLowLatency); + SL_CASE_STR(ReflexMode::eLowLatencyWithBoost); + case ReflexMode::ReflexMode_eCount: break; + }; + return "Unknown"; +} + +inline const char* getPCLMarkerAsStr(PCLMarker marker) +{ + switch (marker) + { + SL_CASE_STR(PCLMarker::eSimulationStart); + SL_CASE_STR(PCLMarker::eSimulationEnd); + SL_CASE_STR(PCLMarker::eRenderSubmitStart); + SL_CASE_STR(PCLMarker::eRenderSubmitEnd); + SL_CASE_STR(PCLMarker::ePresentStart); + SL_CASE_STR(PCLMarker::ePresentEnd); + SL_CASE_STR(PCLMarker::eTriggerFlash); + SL_CASE_STR(PCLMarker::ePCLatencyPing); + SL_CASE_STR(PCLMarker::eOutOfBandRenderSubmitStart); + SL_CASE_STR(PCLMarker::eOutOfBandRenderSubmitEnd); + SL_CASE_STR(PCLMarker::eOutOfBandPresentStart); + SL_CASE_STR(PCLMarker::eOutOfBandPresentEnd); + SL_CASE_STR(PCLMarker::eControllerInputSample); + SL_CASE_STR(PCLMarker::eDeltaTCalculation); + SL_CASE_STR(PCLMarker::eLateWarpPresentStart); + SL_CASE_STR(PCLMarker::eLateWarpPresentEnd); + SL_CASE_STR(PCLMarker::eCameraConstructed); + SL_CASE_STR(PCLMarker::eLateWarpRenderSubmitStart); + SL_CASE_STR(PCLMarker::eLateWarpRenderSubmitEnd); + SL_CASE_STR(PCLMarker::eVendorInternalAsyncPresentStart); + SL_CASE_STR(PCLMarker::eVendorInternalAsyncPresentEnd); + SL_CASE_STR(PCLMarker::eNumPresentsInBatch); + case PCLMarker::eMaximum: break; + }; + return "Unknown"; +} + +inline const char* getDLSSModeAsStr(DLSSMode mode) +{ + switch (mode) + { + SL_CASE_STR(DLSSMode::eOff); + SL_CASE_STR(DLSSMode::eDLAA); + SL_CASE_STR(DLSSMode::eMaxPerformance); + SL_CASE_STR(DLSSMode::eBalanced); + SL_CASE_STR(DLSSMode::eMaxQuality); + SL_CASE_STR(DLSSMode::eUltraPerformance); + SL_CASE_STR(DLSSMode::eUltraQuality); + case DLSSMode::eCount: break; + }; + return "Unknown"; +} + +inline const char* getDLSSGModeAsStr(DLSSGMode mode) +{ + switch (mode) + { + SL_CASE_STR(sl::DLSSGMode::eOff); + SL_CASE_STR(sl::DLSSGMode::eOn); + SL_CASE_STR(sl::DLSSGMode::eAuto); + SL_CASE_STR(sl::DLSSGMode::eDynamic); + case DLSSGMode::eCount: break; + }; + return "Unknown"; +} + +inline const char* getBufferTypeAsStr(BufferType buf) +{ + switch (buf) + { + SL_CASE_STR(kBufferTypeDepth); + SL_CASE_STR(kBufferTypeMotionVectors); + SL_CASE_STR(kBufferTypeHUDLessColor); + SL_CASE_STR(kBufferTypeScalingInputColor); + SL_CASE_STR(kBufferTypeScalingOutputColor); + SL_CASE_STR(kBufferTypeNormals); + SL_CASE_STR(kBufferTypeRoughness); + SL_CASE_STR(kBufferTypeAlbedo); + SL_CASE_STR(kBufferTypeSpecularAlbedo); + SL_CASE_STR(kBufferTypeIndirectAlbedo); + SL_CASE_STR(kBufferTypeSpecularMotionVectors); + SL_CASE_STR(kBufferTypeDisocclusionMask); + SL_CASE_STR(kBufferTypeEmissive); + SL_CASE_STR(kBufferTypeExposure); + SL_CASE_STR(kBufferTypeNormalRoughness); + SL_CASE_STR(kBufferTypeDiffuseHitNoisy); + SL_CASE_STR(kBufferTypeDiffuseHitDenoised); + SL_CASE_STR(kBufferTypeSpecularHitNoisy); + SL_CASE_STR(kBufferTypeSpecularHitDenoised); + SL_CASE_STR(kBufferTypeShadowNoisy); + SL_CASE_STR(kBufferTypeShadowDenoised); + SL_CASE_STR(kBufferTypeAmbientOcclusionNoisy); + SL_CASE_STR(kBufferTypeAmbientOcclusionDenoised); + SL_CASE_STR(kBufferTypeUIColorAndAlpha); + SL_CASE_STR(kBufferTypeUIAlpha); + SL_CASE_STR(kBufferTypeUpliftInputColor); + SL_CASE_STR(kBufferTypeUpliftOutputColor); + SL_CASE_STR(kBufferTypeUpliftControlMask); + SL_CASE_STR(kBufferTypeShadowHint); + SL_CASE_STR(kBufferTypeReflectionHint); + SL_CASE_STR(kBufferTypeParticleHint); + SL_CASE_STR(kBufferTypeTransparencyHint); + SL_CASE_STR(kBufferTypeAnimatedTextureHint); + SL_CASE_STR(kBufferTypeBiasCurrentColorHint); + SL_CASE_STR(kBufferTypeRaytracingDistance); + SL_CASE_STR(kBufferTypeReflectionMotionVectors); + SL_CASE_STR(kBufferTypePosition); + SL_CASE_STR(kBufferTypeInvalidDepthMotionHint); + SL_CASE_STR(kBufferTypeAlpha); + SL_CASE_STR(kBufferTypeOpaqueColor); + SL_CASE_STR(kBufferTypeReactiveMaskHint); + SL_CASE_STR(kBufferTypeTransparencyAndCompositionMaskHint); + SL_CASE_STR(kBufferTypeReflectedAlbedo); + SL_CASE_STR(kBufferTypeColorBeforeParticles); + SL_CASE_STR(kBufferTypeColorBeforeTransparency); + SL_CASE_STR(kBufferTypeColorBeforeFog); + SL_CASE_STR(kBufferTypeSpecularHitDistance); + SL_CASE_STR(kBufferTypeSpecularRayDirectionHitDistance); + SL_CASE_STR(kBufferTypeSpecularRayDirection); + SL_CASE_STR(kBufferTypeDiffuseHitDistance); + SL_CASE_STR(kBufferTypeDiffuseRayDirectionHitDistance); + SL_CASE_STR(kBufferTypeDiffuseRayDirection); + SL_CASE_STR(kBufferTypeHiResDepth); + SL_CASE_STR(kBufferTypeLinearDepth); + SL_CASE_STR(kBufferTypeColorAfterParticles); + SL_CASE_STR(kBufferTypeColorAfterTransparency); + SL_CASE_STR(kBufferTypeColorAfterFog); + SL_CASE_STR(kBufferTypeScreenSpaceSubsurfaceScatteringGuide); + SL_CASE_STR(kBufferTypeColorBeforeScreenSpaceSubsurfaceScattering); + SL_CASE_STR(kBufferTypeColorAfterScreenSpaceSubsurfaceScattering); + SL_CASE_STR(kBufferTypeScreenSpaceRefractionGuide); + SL_CASE_STR(kBufferTypeColorBeforeScreenSpaceRefraction); + SL_CASE_STR(kBufferTypeColorAfterScreenSpaceRefraction); + SL_CASE_STR(kBufferTypeDepthOfFieldGuide); + SL_CASE_STR(kBufferTypeColorBeforeDepthOfField); + SL_CASE_STR(kBufferTypeColorAfterDepthOfField); + SL_CASE_STR(kBufferTypeScalingOutputAlpha); + SL_CASE_STR(kBufferTypeResponsivityMask); + SL_CASE_STR(kBufferTypeBidirectionalDistortionField); + SL_CASE_STR(kBufferTypeTransparencyLayer); + SL_CASE_STR(kBufferTypeTransparencyLayerOpacity); + SL_CASE_STR(kBufferTypeBackbuffer); + SL_CASE_STR(kBufferTypeNoWarpMask); + }; + return "Unknown"; +} + +inline const char* getFeatureAsStr(Feature f) +{ + switch (f) + { + SL_CASE_STR(kFeatureDLSS); + SL_CASE_STR(kFeatureNIS); + SL_CASE_STR(kFeatureReflex); + SL_CASE_STR(kFeaturePCL); + SL_CASE_STR(kFeatureDLSS_G); + SL_CASE_STR(kFeatureNvPerf); + SL_CASE_STR(kFeatureImGUI); + SL_CASE_STR(kFeatureCommon); + SL_CASE_STR(kFeatureDLSS_RR); + SL_CASE_STR(kFeatureDeepDVC); + SL_CASE_STR(kFeatureDirectSR); + SL_CASE_STR(kFeatureLatewarp); + SL_CASE_STR(kFeatureDLSS_NR); + // Removed features + case kFeatureNRD_INVALID: break; + } + return "Unknown"; +} + +// Get the feature file name as a string. For a given feature kFeatureDLSS with +// a plugin name sl.dlss.dll the value "dlss" will be returned +inline const char* getFeatureFilenameAsStrNoSL(Feature f) +{ + switch (f) + { + case kFeatureDLSS: return "dlss"; + case kFeatureNIS: return "nis"; + case kFeatureReflex: return "reflex"; + case kFeaturePCL: return "pcl"; + case kFeatureDLSS_G: return "dlss_g"; + case kFeatureNvPerf: return "nvperf"; + case kFeatureDeepDVC: return "deepdvc"; + case kFeatureImGUI: return "imgui"; + case kFeatureCommon: return "common"; + case kFeatureDLSS_RR: return "dlss_d"; + case kFeatureDirectSR: return "directsr"; + case kFeatureLatewarp: return "latewarp"; + case kFeatureDLSS_NR: return "dlss_nr"; + case kFeatureNRD_INVALID: break; + } + return "Unknown"; +} + +inline const char* getLogLevelAsStr(LogLevel v) +{ + switch (v) + { + SL_CASE_STR(LogLevel::eOff); + SL_CASE_STR(LogLevel::eDefault); + SL_CASE_STR(LogLevel::eVerbose); + case LogLevel::eCount: break; + }; + return "Unknown"; +} + +inline const char* getResourceTypeAsStr(ResourceType v) +{ + switch (v) + { + SL_CASE_STR(ResourceType::eTex2d); + SL_CASE_STR(ResourceType::eBuffer); + SL_CASE_STR(ResourceType::eCommandQueue); + SL_CASE_STR(ResourceType::eCommandBuffer); + SL_CASE_STR(ResourceType::eCommandPool); + SL_CASE_STR(ResourceType::eFence); + SL_CASE_STR(ResourceType::eSwapchain); + SL_CASE_STR(ResourceType::eHostFence); + case ResourceType::eUnknown: break; + case ResourceType::eCount: break; + }; + return "Unknown"; +} + +inline const char* getResourceLifecycleAsStr(ResourceLifecycle v) +{ + switch (v) + { + SL_CASE_STR(ResourceLifecycle::eOnlyValidNow); + SL_CASE_STR(ResourceLifecycle::eValidUntilPresent); + SL_CASE_STR(ResourceLifecycle::eValidUntilEvaluate); + }; + return "Unknown"; +} + +SL_DISABLE_DEPRECATED_WARNINGS +inline DLSSPreset resolveDLSSPreset(DLSSPreset preset) +{ + switch (preset) + { + case DLSSPreset::ePresetJ: + case DLSSPreset::ePresetK: + return preset; + default: + return DLSSPreset::eDefault; + } +} +SL_RESTORE_DEPRECATED_WARNINGS + +inline DLSSDPreset resolveDLSSDPreset(DLSSDPreset preset) +{ + return static_cast(resolveDLSSPreset(static_cast(preset))); +} + + + +// Advanced/internal functions that are not useful or necessary in the vast majority of integrations +// and would just pollute the namespace and/or cause distractions. +// But, may be useful in e.g. intermediary game engine integrations, etc. +#ifndef __INTELLISENSE__ + +//! Find a struct of type T +template +T* findStruct(const void* ptr) +{ + auto base = static_cast(ptr); + while (base && base->structType != T::s_structType) + { + base = base->next; + } + return (T*)base; +} + +//! Find a struct of type T, but stop the search if we find a struct of type S +template +T* findStruct(const void* ptr) +{ + auto base = static_cast(ptr); + while (base && base->structType != T::s_structType) + { + base = base->next; + + // If we find a struct of type S, we know should stop the search + if (base->structType == S::s_structType) + { + return nullptr; + } + } + return (T*)base; +} + +template +T* findStruct(const void** ptr, uint32_t count) +{ + const BaseStructure* base{}; + for (uint32_t i = 0; base == nullptr && i < count; i++) + { + base = static_cast(ptr[i]); + while (base && base->structType != T::s_structType) + { + base = base->next; + } + } + return (T*)base; +} + +template +bool findStructs(const void** ptr, uint32_t count, std::vector& structs) +{ + for (uint32_t i = 0; i < count; i++) + { + auto base = static_cast(ptr[i]); + while (base) + { + if (base->structType == T::s_structType) + { + structs.push_back((T*)base); + } + base = base->next; + } + } + return structs.size() > 0; +} + +#endif // __INTELLISENSE__ + +} // namespace sl diff --git a/third_party/streamline/include/sl_helpers_vk.h b/third_party/streamline/include/sl_helpers_vk.h new file mode 100644 index 000000000..77c4dbc0f --- /dev/null +++ b/third_party/streamline/include/sl_helpers_vk.h @@ -0,0 +1,256 @@ +/* +* Copyright (c) 2022-2023 NVIDIA CORPORATION. All rights reserved +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +#pragma once + +#include "sl.h" +#include + +namespace sl +{ + +#define SL_VK_FEATURE(n) if(strcmp(featureNames[i], #n) == 0) features.n = VK_TRUE; + +inline VkPhysicalDeviceVulkan12Features getVkPhysicalDeviceVulkan12Features(uint32_t featureCount, const char** featureNames) +{ + VkPhysicalDeviceVulkan12Features features{ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES }; + for (uint32_t i = 0; i < featureCount; i++) + { + SL_VK_FEATURE(samplerMirrorClampToEdge); + SL_VK_FEATURE(drawIndirectCount); + SL_VK_FEATURE(storageBuffer8BitAccess); + SL_VK_FEATURE(uniformAndStorageBuffer8BitAccess); + SL_VK_FEATURE(storagePushConstant8); + SL_VK_FEATURE(shaderBufferInt64Atomics); + SL_VK_FEATURE(shaderSharedInt64Atomics); + SL_VK_FEATURE(shaderFloat16); + SL_VK_FEATURE(shaderInt8); + SL_VK_FEATURE(descriptorIndexing); + SL_VK_FEATURE(shaderInputAttachmentArrayDynamicIndexing); + SL_VK_FEATURE(shaderUniformTexelBufferArrayDynamicIndexing); + SL_VK_FEATURE(shaderStorageTexelBufferArrayDynamicIndexing); + SL_VK_FEATURE(shaderUniformBufferArrayNonUniformIndexing); + SL_VK_FEATURE(shaderSampledImageArrayNonUniformIndexing); + SL_VK_FEATURE(shaderStorageBufferArrayNonUniformIndexing); + SL_VK_FEATURE(shaderStorageImageArrayNonUniformIndexing); + SL_VK_FEATURE(shaderInputAttachmentArrayNonUniformIndexing); + SL_VK_FEATURE(shaderUniformTexelBufferArrayNonUniformIndexing); + SL_VK_FEATURE(shaderStorageTexelBufferArrayNonUniformIndexing); + SL_VK_FEATURE(descriptorBindingUniformBufferUpdateAfterBind); + SL_VK_FEATURE(descriptorBindingSampledImageUpdateAfterBind); + SL_VK_FEATURE(descriptorBindingStorageImageUpdateAfterBind); + SL_VK_FEATURE(descriptorBindingStorageBufferUpdateAfterBind); + SL_VK_FEATURE(descriptorBindingUniformTexelBufferUpdateAfterBind); + SL_VK_FEATURE(descriptorBindingStorageTexelBufferUpdateAfterBind); + SL_VK_FEATURE(descriptorBindingUpdateUnusedWhilePending); + SL_VK_FEATURE(descriptorBindingPartiallyBound); + SL_VK_FEATURE(descriptorBindingVariableDescriptorCount); + SL_VK_FEATURE(runtimeDescriptorArray); + SL_VK_FEATURE(samplerFilterMinmax); + SL_VK_FEATURE(scalarBlockLayout); + SL_VK_FEATURE(imagelessFramebuffer); + SL_VK_FEATURE(uniformBufferStandardLayout); + SL_VK_FEATURE(shaderSubgroupExtendedTypes); + SL_VK_FEATURE(separateDepthStencilLayouts); + SL_VK_FEATURE(hostQueryReset); + SL_VK_FEATURE(timelineSemaphore); + SL_VK_FEATURE(bufferDeviceAddress); + SL_VK_FEATURE(bufferDeviceAddressCaptureReplay); + SL_VK_FEATURE(bufferDeviceAddressMultiDevice); + SL_VK_FEATURE(vulkanMemoryModel); + SL_VK_FEATURE(vulkanMemoryModelDeviceScope); + SL_VK_FEATURE(vulkanMemoryModelAvailabilityVisibilityChains); + SL_VK_FEATURE(shaderOutputViewportIndex); + SL_VK_FEATURE(shaderOutputLayer); + SL_VK_FEATURE(subgroupBroadcastDynamicId); + } + return features; +} + +inline VkPhysicalDeviceVulkan13Features getVkPhysicalDeviceVulkan13Features(uint32_t featureCount, const char** featureNames) +{ + VkPhysicalDeviceVulkan13Features features{ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES }; + for (uint32_t i = 0; i < featureCount; i++) + { + SL_VK_FEATURE(robustImageAccess); + SL_VK_FEATURE(robustImageAccess); + SL_VK_FEATURE(inlineUniformBlock); + SL_VK_FEATURE(descriptorBindingInlineUniformBlockUpdateAfterBind); + SL_VK_FEATURE(pipelineCreationCacheControl); + SL_VK_FEATURE(privateData); + SL_VK_FEATURE(shaderDemoteToHelperInvocation); + SL_VK_FEATURE(shaderTerminateInvocation); + SL_VK_FEATURE(subgroupSizeControl); + SL_VK_FEATURE(computeFullSubgroups); + SL_VK_FEATURE(synchronization2); + SL_VK_FEATURE(textureCompressionASTC_HDR); + SL_VK_FEATURE(shaderZeroInitializeWorkgroupMemory); + SL_VK_FEATURE(dynamicRendering); + SL_VK_FEATURE(shaderIntegerDotProduct); + SL_VK_FEATURE(maintenance4); + } + return features; +} + +inline VkPhysicalDeviceOpticalFlowFeaturesNV getVkPhysicalDeviceOpticalFlowNVFeatures(uint32_t featureCount, const char** featureNames) +{ + VkPhysicalDeviceOpticalFlowFeaturesNV features{ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPTICAL_FLOW_FEATURES_NV }; + for (uint32_t i = 0; i < featureCount; i++) + { + SL_VK_FEATURE(opticalFlow); + } + return features; +} + +#define SL_VK_FEATURE_SUPPORT(T, feature, n) ((T*)pPhysicalDeviceFeatures)->n = ((feature) && (((T*)pSupportedFeatures)->n)) +#define SL_VK_FEATURE_MERGE_SUPPORT(T, n) (pFeaturesToMerge == NULL) ? \ + SL_VK_FEATURE_SUPPORT(T, ((T*)pPhysicalDeviceFeatures)->n, n) : SL_VK_FEATURE_SUPPORT(T, ((((T*)pPhysicalDeviceFeatures)->n) || (((T*)pFeaturesToMerge)->n)), n) + +inline void getMergedSupportedVkPhysicalDeviceVulkanFeatures(VkBaseOutStructure* pPhysicalDeviceFeatures, const VkBaseOutStructure* pFeaturesToMerge, const VkBaseOutStructure* pSupportedFeatures) +{ + if (pPhysicalDeviceFeatures == NULL || pSupportedFeatures == NULL) + { + return; + } + + if (pFeaturesToMerge != NULL) + { + assert(pFeaturesToMerge->sType == pPhysicalDeviceFeatures->sType); + } + assert(pSupportedFeatures->sType == pPhysicalDeviceFeatures->sType); + + switch (pPhysicalDeviceFeatures->sType) + { + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES: + SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, samplerMirrorClampToEdge); + SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, samplerMirrorClampToEdge); + SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, drawIndirectCount); + SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, storageBuffer8BitAccess); + SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, uniformAndStorageBuffer8BitAccess); + SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, storagePushConstant8); + SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, shaderBufferInt64Atomics); + SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, shaderSharedInt64Atomics); + SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, shaderFloat16); + SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, shaderInt8); + SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, descriptorIndexing); + SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, shaderInputAttachmentArrayDynamicIndexing); + SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, shaderUniformTexelBufferArrayDynamicIndexing); + SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, shaderStorageTexelBufferArrayDynamicIndexing); + SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, shaderUniformBufferArrayNonUniformIndexing); + SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, shaderSampledImageArrayNonUniformIndexing); + SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, shaderStorageBufferArrayNonUniformIndexing); + SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, shaderStorageImageArrayNonUniformIndexing); + SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, shaderInputAttachmentArrayNonUniformIndexing); + SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, shaderUniformTexelBufferArrayNonUniformIndexing); + SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, shaderStorageTexelBufferArrayNonUniformIndexing); + SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, descriptorBindingUniformBufferUpdateAfterBind); + SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, descriptorBindingSampledImageUpdateAfterBind); + SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, descriptorBindingStorageImageUpdateAfterBind); + SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, descriptorBindingStorageBufferUpdateAfterBind); + SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, descriptorBindingUniformTexelBufferUpdateAfterBind); + SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, descriptorBindingStorageTexelBufferUpdateAfterBind); + SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, descriptorBindingUpdateUnusedWhilePending); + SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, descriptorBindingPartiallyBound); + SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, descriptorBindingVariableDescriptorCount); + SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, runtimeDescriptorArray); + SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, samplerFilterMinmax); + SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, scalarBlockLayout); + SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, imagelessFramebuffer); + SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, uniformBufferStandardLayout); + SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, shaderSubgroupExtendedTypes); + SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, separateDepthStencilLayouts); + SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, hostQueryReset); + SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, timelineSemaphore); + SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, bufferDeviceAddress); + SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, bufferDeviceAddressCaptureReplay); + SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, bufferDeviceAddressMultiDevice); + SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, vulkanMemoryModel); + SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, vulkanMemoryModelDeviceScope); + SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, vulkanMemoryModelAvailabilityVisibilityChains); + SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, shaderOutputViewportIndex); + SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, shaderOutputLayer); + SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan12Features, subgroupBroadcastDynamicId); + break; + + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES: + SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan13Features, robustImageAccess); + SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan13Features, robustImageAccess); + SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan13Features, inlineUniformBlock); + SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan13Features, descriptorBindingInlineUniformBlockUpdateAfterBind); + SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan13Features, pipelineCreationCacheControl); + SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan13Features, privateData); + SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan13Features, shaderDemoteToHelperInvocation); + SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan13Features, shaderTerminateInvocation); + SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan13Features, subgroupSizeControl); + SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan13Features, computeFullSubgroups); + SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan13Features, synchronization2); + SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan13Features, textureCompressionASTC_HDR); + SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan13Features, shaderZeroInitializeWorkgroupMemory); + SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan13Features, dynamicRendering); + SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan13Features, shaderIntegerDotProduct); + SL_VK_FEATURE_MERGE_SUPPORT(VkPhysicalDeviceVulkan13Features, maintenance4); + break; + + default: + break; + } +} + +//! Interface to provide to slSetVulkanInfo when manually hooking Vulkan API and NOT +//! leveraging vkCreateDevice and vkCreateInstance proxies provided by SL. +//! +//! {0EED6FD5-82CD-43A9-BDB5-47A5BA2F45D6} +SL_STRUCT_BEGIN(VulkanInfo, StructType({ 0xeed6fd5, 0x82cd, 0x43a9, { 0xbd, 0xb5, 0x47, 0xa5, 0xba, 0x2f, 0x45, 0xd6 } }), kStructVersion3) +VkDevice device {}; +VkInstance instance{}; +VkPhysicalDevice physicalDevice{}; +//! IMPORTANT: +//! +//! SL features can request additional graphics or compute queues. +//! The below values provide information about the queue families and +//! starting index at which SL queues are created. +uint32_t computeQueueIndex{}; +uint32_t computeQueueFamily{}; +uint32_t graphicsQueueIndex{}; +uint32_t graphicsQueueFamily{}; +uint32_t opticalFlowQueueIndex{}; +uint32_t opticalFlowQueueFamily{}; +bool useNativeOpticalFlowMode = false; +uint32_t computeQueueCreateFlags{}; +uint32_t graphicsQueueCreateFlags{}; +uint32_t opticalFlowQueueCreateFlags{}; +SL_STRUCT_END() + +} + +using PFun_slSetVulkanInfo = sl::Result(const sl::VulkanInfo& info); + +//! Specify Vulkan specific information +//! +//! Use this method to provide Vulkan device, instance information to SL. +//! +//! IMPORTANT: Only call this API if NOT using vkCreateDevice and vkCreateInstance proxies provided by SL. +// +//! @param info Reference to the structure providing the information +//! +//! This method is NOT thread safe and should be called IMMEDIATELY after base interface is created. +SL_API sl::Result slSetVulkanInfo(const sl::VulkanInfo& info); diff --git a/third_party/streamline/include/sl_hooks.h b/third_party/streamline/include/sl_hooks.h new file mode 100644 index 000000000..b9df141aa --- /dev/null +++ b/third_party/streamline/include/sl_hooks.h @@ -0,0 +1,115 @@ +/* +* Copyright (c) 2022-2023 NVIDIA CORPORATION. All rights reserved +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +#pragma once + +#include "sl.h" + +struct VkPhysicalDevice_T; +struct VkDevice_T; +struct VkInstance_T; + +using VkPhysicalDevice = VkPhysicalDevice_T*; +using VkDevice = VkDevice_T*; +using VkInstance = VkInstance_T*; + + +namespace sl +{ + +//! NOTE: Adding new hooks require sl.interposer to be recompiled +//! +//! IMPORTANT: Since SL interposer proxies supports many different versions of various D3D/DXGI interfaces +//! we use only base interface names for our hooks. +//! +//! For example if API was added in IDXGISwapChain5::FUNCTION it is still named eIDXGISwapChain_FUNCTION (there is no 5 in the name) +//! +enum class FunctionHookID : uint32_t +{ + //! Mandatory - IDXGIFactory* + eIDXGIFactory_CreateSwapChain, + eIDXGIFactory_CreateSwapChainForHwnd, + eIDXGIFactory_CreateSwapChainForCoreWindow, + + //! Mandatory - IDXGISwapChain* + eIDXGISwapChain_Present, + eIDXGISwapChain_Present1, + eIDXGISwapChain_GetBuffer, + eIDXGISwapChain_GetDesc, + eIDXGISwapChain_ResizeBuffers, + eIDXGISwapChain_ResizeBuffers1, + eIDXGISwapChain_GetCurrentBackBufferIndex, + eIDXGISwapChain_SetFullscreenState, + //! Internal - please ignore when doing manual hooking + eIDXGISwapChain_Destroyed, + + //! Mandatory - ID3D12Device* + eID3D12Device_CreateCommandQueue, + + //! Mandatory - Vulkan + eVulkan_Present, + eVulkan_CreateSwapchainKHR, + eVulkan_DestroySwapchainKHR, + eVulkan_GetSwapchainImagesKHR, + eVulkan_AcquireNextImageKHR, + eVulkan_DeviceWaitIdle, + eVulkan_CreateWin32SurfaceKHR, + eVulkan_DestroySurfaceKHR, + + eMaxNum +}; + +#ifndef SL_CASE_STR +#define SL_CASE_STR(a) case a : return #a; +#endif + +inline const char* getFunctionHookIDAsStr(FunctionHookID v) +{ + switch (v) + { + SL_CASE_STR(FunctionHookID::eIDXGIFactory_CreateSwapChain); + SL_CASE_STR(FunctionHookID::eIDXGIFactory_CreateSwapChainForHwnd); + SL_CASE_STR(FunctionHookID::eIDXGIFactory_CreateSwapChainForCoreWindow); + SL_CASE_STR(FunctionHookID::eIDXGISwapChain_Present); + SL_CASE_STR(FunctionHookID::eIDXGISwapChain_Present1); + SL_CASE_STR(FunctionHookID::eIDXGISwapChain_GetBuffer); + SL_CASE_STR(FunctionHookID::eIDXGISwapChain_GetDesc); + SL_CASE_STR(FunctionHookID::eIDXGISwapChain_ResizeBuffers); + SL_CASE_STR(FunctionHookID::eIDXGISwapChain_ResizeBuffers1); + SL_CASE_STR(FunctionHookID::eIDXGISwapChain_GetCurrentBackBufferIndex); + SL_CASE_STR(FunctionHookID::eIDXGISwapChain_SetFullscreenState); + SL_CASE_STR(FunctionHookID::eIDXGISwapChain_Destroyed); + SL_CASE_STR(FunctionHookID::eID3D12Device_CreateCommandQueue); + SL_CASE_STR(FunctionHookID::eVulkan_Present); + SL_CASE_STR(FunctionHookID::eVulkan_CreateSwapchainKHR); + SL_CASE_STR(FunctionHookID::eVulkan_DestroySwapchainKHR); + SL_CASE_STR(FunctionHookID::eVulkan_GetSwapchainImagesKHR); + SL_CASE_STR(FunctionHookID::eVulkan_AcquireNextImageKHR); + SL_CASE_STR(FunctionHookID::eVulkan_DeviceWaitIdle); + SL_CASE_STR(FunctionHookID::eVulkan_CreateWin32SurfaceKHR); + SL_CASE_STR(FunctionHookID::eVulkan_DestroySurfaceKHR); + case FunctionHookID::eMaxNum: break; + }; + return "Unknown"; +} + +} // namespace sl diff --git a/third_party/streamline/include/sl_matrix_helpers.h b/third_party/streamline/include/sl_matrix_helpers.h new file mode 100644 index 000000000..4c4fe236b --- /dev/null +++ b/third_party/streamline/include/sl_matrix_helpers.h @@ -0,0 +1,221 @@ +/* +* Copyright (c) 2022-2023 NVIDIA CORPORATION. All rights reserved +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +#pragma once + +#include "sl.h" +#include "sl_consts.h" + +namespace sl +{ + +inline void matrixMul(float4x4& result, const float4x4& a, const float4x4& b) +{ + // Alias raw pointers over the input matrices + const float* pA = &a[0].x; + const float* pB = &b[0].x; + + result[0].x = (float)((pA[0] * pB[0]) + (pA[1] * pB[4]) + (pA[2] * pB[8]) + (pA[3] * pB[12])); + result[0].y = (float)((pA[0] * pB[1]) + (pA[1] * pB[5]) + (pA[2] * pB[9]) + (pA[3] * pB[13])); + result[0].z = (float)((pA[0] * pB[2]) + (pA[1] * pB[6]) + (pA[2] * pB[10]) + (pA[3] * pB[14])); + result[0].w = (float)((pA[0] * pB[3]) + (pA[1] * pB[7]) + (pA[2] * pB[11]) + (pA[3] * pB[15])); + + result[1].x = (float)((pA[4] * pB[0]) + (pA[5] * pB[4]) + (pA[6] * pB[8]) + (pA[7] * pB[12])); + result[1].y = (float)((pA[4] * pB[1]) + (pA[5] * pB[5]) + (pA[6] * pB[9]) + (pA[7] * pB[13])); + result[1].z = (float)((pA[4] * pB[2]) + (pA[5] * pB[6]) + (pA[6] * pB[10]) + (pA[7] * pB[14])); + result[1].w = (float)((pA[4] * pB[3]) + (pA[5] * pB[7]) + (pA[6] * pB[11]) + (pA[7] * pB[15])); + + result[2].x = (float)((pA[8] * pB[0]) + (pA[9] * pB[4]) + (pA[10] * pB[8]) + (pA[11] * pB[12])); + result[2].y = (float)((pA[8] * pB[1]) + (pA[9] * pB[5]) + (pA[10] * pB[9]) + (pA[11] * pB[13])); + result[2].z = (float)((pA[8] * pB[2]) + (pA[9] * pB[6]) + (pA[10] * pB[10]) + (pA[11] * pB[14])); + result[2].w = (float)((pA[8] * pB[3]) + (pA[9] * pB[7]) + (pA[10] * pB[11]) + (pA[11] * pB[15])); + + result[3].x = (float)((pA[12] * pB[0]) + (pA[13] * pB[4]) + (pA[14] * pB[8]) + (pA[15] * pB[12])); + result[3].y = (float)((pA[12] * pB[1]) + (pA[13] * pB[5]) + (pA[14] * pB[9]) + (pA[15] * pB[13])); + result[3].z = (float)((pA[12] * pB[2]) + (pA[13] * pB[6]) + (pA[14] * pB[10]) + (pA[15] * pB[14])); + result[3].w = (float)((pA[12] * pB[3]) + (pA[13] * pB[7]) + (pA[14] * pB[11]) + (pA[15] * pB[15])); +} + +inline void matrixFullInvert(float4x4& result, const float4x4& mat) +{ + // Matrix inversion code from https://stackoverflow.com/questions/1148309/inverting-a-4x4-matrix + // Alias raw pointers over the input matrix and the result + const float* pMat = &mat[0].x; + float* pResult = &result[0].x; + + pResult[0] = pMat[5] * pMat[10] * pMat[15] - pMat[5] * pMat[11] * pMat[14] - pMat[9] * pMat[6] * pMat[15] + pMat[9] * pMat[7] * pMat[14] + pMat[13] * pMat[6] * pMat[11] - pMat[13] * pMat[7] * pMat[10]; + pResult[4] = -pMat[4] * pMat[10] * pMat[15] + pMat[4] * pMat[11] * pMat[14] + pMat[8] * pMat[6] * pMat[15] - pMat[8] * pMat[7] * pMat[14] - pMat[12] * pMat[6] * pMat[11] + pMat[12] * pMat[7] * pMat[10]; + pResult[8] = pMat[4] * pMat[9] * pMat[15] - pMat[4] * pMat[11] * pMat[13] - pMat[8] * pMat[5] * pMat[15] + pMat[8] * pMat[7] * pMat[13] + pMat[12] * pMat[5] * pMat[11] - pMat[12] * pMat[7] * pMat[9]; + pResult[12] = -pMat[4] * pMat[9] * pMat[14] + pMat[4] * pMat[10] * pMat[13] + pMat[8] * pMat[5] * pMat[14] - pMat[8] * pMat[6] * pMat[13] - pMat[12] * pMat[5] * pMat[10] + pMat[12] * pMat[6] * pMat[9]; + pResult[1] = -pMat[1] * pMat[10] * pMat[15] + pMat[1] * pMat[11] * pMat[14] + pMat[9] * pMat[2] * pMat[15] - pMat[9] * pMat[3] * pMat[14] - pMat[13] * pMat[2] * pMat[11] + pMat[13] * pMat[3] * pMat[10]; + pResult[5] = pMat[0] * pMat[10] * pMat[15] - pMat[0] * pMat[11] * pMat[14] - pMat[8] * pMat[2] * pMat[15] + pMat[8] * pMat[3] * pMat[14] + pMat[12] * pMat[2] * pMat[11] - pMat[12] * pMat[3] * pMat[10]; + pResult[9] = -pMat[0] * pMat[9] * pMat[15] + pMat[0] * pMat[11] * pMat[13] + pMat[8] * pMat[1] * pMat[15] - pMat[8] * pMat[3] * pMat[13] - pMat[12] * pMat[1] * pMat[11] + pMat[12] * pMat[3] * pMat[9]; + pResult[13] = pMat[0] * pMat[9] * pMat[14] - pMat[0] * pMat[10] * pMat[13] - pMat[8] * pMat[1] * pMat[14] + pMat[8] * pMat[2] * pMat[13] + pMat[12] * pMat[1] * pMat[10] - pMat[12] * pMat[2] * pMat[9]; + pResult[2] = pMat[1] * pMat[6] * pMat[15] - pMat[1] * pMat[7] * pMat[14] - pMat[5] * pMat[2] * pMat[15] + pMat[5] * pMat[3] * pMat[14] + pMat[13] * pMat[2] * pMat[7] - pMat[13] * pMat[3] * pMat[6]; + pResult[6] = -pMat[0] * pMat[6] * pMat[15] + pMat[0] * pMat[7] * pMat[14] + pMat[4] * pMat[2] * pMat[15] - pMat[4] * pMat[3] * pMat[14] - pMat[12] * pMat[2] * pMat[7] + pMat[12] * pMat[3] * pMat[6]; + pResult[10] = pMat[0] * pMat[5] * pMat[15] - pMat[0] * pMat[7] * pMat[13] - pMat[4] * pMat[1] * pMat[15] + pMat[4] * pMat[3] * pMat[13] + pMat[12] * pMat[1] * pMat[7] - pMat[12] * pMat[3] * pMat[5]; + pResult[14] = -pMat[0] * pMat[5] * pMat[14] + pMat[0] * pMat[6] * pMat[13] + pMat[4] * pMat[1] * pMat[14] - pMat[4] * pMat[2] * pMat[13] - pMat[12] * pMat[1] * pMat[6] + pMat[12] * pMat[2] * pMat[5]; + pResult[3] = -pMat[1] * pMat[6] * pMat[11] + pMat[1] * pMat[7] * pMat[10] + pMat[5] * pMat[2] * pMat[11] - pMat[5] * pMat[3] * pMat[10] - pMat[9] * pMat[2] * pMat[7] + pMat[9] * pMat[3] * pMat[6]; + pResult[7] = pMat[0] * pMat[6] * pMat[11] - pMat[0] * pMat[7] * pMat[10] - pMat[4] * pMat[2] * pMat[11] + pMat[4] * pMat[3] * pMat[10] + pMat[8] * pMat[2] * pMat[7] - pMat[8] * pMat[3] * pMat[6]; + pResult[11] = -pMat[0] * pMat[5] * pMat[11] + pMat[0] * pMat[7] * pMat[9] + pMat[4] * pMat[1] * pMat[11] - pMat[4] * pMat[3] * pMat[9] - pMat[8] * pMat[1] * pMat[7] + pMat[8] * pMat[3] * pMat[5]; + pResult[15] = pMat[0] * pMat[5] * pMat[10] - pMat[0] * pMat[6] * pMat[9] - pMat[4] * pMat[1] * pMat[10] + pMat[4] * pMat[2] * pMat[9] + pMat[8] * pMat[1] * pMat[6] - pMat[8] * pMat[2] * pMat[5]; + + float det = pMat[0] * pResult[0] + pMat[1] * pResult[4] + pMat[2] * pResult[8] + pMat[3] * pResult[12]; + if (det != 0.f) + { + det = 1.0f / det; + + for (int i = 0; i < 16; ++i) + { + pResult[i] *= det; + } + } +} + +// Specialised lightweight matrix invert when the matrix is known to be orthonormal +inline void matrixOrthoNormalInvert(float4x4& result, const float4x4& mat) +{ + // Transpose the first 3x3 + result[0].x = mat[0].x; + result[0].y = mat[1].x; + result[0].z = mat[2].x; + result[1].x = mat[0].y; + result[1].y = mat[1].y; + result[1].z = mat[2].y; + result[2].x = mat[0].z; + result[2].y = mat[1].z; + result[2].z = mat[2].z; + + // Invert the translation + result[3].x = -((mat[3].x * mat[0].x) + (mat[3].y * mat[0].y) + (mat[3].z * mat[0].z)); + result[3].y = -((mat[3].x * mat[1].x) + (mat[3].y * mat[1].y) + (mat[3].z * mat[1].z)); + result[3].z = -((mat[3].x * mat[2].x) + (mat[3].y * mat[2].y) + (mat[3].z * mat[2].z)); + + // Fill in the remaining constants + result[0].w = 0.0f; + result[1].w = 0.0f; + result[2].w = 0.0f; + result[3].w = 1.0f; +} + +inline void vectorNormalize(float3& v) +{ + float k = 1.f / sqrtf((v.x * v.x) + (v.y * v.y) + (v.z * v.z)); + v.x *= k; + v.y *= k; + v.z *= k; +} + +inline void vectorCrossProduct(float3& result, const float3& a, const float3& b) +{ + result.x = a.y * b.z - a.z * b.y; + result.y = a.z * b.x - a.x * b.z; + result.z = a.x * b.y - a.y * b.x; +} + +// Calculate a cameraToPrevCamera matrix from cameraToWorld and cameraToWorldPrev matrices +// but do so in such a way as to avoid precision issues. +// +// Traditionally, you might go something like this... +// +// worldToCameraPrev = invert(cameraToWorldPrev) +// cameraToPrevCamera = cameraToWorld * worldToCameraPrev +// +// But if you do that, you will subject yourself to fp32 precision issues if the camera is +// any kind of reasonable distance from the origin, because you'll end up adding small +// numbers to large numbers due to the large translations. +// +// But the camera's absolute position in the world doesn't matter at all to the result. +// What we're interested in is the camera's motion. +// So if we add the same thing to the translations of cameraToWorld and cameraToWorldPrev +// then we should get the same result. +// If we choose to subtract the current camera's translation in world space, then we will +// change a potentially very large translation value into a very small one - thereby +// sidestepping the precision issues. +inline void calcCameraToPrevCamera(float4x4& outCameraToPrevCamera, const float4x4& cameraToWorld, const float4x4& cameraToWorldPrev) +{ + // Create translated versions of cameraToWorld and cameraToWorldPrev, translated to + // so that the current camera is effectively at the world origin. + // CC == 'Camera-Centred' + float4x4 cameraToCcWorld = cameraToWorld; + cameraToCcWorld[3] = float4(0, 0, 0, 1); + float4x4 cameraToCcWorldPrev = cameraToWorldPrev; + cameraToCcWorldPrev[3].x -= cameraToWorld[3].x; + cameraToCcWorldPrev[3].y -= cameraToWorld[3].y; + cameraToCcWorldPrev[3].z -= cameraToWorld[3].z; + + // We can use an optimised invert if we assume that the camera matrix is orthonormal + float4x4 ccWorldToCameraPrev; + matrixOrthoNormalInvert(ccWorldToCameraPrev, cameraToCcWorldPrev); + matrixMul(outCameraToPrevCamera, cameraToCcWorld, ccWorldToCameraPrev); +} + +// Calculate some of the matrix fields in Constants +// This can be used to validate what the app is providing, or tease out precision issues +// The matrices that are recalculated are... +// - clipToCameraView +// - clipToPrevClip +// - prevClipToClip +inline void recalculateCameraMatrices(Constants& values) +{ + // Form a camera-to-world matrix from the camera fields + vectorNormalize(values.cameraRight); + vectorNormalize(values.cameraFwd); + vectorCrossProduct(values.cameraUp, values.cameraFwd, values.cameraRight); + vectorNormalize(values.cameraUp); + float4x4 cameraViewToWorld = { + float4(values.cameraRight.x, values.cameraRight.y, values.cameraRight.z, 0.f), + float4(values.cameraUp.x, values.cameraUp.y, values.cameraUp.z, 0.f), + float4(values.cameraFwd.x, values.cameraFwd.y, values.cameraFwd.z, 0.f), + float4(values.cameraPos.x, values.cameraPos.y, values.cameraPos.z, 1.f) + }; + // ********* DO NOT USE THIS IN ANYTHING PROPER ********* + // Crap storage of cameraViewToWorldPrev and cameraViewToClipPrev + // These should be provided by the app, or stored by association with the view index. + static float4x4 cameraViewToWorldPrev = { + float4(1, 0, 0, 0), + float4(0, 1, 0, 0), + float4(0, 0, 1, 0), + float4(0, 0, 0, 1), + }; + static float4x4 cameraViewToClipPrev = { + float4(1, 0, 0, 0), + float4(0, 1, 0, 0), + float4(0, 0, 1, 0), + float4(0, 0, 0, 1), + }; + matrixFullInvert(values.clipToCameraView, values.cameraViewToClip); + + float4x4 cameraViewToPrevCameraView; + calcCameraToPrevCamera(cameraViewToPrevCameraView, cameraViewToWorld, cameraViewToWorldPrev); + + float4x4 clipToPrevCameraView; + matrixMul(clipToPrevCameraView, values.clipToCameraView, cameraViewToPrevCameraView); + matrixMul(values.clipToPrevClip, clipToPrevCameraView, cameraViewToClipPrev); + matrixFullInvert(values.prevClipToClip, values.clipToPrevClip); + + // ********* DO NOT USE THIS IN ANYTHING PROPER ********* + cameraViewToWorldPrev = cameraViewToWorld; + cameraViewToClipPrev = values.cameraViewToClip; +} + +} diff --git a/third_party/streamline/include/sl_nis.h b/third_party/streamline/include/sl_nis.h new file mode 100644 index 000000000..8a0e87f8d --- /dev/null +++ b/third_party/streamline/include/sl_nis.h @@ -0,0 +1,102 @@ +/* +* Copyright (c) 2022-2023 NVIDIA CORPORATION. All rights reserved +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +#pragma once + +namespace sl +{ + +enum class NISMode : uint32_t +{ + eOff, + eScaler, + eSharpen, + eCount +}; + +enum class NISHDR : uint32_t +{ + eNone, + eLinear, + ePQ, + eCount +}; + +// {676610E5-9674-4D3A-9C8A-F495D01B36F3} +SL_STRUCT_BEGIN(NISOptions, StructType({ 0x676610e5, 0x9674, 0x4d3a, { 0x9c, 0x8a, 0xf4, 0x95, 0xd0, 0x1b, 0x36, 0xf3 } }), kStructVersion1) + //! Specifies which mode should be used + NISMode mode = NISMode::eScaler; + //! Specifies which hdr mode should be used + NISHDR hdrMode = NISHDR::eNone; + //! Specifies sharpening level in range [0,1] + float sharpness = 0.0f; + + //! IMPORTANT: New members go here or if optional can be chained in a new struct, see sl_struct.h for details +SL_STRUCT_END() + +//! Returned by the NIS plugin +//! +// {71AB4FD0-D959-4C2A-AF69-ED4850BD4E3D} +SL_STRUCT_BEGIN(NISState, StructType({ 0x71ab4fd0, 0xd959, 0x4c2a, { 0xaf, 0x69, 0xed, 0x48, 0x50, 0xbd, 0x4e, 0x3d } }), kStructVersion1) + //! Specified the amount of memory expected to be used + uint64_t estimatedVRAMUsageInBytes {}; + +//! IMPORTANT: New members go here or if optional can be chained in a new struct, see sl_struct.h for details +SL_STRUCT_END() + +} + +//! Sets NIS options +//! +//! Call this method to turn DLSS on/off, change mode etc. +//! +//! @param viewport Specified viewport we are working with +//! @param options Specifies NIS options to use +//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details) +//! +//! This method is NOT thread safe. +using PFun_slNISSetOptions = sl::Result(const sl::ViewportHandle& viewport, const sl::NISOptions& options); + +//! Provides NIS state for the given viewport +//! +//! Call this method to obtain VRAM usage and other information. +//! +//! @param viewport Specified viewport we are working with +//! @param state Reference to a structure where state is to be returned +//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details) +//! +//! This method is NOT thread safe. +using PFun_slNISGetState = sl::Result(const sl::ViewportHandle& viewport, sl::NISState& state); + +//! HELPERS +//! +inline sl::Result slNISSetOptions(const sl::ViewportHandle& viewport, const sl::NISOptions& options) +{ + SL_FEATURE_FUN_IMPORT_STATIC(sl::kFeatureNIS, slNISSetOptions); + return s_slNISSetOptions(viewport, options); +} + +inline sl::Result slNISGetState(const sl::ViewportHandle& viewport, sl::NISState& state) +{ + SL_FEATURE_FUN_IMPORT_STATIC(sl::kFeatureNIS, slNISGetState); + return s_slNISGetState(viewport, state); +} diff --git a/third_party/streamline/include/sl_nvperf.h b/third_party/streamline/include/sl_nvperf.h new file mode 100644 index 000000000..0c570c424 --- /dev/null +++ b/third_party/streamline/include/sl_nvperf.h @@ -0,0 +1,70 @@ +/* + * Copyright 2014-2023 NVIDIA Corporation. All rights reserved. + * + * NOTICE TO USER: + * + * This source code is subject to NVIDIA ownership rights under U.S. and + * international Copyright laws. + * + * This software and the information contained herein is PROPRIETARY and + * CONFIDENTIAL to NVIDIA and is being provided under the terms and conditions + * of a form of NVIDIA software license agreement. + * + * NVIDIA MAKES NO REPRESENTATION ABOUT THE SUITABILITY OF THIS SOURCE + * CODE FOR ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR + * IMPLIED WARRANTY OF ANY KIND. NVIDIA DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOURCE CODE, INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE. + * IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL, + * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE + * OR PERFORMANCE OF THIS SOURCE CODE. + * + * U.S. Government End Users. This source code is a "commercial item" as + * that term is defined at 48 C.F.R. 2.101 (OCT 1995), consisting of + * "commercial computer software" and "commercial computer software + * documentation" as such terms are used in 48 C.F.R. 12.212 (SEPT 1995) + * and is provided to the U.S. Government only as a commercial end item. + * Consistent with 48 C.F.R.12.212 and 48 C.F.R. 227.7202-1 through + * 227.7202-4 (JUNE 1995), all U.S. Government End Users acquire the + * source code with only those rights set forth herein. + * + * Any use of this source code in individual and commercial software must + * include, in the user documentation and internal comments to the code, + * the above Disclaimer and U.S. Government End Users Notice. + */ + +#pragma once + +namespace sl +{ + +//! If your plugin does not have any constants then the code below can be removed +//! +enum class NvPerfMode : uint32_t +{ + eOff, + eOn, + + eCount +}; + +//! IMPORTANT: Each structure must have a unique GUID assigned, change this as needed +//! +// {29DF7FE0-273A-4D72-B481-2DC823D5B1AD} +SL_STRUCT_BEGIN(NvPerfConstants, StructType({ 0x29df7fe0, 0x273a, 0x4d72, { 0xb4, 0x81, 0x2d, 0xc8, 0x23, 0xd5, 0xb1, 0xad } }), kStructVersion1) +NvPerfMode mode = NvPerfMode::eOff; + + //! IMPORTANT: New members go here or if optional can be chained in a new struct, see sl_struct.h for details +SL_STRUCT_END() + +//! IMPORTANT: Each structure must have a unique GUID assigned, change this as needed +//! +// {39DF7FE0-283A-4D72-B481-2DC823D5B1AD} +SL_STRUCT_BEGIN(NvPerfSettings, StructType({ 0x39df7fe0, 0x283a, 0x4d72, { 0xb4, 0x81, 0x2d, 0xc8, 0x23, 0xd5, 0xb1, 0xad } }), kStructVersion1) + + //! IMPORTANT: New members go here or if optional can be chained in a new struct, see sl_struct.h for details +SL_STRUCT_END() + +} diff --git a/third_party/streamline/include/sl_pcl.h b/third_party/streamline/include/sl_pcl.h new file mode 100644 index 000000000..dec5855cc --- /dev/null +++ b/third_party/streamline/include/sl_pcl.h @@ -0,0 +1,163 @@ +/* +* Copyright (c) 2023 NVIDIA CORPORATION. All rights reserved +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +#pragma once + +#include + +#include "sl.h" + +namespace sl +{ + +//! Hot-key which should be used instead of custom message for PC latency marker +enum class PCLHotKey: int16_t +{ + eUsePingMessage = 0, + eVK_F13 = 0x7C, + eVK_F14 = 0x7D, + eVK_F15 = 0x7E, +}; + +// {cfa32f9b-023c-420e-9056-6832b74f89b4} +SL_STRUCT_BEGIN(PCLOptions, StructType({ 0xcfa32f9b, 0x023c, 0x420e, { 0x90, 0x56, 0x68, 0x32, 0xb7, 0x4f, 0x89, 0xb4 } }), kStructVersion1) + //! Specifies the hot-key which should be used instead of custom message for PC latency marker + //! Possible values: VK_F13, VK_F14, VK_F15 + PCLHotKey virtualKey = PCLHotKey::eUsePingMessage; + //! ThreadID for PCL messages + uint32_t idThread = 0; + + //! IMPORTANT: New members go here or if optional can be chained in a new struct, see sl_struct.h for details +SL_STRUCT_END() + +// {cfa32f9b-023c-420e-9056-6832b74f89b5} +SL_STRUCT_BEGIN(PCLState, StructType({ 0xcfa32f9b, 0x023c, 0x420e, { 0x90, 0x56, 0x68, 0x32, 0xb7, 0x4f, 0x89, 0xb5 } }), kStructVersion1) + //! Specifies PCL Windows message id (if PCLOptions::virtualKey is 0) + uint32_t statsWindowMessage; + + //! IMPORTANT: New members go here or if optional can be chained in a new struct, see sl_struct.h for details +SL_STRUCT_END() + +enum class PCLMarker: uint32_t +{ + eSimulationStart = 0, + eSimulationEnd = 1, + eRenderSubmitStart = 2, + eRenderSubmitEnd = 3, + ePresentStart = 4, + ePresentEnd = 5, + //eInputSample = 6, // Deprecated + eTriggerFlash = 7, + ePCLatencyPing = 8, + eOutOfBandRenderSubmitStart = 9, + eOutOfBandRenderSubmitEnd = 10, + eOutOfBandPresentStart = 11, + eOutOfBandPresentEnd = 12, + eControllerInputSample = 13, + eDeltaTCalculation = 14, + eLateWarpPresentStart = 15, + eLateWarpPresentEnd = 16, + eCameraConstructed = 17, + eLateWarpRenderSubmitStart = 18, + eLateWarpRenderSubmitEnd = 19, + eVendorInternalAsyncPresentStart = 20, + eVendorInternalAsyncPresentEnd = 21, + eNumPresentsInBatch = 22, + + eMaximum +}; + +// c++23 has to_underlying implementation +#if __cplusplus == 202302L +using to_underlying = std::to_underlying; +#else +// Return `enum class` member as value of underlying type (i.e. an int). Basically same as: +// static_cast>(value); +// See c++23s std::to_underlying() +template +constexpr auto to_underlying(T value) +{ + return std::underlying_type_t(value); +} +#endif + +// {cfa32f9b-023c-420e-9056-6832b74f89b6} +SL_STRUCT_BEGIN(PCLHelper, StructType({ 0xcfa32f9b, 0x023c, 0x420e, { 0x90, 0x56, 0x68, 0x32, 0xb7, 0x4f, 0x89, 0xb6 } }), kStructVersion1) + PCLHelper(PCLMarker m) : BaseStructure(PCLHelper::s_structType, kStructVersion1), marker(m) {}; + PCLMarker get() const { return marker; }; +private: + PCLMarker marker; +SL_STRUCT_END() + + +} + +//! Provides PCL settings +//! +//! Call this method to get stats etc. +//! +//! @param state Reference to a structure where states are returned +//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details) +//! +//! This method is NOT thread safe. +using PFun_slPCLGetState = sl::Result(sl::PCLState& state); + +//! Sets PCL marker +//! +//! Call this method to set specific PCL marker +//! +//! @param marker Specifies which marker to use +//! @param frame Specifies current frame +//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details) +//! +//! This method is thread safe. +using PFun_slPCLSetMarker = sl::Result(sl::PCLMarker marker, const sl::FrameToken& frame); + +//! Sets PCL options +//! +//! Call this method to set PCL options. +//! +//! @param options Specifies options to use +//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details) +//! +//! This method is NOT thread safe. +using PFun_slPCLSetOptions = sl::Result(const sl::PCLOptions& options); + +//! HELPERS +//! +inline sl::Result slPCLGetState(sl::PCLState& state) +{ + SL_FEATURE_FUN_IMPORT_STATIC(sl::kFeaturePCL, slPCLGetState); + return s_slPCLGetState(state); +} + +inline sl::Result slPCLSetMarker(sl::PCLMarker marker, const sl::FrameToken& frame) +{ + SL_FEATURE_FUN_IMPORT_STATIC(sl::kFeaturePCL, slPCLSetMarker); + return s_slPCLSetMarker(marker, frame); +} + +inline sl::Result slPCLSetOptions(const sl::PCLOptions& options) +{ + SL_FEATURE_FUN_IMPORT_STATIC(sl::kFeaturePCL, slPCLSetOptions); + return s_slPCLSetOptions(options); +} diff --git a/third_party/streamline/include/sl_reflex.h b/third_party/streamline/include/sl_reflex.h new file mode 100644 index 000000000..c974483d9 --- /dev/null +++ b/third_party/streamline/include/sl_reflex.h @@ -0,0 +1,233 @@ +/* +* Copyright (c) 2022-2023 NVIDIA CORPORATION. All rights reserved +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +#pragma once + +#include "sl_pcl.h" + +namespace sl +{ + +enum ReflexMode +{ + eOff, + eLowLatency, + eLowLatencyWithBoost, + + // ReflexMode is a C-enum (rather than enum class) so we can't add an eCount value + // without polluting the global namespace (and conflicts with SMSCGMode::eCount in sl.dlss_g/defines.h) + ReflexMode_eCount +}; + +// {F03AF81A-6D0B-4902-A651-C4965E215434} +SL_STRUCT_BEGIN(ReflexOptions, StructType({ 0xf03af81a, 0x6d0b, 0x4902, { 0xa6, 0x51, 0xc4, 0x96, 0x5e, 0x21, 0x54, 0x34 } }), kStructVersion1) + //! Specifies which mode should be used + ReflexMode mode = ReflexMode::eOff; + //! Specifies if frame limiting (FPS cap) is enabled (0 to disable, microseconds otherwise). + //! One benefit of using Reflex's FPS cap over other implementations is the driver would be aware and can provide better optimizations. + //! This setting is independent of ReflexOptions::mode; it can even be used with mode == ReflexMode::eOff. + //! The value is used each time you call slReflexSetOptions/slSetData, make sure to initialize when changing one of the other Reflex options during frame limiting. + //! It is overridden (ignored) by frameLimitUs if set in sl.reflex.json in non-production builds. + uint32_t frameLimitUs = 0; + //! This should only be enabled in specific scenarios with subtle caveats. + //! Most integrations should leave unset unless advised otherwise by the Reflex team + bool useMarkersToOptimize = false; + //! Specifies the hot-key which should be used instead of custom message for PC latency marker + //! Possible values: VK_F13, VK_F14, VK_F15 + uint16_t virtualKey = 0; + //! ThreadID for PCL Stats messages + //! Most integrations should leave unset unless advised otherwise by the Reflex team + uint32_t idThread = 0; + + //! IMPORTANT: New members go here or if optional can be chained in a new struct, see sl_struct.h for details +SL_STRUCT_END() + +// {0D569B37-A1C8-4453-BE4D-40F4DE57952B} +SL_STRUCT_BEGIN(ReflexReport, StructType({ 0xd569b37, 0xa1c8, 0x4453, { 0xbe, 0x4d, 0x40, 0xf4, 0xde, 0x57, 0x95, 0x2b } }), kStructVersion1) + //! Various latency related stats + uint64_t frameID{}; + uint64_t inputSampleTime{}; + uint64_t simStartTime{}; + uint64_t simEndTime{}; + uint64_t renderSubmitStartTime{}; + uint64_t renderSubmitEndTime{}; + uint64_t presentStartTime{}; + uint64_t presentEndTime{}; + uint64_t driverStartTime{}; + uint64_t driverEndTime{}; + uint64_t osRenderQueueStartTime{}; + uint64_t osRenderQueueEndTime{}; + uint64_t gpuRenderStartTime{}; + uint64_t gpuRenderEndTime{}; + uint32_t gpuActiveRenderTimeUs{}; + uint32_t gpuFrameTimeUs{}; + //! IMPORTANT: This struct cannot have new members because it is arrayed by ReflexState. +SL_STRUCT_END() + +// {68bb0632-5e1c-402b-899d-b49f633c56c2} +SL_STRUCT_BEGIN(ReflexReport2, StructType({ 0x68bb0632, 0x5e1c, 0x402b, { 0x89, 0x9d, 0xb4, 0x9f, 0x63, 0x3c, 0x56, 0xc2 } }), kStructVersion1) + //! Various latency related stats + uint64_t cameraConstructedTime{}; + uint32_t crossAdapterCopyTimeUs{}; + //! IMPORTANT: This struct cannot have new members because it is arrayed by ReflexState. +SL_STRUCT_END() + +constexpr int kReflexFrameReportCount = 64; + +// {F0BB5985-DAF9-4728-B2FD-AE80A2BD7989} +SL_STRUCT_BEGIN(ReflexState, StructType({ 0xf0bb5985, 0xdaf9, 0x4728, { 0xb2, 0xfd, 0xae, 0x80, 0xa2, 0xbd, 0x79, 0x89 } }), kStructVersion2) + //! Specifies if low-latency mode is available or not + bool lowLatencyAvailable = false; + //! Specifies if the frameReport below contains valid data or not + bool latencyReportAvailable = false; + //! Specifies low latency Windows message id (if ReflexOptions::virtualKey is 0) + uint32_t statsWindowMessage; + //! Reflex report per frame + ReflexReport frameReport[kReflexFrameReportCount]; + //! Specifies ownership of flash indicator toggle (true = driver, false = application) + bool flashIndicatorDriverControlled = false; + // kStructVersion2 + //! Reflex report per frame + ReflexReport2 frameReport2[kReflexFrameReportCount]; + + //! IMPORTANT: New members go here or if optional can be chained in a new struct, see sl_struct.h for details +SL_STRUCT_END() + +// {c83cbb02-b4e2-4260-9ca2-d0c3de3a9684} +SL_STRUCT_BEGIN(ReflexCameraData, StructType({ 0xc83cbb02, 0xb4e2, 0x4260, { 0x9c, 0xa2, 0xd0, 0xc3, 0xde, 0x3a, 0x96, 0x84 } }), kStructVersion1) + float4x4 worldToViewMatrix; + float4x4 viewToClipMatrix; + float4x4 prevRenderedWorldToViewMatrix; + float4x4 prevRenderedViewToClipMatrix; + + //! IMPORTANT: New members go here or if optional can be chained in a new struct, see sl_struct.h for details +SL_STRUCT_END() + +// {8b960090-a807-4c85-b02f-1069950d066c} +SL_STRUCT_BEGIN(ReflexPredictedCameraData, StructType({ 0x8b960090, 0xa807, 0x4c85, { 0xb0, 0x2f, 0x10, 0x69, 0x95, 0x0d, 0x06, 0x6c } }), kStructVersion1) + float4x4 predictedWorldToViewMatrix; + float4x4 predictedViewToClipMatrix; + +//! IMPORTANT: New members go here or if optional can be chained in a new struct, see sl_struct.h for details +SL_STRUCT_END() + +using MarkerUnderlying = std::underlying_type_t; + +// {E268B3DC-F963-4C37-9776-AF048E132621} +SL_STRUCT_BEGIN(ReflexHelper, StructType({ 0xe268b3dc, 0xf963, 0x4c37, { 0x97, 0x76, 0xaf, 0x4, 0x8e, 0x13, 0x26, 0x21 } }), kStructVersion1) + ReflexHelper(MarkerUnderlying m) : BaseStructure(ReflexHelper::s_structType, kStructVersion1), marker(m) {}; + ReflexHelper(PCLMarker m) : BaseStructure(ReflexHelper::s_structType, kStructVersion1), marker(to_underlying(m)) {}; + operator MarkerUnderlying () const { return marker; }; +private: + // May be kReflexMarkerSleep which is not a valid PCLMarker value + MarkerUnderlying marker; +SL_STRUCT_END() + + +} + +//! Provides Reflex settings +//! +//! Call this method to check if Reflex is on, get stats etc. +//! +//! @param state Reference to a structure where states are returned +//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details) +//! +//! This method is NOT thread safe. +using PFun_slReflexGetState = sl::Result(sl::ReflexState& state); + +//! Tells reflex to sleep the app +//! +//! Call this method to invoke Reflex sleep in your application. +//! +//! @param frame Specifies current frame +//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details) +//! +//! This method is thread safe. +using PFun_slReflexSleep = sl::Result(const sl::FrameToken& frame); + +//! Sets Reflex options +//! +//! Call this method to turn Reflex on/off, change mode etc. +//! +//! @param options Specifies options to use +//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details) +//! +//! This method is NOT thread safe. +using PFun_slReflexSetOptions = sl::Result(const sl::ReflexOptions& options); + +//! Sets Reflex camera data +//! +//! Call this method to inform Reflex of upcoming camera data +//! +//! @param viewport The viewport the camera corresponds to +//! @param frame The frame to set camera data for +//! @param inCameraData Camera data for an upcoming render frame +//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details) +//! +//! This method is thread safe. +using PFun_slReflexSetCameraData = sl::Result(const sl::ViewportHandle& viewport, const sl::FrameToken& frame, const sl::ReflexCameraData& inCameraData); + +//! Gets predicted Reflex camera data +//! +//! Call this method to get a prediction of upcoming camera data +//! +//! @param viewport The viewport the camera corresponds to +//! @param frame The frame to get camera data for (if available) +//! @param outCameraData Predicted Camera data for an upcoming render frame +//! @return sl::ResultCode::eOk if successful, error code otherwise (see sl_result.h for details) +//! +//! This method is thread safe. +using PFun_slReflexGetPredictedCameraData = sl::Result(const sl::ViewportHandle& viewport, const sl::FrameToken& frame, sl::ReflexPredictedCameraData& outCameraData); + +//! HELPERS +//! +inline sl::Result slReflexGetState(sl::ReflexState& state) +{ + SL_FEATURE_FUN_IMPORT_STATIC(sl::kFeatureReflex, slReflexGetState); + return s_slReflexGetState(state); +} + +inline sl::Result slReflexSleep(const sl::FrameToken& frame) +{ + SL_FEATURE_FUN_IMPORT_STATIC(sl::kFeatureReflex, slReflexSleep); + return s_slReflexSleep(frame); +} + +inline sl::Result slReflexSetOptions(const sl::ReflexOptions& options) +{ + SL_FEATURE_FUN_IMPORT_STATIC(sl::kFeatureReflex, slReflexSetOptions); + return s_slReflexSetOptions(options); +} + +inline sl::Result slReflexSetCameraData(const sl::ViewportHandle& viewport, const sl::FrameToken& frame, const sl::ReflexCameraData& inCameraData) +{ + SL_FEATURE_FUN_IMPORT_STATIC(sl::kFeatureReflex, slReflexSetCameraData); + return s_slReflexSetCameraData(viewport, frame, inCameraData); +} + +inline sl::Result slReflexGetPredictedCameraData(const sl::ViewportHandle& viewport, const sl::FrameToken& frame, sl::ReflexPredictedCameraData& outCameraData) +{ + SL_FEATURE_FUN_IMPORT_STATIC(sl::kFeatureReflex, slReflexGetPredictedCameraData); + return s_slReflexGetPredictedCameraData(viewport, frame, outCameraData); +} + diff --git a/third_party/streamline/include/sl_result.h b/third_party/streamline/include/sl_result.h new file mode 100644 index 000000000..659fc5826 --- /dev/null +++ b/third_party/streamline/include/sl_result.h @@ -0,0 +1,77 @@ +/* +* Copyright (c) 2022-2024 NVIDIA CORPORATION. All rights reserved +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +#pragma once + +#define SL_CHECK(f) {auto _r = f; if(_r != sl::Result::eOk) return _r;} +#define SL_FAILED(r, f) sl::Result r = f; r != sl::Result::eOk +#define SL_SUCCEEDED(r, f) sl::Result r = f; r == sl::Result::eOk + +namespace sl +{ + +enum class Result +{ + eOk, + eErrorIO, + eErrorDriverOutOfDate, + eErrorOSOutOfDate, + eErrorOSDisabledHWS, + eErrorDeviceNotCreated, + eErrorNoSupportedAdapterFound, + eErrorAdapterNotSupported, + eErrorNoPlugins, + eErrorVulkanAPI, + eErrorDXGIAPI, + eErrorD3DAPI, + // NRD was removed + eErrorNRDAPI, + eErrorNVAPI, + eErrorReflexAPI, + eErrorNGXFailed, + eErrorJSONParsing, + eErrorMissingProxy, + eErrorMissingResourceState, + eErrorInvalidIntegration, + eErrorMissingInputParameter, + eErrorNotInitialized, + eErrorComputeFailed, + eErrorInitNotCalled, + eErrorExceptionHandler, + eErrorInvalidParameter, + eErrorMissingConstants, + eErrorDuplicatedConstants, + eErrorMissingOrInvalidAPI, + eErrorCommonConstantsMissing, + eErrorUnsupportedInterface, + eErrorFeatureMissing, + eErrorFeatureNotSupported, + eErrorFeatureMissingHooks, + eErrorFeatureFailedToLoad, + eErrorFeatureWrongPriority, + eErrorFeatureMissingDependency, + eErrorFeatureManagerInvalidState, + eErrorInvalidState, + eWarnOutOfVRAM +}; + +} diff --git a/third_party/streamline/include/sl_security.h b/third_party/streamline/include/sl_security.h new file mode 100644 index 000000000..380783dd7 --- /dev/null +++ b/third_party/streamline/include/sl_security.h @@ -0,0 +1,463 @@ +/* +* Copyright (c) 2022-2023 NVIDIA CORPORATION. All rights reserved +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +#pragma once + +#define _UNICODE 1 +#define UNICODE 1 + +#include +#include +#include +#include +#include +#include +#include +#include + +#define GetProc(hModule, procName, proc) (((NULL == proc) && (NULL == (*((FARPROC*)&proc) = GetProcAddress(hModule, procName)))) ? FALSE : TRUE) + +typedef BOOL(WINAPI* PfnCryptMsgClose)(IN HCRYPTMSG hCryptMsg); +static PfnCryptMsgClose pfnCryptMsgClose = NULL; + +typedef BOOL(WINAPI* PfnCertCloseStore)(IN HCERTSTORE hCertStore, DWORD dwFlags); +static PfnCertCloseStore pfnCertCloseStore = NULL; + +typedef HCERTSTORE (WINAPI* PfnCertOpenStore)( + _In_ LPCSTR lpszStoreProvider, + _In_ DWORD dwEncodingType, + _In_opt_ HCRYPTPROV_LEGACY hCryptProv, + _In_ DWORD dwFlags, + _In_opt_ const void* pvPara +); +static PfnCertOpenStore pfnCertOpenStore = NULL; + +typedef BOOL(WINAPI* PfnCertFreeCertificateContext)(IN PCCERT_CONTEXT pCertContext); +static PfnCertFreeCertificateContext pfnCertFreeCertificateContext = NULL; + +typedef PCCERT_CONTEXT(WINAPI* PfnCertFindCertificateInStore)( + IN HCERTSTORE hCertStore, + IN DWORD dwCertEncodingType, + IN DWORD dwFindFlags, + IN DWORD dwFindType, + IN const void* pvFindPara, + IN PCCERT_CONTEXT pPrevCertContext + ); +static PfnCertFindCertificateInStore pfnCertFindCertificateInStore = NULL; + +typedef BOOL(WINAPI* PfnCryptMsgGetParam)( + IN HCRYPTMSG hCryptMsg, + IN DWORD dwParamType, + IN DWORD dwIndex, + OUT void* pvData, + IN OUT DWORD* pcbData + ); +static PfnCryptMsgGetParam pfnCryptMsgGetParam = NULL; + +typedef HCRYPTMSG (WINAPI* PfnCryptMsgOpenToDecode)( + _In_ DWORD dwMsgEncodingType, + _In_ DWORD dwFlags, + _In_ DWORD dwMsgType, + _In_opt_ HCRYPTPROV_LEGACY hCryptProv, + _Reserved_ PCERT_INFO pRecipientInfo, + _In_opt_ PCMSG_STREAM_INFO pStreamInfo +); +PfnCryptMsgOpenToDecode pfnCryptMsgOpenToDecode = {}; + +typedef BOOL (WINAPI* PfnCryptMsgUpdate)( + _In_ HCRYPTMSG hCryptMsg, + _In_reads_bytes_opt_(cbData) const BYTE* pbData, + _In_ DWORD cbData, + _In_ BOOL fFinal +); +PfnCryptMsgUpdate pfnCryptMsgUpdate = {}; + +typedef BOOL(WINAPI* PfnCryptQueryObject)( + DWORD dwObjectType, + const void* pvObject, + DWORD dwExpectedContentTypeFlags, + DWORD dwExpectedFormatTypeFlags, + DWORD dwFlags, + DWORD* pdwMsgAndCertEncodingType, + DWORD* pdwContentType, + DWORD* pdwFormatType, + HCERTSTORE* phCertStore, + HCRYPTMSG* phMsg, + const void** ppvContext + ); +static PfnCryptQueryObject pfnCryptQueryObject = NULL; + +typedef BOOL(WINAPI* PfnCryptDecodeObjectEx)( + IN DWORD dwCertEncodingType, + IN LPCSTR lpszStructType, + IN const BYTE* pbEncoded, + IN DWORD cbEncoded, + IN DWORD dwFlags, + IN PCRYPT_DECODE_PARA pDecodePara, + OUT void* pvStructInfo, + IN OUT DWORD* pcbStructInfo + ); +static PfnCryptDecodeObjectEx pfnCryptDecodeObjectEx = NULL; + +typedef LONG(WINAPI* PfnWinVerifyTrust)( + IN HWND hwnd, + IN GUID* pgActionID, + IN LPVOID pWVTData + ); +static PfnWinVerifyTrust pfnWinVerifyTrust = NULL; + +namespace sl +{ + +namespace security +{ + +bool isSignedByNVIDIA(const wchar_t* pathToFile) +{ + bool valid = false; + + // Now let's make sure this is actually signed by NVIDIA + + DWORD dwEncoding, dwContentType, dwFormatType; + HCERTSTORE hStore = NULL; + HCRYPTMSG hMsg = NULL; + PCMSG_SIGNER_INFO pSignerInfo = NULL; + DWORD dwSignerInfo; + + if (!pfnCertOpenStore) + { + // We only support Win10+ so we can search for module in system32 directly + auto hModCrypt32 = LoadLibraryExW(L"crypt32.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); + if (!hModCrypt32 || + !GetProc(hModCrypt32, "CryptMsgClose", pfnCryptMsgClose) || + !GetProc(hModCrypt32, "CertOpenStore", pfnCertOpenStore) || + !GetProc(hModCrypt32, "CertCloseStore", pfnCertCloseStore) || + !GetProc(hModCrypt32, "CertFreeCertificateContext", pfnCertFreeCertificateContext) || + !GetProc(hModCrypt32, "CertFindCertificateInStore", pfnCertFindCertificateInStore) || + !GetProc(hModCrypt32, "CryptMsgGetParam", pfnCryptMsgGetParam) || + !GetProc(hModCrypt32, "CryptMsgUpdate", pfnCryptMsgUpdate) || + !GetProc(hModCrypt32, "CryptMsgOpenToDecode", pfnCryptMsgOpenToDecode) || + !GetProc(hModCrypt32, "CryptQueryObject", pfnCryptQueryObject) || + !GetProc(hModCrypt32, "CryptDecodeObjectEx", pfnCryptDecodeObjectEx)) + { + return false; + } + } + + // Get message handle and store handle from the signed file. + auto bResult = pfnCryptQueryObject(CERT_QUERY_OBJECT_FILE, + pathToFile, + CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED, + CERT_QUERY_FORMAT_FLAG_BINARY, + 0, + &dwEncoding, + &dwContentType, + &dwFormatType, + &hStore, + &hMsg, + NULL); + if (!bResult) + { + return false; + } + + // Get signer information size. + bResult = pfnCryptMsgGetParam(hMsg, + CMSG_SIGNER_INFO_PARAM, + 0, + NULL, + &dwSignerInfo); + if (!bResult) + { + return false; + } + + // Allocate memory for signer information. + pSignerInfo = (PCMSG_SIGNER_INFO)LocalAlloc(LPTR, dwSignerInfo); + if (!pSignerInfo) + { + return false; + } + + // Get Signer Information. + bResult = pfnCryptMsgGetParam(hMsg, + CMSG_SIGNER_INFO_PARAM, + 0, + (PVOID)pSignerInfo, + &dwSignerInfo); + if (!bResult) + { + LocalFree(pSignerInfo); + return false; + } + + // Look for nested signature + constexpr const char* kOID_NESTED_SIGNATURE = "1.3.6.1.4.1.311.2.4.1"; + for (DWORD i = 0; i < pSignerInfo->UnauthAttrs.cAttr; i++) + { + if (strcmp(kOID_NESTED_SIGNATURE, pSignerInfo->UnauthAttrs.rgAttr[i].pszObjId) == 0) + { + HCRYPTMSG hMsg2 = pfnCryptMsgOpenToDecode(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, 0, NULL, NULL, NULL); + if (hMsg2) + { + if (pfnCryptMsgUpdate(hMsg2,pSignerInfo->UnauthAttrs.rgAttr[i].rgValue->pbData,pSignerInfo->UnauthAttrs.rgAttr[i].rgValue->cbData,TRUE)) + { + dwSignerInfo = 0; + pfnCryptMsgGetParam(hMsg2, CMSG_SIGNER_INFO_PARAM, 0, NULL, &dwSignerInfo); + if (dwSignerInfo != 0) + { + PCMSG_SIGNER_INFO pSignerInfo2 = (PCMSG_SIGNER_INFO)LocalAlloc(LPTR, dwSignerInfo); + if (pSignerInfo2) + { + if (pfnCryptMsgGetParam(hMsg2, CMSG_SIGNER_INFO_PARAM, 0, (PVOID)pSignerInfo2, &dwSignerInfo)) + { + CRYPT_DATA_BLOB c7Data; + c7Data.pbData = pSignerInfo->UnauthAttrs.rgAttr[i].rgValue->pbData; + c7Data.cbData = pSignerInfo->UnauthAttrs.rgAttr[i].rgValue->cbData; + + auto hStore2 = pfnCertOpenStore(CERT_STORE_PROV_PKCS7, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, NULL, 0, &c7Data); + if (!hStore2) + { + LocalFree(pSignerInfo2); + return false; + } + + CERT_INFO CertInfo{}; + PCCERT_CONTEXT pCertContext = NULL; + + // Search for the signer certificate in the temporary certificate store. + CertInfo.Issuer = pSignerInfo2->Issuer; + CertInfo.SerialNumber = pSignerInfo2->SerialNumber; + pCertContext = pfnCertFindCertificateInStore(hStore2, + (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING), + 0, + CERT_FIND_SUBJECT_CERT, + (PVOID)&CertInfo, + NULL); + if (!pCertContext) + { + LocalFree(pSignerInfo2); + pfnCertCloseStore(hStore2, CERT_CLOSE_STORE_FORCE_FLAG); + return false; + } + + void* decodedPublicKey{}; + DWORD decodedPublicLength{}; + if (pfnCryptDecodeObjectEx((PKCS_7_ASN_ENCODING | X509_ASN_ENCODING), + CNG_RSA_PUBLIC_KEY_BLOB, + pCertContext->pCertInfo->SubjectPublicKeyInfo.PublicKey.pbData, + pCertContext->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData, + CRYPT_ENCODE_ALLOC_FLAG, + NULL, + &decodedPublicKey, + &decodedPublicLength)) + { + static uint8_t s_rsaStreamlinePublicKey[] = + { + 0x52, 0x53, 0x41, 0x31, 0x00, 0x0c, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0xc1, 0x8e, 0x40, 0xc3, 0xf5, + 0xa7, 0x01, 0x9a, 0x37, 0x6b, 0x47, 0xa8, 0x58, 0xe8, 0xbe, 0xe3, 0x55, 0x0a, 0xee, 0x0f, 0x0d, + 0x32, 0xaa, 0x12, 0xf9, 0x56, 0x7f, 0x5d, 0xfd, 0x82, 0x09, 0x33, 0x21, 0x42, 0xf2, 0xe8, 0x74, + 0x98, 0x51, 0xb3, 0x88, 0x74, 0xcd, 0x00, 0x6e, 0xb1, 0x08, 0x10, 0x4b, 0xf1, 0xda, 0xd6, 0x97, + 0x87, 0xd4, 0x9c, 0xb1, 0x13, 0xa8, 0xa2, 0x86, 0x15, 0x0e, 0xc1, 0xa5, 0x9c, 0xe5, 0x90, 0x9b, + 0xbe, 0x69, 0xdc, 0x6a, 0x82, 0xbe, 0xb4, 0x4b, 0x4b, 0xfa, 0x95, 0x8e, 0xc1, 0xfc, 0x2b, 0x61, + 0x95, 0xd1, 0x91, 0xed, 0xeb, 0x87, 0xe7, 0x09, 0x84, 0x05, 0x41, 0x03, 0xb0, 0x2d, 0xd4, 0x39, + 0x7f, 0x62, 0x06, 0x56, 0x33, 0x93, 0x7e, 0x77, 0x54, 0x06, 0x77, 0x2b, 0x75, 0x05, 0xbc, 0xeb, + 0x98, 0xea, 0xc0, 0xa2, 0xca, 0x98, 0x86, 0x0f, 0x10, 0x65, 0xde, 0x19, 0x2c, 0xa6, 0x1e, 0x93, + 0xb0, 0x92, 0x5d, 0x5f, 0x5b, 0x6f, 0x79, 0x6d, 0x2c, 0x76, 0xa6, 0x67, 0x50, 0xaa, 0x8f, 0xc2, + 0x4c, 0xf1, 0x08, 0xf7, 0xc0, 0x27, 0x29, 0xf0, 0x68, 0xf4, 0x64, 0x00, 0x1c, 0xb6, 0x28, 0x1e, + 0x25, 0xb8, 0xf3, 0x8a, 0xd1, 0x6e, 0x65, 0xa3, 0x61, 0x9d, 0xf8, 0xca, 0x4a, 0x41, 0x60, 0x80, + 0x62, 0xdf, 0x41, 0xa4, 0x8b, 0xdc, 0x97, 0xee, 0xeb, 0x64, 0x6f, 0xe4, 0x8f, 0x4b, 0xdf, 0x24, + 0x01, 0x80, 0xd9, 0xb4, 0x0a, 0xec, 0x0d, 0x3e, 0xb7, 0x76, 0xba, 0xe9, 0xe7, 0xde, 0x07, 0xdd, + 0x30, 0xc8, 0x4a, 0x14, 0x79, 0xec, 0x15, 0xed, 0x5c, 0xc6, 0xcc, 0xd4, 0xe6, 0x06, 0x3c, 0x42, + 0x92, 0x10, 0xf7, 0x7c, 0x80, 0x1e, 0x78, 0xd3, 0xb4, 0x9f, 0xc2, 0x3b, 0xa8, 0x7b, 0xa0, 0xe3, + 0x0c, 0xd9, 0xad, 0x2e, 0x09, 0x72, 0xe2, 0x8f, 0x54, 0x28, 0x87, 0x3c, 0xba, 0x7c, 0x97, 0x80, + 0xdc, 0x09, 0xb5, 0x12, 0x34, 0x78, 0x9a, 0x26, 0xd0, 0xa3, 0xa7, 0xa7, 0x1b, 0x25, 0x19, 0xe5, + 0x6e, 0xbe, 0xd7, 0x5a, 0x91, 0x32, 0xc4, 0xa9, 0x2f, 0xcc, 0xd5, 0x82, 0x4b, 0x5b, 0x9f, 0xad, + 0xf3, 0x2f, 0xed, 0x4f, 0x33, 0xe1, 0x50, 0x33, 0xd6, 0x90, 0x79, 0x22, 0xe5, 0x1c, 0xc7, 0x35, + 0xe7, 0x58, 0xe6, 0xb4, 0x8b, 0xc4, 0x28, 0x20, 0xec, 0xca, 0x70, 0xbb, 0x02, 0x1b, 0x48, 0xd8, + 0x84, 0x51, 0x24, 0x33, 0x2a, 0x08, 0xb1, 0x15, 0x4e, 0xbc, 0x88, 0xa5, 0xe1, 0x37, 0x76, 0x70, + 0xe6, 0xdf, 0x3f, 0x73, 0xfd, 0x0d, 0x8a, 0xd9, 0x0d, 0xa5, 0x35, 0xb2, 0xb4, 0x01, 0x42, 0x96, + 0xc4, 0xaa, 0x1c, 0xeb, 0x68, 0x62, 0x36, 0xbf, 0xef, 0x5e, 0x2a, 0x3d, 0x18, 0x91, 0x8b, 0x92, + 0x0a, 0x1e, 0xce, 0x98, 0x5b, 0x7b, 0x64, 0x42, 0x09, 0xb0, 0x1d + }; + + valid = decodedPublicLength == sizeof(s_rsaStreamlinePublicKey) && memcmp(s_rsaStreamlinePublicKey, decodedPublicKey, decodedPublicLength) == 0; + LocalFree(decodedPublicKey); + } + + pfnCertFreeCertificateContext(pCertContext); + pfnCertCloseStore(hStore2, CERT_CLOSE_STORE_FORCE_FLAG); + } + LocalFree(pSignerInfo2); + } + } + } + pfnCryptMsgClose(hMsg2); + } + break; + } + } + + LocalFree(pSignerInfo); + pfnCryptMsgClose(hMsg); + pfnCertCloseStore(hStore, CERT_CLOSE_STORE_FORCE_FLAG); + + return valid; +} + +//! See https://docs.microsoft.com/en-us/windows/win32/seccrypto/example-c-program--verifying-the-signature-of-a-pe-file +//! +//! IMPORTANT: Always pass in the FULL PATH to the file, relative paths are NOT allowed! +bool verifyEmbeddedSignature(const wchar_t* pathToFile) +{ + bool valid = true; + + LONG lStatus = {}; + + // Initialize the WINTRUST_FILE_INFO structure. + + WINTRUST_FILE_INFO FileData; + memset(&FileData, 0, sizeof(FileData)); + FileData.cbStruct = sizeof(WINTRUST_FILE_INFO); + FileData.pcwszFilePath = pathToFile; + FileData.hFile = NULL; + FileData.pgKnownSubject = NULL; + + if (!pfnWinVerifyTrust) + { + // We only support Win10+ so we can search for module in system32 directly + auto hModWintrust = LoadLibraryExW(L"wintrust.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); + if (!hModWintrust || !GetProc(hModWintrust, "WinVerifyTrust", pfnWinVerifyTrust)) + { + return false; + } + } + + /* + WVTPolicyGUID specifies the policy to apply on the file + WINTRUST_ACTION_GENERIC_VERIFY_V2 policy checks: + + 1) The certificate used to sign the file chains up to a root + certificate located in the trusted root certificate store. This + implies that the identity of the publisher has been verified by + a certification authority. + + 2) In cases where user interface is displayed (which this example + does not do), WinVerifyTrust will check for whether the + end entity certificate is stored in the trusted publisher store, + implying that the user trusts content from this publisher. + + 3) The end entity certificate has sufficient permission to sign + code, as indicated by the presence of a code signing EKU or no + EKU. + */ + + GUID WVTPolicyGUID = WINTRUST_ACTION_GENERIC_VERIFY_V2; + WINTRUST_DATA WinTrustData; + + // Initialize the WinVerifyTrust input data structure. + + // Default all fields to 0. + memset(&WinTrustData, 0, sizeof(WinTrustData)); + + WinTrustData.cbStruct = sizeof(WinTrustData); + // Use default code signing EKU. + WinTrustData.pPolicyCallbackData = NULL; + // No data to pass to SIP. + WinTrustData.pSIPClientData = NULL; + // Disable WVT UI. + WinTrustData.dwUIChoice = WTD_UI_NONE; + // No revocation checking. + WinTrustData.fdwRevocationChecks = WTD_REVOKE_NONE; + // Verify an embedded signature on a file. + WinTrustData.dwUnionChoice = WTD_CHOICE_FILE; + // Verify action. + WinTrustData.dwStateAction = WTD_STATEACTION_VERIFY; + // Verification sets this value. + WinTrustData.hWVTStateData = NULL; + // Not used. + WinTrustData.pwszURLReference = NULL; + // This is not applicable if there is no UI because it changes + // the UI to accommodate running applications instead of + // installing applications. + WinTrustData.dwUIContext = 0; + // Set pFile. + WinTrustData.pFile = &FileData; + + // First verify the primary signature (index 0) to determine how many secondary signatures + // are present. We use WSS_VERIFY_SPECIFIC and dwIndex to do this, also setting + // WSS_GET_SECONDARY_SIG_COUNT to have the number of secondary signatures returned. + WINTRUST_SIGNATURE_SETTINGS SignatureSettings = {}; + CERT_STRONG_SIGN_PARA StrongSigPolicy = {}; + SignatureSettings.cbStruct = sizeof(WINTRUST_SIGNATURE_SETTINGS); + SignatureSettings.dwFlags = WSS_GET_SECONDARY_SIG_COUNT | WSS_VERIFY_SPECIFIC; + SignatureSettings.dwIndex = 0; + WinTrustData.pSignatureSettings = &SignatureSettings; + + StrongSigPolicy.cbSize = sizeof(CERT_STRONG_SIGN_PARA); + StrongSigPolicy.dwInfoChoice = CERT_STRONG_SIGN_OID_INFO_CHOICE; + StrongSigPolicy.pszOID = (LPSTR)szOID_CERT_STRONG_SIGN_OS_CURRENT; + WinTrustData.pSignatureSettings->pCryptoPolicy = &StrongSigPolicy; + + // WinVerifyTrust verifies signatures as specified by the GUID and Wintrust_Data. + lStatus = pfnWinVerifyTrust(NULL, &WVTPolicyGUID, &WinTrustData); + + // First signature must be validated by the OS + valid = lStatus == ERROR_SUCCESS; + if (!valid) + { + printf("File '%S' is NOT correctly signed - Streamline will not load unsecured modules\n", pathToFile); + } + else + { + // Now there has to be a secondary one + valid &= WinTrustData.pSignatureSettings->cSecondarySigs == 1; + if (!valid) + { + printf("File '%S' does not have the secondary NVIDIA signature - Streamline will not load unsecured modules\n", pathToFile); + } + else + { + // The secondary signature must be from NVIDIA + valid &= isSignedByNVIDIA(pathToFile); + if (valid) + { + printf("File '%S' is signed by NVIDIA and the signature was verified.\n", pathToFile); + } + else + { + printf("File '%S' is NOT correctly signed - Streamline will not load unsecured modules\n", pathToFile); + } + } + } + + // Any hWVTStateData must be released by a call with close. + WinTrustData.dwStateAction = WTD_STATEACTION_CLOSE; + lStatus = pfnWinVerifyTrust(NULL, &WVTPolicyGUID, &WinTrustData); + + return valid; +} + +} +} + diff --git a/third_party/streamline/include/sl_struct.h b/third_party/streamline/include/sl_struct.h new file mode 100644 index 000000000..e9e911185 --- /dev/null +++ b/third_party/streamline/include/sl_struct.h @@ -0,0 +1,142 @@ +/* +* Copyright (c) 2022-2023 NVIDIA CORPORATION. All rights reserved +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +#pragma once + +#include +#include + +namespace sl +{ + +//! GUID +struct StructType +{ + uint32_t data1; + uint16_t data2; + uint16_t data3; + uint8_t data4[8]; + + inline bool operator==(const StructType& rhs) const { return memcmp(this, &rhs, sizeof(*this)) == 0; } + inline bool operator!=(const StructType& rhs) const { return memcmp(this, &rhs, sizeof(*this)) != 0; } +}; + +//! SL is using typed and versioned structures which can be chained or not. +//! +//! --- OPTION 1 --- +//! +//! New members must be added at the end and version needs to be increased: +//! +//! SL_STRUCT_BEGIN(S1, GUID1, kStructVersion1) +//! A +//! B +//! C +//! SL_STRUCT_END() +//! +//! SL_STRUCT_BEGIN(S1, GUID1, kStructVersion2) // Note that version is bumped +//! // V1 +//! A +//! B +//! C +//! +//! //! V2 - new members always go at the end! +//! D +//! E +//! SL_STRUCT_END() +//! +//! Here is one example on how to check for version and handle backwards compatibility: +//! +//! void func(const S1* input) +//! { +//! // Access A, B, C as needed +//! ... +//! if (input->structVersion >= kStructVersion2) +//! { +//! // Safe to access D, E +//! } +//! } + + +//! --- OPTION 2 --- +//! +//! New members are optional and added to a new struct which is then chained as needed: +//! +//! SL_STRUCT_BEGIN(S1, GUID1, kStructVersion1) +//! A +//! B +//! C +//! SL_STRUCT_END() +//! +//! SL_STRUCT_BEGIN(S2, GUID2, kStructVersion1) // Note that this is a different struct with new GUID +//! D +//! E +//! SL_STRUCT_END() +//! +//! S1 s1; +//! S2 s2 +//! s1.next = &s2; // optional parameters in S2 + +//! IMPORTANT: New members in the structure always go at the end! +//! +constexpr uint32_t kStructVersion1 = 1; +constexpr uint32_t kStructVersion2 = 2; +constexpr uint32_t kStructVersion3 = 3; +constexpr uint32_t kStructVersion4 = 4; +constexpr uint32_t kStructVersion5 = 5; +constexpr uint32_t kStructVersion6 = 6; +constexpr uint32_t kStructVersion7 = 7; + +struct BaseStructure +{ + BaseStructure() = delete; + BaseStructure(StructType t, uint32_t v) : structType(t), structVersion(v) {}; + BaseStructure* next{}; + StructType structType{}; + size_t structVersion; +}; + +#define SL_STRUCT_BEGIN(name, guid, version) \ +struct name : public sl::BaseStructure \ +{ \ + name() : sl::BaseStructure(guid, version){} \ + constexpr static sl::StructType s_structType = guid; + +#define SL_STRUCT_END() }; + +#define SL_STRUCT_PROTECTED_BEGIN(name, guid, version) \ +struct name : public sl::BaseStructure \ +{ \ +protected: \ + name() : sl::BaseStructure(guid, version){} \ +public: \ + constexpr static sl::StructType s_structType = guid; \ + + +// Deprecated: please use SL_STRUCT_BEGIN/SL_STRUCT_END instead +#define SL_STRUCT(name, guid, version) \ +SL_STRUCT_BEGIN(name, guid, version) + +// Deprecated: please use SL_STRUCT_PROTECTED_BEGIN/SL_STRUCT_END instead +#define SL_STRUCT_PROTECTED(name, guid, version) \ +SL_STRUCT_PROTECTED_BEGIN(name, guid, version) + +} // namespace sl diff --git a/third_party/streamline/include/sl_template.h b/third_party/streamline/include/sl_template.h new file mode 100644 index 000000000..e60b6d7d7 --- /dev/null +++ b/third_party/streamline/include/sl_template.h @@ -0,0 +1,57 @@ +/* +* Copyright (c) 2022-2023 NVIDIA CORPORATION. All rights reserved +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +#pragma once + +namespace sl +{ + +//! Each feature must have a unique id, please see sl.h Feature +//! +constexpr uint32_t kFeatureTemplate = 0xffff; + +//! If your plugin does not have any constants then the code below can be removed +//! +enum class TemplateMode : uint32_t +{ + eOff, + eOn +}; + +//! IMPORTANT: Each structure must have a unique GUID assigned, change this as needed +//! +// {29DF7FE0-273A-4D72-B481-2DC823D5B1AD} +SL_STRUCT_BEGIN(TemplateConstants, StructType({ 0x29df7fe0, 0x273a, 0x4d72, { 0xb4, 0x81, 0x2d, 0xc8, 0x23, 0xd5, 0xb1, 0xad } }), kStructVersion1) + TemplateMode mode = TemplateMode::eOff; + + //! IMPORTANT: New members go here or if optional can be chained in a new struct, see sl_struct.h for details +SL_STRUCT_END() + +//! IMPORTANT: Each structure must have a unique GUID assigned, change this as needed +//! +// {39DF7FE0-283A-4D72-B481-2DC823D5B1AD} +SL_STRUCT_BEGIN(TemplateSettings, StructType({ 0x39df7fe0, 0x283a, 0x4d72, { 0xb4, 0x81, 0x2d, 0xc8, 0x23, 0xd5, 0xb1, 0xad } }), kStructVersion1) + + //! IMPORTANT: New members go here or if optional can be chained in a new struct, see sl_struct.h for details +SL_STRUCT_END() + +} diff --git a/third_party/streamline/include/sl_version.h b/third_party/streamline/include/sl_version.h new file mode 100644 index 000000000..1848f70d1 --- /dev/null +++ b/third_party/streamline/include/sl_version.h @@ -0,0 +1,99 @@ +/* +* Copyright (c) 2022-2023 NVIDIA CORPORATION. All rights reserved +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ +#pragma once + +#define SL_VERSION_MAJOR 2 +#define SL_VERSION_MINOR 14 +#define SL_VERSION_PATCH 16 + +#include +#include + +namespace sl +{ +constexpr uint64_t kSDKVersionMagic = 0xfedc; +constexpr uint64_t kSDKVersion = (uint64_t(SL_VERSION_MAJOR) << 48) | (uint64_t(SL_VERSION_MINOR) << 32) | (uint64_t(SL_VERSION_PATCH) << 16) | kSDKVersionMagic; + +struct Version +{ + Version() : major(0), minor(0), build(0) {}; + Version(uint32_t v1, uint32_t v2, uint32_t v3) : major(v1), minor(v2), build(v3) {}; + + inline operator bool() const { return major != 0 || minor != 0 || build != 0; } + + inline std::string toStr() const + { + return std::to_string(major) + "." + std::to_string(minor) + "." + std::to_string(build); + } + inline std::wstring toWStr() const + { + return std::to_wstring(major) + L"." + std::to_wstring(minor) + L"." + std::to_wstring(build); + } + inline std::wstring toWStrOTAId() const + { + return std::to_wstring((major << 16) | (minor << 8) | build); + } + inline bool operator==(const Version& rhs) const + { + return major == rhs.major && minor == rhs.minor && build == rhs.build; + } + inline bool operator>(const Version& rhs) const + { + if (major < rhs.major) return false; + else if (major > rhs.major) return true; + // major version the same + if (minor < rhs.minor) return false; + else if (minor > rhs.minor) return true; + // minor version the same + if (build < rhs.build) return false; + else if (build > rhs.build) return true; + // build version the same + return false; + }; + inline bool operator>=(const Version& rhs) const + { + return operator>(rhs) || operator==(rhs); + }; + inline bool operator<(const Version& rhs) const + { + if (major > rhs.major) return false; + else if (major < rhs.major) return true; + // major version the same + if (minor > rhs.minor) return false; + else if (minor < rhs.minor) return true; + // minor version the same + if (build > rhs.build) return false; + else if (build < rhs.build) return true; + // build version the same + return false; + }; + inline bool operator<=(const Version& rhs) const + { + return operator<(rhs) || operator==(rhs); + }; + + uint32_t major; + uint32_t minor; + uint32_t build; +}; + +} diff --git a/third_party/streamline/license.txt b/third_party/streamline/license.txt new file mode 100644 index 000000000..9f48a0c32 --- /dev/null +++ b/third_party/streamline/license.txt @@ -0,0 +1,33 @@ +/* +* Copyright (c) 2023 NVIDIA CORPORATION. All rights reserved +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in all +* copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +*/ + +/* +* NSight Perf SDK License, Version 2023.3 +* Please see the file included in this package +* "NVIDIA Nsight Perf SDK License (28Sept2022).pdf" for licensing details +* of the NSight Perf SDK. +* NSight Perf SDK ver 2023.3 can be downloaded from here: +* https://developer.nvidia.com/gameworksdownload#?dn=nsight-perf-sdk-2023-3 +* The Streamline files covered by the NSight Perf SDK License are: +* sl_nvperf.h +* sl_nvperf.dll +*/ \ No newline at end of file From 8e71475c66163b7493bfaa7b545ca750b3633a6c Mon Sep 17 00:00:00 2001 From: Jordan Date: Sun, 8 Nov 2026 22:40:29 +0000 Subject: [PATCH 2/5] vk_dlss: Windows 10's headers for Streamline's signature check (llvm-mingw build) sl_security.h uses wintrust.h's WINTRUST_SIGNATURE_SETTINGS, which is Windows 8 and later. llvm-mingw (the builder's compiler) defaults to Windows 7, set already by the C++ headers the build includes first, so vk_dlss.cpp did not compile there: 7 errors in sl_security.h. The file now asks for Windows 10's headers before anything brings in windows.h. Co-Authored-By: Claude Opus 5.5 --- gpu/vk/vk_dlss.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/gpu/vk/vk_dlss.cpp b/gpu/vk/vk_dlss.cpp index 54c7d2006..4c8f71940 100644 --- a/gpu/vk/vk_dlss.cpp +++ b/gpu/vk/vk_dlss.cpp @@ -1,6 +1,15 @@ // NVIDIA DLSS super resolution through NVIDIA Streamline, manual hooking (vk_dlss.h). Ported from Lichii (Eden lineage; // Duck912's Eglantine work), GPL-3.0-or-later: video_core/vulkan_common/streamline.cpp (the loader) and // renderer_vulkan/vk_streamline_dlss.cpp (the evaluation). Streamline's headers are MIT (third_party/streamline/license.txt). +// (Windows 10's headers: sl_security.h's signature check uses wintrust.h's WINTRUST_SIGNATURE_SETTINGS, Windows 8 and later, +// which llvm-mingw leaves out at its default of Windows 7, set already by the C++ headers the build includes first. Before the +// first header that brings in windows.h) +#ifdef _WIN32 +#undef _WIN32_WINNT +#define _WIN32_WINNT 0x0A00 +#undef NTDDI_VERSION +#define NTDDI_VERSION 0x0A000000 +#endif #include "vk_dlss.h" #include "vk_internal.h" From 16aab12425563ec6d14c179f9f840e718df0af46 Mon Sep 17 00:00:00 2001 From: Jordan Date: Sun, 8 Nov 2026 22:40:29 +0000 Subject: [PATCH 3/5] AMD FSR 4.1 in place of the game's upscale, with a sub-pixel jitter (on top of #818's DLSS frame code) A second backend for #818's replacement of OoT's gameplay upscale, ported from the FSR 4.1 work on Lichii's OoT branch (madebyjordan/Lichii-Hyrule oot-dev, 7f8ae5b337..c5f2fce17d). It takes the same colour, depth and camera motion as DLSS; DLSS keeps priority when it is on. - vk_fsr4.cpp: AMD's FSR API (FidelityFX SDK 2.4). Only the MIT headers are vendored (third_party/fidelityfx); AMD's signed loader and upscaler DLLs load at run time from RX_FSR4_DIR or beside hookshot.exe. The newest 4.x provider the loader lists is picked explicitly (RDNA 2 and 3 run its INT8 model). LDR, non-linear colour, standard depth. One context per output size, render sizes up to it, so the Resolution row and the game's dynamic resolution need no new context. - Jitter: the game draws without one, so the draws that test or write the scene's depth move by a Halton (2, 3) sub-pixel offset through the viewport, and FSR is told it. The offset is part of the state dyn_pack compares, or a frame whose draws match the last frame's would keep the old one. From Lichii: the phase moves on at the network's pass (where the game's frame ends), not at presents; it is on only while FSR drew the last network pass. - AMD edge line (Lichii, RX 6700 XT): moved up or left, the AMD driver draws nothing into the scene's last column or row, a stale near-white value that became a flickering line in FSR's history. FSR's colour and the motion's depth repeat the column and row before them. Colour going into FSR is cleaned of NaN and Inf and clamped to [0, 1]; the output pass drops NaN and Inf for both upscalers. - FSR history resets when FSR did not draw the last network pass or on a camera cut, not by present count. - Menu: "AMD FSR 4.1" (Off/On, at once; ini key fsr4, RX_FSR4=0/1). Resolution sets what it upscales from (75% Quality, 50% Performance, 100% anti-aliasing only). RX_FSR4_JITTER=0 turns the jitter off. - What changes on native, compared with Lichii: no GPU-time divisor (Hookshot already scales the game's timer, so it keeps full quality), no hunt for the tonemap draw or depth reader (#818 takes them where the draws are), no 4/3-only size check. - tests/test_fsr_jitter.py: the jitter is compared and applied, moves on at the network's pass, and the edge repeat is in both passes. Co-Authored-By: Claude Opus 5.5 --- gpu/PROVENANCE.md | 6 + gpu/vk/shaders/dlss_color.comp | 12 +- gpu/vk/shaders/dlss_color_comp_spv.h | 139 ++- gpu/vk/shaders/dlss_motion.comp | 3 +- gpu/vk/shaders/dlss_motion_comp_spv.h | 206 ++-- gpu/vk/shaders/dlss_output.comp | 2 + gpu/vk/shaders/dlss_output_comp_spv.h | 69 +- gpu/vk/vk_draw.cpp | 103 +- gpu/vk/vk_fsr4.cpp | 281 +++++ gpu/vk/vk_fsr4.h | 27 + gpu/vk/vk_menu.cpp | 15 +- gpu/vk/vk_menu.h | 1 + nx2/build.py | 4 +- readme.md | 15 + tests/test_fsr_jitter.py | 79 ++ third_party/fidelityfx/LICENSE.md | 992 ++++++++++++++++++ third_party/fidelityfx/README.md | 9 + third_party/fidelityfx/api/include/ffx_api.h | 213 ++++ .../fidelityfx/api/include/ffx_api_types.h | 257 +++++ .../fidelityfx/api/include/vk/ffx_api_vk.h | 308 ++++++ .../upscalers/include/ffx_upscale.h | 230 ++++ 21 files changed, 2777 insertions(+), 194 deletions(-) create mode 100644 gpu/vk/vk_fsr4.cpp create mode 100644 gpu/vk/vk_fsr4.h create mode 100644 tests/test_fsr_jitter.py create mode 100644 third_party/fidelityfx/LICENSE.md create mode 100644 third_party/fidelityfx/README.md create mode 100644 third_party/fidelityfx/api/include/ffx_api.h create mode 100644 third_party/fidelityfx/api/include/ffx_api_types.h create mode 100644 third_party/fidelityfx/api/include/vk/ffx_api_vk.h create mode 100644 third_party/fidelityfx/upscalers/include/ffx_upscale.h diff --git a/gpu/PROVENANCE.md b/gpu/PROVENANCE.md index 412ceebba..8408631ce 100644 --- a/gpu/PROVENANCE.md +++ b/gpu/PROVENANCE.md @@ -34,3 +34,9 @@ Hookshot's NVIDIA DLSS (`vk/vk_dlss.cpp`, the DLSS part of `vk/vk_draw.cpp`, `vk `host_shaders/ocarina_*.comp`; Eden Emulator Project, GPL-3.0-or-later; Lichii credits Duck912's Eglantine work). `third_party/streamline/` is NVIDIA Streamline v2.14.16's headers (MIT, `license.txt`); its DLLs and NVIDIA's DLSS are loaded from the user's PC at run time and are not vendored. + +Hookshot's AMD FSR 4.1 (`vk/vk_fsr4.cpp`, the FSR and jitter parts of `vk/vk_draw.cpp`, the `fsr` paths of +`vk/shaders/dlss_*.comp`) is ported from madebyjordan's FSR 4.1 work on Lichii's OoT branch (`renderer_vulkan/vk_fsr4_upscaler.cpp`, +`vk_rasterizer.cpp`'s Ocarina jitter, `host_shaders/ocarina_*.comp`; GPL-3.0-or-later). `third_party/fidelityfx/` is AMD's +FSR API headers from FidelityFX SDK v2.4.0 (MIT, `LICENSE.md`); AMD's signed DLLs are loaded from the user's PC at run time +and are not vendored. diff --git a/gpu/vk/shaders/dlss_color.comp b/gpu/vk/shaders/dlss_color.comp index 44e5cf83a..cf1323ca2 100644 --- a/gpu/vk/shaders/dlss_color.comp +++ b/gpu/vk/shaders/dlss_color.comp @@ -4,7 +4,7 @@ layout(local_size_x = 8, local_size_y = 8) in; layout(binding = 0) uniform sampler2D guest_color; layout(binding = 1, rgba16f) uniform writeonly image2D dlss_color; -layout(push_constant) uniform P { int encode; } pc; +layout(push_constant) uniform P { int encode; int fsr; } pc; void main() { ivec2 pixel = ivec2(gl_GlobalInvocationID.xy); @@ -14,6 +14,12 @@ void main() { // The guest has already tonemapped this square-root-encoded color for LDR (the network's input, RGB9E5). (hookshot) encode = 1: // the tonemapped scene, the network's first passes left out (vk_draw.cpp), square-root encoded here the same way. // dlss_output.comp squares it back - const vec3 c = max(texelFetch(guest_color, pixel, 0).rgb, vec3(0.0)); - imageStore(dlss_color, pixel, vec4(pc.encode != 0 ? sqrt(c) : c, 1.0)); + // (hookshot-amd) fsr = 1, AMD FSR 4.1: its LDR mode keeps history, where a NaN, infinite or out-of-range value would build up; + // and under its jitter moved up or left, the AMD driver draws nothing into the scene's last column or row (a stale near-white + // value, a flickering line on the right and bottom edges): they repeat the ones before them (vk_draw.cpp FsrJitter) + const ivec2 source = pc.fsr != 0 ? min(pixel, max(imageSize(dlss_color) - 2, ivec2(0))) : pixel; + vec3 c = max(texelFetch(guest_color, source, 0).rgb, vec3(0.0)); + if (pc.fsr != 0 && (any(isnan(c)) || any(isinf(c)))) c = vec3(0.0); + c = pc.encode != 0 ? sqrt(c) : c; + imageStore(dlss_color, pixel, vec4(pc.fsr != 0 ? min(c, vec3(1.0)) : c, 1.0)); } diff --git a/gpu/vk/shaders/dlss_color_comp_spv.h b/gpu/vk/shaders/dlss_color_comp_spv.h index 6ea3734c4..8bb55be4d 100644 --- a/gpu/vk/shaders/dlss_color_comp_spv.h +++ b/gpu/vk/shaders/dlss_color_comp_spv.h @@ -1,60 +1,97 @@ - // 1116.6.0 + // 1116.2.0 #pragma once const uint32_t DLSS_COLOR_COMP_SPV[] = { - 0x07230203,0x00010600,0x0008000b,0x0000004a,0x00000000,0x00020011,0x00000001,0x00020011, + 0x07230203,0x00010500,0x0008000b,0x0000007d,0x00000000,0x00020011,0x00000001,0x00020011, 0x00000032,0x0006000b,0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e, 0x00000000,0x00000001,0x0009000f,0x00000005,0x00000004,0x6e69616d,0x00000000,0x0000000d, - 0x00000016,0x00000026,0x00000035,0x00060010,0x00000004,0x00000011,0x00000008,0x00000008, + 0x00000016,0x00000023,0x0000003f,0x00060010,0x00000004,0x00000011,0x00000008,0x00000008, 0x00000001,0x00030003,0x00000002,0x000001c2,0x00040005,0x00000004,0x6e69616d,0x00000000, 0x00040005,0x00000009,0x65786970,0x0000006c,0x00080005,0x0000000d,0x475f6c67,0x61626f6c, 0x766e496c,0x7461636f,0x496e6f69,0x00000044,0x00050005,0x00000016,0x73736c64,0x6c6f635f, - 0x0000726f,0x00030005,0x00000022,0x00000063,0x00050005,0x00000026,0x73657567,0x6f635f74, - 0x00726f6c,0x00030005,0x00000033,0x00000050,0x00050006,0x00000033,0x00000000,0x6f636e65, - 0x00006564,0x00030005,0x00000035,0x00006370,0x00040047,0x0000000d,0x0000000b,0x0000001c, + 0x0000726f,0x00040005,0x00000020,0x72756f73,0x00006563,0x00030005,0x00000021,0x00000050, + 0x00050006,0x00000021,0x00000000,0x6f636e65,0x00006564,0x00040006,0x00000021,0x00000001, + 0x00727366,0x00030005,0x00000023,0x00006370,0x00030005,0x0000003b,0x00000063,0x00050005, + 0x0000003f,0x73657567,0x6f635f74,0x00726f6c,0x00040047,0x0000000d,0x0000000b,0x0000001c, 0x00030047,0x00000016,0x00000019,0x00040047,0x00000016,0x00000021,0x00000001,0x00040047, - 0x00000016,0x00000022,0x00000000,0x00040047,0x00000026,0x00000021,0x00000000,0x00040047, - 0x00000026,0x00000022,0x00000000,0x00030047,0x00000033,0x00000002,0x00050048,0x00000033, - 0x00000000,0x00000023,0x00000000,0x00020013,0x00000002,0x00030021,0x00000003,0x00000002, - 0x00040015,0x00000006,0x00000020,0x00000001,0x00040017,0x00000007,0x00000006,0x00000002, - 0x00040020,0x00000008,0x00000007,0x00000007,0x00040015,0x0000000a,0x00000020,0x00000000, - 0x00040017,0x0000000b,0x0000000a,0x00000003,0x00040020,0x0000000c,0x00000001,0x0000000b, - 0x0004003b,0x0000000c,0x0000000d,0x00000001,0x00040017,0x0000000e,0x0000000a,0x00000002, - 0x00030016,0x00000013,0x00000020,0x00090019,0x00000014,0x00000013,0x00000001,0x00000000, - 0x00000000,0x00000000,0x00000002,0x00000002,0x00040020,0x00000015,0x00000000,0x00000014, - 0x0004003b,0x00000015,0x00000016,0x00000000,0x00020014,0x00000019,0x00040017,0x0000001a, - 0x00000019,0x00000002,0x00040017,0x00000020,0x00000013,0x00000003,0x00040020,0x00000021, - 0x00000007,0x00000020,0x00090019,0x00000023,0x00000013,0x00000001,0x00000000,0x00000000, - 0x00000000,0x00000001,0x00000000,0x0003001b,0x00000024,0x00000023,0x00040020,0x00000025, - 0x00000000,0x00000024,0x0004003b,0x00000025,0x00000026,0x00000000,0x0004002b,0x00000006, - 0x00000029,0x00000000,0x00040017,0x0000002b,0x00000013,0x00000004,0x0004002b,0x00000013, - 0x0000002e,0x00000000,0x0006002c,0x00000020,0x0000002f,0x0000002e,0x0000002e,0x0000002e, - 0x0003001e,0x00000033,0x00000006,0x00040020,0x00000034,0x00000009,0x00000033,0x0004003b, - 0x00000034,0x00000035,0x00000009,0x00040020,0x00000036,0x00000009,0x00000006,0x0004002b, - 0x00000013,0x00000042,0x3f800000,0x0004002b,0x0000000a,0x00000047,0x00000008,0x0004002b, - 0x0000000a,0x00000048,0x00000001,0x0006002c,0x0000000b,0x00000049,0x00000047,0x00000047, - 0x00000048,0x00050036,0x00000002,0x00000004,0x00000000,0x00000003,0x000200f8,0x00000005, - 0x0004003b,0x00000008,0x00000009,0x00000007,0x0004003b,0x00000021,0x00000022,0x00000007, - 0x0004003b,0x00000021,0x0000003a,0x00000007,0x0004003d,0x0000000b,0x0000000f,0x0000000d, - 0x0007004f,0x0000000e,0x00000010,0x0000000f,0x0000000f,0x00000000,0x00000001,0x0004007c, - 0x00000007,0x00000011,0x00000010,0x0003003e,0x00000009,0x00000011,0x0004003d,0x00000007, - 0x00000012,0x00000009,0x0004003d,0x00000014,0x00000017,0x00000016,0x00040068,0x00000007, - 0x00000018,0x00000017,0x000500af,0x0000001a,0x0000001b,0x00000012,0x00000018,0x0004009a, - 0x00000019,0x0000001c,0x0000001b,0x000300f7,0x0000001e,0x00000000,0x000400fa,0x0000001c, - 0x0000001d,0x0000001e,0x000200f8,0x0000001d,0x000100fd,0x000200f8,0x0000001e,0x0004003d, - 0x00000024,0x00000027,0x00000026,0x0004003d,0x00000007,0x00000028,0x00000009,0x00040064, - 0x00000023,0x0000002a,0x00000027,0x0007005f,0x0000002b,0x0000002c,0x0000002a,0x00000028, - 0x00000002,0x00000029,0x0008004f,0x00000020,0x0000002d,0x0000002c,0x0000002c,0x00000000, - 0x00000001,0x00000002,0x0007000c,0x00000020,0x00000030,0x00000001,0x00000028,0x0000002d, - 0x0000002f,0x0003003e,0x00000022,0x00000030,0x0004003d,0x00000014,0x00000031,0x00000016, - 0x0004003d,0x00000007,0x00000032,0x00000009,0x00050041,0x00000036,0x00000037,0x00000035, - 0x00000029,0x0004003d,0x00000006,0x00000038,0x00000037,0x000500ab,0x00000019,0x00000039, - 0x00000038,0x00000029,0x000300f7,0x0000003c,0x00000000,0x000400fa,0x00000039,0x0000003b, - 0x0000003f,0x000200f8,0x0000003b,0x0004003d,0x00000020,0x0000003d,0x00000022,0x0006000c, - 0x00000020,0x0000003e,0x00000001,0x0000001f,0x0000003d,0x0003003e,0x0000003a,0x0000003e, - 0x000200f9,0x0000003c,0x000200f8,0x0000003f,0x0004003d,0x00000020,0x00000040,0x00000022, - 0x0003003e,0x0000003a,0x00000040,0x000200f9,0x0000003c,0x000200f8,0x0000003c,0x0004003d, - 0x00000020,0x00000041,0x0000003a,0x00050051,0x00000013,0x00000043,0x00000041,0x00000000, - 0x00050051,0x00000013,0x00000044,0x00000041,0x00000001,0x00050051,0x00000013,0x00000045, - 0x00000041,0x00000002,0x00070050,0x0000002b,0x00000046,0x00000043,0x00000044,0x00000045, - 0x00000042,0x00040063,0x00000031,0x00000032,0x00000046,0x000100fd,0x00010038 + 0x00000016,0x00000022,0x00000000,0x00030047,0x00000021,0x00000002,0x00050048,0x00000021, + 0x00000000,0x00000023,0x00000000,0x00050048,0x00000021,0x00000001,0x00000023,0x00000004, + 0x00040047,0x0000003f,0x00000021,0x00000000,0x00040047,0x0000003f,0x00000022,0x00000000, + 0x00040047,0x0000007c,0x0000000b,0x00000019,0x00020013,0x00000002,0x00030021,0x00000003, + 0x00000002,0x00040015,0x00000006,0x00000020,0x00000001,0x00040017,0x00000007,0x00000006, + 0x00000002,0x00040020,0x00000008,0x00000007,0x00000007,0x00040015,0x0000000a,0x00000020, + 0x00000000,0x00040017,0x0000000b,0x0000000a,0x00000003,0x00040020,0x0000000c,0x00000001, + 0x0000000b,0x0004003b,0x0000000c,0x0000000d,0x00000001,0x00040017,0x0000000e,0x0000000a, + 0x00000002,0x00030016,0x00000013,0x00000020,0x00090019,0x00000014,0x00000013,0x00000001, + 0x00000000,0x00000000,0x00000000,0x00000002,0x00000002,0x00040020,0x00000015,0x00000000, + 0x00000014,0x0004003b,0x00000015,0x00000016,0x00000000,0x00020014,0x00000019,0x00040017, + 0x0000001a,0x00000019,0x00000002,0x0004001e,0x00000021,0x00000006,0x00000006,0x00040020, + 0x00000022,0x00000009,0x00000021,0x0004003b,0x00000022,0x00000023,0x00000009,0x0004002b, + 0x00000006,0x00000024,0x00000001,0x00040020,0x00000025,0x00000009,0x00000006,0x0004002b, + 0x00000006,0x00000028,0x00000000,0x0004002b,0x00000006,0x00000030,0x00000002,0x0005002c, + 0x00000007,0x00000033,0x00000028,0x00000028,0x00040017,0x00000039,0x00000013,0x00000003, + 0x00040020,0x0000003a,0x00000007,0x00000039,0x00090019,0x0000003c,0x00000013,0x00000001, + 0x00000000,0x00000000,0x00000000,0x00000001,0x00000000,0x0003001b,0x0000003d,0x0000003c, + 0x00040020,0x0000003e,0x00000000,0x0000003d,0x0004003b,0x0000003e,0x0000003f,0x00000000, + 0x00040017,0x00000043,0x00000013,0x00000004,0x0004002b,0x00000013,0x00000046,0x00000000, + 0x0006002c,0x00000039,0x00000047,0x00000046,0x00000046,0x00000046,0x00040017,0x0000004f, + 0x00000019,0x00000003,0x0004002b,0x00000013,0x00000070,0x3f800000,0x0006002c,0x00000039, + 0x00000071,0x00000070,0x00000070,0x00000070,0x0004002b,0x0000000a,0x0000007a,0x00000008, + 0x0004002b,0x0000000a,0x0000007b,0x00000001,0x0006002c,0x0000000b,0x0000007c,0x0000007a, + 0x0000007a,0x0000007b,0x00050036,0x00000002,0x00000004,0x00000000,0x00000003,0x000200f8, + 0x00000005,0x0004003b,0x00000008,0x00000009,0x00000007,0x0004003b,0x00000008,0x00000020, + 0x00000007,0x0004003b,0x00000008,0x0000002a,0x00000007,0x0004003b,0x0000003a,0x0000003b, + 0x00000007,0x0004003b,0x0000003a,0x0000005f,0x00000007,0x0004003b,0x0000003a,0x0000006c, + 0x00000007,0x0004003d,0x0000000b,0x0000000f,0x0000000d,0x0007004f,0x0000000e,0x00000010, + 0x0000000f,0x0000000f,0x00000000,0x00000001,0x0004007c,0x00000007,0x00000011,0x00000010, + 0x0003003e,0x00000009,0x00000011,0x0004003d,0x00000007,0x00000012,0x00000009,0x0004003d, + 0x00000014,0x00000017,0x00000016,0x00040068,0x00000007,0x00000018,0x00000017,0x000500af, + 0x0000001a,0x0000001b,0x00000012,0x00000018,0x0004009a,0x00000019,0x0000001c,0x0000001b, + 0x000300f7,0x0000001e,0x00000000,0x000400fa,0x0000001c,0x0000001d,0x0000001e,0x000200f8, + 0x0000001d,0x000100fd,0x000200f8,0x0000001e,0x00050041,0x00000025,0x00000026,0x00000023, + 0x00000024,0x0004003d,0x00000006,0x00000027,0x00000026,0x000500ab,0x00000019,0x00000029, + 0x00000027,0x00000028,0x000300f7,0x0000002c,0x00000000,0x000400fa,0x00000029,0x0000002b, + 0x00000036,0x000200f8,0x0000002b,0x0004003d,0x00000007,0x0000002d,0x00000009,0x0004003d, + 0x00000014,0x0000002e,0x00000016,0x00040068,0x00000007,0x0000002f,0x0000002e,0x00050050, + 0x00000007,0x00000031,0x00000030,0x00000030,0x00050082,0x00000007,0x00000032,0x0000002f, + 0x00000031,0x0007000c,0x00000007,0x00000034,0x00000001,0x0000002a,0x00000032,0x00000033, + 0x0007000c,0x00000007,0x00000035,0x00000001,0x00000027,0x0000002d,0x00000034,0x0003003e, + 0x0000002a,0x00000035,0x000200f9,0x0000002c,0x000200f8,0x00000036,0x0004003d,0x00000007, + 0x00000037,0x00000009,0x0003003e,0x0000002a,0x00000037,0x000200f9,0x0000002c,0x000200f8, + 0x0000002c,0x0004003d,0x00000007,0x00000038,0x0000002a,0x0003003e,0x00000020,0x00000038, + 0x0004003d,0x0000003d,0x00000040,0x0000003f,0x0004003d,0x00000007,0x00000041,0x00000020, + 0x00040064,0x0000003c,0x00000042,0x00000040,0x0007005f,0x00000043,0x00000044,0x00000042, + 0x00000041,0x00000002,0x00000028,0x0008004f,0x00000039,0x00000045,0x00000044,0x00000044, + 0x00000000,0x00000001,0x00000002,0x0007000c,0x00000039,0x00000048,0x00000001,0x00000028, + 0x00000045,0x00000047,0x0003003e,0x0000003b,0x00000048,0x00050041,0x00000025,0x00000049, + 0x00000023,0x00000024,0x0004003d,0x00000006,0x0000004a,0x00000049,0x000500ab,0x00000019, + 0x0000004b,0x0000004a,0x00000028,0x000300f7,0x0000004d,0x00000000,0x000400fa,0x0000004b, + 0x0000004c,0x0000004d,0x000200f8,0x0000004c,0x0004003d,0x00000039,0x0000004e,0x0000003b, + 0x0004009c,0x0000004f,0x00000050,0x0000004e,0x0004009a,0x00000019,0x00000051,0x00000050, + 0x000400a8,0x00000019,0x00000052,0x00000051,0x000300f7,0x00000054,0x00000000,0x000400fa, + 0x00000052,0x00000053,0x00000054,0x000200f8,0x00000053,0x0004003d,0x00000039,0x00000055, + 0x0000003b,0x0004009d,0x0000004f,0x00000056,0x00000055,0x0004009a,0x00000019,0x00000057, + 0x00000056,0x000200f9,0x00000054,0x000200f8,0x00000054,0x000700f5,0x00000019,0x00000058, + 0x00000051,0x0000004c,0x00000057,0x00000053,0x000200f9,0x0000004d,0x000200f8,0x0000004d, + 0x000700f5,0x00000019,0x00000059,0x0000004b,0x0000002c,0x00000058,0x00000054,0x000300f7, + 0x0000005b,0x00000000,0x000400fa,0x00000059,0x0000005a,0x0000005b,0x000200f8,0x0000005a, + 0x0003003e,0x0000003b,0x00000047,0x000200f9,0x0000005b,0x000200f8,0x0000005b,0x00050041, + 0x00000025,0x0000005c,0x00000023,0x00000028,0x0004003d,0x00000006,0x0000005d,0x0000005c, + 0x000500ab,0x00000019,0x0000005e,0x0000005d,0x00000028,0x000300f7,0x00000061,0x00000000, + 0x000400fa,0x0000005e,0x00000060,0x00000064,0x000200f8,0x00000060,0x0004003d,0x00000039, + 0x00000062,0x0000003b,0x0006000c,0x00000039,0x00000063,0x00000001,0x0000001f,0x00000062, + 0x0003003e,0x0000005f,0x00000063,0x000200f9,0x00000061,0x000200f8,0x00000064,0x0004003d, + 0x00000039,0x00000065,0x0000003b,0x0003003e,0x0000005f,0x00000065,0x000200f9,0x00000061, + 0x000200f8,0x00000061,0x0004003d,0x00000039,0x00000066,0x0000005f,0x0003003e,0x0000003b, + 0x00000066,0x0004003d,0x00000014,0x00000067,0x00000016,0x0004003d,0x00000007,0x00000068, + 0x00000009,0x00050041,0x00000025,0x00000069,0x00000023,0x00000024,0x0004003d,0x00000006, + 0x0000006a,0x00000069,0x000500ab,0x00000019,0x0000006b,0x0000006a,0x00000028,0x000300f7, + 0x0000006e,0x00000000,0x000400fa,0x0000006b,0x0000006d,0x00000073,0x000200f8,0x0000006d, + 0x0004003d,0x00000039,0x0000006f,0x0000003b,0x0007000c,0x00000039,0x00000072,0x00000001, + 0x00000025,0x0000006f,0x00000071,0x0003003e,0x0000006c,0x00000072,0x000200f9,0x0000006e, + 0x000200f8,0x00000073,0x0004003d,0x00000039,0x00000074,0x0000003b,0x0003003e,0x0000006c, + 0x00000074,0x000200f9,0x0000006e,0x000200f8,0x0000006e,0x0004003d,0x00000039,0x00000075, + 0x0000006c,0x00050051,0x00000013,0x00000076,0x00000075,0x00000000,0x00050051,0x00000013, + 0x00000077,0x00000075,0x00000001,0x00050051,0x00000013,0x00000078,0x00000075,0x00000002, + 0x00070050,0x00000043,0x00000079,0x00000076,0x00000077,0x00000078,0x00000070,0x00040063, + 0x00000067,0x00000068,0x00000079,0x000100fd,0x00010038 }; diff --git a/gpu/vk/shaders/dlss_motion.comp b/gpu/vk/shaders/dlss_motion.comp index eb8588918..678de7201 100644 --- a/gpu/vk/shaders/dlss_motion.comp +++ b/gpu/vk/shaders/dlss_motion.comp @@ -7,6 +7,7 @@ layout(binding = 1, rg16f) uniform writeonly image2D motion; layout(push_constant, row_major) uniform Parameters { mat4 clip_to_previous_clip; + int fsr; // (hookshot-amd: AMD FSR 4.1's jitter on: the last column and row take the depth before them, dlss_color.comp) } params; void main() { @@ -17,7 +18,7 @@ void main() { } vec2 size = vec2(extent); - float depth = texelFetch(scene_depth, pixel, 0).r; + float depth = texelFetch(scene_depth, params.fsr != 0 ? min(pixel, max(extent - 2, ivec2(0))) : pixel, 0).r; vec2 screen = (vec2(pixel) + 0.5) / size; // The captured Zelda path is unjittered, with [-1, 1] clip depth and negative viewport height. vec4 clip = vec4(screen * vec2(2, -2) + vec2(-1, 1), depth * 2 - 1, 1); diff --git a/gpu/vk/shaders/dlss_motion_comp_spv.h b/gpu/vk/shaders/dlss_motion_comp_spv.h index 129471ff3..193d0e612 100644 --- a/gpu/vk/shaders/dlss_motion_comp_spv.h +++ b/gpu/vk/shaders/dlss_motion_comp_spv.h @@ -1,106 +1,120 @@ - // 1116.6.0 + // 1116.2.0 #pragma once const uint32_t DLSS_MOTION_COMP_SPV[] = { - 0x07230203,0x00010600,0x0008000b,0x0000008b,0x00000000,0x00020011,0x00000001,0x00020011, + 0x07230203,0x00010500,0x0008000b,0x0000009d,0x00000000,0x00020011,0x00000001,0x00020011, 0x00000031,0x00020011,0x00000032,0x0006000b,0x00000001,0x4c534c47,0x6474732e,0x3035342e, 0x00000000,0x0003000e,0x00000000,0x00000001,0x0009000f,0x00000005,0x00000004,0x6e69616d, - 0x00000000,0x0000000d,0x00000016,0x0000002c,0x00000052,0x00060010,0x00000004,0x00000011, + 0x00000000,0x0000000d,0x00000016,0x0000002c,0x00000032,0x00060010,0x00000004,0x00000011, 0x00000008,0x00000008,0x00000001,0x00030003,0x00000002,0x000001c2,0x00040005,0x00000004, 0x6e69616d,0x00000000,0x00040005,0x00000009,0x65786970,0x0000006c,0x00080005,0x0000000d, 0x475f6c67,0x61626f6c,0x766e496c,0x7461636f,0x496e6f69,0x00000044,0x00040005,0x00000012, 0x65747865,0x0000746e,0x00040005,0x00000016,0x69746f6d,0x00006e6f,0x00040005,0x00000024, 0x657a6973,0x00000000,0x00040005,0x00000028,0x74706564,0x00000068,0x00050005,0x0000002c, - 0x6e656373,0x65645f65,0x00687470,0x00040005,0x00000035,0x65726373,0x00006e65,0x00040005, - 0x0000003e,0x70696c63,0x00000000,0x00050005,0x0000004e,0x76657270,0x73756f69,0x00000000, - 0x00050005,0x00000050,0x61726150,0x6574656d,0x00007372,0x00090006,0x00000050,0x00000000, - 0x70696c63,0x5f6f745f,0x76657270,0x73756f69,0x696c635f,0x00000070,0x00040005,0x00000052, - 0x61726170,0x0000736d,0x00040005,0x00000058,0x65786970,0x0000736c,0x00060005,0x0000006a, - 0x70736964,0x6563616c,0x746e656d,0x00000000,0x00040047,0x0000000d,0x0000000b,0x0000001c, - 0x00030047,0x00000016,0x00000019,0x00040047,0x00000016,0x00000021,0x00000001,0x00040047, - 0x00000016,0x00000022,0x00000000,0x00040047,0x0000002c,0x00000021,0x00000000,0x00040047, - 0x0000002c,0x00000022,0x00000000,0x00030047,0x00000050,0x00000002,0x00040048,0x00000050, - 0x00000000,0x00000004,0x00050048,0x00000050,0x00000000,0x00000007,0x00000010,0x00050048, - 0x00000050,0x00000000,0x00000023,0x00000000,0x00020013,0x00000002,0x00030021,0x00000003, - 0x00000002,0x00040015,0x00000006,0x00000020,0x00000001,0x00040017,0x00000007,0x00000006, - 0x00000002,0x00040020,0x00000008,0x00000007,0x00000007,0x00040015,0x0000000a,0x00000020, - 0x00000000,0x00040017,0x0000000b,0x0000000a,0x00000003,0x00040020,0x0000000c,0x00000001, - 0x0000000b,0x0004003b,0x0000000c,0x0000000d,0x00000001,0x00040017,0x0000000e,0x0000000a, - 0x00000002,0x00030016,0x00000013,0x00000020,0x00090019,0x00000014,0x00000013,0x00000001, - 0x00000000,0x00000000,0x00000000,0x00000002,0x00000007,0x00040020,0x00000015,0x00000000, - 0x00000014,0x0004003b,0x00000015,0x00000016,0x00000000,0x00020014,0x0000001b,0x00040017, - 0x0000001c,0x0000001b,0x00000002,0x00040017,0x00000022,0x00000013,0x00000002,0x00040020, - 0x00000023,0x00000007,0x00000022,0x00040020,0x00000027,0x00000007,0x00000013,0x00090019, - 0x00000029,0x00000013,0x00000001,0x00000000,0x00000000,0x00000000,0x00000001,0x00000000, - 0x0003001b,0x0000002a,0x00000029,0x00040020,0x0000002b,0x00000000,0x0000002a,0x0004003b, - 0x0000002b,0x0000002c,0x00000000,0x0004002b,0x00000006,0x0000002f,0x00000000,0x00040017, - 0x00000031,0x00000013,0x00000004,0x0004002b,0x0000000a,0x00000033,0x00000000,0x0004002b, - 0x00000013,0x00000038,0x3f000000,0x00040020,0x0000003d,0x00000007,0x00000031,0x0004002b, - 0x00000013,0x00000040,0x40000000,0x0004002b,0x00000013,0x00000041,0xc0000000,0x0005002c, - 0x00000022,0x00000042,0x00000040,0x00000041,0x0004002b,0x00000013,0x00000044,0xbf800000, - 0x0004002b,0x00000013,0x00000045,0x3f800000,0x0005002c,0x00000022,0x00000046,0x00000044, - 0x00000045,0x00040018,0x0000004f,0x00000031,0x00000004,0x0003001e,0x00000050,0x0000004f, - 0x00040020,0x00000051,0x00000009,0x00000050,0x0004003b,0x00000051,0x00000052,0x00000009, - 0x00040020,0x00000053,0x00000009,0x0000004f,0x0004002b,0x00000013,0x00000059,0x00000000, - 0x0005002c,0x00000022,0x0000005a,0x00000059,0x00000059,0x0004002b,0x0000000a,0x00000062, - 0x00000003,0x0004002b,0x00000013,0x00000065,0x358637bd,0x0004002b,0x00000013,0x00000074, - 0xbf000000,0x0005002c,0x00000022,0x00000075,0x00000038,0x00000074,0x0004002b,0x00000013, - 0x0000007b,0x477fe000,0x0005002c,0x00000022,0x0000007c,0x0000007b,0x0000007b,0x0004002b, - 0x0000000a,0x00000088,0x00000008,0x0004002b,0x0000000a,0x00000089,0x00000001,0x0006002c, - 0x0000000b,0x0000008a,0x00000088,0x00000088,0x00000089,0x00050036,0x00000002,0x00000004, - 0x00000000,0x00000003,0x000200f8,0x00000005,0x0004003b,0x00000008,0x00000009,0x00000007, - 0x0004003b,0x00000008,0x00000012,0x00000007,0x0004003b,0x00000023,0x00000024,0x00000007, - 0x0004003b,0x00000027,0x00000028,0x00000007,0x0004003b,0x00000023,0x00000035,0x00000007, - 0x0004003b,0x0000003d,0x0000003e,0x00000007,0x0004003b,0x0000003d,0x0000004e,0x00000007, - 0x0004003b,0x00000023,0x00000058,0x00000007,0x0004003b,0x00000023,0x0000006a,0x00000007, - 0x0004003d,0x0000000b,0x0000000f,0x0000000d,0x0007004f,0x0000000e,0x00000010,0x0000000f, - 0x0000000f,0x00000000,0x00000001,0x0004007c,0x00000007,0x00000011,0x00000010,0x0003003e, - 0x00000009,0x00000011,0x0004003d,0x00000014,0x00000017,0x00000016,0x00040068,0x00000007, - 0x00000018,0x00000017,0x0003003e,0x00000012,0x00000018,0x0004003d,0x00000007,0x00000019, - 0x00000009,0x0004003d,0x00000007,0x0000001a,0x00000012,0x000500af,0x0000001c,0x0000001d, - 0x00000019,0x0000001a,0x0004009a,0x0000001b,0x0000001e,0x0000001d,0x000300f7,0x00000020, - 0x00000000,0x000400fa,0x0000001e,0x0000001f,0x00000020,0x000200f8,0x0000001f,0x000100fd, - 0x000200f8,0x00000020,0x0004003d,0x00000007,0x00000025,0x00000012,0x0004006f,0x00000022, - 0x00000026,0x00000025,0x0003003e,0x00000024,0x00000026,0x0004003d,0x0000002a,0x0000002d, - 0x0000002c,0x0004003d,0x00000007,0x0000002e,0x00000009,0x00040064,0x00000029,0x00000030, - 0x0000002d,0x0007005f,0x00000031,0x00000032,0x00000030,0x0000002e,0x00000002,0x0000002f, - 0x00050051,0x00000013,0x00000034,0x00000032,0x00000000,0x0003003e,0x00000028,0x00000034, - 0x0004003d,0x00000007,0x00000036,0x00000009,0x0004006f,0x00000022,0x00000037,0x00000036, - 0x00050050,0x00000022,0x00000039,0x00000038,0x00000038,0x00050081,0x00000022,0x0000003a, - 0x00000037,0x00000039,0x0004003d,0x00000022,0x0000003b,0x00000024,0x00050088,0x00000022, - 0x0000003c,0x0000003a,0x0000003b,0x0003003e,0x00000035,0x0000003c,0x0004003d,0x00000022, - 0x0000003f,0x00000035,0x00050085,0x00000022,0x00000043,0x0000003f,0x00000042,0x00050081, - 0x00000022,0x00000047,0x00000043,0x00000046,0x0004003d,0x00000013,0x00000048,0x00000028, - 0x00050085,0x00000013,0x00000049,0x00000048,0x00000040,0x00050083,0x00000013,0x0000004a, - 0x00000049,0x00000045,0x00050051,0x00000013,0x0000004b,0x00000047,0x00000000,0x00050051, - 0x00000013,0x0000004c,0x00000047,0x00000001,0x00070050,0x00000031,0x0000004d,0x0000004b, - 0x0000004c,0x0000004a,0x00000045,0x0003003e,0x0000003e,0x0000004d,0x00050041,0x00000053, - 0x00000054,0x00000052,0x0000002f,0x0004003d,0x0000004f,0x00000055,0x00000054,0x0004003d, - 0x00000031,0x00000056,0x0000003e,0x00050091,0x00000031,0x00000057,0x00000055,0x00000056, - 0x0003003e,0x0000004e,0x00000057,0x0003003e,0x00000058,0x0000005a,0x0004003d,0x00000013, - 0x0000005b,0x00000028,0x000500be,0x0000001b,0x0000005c,0x0000005b,0x00000059,0x0004003d, - 0x00000013,0x0000005d,0x00000028,0x000500bc,0x0000001b,0x0000005e,0x0000005d,0x00000045, - 0x000500a7,0x0000001b,0x0000005f,0x0000005c,0x0000005e,0x000300f7,0x00000061,0x00000000, - 0x000400fa,0x0000005f,0x00000060,0x00000061,0x000200f8,0x00000060,0x00050041,0x00000027, - 0x00000063,0x0000004e,0x00000062,0x0004003d,0x00000013,0x00000064,0x00000063,0x000500ba, - 0x0000001b,0x00000066,0x00000064,0x00000065,0x000200f9,0x00000061,0x000200f8,0x00000061, - 0x000700f5,0x0000001b,0x00000067,0x0000005f,0x00000020,0x00000066,0x00000060,0x000300f7, - 0x00000069,0x00000000,0x000400fa,0x00000067,0x00000068,0x00000069,0x000200f8,0x00000068, - 0x0004003d,0x00000031,0x0000006b,0x0000004e,0x0007004f,0x00000022,0x0000006c,0x0000006b, - 0x0000006b,0x00000000,0x00000001,0x00050041,0x00000027,0x0000006d,0x0000004e,0x00000062, - 0x0004003d,0x00000013,0x0000006e,0x0000006d,0x00050050,0x00000022,0x0000006f,0x0000006e, - 0x0000006e,0x00050088,0x00000022,0x00000070,0x0000006c,0x0000006f,0x0004003d,0x00000031, - 0x00000071,0x0000003e,0x0007004f,0x00000022,0x00000072,0x00000071,0x00000071,0x00000000, - 0x00000001,0x00050083,0x00000022,0x00000073,0x00000070,0x00000072,0x00050085,0x00000022, - 0x00000076,0x00000073,0x00000075,0x0004003d,0x00000022,0x00000077,0x00000024,0x00050085, - 0x00000022,0x00000078,0x00000076,0x00000077,0x0003003e,0x0000006a,0x00000078,0x0004003d, - 0x00000022,0x00000079,0x0000006a,0x0006000c,0x00000022,0x0000007a,0x00000001,0x00000004, - 0x00000079,0x000500bc,0x0000001c,0x0000007d,0x0000007a,0x0000007c,0x0004009b,0x0000001b, - 0x0000007e,0x0000007d,0x000300f7,0x00000080,0x00000000,0x000400fa,0x0000007e,0x0000007f, - 0x00000080,0x000200f8,0x0000007f,0x0004003d,0x00000022,0x00000081,0x0000006a,0x0003003e, - 0x00000058,0x00000081,0x000200f9,0x00000080,0x000200f8,0x00000080,0x000200f9,0x00000069, - 0x000200f8,0x00000069,0x0004003d,0x00000014,0x00000082,0x00000016,0x0004003d,0x00000007, - 0x00000083,0x00000009,0x0004003d,0x00000022,0x00000084,0x00000058,0x00050051,0x00000013, - 0x00000085,0x00000084,0x00000000,0x00050051,0x00000013,0x00000086,0x00000084,0x00000001, - 0x00070050,0x00000031,0x00000087,0x00000085,0x00000086,0x00000059,0x00000059,0x00040063, - 0x00000082,0x00000083,0x00000087,0x000100fd,0x00010038 + 0x6e656373,0x65645f65,0x00687470,0x00050005,0x00000030,0x61726150,0x6574656d,0x00007372, + 0x00090006,0x00000030,0x00000000,0x70696c63,0x5f6f745f,0x76657270,0x73756f69,0x696c635f, + 0x00000070,0x00040006,0x00000030,0x00000001,0x00727366,0x00040005,0x00000032,0x61726170, + 0x0000736d,0x00040005,0x0000004b,0x65726373,0x00006e65,0x00040005,0x00000054,0x70696c63, + 0x00000000,0x00050005,0x00000064,0x76657270,0x73756f69,0x00000000,0x00040005,0x0000006a, + 0x65786970,0x0000736c,0x00060005,0x0000007c,0x70736964,0x6563616c,0x746e656d,0x00000000, + 0x00040047,0x0000000d,0x0000000b,0x0000001c,0x00030047,0x00000016,0x00000019,0x00040047, + 0x00000016,0x00000021,0x00000001,0x00040047,0x00000016,0x00000022,0x00000000,0x00040047, + 0x0000002c,0x00000021,0x00000000,0x00040047,0x0000002c,0x00000022,0x00000000,0x00030047, + 0x00000030,0x00000002,0x00040048,0x00000030,0x00000000,0x00000004,0x00050048,0x00000030, + 0x00000000,0x00000007,0x00000010,0x00050048,0x00000030,0x00000000,0x00000023,0x00000000, + 0x00050048,0x00000030,0x00000001,0x00000023,0x00000040,0x00040047,0x0000009c,0x0000000b, + 0x00000019,0x00020013,0x00000002,0x00030021,0x00000003,0x00000002,0x00040015,0x00000006, + 0x00000020,0x00000001,0x00040017,0x00000007,0x00000006,0x00000002,0x00040020,0x00000008, + 0x00000007,0x00000007,0x00040015,0x0000000a,0x00000020,0x00000000,0x00040017,0x0000000b, + 0x0000000a,0x00000003,0x00040020,0x0000000c,0x00000001,0x0000000b,0x0004003b,0x0000000c, + 0x0000000d,0x00000001,0x00040017,0x0000000e,0x0000000a,0x00000002,0x00030016,0x00000013, + 0x00000020,0x00090019,0x00000014,0x00000013,0x00000001,0x00000000,0x00000000,0x00000000, + 0x00000002,0x00000007,0x00040020,0x00000015,0x00000000,0x00000014,0x0004003b,0x00000015, + 0x00000016,0x00000000,0x00020014,0x0000001b,0x00040017,0x0000001c,0x0000001b,0x00000002, + 0x00040017,0x00000022,0x00000013,0x00000002,0x00040020,0x00000023,0x00000007,0x00000022, + 0x00040020,0x00000027,0x00000007,0x00000013,0x00090019,0x00000029,0x00000013,0x00000001, + 0x00000000,0x00000000,0x00000000,0x00000001,0x00000000,0x0003001b,0x0000002a,0x00000029, + 0x00040020,0x0000002b,0x00000000,0x0000002a,0x0004003b,0x0000002b,0x0000002c,0x00000000, + 0x00040017,0x0000002e,0x00000013,0x00000004,0x00040018,0x0000002f,0x0000002e,0x00000004, + 0x0004001e,0x00000030,0x0000002f,0x00000006,0x00040020,0x00000031,0x00000009,0x00000030, + 0x0004003b,0x00000031,0x00000032,0x00000009,0x0004002b,0x00000006,0x00000033,0x00000001, + 0x00040020,0x00000034,0x00000009,0x00000006,0x0004002b,0x00000006,0x00000037,0x00000000, + 0x0004002b,0x00000006,0x0000003e,0x00000002,0x0005002c,0x00000007,0x00000041,0x00000037, + 0x00000037,0x0004002b,0x0000000a,0x00000049,0x00000000,0x0004002b,0x00000013,0x0000004e, + 0x3f000000,0x00040020,0x00000053,0x00000007,0x0000002e,0x0004002b,0x00000013,0x00000056, + 0x40000000,0x0004002b,0x00000013,0x00000057,0xc0000000,0x0005002c,0x00000022,0x00000058, + 0x00000056,0x00000057,0x0004002b,0x00000013,0x0000005a,0xbf800000,0x0004002b,0x00000013, + 0x0000005b,0x3f800000,0x0005002c,0x00000022,0x0000005c,0x0000005a,0x0000005b,0x00040020, + 0x00000065,0x00000009,0x0000002f,0x0004002b,0x00000013,0x0000006b,0x00000000,0x0005002c, + 0x00000022,0x0000006c,0x0000006b,0x0000006b,0x0004002b,0x0000000a,0x00000074,0x00000003, + 0x0004002b,0x00000013,0x00000077,0x358637bd,0x0004002b,0x00000013,0x00000086,0xbf000000, + 0x0005002c,0x00000022,0x00000087,0x0000004e,0x00000086,0x0004002b,0x00000013,0x0000008d, + 0x477fe000,0x0005002c,0x00000022,0x0000008e,0x0000008d,0x0000008d,0x0004002b,0x0000000a, + 0x0000009a,0x00000008,0x0004002b,0x0000000a,0x0000009b,0x00000001,0x0006002c,0x0000000b, + 0x0000009c,0x0000009a,0x0000009a,0x0000009b,0x00050036,0x00000002,0x00000004,0x00000000, + 0x00000003,0x000200f8,0x00000005,0x0004003b,0x00000008,0x00000009,0x00000007,0x0004003b, + 0x00000008,0x00000012,0x00000007,0x0004003b,0x00000023,0x00000024,0x00000007,0x0004003b, + 0x00000027,0x00000028,0x00000007,0x0004003b,0x00000008,0x00000039,0x00000007,0x0004003b, + 0x00000023,0x0000004b,0x00000007,0x0004003b,0x00000053,0x00000054,0x00000007,0x0004003b, + 0x00000053,0x00000064,0x00000007,0x0004003b,0x00000023,0x0000006a,0x00000007,0x0004003b, + 0x00000023,0x0000007c,0x00000007,0x0004003d,0x0000000b,0x0000000f,0x0000000d,0x0007004f, + 0x0000000e,0x00000010,0x0000000f,0x0000000f,0x00000000,0x00000001,0x0004007c,0x00000007, + 0x00000011,0x00000010,0x0003003e,0x00000009,0x00000011,0x0004003d,0x00000014,0x00000017, + 0x00000016,0x00040068,0x00000007,0x00000018,0x00000017,0x0003003e,0x00000012,0x00000018, + 0x0004003d,0x00000007,0x00000019,0x00000009,0x0004003d,0x00000007,0x0000001a,0x00000012, + 0x000500af,0x0000001c,0x0000001d,0x00000019,0x0000001a,0x0004009a,0x0000001b,0x0000001e, + 0x0000001d,0x000300f7,0x00000020,0x00000000,0x000400fa,0x0000001e,0x0000001f,0x00000020, + 0x000200f8,0x0000001f,0x000100fd,0x000200f8,0x00000020,0x0004003d,0x00000007,0x00000025, + 0x00000012,0x0004006f,0x00000022,0x00000026,0x00000025,0x0003003e,0x00000024,0x00000026, + 0x0004003d,0x0000002a,0x0000002d,0x0000002c,0x00050041,0x00000034,0x00000035,0x00000032, + 0x00000033,0x0004003d,0x00000006,0x00000036,0x00000035,0x000500ab,0x0000001b,0x00000038, + 0x00000036,0x00000037,0x000300f7,0x0000003b,0x00000000,0x000400fa,0x00000038,0x0000003a, + 0x00000044,0x000200f8,0x0000003a,0x0004003d,0x00000007,0x0000003c,0x00000009,0x0004003d, + 0x00000007,0x0000003d,0x00000012,0x00050050,0x00000007,0x0000003f,0x0000003e,0x0000003e, + 0x00050082,0x00000007,0x00000040,0x0000003d,0x0000003f,0x0007000c,0x00000007,0x00000042, + 0x00000001,0x0000002a,0x00000040,0x00000041,0x0007000c,0x00000007,0x00000043,0x00000001, + 0x00000027,0x0000003c,0x00000042,0x0003003e,0x00000039,0x00000043,0x000200f9,0x0000003b, + 0x000200f8,0x00000044,0x0004003d,0x00000007,0x00000045,0x00000009,0x0003003e,0x00000039, + 0x00000045,0x000200f9,0x0000003b,0x000200f8,0x0000003b,0x0004003d,0x00000007,0x00000046, + 0x00000039,0x00040064,0x00000029,0x00000047,0x0000002d,0x0007005f,0x0000002e,0x00000048, + 0x00000047,0x00000046,0x00000002,0x00000037,0x00050051,0x00000013,0x0000004a,0x00000048, + 0x00000000,0x0003003e,0x00000028,0x0000004a,0x0004003d,0x00000007,0x0000004c,0x00000009, + 0x0004006f,0x00000022,0x0000004d,0x0000004c,0x00050050,0x00000022,0x0000004f,0x0000004e, + 0x0000004e,0x00050081,0x00000022,0x00000050,0x0000004d,0x0000004f,0x0004003d,0x00000022, + 0x00000051,0x00000024,0x00050088,0x00000022,0x00000052,0x00000050,0x00000051,0x0003003e, + 0x0000004b,0x00000052,0x0004003d,0x00000022,0x00000055,0x0000004b,0x00050085,0x00000022, + 0x00000059,0x00000055,0x00000058,0x00050081,0x00000022,0x0000005d,0x00000059,0x0000005c, + 0x0004003d,0x00000013,0x0000005e,0x00000028,0x00050085,0x00000013,0x0000005f,0x0000005e, + 0x00000056,0x00050083,0x00000013,0x00000060,0x0000005f,0x0000005b,0x00050051,0x00000013, + 0x00000061,0x0000005d,0x00000000,0x00050051,0x00000013,0x00000062,0x0000005d,0x00000001, + 0x00070050,0x0000002e,0x00000063,0x00000061,0x00000062,0x00000060,0x0000005b,0x0003003e, + 0x00000054,0x00000063,0x00050041,0x00000065,0x00000066,0x00000032,0x00000037,0x0004003d, + 0x0000002f,0x00000067,0x00000066,0x0004003d,0x0000002e,0x00000068,0x00000054,0x00050091, + 0x0000002e,0x00000069,0x00000067,0x00000068,0x0003003e,0x00000064,0x00000069,0x0003003e, + 0x0000006a,0x0000006c,0x0004003d,0x00000013,0x0000006d,0x00000028,0x000500be,0x0000001b, + 0x0000006e,0x0000006d,0x0000006b,0x0004003d,0x00000013,0x0000006f,0x00000028,0x000500bc, + 0x0000001b,0x00000070,0x0000006f,0x0000005b,0x000500a7,0x0000001b,0x00000071,0x0000006e, + 0x00000070,0x000300f7,0x00000073,0x00000000,0x000400fa,0x00000071,0x00000072,0x00000073, + 0x000200f8,0x00000072,0x00050041,0x00000027,0x00000075,0x00000064,0x00000074,0x0004003d, + 0x00000013,0x00000076,0x00000075,0x000500ba,0x0000001b,0x00000078,0x00000076,0x00000077, + 0x000200f9,0x00000073,0x000200f8,0x00000073,0x000700f5,0x0000001b,0x00000079,0x00000071, + 0x0000003b,0x00000078,0x00000072,0x000300f7,0x0000007b,0x00000000,0x000400fa,0x00000079, + 0x0000007a,0x0000007b,0x000200f8,0x0000007a,0x0004003d,0x0000002e,0x0000007d,0x00000064, + 0x0007004f,0x00000022,0x0000007e,0x0000007d,0x0000007d,0x00000000,0x00000001,0x00050041, + 0x00000027,0x0000007f,0x00000064,0x00000074,0x0004003d,0x00000013,0x00000080,0x0000007f, + 0x00050050,0x00000022,0x00000081,0x00000080,0x00000080,0x00050088,0x00000022,0x00000082, + 0x0000007e,0x00000081,0x0004003d,0x0000002e,0x00000083,0x00000054,0x0007004f,0x00000022, + 0x00000084,0x00000083,0x00000083,0x00000000,0x00000001,0x00050083,0x00000022,0x00000085, + 0x00000082,0x00000084,0x00050085,0x00000022,0x00000088,0x00000085,0x00000087,0x0004003d, + 0x00000022,0x00000089,0x00000024,0x00050085,0x00000022,0x0000008a,0x00000088,0x00000089, + 0x0003003e,0x0000007c,0x0000008a,0x0004003d,0x00000022,0x0000008b,0x0000007c,0x0006000c, + 0x00000022,0x0000008c,0x00000001,0x00000004,0x0000008b,0x000500bc,0x0000001c,0x0000008f, + 0x0000008c,0x0000008e,0x0004009b,0x0000001b,0x00000090,0x0000008f,0x000300f7,0x00000092, + 0x00000000,0x000400fa,0x00000090,0x00000091,0x00000092,0x000200f8,0x00000091,0x0004003d, + 0x00000022,0x00000093,0x0000007c,0x0003003e,0x0000006a,0x00000093,0x000200f9,0x00000092, + 0x000200f8,0x00000092,0x000200f9,0x0000007b,0x000200f8,0x0000007b,0x0004003d,0x00000014, + 0x00000094,0x00000016,0x0004003d,0x00000007,0x00000095,0x00000009,0x0004003d,0x00000022, + 0x00000096,0x0000006a,0x00050051,0x00000013,0x00000097,0x00000096,0x00000000,0x00050051, + 0x00000013,0x00000098,0x00000096,0x00000001,0x00070050,0x0000002e,0x00000099,0x00000097, + 0x00000098,0x0000006b,0x0000006b,0x00040063,0x00000094,0x00000095,0x00000099,0x000100fd, + 0x00010038 }; diff --git a/gpu/vk/shaders/dlss_output.comp b/gpu/vk/shaders/dlss_output.comp index 7df27f33e..c4b07ff24 100644 --- a/gpu/vk/shaders/dlss_output.comp +++ b/gpu/vk/shaders/dlss_output.comp @@ -15,6 +15,8 @@ void main() { vec3 sampled = all(equal(textureSize(dlss_color, 0), extent)) ? texelFetch(dlss_color, pixel, 0).rgb : textureLod(dlss_color, (vec2(pixel) + 0.5) / vec2(extent), 0).rgb; + // (hookshot-amd) nothing invalid into the game's scene image, whatever the upscaler made + if (any(isnan(sampled)) || any(isinf(sampled))) sampled = vec3(0.0); vec3 color = max(sampled, vec3(0.0)); imageStore(guest_color, pixel, vec4(color * color, 1.0)); } diff --git a/gpu/vk/shaders/dlss_output_comp_spv.h b/gpu/vk/shaders/dlss_output_comp_spv.h index 090f881d1..5cf1d7571 100644 --- a/gpu/vk/shaders/dlss_output_comp_spv.h +++ b/gpu/vk/shaders/dlss_output_comp_spv.h @@ -1,7 +1,7 @@ - // 1116.6.0 + // 1116.2.0 #pragma once const uint32_t DLSS_OUTPUT_COMP_SPV[] = { - 0x07230203,0x00010600,0x0008000b,0x00000059,0x00000000,0x00020011,0x00000001,0x00020011, + 0x07230203,0x00010500,0x0008000b,0x00000066,0x00000000,0x00020011,0x00000001,0x00020011, 0x00000031,0x00020011,0x00000032,0x0006000b,0x00000001,0x4c534c47,0x6474732e,0x3035342e, 0x00000000,0x0003000e,0x00000000,0x00000001,0x0008000f,0x00000005,0x00000004,0x6e69616d, 0x00000000,0x0000000d,0x00000016,0x00000028,0x00060010,0x00000004,0x00000011,0x00000008, @@ -10,30 +10,31 @@ const uint32_t DLSS_OUTPUT_COMP_SPV[] = { 0x61626f6c,0x766e496c,0x7461636f,0x496e6f69,0x00000044,0x00040005,0x00000012,0x65747865, 0x0000746e,0x00050005,0x00000016,0x73657567,0x6f635f74,0x00726f6c,0x00040005,0x00000024, 0x706d6173,0x0064656c,0x00050005,0x00000028,0x73736c64,0x6c6f635f,0x0000726f,0x00040005, - 0x00000048,0x6f6c6f63,0x00000072,0x00040047,0x0000000d,0x0000000b,0x0000001c,0x00030047, + 0x00000056,0x6f6c6f63,0x00000072,0x00040047,0x0000000d,0x0000000b,0x0000001c,0x00030047, 0x00000016,0x00000019,0x00040047,0x00000016,0x00000021,0x00000001,0x00040047,0x00000016, 0x00000022,0x00000000,0x00040047,0x00000028,0x00000021,0x00000000,0x00040047,0x00000028, - 0x00000022,0x00000000,0x00020013,0x00000002,0x00030021,0x00000003,0x00000002,0x00040015, - 0x00000006,0x00000020,0x00000001,0x00040017,0x00000007,0x00000006,0x00000002,0x00040020, - 0x00000008,0x00000007,0x00000007,0x00040015,0x0000000a,0x00000020,0x00000000,0x00040017, - 0x0000000b,0x0000000a,0x00000003,0x00040020,0x0000000c,0x00000001,0x0000000b,0x0004003b, - 0x0000000c,0x0000000d,0x00000001,0x00040017,0x0000000e,0x0000000a,0x00000002,0x00030016, - 0x00000013,0x00000020,0x00090019,0x00000014,0x00000013,0x00000001,0x00000000,0x00000000, - 0x00000000,0x00000002,0x00000008,0x00040020,0x00000015,0x00000000,0x00000014,0x0004003b, - 0x00000015,0x00000016,0x00000000,0x00020014,0x0000001b,0x00040017,0x0000001c,0x0000001b, - 0x00000002,0x00040017,0x00000022,0x00000013,0x00000003,0x00040020,0x00000023,0x00000007, - 0x00000022,0x00090019,0x00000025,0x00000013,0x00000001,0x00000000,0x00000000,0x00000000, - 0x00000001,0x00000000,0x0003001b,0x00000026,0x00000025,0x00040020,0x00000027,0x00000000, - 0x00000026,0x0004003b,0x00000027,0x00000028,0x00000000,0x0004002b,0x00000006,0x0000002a, - 0x00000000,0x00040017,0x00000036,0x00000013,0x00000004,0x00040017,0x0000003c,0x00000013, - 0x00000002,0x0004002b,0x00000013,0x0000003e,0x3f000000,0x0004002b,0x00000013,0x00000044, - 0x00000000,0x0006002c,0x00000022,0x0000004a,0x00000044,0x00000044,0x00000044,0x0004002b, - 0x00000013,0x00000051,0x3f800000,0x0004002b,0x0000000a,0x00000056,0x00000008,0x0004002b, - 0x0000000a,0x00000057,0x00000001,0x0006002c,0x0000000b,0x00000058,0x00000056,0x00000056, - 0x00000057,0x00050036,0x00000002,0x00000004,0x00000000,0x00000003,0x000200f8,0x00000005, + 0x00000022,0x00000000,0x00040047,0x00000065,0x0000000b,0x00000019,0x00020013,0x00000002, + 0x00030021,0x00000003,0x00000002,0x00040015,0x00000006,0x00000020,0x00000001,0x00040017, + 0x00000007,0x00000006,0x00000002,0x00040020,0x00000008,0x00000007,0x00000007,0x00040015, + 0x0000000a,0x00000020,0x00000000,0x00040017,0x0000000b,0x0000000a,0x00000003,0x00040020, + 0x0000000c,0x00000001,0x0000000b,0x0004003b,0x0000000c,0x0000000d,0x00000001,0x00040017, + 0x0000000e,0x0000000a,0x00000002,0x00030016,0x00000013,0x00000020,0x00090019,0x00000014, + 0x00000013,0x00000001,0x00000000,0x00000000,0x00000000,0x00000002,0x00000008,0x00040020, + 0x00000015,0x00000000,0x00000014,0x0004003b,0x00000015,0x00000016,0x00000000,0x00020014, + 0x0000001b,0x00040017,0x0000001c,0x0000001b,0x00000002,0x00040017,0x00000022,0x00000013, + 0x00000003,0x00040020,0x00000023,0x00000007,0x00000022,0x00090019,0x00000025,0x00000013, + 0x00000001,0x00000000,0x00000000,0x00000000,0x00000001,0x00000000,0x0003001b,0x00000026, + 0x00000025,0x00040020,0x00000027,0x00000000,0x00000026,0x0004003b,0x00000027,0x00000028, + 0x00000000,0x0004002b,0x00000006,0x0000002a,0x00000000,0x00040017,0x00000036,0x00000013, + 0x00000004,0x00040017,0x0000003c,0x00000013,0x00000002,0x0004002b,0x00000013,0x0000003e, + 0x3f000000,0x0004002b,0x00000013,0x00000044,0x00000000,0x00040017,0x00000049,0x0000001b, + 0x00000003,0x0006002c,0x00000022,0x00000055,0x00000044,0x00000044,0x00000044,0x0004002b, + 0x00000013,0x0000005e,0x3f800000,0x0004002b,0x0000000a,0x00000063,0x00000008,0x0004002b, + 0x0000000a,0x00000064,0x00000001,0x0006002c,0x0000000b,0x00000065,0x00000063,0x00000063, + 0x00000064,0x00050036,0x00000002,0x00000004,0x00000000,0x00000003,0x000200f8,0x00000005, 0x0004003b,0x00000008,0x00000009,0x00000007,0x0004003b,0x00000008,0x00000012,0x00000007, 0x0004003b,0x00000023,0x00000024,0x00000007,0x0004003b,0x00000023,0x00000030,0x00000007, - 0x0004003b,0x00000023,0x00000048,0x00000007,0x0004003d,0x0000000b,0x0000000f,0x0000000d, + 0x0004003b,0x00000023,0x00000056,0x00000007,0x0004003d,0x0000000b,0x0000000f,0x0000000d, 0x0007004f,0x0000000e,0x00000010,0x0000000f,0x0000000f,0x00000000,0x00000001,0x0004007c, 0x00000007,0x00000011,0x00000010,0x0003003e,0x00000009,0x00000011,0x0004003d,0x00000014, 0x00000017,0x00000016,0x00040068,0x00000007,0x00000018,0x00000017,0x0003003e,0x00000012, @@ -57,13 +58,21 @@ const uint32_t DLSS_OUTPUT_COMP_SPV[] = { 0x00000045,0x0000003a,0x00000043,0x00000002,0x00000044,0x0008004f,0x00000022,0x00000046, 0x00000045,0x00000045,0x00000000,0x00000001,0x00000002,0x0003003e,0x00000030,0x00000046, 0x000200f9,0x00000032,0x000200f8,0x00000032,0x0004003d,0x00000022,0x00000047,0x00000030, - 0x0003003e,0x00000024,0x00000047,0x0004003d,0x00000022,0x00000049,0x00000024,0x0007000c, - 0x00000022,0x0000004b,0x00000001,0x00000028,0x00000049,0x0000004a,0x0003003e,0x00000048, - 0x0000004b,0x0004003d,0x00000014,0x0000004c,0x00000016,0x0004003d,0x00000007,0x0000004d, - 0x00000009,0x0004003d,0x00000022,0x0000004e,0x00000048,0x0004003d,0x00000022,0x0000004f, - 0x00000048,0x00050085,0x00000022,0x00000050,0x0000004e,0x0000004f,0x00050051,0x00000013, - 0x00000052,0x00000050,0x00000000,0x00050051,0x00000013,0x00000053,0x00000050,0x00000001, - 0x00050051,0x00000013,0x00000054,0x00000050,0x00000002,0x00070050,0x00000036,0x00000055, - 0x00000052,0x00000053,0x00000054,0x00000051,0x00040063,0x0000004c,0x0000004d,0x00000055, + 0x0003003e,0x00000024,0x00000047,0x0004003d,0x00000022,0x00000048,0x00000024,0x0004009c, + 0x00000049,0x0000004a,0x00000048,0x0004009a,0x0000001b,0x0000004b,0x0000004a,0x000400a8, + 0x0000001b,0x0000004c,0x0000004b,0x000300f7,0x0000004e,0x00000000,0x000400fa,0x0000004c, + 0x0000004d,0x0000004e,0x000200f8,0x0000004d,0x0004003d,0x00000022,0x0000004f,0x00000024, + 0x0004009d,0x00000049,0x00000050,0x0000004f,0x0004009a,0x0000001b,0x00000051,0x00000050, + 0x000200f9,0x0000004e,0x000200f8,0x0000004e,0x000700f5,0x0000001b,0x00000052,0x0000004b, + 0x00000032,0x00000051,0x0000004d,0x000300f7,0x00000054,0x00000000,0x000400fa,0x00000052, + 0x00000053,0x00000054,0x000200f8,0x00000053,0x0003003e,0x00000024,0x00000055,0x000200f9, + 0x00000054,0x000200f8,0x00000054,0x0004003d,0x00000022,0x00000057,0x00000024,0x0007000c, + 0x00000022,0x00000058,0x00000001,0x00000028,0x00000057,0x00000055,0x0003003e,0x00000056, + 0x00000058,0x0004003d,0x00000014,0x00000059,0x00000016,0x0004003d,0x00000007,0x0000005a, + 0x00000009,0x0004003d,0x00000022,0x0000005b,0x00000056,0x0004003d,0x00000022,0x0000005c, + 0x00000056,0x00050085,0x00000022,0x0000005d,0x0000005b,0x0000005c,0x00050051,0x00000013, + 0x0000005f,0x0000005d,0x00000000,0x00050051,0x00000013,0x00000060,0x0000005d,0x00000001, + 0x00050051,0x00000013,0x00000061,0x0000005d,0x00000002,0x00070050,0x00000036,0x00000062, + 0x0000005f,0x00000060,0x00000061,0x0000005e,0x00040063,0x00000059,0x0000005a,0x00000062, 0x000100fd,0x00010038 }; diff --git a/gpu/vk/vk_draw.cpp b/gpu/vk/vk_draw.cpp index 0a702f763..05423eb5a 100644 --- a/gpu/vk/vk_draw.cpp +++ b/gpu/vk/vk_draw.cpp @@ -47,6 +47,7 @@ #include "shaders/dlss_output_comp_spv.h" #include "shaders/dlss_debug_comp_spv.h" #include "vk_dlss.h" +#include "vk_fsr4.h" #include "vk_menu.h" #include "shader_recompiler/backend/spirv/mma_layout.h" #include "vk_work.h" // (after the others: counts the commands that do GPU work, for full_barrier) @@ -2778,7 +2779,10 @@ bool dyn_same(const float* fp, int nf, const uint32_t* up, int nu, const uint8_t if (raw[i] != craw[i]) return false; return true; } -constexpr int kDynF = 13, kDynU = 35; +// (hookshot-amd) AMD FSR 4.1's sub-pixel jitter of the scene's draws (fsr_jitter_for, with the DLSS frame code): part of the +// state a draw is compared by (fp[13], fp[14]), or a frame whose draws match the last frame's would keep its jitter +bool fsr_jitter_for(const Targets& at, float& jx, float& jy); +constexpr int kDynF = 15, kDynU = 35; struct DynFast { bool on = false; float fp[kDynF]{}; @@ -2794,6 +2798,9 @@ int dyn_pack(const NvnState& s, const Targets& at, VkPrimitiveTopology topo, boo fp[4] = s.depth_near, fp[5] = s.depth_far; std::memcpy(fp + 6, s.blend_color, sizeof s.blend_color); fp[10] = s.poly_offset[0], fp[11] = s.poly_offset[1], fp[12] = s.poly_offset[2]; + // (only draws that test or write the scene's depth: full-screen passes and the HUD are not moved) + fp[13] = fp[14] = 0.0f; + if ((s.ds.dt || s.ds.dw) && at.depth && depth_aspect(at.depth_format)) fsr_jitter_for(at, fp[13], fp[14]); up[0] = (uint32_t)s.scissor[0], up[1] = (uint32_t)s.scissor[1], up[2] = (uint32_t)s.scissor[2], up[3] = (uint32_t)s.scissor[3]; up[4] = s.stencil_ref[0], up[5] = s.stencil_ref[1]; up[6] = s.stencil_value_mask[0], up[7] = s.stencil_value_mask[1]; @@ -2852,6 +2859,7 @@ void dynamic_state(VkCommandBuffer cmd, const NvnState& s, const Targets& at, Vk float vx = s.viewport[0][0], vy = s.viewport[0][1], vw = s.viewport[0][2], vh = s.viewport[0][3]; if (vw == 0.0f && vh == 0.0f) vx = 0, vy = 0, vw = (float)at.width, vh = (float)at.height; d.vp = {vx, vy + vh, vw, -vh, std::clamp(s.depth_near, 0.0f, 1.0f), std::clamp(s.depth_far, 0.0f, 1.0f)}; + d.vp.x += df[13], d.vp.y += df[14]; // (AMD FSR 4.1's jitter, render pixels: right and down for positive values) d.sc = {{0, 0}, {at.width, at.height}}; if (s.scissor[2] > 0 && s.scissor[3] > 0) { const int32_t x0 = std::max(0, s.scissor[0]), y0 = std::max(0, s.scissor[1]); @@ -5476,6 +5484,50 @@ struct DlssState { DlssState ds; // ponytail: one set of images, no lock: the replay records one frame at a time (RX_VK_PARALLEL would need ParLock here) bool dlss_on() { return opts.dlss && dlss_available(); } +// (hookshot-amd) AMD FSR 4.1 on the same frames (vk_fsr4.cpp), from the same colour, depth and camera motion, when DLSS is not on: +// the menu's AMD FSR 4.1 row (at once) and AMD's DLLs found. Ported from madebyjordan's FSR 4.1 work on Lichii +bool fsr_on() { return opts.fsr4 && !dlss_on() && fsr4_available(); } +bool upscaler_on() { return dlss_on() || fsr_on(); } +const char* upscaler_name() { return fsr_on() ? "fsr4" : "dlss"; } + +// FSR's jitter. The game draws without one, so a temporal upscaler has no sub-pixel detail to gather: the draws that test or write +// the scene's depth are moved by a sub-pixel amount through the viewport (dyn_pack, dynamic_state), Halton (2, 3) as FSR's own +// helpers make it, and FSR is told the amount. (Lichii, on the same game and an RX 6700 XT:) +// - The phase moves on at the network's pass, where the game's frame ends; counted by presents, which can come while the next +// frame is drawn, part of a frame's draws had one offset and the rest another. +// - Only while FSR replaces the upscale (the last network pass, and a present at most since): the game's own upscale would show +// the jitter as shimmer. The frame FSR comes back on is drawn and evaluated without one. +// - Moved up or left, the AMD driver draws nothing into the scene's last column or row, which keeps a stale, near-white value: +// a flickering line on the right and bottom edges that built up in FSR's history (one long run ended in device loss). FSR's +// colour and the motion's depth repeat the column and row before them (fsr != 0 in dlss_color.comp and dlss_motion.comp). +// Offsets kept in [0, 1) avoided it but gave FSR 4 horizontal seams every 128 rows in bright haze. +// RX_FSR4_JITTER=0: none (FSR still runs) +struct FsrJitter { + uint64_t phase = 0; + uint32_t phases = 16; // (FSR's 8 per (output pixel / render pixel)^2, from the last evaluation's sizes: 16 at 75%) + float x = 0, y = 0; // (the offset of the frame being drawn: 0 unless live) + bool drew = false; // (FSR replaced the last network pass: its history goes on) + bool live = false; // (and the jitter is on) + bool used = false; // (a draw of this frame was moved: FSR is told x, y) + uint64_t net_present = 0; // (the present the last network pass came in) +}; +FsrJitter fj; +float halton(uint32_t i, uint32_t base) { + float f = 1.0f, r = 0.0f; + for (; i; i /= base) f /= (float)base, r += f * (float)(i % base); + return r; +} +/// At the network's pass (the game's frame ends): the next frame's offset; live: FSR drew this one +void fsr_frame_end(bool live, uint32_t rw, uint32_t ow) { + static const bool off = getenv("RX_FSR4_JITTER") && !atoi(getenv("RX_FSR4_JITTER")); + fj.drew = live, fj.live = live && !off, fj.used = false, fj.phase++, fj.net_present = texture_frame_no(); + if (live && rw && ow) { + const float k = (float)ow / (float)rw; + fj.phases = (uint32_t)std::clamp(8.0f * k * k + 0.5f, 8.0f, 32.0f); + } + const uint32_t i = (uint32_t)(fj.phase % fj.phases) + 1; + fj.x = fj.live ? halton(i, 2) - 0.5f : 0.0f, fj.y = fj.live ? halton(i, 3) - 0.5f : 0.0f; +} // RX_DLSS_DEBUG=1..4 (dlss_debug.comp): motion, depth, or the reprojection error with and without the motion, drawn in place of // DLSS's output (DLSS still runs) int dlss_debug() { static const int v = getenv("RX_DLSS_DEBUG") ? atoi(getenv("RX_DLSS_DEBUG")) : 0; return v; } // (the menu's Off takes effect at once; On needs the start's Streamline) @@ -5483,7 +5535,7 @@ int dlss_debug() { static const int v = getenv("RX_DLSS_DEBUG") ? atoi(getenv("R /// Logged when the reason changes and every 600th repeat: the game's chain draws this frame void dlss_fallback(const char* why) { if (why != ds.reason || ++ds.repeats % 600 == 0) - logf("vk: dlss: the game's upscale draws frame %llu (%s)", (unsigned long long)texture_frame_no(), why); + logf("vk: %s: the game's upscale draws frame %llu (%s)", upscaler_name(), (unsigned long long)texture_frame_no(), why); if (why != ds.reason) ds.reason = why, ds.repeats = 0; } @@ -5552,7 +5604,7 @@ bool dlss_pipelines() { li.flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR, li.bindingCount = 2, li.pBindings = b; VkDescriptorSetLayout set{}; if (vkCreateDescriptorSetLayout(dev.device, &li, nullptr, &set) != VK_SUCCESS) return false; - const VkPushConstantRange pr{VK_SHADER_STAGE_COMPUTE_BIT, 0, 64}; + const VkPushConstantRange pr{VK_SHADER_STAGE_COMPUTE_BIT, 0, 80}; // (hookshot-amd: 64 + the passes' FSR flag) VkPipelineLayoutCreateInfo pi{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; pi.setLayoutCount = 1, pi.pSetLayouts = &set, pi.pushConstantRangeCount = 1, pi.pPushConstantRanges = ≺ if (vkCreatePipelineLayout(dev.device, &pi, nullptr, &ds.layout) != VK_SUCCESS) return false; @@ -5605,7 +5657,7 @@ void dlss_pass(VkCommandBuffer cmd, VkPipeline pipe, VkSampler sampler, VkImageV wr[1].dstBinding = 1, wr[1].descriptorCount = 1, wr[1].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, wr[1].pImageInfo = &oi; vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, pipe); vkCmdPushDescriptorSetKHR(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, ds.layout, 0, 2, wr); - if (push) vkCmdPushConstants(cmd, ds.layout, VK_SHADER_STAGE_COMPUTE_BIT, 0, 64, push); + if (push) vkCmdPushConstants(cmd, ds.layout, VK_SHADER_STAGE_COMPUTE_BIT, 0, 80, push); // (push: 20 words) vkCmdDispatch(cmd, (w + 7) / 8, (h + 7) / 8, 1); } /// RX_DLSS_DEBUG: its view into the network's target (out), then this frame's colour kept as the next one's previous @@ -5632,11 +5684,22 @@ bool dlss_debug_pass(VkCommandBuffer cmd, VkImageView out, uint32_t w, uint32_t } } // namespace +namespace { // (with Targets, as its declaration above dyn_pack) +/// From dyn_pack: the offset a draw into these targets is moved by (0, 0 for a target not the scene's size: shadow maps, reflections) +bool fsr_jitter_for(const Targets& at, float& jx, float& jy) { + if (!fj.live || par_active.load(std::memory_order_relaxed) || !at.depth || !ds.cam.w || at.depth->width != ds.cam.w || + at.depth->height != ds.cam.h || texture_frame_no() - fj.net_present > 1 || !fsr_on()) + return false; + jx = fj.x, jy = fj.y, fj.used = true; + return true; +} +} // namespace + /// From draw(): the scene camera (Lichii's TrackOcarinaCamera): vertex constant buffer 3 of a draw into a B10G11R11 target of at /// least 640x360 with D32 depth, whose +0x120/+0x124 are the target's size and +0xa8/+0xac -1 and 0; current view-projection at /// +0x30, the previous frame's at +0x180. The largest such target of the frame void dlss_note_camera(const NvnState& s, const Targets& at) { - if (!dlss_on() || at.n < 1 || !at.color[0] || at.color_format[0] != VK_FORMAT_B10G11R11_UFLOAT_PACK32 || at.width < 640 || + if (!upscaler_on() || at.n < 1 || !at.color[0] || at.color_format[0] != VK_FORMAT_B10G11R11_UFLOAT_PACK32 || at.width < 640 || at.height < 360 || !at.depth || at.depth_format != VK_FORMAT_D32_SFLOAT || at.samples != VK_SAMPLE_COUNT_1_BIT || at.depth_level || at.depth_layer || !at.depth_view) return; @@ -5670,7 +5733,8 @@ bool dlss_take_colour(VkCommandBuffer cmd, const Program& p, bool encode) { if (!dlss_image(ds.color, ds.cam.w, ds.cam.h, VK_FORMAT_R16G16B16A16_SFLOAT, VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, cmd) || !dlss_image(ds.motion, ds.cam.w, ds.cam.h, VK_FORMAT_R16G16_SFLOAT, VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, cmd)) return dlss_fallback("images not made"), false; - int32_t push[16] = {encode ? 1 : 0}; + // (fsr: AMD FSR 4.1 takes it: no NaN or out-of-range value into its LDR history, the last column and row repeated: FsrJitter) + int32_t push[20] = {encode ? 1 : 0, fsr_on() ? 1 : 0}; gprof_begin(cmd); full_barrier(cmd); dlss_pass(cmd, ds.color_pipe, ds.nearest, dw.imgs[0].imageView, ds.color.view, ds.cam.w, ds.cam.h, push); @@ -5686,7 +5750,7 @@ bool dlss_take_colour(VkCommandBuffer cmd, const Program& p, bool encode) { bool dlss_dispatch(VkCommandBuffer cmd, const NvnState& s, const Program& p) { const bool pre = p.key == kChainFirst || p.key == kChainMid1 || p.key == kChainMid2; const bool known = chain_net(p.key); - if ((!pre && !known && !ds.armed) || !dlss_on()) return false; + if ((!pre && !known && !ds.armed) || !upscaler_on()) return false; // (the first three prepare the network's input and feed nothing else: left out, DLSS takes the tonemapped scene, square-root // encoded here as they do. The same picture as with them (means within 1% in the A/B, docs in the DLSS report). // RX_DLSS_KEEP_PREPASSES=1: they run and DLSS takes the network's input, as Lichii does) @@ -5697,6 +5761,13 @@ bool dlss_dispatch(VkCommandBuffer cmd, const NvnState& s, const Program& p) { return ds.armed; } if (!known && !skip_pre) return false; // (unknown networks by their place only: with the prepasses left out) + // (hookshot-amd: the game's frame ends here; FSR's next jitter, live when FSR drew this one) + const bool fsr = fsr_on(); + struct FrameEnd { + bool drew = false; + uint32_t rw = 0, ow = 0; + ~FrameEnd() { fsr_frame_end(drew, rw, ow); } + } frame_end; const bool armed = ds.armed; // (the network's input was never made: whatever happens, the network cannot run) if (skip_pre ? !armed : !dlss_take_colour(cmd, p, false)) return false; const uint64_t now = texture_frame_no(); @@ -5729,11 +5800,16 @@ bool dlss_dispatch(VkCommandBuffer cmd, const NvnState& s, const Program& p) { Mat clip{}; const bool have_motion = clip_to_previous(ds.used.cur, ds.used.prev, clip); if (ok && have_motion) { - dlss_pass(cmd, ds.motion_pipe, ds.nearest, ds.used.depth_view, ds.motion.view, rw, rh, clip.data()); + float mpush[20] = {}; // (the matrix, then FSR's flag: the last column and row repeat the ones before them) + std::copy(clip.begin(), clip.end(), mpush); + const int32_t edge = fsr ? 1 : 0; + std::memcpy(&mpush[16], &edge, 4); + dlss_pass(cmd, ds.motion_pipe, ds.nearest, ds.used.depth_view, ds.motion.view, rw, rh, mpush); full_barrier(cmd); bool same_camera = true; // (a camera cut: the previous matrix is not last frame's current one) for (int i = 0; i < 16; i++) same_camera = same_camera && std::abs(ds.used.prev[i] - ds.last_vp[i]) < 0.001f; - const bool reset = ds.last_frame == ~0ull || now != ds.last_frame + 1 || !same_camera; + // (FSR: history goes on while it drew the last network pass; presents can come mid-frame, and made frames add presents) + const bool reset = (fsr ? !fj.drew : (ds.last_frame == ~0ull || now != ds.last_frame + 1)) || !same_camera; ds.resets += reset, ds.cuts += reset && !same_camera; if (dlss_debug() && ds.evals >= 1500 && ds.evals < 1512) { // (the camera of 12 frames: a jitter would move [0][3]/[1][3] by ~1/w) const Mat& m = ds.used.cur; @@ -5748,10 +5824,15 @@ bool dlss_dispatch(VkCommandBuffer cmd, const NvnState& s, const Program& p) { const DlssImage depth{ds.used.depth->image, ds.used.depth_view, VK_FORMAT_D32_SFLOAT, rw, rh, VK_IMAGE_ASPECT_DEPTH_BIT}; const DlssImage motion{ds.motion.image, ds.motion.view, VK_FORMAT_R16G16_SFLOAT, rw, rh, VK_IMAGE_ASPECT_COLOR_BIT}; const DlssImage output{ds.out.image, ds.out.view, VK_FORMAT_R16G16B16A16_SFLOAT, ow, oh, VK_IMAGE_ASPECT_COLOR_BIT}; - ok = dlss_evaluate(cmd, color, depth, motion, output, reset, ds.evals++); + // (FSR is told the offset this frame's scene was drawn with: none when no draw was moved) + ok = fsr ? fsr4_evaluate(cmd, color, depth, motion, output, fj.used ? fj.x : 0.0f, fj.used ? fj.y : 0.0f, reset) + : dlss_evaluate(cmd, color, depth, motion, output, reset, ds.evals++); + if (fsr) ds.evals++; + frame_end.drew = ok && fsr, frame_end.rw = rw, frame_end.ow = ow; if (ok) { if (ds.reason || ds.last_frame == ~0ull) - logf("vk: dlss: DLSS draws the upscale from frame %llu (%ux%u -> %ux%u)", (unsigned long long)now, rw, rh, ow, oh); + logf("vk: %s: %s draws the upscale from frame %llu (%ux%u -> %ux%u)", upscaler_name(), fsr ? "AMD FSR 4.1" : "DLSS", + (unsigned long long)now, rw, rh, ow, oh); ds.reason = nullptr; ds.last_frame = now, ds.last_vp = ds.used.cur; } diff --git a/gpu/vk/vk_fsr4.cpp b/gpu/vk/vk_fsr4.cpp new file mode 100644 index 000000000..c357d4835 --- /dev/null +++ b/gpu/vk/vk_fsr4.cpp @@ -0,0 +1,281 @@ +// AMD FSR 4.1 in place of the game's gameplay upscale (vk_fsr4.h). The host side follows the API guide of FidelityFX SDK 2.4 +// (Kits/FidelityFX/docs/getting-started/ffx-api.md): a Vulkan backend description chained to the upscale context description, +// inputs read in SHADER_READ_ONLY_OPTIMAL, the output written in GENERAL. Ported from madebyjordan's FSR 4.1 work on Lichii +// (vk_fsr4_upscaler.cpp), GPL-3.0-or-later. +#include "vk_paths.h" +#include "vk_fsr4.h" + +#include +#include +#include +#include +#include +#include + +#include "vk_internal.h" + +#include "api/include/ffx_api.h" +#include "api/include/ffx_api_types.h" +#include "api/include/vk/ffx_api_vk.h" +#include "upscalers/include/ffx_upscale.h" + +namespace mkwvk { +namespace { + +constexpr const char* kLoader = "amd_fidelityfx_loader_vk.dll"; + +struct Fsr { + bool tried = false, ok = false; + const char* reason = "not started"; + HMODULE lib = nullptr; + PfnFfxCreateContext create = nullptr; + PfnFfxDestroyContext destroy = nullptr; + PfnFfxQuery query = nullptr; + PfnFfxDispatch dispatch = nullptr; + uint64_t version_id = 0; + // (the context keeps pointers into its creation descriptions until it is destroyed) + VkDeviceContext device_context{}; + ffxCreateBackendVKDesc backend{}; + ffxOverrideVersion version{}; + ffxCreateContextDescUpscale upscale{}; + ffxContext context = nullptr; + uint32_t max_w = 0, max_h = 0; // (the context's sizes: the output's, the most the render size can be) + std::chrono::steady_clock::time_point last{}; + uint64_t evals = 0; +}; +Fsr fsr; + +void on_message(uint32_t type, const wchar_t* message) { + char text[512] = {}; + if (message) WideCharToMultiByte(CP_UTF8, 0, message, -1, text, (int)sizeof text - 1, nullptr, nullptr); + logf("vk: fsr4: AMD FSR %s: %s", type == FFX_API_MESSAGE_TYPE_ERROR ? "error" : "warning", text); +} + +/// The folders the loader is looked for in: RX_FSR4_DIR, the executable's (bin\ beside the launcher), the game folder +std::vector loader_dirs() { + std::vector d; + if (const char* e = getenv("RX_FSR4_DIR"); e && *e) d.emplace_back(e); + char exe[MAX_PATH]; + DWORD n = GetModuleFileNameA(nullptr, exe, MAX_PATH); + if (n && n < MAX_PATH) { + std::string s(exe, n); + d.push_back(s.substr(0, s.find_last_of("\\/"))); + } + n = game_module_path(exe, MAX_PATH); + if (n && n < MAX_PATH) { + std::string s(exe, n); + s = s.substr(0, s.find_last_of("\\/")); + if (d.empty() || d.back() != s) d.push_back(s); + } + return d; +} + +bool start() { + fsr.tried = true; + for (const std::string& dir : loader_dirs()) { + const std::string path = dir + "\\" + kLoader; + if (GetFileAttributesA(path.c_str()) == INVALID_FILE_ATTRIBUTES) continue; + // (the upscaler DLL the loader picks lies beside it: the loader's folder first in the search) + fsr.lib = LoadLibraryExA(path.c_str(), nullptr, LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR | LOAD_LIBRARY_SEARCH_DEFAULT_DIRS); + if (fsr.lib) { + logf("vk: fsr4: %s", path.c_str()); + break; + } + } + if (!fsr.lib) { + fsr.reason = "no AMD FSR DLLs"; + logf("vk: fsr4: %s not found (RX_FSR4_DIR, or beside hookshot.exe with amd_fidelityfx_upscaler_vk.dll)", kLoader); + return false; + } + fsr.create = (PfnFfxCreateContext)(void*)GetProcAddress(fsr.lib, "ffxCreateContext"); + fsr.destroy = (PfnFfxDestroyContext)(void*)GetProcAddress(fsr.lib, "ffxDestroyContext"); + fsr.query = (PfnFfxQuery)(void*)GetProcAddress(fsr.lib, "ffxQuery"); + fsr.dispatch = (PfnFfxDispatch)(void*)GetProcAddress(fsr.lib, "ffxDispatch"); + if (!fsr.create || !fsr.destroy || !fsr.query || !fsr.dispatch) { + fsr.reason = "the AMD loader lacks the FSR API"; + logf("vk: fsr4: %s lacks the FSR API's entry points", kLoader); + return false; + } + fsr.device_context = VkDeviceContext{dev.device, dev.physical, vkGetDeviceProcAddr}; + // (the loader lists every upscaler this device can run: the newest 4.x is taken explicitly, so an FSR 3.1 provider never + // stands in silently) + ffxQueryDescGetVersions versions{}; + versions.header.type = FFX_API_QUERY_DESC_TYPE_GET_VERSIONS; + versions.createDescType = FFX_API_CREATE_CONTEXT_DESC_TYPE_UPSCALE; + versions.device = &fsr.device_context; + uint64_t count = 0; + versions.outputCount = &count; + if (fsr.query(nullptr, &versions.header) != FFX_API_RETURN_OK || !count) { + fsr.reason = "no AMD upscaler for this GPU"; + logf("vk: fsr4: the loader lists no upscaler for this device"); + return false; + } + std::vector ids(count); + std::vector names(count); + versions.versionIds = ids.data(); + versions.versionNames = names.data(); + if (fsr.query(nullptr, &versions.header) != FFX_API_RETURN_OK) { + fsr.reason = "no AMD upscaler for this GPU"; + logf("vk: fsr4: the upscaler versions could not be listed"); + return false; + } + std::string listed; + unsigned best[3] = {0, 0, 0}; + for (uint64_t i = 0; i < count; i++) { + const char* name = names[i] ? names[i] : ""; + listed += (listed.empty() ? "" : ", ") + std::string(name); + unsigned v[3] = {0, 0, 0}; + sscanf(name, "%u.%u.%u", &v[0], &v[1], &v[2]); + if (v[0] == 4 && (v[1] > best[1] || (v[1] == best[1] && v[2] >= best[2]))) { + std::memcpy(best, v, sizeof best); + fsr.version_id = ids[i]; + } + } + if (!fsr.version_id) { + fsr.reason = "no FSR 4 for this GPU"; + logf("vk: fsr4: no FSR 4 upscaler for this device (the loader has: %s)", listed.c_str()); + return false; + } + logf("vk: fsr4: upscalers %s; using %u.%u.%u", listed.c_str(), best[0], best[1], best[2]); + fsr.ok = true; + fsr.reason = ""; + return true; +} + +void destroy_context() { + if (!fsr.context) return; + vkDeviceWaitIdle(dev.device); // (recorded evaluations may still use it; the sizes seldom change) + fsr.destroy(&fsr.context, nullptr); + fsr.context = nullptr; +} + +/// The context for outputs of w x h, render sizes up to it (the game's dynamic resolution and the Resolution row's change the +/// render size every so often: one context takes them all) +bool make_context(uint32_t w, uint32_t h) { + destroy_context(); + fsr.backend = {}; + fsr.backend.header.type = FFX_API_CREATE_CONTEXT_DESC_TYPE_BACKEND_VK; + fsr.backend.deviceContext = fsr.device_context; + fsr.version = {}; + fsr.version.header.type = FFX_API_DESC_TYPE_OVERRIDE_VERSION; + fsr.version.versionId = fsr.version_id; + fsr.backend.header.pNext = &fsr.version.header; + fsr.upscale = {}; + fsr.upscale.header.type = FFX_API_CREATE_CONTEXT_DESC_TYPE_UPSCALE; + fsr.upscale.header.pNext = &fsr.backend.header; + // (the game's colour is tonemapped and square-root encoded already: LDR, perceptual, no auto exposure; depth not inverted) + fsr.upscale.flags = FFX_UPSCALE_ENABLE_NON_LINEAR_COLORSPACE; + fsr.upscale.maxRenderSize = {w, h}; + fsr.upscale.maxUpscaleSize = {w, h}; + fsr.upscale.fpMessage = &on_message; + ffxContext made = nullptr; + const ffxReturnCode_t r = fsr.create(&made, &fsr.upscale.header, nullptr); + if (r != FFX_API_RETURN_OK || !made) { + logf("vk: fsr4: creating the upscaler failed (%d)", (int)r); + return false; + } + fsr.context = made; + fsr.max_w = w, fsr.max_h = h; + ffxQueryGetProviderVersion provider{}; + provider.header.type = FFX_API_QUERY_DESC_TYPE_GET_PROVIDER_VERSION; + const bool known = fsr.query(&fsr.context, &provider.header) == FFX_API_RETURN_OK && provider.versionName; + logf("vk: fsr4: AMD FSR %s for outputs of %ux%u", known ? provider.versionName : "?", w, h); + return true; +} + +FfxApiResource resource(const DlssImage& im, VkImageUsageFlags usage, uint32_t state) { + VkImageCreateInfo ci{VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO}; + ci.imageType = VK_IMAGE_TYPE_2D, ci.format = im.format, ci.extent = {im.width, im.height, 1}; + ci.mipLevels = 1, ci.arrayLayers = 1, ci.samples = VK_SAMPLE_COUNT_1_BIT, ci.tiling = VK_IMAGE_TILING_OPTIMAL; + ci.usage = usage, ci.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + return ffxApiGetResourceVK((void*)im.image, ffxApiGetImageResourceDescriptionVK(im.image, ci, 0), state); +} + +VkImageMemoryBarrier2 barrier(const DlssImage& im, VkAccessFlags2 src, VkAccessFlags2 dst, VkImageLayout from, VkImageLayout to) { + VkImageMemoryBarrier2 b{VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2}; + b.srcStageMask = b.dstStageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT; + b.srcAccessMask = src, b.dstAccessMask = dst, b.oldLayout = from, b.newLayout = to; + b.srcQueueFamilyIndex = b.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + b.image = im.image, b.subresourceRange = {im.aspect, 0, 1, 0, 1}; + return b; +} +void barriers(VkCommandBuffer cmd, const VkImageMemoryBarrier2* b, uint32_t n) { + VkDependencyInfo di{VK_STRUCTURE_TYPE_DEPENDENCY_INFO}; + di.imageMemoryBarrierCount = n, di.pImageMemoryBarriers = b; + vkCmdPipelineBarrier2(cmd, &di); +} + +} // namespace + +bool fsr4_available() { + if (!fsr.tried) start(); + return fsr.ok; +} +const char* fsr4_reason() { return fsr.reason; } + +bool fsr4_evaluate(VkCommandBuffer cmd, const DlssImage& color, const DlssImage& depth, const DlssImage& motion, + const DlssImage& output, float jitter_x, float jitter_y, bool reset) { + if (!fsr4_available()) return false; + if (!fsr.context || fsr.max_w != output.width || fsr.max_h != output.height) { + if (!make_context(output.width, output.height)) { + fsr.ok = false, fsr.reason = "FSR 4 did not start"; + return false; + } + reset = true; + } + if (color.width > fsr.max_w || color.height > fsr.max_h) return false; // (a render size past the output: not an upscale) + const auto now = std::chrono::steady_clock::now(); + const float frame_ms = fsr.evals ? std::chrono::duration(now - fsr.last).count() : 1000.0f / 30.0f; + fsr.last = now; + + constexpr VkImageLayout G = VK_IMAGE_LAYOUT_GENERAL, R = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + constexpr VkAccessFlags2 any = VK_ACCESS_2_MEMORY_READ_BIT | VK_ACCESS_2_MEMORY_WRITE_BIT; + const VkImageMemoryBarrier2 in[4] = {barrier(color, VK_ACCESS_2_MEMORY_WRITE_BIT, VK_ACCESS_2_SHADER_READ_BIT, G, R), + barrier(depth, VK_ACCESS_2_MEMORY_WRITE_BIT, VK_ACCESS_2_SHADER_READ_BIT, G, R), + barrier(motion, VK_ACCESS_2_MEMORY_WRITE_BIT, VK_ACCESS_2_SHADER_READ_BIT, G, R), + barrier(output, any, any, G, G)}; + barriers(cmd, in, 4); + + ffxDispatchDescUpscale d{}; + d.header.type = FFX_API_DISPATCH_DESC_TYPE_UPSCALE; + d.commandList = cmd; + d.color = resource(color, VK_IMAGE_USAGE_SAMPLED_BIT, FFX_API_RESOURCE_STATE_COMPUTE_READ); + d.depth = resource(depth, VK_IMAGE_USAGE_SAMPLED_BIT, FFX_API_RESOURCE_STATE_COMPUTE_READ); + d.motionVectors = resource(motion, VK_IMAGE_USAGE_SAMPLED_BIT, FFX_API_RESOURCE_STATE_COMPUTE_READ); + d.output = resource(output, VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, FFX_API_RESOURCE_STATE_UNORDERED_ACCESS); + d.jitterOffset = {jitter_x, jitter_y}; + d.motionVectorScale = {1.0f, 1.0f}; // (render pixels already, towards the previous frame) + d.renderSize = {color.width, color.height}; + d.upscaleSize = {output.width, output.height}; + d.enableSharpening = false; // (the Sharpness row sharpens at the window, after the HUD) + d.sharpness = 0.0f; + d.frameTimeDelta = frame_ms; + d.preExposure = 1.0f; + d.reset = reset; + // (the game hands no camera; FSR uses these only for its depth heuristics) + d.cameraNear = 0.1f, d.cameraFar = 1000.0f, d.cameraFovAngleVertical = 1.0f, d.viewSpaceToMetersFactor = 1.0f; + d.flags = FFX_UPSCALE_FLAG_NON_LINEAR_COLOR_SRGB; + const ffxReturnCode_t r = fsr.dispatch(&fsr.context, &d.header); + + const VkImageMemoryBarrier2 out[4] = {barrier(color, VK_ACCESS_2_SHADER_READ_BIT, any, R, G), + barrier(depth, VK_ACCESS_2_SHADER_READ_BIT, any, R, G), + barrier(motion, VK_ACCESS_2_SHADER_READ_BIT, any, R, G), + barrier(output, any, any, G, G)}; + barriers(cmd, out, 4); + if (r != FFX_API_RETURN_OK) { + logf("vk: fsr4: recording the upscale failed (%d): the game's upscale from now on", (int)r); + fsr.ok = false, fsr.reason = "FSR 4 failed"; + return false; + } + static int told = 0; // (the first evaluation, and the first resets: a camera cut each) + if (fsr.evals++ == 0 || (reset && told < 40)) + told++, logf("vk: fsr4: %ux%u -> %ux%u, jitter %.3f %.3f%s", color.width, color.height, output.width, output.height, jitter_x, + jitter_y, reset ? " (history reset)" : ""); + return true; +} + +void fsr4_stop() { + if (fsr.context) destroy_context(); +} + +} // namespace mkwvk diff --git a/gpu/vk/vk_fsr4.h b/gpu/vk/vk_fsr4.h new file mode 100644 index 000000000..9a96f2aaa --- /dev/null +++ b/gpu/vk/vk_fsr4.h @@ -0,0 +1,27 @@ +// AMD FSR 4.1 through the AMD FSR API (vk_fsr4.cpp), in place of the game's gameplay upscale, beside NVIDIA DLSS (vk_dlss.h): +// the same colour, depth and camera motion from vk_draw.cpp. Only the API's MIT headers are built in (third_party/fidelityfx); +// AMD's signed amd_fidelityfx_loader_vk.dll and amd_fidelityfx_upscaler_vk.dll are loaded from the user's PC at run time and +// none ship with Hookshot. Ported from madebyjordan's FSR 4.1 work on Lichii (vk_fsr4_upscaler.cpp), GPL-3.0-or-later. +#pragma once + +#include + +#include "vk_loader.h" +#include "vk_dlss.h" // (DlssImage: the images both upscalers take) + +namespace mkwvk { + +/// The loader DLL from RX_FSR4_DIR, else the executable's folder, else the game folder; an FSR 4.x upscaler for this device +/// among those it lists. Made at the first use (no instance or device extensions needed), once. True when there is one +bool fsr4_available(); +const char* fsr4_reason(); // (why not, short: the menu and the log) + +/// Records one FSR evaluation on cmd: color (perceptual, tonemapped: FSR's LDR mode), depth (standard, not inverted) and motion +/// (render pixels, towards the previous frame) at the render size, output (RGBA16F, STORAGE | SAMPLED) at the output size. All +/// in GENERAL before and after. jitter: the sub-pixel offset this frame's scene was drawn with, in render pixels. False when FSR +/// failed (then never again: fsr4_available() is false from then on) +bool fsr4_evaluate(VkCommandBuffer cmd, const DlssImage& color, const DlssImage& depth, const DlssImage& motion, + const DlssImage& output, float jitter_x, float jitter_y, bool reset); +void fsr4_stop(); // (before the device goes; safe when never started) + +} // namespace mkwvk diff --git a/gpu/vk/vk_menu.cpp b/gpu/vk/vk_menu.cpp index b15fac10b..092f105cd 100644 --- a/gpu/vk/vk_menu.cpp +++ b/gpu/vk/vk_menu.cpp @@ -15,6 +15,7 @@ #include "vk_paths.h" #include "vk_menu.h" #include "vk_dlss.h" +#include "vk_fsr4.h" #include "vk_work.h" // (after the others: counts the commands that do GPU work, for full_barrier) #ifndef HOOKSHOT_VERSION // (nx2/build.py gives it to this file: nx2/version.py) #define HOOKSHOT_VERSION "unknown" @@ -131,6 +132,12 @@ const char* tx_dlss_preset(int v) { snprintf(b, sizeof b, opts.dlss && dlss_available() ? "%c" : "%c (DLSS off)", 'J' + v); return b; } +const char* tx_fsr4(int v) { + if (!v) return "Off"; + if (opts.dlss && dlss_available()) return "On (DLSS is on)"; + const char* why = fsr4_reason(); // (read only: the replay thread loads AMD's DLLs at the first frame it is wanted) + return *why && strcmp(why, "not started") ? "On (no AMD FSR 4 found)" : "On"; +} const char* tx_ultrawide(int v) { return v ? "Monitor's shape (restart)" : "16:9 (restart)"; } int gpu_device_at_start = 0; // (the row's value the game started with: menu_set_gpu_count) const char* tx_gpu(int v) { @@ -218,6 +225,10 @@ Row rows[] = { "NVIDIA's DLSS model, changed at once. M: NVIDIA's pick for Performance, close to L's picture but nearer K's speed. L: its " "pick for Ultra Performance, sharper and steadier, less ghosting, slower. K: its pick for Quality, Balanced and DLAA. J: " "like K, slightly less ghosting, more flicker."}, + {TAB_GRAPHICS, "AMD FSR 4.1", &opts.fsr4, 0, 1, 1, tx_fsr4, + "AMD FSR 4.1 in place of the game's own upscale, with the scene's depth, the camera's motion and a sub-pixel jitter: steadier " + "edges, less shimmer. Resolution sets what it upscales from: 75% is FSR's Quality, 50% Performance, 100% anti-aliasing only. " + "Needs AMD's two FidelityFX DLLs beside the game. DLSS takes priority when on."}, {TAB_GRAPHICS, "Upscaling", &opts.upscale, 0, 2, 1, tx_upscale, "The filter that scales the picture to your window. Off is the plain copy. Catmull-Rom is sharper, Lanczos sharper still."}, {TAB_GRAPHICS, "Sharpness", &opts.sharpness, 0, 100, 10, tx_percent, @@ -313,7 +324,8 @@ std::string ini_path() { return dir.substr(0, dir.find_last_of("\\/") + 1) + "hookshot_options.ini"; } const char* ini_key(const Row& r) { - if (r.value == &opts.output_res) return "output_res"; // (host/nn_applet.c reads it at the start) + if (r.value == &opts.output_res) return "output_res"; + if (r.value == &opts.fsr4) return "fsr4"; // (host/nn_applet.c reads it at the start) static char k[32]; size_t n = 0; for (const char* p = r.name; *p && n + 1 < sizeof k; p++) k[n++] = *p == ' ' ? '_' : (char)tolower(*p); @@ -897,6 +909,7 @@ void menu_init() { if (const char* e = getenv("HOS_REALTIME_STEP")) opts.realtime = atoi(e) != 0; if (const char* e = getenv("HOS_DYNRES")) opts.resolution = atoi(e) != 0 ? 0 : 1; if (const char* e = getenv("RX_DLSS")) opts.dlss = atoi(e) != 0; + if (const char* e = getenv("RX_FSR4")) opts.fsr4 = atoi(e) != 0; if (const char* e = getenv("HOS_OUTPUT_RES")) opts.output_res = std::min(std::max(atoi(e), 0), 2); if (const char* e = getenv("RX_DLSS_PRESET"); e && e[0] >= 'J' && e[0] <= 'M') opts.dlss_preset = e[0] - 'J'; } diff --git a/gpu/vk/vk_menu.h b/gpu/vk/vk_menu.h index 6d2995b36..ccbdc7a86 100644 --- a/gpu/vk/vk_menu.h +++ b/gpu/vk/vk_menu.h @@ -34,6 +34,7 @@ struct Options { int dlss = 0; // the game's gameplay upscale through NVIDIA DLSS (vk_dlss.cpp); read once, at the start (RX_DLSS=0/1 over it) int dlss_mode = 3; // the render size with DLSS on: 0 Ultra Performance .. 3 Quality, 4 DLAA (dlss_render_size) int dlss_preset = 3; // DLSS's model: 0 J, 1 K, 2 L, 3 M; applies at once (RX_DLSS_PRESET=J..M over it) + int fsr4 = 0; // (hookshot-amd) the gameplay upscale through AMD FSR 4.1 (vk_fsr4.cpp) when DLSS is off; at once (RX_FSR4=0/1 over it) }; extern Options opts; /// (vk_memory.cpp) true when the quality preset's memory budgets (vram_mb, mirror_mb) are to be used: the card has no more diff --git a/nx2/build.py b/nx2/build.py index e95d9d972..309ad4ef4 100644 --- a/nx2/build.py +++ b/nx2/build.py @@ -712,7 +712,9 @@ def main(): "-I" + os.path.join(spirv_headers, "include"), "-I" + os.path.join(spirv_headers, "include", "spirv", "unified1"), # (third_party/streamline: NVIDIA Streamline's MIT headers, vk_dlss.cpp's) "-I" + os.path.join(vk_headers, "include"), "-I" + vk, - "-I" + os.path.join(kit.HERE, "..", "third_party", "streamline", "include")] + (["-I" + os.path.join(cpm_package("vulkanmemoryallocator"), "include")] if cpm_package("vulkanmemoryallocator") else []) + "-I" + os.path.join(kit.HERE, "..", "third_party", "streamline", "include"), + # (third_party/fidelityfx: AMD's FSR API headers, MIT, vk_fsr4.cpp's) + "-I" + os.path.join(kit.HERE, "..", "third_party", "fidelityfx")] + (["-I" + os.path.join(cpm_package("vulkanmemoryallocator"), "include")] if cpm_package("vulkanmemoryallocator") else []) # (Eden's recompiler and sirit see only their own headers: a change to the back end's vk_*.h does not # rebuild their ~500 files; the back end itself depends on everything, suyu's texture decoders included) vk_lib_deps = tree_headers(os.path.join(vk, "eden"), os.path.join(vk, "sirit"), os.path.join(vk, "compat"), diff --git a/readme.md b/readme.md index 3d4adfe47..abb1f6641 100644 --- a/readme.md +++ b/readme.md @@ -192,6 +192,7 @@ and the right one closes the menu. Your choices are saved in `hookshot_options.i | | DLSS | Off, On (after a restart) | Off | | | DLSS mode | Ultra Performance, Performance, Balanced, Quality, DLAA | Quality | | | DLSS preset | J, K, L, M | M | +| | AMD FSR 4.1 | Off, On | Off | | | Upscaling | Off, Catmull-Rom, Lanczos | Off | | | Sharpness | 0 to 100%, in steps of 10 | 0% | | | Handheld profile | Off, On (after a restart) | Off | @@ -245,6 +246,19 @@ so and the game runs as before. **DLSS preset** picks NVIDIA's model and changes For one run: `RX_DLSS=0/1`, `RX_DLSS_PRESET=J..M`, `RX_DLSS_DIR=`, `HOS_OUTPUT_RES=0/1/2`. +### AMD FSR 4.1 + +FSR 4.1 is optional. It replaces the game's own upscale the same way, from the scene's depth and the camera's motion, +and moves the 3D by a sub-pixel amount each frame (a jitter) so it can rebuild edges and fine detail over several +frames. It runs on AMD's RDNA 2 cards and newer (RDNA 2 and 3 use its INT8 model). **Resolution** sets the size it +upscales from: 75% is FSR's Quality, 67% Balanced, 50% Performance, 100% anti-aliasing only. Hookshot does not include +AMD's files: put `amd_fidelityfx_loader_vk.dll` and `amd_fidelityfx_upscaler_vk.dll` from the +[FidelityFX SDK](https://github.com/GPUOpen-LibrariesAndSDKs/FidelityFX-SDK) 2.4 release (`Kits/FidelityFX/signedbin`) +beside the game's exe (`bin\hookshot.exe` with the launcher). Without them the row says so and the game runs as +before. The row changes at once; DLSS takes priority while it is on. + +For one run: `RX_FSR4=0/1`, `RX_FSR4_DIR=`, `RX_FSR4_JITTER=0` (no jitter, for comparisons). + ### Controls Use a controller, or the keyboard and mouse. On the keyboard, W A S D move @@ -420,6 +434,7 @@ Hookshot exists thanks to the work of many people: (trees, ferns, grass, falling leaves, fireflies), the ambient light probes, the pond's water, the game's own fog, the freeze after Load (Horizon's mutex handoff) and the exposure flicker fix. - **[zortos293/Lichii](https://github.com/zortos293/Lichii)**: reference for Ampere shader lowering, and its compare-exchange retry fix; the NVIDIA DLSS replacement of the game's upscale (Streamline loader, camera motion and its shaders), ported in `gpu/vk/vk_dlss.cpp` and `gpu/vk/vk_draw.cpp`, which Lichii credits to Duck912's work in Eglantine. NVIDIA Streamline's headers (MIT) are in `third_party/streamline`; NVIDIA's DLLs are not part of Hookshot. +- **[madebyjordan/Lichii-Hyrule](https://github.com/madebyjordan/Lichii-Hyrule)** (Lichii's OoT branch): AMD FSR 4.1 in place of the game's upscale, its jitter and the AMD edge fixes, ported in `gpu/vk/vk_fsr4.cpp` and `gpu/vk/vk_draw.cpp`. AMD's FSR API headers (MIT) are in `third_party/fidelityfx`; AMD's DLLs are not part of Hookshot. - **[mstorsjo/llvm-mingw](https://github.com/mstorsjo/llvm-mingw)**: the bundled Windows compiler (no Visual Studio needed). - **[kinnay/zbic](https://github.com/kinnay/zbic)**, **Opus** and **SDL**: decompression, audio and controllers. - **[sostenesfreitas/ocarina-recomp](https://github.com/sostenesfreitas/ocarina-recomp)**: this README's layout, and its notes diff --git a/tests/test_fsr_jitter.py b/tests/test_fsr_jitter.py new file mode 100644 index 000000000..c65a1bdb9 --- /dev/null +++ b/tests/test_fsr_jitter.py @@ -0,0 +1,79 @@ +"""AMD FSR 4.1's jitter (gpu/vk/vk_draw.cpp): Halton (2, 3) offsets in [-0.5, 0.5), part of the state a draw is compared by, moved +on only at the network's pass, and the AMD edge repeat in the colour and motion passes. + +python -I -B tests/test_fsr_jitter.py [--cxx g++] +""" +import argparse +import subprocess +import tempfile +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[1] + + +def block(text, marker): + start = text.index(marker) + end = text.index("{", start) + 1 + depth = 1 + while depth: + depth += (text[end] == "{") - (text[end] == "}") + end += 1 + return text[start:end] + + +def main(): + p = argparse.ArgumentParser(description=__doc__) + p.add_argument("--cxx", default="g++") + a = p.parse_args() + source = (ROOT / "gpu" / "vk" / "vk_draw.cpp").read_text(encoding="utf-8") + pack = block(source, "int dyn_pack(") + # (a frame whose draws match the last frame's would keep its jitter if the offset were not compared) + if "fsr_jitter_for(at, fp[13], fp[14])" not in pack: + raise SystemExit("dyn_pack leaves FSR's jitter out of the state a draw is compared by") + if "constexpr int kDynF = 15" not in source: + raise SystemExit("the compared floats do not hold FSR's jitter (fp[13], fp[14])") + dyn = block(source, "void dynamic_state(") + if "d.vp.x += df[13], d.vp.y += df[14]" not in dyn: + raise SystemExit("the viewport is not moved by the jitter dyn_pack compared") + dispatch = block(source, "bool dlss_dispatch(VkCommandBuffer cmd, const NvnState& s, const Program& p) {") + if "fsr_frame_end(drew, rw, ow)" not in dispatch or "fj.used ? fj.x : 0.0f" not in dispatch: + raise SystemExit("the jitter does not move on at the network's pass, or FSR is told an offset no draw had") + jitter_for = block(source, "bool fsr_jitter_for(const Targets& at, float& jx, float& jy) {") + for need in ("fj.live", "par_active", "ds.cam.w", "fj.net_present"): + if need not in jitter_for: + raise SystemExit(f"fsr_jitter_for moves draws without checking {need}") + shaders = ROOT / "gpu" / "vk" / "shaders" + if "imageSize(dlss_color) - 2" not in (shaders / "dlss_color.comp").read_text(encoding="utf-8"): + raise SystemExit("FSR's colour does not repeat the column and row before the last (AMD's edge line)") + if "extent - 2" not in (shaders / "dlss_motion.comp").read_text(encoding="utf-8"): + raise SystemExit("the motion's depth does not repeat the column and row before the last (AMD's edge line)") + fn = block(source, "float halton(") + fixture = r'''#include +#include +#include +#include +#define CHECK(x) do { if (!(x)) { std::fprintf(stderr, "FAIL:%d %s\n", __LINE__, #x); std::exit(1); } } while (0) +''' + fn + r''' +int main() { + CHECK(halton(1, 2) == 0.5f && halton(2, 2) == 0.25f && halton(3, 2) == 0.75f); + CHECK(std::fabs(halton(1, 3) - 1.0f / 3) < 1e-6f && std::fabs(halton(2, 3) - 2.0f / 3) < 1e-6f); + float sx = 0, sy = 0; + for (uint32_t i = 1; i <= 16; i++) { // (the 16 phases of a 75% render: each offset in [-0.5, 0.5), centred overall) + const float x = halton(i, 2) - 0.5f, y = halton(i, 3) - 0.5f; + CHECK(x >= -0.5f && x < 0.5f && y >= -0.5f && y < 0.5f); + sx += x, sy += y; + } + CHECK(std::fabs(sx / 16) < 0.05f && std::fabs(sy / 16) < 0.05f); + std::printf("PASS: FSR's jitter is compared, moved on at the network's pass, and balanced\n"); +} +''' + with tempfile.TemporaryDirectory(prefix="fsr-jitter-") as tmp: + cpp = Path(tmp) / "fixture.cpp" + exe = Path(tmp) / "fixture" + cpp.write_text(fixture, encoding="utf-8") + subprocess.run([a.cxx, "-std=c++20", "-Wall", "-Wextra", "-Werror", str(cpp), "-o", str(exe)], check=True) + subprocess.run([str(exe)], check=True) + + +if __name__ == "__main__": + main() diff --git a/third_party/fidelityfx/LICENSE.md b/third_party/fidelityfx/LICENSE.md new file mode 100644 index 000000000..aef7adddb --- /dev/null +++ b/third_party/fidelityfx/LICENSE.md @@ -0,0 +1,992 @@ +The following license applies to all files except as noted below. + +Copyright (C)  Advanced Micro Devices, Inc. All rights reserved. + +REDISTRIBUTION: Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to install, reproduce, copy and distribute copies of the Software, in binary form only, and to permit persons to whom the Software is provided to do the same, provided that the following conditions are met: + +No reverse engineering, decompilation, or disassembly of this Software is permitted. + +Redistributions must reproduce the above copyright notice, this permission notice, and the following disclaimers and notices in the Software documentation and/or other materials provided with the Software. + +DISCLAIMER: THE USE OF THE SOFTWARE IS AT YOUR SOLE RISK.  THE SOFTWARE +IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND AND COPYRIGHT +HOLDER AND ITS LICENSORS EXPRESSLY DISCLAIM ALL WARRANTIES, EXPRESS AND +IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +COPYRIGHT HOLDER AND ITS LICENSORS DO NOT WARRANT THAT THE SOFTWARE WILL +MEET YOUR REQUIREMENTS, OR THAT THE OPERATION OF THE SOFTWARE WILL BE +UNINTERRUPTED OR ERROR-FREE.  THE ENTIRE RISK ASSOCIATED WITH THE USE OF +THE SOFTWARE IS ASSUMED BY YOU.  FURTHERMORE, COPYRIGHT HOLDER AND ITS +LICENSORS DO NOT WARRANT OR MAKE ANY REPRESENTATIONS REGARDING THE USE +OR THE RESULTS OF THE USE OF THE SOFTWARE IN TERMS OF ITS CORRECTNESS, +ACCURACY, RELIABILITY, CURRENTNESS, OR OTHERWISE. + +DISCLAIMER: UNDER NO CIRCUMSTANCES INCLUDING NEGLIGENCE, SHALL COPYRIGHT HOLDER AND ITS LICENSORS OR ITS DIRECTORS, OFFICERS, EMPLOYEES OR AGENTS ("AUTHORIZED REPRESENTATIVES") BE LIABLE FOR ANY INCIDENTAL, INDIRECT, +SPECIAL OR CONSEQUENTIAL DAMAGES (INCLUDING DAMAGES FOR LOSS OF BUSINESS +PROFITS, BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, AND THE +LIKE) ARISING OUT OF THE USE, MISUSE OR INABILITY TO USE THE SOFTWARE, +BREACH OR DEFAULT, INCLUDING THOSE ARISING FROM INFRINGEMENT OR ALLEGED +INFRINGEMENT OF ANY PATENT, TRADEMARK, COPYRIGHT OR OTHER INTELLECTUAL +PROPERTY RIGHT EVEN IF COPYRIGHT HOLDER AND ITS AUTHORIZED +REPRESENTATIVES HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.  IN +NO EVENT SHALL COPYRIGHT HOLDER OR ITS AUTHORIZED REPRESENTATIVES TOTAL +LIABILITY FOR ALL DAMAGES, LOSSES, AND CAUSES OF ACTION (WHETHER IN +CONTRACT, TORT (INCLUDING NEGLIGENCE) OR OTHERWISE) EXCEED THE AMOUNT OF +US$10. + +These source files + +- `3rdpartynotice.md` +- `ClearMediaCache.bat` +- `docs\getting-started\building-samples.md` +- `docs\getting-started\index.md` +- `docs\getting-started\media\component-dependencies-dark.png` +- `docs\getting-started\media\component-dependencies.png` +- `docs\getting-started\media\config_init.jpg` +- `docs\getting-started\media\lighting-ui.jpg` +- `docs\getting-started\media\limiter-ui.jpg` +- `docs\getting-started\media\magnifier-ui.jpg` +- `docs\getting-started\media\particle-ui.jpg` +- `docs\getting-started\media\postprocessing-ui.jpg` +- `docs\getting-started\media\shadowraster-ui.jpg` +- `docs\getting-started\media\skydome-ui.jpg` +- `docs\getting-started\media\taa-ui.jpg` +- `docs\getting-started\running-samples.md` +- `docs\getting-started\sdk-structure.md` +- `docs\license.md` +- `docs\media\AMD_FidelityFX_Lockup_Black.png` +- `docs\media\AMD_FidelityFX_SDK_Colored.jpg` +- `docs\media\fidelityfxsdk-logo-rescaled.png` +- `docs\samples\denoiser.md` +- `docs\samples\index.md` +- `docs\samples\media\blur\blur.jpg` +- `docs\samples\media\blur\blur.png` +- `docs\samples\media\brixelizergi\sample.png` +- `docs\samples\media\contrast-adaptive-sharpening\cas-sample.png` +- `docs\samples\media\denoiser\fsr-ray-regeneration-sample.png` +- `docs\samples\media\hybrid-reflections\hybrid-reflections.jpg` +- `docs\samples\media\hybrid-reflections\hybrid-reflections.png` +- `docs\samples\media\hybrid-shadows\hybrid-shadows-sample.jpg` +- `docs\samples\media\hybrid-shadows\hybrid-shadows-sample.png` +- `docs\samples\media\lens\lens-sample_resized.jpg` +- `docs\samples\media\lens\lens-sample.jpg` +- `docs\samples\media\luma-preserving-mapper\LPM.jpg` +- `docs\samples\media\luma-preserving-mapper\LPM.png` +- `docs\samples\media\luma-preserving-mapper\NoLPM.jpg` +- `docs\samples\media\luma-preserving-mapper\NoLPM.png` +- `docs\samples\media\parallel-sort\parallel-sort_resized.jpg` +- `docs\samples\media\parallel-sort\parallel-sort.jpg` +- `docs\samples\media\radiance-caching\nrc-preview-sample.png` +- `docs\samples\media\single-pass-downsampler\spd-sample.jpg` +- `docs\samples\media\stochastic-screen-space-reflections\sssr-sample_resized.jpg` +- `docs\samples\media\stochastic-screen-space-reflections\sssr-sample.jpg` +- `docs\samples\media\super-resolution\frame-interpolation-debug-overlay.svg` +- `docs\samples\media\super-resolution\fsr3-sample_resized.jpg` +- `docs\samples\media\super-resolution\fsr3-sample.jpg` +- `docs\samples\media\super-resolution\upscaler-debug-overlay.svg` +- `docs\samples\media\variable-shading\variable-shading.jpg` +- `docs\samples\media\variable-shading\variable-shading.png` +- `docs\samples\radiance-cache.md` +- `docs\samples\super-resolution.md` +- `docs\sdk.css` +- `docs\tools\index.md` +- `docs\tools\media-delivery.md` +- `Kits\Cauldron2\dx12\Cauldron_vs2022.vcxproj` +- `Kits\Cauldron2\dx12\Cauldron_vs2022.vcxproj.filters` +- `Kits\Cauldron2\dx12\vcpkg.json` +- `Kits\Cauldron2\framework\config\cauldronconfig.json` +- `Kits\Cauldron2\framework\core\backend_interface.h` +- `Kits\Cauldron2\framework\core\component.cpp` +- `Kits\Cauldron2\framework\core\component.h` +- `Kits\Cauldron2\framework\core\components\animationcomponent.cpp` +- `Kits\Cauldron2\framework\core\components\animationcomponent.h` +- `Kits\Cauldron2\framework\core\components\cameracomponent.cpp` +- `Kits\Cauldron2\framework\core\components\cameracomponent.h` +- `Kits\Cauldron2\framework\core\components\lightcomponent.cpp` +- `Kits\Cauldron2\framework\core\components\lightcomponent.h` +- `Kits\Cauldron2\framework\core\components\meshcomponent.cpp` +- `Kits\Cauldron2\framework\core\components\meshcomponent.h` +- `Kits\Cauldron2\framework\core\components\particlespawnercomponent.cpp` +- `Kits\Cauldron2\framework\core\components\particlespawnercomponent.h` +- `Kits\Cauldron2\framework\core\contentloader.h` +- `Kits\Cauldron2\framework\core\contentmanager.cpp` +- `Kits\Cauldron2\framework\core\contentmanager.h` +- `Kits\Cauldron2\framework\core\entity.cpp` +- `Kits\Cauldron2\framework\core\entity.h` +- `Kits\Cauldron2\framework\core\framework.cpp` +- `Kits\Cauldron2\framework\core\framework.h` +- `Kits\Cauldron2\framework\core\inputmanager.cpp` +- `Kits\Cauldron2\framework\core\inputmanager.h` +- `Kits\Cauldron2\framework\core\loaders\gltfloader.cpp` +- `Kits\Cauldron2\framework\core\loaders\gltfloader.h` +- `Kits\Cauldron2\framework\core\loaders\particleloader.cpp` +- `Kits\Cauldron2\framework\core\loaders\particleloader.h` +- `Kits\Cauldron2\framework\core\loaders\textureloader.cpp` +- `Kits\Cauldron2\framework\core\loaders\textureloader.h` +- `Kits\Cauldron2\framework\core\scene.cpp` +- `Kits\Cauldron2\framework\core\scene.h` +- `Kits\Cauldron2\framework\core\taskmanager.cpp` +- `Kits\Cauldron2\framework\core\taskmanager.h` +- `Kits\Cauldron2\framework\core\uibackend.cpp` +- `Kits\Cauldron2\framework\core\uibackend.h` +- `Kits\Cauldron2\framework\core\uimanager.cpp` +- `Kits\Cauldron2\framework\core\uimanager.h` +- `Kits\Cauldron2\framework\core\win\framework_win.cpp` +- `Kits\Cauldron2\framework\core\win\framework_win.h` +- `Kits\Cauldron2\framework\core\win\inputmanager_win.cpp` +- `Kits\Cauldron2\framework\core\win\inputmanager_win.h` +- `Kits\Cauldron2\framework\core\win\uibackend_win.cpp` +- `Kits\Cauldron2\framework\core\win\uibackend_win.h` +- `Kits\Cauldron2\framework\misc\assert.h` +- `Kits\Cauldron2\framework\misc\corecounts.cpp` +- `Kits\Cauldron2\framework\misc\corecounts.h` +- `Kits\Cauldron2\framework\misc\fileio.cpp` +- `Kits\Cauldron2\framework\misc\fileio.h` +- `Kits\Cauldron2\framework\misc\helpers.h` +- `Kits\Cauldron2\framework\misc\log.cpp` +- `Kits\Cauldron2\framework\misc\log.h` +- `Kits\Cauldron2\framework\misc\math.cpp` +- `Kits\Cauldron2\framework\misc\math.h` +- `Kits\Cauldron2\framework\misc\sync.h` +- `Kits\Cauldron2\framework\misc\threadsafe_queue.h` +- `Kits\Cauldron2\framework\misc\threadsafe_ringbuffer.h` +- `Kits\Cauldron2\framework\render\animation.cpp` +- `Kits\Cauldron2\framework\render\animation.h` +- `Kits\Cauldron2\framework\render\backend_shader_reloader\backend_shader_reloader_common.cpp` +- `Kits\Cauldron2\framework\render\backend_shader_reloader\backend_shader_reloader_common.h` +- `Kits\Cauldron2\framework\render\backend_shader_reloader\backend_shader_reloader.cpp` +- `Kits\Cauldron2\framework\render\backend_shader_reloader\backend_shader_reloader.h` +- `Kits\Cauldron2\framework\render\backend_shader_reloader\CMakeLists.txt` +- `Kits\Cauldron2\framework\render\backend_shader_reloader\command_execution.cpp` +- `Kits\Cauldron2\framework\render\backend_shader_reloader\command_execution.h` +- `Kits\Cauldron2\framework\render\backend_shader_reloader\native_backend_shader_reloader.cpp` +- `Kits\Cauldron2\framework\render\backend_shader_reloader\native_backend_shader_reloader.h` +- `Kits\Cauldron2\framework\render\buffer.cpp` +- `Kits\Cauldron2\framework\render\buffer.h` +- `Kits\Cauldron2\framework\render\color_conversion.cpp` +- `Kits\Cauldron2\framework\render\color_conversion.h` +- `Kits\Cauldron2\framework\render\commandlist.cpp` +- `Kits\Cauldron2\framework\render\commandlist.h` +- `Kits\Cauldron2\framework\render\copyresource.cpp` +- `Kits\Cauldron2\framework\render\copyresource.h` +- `Kits\Cauldron2\framework\render\device.cpp` +- `Kits\Cauldron2\framework\render\device.h` +- `Kits\Cauldron2\framework\render\dx12\buffer_dx12.cpp` +- `Kits\Cauldron2\framework\render\dx12\buffer_dx12.h` +- `Kits\Cauldron2\framework\render\dx12\commandlist_dx12.cpp` +- `Kits\Cauldron2\framework\render\dx12\commandlist_dx12.h` +- `Kits\Cauldron2\framework\render\dx12\copyresource_dx12.cpp` +- `Kits\Cauldron2\framework\render\dx12\copyresource_dx12.h` +- `Kits\Cauldron2\framework\render\dx12\defines_dx12.h` +- `Kits\Cauldron2\framework\render\dx12\device_dx12.cpp` +- `Kits\Cauldron2\framework\render\dx12\device_dx12.h` +- `Kits\Cauldron2\framework\render\dx12\dynamicbufferpool_dx12.cpp` +- `Kits\Cauldron2\framework\render\dx12\dynamicbufferpool_dx12.h` +- `Kits\Cauldron2\framework\render\dx12\gpuresource_dx12.cpp` +- `Kits\Cauldron2\framework\render\dx12\gpuresource_dx12.h` +- `Kits\Cauldron2\framework\render\dx12\indirectworkload_dx12.cpp` +- `Kits\Cauldron2\framework\render\dx12\indirectworkload_dx12.h` +- `Kits\Cauldron2\framework\render\dx12\parameterset_dx12.cpp` +- `Kits\Cauldron2\framework\render\dx12\parameterset_dx12.h` +- `Kits\Cauldron2\framework\render\dx12\pipelinedesc_dx12.cpp` +- `Kits\Cauldron2\framework\render\dx12\pipelinedesc_dx12.h` +- `Kits\Cauldron2\framework\render\dx12\pipelineobject_dx12.cpp` +- `Kits\Cauldron2\framework\render\dx12\pipelineobject_dx12.h` +- `Kits\Cauldron2\framework\render\dx12\profiler_dx12.cpp` +- `Kits\Cauldron2\framework\render\dx12\profiler_dx12.h` +- `Kits\Cauldron2\framework\render\dx12\resourceview_dx12.cpp` +- `Kits\Cauldron2\framework\render\dx12\resourceview_dx12.h` +- `Kits\Cauldron2\framework\render\dx12\resourceviewallocator_dx12.cpp` +- `Kits\Cauldron2\framework\render\dx12\resourceviewallocator_dx12.h` +- `Kits\Cauldron2\framework\render\dx12\rootsignature_dx12.cpp` +- `Kits\Cauldron2\framework\render\dx12\rootsignature_dx12.h` +- `Kits\Cauldron2\framework\render\dx12\rootsignaturedesc_dx12.cpp` +- `Kits\Cauldron2\framework\render\dx12\rootsignaturedesc_dx12.h` +- `Kits\Cauldron2\framework\render\dx12\rtresources_dx12.cpp` +- `Kits\Cauldron2\framework\render\dx12\rtresources_dx12.h` +- `Kits\Cauldron2\framework\render\dx12\sampler_dx12.cpp` +- `Kits\Cauldron2\framework\render\dx12\sampler_dx12.h` +- `Kits\Cauldron2\framework\render\dx12\swapchain_dx12.cpp` +- `Kits\Cauldron2\framework\render\dx12\swapchain_dx12.h` +- `Kits\Cauldron2\framework\render\dx12\texture_dx12.cpp` +- `Kits\Cauldron2\framework\render\dx12\texture_dx12.h` +- `Kits\Cauldron2\framework\render\dx12\uploadheap_dx12.cpp` +- `Kits\Cauldron2\framework\render\dx12\uploadheap_dx12.h` +- `Kits\Cauldron2\framework\render\dynamicbufferpool.cpp` +- `Kits\Cauldron2\framework\render\dynamicbufferpool.h` +- `Kits\Cauldron2\framework\render\dynamicresourcepool.cpp` +- `Kits\Cauldron2\framework\render\dynamicresourcepool.h` +- `Kits\Cauldron2\framework\render\gpuresource.cpp` +- `Kits\Cauldron2\framework\render\gpuresource.h` +- `Kits\Cauldron2\framework\render\indirectworkload.h` +- `Kits\Cauldron2\framework\render\material.cpp` +- `Kits\Cauldron2\framework\render\material.h` +- `Kits\Cauldron2\framework\render\mesh.cpp` +- `Kits\Cauldron2\framework\render\mesh.h` +- `Kits\Cauldron2\framework\render\parameterset.cpp` +- `Kits\Cauldron2\framework\render\parameterset.h` +- `Kits\Cauldron2\framework\render\particle.cpp` +- `Kits\Cauldron2\framework\render\particle.h` +- `Kits\Cauldron2\framework\render\pipelinedesc.cpp` +- `Kits\Cauldron2\framework\render\pipelinedesc.h` +- `Kits\Cauldron2\framework\render\pipelineobject.h` +- `Kits\Cauldron2\framework\render\profiler.cpp` +- `Kits\Cauldron2\framework\render\profiler.h` +- `Kits\Cauldron2\framework\render\rasterview.cpp` +- `Kits\Cauldron2\framework\render\rasterview.h` +- `Kits\Cauldron2\framework\render\renderdefines.h` +- `Kits\Cauldron2\framework\render\rendermodule.cpp` +- `Kits\Cauldron2\framework\render\rendermodule.h` +- `Kits\Cauldron2\framework\render\rendermodules\fpslimiter\fpslimiterrendermodule.cpp` +- `Kits\Cauldron2\framework\render\rendermodules\fpslimiter\fpslimiterrendermodule.h` +- `Kits\Cauldron2\framework\render\rendermodules\raytracing\raytracingrendermodule.cpp` +- `Kits\Cauldron2\framework\render\rendermodules\raytracing\raytracingrendermodule.h` +- `Kits\Cauldron2\framework\render\rendermodules\rsr\runtimeshaderrecompilerrendermodule.cpp` +- `Kits\Cauldron2\framework\render\rendermodules\rsr\runtimeshaderrecompilerrendermodule.h` +- `Kits\Cauldron2\framework\render\rendermodules\skinning\skinningrendermodule.cpp` +- `Kits\Cauldron2\framework\render\rendermodules\skinning\skinningrendermodule.h` +- `Kits\Cauldron2\framework\render\rendermodules\swapchain\swapchainrendermodule.cpp` +- `Kits\Cauldron2\framework\render\rendermodules\swapchain\swapchainrendermodule.h` +- `Kits\Cauldron2\framework\render\rendermodules\tonemapping\tonemappingrendermodule.cpp` +- `Kits\Cauldron2\framework\render\rendermodules\tonemapping\tonemappingrendermodule.h` +- `Kits\Cauldron2\framework\render\rendermodules\ui\uirendermodule.cpp` +- `Kits\Cauldron2\framework\render\rendermodules\ui\uirendermodule.h` +- `Kits\Cauldron2\framework\render\resourceresizedlistener.cpp` +- `Kits\Cauldron2\framework\render\resourceresizedlistener.h` +- `Kits\Cauldron2\framework\render\resourceview.cpp` +- `Kits\Cauldron2\framework\render\resourceview.h` +- `Kits\Cauldron2\framework\render\resourceviewallocator.cpp` +- `Kits\Cauldron2\framework\render\resourceviewallocator.h` +- `Kits\Cauldron2\framework\render\rootsignature.h` +- `Kits\Cauldron2\framework\render\rootsignaturedesc.cpp` +- `Kits\Cauldron2\framework\render\rootsignaturedesc.h` +- `Kits\Cauldron2\framework\render\rtresources.h` +- `Kits\Cauldron2\framework\render\sampler.h` +- `Kits\Cauldron2\framework\render\shaderbuilder.h` +- `Kits\Cauldron2\framework\render\shaderbuilderhelper.cpp` +- `Kits\Cauldron2\framework\render\shaderbuilderhelper.h` +- `Kits\Cauldron2\framework\render\shadowmapresourcepool.cpp` +- `Kits\Cauldron2\framework\render\shadowmapresourcepool.h` +- `Kits\Cauldron2\framework\render\swapchain.cpp` +- `Kits\Cauldron2\framework\render\swapchain.h` +- `Kits\Cauldron2\framework\render\texture.cpp` +- `Kits\Cauldron2\framework\render\texture.h` +- `Kits\Cauldron2\framework\render\uploadheap.cpp` +- `Kits\Cauldron2\framework\render\uploadheap.h` +- `Kits\Cauldron2\framework\render\vk\buffer_vk.cpp` +- `Kits\Cauldron2\framework\render\vk\buffer_vk.h` +- `Kits\Cauldron2\framework\render\vk\commandlist_vk.cpp` +- `Kits\Cauldron2\framework\render\vk\commandlist_vk.h` +- `Kits\Cauldron2\framework\render\vk\copyresource_vk.cpp` +- `Kits\Cauldron2\framework\render\vk\copyresource_vk.h` +- `Kits\Cauldron2\framework\render\vk\device_vk.cpp` +- `Kits\Cauldron2\framework\render\vk\device_vk.h` +- `Kits\Cauldron2\framework\render\vk\dynamicbufferpool_vk.cpp` +- `Kits\Cauldron2\framework\render\vk\dynamicbufferpool_vk.h` +- `Kits\Cauldron2\framework\render\vk\gpuresource_vk.cpp` +- `Kits\Cauldron2\framework\render\vk\gpuresource_vk.h` +- `Kits\Cauldron2\framework\render\vk\helpers.cpp` +- `Kits\Cauldron2\framework\render\vk\helpers.h` +- `Kits\Cauldron2\framework\render\vk\indirectworkload_vk.cpp` +- `Kits\Cauldron2\framework\render\vk\indirectworkload_vk.h` +- `Kits\Cauldron2\framework\render\vk\parameterset_vk.cpp` +- `Kits\Cauldron2\framework\render\vk\parameterset_vk.h` +- `Kits\Cauldron2\framework\render\vk\pipelinedesc_vk.cpp` +- `Kits\Cauldron2\framework\render\vk\pipelinedesc_vk.h` +- `Kits\Cauldron2\framework\render\vk\pipelineobject_vk.cpp` +- `Kits\Cauldron2\framework\render\vk\pipelineobject_vk.h` +- `Kits\Cauldron2\framework\render\vk\profiler_vk.cpp` +- `Kits\Cauldron2\framework\render\vk\profiler_vk.h` +- `Kits\Cauldron2\framework\render\vk\resourceview_vk.cpp` +- `Kits\Cauldron2\framework\render\vk\resourceview_vk.h` +- `Kits\Cauldron2\framework\render\vk\resourceviewallocator_vk.cpp` +- `Kits\Cauldron2\framework\render\vk\resourceviewallocator_vk.h` +- `Kits\Cauldron2\framework\render\vk\rootsignature_vk.cpp` +- `Kits\Cauldron2\framework\render\vk\rootsignature_vk.h` +- `Kits\Cauldron2\framework\render\vk\rootsignaturedesc_vk.cpp` +- `Kits\Cauldron2\framework\render\vk\rootsignaturedesc_vk.h` +- `Kits\Cauldron2\framework\render\vk\rtresources_vk.cpp` +- `Kits\Cauldron2\framework\render\vk\rtresources_vk.h` +- `Kits\Cauldron2\framework\render\vk\sampler_vk.cpp` +- `Kits\Cauldron2\framework\render\vk\sampler_vk.h` +- `Kits\Cauldron2\framework\render\vk\swapchain_vk.cpp` +- `Kits\Cauldron2\framework\render\vk\swapchain_vk.h` +- `Kits\Cauldron2\framework\render\vk\texture_vk.cpp` +- `Kits\Cauldron2\framework\render\vk\texture_vk.h` +- `Kits\Cauldron2\framework\render\vk\uploadheap_vk.cpp` +- `Kits\Cauldron2\framework\render\vk\uploadheap_vk.h` +- `Kits\Cauldron2\framework\render\win\shaderbuilder_win.cpp` +- `Kits\Cauldron2\framework\shaders\autoexposure.hlsl` +- `Kits\Cauldron2\framework\shaders\builddistortionfield.hlsl` +- `Kits\Cauldron2\framework\shaders\commonintersect.hlsl` +- `Kits\Cauldron2\framework\shaders\computeskinning.hlsl` +- `Kits\Cauldron2\framework\shaders\copytexture.hlsl` +- `Kits\Cauldron2\framework\shaders\fidelityfx\ffx_common_types.h` +- `Kits\Cauldron2\framework\shaders\fidelityfx\ffx_core_cpu.h` +- `Kits\Cauldron2\framework\shaders\fidelityfx\ffx_core_gpu_common_half.h` +- `Kits\Cauldron2\framework\shaders\fidelityfx\ffx_core_gpu_common.h` +- `Kits\Cauldron2\framework\shaders\fidelityfx\ffx_core_hlsl.h` +- `Kits\Cauldron2\framework\shaders\fidelityfx\ffx_core_portability.h` +- `Kits\Cauldron2\framework\shaders\fidelityfx\ffx_core.h` +- `Kits\Cauldron2\framework\shaders\fidelityfx\parallelsort\ffx_parallelsort_common.h` +- `Kits\Cauldron2\framework\shaders\fidelityfx\parallelsort\ffx_parallelsort.h` +- `Kits\Cauldron2\framework\shaders\fidelityfx\spd\ffx_spd.h` +- `Kits\Cauldron2\framework\shaders\fpslimiter.hlsl` +- `Kits\Cauldron2\framework\shaders\fullscreen.hlsl` +- `Kits\Cauldron2\framework\shaders\hudlessblit.hlsl` +- `Kits\Cauldron2\framework\shaders\lensdistortion.h` +- `Kits\Cauldron2\framework\shaders\lightfunctionscommon.hlsl` +- `Kits\Cauldron2\framework\shaders\lightingcommon.h` +- `Kits\Cauldron2\framework\shaders\particlecommon.h` +- `Kits\Cauldron2\framework\shaders\rasterlightfunctions.hlsl` +- `Kits\Cauldron2\framework\shaders\raytracingcommon.hlsl` +- `Kits\Cauldron2\framework\shaders\raytracinglightfunctions.hlsl` +- `Kits\Cauldron2\framework\shaders\shadercommon.h` +- `Kits\Cauldron2\framework\shaders\shadowFiltering.h` +- `Kits\Cauldron2\framework\shaders\surfacerendercommon.h` +- `Kits\Cauldron2\framework\shaders\tonemappercommon.h` +- `Kits\Cauldron2\framework\shaders\tonemappers.hlsl` +- `Kits\Cauldron2\framework\shaders\tonemapping.hlsl` +- `Kits\Cauldron2\framework\shaders\transferFunction.h` +- `Kits\Cauldron2\framework\shaders\transformVS.hlsl` +- `Kits\Cauldron2\framework\shaders\ui.hlsl` +- `Kits\Cauldron2\framework\shaders\uicommon.h` +- `Kits\Cauldron2\framework\shaders\upscaler.h` +- `Kits\Cauldron2\rendermodules\animatedtextures\animatedtexturesrendermodule.cpp` +- `Kits\Cauldron2\rendermodules\animatedtextures\animatedtexturesrendermodule.h` +- `Kits\Cauldron2\rendermodules\animatedtextures\shaders\AnimatedTexture.hlsl` +- `Kits\Cauldron2\rendermodules\gbuffer\config\gbufferrendermodule.json` +- `Kits\Cauldron2\rendermodules\gbuffer\gbufferrendermodule.cpp` +- `Kits\Cauldron2\rendermodules\gbuffer\gbufferrendermodule.h` +- `Kits\Cauldron2\rendermodules\gbuffer\shaders\gbufferps.hlsl` +- `Kits\Cauldron2\rendermodules\gpuparticle\ffx_assert.h` +- `Kits\Cauldron2\rendermodules\gpuparticle\ffx_error.h` +- `Kits\Cauldron2\rendermodules\gpuparticle\ffx_interface.h` +- `Kits\Cauldron2\rendermodules\gpuparticle\ffx_parallelsort_private.h` +- `Kits\Cauldron2\rendermodules\gpuparticle\ffx_parallelsort.h` +- `Kits\Cauldron2\rendermodules\gpuparticle\ffx_types.h` +- `Kits\Cauldron2\rendermodules\gpuparticle\ffx_util.h` +- `Kits\Cauldron2\rendermodules\gpuparticle\gpuparticlerendermodule.cpp` +- `Kits\Cauldron2\rendermodules\gpuparticle\gpuparticlerendermodule.h` +- `Kits\Cauldron2\rendermodules\gpuparticle\parallelsort.cpp` +- `Kits\Cauldron2\rendermodules\gpuparticle\parallelsort.h` +- `Kits\Cauldron2\rendermodules\gpuparticle\parallelsort\ffx_parallelsort_callbacks_glsl.h` +- `Kits\Cauldron2\rendermodules\gpuparticle\parallelsort\ffx_parallelsort_callbacks_hlsl.h` +- `Kits\Cauldron2\rendermodules\gpuparticle\parallelsort\ffx_parallelsort_common.h` +- `Kits\Cauldron2\rendermodules\gpuparticle\parallelsort\ffx_parallelsort_reduce.h` +- `Kits\Cauldron2\rendermodules\gpuparticle\parallelsort\ffx_parallelsort_resources.h` +- `Kits\Cauldron2\rendermodules\gpuparticle\parallelsort\ffx_parallelsort_scan_add.h` +- `Kits\Cauldron2\rendermodules\gpuparticle\parallelsort\ffx_parallelsort_scan.h` +- `Kits\Cauldron2\rendermodules\gpuparticle\parallelsort\ffx_parallelsort_scatter.h` +- `Kits\Cauldron2\rendermodules\gpuparticle\parallelsort\ffx_parallelsort_setup_indirect_args.h` +- `Kits\Cauldron2\rendermodules\gpuparticle\parallelsort\ffx_parallelsort_sum.h` +- `Kits\Cauldron2\rendermodules\gpuparticle\parallelsort\ffx_parallelsort.h` +- `Kits\Cauldron2\rendermodules\gpuparticle\shaders\parallelsort_common_ffx.h` +- `Kits\Cauldron2\rendermodules\gpuparticle\shaders\parallelsort_reduce_pass.hlsl` +- `Kits\Cauldron2\rendermodules\gpuparticle\shaders\parallelsort_scan_add_pass.hlsl` +- `Kits\Cauldron2\rendermodules\gpuparticle\shaders\parallelsort_scan_pass.hlsl` +- `Kits\Cauldron2\rendermodules\gpuparticle\shaders\parallelsort_scatter_pass.hlsl` +- `Kits\Cauldron2\rendermodules\gpuparticle\shaders\parallelsort_setup_indirect_args.hlsl` +- `Kits\Cauldron2\rendermodules\gpuparticle\shaders\parallelsort_sum_pass.hlsl` +- `Kits\Cauldron2\rendermodules\gpuparticle\shaders\particleemit.hlsl` +- `Kits\Cauldron2\rendermodules\gpuparticle\shaders\particlesimulation.hlsl` +- `Kits\Cauldron2\rendermodules\gpuparticle\shaders\particlesimulationcommon.h` +- `Kits\Cauldron2\rendermodules\gpuparticle\shaders\simulationbindings.h` +- `Kits\Cauldron2\rendermodules\lighting\lightingrendermodule.cpp` +- `Kits\Cauldron2\rendermodules\lighting\lightingrendermodule.h` +- `Kits\Cauldron2\rendermodules\lighting\shaders\lighting.hlsl` +- `Kits\Cauldron2\rendermodules\rastershadow\config\rastershadowrendermodule.json` +- `Kits\Cauldron2\rendermodules\rastershadow\rastershadowrendermodule.cpp` +- `Kits\Cauldron2\rendermodules\rastershadow\rastershadowrendermodule.h` +- `Kits\Cauldron2\rendermodules\rastershadow\shaders\rastershadowps.hlsl` +- `Kits\Cauldron2\rendermodules\rendermoduleregistry.cpp` +- `Kits\Cauldron2\rendermodules\rendermoduleregistry.h` +- `Kits\Cauldron2\rendermodules\skydome\config\skydomerendermodule.json` +- `Kits\Cauldron2\rendermodules\skydome\shaders\skydome.hlsl` +- `Kits\Cauldron2\rendermodules\skydome\shaders\skydomecommon.h` +- `Kits\Cauldron2\rendermodules\skydome\shaders\skydomeproc.hlsl` +- `Kits\Cauldron2\rendermodules\skydome\skydomerendermodule.cpp` +- `Kits\Cauldron2\rendermodules\skydome\skydomerendermodule.h` +- `Kits\Cauldron2\rendermodules\taa\config\taarendermodule.json` +- `Kits\Cauldron2\rendermodules\taa\shaders\taa.hlsl` +- `Kits\Cauldron2\rendermodules\taa\shaders\taacommon.h` +- `Kits\Cauldron2\rendermodules\taa\shaders\taaPost.hlsl` +- `Kits\Cauldron2\rendermodules\taa\taarendermodule.cpp` +- `Kits\Cauldron2\rendermodules\taa\taarendermodule.h` +- `Kits\Cauldron2\rendermodules\translucency\config\translucencyrendermodule.json` +- `Kits\Cauldron2\rendermodules\translucency\shaders\particlerender.hlsl` +- `Kits\Cauldron2\rendermodules\translucency\shaders\particlerendercommon.h` +- `Kits\Cauldron2\rendermodules\translucency\shaders\translucencyps.hlsl` +- `Kits\Cauldron2\rendermodules\translucency\translucencyrendermodule.cpp` +- `Kits\Cauldron2\rendermodules\translucency\translucencyrendermodule.h` +- `Kits\Cauldron2\vk\Cauldron_vs2022.vcxproj` +- `Kits\Cauldron2\vk\Cauldron_vs2022.vcxproj.filters` +- `Kits\Cauldron2\vk\vcpkg.json` +- `Kits\FidelityFX\api\include\dx12\ffx_api_dx12.h` +- `Kits\FidelityFX\api\include\dx12\ffx_api_dx12.hpp` +- `Kits\FidelityFX\api\include\ffx_api_loader.h` +- `Kits\FidelityFX\api\include\ffx_api_matrix_helpers.h` +- `Kits\FidelityFX\api\include\ffx_api_matrix_helpers.hpp` +- `Kits\FidelityFX\api\include\ffx_api_types.h` +- `Kits\FidelityFX\api\include\ffx_api.h` +- `Kits\FidelityFX\api\include\ffx_api.hpp` +- `Kits\FidelityFX\api\include\vk\ffx_api_vk.h` +- `Kits\FidelityFX\api\include\vk\ffx_api_vk.hpp` +- `Kits\FidelityFX\api\internal\ffx_api_helper.h` +- `Kits\FidelityFX\api\internal\ffx_api.cpp` +- `Kits\FidelityFX\api\internal\ffx_assert.cpp` +- `Kits\FidelityFX\api\internal\ffx_assert.h` +- `Kits\FidelityFX\api\internal\ffx_backends.h` +- `Kits\FidelityFX\api\internal\ffx_blob_compression.h` +- `Kits\FidelityFX\api\internal\ffx_blob_decompress.h` +- `Kits\FidelityFX\api\internal\ffx_error.h` +- `Kits\FidelityFX\api\internal\ffx_interface.h` +- `Kits\FidelityFX\api\internal\ffx_internal_types.h` +- `Kits\FidelityFX\api\internal\ffx_message.cpp` +- `Kits\FidelityFX\api\internal\ffx_message.h` +- `Kits\FidelityFX\api\internal\ffx_object_management.cpp` +- `Kits\FidelityFX\api\internal\ffx_object_management.h` +- `Kits\FidelityFX\api\internal\ffx_provider.h` +- `Kits\FidelityFX\api\internal\ffx_query_fallback.cpp` +- `Kits\FidelityFX\api\internal\ffx_util.h` +- `Kits\FidelityFX\api\internal\gpu\ffx_common_types.h` +- `Kits\FidelityFX\api\internal\gpu\ffx_core_cpu.h` +- `Kits\FidelityFX\api\internal\gpu\ffx_core_gpu_common_half.h` +- `Kits\FidelityFX\api\internal\gpu\ffx_core_gpu_common.h` +- `Kits\FidelityFX\api\internal\gpu\ffx_core_hlsl.h` +- `Kits\FidelityFX\api\internal\gpu\ffx_core_portability.h` +- `Kits\FidelityFX\api\internal\gpu\ffx_core.h` +- `Kits\FidelityFX\backend\dx12\d3dx12.h` +- `Kits\FidelityFX\backend\dx12\ffx_backends_dx12.cpp` +- `Kits\FidelityFX\backend\dx12\ffx_dx12.cpp` +- `Kits\FidelityFX\backend\dx12\ffx_dx12.h` +- `Kits\FidelityFX\backend\vk\ffx_backends_vk.cpp` +- `Kits\FidelityFX\backend\vk\ffx_vk.cpp` +- `Kits\FidelityFX\backend\vk\ffx_vk.h` +- `Kits\FidelityFX\denoisers\include\ffx_denoiser.h` +- `Kits\FidelityFX\denoisers\include\ffx_denoiser.hpp` +- `Kits\FidelityFX\docs\getting-started\ffx-api.md` +- `Kits\FidelityFX\docs\getting-started\index.md` +- `Kits\FidelityFX\docs\getting-started\media\component-dependencies-dark.png` +- `Kits\FidelityFX\docs\getting-started\media\component-dependencies.png` +- `Kits\FidelityFX\docs\getting-started\media\config_init.jpg` +- `Kits\FidelityFX\docs\getting-started\media\lighting-ui.jpg` +- `Kits\FidelityFX\docs\getting-started\media\limiter-ui.jpg` +- `Kits\FidelityFX\docs\getting-started\media\magnifier-ui.jpg` +- `Kits\FidelityFX\docs\getting-started\media\particle-ui.jpg` +- `Kits\FidelityFX\docs\getting-started\media\postprocessing-ui.jpg` +- `Kits\FidelityFX\docs\getting-started\media\shadowraster-ui.jpg` +- `Kits\FidelityFX\docs\getting-started\media\skydome-ui.jpg` +- `Kits\FidelityFX\docs\getting-started\media\taa-ui.jpg` +- `Kits\FidelityFX\docs\getting-started\naming-guidelines.md` +- `Kits\FidelityFX\docs\getting-started\sdk-structure.md` +- `Kits\FidelityFX\docs\license.md` +- `Kits\FidelityFX\docs\media\AMD_FSR_SDK_Lockup_RGB_Blk.png` +- `Kits\FidelityFX\docs\media\AMD_FSR_SDK_Lockup_RGB_Wht.png` +- `Kits\FidelityFX\docs\techniques\denoising.md` +- `Kits\FidelityFX\docs\techniques\frame-interpolation-api.md` +- `Kits\FidelityFX\docs\techniques\frame-interpolation-ml.md` +- `Kits\FidelityFX\docs\techniques\frame-interpolation-swap-chain.md` +- `Kits\FidelityFX\docs\techniques\frame-interpolation.md` +- `Kits\FidelityFX\docs\techniques\index.md` +- `Kits\FidelityFX\docs\techniques\media\cross.png` +- `Kits\FidelityFX\docs\techniques\media\denoiser\fsr-ray-regeneration-brdf-lut.jpg` +- `Kits\FidelityFX\docs\techniques\media\denoiser\fsr-ray-regeneration-debug-view.png` +- `Kits\FidelityFX\docs\techniques\media\denoiser\fsr-ray-regeneration-denoised-sample.png` +- `Kits\FidelityFX\docs\techniques\media\denoiser\fsr-ray-regeneration-dispatch.png` +- `Kits\FidelityFX\docs\techniques\media\denoiser\fsr-ray-regeneration-noisy-sample.png` +- `Kits\FidelityFX\docs\techniques\media\denoiser\fsr-ray-regeneration-sample.png` +- `Kits\FidelityFX\docs\techniques\media\frame-interpolation-swapchain\frame-interpolation-swap-chain.svg` +- `Kits\FidelityFX\docs\techniques\media\frame-interpolation\frame-interpolation-debug-overlay.svg` +- `Kits\FidelityFX\docs\techniques\media\frame-pacing\fixed-high.svg` +- `Kits\FidelityFX\docs\techniques\media\frame-pacing\fixed-low.svg` +- `Kits\FidelityFX\docs\techniques\media\frame-pacing\pacing-overview.svg` +- `Kits\FidelityFX\docs\techniques\media\frame-pacing\variable-inside.svg` +- `Kits\FidelityFX\docs\techniques\media\radiance-cache\banner.jpg` +- `Kits\FidelityFX\docs\techniques\media\radiance-cache\path-tracer-schematic-querying.png` +- `Kits\FidelityFX\docs\techniques\media\radiance-cache\path-tracer-schematic-self-train.png` +- `Kits\FidelityFX\docs\techniques\media\radiance-cache\path-tracer-schematic-subpaths.png` +- `Kits\FidelityFX\docs\techniques\media\radiance-cache\pipeline-one-pass.png` +- `Kits\FidelityFX\docs\techniques\media\radiance-cache\pipeline-two-pass.png` +- `Kits\FidelityFX\docs\techniques\media\radiance-cache\sub-path-eqn.png` +- `Kits\FidelityFX\docs\techniques\media\super-resolution-interpolation\01_FSR3_DataFlow.svg` +- `Kits\FidelityFX\docs\techniques\media\super-resolution-interpolation\02_FSR3_Flow.svg` +- `Kits\FidelityFX\docs\techniques\media\super-resolution-interpolation\03_FSR3_FlowAsyncQueue.svg` +- `Kits\FidelityFX\docs\techniques\media\super-resolution-interpolation\04_FSR3_UiCallback.svg` +- `Kits\FidelityFX\docs\techniques\media\super-resolution-interpolation\05_FSR3_NoFG_UiCallback.svg` +- `Kits\FidelityFX\docs\techniques\media\super-resolution-interpolation\06_FSR3_UiTex.svg` +- `Kits\FidelityFX\docs\techniques\media\super-resolution-interpolation\07_FSR3_NoFG_UiTex.svg` +- `Kits\FidelityFX\docs\techniques\media\super-resolution-interpolation\08_FSR3_HUDLess.svg` +- `Kits\FidelityFX\docs\techniques\media\super-resolution-ml\fsr4-sample.jpg` +- `Kits\FidelityFX\docs\techniques\media\super-resolution-ml\pipeline-placement.svg` +- `Kits\FidelityFX\docs\techniques\media\super-resolution-temporal\fsr2-sample_resized.jpg` +- `Kits\FidelityFX\docs\techniques\media\super-resolution-temporal\fsr2-sample.jpg` +- `Kits\FidelityFX\docs\techniques\media\super-resolution-temporal\fsr3-sample_resized.jpg` +- `Kits\FidelityFX\docs\techniques\media\super-resolution-temporal\fsr3-sample.jpg` +- `Kits\FidelityFX\docs\techniques\media\super-resolution-temporal\jitter-space.svg` +- `Kits\FidelityFX\docs\techniques\media\super-resolution-temporal\motion-vectors.svg` +- `Kits\FidelityFX\docs\techniques\media\super-resolution-temporal\overview.svg` +- `Kits\FidelityFX\docs\techniques\media\super-resolution-temporal\pipeline-placement.svg` +- `Kits\FidelityFX\docs\techniques\media\super-resolution-upscaler\overview.svg` +- `Kits\FidelityFX\docs\techniques\media\super-resolution-upscaler\upscaler-debug-fsr4.png` +- `Kits\FidelityFX\docs\techniques\media\super-resolution-upscaler\upscaler-debug-overlay.svg` +- `Kits\FidelityFX\docs\techniques\media\tick.png` +- `Kits\FidelityFX\docs\techniques\radiance-cache.md` +- `Kits\FidelityFX\docs\techniques\super-resolution-ml.md` +- `Kits\FidelityFX\docs\techniques\super-resolution-temporal.md` +- `Kits\FidelityFX\docs\techniques\super-resolution-upscaler.md` +- `Kits\FidelityFX\docs\whats-new\index.md` +- `Kits\FidelityFX\docs\whats-new\version_1_0.md` +- `Kits\FidelityFX\docs\whats-new\version_1_1_1.md` +- `Kits\FidelityFX\docs\whats-new\version_1_1_2.md` +- `Kits\FidelityFX\docs\whats-new\version_1_1_3.md` +- `Kits\FidelityFX\docs\whats-new\version_1_1_4.md` +- `Kits\FidelityFX\docs\whats-new\version_1_1.md` +- `Kits\FidelityFX\docs\whats-new\version_2_0_0.md` +- `Kits\FidelityFX\docs\whats-new\version_2_1_0.md` +- `Kits\FidelityFX\docs\whats-new\version_2_2_0.md` +- `Kits\FidelityFX\docs\whats-new\version_2_3_0.md` +- `Kits\FidelityFX\framegeneration\fsr3\dx12\antilag2\ffx_antilag2_dx12.h` +- `Kits\FidelityFX\framegeneration\fsr3\dx12\ffx_provider_fsr3framegenerationswapchain_dx12.cpp` +- `Kits\FidelityFX\framegeneration\fsr3\dx12\FrameInterpolationSwapchainDebugPacingPS.h` +- `Kits\FidelityFX\framegeneration\fsr3\dx12\FrameInterpolationSwapchainDebugPacingVS.h` +- `Kits\FidelityFX\framegeneration\fsr3\dx12\FrameInterpolationSwapchainDX12_DebugPacing.cpp` +- `Kits\FidelityFX\framegeneration\fsr3\dx12\FrameInterpolationSwapchainDX12_DebugPacing.h` +- `Kits\FidelityFX\framegeneration\fsr3\dx12\FrameInterpolationSwapchainDX12_Helpers.cpp` +- `Kits\FidelityFX\framegeneration\fsr3\dx12\FrameInterpolationSwapchainDX12_Helpers.h` +- `Kits\FidelityFX\framegeneration\fsr3\dx12\FrameInterpolationSwapchainDX12_UiComposition.cpp` +- `Kits\FidelityFX\framegeneration\fsr3\dx12\FrameInterpolationSwapchainDX12_UiComposition.h` +- `Kits\FidelityFX\framegeneration\fsr3\dx12\FrameInterpolationSwapchainDX12.cpp` +- `Kits\FidelityFX\framegeneration\fsr3\dx12\FrameInterpolationSwapchainDX12.h` +- `Kits\FidelityFX\framegeneration\fsr3\dx12\FrameInterpolationSwapchainUiCompositionPremulPS.h` +- `Kits\FidelityFX\framegeneration\fsr3\dx12\FrameInterpolationSwapchainUiCompositionPremulVS.h` +- `Kits\FidelityFX\framegeneration\fsr3\dx12\FrameInterpolationSwapchainUiCompositionPS.h` +- `Kits\FidelityFX\framegeneration\fsr3\dx12\FrameInterpolationSwapchainUiCompositionVS.h` +- `Kits\FidelityFX\framegeneration\fsr3\include\ffx_frameinterpolation.h` +- `Kits\FidelityFX\framegeneration\fsr3\include\ffx_opticalflow.h` +- `Kits\FidelityFX\framegeneration\fsr3\include\ffx_provider_fsr3framegeneration.h` +- `Kits\FidelityFX\framegeneration\fsr3\include\ffx_provider_fsr3framegenerationswapchain.h` +- `Kits\FidelityFX\framegeneration\fsr3\include\gpu\frameinterpolation\ffx_frameinterpolation_callbacks_hlsl.h` +- `Kits\FidelityFX\framegeneration\fsr3\include\gpu\frameinterpolation\ffx_frameinterpolation_common.h` +- `Kits\FidelityFX\framegeneration\fsr3\include\gpu\frameinterpolation\ffx_frameinterpolation_compute_game_vector_field_inpainting_pyramid.h` +- `Kits\FidelityFX\framegeneration\fsr3\include\gpu\frameinterpolation\ffx_frameinterpolation_compute_inpainting_pyramid.h` +- `Kits\FidelityFX\framegeneration\fsr3\include\gpu\frameinterpolation\ffx_frameinterpolation_debug_view.h` +- `Kits\FidelityFX\framegeneration\fsr3\include\gpu\frameinterpolation\ffx_frameinterpolation_disocclusion_mask.h` +- `Kits\FidelityFX\framegeneration\fsr3\include\gpu\frameinterpolation\ffx_frameinterpolation_game_motion_vector_field.h` +- `Kits\FidelityFX\framegeneration\fsr3\include\gpu\frameinterpolation\ffx_frameinterpolation_inpainting.h` +- `Kits\FidelityFX\framegeneration\fsr3\include\gpu\frameinterpolation\ffx_frameinterpolation_optical_flow_vector_field.h` +- `Kits\FidelityFX\framegeneration\fsr3\include\gpu\frameinterpolation\ffx_frameinterpolation_reconstruct_dilated_velocity_and_previous_depth.h` +- `Kits\FidelityFX\framegeneration\fsr3\include\gpu\frameinterpolation\ffx_frameinterpolation_reconstruct_previous_depth.h` +- `Kits\FidelityFX\framegeneration\fsr3\include\gpu\frameinterpolation\ffx_frameinterpolation_resources.h` +- `Kits\FidelityFX\framegeneration\fsr3\include\gpu\frameinterpolation\ffx_frameinterpolation_setup.h` +- `Kits\FidelityFX\framegeneration\fsr3\include\gpu\frameinterpolation\ffx_frameinterpolation.h` +- `Kits\FidelityFX\framegeneration\fsr3\include\gpu\opticalflow\ffx_opticalflow_callbacks_hlsl.h` +- `Kits\FidelityFX\framegeneration\fsr3\include\gpu\opticalflow\ffx_opticalflow_common.h` +- `Kits\FidelityFX\framegeneration\fsr3\include\gpu\opticalflow\ffx_opticalflow_compute_luminance_pyramid.h` +- `Kits\FidelityFX\framegeneration\fsr3\include\gpu\opticalflow\ffx_opticalflow_compute_optical_flow_v5.h` +- `Kits\FidelityFX\framegeneration\fsr3\include\gpu\opticalflow\ffx_opticalflow_compute_scd_divergence.h` +- `Kits\FidelityFX\framegeneration\fsr3\include\gpu\opticalflow\ffx_opticalflow_filter_optical_flow_v5.h` +- `Kits\FidelityFX\framegeneration\fsr3\include\gpu\opticalflow\ffx_opticalflow_generate_scd_histogram.h` +- `Kits\FidelityFX\framegeneration\fsr3\include\gpu\opticalflow\ffx_opticalflow_prepare_luma.h` +- `Kits\FidelityFX\framegeneration\fsr3\include\gpu\opticalflow\ffx_opticalflow_resources.h` +- `Kits\FidelityFX\framegeneration\fsr3\include\gpu\opticalflow\ffx_opticalflow_scale_optical_flow_advanced_v5.h` +- `Kits\FidelityFX\framegeneration\fsr3\include\gpu\spd\ffx_spd.h` +- `Kits\FidelityFX\framegeneration\fsr3\internal\ffx_frameinterpolation_private.h` +- `Kits\FidelityFX\framegeneration\fsr3\internal\ffx_frameinterpolation_shaderblobs.cpp` +- `Kits\FidelityFX\framegeneration\fsr3\internal\ffx_frameinterpolation_shaderblobs.h` +- `Kits\FidelityFX\framegeneration\fsr3\internal\ffx_frameinterpolation.cpp` +- `Kits\FidelityFX\framegeneration\fsr3\internal\ffx_opticalflow_private.h` +- `Kits\FidelityFX\framegeneration\fsr3\internal\ffx_opticalflow_shaderblobs.cpp` +- `Kits\FidelityFX\framegeneration\fsr3\internal\ffx_opticalflow_shaderblobs.h` +- `Kits\FidelityFX\framegeneration\fsr3\internal\ffx_opticalflow.cpp` +- `Kits\FidelityFX\framegeneration\fsr3\internal\ffx_provider_fsr3framegeneration.cpp` +- `Kits\FidelityFX\framegeneration\fsr3\internal\shaders\ffx_frameinterpolation_compute_game_vector_field_inpainting_pyramid_pass.hlsl` +- `Kits\FidelityFX\framegeneration\fsr3\internal\shaders\ffx_frameinterpolation_compute_inpainting_pyramid_pass.hlsl` +- `Kits\FidelityFX\framegeneration\fsr3\internal\shaders\ffx_frameinterpolation_debug_view_pass.hlsl` +- `Kits\FidelityFX\framegeneration\fsr3\internal\shaders\ffx_frameinterpolation_disocclusion_mask_pass.hlsl` +- `Kits\FidelityFX\framegeneration\fsr3\internal\shaders\ffx_frameinterpolation_game_motion_vector_field_pass.hlsl` +- `Kits\FidelityFX\framegeneration\fsr3\internal\shaders\ffx_frameinterpolation_inpainting_pass.hlsl` +- `Kits\FidelityFX\framegeneration\fsr3\internal\shaders\ffx_frameinterpolation_optical_flow_vector_field_pass.hlsl` +- `Kits\FidelityFX\framegeneration\fsr3\internal\shaders\ffx_frameinterpolation_pass.hlsl` +- `Kits\FidelityFX\framegeneration\fsr3\internal\shaders\ffx_frameinterpolation_reconstruct_and_dilate_pass.hlsl` +- `Kits\FidelityFX\framegeneration\fsr3\internal\shaders\ffx_frameinterpolation_reconstruct_previous_depth_pass.hlsl` +- `Kits\FidelityFX\framegeneration\fsr3\internal\shaders\ffx_frameinterpolation_setup_pass.hlsl` +- `Kits\FidelityFX\framegeneration\fsr3\internal\shaders\ffx_opticalflow_compute_luminance_pyramid_pass.hlsl` +- `Kits\FidelityFX\framegeneration\fsr3\internal\shaders\ffx_opticalflow_compute_optical_flow_advanced_pass_v5.hlsl` +- `Kits\FidelityFX\framegeneration\fsr3\internal\shaders\ffx_opticalflow_compute_scd_divergence_pass.hlsl` +- `Kits\FidelityFX\framegeneration\fsr3\internal\shaders\ffx_opticalflow_filter_optical_flow_pass_v5.hlsl` +- `Kits\FidelityFX\framegeneration\fsr3\internal\shaders\ffx_opticalflow_generate_scd_histogram_pass.hlsl` +- `Kits\FidelityFX\framegeneration\fsr3\internal\shaders\ffx_opticalflow_prepare_luma_pass.hlsl` +- `Kits\FidelityFX\framegeneration\fsr3\internal\shaders\ffx_opticalflow_scale_optical_flow_advanced_pass_v5.hlsl` +- `Kits\FidelityFX\framegeneration\fsr3\internal\shaders\FrameInterpolationSwapchainDebugPacing.hlsl` +- `Kits\FidelityFX\framegeneration\fsr3\internal\shaders\FrameInterpolationSwapchainUiComposition.hlsl` +- `Kits\FidelityFX\framegeneration\fsr3\vk\ffx_provider_framegenerationswapchain_vk.cpp` +- `Kits\FidelityFX\framegeneration\fsr3\vk\FrameInterpolationSwapchainDebugPacingPS.h` +- `Kits\FidelityFX\framegeneration\fsr3\vk\FrameInterpolationSwapchainDebugPacingVS.h` +- `Kits\FidelityFX\framegeneration\fsr3\vk\FrameInterpolationSwapchainUiCompositionPremulPS.h` +- `Kits\FidelityFX\framegeneration\fsr3\vk\FrameInterpolationSwapchainUiCompositionPremulVS.h` +- `Kits\FidelityFX\framegeneration\fsr3\vk\FrameInterpolationSwapchainUiCompositionPS.h` +- `Kits\FidelityFX\framegeneration\fsr3\vk\FrameInterpolationSwapchainUiCompositionVS.h` +- `Kits\FidelityFX\framegeneration\fsr3\vk\FrameInterpolationSwapchainVK_DebugPacing.cpp` +- `Kits\FidelityFX\framegeneration\fsr3\vk\FrameInterpolationSwapchainVK_DebugPacing.h` +- `Kits\FidelityFX\framegeneration\fsr3\vk\FrameInterpolationSwapchainVK_Helpers.cpp` +- `Kits\FidelityFX\framegeneration\fsr3\vk\FrameInterpolationSwapchainVK_Helpers.h` +- `Kits\FidelityFX\framegeneration\fsr3\vk\FrameInterpolationSwapchainVK_UiComposition.cpp` +- `Kits\FidelityFX\framegeneration\fsr3\vk\FrameInterpolationSwapchainVK_UiComposition.h` +- `Kits\FidelityFX\framegeneration\fsr3\vk\FrameInterpolationSwapchainVK.cpp` +- `Kits\FidelityFX\framegeneration\fsr3\vk\FrameInterpolationSwapchainVK.h` +- `Kits\FidelityFX\framegeneration\include\dx12\ffx_api_framegeneration_dx12.h` +- `Kits\FidelityFX\framegeneration\include\dx12\ffx_api_framegeneration_dx12.hpp` +- `Kits\FidelityFX\framegeneration\include\ffx_framegeneration_api_types.h` +- `Kits\FidelityFX\framegeneration\include\ffx_framegeneration.h` +- `Kits\FidelityFX\framegeneration\include\ffx_framegeneration.hpp` +- `Kits\FidelityFX\framegeneration\include\vk\ffx_api_framegeneration_vk.h` +- `Kits\FidelityFX\framegeneration\include\vk\ffx_api_framegeneration_vk.hpp` +- `Kits\FidelityFX\framegeneration\internal\ffx_framegeneration_internal.h` +- `Kits\FidelityFX\radiancecache\include\ffx_radiancecache.h` +- `Kits\FidelityFX\radiancecache\include\ffx_radiancecache.hpp` +- `Kits\FidelityFX\readme.md` +- `Kits\FidelityFX\signedbin\amd_fidelityfx_denoiser_dx12.dll` +- `Kits\FidelityFX\signedbin\amd_fidelityfx_framegeneration_dx12.dll` +- `Kits\FidelityFX\signedbin\amd_fidelityfx_framegeneration_vk.dll` +- `Kits\FidelityFX\signedbin\amd_fidelityfx_loader_dx12.dll` +- `Kits\FidelityFX\signedbin\amd_fidelityfx_loader_dx12.lib` +- `Kits\FidelityFX\signedbin\amd_fidelityfx_loader_vk.dll` +- `Kits\FidelityFX\signedbin\amd_fidelityfx_loader_vk.lib` +- `Kits\FidelityFX\signedbin\amd_fidelityfx_radiancecache_dx12.dll` +- `Kits\FidelityFX\signedbin\amd_fidelityfx_upscaler_dx12.dll` +- `Kits\FidelityFX\signedbin\amd_fidelityfx_upscaler_vk.dll` +- `Kits\FidelityFX\upscalers\fsr3\include\ffx_fsr2.h` +- `Kits\FidelityFX\upscalers\fsr3\include\ffx_fsr3upscaler.h` +- `Kits\FidelityFX\upscalers\fsr3\include\ffx_provider_fsr2.h` +- `Kits\FidelityFX\upscalers\fsr3\include\ffx_provider_fsr3upscale.h` +- `Kits\FidelityFX\upscalers\fsr3\include\ffx_spd.h` +- `Kits\FidelityFX\upscalers\fsr3\include\gpu\fsr1\ffx_fsr1.h` +- `Kits\FidelityFX\upscalers\fsr3\include\gpu\fsr2\ffx_fsr2_accumulate.h` +- `Kits\FidelityFX\upscalers\fsr3\include\gpu\fsr2\ffx_fsr2_callbacks_hlsl.h` +- `Kits\FidelityFX\upscalers\fsr3\include\gpu\fsr2\ffx_fsr2_common.h` +- `Kits\FidelityFX\upscalers\fsr3\include\gpu\fsr2\ffx_fsr2_compute_luminance_pyramid.h` +- `Kits\FidelityFX\upscalers\fsr3\include\gpu\fsr2\ffx_fsr2_depth_clip.h` +- `Kits\FidelityFX\upscalers\fsr3\include\gpu\fsr2\ffx_fsr2_lock.h` +- `Kits\FidelityFX\upscalers\fsr3\include\gpu\fsr2\ffx_fsr2_postprocess_lock_status.h` +- `Kits\FidelityFX\upscalers\fsr3\include\gpu\fsr2\ffx_fsr2_rcas.h` +- `Kits\FidelityFX\upscalers\fsr3\include\gpu\fsr2\ffx_fsr2_reconstruct_previous_depth.h` +- `Kits\FidelityFX\upscalers\fsr3\include\gpu\fsr2\ffx_fsr2_reproject.h` +- `Kits\FidelityFX\upscalers\fsr3\include\gpu\fsr2\ffx_fsr2_resources.h` +- `Kits\FidelityFX\upscalers\fsr3\include\gpu\fsr2\ffx_fsr2_sample.h` +- `Kits\FidelityFX\upscalers\fsr3\include\gpu\fsr2\ffx_fsr2_tcr_autogen.h` +- `Kits\FidelityFX\upscalers\fsr3\include\gpu\fsr2\ffx_fsr2_upsample.h` +- `Kits\FidelityFX\upscalers\fsr3\include\gpu\fsr3\ffx_fsr3_callbacks_hlsl.h` +- `Kits\FidelityFX\upscalers\fsr3\include\gpu\fsr3\ffx_fsr3_common.h` +- `Kits\FidelityFX\upscalers\fsr3\include\gpu\fsr3\ffx_fsr3_resources.h` +- `Kits\FidelityFX\upscalers\fsr3\include\gpu\fsr3upscaler\ffx_fsr3upscaler_accumulate.h` +- `Kits\FidelityFX\upscalers\fsr3\include\gpu\fsr3upscaler\ffx_fsr3upscaler_callbacks_hlsl.h` +- `Kits\FidelityFX\upscalers\fsr3\include\gpu\fsr3upscaler\ffx_fsr3upscaler_common.h` +- `Kits\FidelityFX\upscalers\fsr3\include\gpu\fsr3upscaler\ffx_fsr3upscaler_debug_view.h` +- `Kits\FidelityFX\upscalers\fsr3\include\gpu\fsr3upscaler\ffx_fsr3upscaler_luma_instability.h` +- `Kits\FidelityFX\upscalers\fsr3\include\gpu\fsr3upscaler\ffx_fsr3upscaler_luma_pyramid.h` +- `Kits\FidelityFX\upscalers\fsr3\include\gpu\fsr3upscaler\ffx_fsr3upscaler_prepare_inputs.h` +- `Kits\FidelityFX\upscalers\fsr3\include\gpu\fsr3upscaler\ffx_fsr3upscaler_prepare_reactivity.h` +- `Kits\FidelityFX\upscalers\fsr3\include\gpu\fsr3upscaler\ffx_fsr3upscaler_rcas.h` +- `Kits\FidelityFX\upscalers\fsr3\include\gpu\fsr3upscaler\ffx_fsr3upscaler_reproject.h` +- `Kits\FidelityFX\upscalers\fsr3\include\gpu\fsr3upscaler\ffx_fsr3upscaler_resources.h` +- `Kits\FidelityFX\upscalers\fsr3\include\gpu\fsr3upscaler\ffx_fsr3upscaler_sample.h` +- `Kits\FidelityFX\upscalers\fsr3\include\gpu\fsr3upscaler\ffx_fsr3upscaler_shading_change_pyramid.h` +- `Kits\FidelityFX\upscalers\fsr3\include\gpu\fsr3upscaler\ffx_fsr3upscaler_shading_change.h` +- `Kits\FidelityFX\upscalers\fsr3\include\gpu\fsr3upscaler\ffx_fsr3upscaler_upsample.h` +- `Kits\FidelityFX\upscalers\fsr3\include\gpu\spd\ffx_spd.h` +- `Kits\FidelityFX\upscalers\fsr3\internal\ffx_fsr2_maximum_bias.h` +- `Kits\FidelityFX\upscalers\fsr3\internal\ffx_fsr2_private.h` +- `Kits\FidelityFX\upscalers\fsr3\internal\ffx_fsr2_shaderblobs.cpp` +- `Kits\FidelityFX\upscalers\fsr3\internal\ffx_fsr2_shaderblobs.h` +- `Kits\FidelityFX\upscalers\fsr3\internal\ffx_fsr2.cpp` +- `Kits\FidelityFX\upscalers\fsr3\internal\ffx_fsr3_private.h` +- `Kits\FidelityFX\upscalers\fsr3\internal\ffx_fsr3upscaler_private.h` +- `Kits\FidelityFX\upscalers\fsr3\internal\ffx_fsr3upscaler_shaderblobs.cpp` +- `Kits\FidelityFX\upscalers\fsr3\internal\ffx_fsr3upscaler_shaderblobs.h` +- `Kits\FidelityFX\upscalers\fsr3\internal\ffx_fsr3upscaler.cpp` +- `Kits\FidelityFX\upscalers\fsr3\internal\ffx_provider_fsr2.cpp` +- `Kits\FidelityFX\upscalers\fsr3\internal\ffx_provider_fsr3upscale.cpp` +- `Kits\FidelityFX\upscalers\fsr3\internal\shaders\ffx_fsr2_accumulate_pass.hlsl` +- `Kits\FidelityFX\upscalers\fsr3\internal\shaders\ffx_fsr2_autogen_reactive_pass.hlsl` +- `Kits\FidelityFX\upscalers\fsr3\internal\shaders\ffx_fsr2_compute_luminance_pyramid_pass.hlsl` +- `Kits\FidelityFX\upscalers\fsr3\internal\shaders\ffx_fsr2_debug_blit.hlsl` +- `Kits\FidelityFX\upscalers\fsr3\internal\shaders\ffx_fsr2_depth_clip_pass.hlsl` +- `Kits\FidelityFX\upscalers\fsr3\internal\shaders\ffx_fsr2_lock_pass.hlsl` +- `Kits\FidelityFX\upscalers\fsr3\internal\shaders\ffx_fsr2_rcas_pass.hlsl` +- `Kits\FidelityFX\upscalers\fsr3\internal\shaders\ffx_fsr2_reconstruct_previous_depth_pass.hlsl` +- `Kits\FidelityFX\upscalers\fsr3\internal\shaders\ffx_fsr2_tcr_autogen_pass.hlsl` +- `Kits\FidelityFX\upscalers\fsr3\internal\shaders\ffx_fsr3upscaler_accumulate_pass.hlsl` +- `Kits\FidelityFX\upscalers\fsr3\internal\shaders\ffx_fsr3upscaler_autogen_reactive_pass.hlsl` +- `Kits\FidelityFX\upscalers\fsr3\internal\shaders\ffx_fsr3upscaler_debug_view_pass.hlsl` +- `Kits\FidelityFX\upscalers\fsr3\internal\shaders\ffx_fsr3upscaler_luma_instability_pass.hlsl` +- `Kits\FidelityFX\upscalers\fsr3\internal\shaders\ffx_fsr3upscaler_luma_pyramid_pass.hlsl` +- `Kits\FidelityFX\upscalers\fsr3\internal\shaders\ffx_fsr3upscaler_prepare_inputs_pass.hlsl` +- `Kits\FidelityFX\upscalers\fsr3\internal\shaders\ffx_fsr3upscaler_prepare_reactivity_pass.hlsl` +- `Kits\FidelityFX\upscalers\fsr3\internal\shaders\ffx_fsr3upscaler_rcas_pass.hlsl` +- `Kits\FidelityFX\upscalers\fsr3\internal\shaders\ffx_fsr3upscaler_shading_change_pass.hlsl` +- `Kits\FidelityFX\upscalers\fsr3\internal\shaders\ffx_fsr3upscaler_shading_change_pyramid_pass.hlsl` +- `Kits\FidelityFX\upscalers\include\ffx_upscale.h` +- `Kits\FidelityFX\upscalers\include\ffx_upscale.hpp` +- `Kits\OpenSource\amd\acs\amd_acs_ARM64_2022_MD.lib` +- `Kits\OpenSource\amd\acs\amd_acs_ARM64_2022_MDd.lib` +- `Kits\OpenSource\amd\acs\amd_acs_ARM64_2022_MT.lib` +- `Kits\OpenSource\amd\acs\amd_acs_ARM64_2022_MTd.lib` +- `Kits\OpenSource\amd\acs\amd_acs_ARM64.dll` +- `Kits\OpenSource\amd\acs\amd_acs_ARM64.exp` +- `Kits\OpenSource\amd\acs\amd_acs_ARM64.lib` +- `Kits\OpenSource\amd\acs\amd_acs_ARM64d.exp` +- `Kits\OpenSource\amd\acs\amd_acs_ARM64d.lib` +- `Kits\OpenSource\amd\acs\amd_acs_x64_2019_MD.lib` +- `Kits\OpenSource\amd\acs\amd_acs_x64_2019_MDd.lib` +- `Kits\OpenSource\amd\acs\amd_acs_x64_2019_MT.lib` +- `Kits\OpenSource\amd\acs\amd_acs_x64_2019_MTd.lib` +- `Kits\OpenSource\amd\acs\amd_acs_x64.dll` +- `Kits\OpenSource\amd\acs\amd_acs_x64.exp` +- `Kits\OpenSource\amd\acs\amd_acs_x64.lib` +- `Kits\OpenSource\amd\acs\amd_acs_x64d.exp` +- `Kits\OpenSource\amd\acs\amd_acs_x64d.lib` +- `Kits\OpenSource\amd\acs\amd_acs.h` +- `Kits\OpenSource\amd\acs\LICENSE.txt` +- `Kits\OpenSource\amd\acs\README.md` +- `Kits\OpenSource\amd\ags\ags_shader_intrinsics_dx12.hlsl` +- `Kits\OpenSource\amd\ags\amd_ags_x64.dll` +- `Kits\OpenSource\amd\ags\amd_ags_x64.lib` +- `Kits\OpenSource\amd\ags\amd_ags.chm` +- `Kits\OpenSource\amd\ags\amd_ags.h` +- `Kits\OpenSource\amd\ags\LICENSE.txt` +- `Kits\OpenSource\amd\ags\README.md` +- `Kits\OpenSource\amd\antilag2\ffx_antilag2_dx12.h` +- `Kits\OpenSource\amd\antilag2\LICENSE.txt` +- `Kits\OpenSource\amd\memoryallocator\D3D12MemAlloc.cpp` +- `Kits\OpenSource\amd\memoryallocator\D3D12MemAlloc.h` +- `Kits\OpenSource\amd\memoryallocator\license.txt` +- `Kits\OpenSource\amd\memoryallocator\memoryallocator.cpp` +- `Kits\OpenSource\amd\memoryallocator\memoryallocator.h` +- `Kits\OpenSource\amd\memoryallocator\vk_mem_alloc.h` +- `Kits\OpenSource\imgui\backends\imgui_impl_dx12.cpp` +- `Kits\OpenSource\imgui\backends\imgui_impl_dx12.h` +- `Kits\OpenSource\imgui\backends\imgui_impl_win32.cpp` +- `Kits\OpenSource\imgui\backends\imgui_impl_win32.h` +- `Kits\OpenSource\imgui\docs\BACKENDS.md` +- `Kits\OpenSource\imgui\docs\CHANGELOG.txt` +- `Kits\OpenSource\imgui\docs\CONTRIBUTING.md` +- `Kits\OpenSource\imgui\docs\EXAMPLES.md` +- `Kits\OpenSource\imgui\docs\FAQ.md` +- `Kits\OpenSource\imgui\docs\FONTS.md` +- `Kits\OpenSource\imgui\docs\README.md` +- `Kits\OpenSource\imgui\docs\TODO.txt` +- `Kits\OpenSource\imgui\imconfig.h` +- `Kits\OpenSource\imgui\imgui_demo.cpp` +- `Kits\OpenSource\imgui\imgui_draw.cpp` +- `Kits\OpenSource\imgui\imgui_internal.h` +- `Kits\OpenSource\imgui\imgui_tables.cpp` +- `Kits\OpenSource\imgui\imgui_widgets.cpp` +- `Kits\OpenSource\imgui\imgui.cpp` +- `Kits\OpenSource\imgui\imgui.h` +- `Kits\OpenSource\imgui\imstb_rectpack.h` +- `Kits\OpenSource\imgui\imstb_textedit.h` +- `Kits\OpenSource\imgui\imstb_truetype.h` +- `Kits\OpenSource\imgui\LICENSE.txt` +- `Kits\OpenSource\imgui\misc\cpp\imgui_stdlib.cpp` +- `Kits\OpenSource\imgui\misc\cpp\imgui_stdlib.h` +- `Kits\OpenSource\imgui\misc\cpp\README.txt` +- `Kits\OpenSource\imgui\misc\debuggers\imgui.gdb` +- `Kits\OpenSource\imgui\misc\debuggers\imgui.natstepfilter` +- `Kits\OpenSource\imgui\misc\debuggers\imgui.natvis` +- `Kits\OpenSource\imgui\misc\debuggers\README.txt` +- `Kits\OpenSource\imgui\misc\fonts\binary_to_compressed_c.cpp` +- `Kits\OpenSource\imgui\misc\fonts\Cousine-Regular.ttf` +- `Kits\OpenSource\imgui\misc\fonts\DroidSans.ttf` +- `Kits\OpenSource\imgui\misc\fonts\Karla-Regular.ttf` +- `Kits\OpenSource\imgui\misc\fonts\ProggyClean.ttf` +- `Kits\OpenSource\imgui\misc\fonts\ProggyTiny.ttf` +- `Kits\OpenSource\imgui\misc\fonts\Roboto-Medium.ttf` +- `Kits\OpenSource\imgui\misc\freetype\imgui_freetype.cpp` +- `Kits\OpenSource\imgui\misc\freetype\imgui_freetype.h` +- `Kits\OpenSource\imgui\misc\freetype\README.md` +- `Kits\OpenSource\imgui\misc\README.txt` +- `Kits\OpenSource\imgui\misc\single_file\imgui_single_file.h` +- `Kits\OpenSource\nlohmann\json_fwd.hpp` +- `Kits\OpenSource\nlohmann\json.hpp` +- `Kits\OpenSource\nlohmann\LICENSE.MIT` +- `Kits\OpenSource\nlohmann\version.txt` +- `Kits\OpenSource\stb\LICENSE.MIT` +- `Kits\OpenSource\stb\stb_image_write.h` +- `Kits\OpenSource\stb\stb_image.h` +- `Kits\OpenSource\vectormath\common.hpp` +- `Kits\OpenSource\vectormath\docs\VectorMath-Library-Overview.pdf` +- `Kits\OpenSource\vectormath\LICENSE.txt` +- `Kits\OpenSource\vectormath\README.md` +- `Kits\OpenSource\vectormath\scalar\matrix.hpp` +- `Kits\OpenSource\vectormath\scalar\quaternion.hpp` +- `Kits\OpenSource\vectormath\scalar\vector.hpp` +- `Kits\OpenSource\vectormath\scalar\vectormath.hpp` +- `Kits\OpenSource\vectormath\sse\boolinvec.hpp` +- `Kits\OpenSource\vectormath\sse\floatinvec.hpp` +- `Kits\OpenSource\vectormath\sse\internal.hpp` +- `Kits\OpenSource\vectormath\sse\matrix.hpp` +- `Kits\OpenSource\vectormath\sse\quaternion.hpp` +- `Kits\OpenSource\vectormath\sse\vecidx.hpp` +- `Kits\OpenSource\vectormath\sse\vector.hpp` +- `Kits\OpenSource\vectormath\sse\vectormath.hpp` +- `Kits\OpenSource\vectormath\vec2d.hpp` +- `Kits\OpenSource\vectormath\vectormath.hpp` +- `readme.md` +- `Samples\Denoisers\FidelityFX_Denoiser\dx12\config\denoiserconfig.json` +- `Samples\Denoisers\FidelityFX_Denoiser\dx12\debugoverlayrendermodule.cpp` +- `Samples\Denoisers\FidelityFX_Denoiser\dx12\debugoverlayrendermodule.h` +- `Samples\Denoisers\FidelityFX_Denoiser\dx12\denoiserrendermodule.cpp` +- `Samples\Denoisers\FidelityFX_Denoiser\dx12\denoiserrendermodule.h` +- `Samples\Denoisers\FidelityFX_Denoiser\dx12\denoisersettingshandler.cpp` +- `Samples\Denoisers\FidelityFX_Denoiser\dx12\denoisersettingshandler.h` +- `Samples\Denoisers\FidelityFX_Denoiser\dx12\dpiawarescaling.manifest` +- `Samples\Denoisers\FidelityFX_Denoiser\dx12\FidelityFX_Denoiser_Sample_2022.props` +- `Samples\Denoisers\FidelityFX_Denoiser\dx12\FidelityFX_Denoiser_Sample_2022.sln` +- `Samples\Denoisers\FidelityFX_Denoiser\dx12\FidelityFX_Denoiser_Sample_2022.vcxproj` +- `Samples\Denoisers\FidelityFX_Denoiser\dx12\FidelityFX_Denoiser_Sample_2022.vcxproj.filters` +- `Samples\Denoisers\FidelityFX_Denoiser\dx12\fsrapirendermodule.cpp` +- `Samples\Denoisers\FidelityFX_Denoiser\dx12\fsrapirendermodule.h` +- `Samples\Denoisers\FidelityFX_Denoiser\dx12\fsrsettingshandler.cpp` +- `Samples\Denoisers\FidelityFX_Denoiser\dx12\fsrsettingshandler.h` +- `Samples\Denoisers\FidelityFX_Denoiser\dx12\main.cpp` +- `Samples\Denoisers\FidelityFX_Denoiser\dx12\pathtracingrendermodule.cpp` +- `Samples\Denoisers\FidelityFX_Denoiser\dx12\pathtracingrendermodule.h` +- `Samples\Denoisers\FidelityFX_Denoiser\dx12\resources\cauldron.rc` +- `Samples\Denoisers\FidelityFX_Denoiser\dx12\resources\GPUOpenChip.ico` +- `Samples\Denoisers\FidelityFX_Denoiser\dx12\resources\resource.h` +- `Samples\Denoisers\FidelityFX_Denoiser\dx12\sample.cpp` +- `Samples\Denoisers\FidelityFX_Denoiser\dx12\sample.h` +- `Samples\Denoisers\FidelityFX_Denoiser\dx12\sampleautomation.cpp` +- `Samples\Denoisers\FidelityFX_Denoiser\dx12\sampleautomation.h` +- `Samples\Denoisers\FidelityFX_Denoiser\dx12\shaders\Basis.hlsli` +- `Samples\Denoisers\FidelityFX_Denoiser\dx12\shaders\Bindings.hlsli` +- `Samples\Denoisers\FidelityFX_Denoiser\dx12\shaders\Color.hlsli` +- `Samples\Denoisers\FidelityFX_Denoiser\dx12\shaders\DebugOverlay.cs.hlsl` +- `Samples\Denoisers\FidelityFX_Denoiser\dx12\shaders\DebugOverlayData.h` +- `Samples\Denoisers\FidelityFX_Denoiser\dx12\shaders\DenoisingCompose.cs.hlsl` +- `Samples\Denoisers\FidelityFX_Denoiser\dx12\shaders\DenoisingData.h` +- `Samples\Denoisers\FidelityFX_Denoiser\dx12\shaders\DenoisingPrepare.cs.hlsl` +- `Samples\Denoisers\FidelityFX_Denoiser\dx12\shaders\Dispatch.hlsli` +- `Samples\Denoisers\FidelityFX_Denoiser\dx12\shaders\Geometry.hlsli` +- `Samples\Denoisers\FidelityFX_Denoiser\dx12\shaders\Lighting.hlsli` +- `Samples\Denoisers\FidelityFX_Denoiser\dx12\shaders\Material.hlsli` +- `Samples\Denoisers\FidelityFX_Denoiser\dx12\shaders\Numeric.hlsli` +- `Samples\Denoisers\FidelityFX_Denoiser\dx12\shaders\PackedData.h` +- `Samples\Denoisers\FidelityFX_Denoiser\dx12\shaders\PathTracing.cs.hlsl` +- `Samples\Denoisers\FidelityFX_Denoiser\dx12\shaders\PathTracing.hlsli` +- `Samples\Denoisers\FidelityFX_Denoiser\dx12\shaders\PathTracingData.h` +- `Samples\Denoisers\FidelityFX_Denoiser\dx12\shaders\Random.hlsli` +- `Samples\Denoisers\FidelityFX_Denoiser\dx12\shaders\Sampling.hlsli` +- `Samples\Denoisers\FidelityFX_Denoiser\dx12\shaders\Shadow.hlsli` +- `Samples\Denoisers\FidelityFX_Denoiser\dx12\shaders\Transformation.hlsli` +- `Samples\Denoisers\FidelityFX_Denoiser\dx12\shaders\Types.h` +- `Samples\Denoisers\FidelityFX_Denoiser\dx12\shaders\UnitVector.hlsli` +- `Samples\RadianceCaches\FidelityFX_NRC\dx12\config.json` +- `Samples\RadianceCaches\FidelityFX_NRC\dx12\D3DBase.h` +- `Samples\RadianceCaches\FidelityFX_NRC\dx12\D3DPipeline.cpp` +- `Samples\RadianceCaches\FidelityFX_NRC\dx12\D3DPipeline.h` +- `Samples\RadianceCaches\FidelityFX_NRC\dx12\dpiawarescaling.manifest` +- `Samples\RadianceCaches\FidelityFX_NRC\dx12\DXC.cpp` +- `Samples\RadianceCaches\FidelityFX_NRC\dx12\DXC.h` +- `Samples\RadianceCaches\FidelityFX_NRC\dx12\FidelityFX_NRC_2022.props` +- `Samples\RadianceCaches\FidelityFX_NRC\dx12\FidelityFX_NRC_2022.sln` +- `Samples\RadianceCaches\FidelityFX_NRC\dx12\FidelityFX_NRC_2022.vcxproj` +- `Samples\RadianceCaches\FidelityFX_NRC\dx12\FidelityFX_NRC_2022.vcxproj.filters` +- `Samples\RadianceCaches\FidelityFX_NRC\dx12\RenderManager.cpp` +- `Samples\RadianceCaches\FidelityFX_NRC\dx12\RenderManager.h` +- `Samples\RadianceCaches\FidelityFX_NRC\dx12\resources\cauldron.rc` +- `Samples\RadianceCaches\FidelityFX_NRC\dx12\resources\GPUOpenChip.ico` +- `Samples\RadianceCaches\FidelityFX_NRC\dx12\resources\resource.h` +- `Samples\RadianceCaches\FidelityFX_NRC\dx12\ShaderGraph.cpp` +- `Samples\RadianceCaches\FidelityFX_NRC\dx12\ShaderGraph.h` +- `Samples\RadianceCaches\FidelityFX_NRC\dx12\shaders\common\Basis.hlsl` +- `Samples\RadianceCaches\FidelityFX_NRC\dx12\shaders\common\bsdf\Beckmann.hlsl` +- `Samples\RadianceCaches\FidelityFX_NRC\dx12\shaders\common\bsdf\BSDF.hlsli` +- `Samples\RadianceCaches\FidelityFX_NRC\dx12\shaders\common\bsdf\GGX.hlsl` +- `Samples\RadianceCaches\FidelityFX_NRC\dx12\shaders\common\bsdf\Simple.hlsl` +- `Samples\RadianceCaches\FidelityFX_NRC\dx12\shaders\common\Camera.hlsl` +- `Samples\RadianceCaches\FidelityFX_NRC\dx12\shaders\common\Cel.hlsl` +- `Samples\RadianceCaches\FidelityFX_NRC\dx12\shaders\common\color\Color.hlsl` +- `Samples\RadianceCaches\FidelityFX_NRC\dx12\shaders\common\color\Grade.hlsl` +- `Samples\RadianceCaches\FidelityFX_NRC\dx12\shaders\common\Constants.hlsli` +- `Samples\RadianceCaches\FidelityFX_NRC\dx12\shaders\common\Ctor.hlsli` +- `Samples\RadianceCaches\FidelityFX_NRC\dx12\shaders\common\FrameCtx.hlsl` +- `Samples\RadianceCaches\FidelityFX_NRC\dx12\shaders\common\Half.hlsl` +- `Samples\RadianceCaches\FidelityFX_NRC\dx12\shaders\common\Hash.hlsl` +- `Samples\RadianceCaches\FidelityFX_NRC\dx12\shaders\common\Hatch.hlsl` +- `Samples\RadianceCaches\FidelityFX_NRC\dx12\shaders\common\integrator\PT.hlsl` +- `Samples\RadianceCaches\FidelityFX_NRC\dx12\shaders\common\light\Planar.hlsl` +- `Samples\RadianceCaches\FidelityFX_NRC\dx12\shaders\common\Math.hlsl` +- `Samples\RadianceCaches\FidelityFX_NRC\dx12\shaders\common\RadianceCache.hlsl` +- `Samples\RadianceCaches\FidelityFX_NRC\dx12\shaders\common\random\Halton.hlsl` +- `Samples\RadianceCaches\FidelityFX_NRC\dx12\shaders\common\random\OwenSobol.hlsl` +- `Samples\RadianceCaches\FidelityFX_NRC\dx12\shaders\common\random\PCG.hlsl` +- `Samples\RadianceCaches\FidelityFX_NRC\dx12\shaders\common\random\Random.hlsl` +- `Samples\RadianceCaches\FidelityFX_NRC\dx12\shaders\common\Ray.hlsl` +- `Samples\RadianceCaches\FidelityFX_NRC\dx12\shaders\common\texture\Simple.hlsl` +- `Samples\RadianceCaches\FidelityFX_NRC\dx12\shaders\common\tracable\Boolean.hlsl` +- `Samples\RadianceCaches\FidelityFX_NRC\dx12\shaders\common\tracable\Intersector.hlsl` +- `Samples\RadianceCaches\FidelityFX_NRC\dx12\shaders\common\tracable\KIFS.hlsl` +- `Samples\RadianceCaches\FidelityFX_NRC\dx12\shaders\common\tracable\Primitive.hlsl` +- `Samples\RadianceCaches\FidelityFX_NRC\dx12\shaders\common\tracable\SimpleCSG.hlsl` +- `Samples\RadianceCaches\FidelityFX_NRC\dx12\shaders\common\Transform.hlsl` +- `Samples\RadianceCaches\FidelityFX_NRC\dx12\shaders\common\Triplanar.hlsl` +- `Samples\RadianceCaches\FidelityFX_NRC\dx12\shaders\scene\Composite.hlsl` +- `Samples\RadianceCaches\FidelityFX_NRC\dx12\shaders\scene\Display.hlsl` +- `Samples\RadianceCaches\FidelityFX_NRC\dx12\shaders\scene\Meta.json` +- `Samples\RadianceCaches\FidelityFX_NRC\dx12\shaders\scene\Renderer.hlsl` +- `Samples\RadianceCaches\FidelityFX_NRC\dx12\utils\Assert.h` +- `Samples\RadianceCaches\FidelityFX_NRC\dx12\utils\Backtrace.cpp` +- `Samples\RadianceCaches\FidelityFX_NRC\dx12\utils\Backtrace.h` +- `Samples\RadianceCaches\FidelityFX_NRC\dx12\utils\FilesystemUtils.cpp` +- `Samples\RadianceCaches\FidelityFX_NRC\dx12\utils\FilesystemUtils.h` +- `Samples\RadianceCaches\FidelityFX_NRC\dx12\utils\HighResTimer.h` +- `Samples\RadianceCaches\FidelityFX_NRC\dx12\utils\Json.cpp` +- `Samples\RadianceCaches\FidelityFX_NRC\dx12\utils\Json.h` +- `Samples\RadianceCaches\FidelityFX_NRC\dx12\utils\Log.cpp` +- `Samples\RadianceCaches\FidelityFX_NRC\dx12\utils\Log.h` +- `Samples\RadianceCaches\FidelityFX_NRC\dx12\utils\StringUtils.cpp` +- `Samples\RadianceCaches\FidelityFX_NRC\dx12\utils\StringUtils.h` +- `Samples\RadianceCaches\FidelityFX_NRC\dx12\vcpkg.json` +- `Samples\RadianceCaches\FidelityFX_NRC\dx12\Win32.cpp` +- `Samples\RadianceCaches\FidelityFX_NRC\dx12\Win32.h` +- `Samples\Upscalers\FidelityFX_FSR\dx12\config\fsrapiconfig.json` +- `Samples\Upscalers\FidelityFX_FSR\dx12\dpiawarescaling.manifest` +- `Samples\Upscalers\FidelityFX_FSR\dx12\FidelityFX_FSR_2022.props` +- `Samples\Upscalers\FidelityFX_FSR\dx12\FidelityFX_FSR_2022.sln` +- `Samples\Upscalers\FidelityFX_FSR\dx12\FidelityFX_FSR_2022.vcxproj` +- `Samples\Upscalers\FidelityFX_FSR\dx12\FidelityFX_FSR_2022.vcxproj.filters` +- `Samples\Upscalers\FidelityFX_FSR\dx12\resources\cauldron.rc` +- `Samples\Upscalers\FidelityFX_FSR\dx12\resources\GPUOpenChip.ico` +- `Samples\Upscalers\FidelityFX_FSR\dx12\resources\resource.h` +- `Samples\Upscalers\FidelityFX_FSR\internal\fsrapirendermodule.cpp` +- `Samples\Upscalers\FidelityFX_FSR\internal\fsrapirendermodule.h` +- `Samples\Upscalers\FidelityFX_FSR\internal\fsrsettingshandler.cpp` +- `Samples\Upscalers\FidelityFX_FSR\internal\fsrsettingshandler.h` +- `Samples\Upscalers\FidelityFX_FSR\internal\main.cpp` +- `Samples\Upscalers\FidelityFX_FSR\internal\sample.cpp` +- `Samples\Upscalers\FidelityFX_FSR\internal\sample.h` +- `Samples\Upscalers\FidelityFX_FSR\vk\config\fsrapiconfig.json` +- `Samples\Upscalers\FidelityFX_FSR\vk\dpiawarescaling.manifest` +- `Samples\Upscalers\FidelityFX_FSR\vk\FidelityFX_FSR_2022.props` +- `Samples\Upscalers\FidelityFX_FSR\vk\FidelityFX_FSR_2022.sln` +- `Samples\Upscalers\FidelityFX_FSR\vk\FidelityFX_FSR_2022.vcxproj` +- `Samples\Upscalers\FidelityFX_FSR\vk\FidelityFX_FSR_2022.vcxproj.filters` +- `Samples\Upscalers\FidelityFX_FSR\vk\fsrapirendermodule.cpp` +- `Samples\Upscalers\FidelityFX_FSR\vk\resources\cauldron.rc` +- `Samples\Upscalers\FidelityFX_FSR\vk\resources\GPUOpenChip.ico` +- `Samples\Upscalers\FidelityFX_FSR\vk\resources\resource.h` +- `Tools\media_delivery\MediaDelivery.exe` +- `UpdateMedia.bat` + +are subject to the following license: + + +Copyright (C)  Advanced Micro Devices, Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/third_party/fidelityfx/README.md b/third_party/fidelityfx/README.md new file mode 100644 index 000000000..c4db24cfd --- /dev/null +++ b/third_party/fidelityfx/README.md @@ -0,0 +1,9 @@ +# AMD FSR API headers (FidelityFX SDK v2.4.0) + +Unmodified MIT-licensed headers from AMD's FidelityFX SDK, tag `v2.4.0` +(, `Kits/FidelityFX/api/include` and +`Kits/FidelityFX/upscalers/include`). See `LICENSE.md`. + +Only the headers are compiled in (`gpu/vk/vk_fsr4.cpp`). AMD's signed `amd_fidelityfx_loader_vk.dll` and +`amd_fidelityfx_upscaler_vk.dll` (from `Kits/FidelityFX/signedbin` of the same release) are not vendored: they are +loaded at run time, from `RX_FSR4_DIR` or the folder of `hookshot.exe`, when the AMD FSR 4.1 row is on. diff --git a/third_party/fidelityfx/api/include/ffx_api.h b/third_party/fidelityfx/api/include/ffx_api.h new file mode 100644 index 000000000..d351c168e --- /dev/null +++ b/third_party/fidelityfx/api/include/ffx_api.h @@ -0,0 +1,213 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2026 Advanced Micro Devices, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and /or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#pragma once + +#if defined(__cplusplus) +extern "C" { +#endif // #if defined(__cplusplus) + +#define FFX_API_ENTRY __declspec(dllexport) + +#include + +enum FfxApiReturnCodes +{ + FFX_API_RETURN_OK = 0, ///< The oparation was successful. + FFX_API_RETURN_ERROR = 1, ///< An error occurred that is not further specified. + FFX_API_RETURN_ERROR_UNKNOWN_DESCTYPE = 2, ///< The structure type given was not recognized for the function or context with which it was used. This is likely a programming error. + FFX_API_RETURN_ERROR_RUNTIME_ERROR = 3, ///< The underlying runtime (e.g. D3D12, Vulkan) or effect returned an error code. + FFX_API_RETURN_NO_PROVIDER = 4, ///< No provider was found for the given structure type. This is likely a programming error. + FFX_API_RETURN_ERROR_MEMORY = 5, ///< A memory allocation failed. + FFX_API_RETURN_ERROR_PARAMETER = 6, ///< A parameter was invalid, e.g. a null pointer, empty resource or out-of-bounds enum value. + FFX_API_RETURN_PROVIDER_NO_SUPPORT_NEW_DESCTYPE = 7, ///< The structure type given is new and not supported in the old provider. This is likely fixed with driver upgrade or effect DLL upgrade. +}; + +typedef void* ffxContext; +typedef uint32_t ffxReturnCode_t; + +#define FFX_API_EFFECT_MASK 0x00ff0000u +#define FFX_API_BACKEND_MASK 0xff000000u +#define FFX_API_EFFECT_ID_GENERAL 0x00000000u + +// Base Descriptor types +typedef uint64_t ffxStructType_t; +typedef struct ffxApiHeader +{ + ffxStructType_t type; ///< The structure type. Must always be set to the corresponding value for any structure (found nearby with a similar name). + struct ffxApiHeader* pNext; ///< Pointer to next structure, used for optional parameters and extensions. Can be null. +} ffxApiHeader; + +typedef ffxApiHeader ffxCreateContextDescHeader; +typedef ffxApiHeader ffxConfigureDescHeader; +typedef ffxApiHeader ffxQueryDescHeader; +typedef ffxApiHeader ffxDispatchDescHeader; + +// Extensions for global debug +#define FFX_API_CONFIGURE_GLOBALDEBUG_LEVEL_SILENCE 0x0000000u +#define FFX_API_CONFIGURE_GLOBALDEBUG_LEVEL_ERRORS 0x0000001u +#define FFX_API_CONFIGURE_GLOBALDEBUG_LEVEL_WARNINGS 0x0000002u +#define FFX_API_CONFIGURE_GLOBALDEBUG_LEVEL_VERBOSE 0xfffffffu + +enum FfxApiMsgType +{ + FFX_API_MESSAGE_TYPE_ERROR = 0, + FFX_API_MESSAGE_TYPE_WARNING = 1, + FFX_API_MESSAGE_TYPE_COUNT +}; + +typedef void (*ffxApiMessage)(uint32_t type, const wchar_t* message); + +#define FFX_API_CONFIGURE_DESC_TYPE_GLOBALDEBUG 7u +struct ffxConfigureDescGlobalDebug +{ + ffxConfigureDescHeader header; + uint64_t effectId; + ffxApiMessage fpMessage; ///< A pointer to a function that can receive messages from the runtime. May be null. + uint32_t debugLevel; +}; + +#define FFX_API_QUERY_DESC_TYPE_GET_VERSIONS 4u +struct ffxQueryDescGetVersions +{ + ffxQueryDescHeader header; + uint64_t createDescType; ///< Create description for the effect whose versions should be enumerated. + void* device; ///< For DX12: pointer to ID3D12Device. For VK, pointer to VkDeviceContext. + uint64_t *outputCount; ///< Input capacity of id and name arrays. Output number of returned versions. If initially zero, output is number of available versions. + uint64_t *versionIds; ///< Output array of version ids to be used as version overrides. If null, only names and count are returned. + const char** versionNames; ///< Output array of version names for display. If null, only ids and count are returned. If both this and versionIds are null, only count is returned. +}; + +#define FFX_API_DESC_TYPE_OVERRIDE_VERSION 5u +struct ffxOverrideVersion +{ + ffxApiHeader header; + uint64_t versionId; ///< Id of version to use. Must be a value returned from a query in ffxQueryDescGetVersions.versionIds array. +}; + +#define FFX_API_QUERY_DESC_TYPE_GET_PROVIDER_VERSION 6u +struct ffxQueryGetProviderVersion +{ + ffxQueryDescHeader header; + uint64_t versionId; ///< Id of provider being used for queried context. 0 if invalid. + const char* versionName; ///< Version name for display. If nullptr, the query was invalid. +}; + +// Memory allocation function. Must return a valid pointer to at least size bytes of memory aligned to hold any type. +// May return null to indicate failure. Standard library malloc fulfills this requirement. +typedef void* (*ffxAlloc)(void* pUserData, uint64_t size); + +// Memory deallocation function. May be called with null pointer as second argument. +typedef void (*ffxDealloc)(void* pUserData, void* pMem); + +typedef struct ffxAllocationCallbacks +{ + void* pUserData; + ffxAlloc alloc; + ffxDealloc dealloc; +} ffxAllocationCallbacks; + +// Creates a FFX object context. +// Depending on the desc structures provided to this function, the context will be created with the desired version and attributes. +// Non-zero return indicates error code. +// Pointers passed in desc must remain live until ffxDestroyContext is called on the context. +// MemCb may be null; the system allocator (malloc/free) will be used in this case. +FFX_API_ENTRY ffxReturnCode_t ffxCreateContext(ffxContext* context, ffxCreateContextDescHeader* desc, const ffxAllocationCallbacks* memCb); +typedef ffxReturnCode_t (*PfnFfxCreateContext)(ffxContext* context, ffxCreateContextDescHeader* desc, const ffxAllocationCallbacks* memCb); + +// Destroys an FFX object context. +// Non-zero return indicates error code. +// MemCb must be compatible with the callbacks passed into ffxCreateContext. +FFX_API_ENTRY ffxReturnCode_t ffxDestroyContext(ffxContext* context, const ffxAllocationCallbacks* memCb); +typedef ffxReturnCode_t (*PfnFfxDestroyContext)(ffxContext* context, const ffxAllocationCallbacks* memCb); + +// Configures the provided FFX object context. +// If context is null, configure operates on any global state. +// Non-zero return indicates error code. +FFX_API_ENTRY ffxReturnCode_t ffxConfigure(ffxContext* context, const ffxConfigureDescHeader* desc); +typedef ffxReturnCode_t (*PfnFfxConfigure)(ffxContext* context, const ffxConfigureDescHeader* desc); + +// Queries the provided FFX object context. +// If context is null, query operates on any global state. +// Non-zero return indicates error code. +FFX_API_ENTRY ffxReturnCode_t ffxQuery(ffxContext* context, ffxQueryDescHeader* desc); +typedef ffxReturnCode_t (*PfnFfxQuery)(ffxContext* context, ffxQueryDescHeader* desc); + +// Dispatches work on the given FFX object context defined by the dispatch descriptor. +// Non-zero return indicates error code. +FFX_API_ENTRY ffxReturnCode_t ffxDispatch(ffxContext* context, const ffxDispatchDescHeader* desc); +typedef ffxReturnCode_t (*PfnFfxDispatch)(ffxContext* context, const ffxDispatchDescHeader* desc); + +// FFX_API_EFFECT_IDs +#define FFX_API_EFFECT_ID_UPSCALE 0x00010000u +#define FFX_API_EFFECT_ID_FRAMEGENERATION 0x00020000u +#define FFX_API_EFFECT_ID_FRAMEGENERATIONSWAPCHAIN 0x00030000u +// Need to keep this ID around for the deprecated VK frame gen swapchain +#define FFX_API_EFFECT_ID_FRAMEGENERATIONSWAPCHAIN_VK 0x00040000u +#define FFX_API_EFFECT_ID_DENOISER 0x00050000u +#define FFX_API_EFFECT_ID_RADIANCECACHE 0x00060000u +#define FFX_API_EFFECT_COUNT 6u + +#define FFX_API_MAKE_EFFECT_SUB_ID(effectId, subversion) ((effectId & FFX_API_EFFECT_MASK) | (subversion & ~FFX_API_EFFECT_MASK)) + +// FFX_APID_BACKEND_IDs +#define FFX_API_BACKEND_ID_DX12 0x00000000u +#define FFX_API_BACKEND_ID_VK 0x01000000u // For new effects going forward, please use this backend ID for vulkan specifics +#define FFX_API_BACKEND_ID_XBOX 0x02000000u + +#define FFX_API_MAKE_BACKEND_SUB_ID(backendId, subversion) ((backendId & FFX_API_BACKEND_MASK) | (subversion & ~FFX_API_BACKEND_MASK)) + +// Combiner for BACKEND-specific EFFECT sub-Ids +#define FFX_API_MAKE_BACKEND_EFFECT_SUB_ID(backendId, effectId, subversion) ((subversion & ~FFX_API_EFFECT_MASK) | (effectId & FFX_API_EFFECT_MASK) | (backendId & FFX_API_BACKEND_MASK) | (subversion & ~(FFX_API_BACKEND_MASK | FFX_API_EFFECT_MASK))) + +// Pragma macros for controlling warnings so that deprecations take affect externally but can be suppressed internally. +// This is so we can maintain the API/ABI until we are ready to make the breaking change. +// These are sadly compiler specific. +#if defined(_MSC_VER) && !defined(__clang__) && !defined(__GNUC__) && !defined(__INTEL_COMPILER) +#define FFX_PRAGMA_WARNING_PUSH warning( push ) +#define FFX_PRAGMA_WARNING_POP warning( pop ) +#define FFX_PRAGMA_WARNING_DISABLE_DEPRECATIONS warning( disable: 4996 ) +#define FFX_PRAGMA_WARNING_WARN_DEPRECATIONS warning( default: 4996 ) +#elif defined(__clang__) || defined(__GNUC__) +#define FFX_PRAGMA_WARNING_PUSH GCC diagnostic push +#define FFX_PRAGMA_WARNING_POP GCC diagnostic pop +#define FFX_PRAGMA_WARNING_DISABLE_DEPRECATIONS GCC diagnostic ignored "-Wdeprecated" +#define FFX_PRAGMA_WARNING_WARN_DEPRECATIONS GCC diagnostic warning "-Wdeprecated" +#else +#define FFX_PRAGMA_WARNING_PUSH +#define FFX_PRAGMA_WARNING_POP +#define FFX_PRAGMA_WARNING_DISABLE_DEPRECATIONS +#endif + +#define FFX_DEPRECATION(message) [[deprecated(message)]] + +#define FFX_API_CONFIGURE_DESC_TYPE_GLOBALDEBUG1 0x0000001u +struct FFX_DEPRECATION("Use ffxConfigureDescGlobalDebug instead of ffxConfigureDescGlobalDebug1.") ffxConfigureDescGlobalDebug1 +{ + ffxConfigureDescHeader header; + ffxApiMessage fpMessage; + uint32_t debugLevel; +}; + +#if defined(__cplusplus) +} +#endif // #if defined(__cplusplus) diff --git a/third_party/fidelityfx/api/include/ffx_api_types.h b/third_party/fidelityfx/api/include/ffx_api_types.h new file mode 100644 index 000000000..380c4c0a1 --- /dev/null +++ b/third_party/fidelityfx/api/include/ffx_api_types.h @@ -0,0 +1,257 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2026 Advanced Micro Devices, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and /or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#pragma once + +#include +#include + +/// An enumeration of surface formats. Needs to match enum FfxApiSurfaceFormat +enum FfxApiSurfaceFormat +{ + FFX_API_SURFACE_FORMAT_UNKNOWN, ///< Unknown format + FFX_API_SURFACE_FORMAT_R32G32B32A32_TYPELESS, ///< 32 bit per channel, 4 channel typeless format + FFX_API_SURFACE_FORMAT_R32G32B32A32_UINT, ///< 32 bit per channel, 4 channel uint format + FFX_API_SURFACE_FORMAT_R32G32B32A32_FLOAT, ///< 32 bit per channel, 4 channel float format + FFX_API_SURFACE_FORMAT_R16G16B16A16_FLOAT, ///< 16 bit per channel, 4 channel float format + FFX_API_SURFACE_FORMAT_R32G32B32_FLOAT, ///< 32 bit per channel, 3 channel float format + FFX_API_SURFACE_FORMAT_R32G32_FLOAT, ///< 32 bit per channel, 2 channel float format + FFX_API_SURFACE_FORMAT_R8_UINT, ///< 8 bit per channel, 1 channel float format + FFX_API_SURFACE_FORMAT_R32_UINT, ///< 32 bit per channel, 1 channel float format + FFX_API_SURFACE_FORMAT_R8G8B8A8_TYPELESS, ///< 8 bit per channel, 4 channel typeless format + FFX_API_SURFACE_FORMAT_R8G8B8A8_UNORM, ///< 8 bit per channel, 4 channel unsigned normalized format + FFX_API_SURFACE_FORMAT_R8G8B8A8_SNORM, ///< 8 bit per channel, 4 channel signed normalized format + FFX_API_SURFACE_FORMAT_R8G8B8A8_SRGB, ///< 8 bit per channel, 4 channel srgb normalized + FFX_API_SURFACE_FORMAT_B8G8R8A8_TYPELESS, ///< 8 bit per channel, 4 channel typeless format + FFX_API_SURFACE_FORMAT_B8G8R8A8_UNORM, ///< 8 bit per channel, 4 channel unsigned normalized format + FFX_API_SURFACE_FORMAT_B8G8R8A8_SRGB, ///< 8 bit per channel, 4 channel srgb normalized + FFX_API_SURFACE_FORMAT_R11G11B10_FLOAT, ///< 32 bit 3 channel float format + FFX_API_SURFACE_FORMAT_R10G10B10A2_UNORM, ///< 10 bit per 3 channel, 2 bit for 1 channel normalized format + FFX_API_SURFACE_FORMAT_R16G16_FLOAT, ///< 16 bit per channel, 2 channel float format + FFX_API_SURFACE_FORMAT_R16G16_UINT, ///< 16 bit per channel, 2 channel unsigned int format + FFX_API_SURFACE_FORMAT_R16G16_SINT, ///< 16 bit per channel, 2 channel signed int format + FFX_API_SURFACE_FORMAT_R16_FLOAT, ///< 16 bit per channel, 1 channel float format + FFX_API_SURFACE_FORMAT_R16_UINT, ///< 16 bit per channel, 1 channel unsigned int format + FFX_API_SURFACE_FORMAT_R16_UNORM, ///< 16 bit per channel, 1 channel unsigned normalized format + FFX_API_SURFACE_FORMAT_R16_SNORM, ///< 16 bit per channel, 1 channel signed normalized format + FFX_API_SURFACE_FORMAT_R8_UNORM, ///< 8 bit per channel, 1 channel unsigned normalized format + FFX_API_SURFACE_FORMAT_R8G8_UNORM, ///< 8 bit per channel, 2 channel unsigned normalized format + FFX_API_SURFACE_FORMAT_R8G8_UINT, ///< 8 bit per channel, 2 channel unsigned integer format + FFX_API_SURFACE_FORMAT_R32_FLOAT, ///< 32 bit per channel, 1 channel float format + FFX_API_SURFACE_FORMAT_R9G9B9E5_SHAREDEXP, ///< 9 bit per channel, 5 bit exponent format + + FFX_API_SURFACE_FORMAT_R16G16B16A16_TYPELESS, ///< 16 bit per channel, 4 channel typeless format + FFX_API_SURFACE_FORMAT_R32G32_TYPELESS, ///< 32 bit per channel, 2 channel typeless format + FFX_API_SURFACE_FORMAT_R10G10B10A2_TYPELESS, ///< 10 bit per 3 channel, 2 bit for 1 channel typeless format + FFX_API_SURFACE_FORMAT_R16G16_TYPELESS, ///< 16 bit per channel, 2 channel typless format + FFX_API_SURFACE_FORMAT_R16_TYPELESS, ///< 16 bit per channel, 1 channel typeless format + FFX_API_SURFACE_FORMAT_R8_TYPELESS, ///< 8 bit per channel, 1 channel typeless format + FFX_API_SURFACE_FORMAT_R8G8_TYPELESS, ///< 8 bit per channel, 2 channel typeless format + FFX_API_SURFACE_FORMAT_R32_TYPELESS, ///< 32 bit per channel, 1 channel typeless format + FFX_API_SURFACE_FORMAT_R32G32_UINT, ///< 32 bit per channel, 2 channel uint format + + FFX_API_SURFACE_FORMAT_R8_SNORM, ///< 8 bit per channel, 1 channel signed normalized format +}; + +/// An enumeration of resource usage. +enum FfxApiResourceUsage +{ + FFX_API_RESOURCE_USAGE_READ_ONLY = 0, ///< No usage flags indicate a resource is read only. + FFX_API_RESOURCE_USAGE_RENDERTARGET = (1<<0), ///< Indicates a resource will be used as render target. + FFX_API_RESOURCE_USAGE_UAV = (1<<1), ///< Indicates a resource will be used as UAV. + FFX_API_RESOURCE_USAGE_DEPTHTARGET = (1<<2), ///< Indicates a resource will be used as depth target. + FFX_API_RESOURCE_USAGE_INDIRECT = (1<<3), ///< Indicates a resource will be used as indirect argument buffer + FFX_API_RESOURCE_USAGE_ARRAYVIEW = (1<<4), ///< Indicates a resource that will generate array views. Works on 2D and cubemap textures + FFX_API_RESOURCE_USAGE_STENCILTARGET = (1<<5), ///< Indicates a resource will be used as stencil target. + + FFX_API_RESOURCE_USAGE_DCC_RENDERTARGET = (1<<15), ///< Indicates a resource that should specify optimal render target memory access flags (for console use) +}; + + +/// An enumeration of resource states. +enum FfxApiResourceState +{ + FFX_API_RESOURCE_STATE_COMMON = (1 << 0), + FFX_API_RESOURCE_STATE_UNORDERED_ACCESS = (1 << 1), ///< Indicates a resource is in the state to be used as UAV. + FFX_API_RESOURCE_STATE_COMPUTE_READ = (1 << 2), ///< Indicates a resource is in the state to be read by compute shaders. + FFX_API_RESOURCE_STATE_PIXEL_READ = (1 << 3), ///< Indicates a resource is in the state to be read by pixel shaders. + FFX_API_RESOURCE_STATE_PIXEL_COMPUTE_READ = (FFX_API_RESOURCE_STATE_PIXEL_READ | FFX_API_RESOURCE_STATE_COMPUTE_READ), ///< Indicates a resource is in the state to be read by pixel or compute shaders. + FFX_API_RESOURCE_STATE_COPY_SRC = (1 << 4), ///< Indicates a resource is in the state to be used as source in a copy command. + FFX_API_RESOURCE_STATE_COPY_DEST = (1 << 5), ///< Indicates a resource is in the state to be used as destination in a copy command. + FFX_API_RESOURCE_STATE_GENERIC_READ = (FFX_API_RESOURCE_STATE_COPY_SRC | FFX_API_RESOURCE_STATE_COMPUTE_READ), ///< Indicates a resource is in generic (slow) read state. + FFX_API_RESOURCE_STATE_INDIRECT_ARGUMENT = (1 << 6), ///< Indicates a resource is in the state to be used as an indirect command argument + FFX_API_RESOURCE_STATE_PRESENT = (1 << 7), ///< Indicates a resource is in the state to be used to present to the swap chain + FFX_API_RESOURCE_STATE_RENDER_TARGET = (1 << 8), ///< Indicates a resource is in the state to be used as render target + FFX_API_RESOURCE_STATE_DEPTH_ATTACHMENT = (1 << 9), ///< Indicates a resource is in the state to be used as depth attachment +}; + +/// An enumeration of surface dimensions. +enum FfxApiResourceDimension +{ + FFX_API_RESOURCE_DIMENSION_TEXTURE_1D, ///< A resource with a single dimension. + FFX_API_RESOURCE_DIMENSION_TEXTURE_2D, ///< A resource with two dimensions. +}; + +/// An enumeration of resource flags. +enum FfxApiResourceFlags +{ + FFX_API_RESOURCE_FLAGS_NONE = 0, ///< No flags. + FFX_API_RESOURCE_FLAGS_ALIASABLE = (1 << 0), ///< A bit indicating a resource does not need to persist across frames. + FFX_API_RESOURCE_FLAGS_UNDEFINED = (1 << 1), ///< Special case flag used internally when importing resources that require additional setup +}; + +// An enumeration for different resource types +enum FfxApiResourceType +{ + FFX_API_RESOURCE_TYPE_BUFFER, ///< The resource is a buffer. + FFX_API_RESOURCE_TYPE_TEXTURE1D, ///< The resource is a 1-dimensional texture. + FFX_API_RESOURCE_TYPE_TEXTURE2D, ///< The resource is a 2-dimensional texture. + FFX_API_RESOURCE_TYPE_TEXTURE_CUBE, ///< The resource is a cube map. + FFX_API_RESOURCE_TYPE_TEXTURE3D, ///< The resource is a 3-dimensional texture. +}; + +enum FfxApiBackbufferTransferFunction +{ + FFX_API_BACKBUFFER_TRANSFER_FUNCTION_SRGB, + FFX_API_BACKBUFFER_TRANSFER_FUNCTION_PQ, + FFX_API_BACKBUFFER_TRANSFER_FUNCTION_SCRGB +}; + +/// A structure encapsulating a 2-dimensional point, using 32bit unsigned integers. +struct FfxApiDimensions2D +{ + uint32_t width; ///< The width of a 2-dimensional range. + uint32_t height; ///< The height of a 2-dimensional range. +}; + +/// A structure encapsulating a 2-dimensional set of floating point coordinates. +struct FfxApiFloatCoords2D +{ + float x; ///< The x coordinate of a 2-dimensional point. + float y; ///< The y coordinate of a 2-dimensional point. +}; + +/// A structure encapsulating a 3-dimensional set of floating point coordinates. +struct FfxApiFloatCoords3D +{ + float x; ///< The x coordinate of a 3-dimensional point. + float y; ///< The y coordinate of a 3-dimensional point. + float z; ///< The z coordinate of a 3-dimensional point. +}; + +/// A structure encapsulating a 2-dimensional rect. +struct FfxApiRect2D +{ + int32_t left; + int32_t top; + int32_t width; + int32_t height; +}; + +/// A structure describing a resource. +/// +/// @ingroup SDKTypes +struct FfxApiResourceDescription +{ + uint32_t type; ///< The type of the resource. + uint32_t format; ///< The surface format. + union { + uint32_t width; ///< The width of the texture resource. + uint32_t size; ///< The size of the buffer resource. + }; + + union { + uint32_t height; ///< The height of the texture resource. + uint32_t stride; ///< The stride of the buffer resource. + }; + + union { + uint32_t depth; ///< The depth of the texture resource. + uint32_t alignment; ///< The alignment of the buffer resource. + }; + + uint32_t mipCount; ///< Number of mips (or 0 for full mipchain). + uint32_t flags; ///< A set of resource flags. + uint32_t usage; ///< Resource usage flags. +}; + +#define FFX_RESOURCE_NAME_SIZE 64 + +struct FfxApiResource +{ + void* resource; + struct FfxApiResourceDescription description; + uint32_t state; +}; + +//struct definition matches FfxApiEffectMemoryUsage +typedef struct FfxApiEffectMemoryUsage +{ + uint64_t totalUsageInBytes; + uint64_t aliasableUsageInBytes; +} FfxApiEffectMemoryUsage; + +/// A structure describing a constant buffer allocation. +/// +/// @ingroup SDKTypes +typedef struct FfxApiConstantBufferAllocation +{ + struct FfxApiResource resource; ///< The resource representing the constant buffer resource. + uint64_t handle; ///< The binding handle for the constant buffer + +} FfxApiConstantBufferAllocation; + +/// A function definition for a constant buffer allocation callback +/// Used to provide a constant buffer allocator to the calling backend +/// +/// @param [in] data The constant buffer data. +/// @param [in] dataSize The size of the constant buffer data. +/// +/// @ingroup SDKTypes +typedef FfxApiConstantBufferAllocation(*FfxApiConstantBufferAllocator)(void* data, const uint64_t dataSize); + +/// A 4-component floating point vector +typedef struct FfxApiFloat4 +{ + float x; + float y; + float z; + float w; +} FfxApiFloat4; + +/// A 4x4 matrix in row-major layout with row-vector convention. +/// This is the canonical format expected by FFX APIs. +/// +/// Memory layout: rows[row_index][column_index] +/// Mathematical convention: v * M (row vector multiplied by matrix) +typedef struct FfxApiMatrix4x4 +{ + FfxApiFloat4 rows[4]; ///< Four rows of the matrix. Access as rows[row].x, rows[row].y etc. +} FfxApiMatrix4x4; + +/// An inclusive floating-point interval [min, max]. +/// Valid instances must satisfy min <= max. +typedef struct FfxApiFloatBounds +{ + float min; ///< Lower bound of the interval. + float max; ///< Upper bound of the interval. +} FfxApiFloatBounds; diff --git a/third_party/fidelityfx/api/include/vk/ffx_api_vk.h b/third_party/fidelityfx/api/include/vk/ffx_api_vk.h new file mode 100644 index 000000000..1bbe1d9e4 --- /dev/null +++ b/third_party/fidelityfx/api/include/vk/ffx_api_vk.h @@ -0,0 +1,308 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2026 Advanced Micro Devices, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and /or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#pragma once +#include "../ffx_api.h" +#include "../ffx_api_types.h" +#include + +/// FFX specific callback type when submitting a command buffer to a queue. +typedef VkResult(*PFN_vkQueueSubmitFFXAPI)(uint32_t submitCount, const VkSubmitInfo* pSubmits, VkFence fence); + +/// Helper stucture +struct VkQueueInfoFFXAPI +{ + VkQueue queue; ///< the vulkan queue + uint32_t familyIndex; ///< the queue family index, that will be used to perform queue family ownership transfer + PFN_vkQueueSubmitFFXAPI submitFunc; ///< an optional submit function in case there might be some concurrent submissions +}; + +// We need to keep this one alive because of VK verison of FSR3.1.4 +// Deprecated version of the VK backend create context descriptor, please use the non-deprecated version below. +#define FFX_API_CREATE_CONTEXT_DESC_TYPE_BACKEND_VK_DEPRECATED 0x0000003u +struct ffxCreateBackendVKDesc_DEPRECATED +{ + ffxCreateContextDescHeader header; + VkDevice vkDevice; ///< the logical device used by the program. + VkPhysicalDevice vkPhysicalDevice; ///< the physical device used by the program. + PFN_vkGetDeviceProcAddr vkDeviceProcAddr; ///< function pointer to get device procedure addresses +}; + +/// Convenience structure to hold all VK-related device information. +typedef struct VkDeviceContext { + VkDevice vkDevice; ///< The Vulkan device + VkPhysicalDevice vkPhysicalDevice; ///< The Vulkan physical device + PFN_vkGetDeviceProcAddr vkDeviceProcAddr; ///< The device's function address table +} VkDeviceContext; + +#define FFX_API_CREATE_CONTEXT_DESC_TYPE_BACKEND_VK FFX_API_MAKE_BACKEND_SUB_ID(FFX_API_BACKEND_ID_VK, 0x03) +struct ffxCreateBackendVKDesc +{ + ffxCreateContextDescHeader header; + VkDeviceContext deviceContext; ///< the VK device information used by the program. +}; + +/// Resource allocation callback function. (TODO) +typedef ffxReturnCode_t(*PfnFfxResourceAllocatorFunc)(uint32_t effectId/*, + D3D12_RESOURCE_STATES initialState, + const D3D12_HEAP_PROPERTIES* pHeapProps, + const D3D12_RESOURCE_DESC* pD3DDesc, + const FfxApiResourceDescription* pFfxDesc, + const D3D12_CLEAR_VALUE* pOptimizedClear, + ID3D12Resource** ppD3DResource*/); + +/// Resource destruction callback function. (TODO) +typedef ffxReturnCode_t(*PfnFfxResourceDeallocatorFunc)(uint32_t effectId/*, ID3D12Resource* pResource*/); + +#define FFX_API_CREATE_CONTEXT_DESC_TYPE_BACKEND_VK_ALLOCATION_CALLBACKS FFX_API_MAKE_BACKEND_SUB_ID(FFX_API_BACKEND_ID_VK, 0x04) +struct ffxCreateBackendVKAllocationCallbacksDesc +{ + ffxCreateContextDescHeader header; + PfnFfxResourceAllocatorFunc pfnFfxResourceAllocator; ///< Resource allocation function (can be null) <------- NOT IMPL YET, SEE DX12/XBOX IMPL + PfnFfxResourceDeallocatorFunc pfnFfxResourceDeallocator; ///< Resource deallocation function (can be null) <------- NOT IMPL YET, SEE DX12/XBOX IMPL + FfxApiConstantBufferAllocator pfnFfxConstantBufferAllocator; ///< Constant buffer allocation function (can be null) +}; + +#if defined(__cplusplus) + +static inline uint32_t ffxApiGetSurfaceFormatVK(VkFormat fmt) +{ + switch (fmt) + { + case VK_FORMAT_R32G32B32A32_SFLOAT: + return FFX_API_SURFACE_FORMAT_R32G32B32A32_FLOAT; + case VK_FORMAT_R32G32B32_SFLOAT: + return FFX_API_SURFACE_FORMAT_R32G32B32_FLOAT; + case VK_FORMAT_R32G32B32A32_UINT: + return FFX_API_SURFACE_FORMAT_R32G32B32A32_UINT; + case VK_FORMAT_R16G16B16A16_SFLOAT: + return FFX_API_SURFACE_FORMAT_R16G16B16A16_FLOAT; + case VK_FORMAT_R32G32_SFLOAT: + return FFX_API_SURFACE_FORMAT_R32G32_FLOAT; + case VK_FORMAT_R32_UINT: + case VK_FORMAT_D24_UNORM_S8_UINT: + case VK_FORMAT_X8_D24_UNORM_PACK32: + return FFX_API_SURFACE_FORMAT_R32_UINT; + case VK_FORMAT_R8G8B8A8_UNORM: + return FFX_API_SURFACE_FORMAT_R8G8B8A8_UNORM; + case VK_FORMAT_R8G8B8A8_SNORM: + return FFX_API_SURFACE_FORMAT_R8G8B8A8_SNORM; + case VK_FORMAT_R8G8B8A8_SRGB: + return FFX_API_SURFACE_FORMAT_R8G8B8A8_SRGB; + case VK_FORMAT_B8G8R8A8_UNORM: + return FFX_API_SURFACE_FORMAT_B8G8R8A8_UNORM; + case VK_FORMAT_B8G8R8A8_SRGB: + return FFX_API_SURFACE_FORMAT_B8G8R8A8_SRGB; + case VK_FORMAT_B10G11R11_UFLOAT_PACK32: + return FFX_API_SURFACE_FORMAT_R11G11B10_FLOAT; + case VK_FORMAT_A2B10G10R10_UNORM_PACK32: + return FFX_API_SURFACE_FORMAT_R10G10B10A2_UNORM; + case VK_FORMAT_R16G16_SFLOAT: + return FFX_API_SURFACE_FORMAT_R16G16_FLOAT; + case VK_FORMAT_R16G16_UINT: + return FFX_API_SURFACE_FORMAT_R16G16_UINT; + case VK_FORMAT_R16G16_SINT: + return FFX_API_SURFACE_FORMAT_R16G16_SINT; + case VK_FORMAT_R16_SFLOAT: + return FFX_API_SURFACE_FORMAT_R16_FLOAT; + case VK_FORMAT_R16_UINT: + return FFX_API_SURFACE_FORMAT_R16_UINT; + case VK_FORMAT_R16_UNORM: + case VK_FORMAT_D16_UNORM: + case VK_FORMAT_D16_UNORM_S8_UINT: + return FFX_API_SURFACE_FORMAT_R16_UNORM; + case VK_FORMAT_R16_SNORM: + return FFX_API_SURFACE_FORMAT_R16_SNORM; + case VK_FORMAT_R8_UNORM: + return FFX_API_SURFACE_FORMAT_R8_UNORM; + case VK_FORMAT_R8_SNORM: + return FFX_API_SURFACE_FORMAT_R8_SNORM; + case VK_FORMAT_R8_UINT: + case VK_FORMAT_S8_UINT: + return FFX_API_SURFACE_FORMAT_R8_UINT; + case VK_FORMAT_R8G8_UNORM: + return FFX_API_SURFACE_FORMAT_R8G8_UNORM; + case VK_FORMAT_R8G8_UINT: + return FFX_API_SURFACE_FORMAT_R8G8_UINT; + case VK_FORMAT_R32_SFLOAT: + case VK_FORMAT_D32_SFLOAT: + case VK_FORMAT_D32_SFLOAT_S8_UINT: + return FFX_API_SURFACE_FORMAT_R32_FLOAT; + case VK_FORMAT_E5B9G9R9_UFLOAT_PACK32: + return FFX_API_SURFACE_FORMAT_R9G9B9E5_SHAREDEXP; + case VK_FORMAT_UNDEFINED: + return FFX_API_SURFACE_FORMAT_UNKNOWN; + + default: + // NOTE: we do not support typeless formats here + //FFX_ASSERT_MESSAGE(false, "Format not yet supported"); + return FFX_API_SURFACE_FORMAT_UNKNOWN; + } +} + +static inline uint32_t ffxApiGetSurfaceFormatToGamma(uint32_t fmt) +{ + switch (fmt) + { + case (FFX_API_SURFACE_FORMAT_R8G8B8A8_UNORM): + return FFX_API_SURFACE_FORMAT_R8G8B8A8_SRGB; + case (FFX_API_SURFACE_FORMAT_B8G8R8A8_UNORM): + return FFX_API_SURFACE_FORMAT_B8G8R8A8_SRGB; + default: + return fmt; + } +} + +static inline bool ffxApiIsDepthFormat(VkFormat fmt) +{ + switch (fmt) + { + case VK_FORMAT_D16_UNORM: + case VK_FORMAT_X8_D24_UNORM_PACK32: + case VK_FORMAT_D32_SFLOAT: + case VK_FORMAT_D16_UNORM_S8_UINT: + case VK_FORMAT_D24_UNORM_S8_UINT: + case VK_FORMAT_D32_SFLOAT_S8_UINT: + return true; + + default: + return false; + } +} + +static inline bool ffxApiIsStencilFormat(VkFormat fmt) +{ + switch (fmt) + { + case VK_FORMAT_S8_UINT: + case VK_FORMAT_D16_UNORM_S8_UINT: + case VK_FORMAT_D24_UNORM_S8_UINT: + case VK_FORMAT_D32_SFLOAT_S8_UINT: + return true; + + default: + return false; + } +} + +static inline FfxApiResourceDescription ffxApiGetBufferResourceDescriptionVK(const VkBuffer buffer, + const VkBufferCreateInfo createInfo, + uint32_t additionalUsages) +{ + FfxApiResourceDescription resourceDescription = {}; + + // This is valid + if (buffer == VK_NULL_HANDLE) + return resourceDescription; + + resourceDescription.flags = FFX_API_RESOURCE_FLAGS_NONE; + resourceDescription.usage = additionalUsages; + resourceDescription.size = (uint32_t)createInfo.size; + resourceDescription.stride = 0; + resourceDescription.format = FFX_API_SURFACE_FORMAT_UNKNOWN; + + if ((createInfo.usage & VK_BUFFER_USAGE_STORAGE_BUFFER_BIT) != 0) + resourceDescription.usage |= FFX_API_RESOURCE_USAGE_UAV; + if ((createInfo.usage & VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT) != 0) + resourceDescription.usage |= FFX_API_RESOURCE_USAGE_INDIRECT; + + // What should we initialize this to?? No case for this yet + resourceDescription.depth = 0; + resourceDescription.mipCount = 0; + + // Set the type + resourceDescription.type = FFX_API_RESOURCE_TYPE_BUFFER; + + return resourceDescription; +} + +static inline FfxApiResourceDescription ffxApiGetImageResourceDescriptionVK(const VkImage image, const VkImageCreateInfo createInfo, uint32_t additionalUsages) +{ + FfxApiResourceDescription resourceDescription = {}; + + // This is valid + if (image == VK_NULL_HANDLE) + return resourceDescription; + + // Set flags properly for resource registration + resourceDescription.flags = FFX_API_RESOURCE_FLAGS_NONE; + resourceDescription.usage = FFX_API_RESOURCE_USAGE_READ_ONLY; + + // Check for depth stencil use + if (ffxApiIsDepthFormat(createInfo.format)) + resourceDescription.usage |= FFX_API_RESOURCE_USAGE_DEPTHTARGET; + if (ffxApiIsStencilFormat(createInfo.format)) + resourceDescription.usage |= FFX_API_RESOURCE_USAGE_STENCILTARGET; + + // Unordered access use + if ((createInfo.usage & VK_IMAGE_USAGE_STORAGE_BIT) != 0) + resourceDescription.usage |= FFX_API_RESOURCE_USAGE_UAV; + + // Resource-specific supplemental use flags + resourceDescription.usage |= additionalUsages; + + resourceDescription.width = createInfo.extent.width; + resourceDescription.height = createInfo.extent.height; + resourceDescription.mipCount = createInfo.mipLevels; + resourceDescription.format = ffxApiGetSurfaceFormatVK(createInfo.format); + + // if the mutable flag is present, assume that the real format is sRGB + if ((createInfo.flags & VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT) != 0) + resourceDescription.format = ffxApiGetSurfaceFormatToGamma(resourceDescription.format); + + switch (createInfo.imageType) + { + case VK_IMAGE_TYPE_1D: + resourceDescription.type = FFX_API_RESOURCE_TYPE_TEXTURE1D; + break; + case VK_IMAGE_TYPE_2D: + resourceDescription.depth = createInfo.arrayLayers; + if ((additionalUsages & FFX_API_RESOURCE_USAGE_ARRAYVIEW) != 0) + resourceDescription.type = FFX_API_RESOURCE_TYPE_TEXTURE2D; + else if ((createInfo.flags & VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT) != 0) + resourceDescription.type = FFX_API_RESOURCE_TYPE_TEXTURE_CUBE; + else + resourceDescription.type = FFX_API_RESOURCE_TYPE_TEXTURE2D; + break; + case VK_IMAGE_TYPE_3D: + resourceDescription.depth = createInfo.extent.depth; + resourceDescription.type = FFX_API_RESOURCE_TYPE_TEXTURE3D; + break; + default: + //FFX_ASSERT_MESSAGE(false, "FFXInterface: VK: Unsupported texture dimension requested. Please implement."); + break; + } + + return resourceDescription; +} + +static inline FfxApiResource ffxApiGetResourceVK(void* vkResource, FfxApiResourceDescription ffxResDescription, uint32_t state) +{ + FfxApiResource resource = {}; + resource.resource = vkResource; + resource.state = state; + resource.description = ffxResDescription; + + return resource; +} + +#endif diff --git a/third_party/fidelityfx/upscalers/include/ffx_upscale.h b/third_party/fidelityfx/upscalers/include/ffx_upscale.h new file mode 100644 index 000000000..9d4a3e5f6 --- /dev/null +++ b/third_party/fidelityfx/upscalers/include/ffx_upscale.h @@ -0,0 +1,230 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2026 Advanced Micro Devices, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and /or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#pragma once +#include "../../api/include/ffx_api.h" +#include "../../api/include/ffx_api_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define FFX_UPSCALER_VERSION_MAJOR 4 +#define FFX_UPSCALER_VERSION_MINOR 1 +#define FFX_UPSCALER_VERSION_PATCH 2 + +#define FFX_UPSCALER_MAKE_VERSION(major, minor, patch) (((major) << 22) | ((minor) << 12) | (patch)) +#define FFX_UPSCALER_VERSION FFX_UPSCALER_MAKE_VERSION(FFX_UPSCALER_VERSION_MAJOR, FFX_UPSCALER_VERSION_MINOR, FFX_UPSCALER_VERSION_PATCH) + +enum FfxApiUpscaleQualityMode +{ + FFX_UPSCALE_QUALITY_MODE_NATIVEAA = 0, ///< Perform upscaling with a per-dimension upscaling ratio of 1.0x. + FFX_UPSCALE_QUALITY_MODE_QUALITY = 1, ///< Perform upscaling with a per-dimension upscaling ratio of 1.5x. + FFX_UPSCALE_QUALITY_MODE_BALANCED = 2, ///< Perform upscaling with a per-dimension upscaling ratio of 1.7x. + FFX_UPSCALE_QUALITY_MODE_PERFORMANCE = 3, ///< Perform upscaling with a per-dimension upscaling ratio of 2.0x. + FFX_UPSCALE_QUALITY_MODE_ULTRA_PERFORMANCE = 4 ///< Perform upscaling with a per-dimension upscaling ratio of 3.0x. +}; + +enum FfxApiCreateContextUpscaleFlags +{ + FFX_UPSCALE_ENABLE_HIGH_DYNAMIC_RANGE = (1 << 0), ///< A bit indicating if the input color data provided is using a high-dynamic range. + FFX_UPSCALE_ENABLE_DISPLAY_RESOLUTION_MOTION_VECTORS = (1 << 1), ///< A bit indicating if the motion vectors are rendered at display resolution. + FFX_UPSCALE_ENABLE_MOTION_VECTORS_JITTER_CANCELLATION = (1 << 2), ///< A bit indicating that the motion vectors have the jittering pattern applied to them. + FFX_UPSCALE_ENABLE_DEPTH_INVERTED = (1 << 3), ///< A bit indicating that the input depth buffer data provided is inverted [1..0]. + FFX_UPSCALE_ENABLE_DEPTH_INFINITE = (1 << 4), ///< A bit indicating that the input depth buffer data provided is using an infinite far plane. + FFX_UPSCALE_ENABLE_AUTO_EXPOSURE = (1 << 5), ///< A bit indicating if automatic exposure should be applied to input color data. + FFX_UPSCALE_ENABLE_DYNAMIC_RESOLUTION = (1 << 6), ///< A bit indicating that the application uses dynamic resolution scaling. + FFX_UPSCALE_ENABLE_DEBUG_CHECKING = (1 << 7), ///< A bit indicating that the runtime should check some API values and report issues. + FFX_UPSCALE_ENABLE_NON_LINEAR_COLORSPACE = (1 << 8), ///< A bit indicating that the color resource contains perceptual (gamma corrected) colors + FFX_UPSCALE_ENABLE_DEBUG_VISUALIZATION = (1 << 9), ///< A bit indicating if debug visualization is allowed. (memory consumption could increase) +}; + +enum FfxApiDispatchFsrUpscaleFlags +{ + FFX_UPSCALE_FLAG_DRAW_DEBUG_VIEW = (1 << 0), ///< A bit indicating that the output resource will contain debug views with relevant information. + FFX_UPSCALE_FLAG_NON_LINEAR_COLOR_SRGB = (1 << 1), ///< A bit indicating that the input color resource contains perceptual sRGB colors + FFX_UPSCALE_FLAG_NON_LINEAR_COLOR_PQ = (1 << 2), ///< A bit indicating that the input color resource contains perceptual PQ colors +}; + +enum FfxApiDispatchUpscaleAutoreactiveFlags +{ + FFX_UPSCALE_AUTOREACTIVEFLAGS_APPLY_TONEMAP = (1 << 0), ///< Apply tonemapping function prior to calculating reactivity. + FFX_UPSCALE_AUTOREACTIVEFLAGS_APPLY_INVERSETONEMAP = (1 << 1), ///< Apply inverse tonemapping function prior to calculating reactivity. + FFX_UPSCALE_AUTOREACTIVEFLAGS_APPLY_THRESHOLD = (1 << 2), ///< Compare to a threshold value and only record reactivity above the threshold. + FFX_UPSCALE_AUTOREACTIVEFLAGS_USE_COMPONENTS_MAX = (1 << 3), ///< When enabled use the max. component value, otherwise use the length to calculate reactivity. +}; + +#define FFX_API_CREATE_CONTEXT_DESC_TYPE_UPSCALE FFX_API_MAKE_EFFECT_SUB_ID(FFX_API_EFFECT_ID_UPSCALE, 0x00) +struct ffxCreateContextDescUpscale +{ + ffxCreateContextDescHeader header; ///< Header descriptor, use type FFX_API_CREATE_CONTEXT_DESC_TYPE_UPSCALE. + uint32_t flags; ///< Zero or a combination of values from FfxApiCreateContextUpscaleFlags. + struct FfxApiDimensions2D maxRenderSize; ///< The maximum size that rendering will be performed at. + struct FfxApiDimensions2D maxUpscaleSize; ///< The size of the presentation resolution targeted by the upscaling process. + ffxApiMessage fpMessage; ///< A pointer to a function that can receive messages from the runtime. May be null. +}; + +#define FFX_API_DISPATCH_DESC_TYPE_UPSCALE FFX_API_MAKE_EFFECT_SUB_ID(FFX_API_EFFECT_ID_UPSCALE, 0x01) +struct ffxDispatchDescUpscale +{ + ffxDispatchDescHeader header; ///< Header descriptor, use type FFX_API_DISPATCH_DESC_TYPE_UPSCALE. + void* commandList; ///< Command list to record upscaling rendering commands into. + struct FfxApiResource color; ///< Color buffer for the current frame (at render resolution). + struct FfxApiResource depth; ///< 32bit depth values for the current frame (at render resolution). + struct FfxApiResource motionVectors; ///< 2-dimensional motion vectors (at render resolution if FFX_FSR_ENABLE_DISPLAY_RESOLUTION_MOTION_VECTORS is not set). + struct FfxApiResource exposure; ///< Optional resource containing a 1x1 exposure value. + struct FfxApiResource reactive; ///< Optional resource containing alpha value of reactive objects in the scene. + struct FfxApiResource transparencyAndComposition; ///< Optional resource containing alpha value of special objects in the scene. + struct FfxApiResource output; ///< Output color buffer for the current frame (at presentation resolution). + struct FfxApiFloatCoords2D jitterOffset; ///< The subpixel jitter offset applied to the camera. + struct FfxApiFloatCoords2D motionVectorScale; ///< The scale factor to convert motion vectors to pixel space. Internally: pixelSpaceMV = motionVector * motionVectorScale. Set to renderSize if motion vectors are in UV space [0,1], or to (1.0, 1.0) if motion vectors are already in pixel space. When using display-resolution motion vectors, set to displaySize. + struct FfxApiDimensions2D renderSize; ///< The resolution that was used for rendering the input resources. + struct FfxApiDimensions2D upscaleSize; ///< The resolution that the upscaler will upscale to (optional, assumed maxUpscaleSize otherwise). + bool enableSharpening; ///< Enable an additional sharpening pass. + float sharpness; ///< The sharpness value between 0 and 1, where 0 is no additional sharpness and 1 is maximum additional sharpness. + float frameTimeDelta; ///< The time elapsed since the last frame (expressed in milliseconds). + float preExposure; ///< The pre exposure value (must be > 0.0f) + bool reset; ///< A boolean value which when set to true, indicates the camera has moved discontinuously. + float cameraNear; ///< The distance to the near plane of the camera. + float cameraFar; ///< The distance to the far plane of the camera. + float cameraFovAngleVertical; ///< The camera angle field of view in the vertical direction (expressed in radians). + float viewSpaceToMetersFactor; ///< The scale factor to convert view space units to meters + uint32_t flags; ///< Zero or a combination of values from FfxApiDispatchFsrUpscaleFlags. +}; + +#define FFX_API_QUERY_DESC_TYPE_UPSCALE_GETUPSCALERATIOFROMQUALITYMODE FFX_API_MAKE_EFFECT_SUB_ID(FFX_API_EFFECT_ID_UPSCALE, 0x02) +struct ffxQueryDescUpscaleGetUpscaleRatioFromQualityMode +{ + ffxQueryDescHeader header; ///< Header descriptor, use type FFX_API_QUERY_DESC_TYPE_UPSCALE_GETUPSCALERATIOFROMQUALITYMODE. + uint32_t qualityMode; ///< The desired quality mode for FSR upscaling. + float* pOutUpscaleRatio; ///< A pointer to a float which will hold the upscaling the per-dimension upscaling ratio. +}; + +#define FFX_API_QUERY_DESC_TYPE_UPSCALE_GETRENDERRESOLUTIONFROMQUALITYMODE FFX_API_MAKE_EFFECT_SUB_ID(FFX_API_EFFECT_ID_UPSCALE, 0x03) +struct ffxQueryDescUpscaleGetRenderResolutionFromQualityMode +{ + ffxQueryDescHeader header; ///< Header descriptor, use type FFX_API_QUERY_DESC_TYPE_UPSCALE_GETRENDERRESOLUTIONFROMQUALITYMODE. + uint32_t displayWidth; ///< The target display resolution width. + uint32_t displayHeight; ///< The target display resolution height. + uint32_t qualityMode; ///< The desired quality mode for FSR upscaling. + uint32_t* pOutRenderWidth; ///< A pointer to a uint32_t which will hold the calculated render resolution width. + uint32_t* pOutRenderHeight; ///< A pointer to a uint32_t which will hold the calculated render resolution height. +}; + +#define FFX_API_QUERY_DESC_TYPE_UPSCALE_GETJITTERPHASECOUNT FFX_API_MAKE_EFFECT_SUB_ID(FFX_API_EFFECT_ID_UPSCALE, 0x04) +struct ffxQueryDescUpscaleGetJitterPhaseCount +{ + ffxQueryDescHeader header; ///< Header descriptor, use type FFX_API_QUERY_DESC_TYPE_UPSCALE_GETJITTERPHASECOUNT. + uint32_t renderWidth; ///< The render resolution width. + uint32_t displayWidth; ///< The output resolution width. + int32_t* pOutPhaseCount; ///< A pointer to a int32_t which will hold the jitter phase count for the scaling factor between renderWidth and displayWidth. +}; + +#define FFX_API_QUERY_DESC_TYPE_UPSCALE_GETJITTEROFFSET FFX_API_MAKE_EFFECT_SUB_ID(FFX_API_EFFECT_ID_UPSCALE, 0x05) +struct ffxQueryDescUpscaleGetJitterOffset +{ + ffxQueryDescHeader header; ///< Header descriptor, use type FFX_API_QUERY_DESC_TYPE_UPSCALE_GETJITTEROFFSET. + int32_t index; ///< The index within the jitter sequence. + int32_t phaseCount; ///< The length of jitter phase. See ffxQueryDescFsrGetJitterPhaseCount. + float* pOutX; ///< A pointer to a float which will contain the subpixel jitter offset for the x dimension. + float* pOutY; ///< A pointer to a float which will contain the subpixel jitter offset for the y dimension. +}; + +#define FFX_API_DISPATCH_DESC_TYPE_UPSCALE_GENERATEREACTIVEMASK FFX_API_MAKE_EFFECT_SUB_ID(FFX_API_EFFECT_ID_UPSCALE, 0x06) +struct ffxDispatchDescUpscaleGenerateReactiveMask +{ + ffxDispatchDescHeader header; ///< Header descriptor, use type FFX_API_DISPATCH_DESC_TYPE_UPSCALE_GENERATEREACTIVEMASK. + void* commandList; ///< The FfxCommandList to record FSRUPSCALE rendering commands into. + struct FfxApiResource colorOpaqueOnly; ///< A FfxApiResource containing the opaque only color buffer for the current frame (at render resolution). + struct FfxApiResource colorPreUpscale; ///< A FfxApiResource containing the opaque+translucent color buffer for the current frame (at render resolution). + struct FfxApiResource outReactive; ///< A FfxApiResource containing the surface to generate the reactive mask into. + struct FfxApiDimensions2D renderSize; ///< The resolution that was used for rendering the input resources. + float scale; ///< A value to scale the output + float cutoffThreshold; ///< A threshold value to generate a binary reactive mask + float binaryValue; ///< A value to set for the binary reactive mask + uint32_t flags; ///< Flags to determine how to generate the reactive mask +}; + +#define FFX_API_CONFIGURE_DESC_TYPE_UPSCALE_KEYVALUE FFX_API_MAKE_EFFECT_SUB_ID(FFX_API_EFFECT_ID_UPSCALE, 0x07) +struct ffxConfigureDescUpscaleKeyValue +{ + ffxConfigureDescHeader header; ///< Header descriptor, use type FFX_API_CONFIGURE_DESC_TYPE_UPSCALE_KEYVALUE. + uint64_t key; ///< Configuration key, member of the FfxApiConfigureUpscaleKey enumeration. + uint64_t u64; ///< Integer value or enum value to set. + void* ptr; ///< Pointer to set or pointer to value to set. +}; + +enum FfxApiConfigureUpscaleKey +{ + FFX_API_CONFIGURE_UPSCALE_KEY_FVELOCITYFACTOR = 0, ///< Override constant buffer fVelocityFactor. The float value is casted from void * ptr. Value of 0.0f can improve temporal stability of bright pixels. Default value is 1.0f. Value is clamped to [0.0f, 1.0f]. + FFX_API_CONFIGURE_UPSCALE_KEY_FREACTIVENESSSCALE = 1, ///< Override constant buffer fReactivenessScale. The float value is casted from void * ptr. Meant for development purpose to test if writing a larger value to reactive mask, reduces ghosting. Default value is 1.0f. Value is clamped to [0.0f, +infinity]. + FFX_API_CONFIGURE_UPSCALE_KEY_FSHADINGCHANGESCALE = 2, ///< Override fShadingChangeScale. Increasing this scales fsr3.1 computed shading change value at read to have higher reactiveness. Default value is 1.0f. Value is clamped to [0.0f, +infinity]. + FFX_API_CONFIGURE_UPSCALE_KEY_FACCUMULATIONADDEDPERFRAME = 3, ///< Override constant buffer fAccumulationAddedPerFrame. Corresponds to amount of accumulation added per frame at pixel coordinate where disocclusion occured or when reactive mask value is > 0.0f. Decreasing this and drawing the ghosting object (IE no mv) to reactive mask with value close to 1.0f can decrease temporal ghosting. Decreasing this value could result in more thin feature pixels flickering. Default value is 0.333. Value is clamped to [0.0f, 1.0f]. + FFX_API_CONFIGURE_UPSCALE_KEY_FMINDISOCCLUSIONACCUMULATION = 4, ///< Override constant buffer fMinDisocclusionAccumulation. Increasing this value may reduce white pixel temporal flickering around swaying thin objects that are disoccluding one another often. Too high value may increase ghosting. A sufficiently negative value means for pixel coordinate at frame N that is disoccluded, add fAccumulationAddedPerFrame starting at frame N+2. Default value is -0.333. Value is clamped to [-1.0f, 1.0f]. +}; + +#define FFX_API_QUERY_DESC_TYPE_UPSCALE_GPU_MEMORY_USAGE FFX_API_MAKE_EFFECT_SUB_ID(FFX_API_EFFECT_ID_UPSCALE, 0x08) +struct ffxQueryDescUpscaleGetGPUMemoryUsage +{ + ffxQueryDescHeader header; ///< Header descriptor, use type FFX_API_QUERY_DESC_TYPE_UPSCALE_GPU_MEMORY_USAGE. + struct FfxApiEffectMemoryUsage* gpuMemoryUsageUpscaler; ///< Output values by Query() call. +}; + +#define FFX_API_QUERY_DESC_TYPE_UPSCALE_GPU_MEMORY_USAGE_V2 FFX_API_MAKE_EFFECT_SUB_ID(FFX_API_EFFECT_ID_UPSCALE, 0x09) +struct ffxQueryDescUpscaleGetGPUMemoryUsageV2 +{ + ffxQueryDescHeader header; ///< Header descriptor, use type FFX_API_QUERY_DESC_TYPE_UPSCALE_GPU_MEMORY_USAGE_V2. + void* device; ///< For DX12: pointer to ID3D12Device. For VK, pointer to VkDeviceContext. App needs to fill out before Query() call. + struct FfxApiDimensions2D maxRenderSize; ///< App needs to fill out before Query() call. + struct FfxApiDimensions2D maxUpscaleSize; ///< App needs to fill out before Query() call. + uint32_t flags; ///< Zero or a combination of values from FfxApiCreateContextUpscaleFlags. App needs to fill out before Query() call. + struct FfxApiEffectMemoryUsage* gpuMemoryUsageUpscaler; ///< Output values by Query() call. +}; + +enum FfxApiQueryResourceIdentifiers +{ + FFX_API_QUERY_RESOURCE_INPUT_COLOR = (1 << 0), ///< Color buffer for the current frame (at render resolution). + FFX_API_QUERY_RESOURCE_INPUT_DEPTH = (1 << 1), ///< 32bit depth values for the current frame (at render resolution). + FFX_API_QUERY_RESOURCE_INPUT_MV = (1 << 2), ///< 2-dimensional motion vectors (at render resolution if FFX_FSR_ENABLE_DISPLAY_RESOLUTION_MOTION_VECTORS is not set). + FFX_API_QUERY_RESOURCE_INPUT_EXPOSURE = (1 << 3), ///< A 1x1 texture containing exposure value or the FFX_UPSCALE_ENABLE_AUTO_EXPOSURE set at context creation. + FFX_API_QUERY_RESOURCE_INPUT_REACTIVEMASK = (1 << 4), ///< An R8 UNORM texture at render resolution that controls the influence of pixel history on upscaling result. + FFX_API_QUERY_RESOURCE_INPUT_TRANSPARENCYCOMPOSITION = (1 << 5), ///< An R8 UNORM texture at render resolution that controls the blending of color in the upscaling result. +}; + +#define FFX_API_QUERY_DESC_TYPE_UPSCALE_GET_RESOURCE_REQUIREMENTS FFX_API_MAKE_EFFECT_SUB_ID(FFX_API_EFFECT_ID_UPSCALE, 0x0a) +struct ffxQueryDescUpscaleGetResourceRequirements +{ + ffxQueryDescHeader header; ///< Header descriptor, use type FFX_API_QUERY_DESC_TYPE_UPSCALE_GET_RESOURCE_REQUIREMENTS. + uint64_t required_resources; ///< resources 64b bitfield, that given current context state, are required for effect correctness. + uint64_t optional_resources; ///< resources 64b bitfield, that given current context state, will be consumed if provided, but are optional. +}; + +#define FFX_API_CREATE_CONTEXT_DESC_TYPE_UPSCALE_VERSION FFX_API_MAKE_EFFECT_SUB_ID(FFX_API_EFFECT_ID_UPSCALE, 0x0b) +struct ffxCreateContextDescUpscaleVersion +{ + ffxCreateContextDescHeader header; ///< Header descriptor, use type FFX_API_CREATE_CONTEXT_DESC_TYPE_UPSCALE_VERSION. + uint32_t version; ///< The version of the API the application was built against. This must be set to FFX_UPSCALER_VERSION. +}; + +#ifdef __cplusplus +} +#endif From eed481a05ae990b20d0d134767a7fbebbabff1fe Mon Sep 17 00:00:00 2001 From: NoBoDyZ Date: Mon, 9 Nov 2026 00:17:09 +0100 Subject: [PATCH 4/5] feat(fsr): run FSR 4 on Linux through a Vulkan FSR 4 library There is no AMD loader on Linux, so the upscaler library itself (amd_fidelityfx_upscaler_vk.so) is loaded with dlopen from RX_FSR4_DIR or beside the game. A Vulkan FSR 4 build reads the SDK's older backend description and records with descriptor buffers: the description is chained next to the current one, and VK_EXT_descriptor_buffer is enabled only when the library is there. Windows is unchanged. BITMAPFILEHEADER joins the POSIX windows.h shim, for the menu dump. Assisted-by: Claude Opus 5.5 Co-Authored-By: Claude Opus 5.5 --- gpu/vk/vk_fsr4.cpp | 55 ++++++++++++++++++++++++++++++++++++++++---- gpu/vk/vk_fsr4.h | 2 ++ gpu/vk/vk_main.cpp | 6 +++++ host/posix/windows.h | 3 +++ 4 files changed, 62 insertions(+), 4 deletions(-) diff --git a/gpu/vk/vk_fsr4.cpp b/gpu/vk/vk_fsr4.cpp index c357d4835..69a6a4833 100644 --- a/gpu/vk/vk_fsr4.cpp +++ b/gpu/vk/vk_fsr4.cpp @@ -11,6 +11,10 @@ #include #include #include +#ifndef _WIN32 +#include +#include +#endif #include "vk_internal.h" @@ -22,7 +26,12 @@ namespace mkwvk { namespace { +#ifdef _WIN32 constexpr const char* kLoader = "amd_fidelityfx_loader_vk.dll"; +#else +// (linux) no AMD loader exists there: the upscaler library itself, which exports the ffx entry points (a Vulkan FSR 4 build) +constexpr const char* kLoader = "amd_fidelityfx_upscaler_vk.so"; +#endif struct Fsr { bool tried = false, ok = false; @@ -37,6 +46,9 @@ struct Fsr { VkDeviceContext device_context{}; ffxCreateBackendVKDesc backend{}; ffxOverrideVersion version{}; +#ifndef _WIN32 + ffxCreateBackendVKDesc_DEPRECATED legacy_backend{}; // (linux) the backend description a Vulkan FSR 4 build like fsr4-vk reads +#endif ffxCreateContextDescUpscale upscale{}; ffxContext context = nullptr; uint32_t max_w = 0, max_h = 0; // (the context's sizes: the output's, the most the render size can be) @@ -70,13 +82,28 @@ std::vector loader_dirs() { return d; } +void* symbol(const char* name) { +#ifdef _WIN32 + return (void*)GetProcAddress(fsr.lib, name); +#else + return dlsym(fsr.lib, name); +#endif +} + bool start() { fsr.tried = true; for (const std::string& dir : loader_dirs()) { +#ifdef _WIN32 const std::string path = dir + "\\" + kLoader; if (GetFileAttributesA(path.c_str()) == INVALID_FILE_ATTRIBUTES) continue; // (the upscaler DLL the loader picks lies beside it: the loader's folder first in the search) fsr.lib = LoadLibraryExA(path.c_str(), nullptr, LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR | LOAD_LIBRARY_SEARCH_DEFAULT_DIRS); +#else + const std::string path = dir + "/" + kLoader; + if (access(path.c_str(), R_OK) != 0) continue; + fsr.lib = (HMODULE)dlopen(path.c_str(), RTLD_NOW | RTLD_LOCAL); + if (!fsr.lib) logf("vk: fsr4: %s not loaded: %s", path.c_str(), dlerror()); +#endif if (fsr.lib) { logf("vk: fsr4: %s", path.c_str()); break; @@ -87,10 +114,10 @@ bool start() { logf("vk: fsr4: %s not found (RX_FSR4_DIR, or beside hookshot.exe with amd_fidelityfx_upscaler_vk.dll)", kLoader); return false; } - fsr.create = (PfnFfxCreateContext)(void*)GetProcAddress(fsr.lib, "ffxCreateContext"); - fsr.destroy = (PfnFfxDestroyContext)(void*)GetProcAddress(fsr.lib, "ffxDestroyContext"); - fsr.query = (PfnFfxQuery)(void*)GetProcAddress(fsr.lib, "ffxQuery"); - fsr.dispatch = (PfnFfxDispatch)(void*)GetProcAddress(fsr.lib, "ffxDispatch"); + fsr.create = (PfnFfxCreateContext)symbol("ffxCreateContext"); + fsr.destroy = (PfnFfxDestroyContext)symbol("ffxDestroyContext"); + fsr.query = (PfnFfxQuery)symbol("ffxQuery"); + fsr.dispatch = (PfnFfxDispatch)symbol("ffxDispatch"); if (!fsr.create || !fsr.destroy || !fsr.query || !fsr.dispatch) { fsr.reason = "the AMD loader lacks the FSR API"; logf("vk: fsr4: %s lacks the FSR API's entry points", kLoader); @@ -160,6 +187,16 @@ bool make_context(uint32_t w, uint32_t h) { fsr.version.header.type = FFX_API_DESC_TYPE_OVERRIDE_VERSION; fsr.version.versionId = fsr.version_id; fsr.backend.header.pNext = &fsr.version.header; +#ifndef _WIN32 + // (linux) fsr4-vk looks for the SDK's older backend description, not ffxCreateBackendVKDesc: without it, it finds no device + // and creation returns FFX_API_RETURN_ERROR_PARAMETER. Both stay chained + fsr.legacy_backend = {}; + fsr.legacy_backend.header.type = FFX_API_CREATE_CONTEXT_DESC_TYPE_BACKEND_VK_DEPRECATED; + fsr.legacy_backend.vkDevice = fsr.device_context.vkDevice; + fsr.legacy_backend.vkPhysicalDevice = fsr.device_context.vkPhysicalDevice; + fsr.legacy_backend.vkDeviceProcAddr = fsr.device_context.vkDeviceProcAddr; + fsr.version.header.pNext = &fsr.legacy_backend.header; +#endif fsr.upscale = {}; fsr.upscale.header.type = FFX_API_CREATE_CONTEXT_DESC_TYPE_UPSCALE; fsr.upscale.header.pNext = &fsr.backend.header; @@ -213,6 +250,16 @@ bool fsr4_available() { } const char* fsr4_reason() { return fsr.reason; } +bool fsr4_wants_descriptor_buffer() { +#ifdef _WIN32 + return false; +#else + for (const std::string& dir : loader_dirs()) + if (access((dir + "/" + kLoader).c_str(), R_OK) == 0) return true; + return false; +#endif +} + bool fsr4_evaluate(VkCommandBuffer cmd, const DlssImage& color, const DlssImage& depth, const DlssImage& motion, const DlssImage& output, float jitter_x, float jitter_y, bool reset) { if (!fsr4_available()) return false; diff --git a/gpu/vk/vk_fsr4.h b/gpu/vk/vk_fsr4.h index 9a96f2aaa..92d747967 100644 --- a/gpu/vk/vk_fsr4.h +++ b/gpu/vk/vk_fsr4.h @@ -15,6 +15,8 @@ namespace mkwvk { /// among those it lists. Made at the first use (no instance or device extensions needed), once. True when there is one bool fsr4_available(); const char* fsr4_reason(); // (why not, short: the menu and the log) +/// (linux) a Vulkan FSR 4 library such as fsr4-vk's is there and records with descriptor buffers: the device has to enable them +bool fsr4_wants_descriptor_buffer(); /// Records one FSR evaluation on cmd: color (perceptual, tonemapped: FSR's LDR mode), depth (standard, not inverted) and motion /// (render pixels, towards the previous frame) at the render size, output (RGBA16F, STORAGE | SAMPLED) at the output size. All diff --git a/gpu/vk/vk_main.cpp b/gpu/vk/vk_main.cpp index 9aba76b38..4d2d4dbd0 100644 --- a/gpu/vk/vk_main.cpp +++ b/gpu/vk/vk_main.cpp @@ -17,6 +17,7 @@ #include "vk_draw.h" #include "vk_internal.h" #include "vk_dlss.h" +#include "vk_fsr4.h" #include "gpu_choice.h" #include "vk_menu.h" @@ -240,6 +241,8 @@ bool create_device() { optional(VK_KHR_COOPERATIVE_MATRIX_EXTENSION_NAME, dev.coop_matrix); for (const char* e : dlss_device_exts()) // (hookshot: NVIDIA Streamline's, vk_dlss.cpp) if (has_extension(exts, e) && std::none_of(want.begin(), want.end(), [&](const char* x) { return !std::strcmp(x, e); })) want.push_back(e); + bool fsr_descriptor_buffer = false; // (hookshot, linux: only with a Vulkan FSR 4 library beside the game, vk_fsr4.cpp) + if (fsr4_wants_descriptor_buffer()) optional(VK_EXT_DESCRIPTOR_BUFFER_EXTENSION_NAME, fsr_descriptor_buffer); // the queue: one family for graphics, compute and transfer vkGetPhysicalDeviceQueueFamilyProperties(dev.physical, &n, nullptr); @@ -290,7 +293,10 @@ bool create_device() { if (dev.view_2d_of_3d) *tail = &v2d3d, tail = &v2d3d.pNext; VkPhysicalDeviceCooperativeMatrixFeaturesKHR coop{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_FEATURES_KHR}; if (dev.coop_matrix) *tail = &coop, tail = &coop.pNext; + VkPhysicalDeviceDescriptorBufferFeaturesEXT descriptor_buffer{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_FEATURES_EXT}; + if (fsr_descriptor_buffer) *tail = &descriptor_buffer, tail = &descriptor_buffer.pNext; vkGetPhysicalDeviceFeatures2(dev.physical, &f); + descriptor_buffer.descriptorBufferCaptureReplay = VK_FALSE; dev.view_2d_of_3d = dev.view_2d_of_3d && v2d3d.sampler2DViewOf3D; coop.cooperativeMatrixRobustBufferAccess = VK_FALSE; dev.coop_matrix = dev.coop_matrix && coop.cooperativeMatrix && diff --git a/host/posix/windows.h b/host/posix/windows.h index 85d262f0f..84efc5914 100644 --- a/host/posix/windows.h +++ b/host/posix/windows.h @@ -577,6 +577,9 @@ int MessageBoxA(HWND w, LPCSTR text, LPCSTR caption, UINT type); #define ANTIALIASED_QUALITY 4 #define CLEARTYPE_QUALITY 5 #define DEFAULT_PITCH 0 +#pragma pack(push, 2) +typedef struct { WORD bfType; DWORD bfSize; WORD bfReserved1, bfReserved2; DWORD bfOffBits; } BITMAPFILEHEADER; /* (the 14 bytes of a .bmp) */ +#pragma pack(pop) typedef struct { DWORD biSize; LONG biWidth, biHeight; From 86b1e1bdd0e92d3310df55eaa8ca791095866c44 Mon Sep 17 00:00:00 2001 From: NoBoDyZ Date: Mon, 9 Nov 2026 00:17:09 +0100 Subject: [PATCH 5/5] fix(fsr): pick the first of equal providers, give the upscaler a unit exposure A Vulkan FSR 4 build lists its Auto provider before INT8 and FP8, so taking the last of equal versions chose FP8 on hardware without it. It also rejects a dispatch without an exposure: the game's colour is already tonemapped, so it gets a 1x1 R32F of 1. Assisted-by: Claude Opus 5.5 Co-Authored-By: Claude Opus 5.5 --- gpu/vk/vk_fsr4.cpp | 39 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/gpu/vk/vk_fsr4.cpp b/gpu/vk/vk_fsr4.cpp index 69a6a4833..0a48c5219 100644 --- a/gpu/vk/vk_fsr4.cpp +++ b/gpu/vk/vk_fsr4.cpp @@ -153,7 +153,8 @@ bool start() { listed += (listed.empty() ? "" : ", ") + std::string(name); unsigned v[3] = {0, 0, 0}; sscanf(name, "%u.%u.%u", &v[0], &v[1], &v[2]); - if (v[0] == 4 && (v[1] > best[1] || (v[1] == best[1] && v[2] >= best[2]))) { + // (the first of equal versions: a Vulkan FSR 4 build lists its Auto, which picks the GPU's model, before INT8 and FP8) + if (v[0] == 4 && (!fsr.version_id || v[1] > best[1] || (v[1] == best[1] && v[2] > best[2]))) { std::memcpy(best, v, sizeof best); fsr.version_id = ids[i]; } @@ -242,6 +243,35 @@ void barriers(VkCommandBuffer cmd, const VkImageMemoryBarrier2* b, uint32_t n) { vkCmdPipelineBarrier2(cmd, &di); } +#ifndef _WIN32 +/// (linux) a Vulkan FSR 4 build takes no frame without an exposure, and the game's colour is tonemapped already: a 1x1 R32F of 1 +bool unit_exposure(VkCommandBuffer cmd, DlssImage& out) { + static VkImage image = VK_NULL_HANDLE; + static VmaAllocation allocation{}; + const bool made = image != VK_NULL_HANDLE; + if (!made) { + VkImageCreateInfo ci{VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO}; + ci.imageType = VK_IMAGE_TYPE_2D, ci.format = VK_FORMAT_R32_SFLOAT, ci.extent = {1, 1, 1}, ci.mipLevels = 1, ci.arrayLayers = 1; + ci.samples = VK_SAMPLE_COUNT_1_BIT, ci.tiling = VK_IMAGE_TILING_OPTIMAL; + ci.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; + if (!create_image(ci, image, allocation)) return image = VK_NULL_HANDLE, false; + } + out = DlssImage{image, VK_NULL_HANDLE, VK_FORMAT_R32_SFLOAT, 1, 1, VK_IMAGE_ASPECT_COLOR_BIT}; + if (!made) { + const VkImageMemoryBarrier2 to_clear = barrier(out, 0, VK_ACCESS_2_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + barriers(cmd, &to_clear, 1); + const VkClearColorValue one{{1.0f, 0.0f, 0.0f, 0.0f}}; + const VkImageSubresourceRange range{VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}; + vkCmdClearColorImage(cmd, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &one, 1, &range); + const VkImageMemoryBarrier2 to_read = barrier(out, VK_ACCESS_2_TRANSFER_WRITE_BIT, VK_ACCESS_2_SHADER_READ_BIT, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + barriers(cmd, &to_read, 1); + } + return true; +} +#endif + } // namespace bool fsr4_available() { @@ -271,6 +301,10 @@ bool fsr4_evaluate(VkCommandBuffer cmd, const DlssImage& color, const DlssImage& reset = true; } if (color.width > fsr.max_w || color.height > fsr.max_h) return false; // (a render size past the output: not an upscale) +#ifndef _WIN32 + DlssImage exposure{}; + if (!unit_exposure(cmd, exposure)) return false; +#endif const auto now = std::chrono::steady_clock::now(); const float frame_ms = fsr.evals ? std::chrono::duration(now - fsr.last).count() : 1000.0f / 30.0f; fsr.last = now; @@ -290,6 +324,9 @@ bool fsr4_evaluate(VkCommandBuffer cmd, const DlssImage& color, const DlssImage& d.depth = resource(depth, VK_IMAGE_USAGE_SAMPLED_BIT, FFX_API_RESOURCE_STATE_COMPUTE_READ); d.motionVectors = resource(motion, VK_IMAGE_USAGE_SAMPLED_BIT, FFX_API_RESOURCE_STATE_COMPUTE_READ); d.output = resource(output, VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, FFX_API_RESOURCE_STATE_UNORDERED_ACCESS); +#ifndef _WIN32 + d.exposure = resource(exposure, VK_IMAGE_USAGE_SAMPLED_BIT, FFX_API_RESOURCE_STATE_COMPUTE_READ); +#endif d.jitterOffset = {jitter_x, jitter_y}; d.motionVectorScale = {1.0f, 1.0f}; // (render pixels already, towards the previous frame) d.renderSize = {color.width, color.height};