Skip to content

Run FSR 4 on Linux through a Vulkan FSR 4 library - #857

Closed
N3oTraX wants to merge 5 commits into
NotRexed:mainfrom
N3oTraX:linux/fsr4-native
Closed

N3oTraX wants to merge 5 commits into
NotRexed:mainfrom
N3oTraX:linux/fsr4-native

Conversation

@N3oTraX

@N3oTraX N3oTraX commented Nov 8, 2026 •

Copy link
Copy Markdown

Makes the FSR 4.1 path of #828 work on native Linux.

Stacked on #828 (which contains #818). Only the last two commits are new here; GitHub also shows the commits of those PRs until they land. I will rebase then.

What changed

  • Loading: there is no AMD loader for Linux, so the upscaler library itself (amd_fidelityfx_upscaler_vk.so) is loaded with dlopen, from RX_FSR4_DIR or beside the game.
  • Backend description: the library reads the SDK's older backend type, so ffxCreateBackendVKDesc_DEPRECATED is chained next to the current one. Without it, creation returned FFX_API_RETURN_ERROR_PARAMETER.
  • VK_EXT_descriptor_buffer: the library records with it. It is requested only when the library is present.
  • Provider choice: the first of equal versions is kept instead of the last. The library lists Auto, INT8, FP8, so the last one forced FP8 on hardware without it.
  • Exposure: the library rejects a dispatch without an exposure, and the colour is already tonemapped, so it gets a 1x1 R32_SFLOAT of 1.
  • BITMAPFILEHEADER joins the POSIX windows.h shim: the menu dump from NVIDIA DLSS, Output resolution and a full-size 3D at 4K #818 did not build on Linux.

No AMD binary is added or downloaded. Without a library, the game's upscale stays.

How it was tested

GPU, driver RX 7900 XTX (RDNA3), RADV Mesa 26.2.6
System Linux 7.3.1, Hyprland
Game v131072, build e0f3ccfa, Kokiri Forest
Library third-party fsr4-vk b0125ea, built locally from AMD's SDK DLL. Not affiliated with AMD; whether to use it is the user's call
Result FSR 4.1.1 Vulkan INT8, 3416x1440 to 3416x1440, FSR draws the upscale from frame 835, no crash or device lost in the log
Checks tests/run_all.py fsr menu upscale resolution: 5 passed. The full suite was not run

fps before and after: not measured.

The test had to run with RX_VK_NO_WARM=1, RX_VK_NO_PREDICT=1 and RX_VK_PRECOMPILE=0, because v2.0.5 crashes in the driver on this Mesa (#803, precompile_run). It also set RX_VK_ANISO=16.

Not tested

  • 3840x2160 output, and upscaling from 75% or lower.
  • RDNA2, RDNA4, and FP8.
  • Windows: not compiled or run here. The Linux code is behind _WIN32 guards; only the provider choice above is shared.

🤖 Generated with Claude Code

BlueHeisenberg and others added 5 commits November 8, 2026 23:20
… 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.
…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 <noreply@anthropic.com>
…on top of NotRexed#818's DLSS frame code)

A second backend for NotRexed#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 (NotRexed#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 <noreply@anthropic.com>
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 <noreply@anthropic.com>
… 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 <noreply@anthropic.com>
@madebyjordan

Copy link
Copy Markdown
Contributor

Thanks for this. Linux support is great, and your provider fix helps Windows too (RDNA 2 has no FP8).

#828 is the shared branch for FSR 4.1, so contributions all land in one place. Could you open this as a PR against madebyjordan/hookshot-amd, branch amd/fsr4? It applies cleanly. One heads-up: since you branched, I made vk_fsr4.cpp Windows-only, which would hide your Linux code. I'll remove that when yours comes in.

If you'd rather not open another PR, I can copy your two commits over myself with your name kept and credit you in #828. Whichever you prefer.

@N3oTraX

N3oTraX commented Nov 8, 2026

Copy link
Copy Markdown
Author

Thanks! Opened against amd/fsr4: madebyjordan#2. It also removes the Windows-only guard, so you don't have to. I'll keep this one until that lands.

@madebyjordan

Copy link
Copy Markdown
Contributor

Merged into amd/fsr4 (madebyjordan#2), so it is part of #828 now, with you credited for Linux support. Thanks for rebasing it onto the new head. Feel free to close this one whenever suits you.

@N3oTraX
N3oTraX marked this pull request as ready for review November 9, 2026 00:06
@N3oTraX

N3oTraX commented Nov 9, 2026

Copy link
Copy Markdown
Author

Closing: this landed in amd/fsr4 through madebyjordan#2, which #828 carries. #871 builds on it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants