Repository navigation
ASTRO BOT (PPSA21564) on Windows / AMD RX 6600 XT: GPU hang in the first 3D frames after the start-up logos (TDR, vkQueueSubmit -4) #6284
Description
What happens
ASTRO BOT (PPSA21564, 01.007.000) plays the start-up logos with sound, then stops at the final ASTRO BOT logo, where the first 3D scene starts. One recorded batch never completes; Windows resets the display driver and the next submission fails:
[gpu] recorded batch still running on the GPU after 5 s
[gpu] recorded batch still running on the GPU after 10 s
[device-fault] result 0: No fault detected
terminate called after throwing an instance of 'std::runtime_error'
what(): AGC graphics: vkQueueSubmit recorder: Vulkan result -4
System log at the same time: event 4101 (Display driver amduw23g-... stopped responding and has successfully recovered) and a LiveKernelEvent 141.
It reproduces at the same point every run:
| Run | Build | Setting | Result |
|---|---|---|---|
| 1 | main d92a8dad3 |
default, cold shader cache | 1832 shaders compiled, TDR after 6 min 40 s |
| 2 | main d92a8dad3 |
default, warm cache | 1832 cache hits, 0 misses, TDR after 3 min 38 s |
| 4 | main d92a8dad3 |
TdrDelay=10 (rebooted) |
batch still running after 5 s and 10 s, then TDR |
| 5 | main db81992c5 + #4855 |
APS5_PM4_RING=64, APS5_STALL_WATCHDOG_SECS=3 |
same stop; rings below |
With the timeout raised to 10 s the batch still does not finish, so this is a hang rather than slow work at 4K. The stall watchdog did not fire: no queue was waiting on a WAIT_REG_MEM, a REWIND or queue 0.
What the queues were doing (#4855 rings, run 5)
Queue 0 at that point is rendering full frames of the title's 3D scene. Its markers per frame are Draw Geometry_N, Draw Extra Geometry_N (ClearGBuffer_0, OutputGBuffer2_0, Spray_0, Ripple_0, Wind_0), Draw Decal_N (Resolve Cmask for lighting) and Draw Shadow_N (dir_shadow_0..2, spot_shadow_0/1, decal_shadow_0). Frames start about every 350-380 ms (t=252616, 252977, 253316, 253697 ms), which matches the ~2-3 fps seen on screen just before the stop. The last frame was submitted 50 ms after the previous one (t=253749 ms, Draw Geometry_1 .. Draw Shadow_1) and nothing completes after it.
- Queue 0x40, every frame:
JsParticleUpdate_Async,ResizeDepthOnAsync,GenerateMipMapMaxDepthOnAsync(5 dispatches, 4WAIT_REG_MEM_64). - Queue 0x48:
Async Geometry_NwithFroxelUpdate,FroxelReprojection,FroxelCopy; its last full froxel submission is at t=250254 ms, then one single-dispatch submission at t=252977 ms.
All 9 compute programs in the rings (COMPUTE_PGM_LO writes) already ran in earlier frames that completed; none is first seen in the last second. So the stuck work is not a newly prepared shader. It looks data dependent (a program that completed in earlier frames does not terminate in this one), but I can't tell which draw or dispatch it is from here.
Ruled out
APS5_NO_GPL=1: stops 36 s in, before the first logo, with[device-fault] result 0: GPU fault/read invalid at 0xbeefdeadc000, which is AMD Windows GPL-off: agc_driver_cmask_fast_clear fails with Vulkan device loss #5150, not this.- The 64-bit LDS lock hang from agc_* tests: 3 of 483 fail on AMD Radeon RX 6400, pass on NVIDIA RTX 4080 SUPER #5271 / fix(shader): serialize locked LDS updates with a wave-uniform loop exit #833: none of the 3433 cached SPIR-V modules contains the
LockedLdsUpdatepattern (OpGroupNonUniformElectplusOpAtomicCompareExchange). - VRAM: 2.3-2.7 GB of 7.4 GB in use shortly before the stop. Process memory about 17.7 GB of 32 GB.
- fix(agc): keep RADV's descriptor pool overrun inside the pool's pages #1065 (the RADV descriptor pool overrun behind AMD ring timeouts in Astro Bot (PPSA21564) #357): that shows as a page fault; here the driver reports none.
VK_EXT_device_faultreports no fault, andAPS5_GPU_CHECKPOINTSneeds the NVIDIA checkpoint extension, so there is no device-side record of the hung command. Radeon GPU Detective does not support RDNA 2 or Windows 10.
Linux runs on RTX 4090 and RX 9070 XT (RADV) pass this point (#357, #5309), so this looks specific to the AMD Windows driver or the Windows path.
Setup
Windows 10 Home 22H2 (19045), Ryzen 5 5600X, Radeon RX 6600 XT 8 GB (RDNA 2, 1002:73ff), driver 32.0.21045.5002 (Adrenalin 26.8.1), Vulkan 1.4.315, 32 GB RAM. WinLibs GCC 15.2.0 r7, Release, ANYPS5_ENABLE_SPIRV_TOOLS=OFF. The eboot was unwrapped with tools/unwrap_self.py; both bundled modules are plain ELF. No other environment variables. The title renders at 3840x2160.
I can run more switches on this machine, for example APS5_BATCH_CAP=1 with APS5_TRACE_DRAW_PROGRAMS=1 to narrow the batch to one draw, if that helps.
Attached:
- astro-pr4855-ring-game.err.txt (run 5, with the rings)
- astro-main-tdr10-game.err.txt (run 4)
AI-assisted: yes
Activity
MarcZX10 commentedon Oct 15, 2026
The ring dump narrows the stall to the last queue-0 frame but not to one draw or dispatch within that submission. In the current source,
APS5_BATCH_CAPis the maximum recorded-work count before submitting (default 64), andAPS5_TRACE_DRAW_PROGRAMS=1logs draw program addresses. A warm-cache run withAPS5_BATCH_CAP=1 APS5_TRACE_DRAW_PROGRAMS=1, keeping the same title/settings, should show the last individual work item that completes before the GPU hang. If the cap changes whether it hangs, that comparison would also help distinguish a single-command hang from an interaction/order issue.Cleverdee commentedon Oct 15, 2026
Ran it: same build (main
db81992c5+ #4855), warm cache,APS5_BATCH_CAP=1 APS5_TRACE_DRAW_PROGRAMS=1, plus the sameAPS5_PM4_RING=64 APS5_STALL_WATCHDOG_SECS=3,TdrDelay=10.The cap does not change it. It hangs at the same point, only slower (13 min 53 s instead of ~4 min):
recorded batch still running on the GPU after 5 s,[device-fault] result 0: No fault detected,vkQueueSubmit recorder: Vulkan result -4, event 4101.Where it stops. All traced draws before the hang belong to queue 0 serial 9679 (queue entry 5730, 25355 dwords): the main pass of the frame (first markers
JsParticleUpdate,Main_0_0_0,ClearDistortionBuffer_0,blur_dir_shadow_0,ShadowVolume_0,CaptureCubemap_0,GiProbe_0). The same pass in the two previous frames (serials 9663 and 9671) has 218 draws with identical program pairs in identical order. In 9679 the trace stops after 67 draws, and those 67 match the earlier frames exactly:[draw-programs]is printed when the draw is decoded (Draw.cpp, before recording), so draw 67 (the only mesh-stage draw in that part of the pass) was never decoded and never reached the GPU. The game had already submitted serials 9682-9686 (Draw Geometry_1..Draw Shadow_1), so the queue worker was blocked inside 9679 between finishing draw 66 and decoding draw 67, waiting on work already on the GPU. With the cap at 1, the stuck batch should be draw 66 (0x500644f00/0x500645900), the rect-list draw 65, or a dispatch recorded between 66 and 67 (dispatches aren't in this trace). No program in the last 300 traced draws is new.Rect-list draws with a host fragment program appear at indices 9, 11, 65, 101 and 160 of each full frame; this run logs the usual
Rect-list draw of shader 0x148e7cd00 has no rectangle for fragment shader 0x7ff...; preparing it at draw.Log attached (zipped, 12 MB unpacked): astro-cap1-trace-game.err.zip. Happy to run a dispatch trace or anything else around draw 66/67.
AI-assisted: yes
MarcZX10 commentedon Oct 15, 2026
One focused next capture: add
APS5_TRACE_DISPATCH_IO=1to the same warm-cacheAPS5_BATCH_CAP=1 APS5_TRACE_DRAW_PROGRAMS=1run. In currentDispatch.cpp, this prints each compute shader address ([dispatch-io] shader ...); the draw-program trace does not include dispatches, so this can reveal whether a compute dispatch occurs between draw 66 and the point where decoding draw 67 blocks.APS5_TRACE_DISPATCH_IO=2also prints user-data words and will be much noisier, so I would start with=1.MarcZX10 commentedon Oct 15, 2026
Thanks, the cap=1 trace confirms the worker stalls before decoding draw 67, but it still cannot tell whether a queued compute dispatch is involved. Could you run the same warm-cache setup once with
APS5_TRACE_DISPATCH_IO=1added, keepingAPS5_BATCH_CAP=1,APS5_TRACE_DRAW_PROGRAMS=1, and the existing watchdog/ring settings? Please include the final[dispatch-io] shaderlines around the last completed serial and the corresponding[gpu] execute/done seriallines if present. This should help identify the dispatch boundary without the much noisier user-data mode.Cleverdee commentedon Oct 15, 2026
Ran it: same build (main
db81992c5+ #4855), same warm cache,APS5_BATCH_CAP=1 APS5_TRACE_DRAW_PROGRAMS=1 APS5_PM4_RING=64 APS5_STALL_WATCHDOG_SECS=3 APS5_TRACE_DISPATCH_IO=1, plusAPS5_TRACE_GPU=1for theexecute/done seriallines. AMD driver is now 26.9.2 (32.0.21045.11001); the hang is the same on it. It took 66 min to get there with these traces (0.38 fps).Same stop: queue 0 serial 9543 (the main pass), last draw decoded
vertex/main=0x500644f00 fragment/fragment=0x500645900right after the rect-list draw, thenrecorded batch still running on the GPU after 5 s / 10 s, no fault,Vulkan result -4, event 4101. The watchdog did not print.No compute dispatch between draw 66 and the stall. The last
[dispatch-io] shaderline comes about 60 draws earlier:What sits between the last draws is queue 0
WAIT_REG_MEMs, each logged and then satisfied (the next draw is decoded):So the wait between the rect-list draw and draw 66 completed, draw 66 was decoded, and the next GPU completion never came. With the cap at 1 that points at draw 66's batch (or the rect-list draw just before it, if that wait didn't depend on it).
Last
execute/doneserial per queue before the stall:doneThe
[dispatch-io]lines don't name their queue, so I can't tell from this log whether 9545 / 9547 got any dispatch onto the GPU after the lines above; the excerpt has every line from the last ~340 before the stall.Attached: astro-dispatch-tail.txt (last ~340 lines before the stall) and astro-dispatch-trace-game.err.zip (full log, 90 MB unpacked).
MarcZX10 commentedon Oct 17, 2026
I opened PR #7010, a diagnostic-only change that adds the queue ID and submission serial to each
APS5_TRACE_DISPATCH_IOshader line. It does not claim to fix the GPU hang. If it lands, the same capture can identify whether later dispatches came from queues0x40or0x48while queue 0 was stalled.