mirror of
https://github.com/tangerineturtle1/NX2navi.git
synced 2026-11-15 19:19:58 -04:00
With DLSS-G, Reflex's sleep held each frame's start with no limit while the game's pacer still held the limit on the present thread and at the window image's acquire (A-16, P-16): the pacer's wait came after the picture was drawn, so the pad was read up to a period before the picture left, on top of Reflex's own wait for the GPU. vk_dlssg.c vk_dlssg_pace, on the presenting guest thread in nvnQueuePresentTexture, asks dlssg_pace.h which limit Reflex should hold and stores it; vk_dlssg_frame on the present thread hands a changed limit to Streamline before its present (reflex_apply, under the present lock, which keeps Streamline's options calls on one thread at a time), as does each new swapchain, which has neither mode nor limit. GfxBackend.frame_paced now returns the period the pacer still holds: vk_backend.c vk_be_frame_paced gives the game's ceiling (frame_step_ceiling_ns, 240) while Reflex holds the limit, 0 where a driver's low latency holds it (vk_lowlat_pace, unchanged), else the period; during a movie the back ends get 0 and the pacer keeps the movie's period and catch-up slots as before. The pacer takes the limit back before the first host present, after 200 ms without one, with a DLL older than nx2sl_reflex2 (one log line at start), for a limit Streamline refused, and for the run when the frames show Reflex does not hold it; the "frame rate:" lines name who holds it, the "dlssg: present N" line counts the frame starts Reflex held, and Reflex's sleep now counts as pacing (perf_end_any, on whichever thread acquires). No wait is added on a drawing thread: the limiter's wait moves from the acquire's sleep_until and the present thread's slot to Reflex's sleep a few lines later in the same acquire, and the present thread's options call returns at once. docs/architecture.md names Reflex as a limiter. Not reproduced before the change (no RTX 40 or 50 here); vk_dlssg.c, vk_backend.c and nvn_api_obj.c compile clean with the dev build's flags, and dlssg_pace_check, fg_reset_check and frame_step_check pass. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
55 lines
4.4 KiB
C
55 lines
4.4 KiB
C
// DLSS Frame Generation through NVIDIA Streamline (vk_dlssg.c, nx2navi_dlssg.dll).
|
|
#pragma once
|
|
#include <stdint.h>
|
|
#include <vulkan/vulkan.h>
|
|
|
|
int vk_dlssg_wanted(void); // NX2NAVI_FRAMEGEN = dlss, with any upscaler or none (read once)
|
|
int vk_dlssg_early(void); // before the instance exists: loads the DLL and Streamline; 1 when its proxies are there
|
|
// vk_device.c: the instance and device through Streamline's proxies when vk_dlssg_early succeeded, else the loader's
|
|
VkResult vk_dlssg_create_instance(const VkInstanceCreateInfo *ci, VkInstance *out);
|
|
VkResult vk_dlssg_enumerate(VkInstance inst, uint32_t *n, VkPhysicalDevice *pd); // through the interposer too
|
|
PFN_vkVoidFunction vk_dlssg_instance_proc(VkInstance inst, const char *name); // the interposer's, or NULL
|
|
VkResult vk_dlssg_create_device(VkInstance inst, VkPhysicalDevice pd, const VkDeviceCreateInfo *ci, VkDevice *out);
|
|
void vk_dlssg_device_ready(VkPhysicalDevice physical, VkDevice dev); // after the device: checks DLSS-G and takes the swapchain hooks
|
|
PFN_vkGetDeviceProcAddr vk_dlssg_dpa(void); // Streamline's device entry points, or NULL when it is not in use
|
|
int vk_dlssg_active(void);
|
|
// gfx_present.c's swapchain calls while active
|
|
VkResult vk_dlssg_create_swapchain(VkDevice d, const VkSwapchainCreateInfoKHR *ci, VkSwapchainKHR *sc);
|
|
void vk_dlssg_destroy_swapchain(VkDevice d, VkSwapchainKHR sc);
|
|
VkResult vk_dlssg_get_images(VkDevice d, VkSwapchainKHR sc, uint32_t *n, VkImage *img);
|
|
VkResult vk_dlssg_acquire(VkDevice d, VkSwapchainKHR sc, uint64_t timeout, VkSemaphore sem, uint32_t *idx);
|
|
VkResult vk_dlssg_present(VkQueue q, const VkPresentInfoKHR *pi);
|
|
void vk_dlssg_frame(VkCommandBuffer cb, VkExtent2D ext); // each present, before its command buffer is submitted
|
|
// Frames are numbered by the game's presents (frame n ends with the n-th). Reflex's frame timing while active:
|
|
void vk_dlssg_frame_start(void); // the game starts a frame (nvn_api_obj.c nvnWindowAcquireTexture): Reflex's sleep
|
|
// The game presents (nvn_api_obj.c nvnQueuePresentTexture, through vk_backend.c vk_be_frame_paced) with the pacer's
|
|
// period, 0 during a movie: 1 when Reflex holds the frame limit where the frame starts (dlssg_pace.h), so the pacer
|
|
// keeps only the game's ceiling. Atomics only, no wait; 0 while DLSS-G does not run.
|
|
int vk_dlssg_pace(uint64_t period_ns);
|
|
void vk_dlssg_game_present(void); // the game presents it (vk_backend.c vk_be_present): counts it
|
|
// its submissions went out (vk_backend.c: vk_be_present, or replay_main with asynchronous replay): the render-submit-end
|
|
// marker; frame is gfx_counters.frames of its present, the same count
|
|
void vk_dlssg_submitted(uint64_t frame);
|
|
void vk_dlssg_present_frame(uint64_t frame); // the present thread's next blit and present are of this frame
|
|
uint64_t vk_dlssg_shown(void); // the frames the display got, generated ones included (present thread); 0 when off
|
|
void vk_dlssg_release(void);
|
|
|
|
// The multiplier: the frames the display gets per rendered frame, 2, 3 or 4 (one to three generated), set by
|
|
// NX2NAVI_FRAMEGEN_MULTIPLIER and applied at once.
|
|
// What a setting value gives where the GPU and driver allow up to max (2 to 4): the value when it is 2, 3 or 4 ("3x"
|
|
// too) and at most max, else the nearest that is; unset or empty, 2. *why (may be NULL): the reason the value was not
|
|
// taken as it is, for the log, or NULL.
|
|
int vk_dlssg_multiplier_of(const char *value, int max, const char **why);
|
|
// The highest multiplier while DLSS-G runs: 2 to 4 from Streamline's numFramesToGenerateMax; 0 while DLSS-G does not
|
|
// run, or before Streamline reported its limit (the first frames; one frame is generated until then). *old_dll (may be
|
|
// NULL): 1 when the limit of 2 is nx2navi_dlssg.dll's, a build older than its nx2sl_frames_max, not the GPU's.
|
|
int vk_dlssg_multiplier_max(int *old_dll);
|
|
// The frames the display gets per game frame now: the multiplier while generation runs, 1 while it is off or paused
|
|
// (the menu). frame_rate.c paces the game at the frame limit over it. Any thread.
|
|
int vk_dlssg_multiplier(void);
|
|
// Why DLSS-G runs or not: DLSSG_NOT_WANTED (NX2NAVI_FRAMEGEN was not dlss at start, or no DLSS or FSR 3.1 upscaling),
|
|
// DLSSG_NO_FILES (nx2navi_dlssg.dll, Streamline or its swapchain hooks missing or failing), DLSSG_UNAVAILABLE (Streamline
|
|
// loaded but DLSS-G or a required plugin function was unavailable).
|
|
enum { DLSSG_NOT_WANTED, DLSSG_RUNS, DLSSG_NO_FILES, DLSSG_UNAVAILABLE };
|
|
int vk_dlssg_status(void);
|