Files
NX2navi/runtime/vk_fg.h
epicmeme546 5bdf583331 Add frame generation through AMD's FSR SDK 2.4 as a setting to try with FSR 4, and never generate a frame without the HUD-less picture.
runtime/vk_fg4.cpp makes the frame generation swapchain and context with the libraries FSR 4 comes with
(amd_fidelityfx_loader_vk.dll and amd_fidelityfx_framegeneration_vk.dll beside the executable). vk_fg.cpp takes
that path only with fsr4_fg = 1 while FSR 4 is the upscaler; the default stays the FSR 3.1 library. The loader
picks the version for the card: the machine-learned FSR Frame Generation 4 on Radeon RX 9000 cards with Windows 11,
which is untested, and 3.1.6 elsewhere. On an RX 7900 XT (driver 26.10.1) it lists frame generation 3.1.6 and the
swapchains 4.0.0, which the driver brings and the loader chooses, and 3.1.7. The swapchain in place is wanted only
while its library is the one to use, so a change of the setting or of the upscaler, or a failure of this path,
takes it down as switching frame generation off does and the next present makes it with the other library.

The preparation gives this library the camera's position and axes, which FSR Frame Generation 4 requires, and a
scene scale of one metre a unit: with the 0.01 the FSR 3.1 path uses, version 3.1.6 drew grey translucent shapes
into the sky of its frames while the camera turned (160 captures of the screen during a camera sweep; clean with 1).

Both paths now generate a frame only when the picture without the HUD is there for it: generated from the
presented picture alone, the HUD would be warped with the scene behind it. In four configurations (21:9 with either
library, a 16:9 picture in a 21:9 window, a 1080 picture without HDR) every generated frame had it, and the log
counts the frames without. On screen, of the 6,404 pixels of the HUD's item button that stayed fixed through a
camera sweep with the FSR 3.1 library, 6,162 stayed fixed with this one.

Standing in Hyrule Field at 3440x1440 with FSR 4 Quality the game draws 43.0 frames a second with this path and
42.2 with the FSR 3.1 library, each shown twice over. One run changed the present mode, HDR, fullscreen, frame
generation, FSR 4, this setting and the upscaler in turn: 216 screenshots without a bad frame, and no failure.

The SDK's frame generation headers join runtime/third_party/ffx_sdk, unmodified. tools/make_kit.py and
tools/make_launcher.py take the third library from the --ffx4 folder when it is there, and tools/make_game.py
copies it beside the game.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
2026-11-11 04:49:01 -05:00

46 lines
3.4 KiB
C

// Frame generation with AMD FSR 3.1 (vk_fg.cpp): AMD's frame generation swapchain in gfx_present.c's place.
#pragma once
#include <stdint.h>
#include <vulkan/vulkan.h>
int vk_fg_wanted(void); // NX2NAVI_FRAMEGEN = fsr3 with DLSS or FSR 3.1 upscaling on (live), where FSR 3.1 loads
uint32_t vk_fg_queue_count(void); // graphics-family queues the device creates
void vk_fg_queues(VkQueue present, VkQueue acquire); // vk_device.c, after the device exists
int vk_fg_active(void); // the frame generation swapchain exists
int vk_fg_generating(void); // ... and the last frame had generation on (not paused for the menu)
// gfx_present.c's swapchain calls while vk_fg_wanted: the first create makes AMD's swapchain context, later ones
// (window resizes) its swapchain again. Non-success from the first: the plain swapchain path stays.
VkResult vk_fg_create_swapchain(const VkSwapchainCreateInfoKHR *ci, VkSwapchainKHR *sc);
void vk_fg_destroy_swapchain(VkSwapchainKHR sc);
VkResult vk_fg_get_images(VkSwapchainKHR sc, uint32_t *n, VkImage *img);
VkResult vk_fg_acquire(VkSwapchainKHR sc, uint64_t timeout, VkSemaphore sem, uint32_t *idx);
VkResult vk_fg_present(const VkPresentInfoKHR *pi); // on the game's queue, its lock held by the caller
// Each present, before its command buffer is submitted: configures generation for this frame and records its
// preparation (the frame's depth and motion vectors, vk_dlaa_fg_inputs) into cb.
// hudless: this frame's picture without the HUD at the swapchain's size and format, in GENERAL (VK_NULL_HANDLE: none),
// from which generation tells the HUD apart and keeps it out of the generated frames.
// pic: the picture's rectangle in the swapchain {x, y, w, h} (black bars around it when the window has another shape);
// frames are generated inside it only.
void vk_fg_frame(VkCommandBuffer cb, VkSwapchainKHR sc, VkFormat fmt, VkExtent2D ext, VkImage hudless, VkImageView hudless_view,
const int pic[4]);
uint64_t vk_fg_presents(VkSwapchainKHR sc); // frames the swapchain presented, generated ones included (0: off)
PFN_vkSetHdrMetadataEXT vk_fg_hdr_metadata_fn(void); // AMD's replacement for vkSetHdrMetadataEXT while active, else NULL
void vk_fg_release(void);
// The same through AMD's FSR SDK 2.4 (vk_fg4.cpp), for vk_fg.cpp alone: it takes this path while FSR 4 is the upscaler,
// and every call above goes to these while this path holds the swapchain.
int vk_fg4_available(void); // its libraries are beside the executable and list a frame generation for the device
int vk_fg4_failed(void); // it failed in this run: FSR 3.1's library generates the frames
int vk_fg4_active(void);
int vk_fg4_generating(void);
void vk_fg4_queues(VkQueue present, VkQueue acquire);
VkResult vk_fg4_create_swapchain(const VkSwapchainCreateInfoKHR *ci, VkSwapchainKHR *sc);
void vk_fg4_destroy_swapchain(VkSwapchainKHR sc);
VkResult vk_fg4_get_images(VkSwapchainKHR sc, uint32_t *n, VkImage *img);
VkResult vk_fg4_acquire(VkSwapchainKHR sc, uint64_t timeout, VkSemaphore sem, uint32_t *idx);
VkResult vk_fg4_present(const VkPresentInfoKHR *pi);
void vk_fg4_frame(VkCommandBuffer cb, VkSwapchainKHR sc, VkFormat fmt, VkExtent2D ext, VkImage hudless, const int pic[4]);
uint64_t vk_fg4_presents(VkSwapchainKHR sc);
PFN_vkSetHdrMetadataEXT vk_fg4_hdr_metadata_fn(void);
void vk_fg4_release(void);