WIP: fix(vk): the cooperative matrix test waits for its dispatch before destroying what it uses #912
No reviewers
Labels
No labels
area/accessibility
area/audio
area/input
area/install
area/menu
area/renderer
area/saves
area/tooling
area/upscaling
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
risk
high
risk
low
risk
medium
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!912
Loading…
Reference in a new issue
No description provided.
Delete branch "mooki/Longshot:fix/coopmat-safe-free"
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?
Type: fix · Risk: low · Tested on: macOS 26.7, Apple M4 Max (game-free checks only, arm64 and x86_64) · Needs: Windows or Linux, an NVIDIA GPU with cooperative matrix
Why
At start, on a GPU with cooperative matrices, the renderer runs a small test on the GPU to decide whether the game's matrix multiplies (the movie upscaler's and TAAU's networks) can run natively. It waits 5 s for that test. If the GPU has not finished by then, the renderer destroys everything the test uses anyway, while the GPU may still be running it. That can end in a GPU fault or a lost device at start, on any GPU that offers cooperative matrices.
It has not been seen in a game; it was found by reading the source (it is the same pattern #788 fixes for the texture read-backs), and the new test shows it on main's code. No title in the issue tracker (snapshot of 2026-11-14 20:01) names the cooperative matrix test or a start-up timeout: the device losses and GPU hangs there (#130, #316, #365, #583, #606) come in play, not at start.
How to reproduce
Seen on: not seen in a game; shown on main's own
run_shaderbytests/test_coopmat_safe_free.py, on any OSSettings and switches: defaults, on a GPU whose driver offers
VK_KHR_cooperative_matrixwith 16x8x16 f16 (vk: native matrix multiplies oninlongshot_log.txt), and a GPU stall of more than 5 s during the test at start (vk: cooperative matrix test: the dispatch did not complete)Steps: run
python -I -B tests/test_coopmat_safe_free.py --headers <Vulkan-Headers/include>on main; in a game run,RX_VK_VALIDATION=1and a GPU busy with other work at startExpected: nothing the test's dispatch uses is destroyed while it may still be running
Actual: the test reports the fence, the command pool, the descriptor pool, the pipeline, the buffer and its memory destroyed under a dispatch that has not finished. The validation layer would name it (for example
VUID-vkDestroyFence-fence-01120,VUID-vkDestroyCommandPool-commandPool-00041) when the GPU is that lateWhat changed
A dispatch not seen done in 5 s is now waited for, without a limit, before what it uses is destroyed, as #788 does for the read-backs (
readback_settle). The test's result is as before: a dispatch not done in 5 s still fails it, and the multiplies run in software. Nothing is freed earlier than before.gpu/vk/vk_coopmat.cpp:run_shader(main:114), called bymeasure_orderandtest_multiplyfromcoopmat_init(:411, once the device is made,gpu/vk/vk_main.cpp:691), waited 5 s for its dispatch (:211) and then destroyed the fence, the command pool, the descriptor pool and the pipeline (:214-:217), and the buffer and its memory (:224-:225), whether the dispatch had finished or not. Vulkan forbids destroying a fence of a pending submit, a pool with a pending command buffer, and a pipeline or buffer a pending command uses.submitted), and when the 5 s wait gave up the fence is waited for without a limit before the destroys. A submit that failed is not waited for: nothing will signal its fence.RX_VK_GPU_HANG_SEC) starts at the first present, after this test, so it does not cover this wait; a lost device ends it (VK_ERROR_DEVICE_LOST).Measurements
Verdict: nothing to measure. A normal start does the same work at the same time; only a test that runs past its 5 s wait changes when its objects are destroyed.
Flags and settings
None
Testing
Tested: game-free, on macOS 26.7, Apple M4 Max, arm64 and x86_64 (Rosetta):
tests/test_coopmat_safe_free.py(new) fails on main7bacf846and passes on this PR, on both architectures. It runs the realrun_shaderagainst a GPU that finishes in time (as before), one that does not finish in 5 s (main destroys six objects under it; this PR waits first), and a submit that fails (no wait without a limit).gpu/vk/vk_coopmat.cppwith the macOS port's ownnx2/build.pycommands (main has no macOS build), on both architectures: each exits 0, as on main. (Those commands turn warnings off, so only the exit codes count.)python -I -B tests/run_all.pyon this Mac, where main's runner takes macOS for Linux: 559 passed, 34 failed, 17 skipped. Main7bacf846gives 558 passed, 34 failed, 17 skipped, and by name every result is the same apart from the new test (pass). The 34 fail on main too, on this Mac.Not tested: in the game, on any platform: no GPU on this Mac offers cooperative matrices (MoltenVK has none), so the test does not run here at all, and a dispatch that runs past its 5 s wait cannot be made on demand. Not built on Windows (llvm-mingw) or Linux. The code has no platform branch, so it runs the same on both.
Must be tested:
VK_KHR_cooperative_matrixwith 16x8x16 f16: with the Khronos validation layer installed, build this PR (headc45cad61) and main7bacf846the same way and runpython -I -B tests/run_all.py. Then start each withRX_VK_VALIDATION=1and play to the title, expecting every check to pass,vk: native matrix multiplies on (cooperative matrices, the console's fragment layout checked)inlongshot_log.txton both, and no validation error at start on this PR that main does not also show. A dispatch that runs past its 5 s wait cannot be made on demand (by hand: test request T-SUWS)Risks
What could break: a cooperative matrix test that runs past its 5 s wait now holds the start until the GPU finishes it, instead of going on with its objects destroyed under it. A lost device still ends the wait. A GPU that hangs at that point without reporting the device lost would hold the start there, after the log line
vk: cooperative matrix test: the dispatch did not complete; the hang watch does not run yet at that point.Turning it off: revert the commit (
RX_VK_NATIVE_MMA=0orRX_VK_MMA_SOFTWARE=1skip the test altogether, as on main)Compatibility: Nothing changes
Checklist
Everyone
type(scope): description) of the status line's type.main(main7bacf846, headc45cad61).python -I -B tests/run_all.pypasses (any failure that also fails onmainis named).third_party/untouched (a new folder with aPROVENANCE.mdinstead).When it applies
Assisted-by:/Co-Authored-By:trailers.mainand passing here.tests/that reads changed source updated in this PR, not weakened. (None needed a change:test_recorder_syncalready namesvk_coopmat.cpp's submit and fence wait;test_intel_compiler_gate,test_vendor_fixesandtest_global_table_loopread other parts of it.)View command line instructions
Checkout
From your project repository, check out a new branch and test the changes.