perf(vk): the renderer is built with a committed play profile, about 3-5 % less frame time #569
No reviewers
Labels
No labels
area/accessibility
area/audio
area/input
area/install
area/menu
area/renderer
area/saves
area/upscaling
beanstalk: approved @ 1697603
beanstalk: approved @ 2c5a62e
beanstalk: approved @ 4fd82b7
beanstalk: approved @ 64d6d09
beanstalk: approved @ 6f91fae
beanstalk: approved @ 70a78f9
beanstalk: approved @ 8015c9a
beanstalk: approved @ 8d361dc
beanstalk: approved @ 9d8356e
beanstalk: approved @ abf2227
beanstalk: approved @ d82f202
beanstalk: approved @ e5f1e40
beanstalk: approved @ ee8ab5f
ci: approved
good first issue
gpu/amd
gpu/igpu
gpu/intel
gpu/nvidia
help wanted
kind
bug
kind
chore
kind
docs
kind
feature
kind
performance
kind
question
needs measurements
platform/linux
platform/macos
platform/steam-deck
platform/windows
preview
priority
critical
priority
high
priority
low
regression
status
blocked
status
confirmed
status
duplicate
status
invalid
status
needs-info
status
wontfix
testing wanted
ci: approved
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
MagicBeanDev/Longshot!569
Loading…
Reference in a new issue
No description provided.
Delete branch "HumanBean/Longshot:perf/vk-profile"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Why
The renderer's replay is the frame's limit in heavy places, and compiling it with a play profile makes it about 3-5 % faster per frame at almost no build cost. Most players build with DLSS or FSR 4, which compile the renderer on their own PC, so the profile is committed in the repo and used by every renderer build rather than only by a prebuilt one.
What changed
nx2/build.py, ported from ProjectReLink (GPL-3.0-or-later).RX_VK_PGO=genbuilds the back end's own files (gpu/vk/*.cppand suyu's texture decoders; not Eden's recompiler, sirit, Dear ImGui or zstd) with-fprofile-instr-generateand links the module's own copy ofhost/pgo_rt.c.RX_VK_PGO=<file>builds them with that profile; its contents go into the flags the object keys hash, so another profile rebuilds those 35 files and nothing else.host/pgo_rt.creads its variable throughPGO_ENV(HOS_PGOfor the game module,RX_VK_PGO_FILEfor the renderer's copy). On Linux it finds the__llvm_prf_*ELF sections by their__start_/__stop_symbols; ReLink only had Windows' COFF markers.assets/profiles/longshot_vk.profdata.xz(160 KB) andassets/profiles/README.md(where, how and on what it was recorded, and what it measured). One profile for every build for now: a Linux recording, Kokiri Forest standing and the Market walk, mesh shaders.nx2/make_game.pyvk_profile_for():work/longshot_vk.profdatawhen there is one (a developer's recording), else the committed profile, unpacked into the work folder aslongshot_vk.shipped.profdata(rewritten only when it changes);RX_VK_PGOonly when this compiler reads it, and unlessRX_VK_PGOis set already;profile_readable()now checks on Windows too for this profile (any_os=True): it comes from LLVM 23.1.5, llvm-mingw is another LLVM, and an unreadable profile would stop the build;RX_VK_PGOandRX_VK_PGO_FILEare left out of the lift key.scripts/linux/appimage.shbuilds the AppImage's renderer with the same profile (the checkout's, else the committed one). The AppImage already carriesassets/, so a player's own renderer there (DLSS, FSR 4) gets it too.scripts/dev_packs.pybuilds a pack of the renderer alone with its base's profile.docs/development.md("The renderer's play profile": the committed profile, recording a new one, shipping it; the switch rows),docs/design.md,RELEASING.md(step 0: record it again before a minor's first candidate when the renderer changed much).tests/test_vk_pgo.py(new: the choice between the checkout's and the committed profile, the unpacking, the opt-outs, the committed file and its note, the writer, the AppImage),tests/test_shader_stamp_cache.py(build.py's real branch withRX_VK_PGO: which files count, the writer, the object keys),tests/test_dlss_sdk_cache.py(the new name in its namespace).Flags and settings
RX_VK_PGO=gen/RX_VK_PGO=<file>RX_VK_PGO_FILE=<file><file>.reset/<file>.dumpassets/profiles/longshot_vk.profdata.xzMeasurements
main:
0caf0618(2026-11-14)this PR: the profile's first version,
build/vk-pgo@ a601a547 on0caf0618(the same code as this PR's, before the profile moved toassets/profiles/); rebased since onto main7ff5256ewith no conflictHardware: RTX 3090, Ryzen 9 7900X, 32 GB, CachyOS (Linux)
Scene: the Market from a save, standing, then running in the square; 2560x1440, default options
Method: full-length sessions at low priority on a busy PC, interleaved: control, profile, profile, control, control, profile, baseline x86-64, control. The median frame of each phase, from the frame log (
RX_VK_FRAME_LOG). Both arms ran with the default reserved core and without ReplayPin in the base. A fourth control in a noisy stretch (14.63 / 17.95 ms) and the single baseline x86-64 session are left out of the table.How to reproduce: build the renderer with and without
RX_VK_PGO=<the profile>over one base (scripts/dev_packs.py), and play the same save.0caf0618The profile was recorded on Kokiri Forest and the Market walk, so the Market numbers are on part of the route it was recorded on. A broader recording (the pipeline tour, PR 111) is to follow.
Testing
Tested: the sessions above, on Linux with the RTX 3090: the counting build, the recording (
.reset/.dump),llvm-profdata merge, and the renderer built with the profile all ran, and the game played through the route each time. No local checks run (tests/run_all.pyis left to CI).Not tested: this PR's own path from the committed file:
vk_profile_for()unpackingassets/profiles/longshot_vk.profdata.xzandappimage.sh's fallback have not run in a build. Windows: the counting renderer, its writer (ReLink's COFF code) and whether llvm-mingw's clang reads this profile. AMD and Intel GPUs, the compute fallback, the Steam Deck.Needs other testers:
the Vulkan back end: built with the profile ...longshot_vk.shipped.profdatain the build log (orthis compiler cannot read the play profile, then built without), and the game running (request to open)Screenshots
Nothing on screen.
Risk and rollback
assets/profiles/longshot_vk.profdata.xz, or revert.Reviewer notes
vk_profile_for()innx2/make_game.py, thennx2/build.py'sRX_VK_PGObranch andhost/pgo_rt.c.flag_textchange fixes both.Issues
See #505
Checklist
For everyone
type(scope): description).main.python -I -B tests/run_all.pyrun and passing (any failure that also fails onmainis named above). (not run here: left to CI)third_party/untouched (a new folder with aPROVENANCE.mdinstead).If applicable
Assisted-by:/Co-Authored-By:trailers.docs/tested/for each new measured run (format indocs/tested-configurations.md; no appended row or assembled view).tests/that reads changed source updated in this PR, not weakened.🤖 Generated with Claude Code
WIP: perf(vk): the renderer is built with a committed play profile, about 3-5 % less frame timeto perf(vk): the renderer is built with a committed play profile, about 3-5 % less frame timeHumanBean referenced this pull request2026-11-14 20:23:00 +00:00