Files
NX2navi/runtime/vk_ffx.h
chrg6 74bedbee73 Name the upscalers' wait mark "upscaler GPU waits", since it also times the timeline wait after a refused creation.
The review of 9071dfc3 found that PERF_M_UPWAIT, printed as "upscaler device waits", times two waits: vk_dlaa.c
vk_upscaler_device_idle's wait for the device, and vk_upscaler_gpu_wait's host wait on the timeline after a refused
DLSS or FSR creation, which touches no queue. host.h tied the mark to the first alone, and a play-test that expects no
"upscaler device waits" would have read the second, at a refused creation on a card short of video memory, as a wait
for the device. perf.c now names the mark "upscaler GPU waits", and host.h, vk_ffx.h and vk_dlaa.c say that both waits
are in it. What makes it a wait for the device still shows in the log: the rollback switch in the "cfg: ... sets:"
line, a full list ("a wait for the device") and a failed timeline wait ("waiting for the device instead") in lines of
their own.

Checks that passed: perf.c, vk_dlaa.c and vk_ffx.cpp compile with -Wall -Wextra and no warning, upscaler_idle_check (one
name per mark kind), tools/check_content.py --staged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-13 20:13:02 -05:00

94 lines
6.5 KiB
C

// AMD FidelityFX (vk_ffx.cpp): FSR 3.1 temporal upscaling through amd_fidelityfx_vk.dll, loaded at run time.
#pragma once
#include <vulkan/vulkan.h>
typedef struct {
VkImage image; // level 0, layer 0, in VK_IMAGE_LAYOUT_GENERAL
VkFormat format;
uint32_t width, height;
int storage; // created with VK_IMAGE_USAGE_STORAGE_BIT (FSR writes it)
} VkFfxImage;
// The scene camera FSR takes, from the frame's projection (vk_dlaa.c proj_planes): the vertical field of view in
// radians, the near and far planes' view distances (far: VK_DLAA_FAR_INFINITE, 1e8, for a projection without a far
// plane) and the metres in one unit of view space. A field of 0 is not known, and FSR then gets 1 radian, 0.1, 1e8 and
// 1.
typedef struct { float fov_y, znear, zfar, meters; } VkFfxCamera;
// vk_dlaa.c: the share (0..1) of the extra sharpening FSR 3.1 gets at a render width w of an output width ow
float vk_dlaa_fsr3_boost(uint32_t w, uint32_t ow);
// vk_dlaa.c: a wait for the device to be idle, the queue lock held, before an upscaler frees what the GPU may still
// use (NX2NAVI_TRACE=perf: "upscaler GPU waits", with vk_upscaler_gpu_wait's)
void vk_upscaler_device_idle(void);
// vk_dlaa.c "what the upscalers let go of while the GPU may still use it", on the thread that makes the upscalers'
// calls (vk_dlaa.c's pass hooks):
int vk_upscaler_idle_wait(void); // NX2NAVI_UPSCALER_IDLE_WAIT: 1 waits for the device wherever one lets go of something
// After something was let go of: what the GPU is past goes (with NX2NAVI_UPSCALER_IDLE_WAIT=1 after a wait for the
// device, vk_upscaler_settle).
void vk_upscaler_let_go(void);
// A wait for the device, then everything let go of that a submission made so far names goes (a present gate stays).
void vk_upscaler_settle(void);
// A refused creation: waits, without the device's idle, until the GPU is past timeline value v (no further than the
// submissions made so far) and returns the value it is past; with NX2NAVI_UPSCALER_IDLE_WAIT=1, or when that wait
// fails, a wait for the device.
uint64_t vk_upscaler_gpu_wait(uint64_t v);
int vk_ffx_load(void); // 1 when the library is there with its entry points (loaded once)
// Whether FSR 3.1 upscaling can run in this build, for the settings menu: after vk_ffx_load ran, what it found; before,
// whether the library file is there, asked once without loading it. 0 where the build has no FSR 3.1 to load.
int vk_ffx_available(void);
// The same for frame generation (vk_fg.cpp), which runs through the library's own API calls (vk_ffx_create and the
// rest below), not only an upscaler.
int vk_ffx_framegen_available(void);
// Records FSR 3.1 into cb: color (the scene light, render size), depth (D32F), mv (R16G16F, render pixels, current to
// previous), out (the output size, RGBA16F, storage). jx, jy: the jitter the scene took, render pixels. cam: the
// frame's camera. 0 on failure (the caller falls back as it does when DLSS fails).
int vk_ffx_upscale(VkCommandBuffer cb, const VkFfxImage *color, const VkFfxImage *depth, const VkFfxImage *mv,
const VkFfxImage *out, float jx, float jy, int reset, float dt_ms, const VkFfxCamera *cam);
void vk_ffx_release(void); // before the device goes away (the device idle)
// The upscale contexts of FSR 3.1 and FSR 4 (vk_dlaa.c retire_idle): any held, and let them all go (the caller's
// vk_upscaler_let_go frees them once the GPU is past them).
int vk_ffx_holds(void);
void vk_ffx_release_idle(void);
// FSR 3.1's contexts that no upscale used in the last `recent` calls, let go of: room for an FSR 4 context whose
// creation failed, whose caller makes their memory free (vk_ffx_dead_take after vk_upscaler_gpu_wait). Their count.
int vk_ffx_trim_idle(uint64_t recent);
// The FSR 3.1 and FSR 4 contexts let go of: those whose last upscale's submission is at most done are destroyed (their
// count); the highest such submission among those left (0: none).
int vk_ffx_dead_take(uint64_t done);
uint64_t vk_ffx_dead_fence(void);
// The device's functions as the library is given them (ffxCreateBackendVKDesc.vkDeviceProcAddr): its pipeline creates
// go through the runtime's pipeline caches (vk_pipeline.c vk_pipeline_create_foreign; NX2NAVI_FFX_PIPE_CACHE=0: not).
VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vk_ffx_proc_addr(VkDevice dev, const char *name);
// AMD FSR 4 (vk_ffx4.cpp): the ML upscaler of AMD's FSR SDK 2.4, through amd_fidelityfx_loader_vk.dll and
// amd_fidelityfx_upscaler_vk.dll beside the executable. vk_ffx_upscale runs it in FSR 3.1's place when the setting
// asks (NX2NAVI_FSR4) and it runs here, and falls back to FSR 3.1 when it fails.
int vk_ffx4_available(void); // the libraries are there and list a 4.x version for the device; asked once, with the
// device, from any thread (0 before the device exists)
const char *vk_ffx4_name(void); // "AMD FSR 4.1.2" once vk_ffx4_available found it
int vk_ffx4_upscale(VkCommandBuffer cb, const VkFfxImage *color, const VkFfxImage *depth, const VkFfxImage *mv,
const VkFfxImage *out, float jx, float jy, int reset, float dt_ms,
const VkFfxCamera *cam); // as vk_ffx_upscale
void vk_ffx4_release(void);
int vk_ffx4_holds(void); // an FSR 4 upscale context is made
void vk_ffx4_release_idle(void); // every FSR 4 upscale context let go of (vk_ffx_release_idle)
int vk_ffx4_dead_take(uint64_t done); // FSR 4's part of vk_ffx_dead_take
uint64_t vk_ffx4_dead_fence(void); // FSR 4's part of vk_ffx_dead_fence
int vk_ffx4_failed(void); // it failed three times in a row: FSR 3.1 serves until vk_ffx4_retry
void vk_ffx4_retry(void); // the menu chose FSR 4 again: try it anew after such failures
void vk_ffx4_trim(uint64_t now_ns); // at each upscale: FSR 4's contexts unused for a while go
uint64_t vk_ffx4_vram(int *contexts); // FSR 4's upscale contexts and their video memory (vk_ffx_vram)
int vk_ffx_fsr4(void); // the setting asks for FSR 4 and it runs here: what vk_ffx_upscale uses, for the menu
#if defined(__cplusplus) && !defined(VK_FFX_NO_API)
// The API's calls themselves, for vk_fg.cpp (0 = FFX_API_RETURN_OK): the library loaded first (vk_ffx_load).
#include "third_party/ffx_api/ffx_api.h"
extern "C" {
ffxReturnCode_t vk_ffx_create(ffxContext *ctx, ffxCreateContextDescHeader *desc);
ffxReturnCode_t vk_ffx_destroy(ffxContext *ctx);
ffxReturnCode_t vk_ffx_configure(ffxContext *ctx, const ffxConfigureDescHeader *desc);
ffxReturnCode_t vk_ffx_query(ffxContext *ctx, ffxQueryDescHeader *desc);
ffxReturnCode_t vk_ffx_dispatch(ffxContext *ctx, const ffxDispatchDescHeader *desc);
}
#endif