WIP: fix(vk): an event signal's add writes the value the stream gives the event #772
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
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
MagicBeanDev/Longshot!772
Loading…
Reference in a new issue
No description provided.
Delete branch "dyst/Longshot:fix/event-signal-add"
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: Windows 11 (the game-free checks only; no game run) · Needs: a game run, any OS and GPU
Why
When the GPU signals an event by adding to its value (NVN's ADD mode), the renderer wrote the wrong number into the event: it added to what the event held in the game's memory, which doesn't yet have the earlier signals of the same recording. Two adds in a row wrote the same value, and an add after a set added to the value before the set. The renderer's own waits were not affected (they keep the right value), but the game's reads of the event (
nvnEventGetValue) saw fewer signals than were made, which can hold a thread that waits for the count or let it go early.In Ocarina of Time this probably doesn't happen: in 133 run logs on this PC, all 200 sampled GPU event signals are SET, none ADD. The fix is for correctness where ADD is used. Found by reading the replay. The tracker has no issue for it (
forge.py issue list,pr list: nothing on event signals).How to reproduce
Seen on: not seen in the game; reproduced by the new game-free check
Settings and switches: defaults
Steps:
python -I -B tests/test_event_signal_add.pyagainst main'sgpu/vk/vk_replay.cpp: two adds of 1 from 5, a set of 10 and an add of 5 in one recordingExpected: the GPU writes 6, 7, 10, 15
Actual: main writes 6, 6, 10, 10 (serial replay, and the parallel replay's workers alike)
What changed
An event signal's GPU write now takes the value the replay already keeps for the event in stream order, instead of guest memory's value plus the add. The parallel replay's workers, which don't keep those values, take each signal's value from the dry pass, the same way they take the render conditions' results. SET signals write exactly what they wrote before.
NOP_SIGNAL_EVENTinreplay()(gpu/vk/vk_replay.cpp) writesev_values[e.gpu]; the dry pass records each signal's value inpar_signals, whichParPointandSegmentcarry assigtorecord_segment(sig_at), besidepar_conds/cond_at. A worker with no value from the dry pass falls back to the old add.tests/test_event_signal_add.pycompiles the realNOP_SIGNAL_EVENTcase in a stub replay loop and runs it serially, as a dry pass, as a worker, and as a worker starting at a later segment.Measurements
Verdict: nothing to measure for speed: the change only alters the value an ADD signal writes (one map lookup it already made). The new check fails on main and passes here.
Flags and settings
None.
Testing
Tested: Windows 11 (llvm-mingw from the builder, v2.0.14 tools):
tests/test_event_signal_add.pypasses on this branch and fails on main @aa95d35f(output above).gpu/vk/vk_replay.cppcompiles (-fsyntax-only) with the renderer's flags and the CPM Vulkan, SPIR-V and VMA headers.python -I -B tests/run_all.pyon this branch and on main @aa95d35f, same PC and environment: 497 passed, 19 failed, 78 skipped here; 496 passed, 19 failed, 78 skipped on main. The only difference is the new check. The 19 fail on main too, on this PC (among themtest_env_on, which flags main'sRX_VK_PRESENT_AFTER_SIGNALread atvk_replay.cpp:5794):test_appimage_player_build.py,test_bake_portability.py,test_cpm_discovery.py,test_cpp_preflight.py,test_crash_dialog.py,test_env_on.py,test_fpx_sticky.py,test_lift_cleanup_error.py,test_linux_preflight.py,test_make_game_cache.py,test_make_game_prepare.py,test_missing_nup.py,test_oot_state_tap.py,test_options_budget_once.py,test_readback_late.py,test_spawn_emit.py,test_tested_configurations.py,test_vk_pgo.py,test_walk_key.py.Not tested: the game. No build was made; this PC's builds were not used for this change. The parallel replay's segments (
RX_VK_PARALLEL) and the render thread are covered by the game-free check only.Must be tested:
RX_VK_PARALLEL=4: load a save in Kokiri Forest and play two minutes, expecting the same picture and frame rate as main and no newvk: a wait not met in replay orderlines in the log (Test Farm: @Beanstalk any, Kokiri Forest two minutes with defaults and with RX_VK_PARALLEL=4, compare the log's wait lines with main)Risks
What could break: the parallel replay's workers indexing the wrong signal (a segment starting at the wrong
sig): an event would get another signal's value and a queue could wait too long or go on early. SET signals, the only kind seen in this game, write the same value as before in every mode.Turning it off: revert the commit.
Compatibility: Nothing changes: no caches, settings or vk ABI involved.
Checklist
Everyone
type(scope): description) of the status line's type.main.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.🤖 Generated with Claude Code
@Beanstalk any OS and GPU: load a save in Kokiri Forest and play two minutes, once with the defaults and once with RX_VK_PARALLEL=4, on this PR and on main. Expected: the same picture and frame rate as main, and no new 'vk: a wait not met in replay order' lines in longshot_log.txt. SET signals (all this game uses) write the same values as before, so nothing should change on screen.
Beanstalk test farm
Commit
2c5a62e· tier reviewed · approved by dyst · dashboardWhat will be tested · AI plan (
gpt-6.1-terra)Compare the pull request with main in Kokiri Forest for two minutes per run, first with defaults and then with RX_VK_PARALLEL=4 to exercise parallel replay. The plan measures frame times, compares pictures, and checks for replay-order wait warnings. Crashes, warnings, substantial frame-time regressions, or picture differences fail the plan; this game run does not directly prove ADD-signal correctness.
RX_VK_PARALLEL=4), then move the stick, take the picture forest to compare with main, measure forest for 2 min (after 5 s warm-up); 1 run on each side.Done. Run 2: re-planned by dyst. Comment
@Beanstalkto run it again.NVIDIA GeForce RTX 4070, 615.71.9Measurements · linux
Verdict: could not be judged on linux (1/1 report).
Hardware: 1: linux+nvidia+nvidia-proprietary+dgpu
NVIDIA GeForce RTX 4070, 615.71.9AMD Ryzen 7 5800X3D 8-Core Processor, 63 GB RAMScene: kokiri-default, from a new save; kokiri-parallel, from a new save (RX_VK_PARALLEL=4); each cell's settings and switches as the table names them
Method: the Beanstalk test farm: main and this PR built and run on the same PC in one session, game starts alternating (ABBA); kokiri-default: 1 game start a side, forest 120 s after 5 s warm-up; kokiri-parallel: 1 game start a side, forest 120 s after 5 s warm-up; each number the median of the runs, then of 1 report
How to reproduce: the farm's plan above (
@Beanstalkon this PR runs it again)aa95d352c5a62eFlags and settings
None: the plan varied no setting, switch or build option.
Markdown for the PR description
The farm's first run (rp_20b7db7482e51065, Linux RTX 4070) judged no scenario: 'a step ran out of time: timeout: the game did not read the controller', on main and on this PR alike, before any measurement, so it says nothing about the change either way. @Beanstalk once more, please: the same plan (Kokiri Forest two minutes, defaults and RX_VK_PARALLEL=4, this PR against main).
View command line instructions
Checkout
From your project repository, check out a new branch and test the changes.