fix(linux): a Linux build with AMD FSR 4 compiles its own Vulkan back end, from AMD's FSR API headers the AppImage now carries #174

Merged
HumanBean merged 1 commit from HumanBean/Longshot:fix/linux-fsr4-own-backend into main 2026-11-13 10:30:55 +00:00
Owner

Why

AMD FSR 4 can't be had on Linux from the launcher or the AppImage: their builds use the AppImage's prebuilt Vulkan back end, compiled without FSR 4, so --fsr built a game whose Upscaler row never offers it (make_game.py only warned). The game's Linux FSR 4 path (gpu/vk/vk_fsr4.cpp, a Vulkan FSR 4 library through dlopen) has been there all along. The builds just never compiled it in.

What changed

  • build: prebuilt_renderer() in nx2/build.py sets LONGSHOT_VK_PREBUILT aside when LONGSHOT_FSR=1, as it already does for DLSS, so a build with FSR 4 compiles its own longshot_vk.so with AMD's FSR API headers (FSR_HEADERS).
  • make_game: main() in nx2/make_game.py works out fsr_wanted() and sets or clears LONGSHOT_FSR in one place, before check_cpu() and check_windows_sdk(), so a LONGSHOT_FSR=1 left in the shell is never taken for this build's. check_cpu(fsr) takes the build's decision rather than reading the environment: a build with FSR 4 compiles its own back end for this PC, so the prebuilt one's AVX2 doesn't stop it. The Linux prerequisite check (check_linux_prerequisites()) looks for the Vulkan headers the compile needs rather than the prebuilt .so, and lists AMD's FSR API headers as missing when a tool tree lacks them, before the game is read. (An AppImage made before this change carries the old make_game.py and build.py, which use the prebuilt back end without FSR 4 as before, so it never gets that far.) The old "prebuilt has no FSR 4" warning now says the back end is compiled here.
  • AppImage: scripts/linux/appimage.sh carries third_party/fidelityfx (AMD's MIT FSR API headers, already in the repository) and its licence under licenses/fidelityfx/. AMD's runtime is not among them: on Linux it's the player's own amd_fidelityfx_upscaler_vk.so, as before.
  • check: scripts/linux/check_player_build.sh runs the extracted image's build.py --dry-run a second time with LONGSHOT_FSR=1, and requires the "with AMD FSR 4" line.
  • tests: tests/test_linux_preflight.py gets test_fsr_overrides_prebuilt_renderer and test_fsr_without_its_headers_says_so_first; tests/test_cpu_target.py gets test_fsr_build_without_avx2_goes_on and test_fsr_in_the_shell_is_not_the_builds, clears LONGSHOT_FSR, and follows check_cpu(fsr); tests/test_appimage_player_build.py gets test_fsr_compiles_the_back_end_from_the_packaged_tree (a dry run from a packaged AppImage tree with LONGSHOT_FSR=1, like the DLSS one); tests/test_appimage_licenses.py covers the fidelityfx licence and headers; tests/test_make_game_ngx.py follows the new prebuilt_renderer() line.
  • README: the AMD FSR 4 section says what a Linux build with FSR 4 does and that the library is the player's.

The launcher side, its AMD FSR 4 switch on Linux, is MagicBeanDev/LongshotLauncher#24. It passes --fsr only when the tools carry third_party/fidelityfx, so it does nothing until a Longshot release with this change is out.

Flags and settings

Flag What it does Default now Recommendation Helps on Doesn't help on Untested on
make_game.py --fsr / LONGSHOT_FSR=1 (Linux) Now compiles the Vulkan back end with FSR 4 instead of using the AppImage's prebuilt one without it off (opt-in, unchanged) Keep opt-in: it needs the player's own FSR 4 library and adds the back end's compile (a few minutes) AMD RDNA 4 on Linux with a Vulkan FSR 4 library (e.g. fsr4-vk) Everyone else: no change unless they opt in A real game build from the AppImage with it (below)

Measurements

This changes how a Linux build is put together, not frame time, so the game-free checks are the measure for now. A game run on an AMD card is still owed (Testing).

main: 839e85ff (2026-11-13)
this PR: fix/linux-fsr4-own-backend @ 8f674e95
Hardware: build machine only (Linux, CachyOS, kernel 7.3.3)
Method: python -I -B tests/run_all.py (outside the sandbox), then the 2 failures re-run on a clean export of main

main @ 839e85ff this PR @ 8f674e95
tests/run_all.py the 2 failures below 465 passed, 2 failed (the same 2), 69 skipped
build.py --dry-run, LONGSHOT_FSR=1, LONGSHOT_VK_PREBUILT set "the Vulkan back end: …, as built" (the prebuilt one, no FSR 4) the prebuilt is set aside; it looks for the Vulkan headers to compile its own
465 passed, 2 failed, 69 skipped in 77 s (linux, 24 at once)
FAIL tests/test_bake_portability.py          (also fails on main 839e85ff)
FAIL tests/test_builder_log_read_only.py     (also fails on main 839e85ff)

Testing

Tested: the game-free checks above on Linux, including the new ones: test_linux_preflight (19), test_cpu_target, test_appimage_player_build (the FSR 4 dry run from a packaged AppImage tree passes here: the back end is compiled with AMD FSR 4 and no file is missing), test_appimage_licenses, test_make_game_ngx, test_shader_stamp_cache. In CI, the existing "longshot_vk.so with AMD FSR 4 (build check)" job compiles the back end with FSR 4, and check_player_build.sh's new step does the dry run from the real image.

Not tested: a full game build from the AppImage with --fsr, and FSR 4 in the game on Linux: this PC has an NVIDIA card. The game-side Linux FSR 4 path is unchanged and was run on an RX 9070 XT with fsr4-vk (docs/tested-configurations.md, 2026-11-11).

Needs other testers:

  • Linux, AMD RX 9000 with Mesa RADV and a Vulkan FSR 4 library (fsr4-vk): build from this PR's AppImage with --cli … --fsr, put amd_fidelityfx_upscaler_vk.so beside the game, and check that the Upscaler row offers AMD FSR 4 and the log's vk: AMD FSR 4: line names it (T-MARB)

Screenshots

Nothing on screen.

Risk and rollback

Only builds that ask for FSR 4 change. A Linux --fsr build now compiles the Vulkan back end (a few minutes longer) where it used the prebuilt one before, and it needs the build tools' Vulkan headers, as DLSS builds already do. Nothing changes for builds without --fsr or on Windows. The AppImage grows by AMD's headers (about 100 KB). Reverting the commit is enough.

Reviewer notes

Start with prebuilt_renderer() in nx2/build.py and the move of the LONGSHOT_FSR switch in make_game.py's main(). After the self-review: the switch is set or cleared in one place before the checks, check_cpu takes the decision as an argument, and the missing-headers check moved from build.py to make_game.py's Linux prerequisites.

Issues

See MagicBeanDev/LongshotLauncher#24 (the launcher's AMD FSR 4 switch on Linux).

Checklist

For everyone

  • One topic.
  • The title is a Conventional Commit (type(scope): description).
  • Rebased on current main.
  • python -I -B tests/run_all.py run and passing (any failure that also fails on main is named above).
  • Tested in the game, or what wasn't is named under Testing.
  • Testing filled in: what was tested, what wasn't, and what needs other testers (with test requests).
  • Measured: main and this PR at named commits, on the same PC, scene and settings, at least 2 interleaved runs each, the median reported. (open: a Linux AMD build and run with FSR 4 is owed; the PR stays WIP until then)
  • No game files, dumps, build output or generated files.
  • third_party/ untouched (a new folder with a PROVENANCE.md instead).
  • The license is OK: GPL-3.0-or-later, nothing incompatible and nothing decompiled.

If applicable

  • AI assistance recorded with Assisted-by: / Co-Authored-By: trailers.
  • Flags noted, and the switch reference updated (docs/development.md, the README).
  • A game-free test added for the fix, failing on main and passing here.
  • A check under tests/ that reads changed source updated in this PR, not weakened.
  • Docs updated.

🤖 Generated with Claude Code

## Why AMD FSR 4 can't be had on Linux from the launcher or the AppImage: their builds use the AppImage's prebuilt Vulkan back end, compiled without FSR 4, so `--fsr` built a game whose Upscaler row never offers it (make_game.py only warned). The game's Linux FSR 4 path (`gpu/vk/vk_fsr4.cpp`, a Vulkan FSR 4 library through `dlopen`) has been there all along. The builds just never compiled it in. ## What changed - build: `prebuilt_renderer()` in `nx2/build.py` sets `LONGSHOT_VK_PREBUILT` aside when `LONGSHOT_FSR=1`, as it already does for DLSS, so a build with FSR 4 compiles its own `longshot_vk.so` with AMD's FSR API headers (`FSR_HEADERS`). - make_game: `main()` in `nx2/make_game.py` works out `fsr_wanted()` and sets *or clears* `LONGSHOT_FSR` in one place, before `check_cpu()` and `check_windows_sdk()`, so a `LONGSHOT_FSR=1` left in the shell is never taken for this build's. `check_cpu(fsr)` takes the build's decision rather than reading the environment: a build with FSR 4 compiles its own back end for this PC, so the prebuilt one's AVX2 doesn't stop it. The Linux prerequisite check (`check_linux_prerequisites()`) looks for the Vulkan headers the compile needs rather than the prebuilt `.so`, and lists AMD's FSR API headers as missing when a tool tree lacks them, before the game is read. (An AppImage made before this change carries the old make_game.py and build.py, which use the prebuilt back end without FSR 4 as before, so it never gets that far.) The old "prebuilt has no FSR 4" warning now says the back end is compiled here. - AppImage: `scripts/linux/appimage.sh` carries `third_party/fidelityfx` (AMD's MIT FSR API headers, already in the repository) and its licence under `licenses/fidelityfx/`. AMD's runtime is not among them: on Linux it's the player's own `amd_fidelityfx_upscaler_vk.so`, as before. - check: `scripts/linux/check_player_build.sh` runs the extracted image's `build.py --dry-run` a second time with `LONGSHOT_FSR=1`, and requires the "with AMD FSR 4" line. - tests: `tests/test_linux_preflight.py` gets `test_fsr_overrides_prebuilt_renderer` and `test_fsr_without_its_headers_says_so_first`; `tests/test_cpu_target.py` gets `test_fsr_build_without_avx2_goes_on` and `test_fsr_in_the_shell_is_not_the_builds`, clears `LONGSHOT_FSR`, and follows `check_cpu(fsr)`; `tests/test_appimage_player_build.py` gets `test_fsr_compiles_the_back_end_from_the_packaged_tree` (a dry run from a packaged AppImage tree with `LONGSHOT_FSR=1`, like the DLSS one); `tests/test_appimage_licenses.py` covers the fidelityfx licence and headers; `tests/test_make_game_ngx.py` follows the new `prebuilt_renderer()` line. - README: the AMD FSR 4 section says what a Linux build with FSR 4 does and that the library is the player's. The launcher side, its AMD FSR 4 switch on Linux, is https://git.magicbean.dev/MagicBeanDev/LongshotLauncher/pulls/24. It passes `--fsr` only when the tools carry `third_party/fidelityfx`, so it does nothing until a Longshot release with this change is out. ## Flags and settings | Flag | What it does | Default now | Recommendation | Helps on | Doesn't help on | Untested on | |---|---|---|---|---|---|---| | `make_game.py --fsr` / `LONGSHOT_FSR=1` (Linux) | Now compiles the Vulkan back end with FSR 4 instead of using the AppImage's prebuilt one without it | off (opt-in, unchanged) | Keep opt-in: it needs the player's own FSR 4 library and adds the back end's compile (a few minutes) | AMD RDNA 4 on Linux with a Vulkan FSR 4 library (e.g. fsr4-vk) | Everyone else: no change unless they opt in | A real game build from the AppImage with it (below) | ## Measurements This changes how a Linux build is put together, not frame time, so the game-free checks are the measure for now. A game run on an AMD card is still owed (Testing). main: 839e85ff (2026-11-13) this PR: fix/linux-fsr4-own-backend @ 8f674e95 Hardware: build machine only (Linux, CachyOS, kernel 7.3.3) Method: `python -I -B tests/run_all.py` (outside the sandbox), then the 2 failures re-run on a clean export of main | | main @ 839e85ff | this PR @ 8f674e95 | |---|---|---| | tests/run_all.py | the 2 failures below | 465 passed, 2 failed (the same 2), 69 skipped | | `build.py --dry-run`, `LONGSHOT_FSR=1`, `LONGSHOT_VK_PREBUILT` set | "the Vulkan back end: …, as built" (the prebuilt one, no FSR 4) | the prebuilt is set aside; it looks for the Vulkan headers to compile its own | ``` 465 passed, 2 failed, 69 skipped in 77 s (linux, 24 at once) FAIL tests/test_bake_portability.py (also fails on main 839e85ff) FAIL tests/test_builder_log_read_only.py (also fails on main 839e85ff) ``` ## Testing **Tested:** the game-free checks above on Linux, including the new ones: test_linux_preflight (19), test_cpu_target, test_appimage_player_build (the FSR 4 dry run from a packaged AppImage tree passes here: the back end is compiled with AMD FSR 4 and no file is missing), test_appimage_licenses, test_make_game_ngx, test_shader_stamp_cache. In CI, the existing "longshot_vk.so with AMD FSR 4 (build check)" job compiles the back end with FSR 4, and check_player_build.sh's new step does the dry run from the real image. **Not tested:** a full game build from the AppImage with `--fsr`, and FSR 4 in the game on Linux: this PC has an NVIDIA card. The game-side Linux FSR 4 path is unchanged and was run on an RX 9070 XT with fsr4-vk (docs/tested-configurations.md, 2026-11-11). **Needs other testers:** - Linux, AMD RX 9000 with Mesa RADV and a Vulkan FSR 4 library (fsr4-vk): build from this PR's AppImage with `--cli … --fsr`, put `amd_fidelityfx_upscaler_vk.so` beside the game, and check that the Upscaler row offers AMD FSR 4 and the log's `vk: AMD FSR 4:` line names it (T-MARB) ## Screenshots Nothing on screen. ## Risk and rollback Only builds that ask for FSR 4 change. A Linux `--fsr` build now compiles the Vulkan back end (a few minutes longer) where it used the prebuilt one before, and it needs the build tools' Vulkan headers, as DLSS builds already do. Nothing changes for builds without `--fsr` or on Windows. The AppImage grows by AMD's headers (about 100 KB). Reverting the commit is enough. ## Reviewer notes Start with `prebuilt_renderer()` in nx2/build.py and the move of the `LONGSHOT_FSR` switch in make_game.py's `main()`. After the self-review: the switch is set or cleared in one place before the checks, `check_cpu` takes the decision as an argument, and the missing-headers check moved from build.py to make_game.py's Linux prerequisites. ## Issues See https://git.magicbean.dev/MagicBeanDev/LongshotLauncher/pulls/24 (the launcher's AMD FSR 4 switch on Linux). ## Checklist ### For everyone - [x] One topic. - [x] The title is a Conventional Commit (`type(scope): description`). - [x] Rebased on current `main`. - [x] `python -I -B tests/run_all.py` run and passing (any failure that also fails on `main` is named above). - [x] Tested in the game, or what wasn't is named under Testing. - [x] Testing filled in: what was tested, what wasn't, and what needs other testers (with test requests). - [ ] Measured: main and this PR at named commits, on the same PC, scene and settings, at least 2 interleaved runs each, the median reported. *(open: a Linux AMD build and run with FSR 4 is owed; the PR stays WIP until then)* - [x] No game files, dumps, build output or generated files. - [x] `third_party/` untouched (a new folder with a `PROVENANCE.md` instead). - [x] The license is OK: GPL-3.0-or-later, nothing incompatible and nothing decompiled. ### If applicable - [x] AI assistance recorded with `Assisted-by:` / `Co-Authored-By:` trailers. - [x] Flags noted, and the switch reference updated (docs/development.md, the README). - [x] A game-free test added for the fix, failing on `main` and passing here. - [x] A check under `tests/` that reads changed source updated in this PR, not weakened. - [x] Docs updated. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Author
Owner

Linked the launcher side: MagicBeanDev/LongshotLauncher#24 (its AMD FSR 4 switch on Linux, which passes --fsr only when the tools carry third_party/fidelityfx). Added LONGSHOT_VK_PREBUILT to docs/development.md's build switches.

Linked the launcher side: https://git.magicbean.dev/MagicBeanDev/LongshotLauncher/pulls/24 (its AMD FSR 4 switch on Linux, which passes --fsr only when the tools carry third_party/fidelityfx). Added LONGSHOT_VK_PREBUILT to docs/development.md's build switches.
Author
Owner

Test request T-MARB is open for the Linux AMD run with FSR 4.

Test request T-MARB is open for the Linux AMD run with FSR 4.
HumanBean left a comment

Code review only: I read the diff and the code around it, and ran no tests or builds.

Verdict: the approach holds. prebuilt_renderer() is the single switch, build is imported lazily in check_linux_prerequisites() so it reads LONGSHOT_FSR after main() sets it, and the AppImage's FSR dry run in check_player_build.sh should pass: AppRun's build_tools gives RX_CPM and clang++ from tools.lock, and cp -a third_party/fidelityfx carries all four headers vk_fsr4.cpp includes. Some things to fix before ready, most important first:

  1. (medium) LONGSHOT_FSR from the environment is cleared too late (make_game.py main()). The else: os.environ.pop("LONGSHOT_FSR") now runs after check_cpu() and check_windows_sdk(). So LONGSHOT_FSR=1 exported, with --no-fsr or without --fsr, makes check_cpu() skip the AVX2 stop and makes the preflight look for headers instead of the prebuilt. The build itself then uses the prebuilt back end, and on a CPU without AVX2 that is the "40 minutes in" failure issue 363 was about. Set the variable or pop it in one place, before the checks (or pass fsr to check_cpu).
  2. (low) The new header check guards a case that can't happen, and the description says it can (build.py elif build_vk:). An AppImage made before this change carries the old build.py, which uses its prebuilt and never reaches this line, and with this change the image always carries the headers. If you keep it, the preflight (check_linux_prerequisites, which already reads build.prebuilt_renderer()) is the place that runs before the game is read. Either way, the "an AppImage made before this change" wording in the description and the comment should go.
  3. (low) Tests: the new check_cpu branch and the move of LONGSHOT_FSR ahead of check_cpu() in main() have no check. tests/test_cpu_target.py AppImageCheck.run_check clears LONGSHOT_VK_PREBUILT and RX_MARCH but not LONGSHOT_FSR, so with LONGSHOT_FSR=1 in the shell, test_appimage_without_avx2_stops now fails. tests/test_appimage_player_build.py has test_dlss_compiles_the_back_end_from_the_packaged_tree, and an FSR twin of it would cover the image path without CI.
  4. (nit) Docs: the README names "the launcher's AMD FSR 4 switch", which doesn't exist on Linux until LongshotLauncher#24 lands (MagicBeanDev/LongshotLauncher#24). The CI comment in .forgejo/workflows/build-linux.yml ("a build option the AppImage leaves off") is now half true.
Code review only: I read the diff and the code around it, and ran no tests or builds. **Verdict:** the approach holds. `prebuilt_renderer()` is the single switch, `build` is imported lazily in `check_linux_prerequisites()` so it reads `LONGSHOT_FSR` after `main()` sets it, and the AppImage's FSR dry run in `check_player_build.sh` should pass: AppRun's `build_tools` gives `RX_CPM` and clang++ from tools.lock, and `cp -a third_party/fidelityfx` carries all four headers `vk_fsr4.cpp` includes. Some things to fix before ready, most important first: 1. **(medium) `LONGSHOT_FSR` from the environment is cleared too late** (make_game.py `main()`). The `else: os.environ.pop("LONGSHOT_FSR")` now runs after `check_cpu()` and `check_windows_sdk()`. So `LONGSHOT_FSR=1` exported, with `--no-fsr` or without `--fsr`, makes `check_cpu()` skip the AVX2 stop and makes the preflight look for headers instead of the prebuilt. The build itself then uses the prebuilt back end, and on a CPU without AVX2 that is the "40 minutes in" failure issue 363 was about. Set the variable or pop it in one place, before the checks (or pass `fsr` to `check_cpu`). 2. **(low) The new header check guards a case that can't happen, and the description says it can** (build.py `elif build_vk:`). An AppImage made before this change carries the old build.py, which uses its prebuilt and never reaches this line, and with this change the image always carries the headers. If you keep it, the preflight (`check_linux_prerequisites`, which already reads `build.prebuilt_renderer()`) is the place that runs before the game is read. Either way, the "an AppImage made before this change" wording in the description and the comment should go. 3. **(low) Tests:** the new `check_cpu` branch and the move of `LONGSHOT_FSR` ahead of `check_cpu()` in `main()` have no check. `tests/test_cpu_target.py` `AppImageCheck.run_check` clears `LONGSHOT_VK_PREBUILT` and `RX_MARCH` but not `LONGSHOT_FSR`, so with `LONGSHOT_FSR=1` in the shell, `test_appimage_without_avx2_stops` now fails. `tests/test_appimage_player_build.py` has `test_dlss_compiles_the_back_end_from_the_packaged_tree`, and an FSR twin of it would cover the image path without CI. 4. **(nit) Docs:** the README names "the launcher's **AMD FSR 4** switch", which doesn't exist on Linux until LongshotLauncher#24 lands (https://git.magicbean.dev/MagicBeanDev/LongshotLauncher/pulls/24). The CI comment in `.forgejo/workflows/build-linux.yml` ("a build option the AppImage leaves off") is now half true.
README.md Outdated
@ -927,2 +927,3 @@
says so and offers the rest. On Linux, a Vulkan FSR 4 library (`amd_fidelityfx_upscaler_vk.so`, such as fsr4-vk's)
takes their place.
takes their place: AMD publishes none for Linux, so you put it beside the game yourself. A Linux build with FSR 4
(the launcher's **AMD FSR 4** switch, or `--fsr`) compiles its own Vulkan back end, as with DLSS, since the AppImage's
Author
Owner

(nit) The launcher's AMD FSR 4 switch on Linux is LongshotLauncher#24 (MagicBeanDev/LongshotLauncher#24), not merged yet. Maybe "(--fsr, or the launcher's AMD FSR 4 switch where it offers it)".

(nit) The launcher's AMD FSR 4 switch on Linux is LongshotLauncher#24 (https://git.magicbean.dev/MagicBeanDev/LongshotLauncher/pulls/24), not merged yet. Maybe "(`--fsr`, or the launcher's **AMD FSR 4** switch where it offers it)".
nx2/build.py Outdated
@ -1158,6 +1160,11 @@ def main():
return 1
elif build_vk:
print("the Vulkan back end: Vulkan %s, SPIR-V %s, VMA %s" % (vk_headers, spirv_headers, vma_headers), flush=True)
if FSR and not os.path.isfile(os.path.join(FSR_HEADERS, "api", "include", "ffx_api.h")):
Author
Owner

(low) An AppImage from before this change has the old build.py, which takes its prebuilt and never gets here, and from now on the image always carries third_party/fidelityfx. So this guards a case that can't happen through the AppImage. If it stays, check_linux_prerequisites() is where it would be said before the game is read. The comment, and the PR description's "an AppImage made before this change", should be reworded either way.

(low) An AppImage from before this change has the old build.py, which takes its prebuilt and never gets here, and from now on the image always carries `third_party/fidelityfx`. So this guards a case that can't happen through the AppImage. If it stays, `check_linux_prerequisites()` is where it would be said before the game is read. The comment, and the PR description's "an AppImage made before this change", should be reworded either way.
nx2/make_game.py Outdated
@ -593,2 +593,2 @@
its start. Said now, before the game is read, not 40 minutes in (issue 363)"""
if not os.environ.get("LONGSHOT_VK_PREBUILT") or os.environ.get("RX_MARCH"):
its start. Said now, before the game is read, not 40 minutes in (issue 363). A build with AMD FSR 4 compiles its own"""
if not os.environ.get("LONGSHOT_VK_PREBUILT") or os.environ.get("RX_MARCH") or os.environ.get("LONGSHOT_FSR") == "1":
Author
Owner

Reads the environment rather than the build's decision, which is what makes the ordering in main() matter (see the comment there). Passing fsr in, or popping the variable before this runs, would make it robust. A case in tests/test_cpu_target.py (FSR set + prebuilt + x86-64-v2 goes on) would pin it down, and run_check there should also clear LONGSHOT_FSR.

Reads the environment rather than the build's decision, which is what makes the ordering in `main()` matter (see the comment there). Passing `fsr` in, or popping the variable before this runs, would make it robust. A case in `tests/test_cpu_target.py` (FSR set + prebuilt + `x86-64-v2` goes on) would pin it down, and `run_check` there should also clear `LONGSHOT_FSR`.
nx2/make_game.py Outdated
@ -2182,1 +2182,4 @@
check_writable(out)
# (AMD FSR 4: the build's switch for nx2/build.py, set before the checks: on Linux it compiles its own Vulkan back end, as
# with DLSS, so the AppImage's prebuilt one is neither checked nor used)
fsr = fsr_wanted(a, out)
Author
Owner

(medium) fsr is decided here, but LONGSHOT_FSR is only popped in the else at the end of this block, after check_cpu() and check_windows_sdk(). With LONGSHOT_FSR=1 inherited and --no-fsr (or no --fsr), check_cpu() skips the AVX2 stop and the preflight checks headers rather than the prebuilt, yet build.py then runs with the prebuilt back end. Suggest if fsr: os.environ[...] = "1" / else: os.environ.pop("LONGSHOT_FSR", None) right here, keeping only the mark handling below.

(medium) `fsr` is decided here, but `LONGSHOT_FSR` is only popped in the `else` at the end of this block, after `check_cpu()` and `check_windows_sdk()`. With `LONGSHOT_FSR=1` inherited and `--no-fsr` (or no `--fsr`), `check_cpu()` skips the AVX2 stop and the preflight checks headers rather than the prebuilt, yet build.py then runs with the prebuilt back end. Suggest `if fsr: os.environ[...] = "1"` / `else: os.environ.pop("LONGSHOT_FSR", None)` right here, keeping only the mark handling below.
@ -58,0 +59,4 @@
echo "== the same with AMD FSR 4 (make_game.py --fsr): the Vulkan back end compiled from the image's sources and AMD's headers"
(cd "$T" && in_image env OOT_WORK="$TMP/work-fsr" RX_RELEASE=1 A64_HOT_CHUNK=1 PYTHONIOENCODING=utf-8 LONGSHOT_FSR=1 \
"$R/usr/python/bin/python3" -I -B -u -X utf8 nx2/build.py --standalone --jobs 1 --dry-run) | tee "$TMP/fsr.txt"
grep -q "with AMD FSR 4" "$TMP/fsr.txt" || { echo "a build with AMD FSR 4 did not compile its own Vulkan back end"; exit 1; }
Author
Owner

This looks sound: build_tools gives RX_CPM and clang++, the grep string only comes from the if FSR: print in the compile block, and pipefail carries the dry run's exit code through tee. A game-free twin in tests/test_appimage_player_build.py, like test_dlss_compiles_the_back_end_from_the_packaged_tree, would cover the image path locally too.

This looks sound: `build_tools` gives `RX_CPM` and clang++, the `grep` string only comes from the `if FSR:` print in the compile block, and `pipefail` carries the dry run's exit code through `tee`. A game-free twin in `tests/test_appimage_player_build.py`, like `test_dlss_compiles_the_back_end_from_the_packaged_tree`, would cover the image path locally too.
HumanBean force-pushed fix/linux-fsr4-own-backend from 68e659a4b2
All checks were successful
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Has been skipped
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Has been skipped
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Has been skipped
Third-party parts / The same as upstream (pull_request) Has been skipped
CI / Conventional Commit title (pull_request) Successful in 2s
CI / Workflow lint (actionlint) (pull_request) Successful in 6s
Third-party parts / As their notes say (pull_request) Successful in 7s
PR description / Description follows the template (pull_request_target) Successful in 3s
to 8f674e95ab
Some checks failed
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Has been skipped
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Has been skipped
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Has been skipped
Third-party parts / The same as upstream (pull_request) Has been skipped
CI / Conventional Commit title (pull_request) Successful in 3s
Third-party parts / As their notes say (pull_request) Successful in 7s
CI / Workflow lint (actionlint) (pull_request) Successful in 8s
PR description / Description follows the template (pull_request_target) Failing after 8s
2026-11-13 10:28:13 +00:00
Compare
Author
Owner

Self-review fixes (8f674e95): LONGSHOT_FSR is set or cleared in one place before the checks, so one left in the shell no longer skips check_cpu for a build that uses the prebuilt back end; check_cpu takes the build's FSR decision; the missing-headers check moved from build.py (where it couldn't fire) to make_game.py's Linux prerequisites, and the description no longer claims it covers old AppImages; new tests in test_cpu_target, test_linux_preflight and test_appimage_player_build (an FSR 4 dry run from a packaged AppImage tree, passing); README and build-linux.yml comment corrected. run_all: 465 passed, 2 failed, the same 2 as main.

Self-review fixes (8f674e95): LONGSHOT_FSR is set or cleared in one place before the checks, so one left in the shell no longer skips check_cpu for a build that uses the prebuilt back end; check_cpu takes the build's FSR decision; the missing-headers check moved from build.py (where it couldn't fire) to make_game.py's Linux prerequisites, and the description no longer claims it covers old AppImages; new tests in test_cpu_target, test_linux_preflight and test_appimage_player_build (an FSR 4 dry run from a packaged AppImage tree, passing); README and build-linux.yml comment corrected. run_all: 465 passed, 2 failed, the same 2 as main.
HumanBean changed title from WIP: fix(linux): a Linux build with AMD FSR 4 compiles its own Vulkan back end, from AMD's FSR API headers the AppImage now carries to fix(linux): a Linux build with AMD FSR 4 compiles its own Vulkan back end, from AMD's FSR API headers the AppImage now carries 2026-11-13 10:30:50 +00:00
HumanBean deleted branch fix/linux-fsr4-own-backend 2026-11-13 10:30:56 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
MagicBeanDev/Longshot!174
No description provided.