WIP: fix(vk): a marker before every GPU command on AMD's integrated GPUs, so Kokiri Forest no longer loses the device #466
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 @ 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!466
Loading…
Reference in a new issue
No description provided.
Delete branch "Yeetbot90/Longshot:fix/amd-igpu-markers"
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
On an AMD integrated GPU (a Ryzen 9 7900X's Radeon Graphics, Windows) the game loses the GPU device (
VK_ERROR_DEVICE_LOST, then FATAL) within seconds of Kokiri Forest loading, every time. With a marker written before every GPU command, as NVIDIA's checkpoints already are by default for the same kind of loss, it kept the device for 110 minutes.What changed
What the GPU was doing when it was lost: with markers it stood still for 4-6 s (
nvn: GPU waits in 5 s: 1 sync waits (4176-6305 ms)) before Windows reset it. Every marker it had reached had its earlier work finished, so it was not inside any draw, dispatch, upload, mirror sync, write-back or present copy: it stood between commands. Turning off each suspect in turn did not keep the device (Measurements). Markers before every command did. Each one waits for the work before it, so like the NV checkpoints (vk_main.cpp: "The race they hide is not found yet") they hide a race that is still to be found; this PR does not claim to have found it.gpu/vk/vk_work.h. The work macros that are not draws or dispatches (barriers, render pass begin/end, copies, blits, resolves, clears, fills, updates, queries) callfine_markbefore the command, through a lambda that takes the macro's arguments once and passes them on, so no argument is evaluated twice.fine_markdoes nothing unlessdev.fine_markers.create_device()ingpu/vk/vk_main.cpp. On AMD integrated GPUs on Windows (vendorID 0x1002,VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU)VK_AMD_buffer_markeris enabled anddev.fine_markersset with no switch.RX_VK_CHECKPOINTS=allasks for the same anywhere the NV checkpoints are missing,RX_VK_CHECKPOINTS=1keeps them to draws and dispatches,RX_VK_CHECKPOINTS=0turns them off.buffer_markers_report()ingpu/vk/vk_draw.cpp. Each marker now keeps its command buffer, and after a lost device the log lists, for each command buffer, its last markers done and its first not reached. Before, an upload command buffer's markers interleaved in number with its recording's draws, and the single "RUNNING after" line could name the wrong command. New marker kinds name the commands, a recording's start (begin_recordingingpu/vk/vk_replay.cpp) and the present's copy (present_image).tests/test_recorder_sync.pyaccepts the lambda form (the packer still called, the driver never directly);tests/test_inline_write_order.pystubsfine_markand removes the work count by the macro's start, so its negative control still fails;tests/fsr_uniform_ownership_test.cppandtests/recorder_sync_test.cppstubcheckpoint_markandcheckpoint_fine.docs/development.md,RX_VK_CHECKPOINTS=1/all.RX_VK_CHECKPOINTSasks for it.Flags and settings
RX_VK_CHECKPOINTS=all(new value)VK_AMD_buffer_markerbefore every command, not only draws and dispatches; the lost-device report by command bufferRX_VK_CHECKPOINTS=0Measurements
main:
5e072fc8(2026-11-14)this PR: fix/amd-igpu-markers @
0cb75e95Baseline: main @
5e072fc8. In the game its side is e072164e's renderer without these markers: the game folder on the iGPU was built frome072164e(#404's branch: main @0caf0618plus two Intel commits), and each run below swapped only itslongshot_vk.dll, built from that source with the switch or change named. A renderer from5e072fc8changes the shader translator and would restart the shader preparation each time. The renderer files this PR touches are the same on both bases. Without markers, or withRX_VK_CHECKPOINTS=1, is main's behaviour on this GPU.Hardware: Ryzen 9 7900X's AMD Radeon(TM) Graphics (RDNA 2, 2 CUs), AMD proprietary driver 26.10.1 (Vulkan driver 0x800161), no mesh shaders (the compute fallback), Windows 11; the screen on an RX 9070 XT, so the iGPU's frames are presented across adapters
Scene: New Game, then Kokiri Forest (
map: KokiriForest_Child); output resolution 2048x1152Method: one run each, played by hand until the device was lost or the run was stopped; the lines from each run's
longshot_log.txt. The checks:tests/run_all.pyon main and on this PRHow to reproduce: on an AMD APU on Windows, walk into Kokiri Forest on main (or with
RX_VK_CHECKPOINTS=1), then with this PR and no switchThe runs on the iGPU, each a renderer built from
e072164e(frame and submit where the device was lost; where the GPU stood, the last marker whose earlier work was done):RX_VK_CHECKPOINTS=1: lost seconds after, frame 794, submit 5574; after a dispatch of 53fcaee4dc45c6ee.=1withRX_VK_SKIP_PROG=53fcaee4dc45c6ee,53509044401d78d2: lost, frame 3678, submit 25762; after a dispatch of 0ba2f076e4a94acf.=1withRX_VK_MIRROR=1: lost, frame 2463, submit 17257; after a pool's write-back.=1with the swapchain image waited for on the CPU (not in this PR): lost, frame 853, submit 5980; after a texture upload.=1withRX_VK_SKIP_CODE=2c56dc1006942f74(issue 817's task shader): lost, frame 840, submit 5889; after the present's copy.RX_VK_CHECKPOINTS=all(this PR's default): not lost, 14:28 to past 16:15 (110 min), Kokiri Forest in them.5e072fc80cb75e95tests/run_all.pyTesting
Tested: On the iGPU above, the seven runs in Measurements (Kokiri Forest, played by hand).
tests/run_all.pyon main and on this PR, Windows 11, llvm-mingw fromnightly-132-5e072fc8: the same seven fail on both. The three checks updated here (test_recorder_sync,test_inline_write_order,test_fsr_uniform_ownership) failed on this PR's source before their updates and pass with them. The renderer (RX_VK_ONLY) builds on5e072fc8and one072164e. With no switch, the log on the iGPU says the markers are on.Not tested: This PR's own build with no switch through Kokiri Forest: running now, result to follow in a comment. The frame-rate cost of the markers on the iGPU: main loses the device there, so there is nothing to compare with. Other AMD APUs, newer APU drivers. A Linux build was not run: the change is standard C++ and the default sits under
#ifdef _WIN32, so Linux keeps main's behaviour. Dedicated cards are untouched.Needs other testers:
RX_VK_CHECKPOINTS=0to see whether that APU loses the device without them (request to open)Screenshots
Nothing on screen: the change is in how commands are recorded.
Risk and rollback
RX_VK_CHECKPOINTS=0turns them off.vkCmdWriteBufferMarkerAMDpair before each command on those GPUs; elsewhere one predictable branch per command (checkpoint_fine()).Reviewer notes
Start with the macros in
gpu/vk/vk_work.hand the default increate_device()(gpu/vk/vk_main.cpp).A lead for the race: in five of the six lost runs (all but the issue 817 one), the device was lost in the frame of, or the frame after, these lines: the same seven programs rebinding the same 149 MB storage buffer, logged once as Kokiri Forest starts. The run with markers before every command passed the same moment (frame 377250) and went on.
The per-command-buffer report is the tool for the follow-up: with
RX_VK_CHECKPOINTS=allthe device is no longer lost, so the next step is fewer markers, by kind, to see which one keeps it. Open question: should this cover every AMD integrated GPU, or only RDNA 2 APUs, until other APUs are tried?Issues
See the Kokiri Forest device loss on AMD integrated graphics (no issue on the tracker yet).
Checklist
For everyone
type(scope): description).main.python -I -B tests/run_all.pyrun and passing (any failure that also fails onmainis named above).third_party/untouched (a new folder with aPROVENANCE.mdinstead).If applicable
Assisted-by:/Co-Authored-By:trailers.tests/that reads changed source updated in this PR, not weakened.Closing: the claim here does not hold. This PR's own build, markers before every command by default, lost the device in Kokiri Forest all the same (
submit 470388 failed (-4), the GPU waited for 5468 ms first), so the 110-minute run was not the fix.The cause is the GPU's decode and BC3 re-encode of the terrain's two 1365 x 1365 x 90 ASTC arrays in one upload submission; decoded on the CPU, Kokiri Forest loaded 3 times of 3. That is #489, which replaces this one.
Pull request closed