Skip to content

AMD FSR 4.1 (collaboration branch) - #828

Closed
madebyjordan wants to merge 8 commits into
NotRexed:mainfrom
madebyjordan:amd/fsr4
Closed

madebyjordan wants to merge 8 commits into
NotRexed:mainfrom
madebyjordan:amd/fsr4

Conversation

@madebyjordan

@madebyjordan madebyjordan commented Nov 8, 2026 •

Copy link
Copy Markdown
Contributor

Adds AMD FSR 4.1 in place of OoT's own upscale: steadier edges and less shimmer. Opt-in from the Insert menu, off by default. Windows, and Linux with a Vulkan FSR 4 library.

Builds on #850 (DLSS), which builds on #849. The new commits are 040a9ab, 211585a and N3oTraX's Linux support (merged as bb87ae2).

How it works

  • Uses NVIDIA DLSS in place of the game's upscale (optional, RTX GPUs) #850's colour, depth and camera motion. FSR is a second backend; DLSS wins if both are on.
  • Moves the 3D by a sub-pixel amount each frame, the jitter FSR needs to rebuild detail. The game draws without one.
  • AMD's two signed DLLs load at run time from beside hookshot.exe. Only AMD's MIT headers are added; no AMD binaries.
  • The Resolution row sets the input size: 75% = Quality, 50% = Performance, 100% = anti-aliasing only.

Tested

  • RX 6700 XT (RDNA 2), Windows: FSR 4.1.2, 1536x864 to 2048x1152.
  • RX 7900 XTX (RDNA 3), Linux (N3oTraX): FSR 4.1.1 INT8 at 3416x1440 and 5120x2160, no crash or device loss. It used a third-party Vulkan FSR 4 library (fsr4-vk); none is included here.
  • No errors and no fallbacks to the game's upscale. FSR kept its history the whole session.
  • Looks right: no edge flicker or haze stripes, which the same code had on the Lichii emulator.
  • tests/run_all.py: 94 passed, including the new test_fsr_jitter.py. The 3 failures also fail on NVIDIA DLSS in place of the game's upscale (optional, RTX GPUs) #850's head on this PC.

Not yet

Using it

Put amd_fidelityfx_loader_vk.dll and amd_fidelityfx_upscaler_vk.dll (FidelityFX SDK 2.4, signedbin) beside bin\hookshot.exe, then turn on Insert → Graphics → AMD FSR 4.1. On Linux, put a Vulkan FSR 4 library (amd_fidelityfx_upscaler_vk.so) beside the game instead. Overrides: RX_FSR4=0/1, RX_FSR4_DIR, RX_FSR4_JITTER=0.

Related

#577 uses the same AMD API for FSR 4 at native resolution; the vendored headers are identical, so either can land first. #821/#822 take a different route (FSR 3.1 compiled from AMD's source code).

Linux support by @N3oTraX (from #857). Ported from my FSR 4.1 work on Lichii (madebyjordan/Lichii-Hyrule). AI-assisted (Claude Code).

🤖 Generated with Claude Code

…ze 3D at 3840x2160, and the Resolution row reaching the 3D

- 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, and the graphics scale reads x1 for a chosen output; 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.
  At 2048x1152 and 2560x1440 nothing changes.
- 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 row shows the 3D's size for the chosen output, and follows the Output resolution row at once.
- Test switches: HOS_RES_LOG (the 3D's scale in the log), RX_VK_SHOT_W/H (the screenshots' size), RX_VK_MENU_SCRIPT (timed
  menu keys) and RX_VK_MENU_DUMP (each drawing of the menu as a BMP).
…A's DLLs not included)

- 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, gpu/PROVENANCE.md). sl.interposer.dll, sl.common.dll,
  sl.dlss.dll and nvngx_dlss.dll are loaded from a streamline folder beside the game exe, or the NVIDIA app's DLSS; the
  interposer and the model must carry a valid NVIDIA Corporation signature (WinVerifyTrust). Windows only: elsewhere DLSS is
  unavailable.
- Menu rows DLSS (after a restart), DLSS mode (Ultra Performance .. DLAA, each with its size for the chosen output; it sets the
  3D's scale in place of Resolution) and DLSS preset (J..M, at once); RX_DLSS, RX_DLSS_PRESET, RX_DLSS_DIR over them,
  RX_DLSS_DEBUG for its inputs. The scale sent to the game is for the output it runs at (the window crop).
- readme: the rows, where NVIDIA's files come from; the Lichii credit.
@madebyjordan madebyjordan changed the title AMD FSR 4.1 as a second backend for #818, with a sub-pixel jitter (AMD RDNA2 fixes from Lichii) AMD FSR 4.1 (collaboration branch, WIP) Nov 8, 2026
madebyjordan and others added 2 commits November 8, 2026 23:48
…on top of NotRexed#850's DLSS frame code)

A second backend for NotRexed#850'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>
… images given back

- The FSR context is made with FFX_UPSCALE_ENABLE_DYNAMIC_RESOLUTION: the
  render size changes under it with the Resolution row and the game's
  dynamic resolution.
- vk_fsr4.cpp is Windows only (AMD's signed runtime is), with stubs
  elsewhere: the Linux build has no LoadLibraryExA.
- AMD's dispatches count as work (note_work, vk_work.h), so full_barrier
  does not leave out the barrier after them as a repeat.
- dlss_image gives a replaced image back 120 presents later, as
  typed_upscale does with its histories, instead of keeping it: DLSS
  fixes the render size, but FSR can run with Resolution Auto.
- The dlss_*.comp headers regenerated at SPIR-V 1.6, as NotRexed#850 makes them.
- readme: FSR 4 claims limited to what was tested (RX 6700 XT, INT8).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@madebyjordan madebyjordan changed the title AMD FSR 4.1 (collaboration branch, WIP) AMD FSR 4.1 (collaboration branch) Nov 8, 2026
@madebyjordan
madebyjordan marked this pull request as ready for review November 8, 2026 23:51
N3oTraX and others added 3 commits November 9, 2026 00:52
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>
The file was Windows-only, which hid the Linux loading. Remove the
guard and its stubs, and say in the readme what Linux needs.

Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Run FSR 4 on Linux through a Vulkan FSR 4 library
@NotRexed

NotRexed commented Nov 9, 2026

Copy link
Copy Markdown
Owner

Thank you! This is still stacked on #818, which was closed and split into #849 (merged) and #850. Closing to keep the queue clear — please rebase on current main and reopen; thanks! (Onto main, or onto #850 once it is back.)

@madebyjordan

Copy link
Copy Markdown
Contributor Author

Rebased onto current main. GitHub won't let me reopen this one, so it continues in #1008. #850 is closed too, so it now carries #850's DLSS commit unchanged (BlueHeisenberg's, credited), since FSR builds on its colour, depth and motion code. Merges cleanly; build and tests pass.

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.

4 participants