fix(vk): seed_keys is filled only for RX_VK_SEED_CHECK, its one reader #393
No reviewers
Labels
No labels
area/accessibility
area/audio
area/input
area/install
area/menu
area/renderer
area/saves
area/upscaling
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/steam-deck
platform/windows
preview
priority
critical
priority
high
priority
low
status
blocked
status
confirmed
status
duplicate
status
invalid
status
needs-info
status
wontfix
testing wanted
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
MagicBeanDev/Longshot!393
Loading…
Reference in a new issue
No description provided.
Delete branch "madebyjordan/Longshot:fix/seed-keys-race"
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
When the shaders' preparation runs during play (
RX_VK_PREPARE_BACKGROUND), it can fill a hash set while the renderer's thread is reading it. That's a data race that can walk freed memory and crash. The set only serves a debugging switch, so now it's filled only when that switch is on.What changed
seed_open()(gpu/vk/vk_shader.cpp), every seed stage's key goes intoseed_keysonly whenRX_VK_SEED_CHECK=1(read once,seed_check).seed_keys(astd::unordered_set) has one reader:miss_note, which marks the replay's program misses (the first 1,500 in play) with the stages the seed holds.prepare_backgroundinserted every key while those reads ran. A rehash under a reader can walk freed buckets.RX_VK_SEED_CHECKthe set now stays empty, andmiss_notereads an empty set that nothing writes.tests/test_seed_keys_race.py(new) readsseed_open()and checks that everyseed_keys.insertis underseed_check, and thatseed_checkisRX_VK_SEED_CHECKread once. It fails on main.docs/development.md, anRX_VK_SEED_CHECKrow; it wasn't in the switch table, only indocs/BAKE.md.tests/test_seed_reader.py, which compiles the realseed_open()against stand-ins, gets one forenv_on. Its 20,000 mutations are unchanged.Flags and settings
RX_VK_SEED_CHECK=1(existing)miss_note's+); now also the only timeseed_keysis filledMeasurements
A fix of a timing-dependent race, so the evidence for the race is the test. The game runs show the fix changes nothing else.
main:
cf605c85(2026-11-14)this PR: fix/seed-keys-race @ a4fa2ab0
Rebased since onto main
0caf0618(nowe867b434): the numbers still hold. #357 and #358, merged since, change the lift and the button prompts, not the renderer.Hardware: Ryzen 5 5600, 16 GB, AMD Radeon RX 6700 XT, AMD driver 26.10.1, Windows 11
Scene: the path where the seed is first opened in play. An update start (another translator's prepare record kept, caches removed),
RX_VK_PREPARE_BACKGROUND=1 RX_VK_NO_STATE_LIST=1, soprepare_backgroundopens the seed 20 s into play while play misses programs. ThenHOS_SKIP_OPENING=1, New Game into Link's house and Kokiri Forest, headless, 480 s, a cold driver cache each run. With the state list on, the seed opens before the title and the race can't happen.Method:
longshot_vk.dllbuilt from each commit (RX_VK_ONLY=1 RX_RELEASE=1, llvm-mingw clang 23) into the same game folder, main and this PR alternated, 2 runs each. Read from the game log (miss_notelines, crash lines) andRX_VK_FRAME_LOG.How to reproduce: the scene above, with each build's
longshot_vk.dll; count themiss_notelines with a+after the in-play seed opens.cf605c85miss_notelines after the seed opened in play+(the set read while it was filled)The lines name the same programs: main's two runs share 140 of 144/145, and the second PR run names 2 programs neither main run did. The first PR run walked further (a shorter stall, the same timed inputs), hence its 58 more lines. The stall varies this much on main too. The race didn't visibly fire in these four runs; it depends on timing.
0caf0618e867b434tests/test_seed_keys_race.pytests/run_all.py --jobs 4Testing
Tested:
tests/test_seed_keys_race.py.tests/test_seed_reader.pywith clang 23.python -I -B tests/run_all.py --jobs 4on main and this PR.Not tested:
static const booland anif, in code Linux already compiles.Needs other testers:
RX_VK_PREPARE_BACKGROUND=1plays into Kokiri without a crash (T-5QMM).Screenshots
Nothing on screen.
Risk and rollback
gpu/vk/vk_shader.cppis part of the translator's stamp, so every player's programs are translated once more after this lands, as with any release that touches the translator.RX_VK_SEED_CHECK=1the set is filled as before, and so is the race; that's a developer switch.Issues
Found while measuring the in-play shader preparation (#362's shader work).
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.mainand passing here.tests/that reads changed source updated in this PR, not weakened.WIP: fix(vk): seed_keys is filled only for RX_VK_SEED_CHECK, its one readerto fix(vk): seed_keys is filled only for RX_VK_SEED_CHECK, its one readerPushed
74e7350f:RX_VK_SEED_CHECKgets a row in docs/development.md's switch table (it was only in docs/BAKE.md), since this changes what the switch does. Docs only; no code change.View command line instructions
Checkout
From your project repository, check out a new branch and test the changes.