fix(vk): the uniform buffer snapshot keys on the binding's pool, not the device #2609
Open
blessedplummer wants to merge 1 commit from
blessedplummer/ub-snapshot-pr into main
pull from: blessedplummer/ub-snapshot-pr
merge into: MagicBeanDev:main
MagicBeanDev:main
MagicBeanDev:github/pr/2893
MagicBeanDev:github/pr/2890
MagicBeanDev:github/pr/2887
MagicBeanDev:github/pr/2878
MagicBeanDev:github/pr/2875
MagicBeanDev:github/pr/2874
MagicBeanDev:github/pr/2873
MagicBeanDev:github/pr/2871
MagicBeanDev:github/pr/2756
MagicBeanDev:github/pr/2897
MagicBeanDev:github/pr/2896
MagicBeanDev:github/pr/2718
MagicBeanDev:github/pr/2842
MagicBeanDev:github/pr/2691
MagicBeanDev:github/pr/2895
MagicBeanDev:github/pr/2743
MagicBeanDev:github/pr/2765
MagicBeanDev:github/pr/2708
MagicBeanDev:github/pr/2732
MagicBeanDev:github/pr/2755
MagicBeanDev:github/pr/2817
MagicBeanDev:github/pr/2876
MagicBeanDev:release-please--branches--main
MagicBeanDev:release-please--branches--main--release-notes
MagicBeanDev:github/pr/2778
MagicBeanDev:github/pr/2888
MagicBeanDev:github/pr/2866
MagicBeanDev:github/pr/2877
MagicBeanDev:github/pr/2800
MagicBeanDev:github/pr/2829
MagicBeanDev:github/pr/2850
MagicBeanDev:github/pr/2889
MagicBeanDev:github/pr/2882
MagicBeanDev:github/pr/2860
MagicBeanDev:github/pr/2849
MagicBeanDev:github/pr/2886
MagicBeanDev:github/pr/2794
MagicBeanDev:github/pr/2840
MagicBeanDev:github/pr/2830
MagicBeanDev:github/pr/2834
MagicBeanDev:github/pr/2719
MagicBeanDev:github/pr/2742
MagicBeanDev:github/pr/2741
MagicBeanDev:github/pr/2820
MagicBeanDev:github/pr/2771
MagicBeanDev:github/pr/2859
MagicBeanDev:github/pr/2858
MagicBeanDev:github/pr/2823
MagicBeanDev:github/pr/2757
MagicBeanDev:github/pr/2769
MagicBeanDev:github/pr/2844
MagicBeanDev:github/pr/2843
MagicBeanDev:github/pr/2673
MagicBeanDev:github/pr/2855
MagicBeanDev:github/pr/2739
MagicBeanDev:github/pr/2807
MagicBeanDev:github/pr/2851
MagicBeanDev:github/pr/2789
MagicBeanDev:github/pr/2814
MagicBeanDev:github/pr/2818
MagicBeanDev:github/pr/2774
MagicBeanDev:github/pr/2772
MagicBeanDev:github/pr/2750
MagicBeanDev:github/pr/2786
MagicBeanDev:github/pr/2785
MagicBeanDev:github/pr/2782
MagicBeanDev:github/pr/2779
MagicBeanDev:github/pr/2775
MagicBeanDev:github/pr/2706
MagicBeanDev:github/pr/2766
MagicBeanDev:github/pr/2747
MagicBeanDev:github/pr/2759
MagicBeanDev:github/pr/2745
MagicBeanDev:github/pr/2740
MagicBeanDev:github/pr/2733
MagicBeanDev:github/pr/2725
MagicBeanDev:github/pr/2727
MagicBeanDev:github/pr/2728
MagicBeanDev:github/pr/2729
MagicBeanDev:github/pr/2721
MagicBeanDev:github/pr/2722
MagicBeanDev:github/pr/2715
MagicBeanDev:github/pr/2714
MagicBeanDev:github/pr/2707
MagicBeanDev:github/pr/2703
MagicBeanDev:github/pr/2705
MagicBeanDev:github/pr/2697
MagicBeanDev:github/pr/2679
MagicBeanDev:github/pr/2676
MagicBeanDev:github/pr/2669
MagicBeanDev:docs/what-hookshot-connects-to
MagicBeanDev:fix/hdr-encode-test
MagicBeanDev:fix/main-tests
MagicBeanDev:fix/play-cache-files
MagicBeanDev:perf/game-barrier-order
MagicBeanDev:feat/heap-lazy
MagicBeanDev:feat/texture-detail
MagicBeanDev:perf/astc-opaque-bc1
MagicBeanDev:fix/fs-dir-lock
MagicBeanDev:fix/framegen-native-kept
MagicBeanDev:fix/update-no-downgrade
MagicBeanDev:port/k10-gcn-f16-mirrors
MagicBeanDev:fix/framegen-mult-cap
MagicBeanDev:chore/release-as-2.1.1
MagicBeanDev:perf/pcache-load-switch
MagicBeanDev:fix/prepare-progress-log
MagicBeanDev:fix/update-closes-stale-game
MagicBeanDev:fix/hdr-scaled-sampled
MagicBeanDev:perf/first-start-preset
MagicBeanDev:perf/zero-upload
MagicBeanDev:fix/vcore-escape-2s
MagicBeanDev:test/fake-gh-atomic
MagicBeanDev:perf/batch-idle-flush
MagicBeanDev:test/finish-stub-a
MagicBeanDev:chore/record-2.1.0
MagicBeanDev:fix/main-red-tests
MagicBeanDev:fix/test-display-startup-driver-cache
MagicBeanDev:feat/mesh-shader-mode
MagicBeanDev:fix/menu-probes-at-startup
MagicBeanDev:fix/fps-counter-classic
MagicBeanDev:fix/test-log-batch-flake
MagicBeanDev:fix/narrow-screen-hud
MagicBeanDev:ci/prereleases
MagicBeanDev:release/v2.0.15
MagicBeanDev:hotfix/v2.0.15
MagicBeanDev:fix/present-ahead-replay
MagicBeanDev:release/v2.0.13
MagicBeanDev:fix/bracket-paths-2013
MagicBeanDev:fix/hdr-overlays-2013
MagicBeanDev:fix/fps-counter-scale-2013
MagicBeanDev:fix/stick-seen-at-rest
MagicBeanDev:hotfix/menu-fits-screen
MagicBeanDev:fix/f1-always-opens-menu
MagicBeanDev:fix/ini-keep-lines
MagicBeanDev:claude/cranky-pike-7cf247
MagicBeanDev:perf/texture-answer-flat
MagicBeanDev:fix/stamp-test-modules
MagicBeanDev:fix/appimage-fonts
MagicBeanDev:fix/display-awake
MagicBeanDev:release/v2.0.12
MagicBeanDev:fix/discord-windows
MagicBeanDev:rc/v2.0.12-tests
MagicBeanDev:fix/dlss-keep-feature
MagicBeanDev:rc/v2.0.12
MagicBeanDev:button-icons
No reviewers
Labels
Clear labels
accessibility
Barrier affecting people with disabilities
autorelease: pending
autorelease: tagged
bug
Something isn't working
dependencies
Pull requests that update a dependency file
documentation
Improvements or additions to documentation
duplicate
This issue or pull request already exists
enhancement
New feature or request
github_actions
Pull requests that update GitHub Actions code
good first issue
Good for newcomers
help wanted
Extra attention is needed
invalid
This doesn't seem right
question
Further information is requested
testing wanted
wontfix
This will not be worked on
No labels
accessibility
autorelease: pending
autorelease: tagged
bug
dependencies
documentation
duplicate
enhancement
github_actions
good first issue
help wanted
invalid
question
testing wanted
wontfix
Milestone
Clear milestone
No items
No milestone
Assignees
Clear assignees
No assignees
2 participants
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".
No due date set.
Dependencies
No dependencies set
Reference
MagicBeanDev/Hookshot!2609
Loading…
Reference in a new issue
No description provided.
Delete branch "blessedplummer/ub-snapshot-pr"
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
#1795's in-place hazard: a uniform buffer bound as the pool's guest memory is read by the GPU when the recording executes, and the game rewrites its constants right after the submit — the Steam Deck drew giant HUD hearts, slabs and stretched geometry from exactly this. The fix proposed there keys the snapshot globally (no mirrors on the device ⇒ copy every uniform buffer), which covers integrated GPUs,
RX_VK_MIRROR=0and GCN's default — but leaves the mixed states of a mirrored device exposed: a pool whose mirror the budget refused, or whose make is queued or deferred, binds the same guest memory with the same hazard while mirrors run everywhere else.This keys the condition per binding instead of globally: the protection follows the hazard itself, so any mirror-less bind on any device is safe — including mixed states that don't exist yet.
What
gpu_buffer_bindtags the bindings that ARE the pool's guest memory (BufferRef::live, set by its three direct paths — the mirror-less states, and only where a recording will execute them), and the uniform-buffer path copies exactly those as submitted. A mirror's binding stays in place (it was synced at the submit); a bind outside a recording executes nothing.The states (where behavior changes on unset)
RX_VK_MIRROR_DEFER=1, a parallel replay's segments (the make is skipped), a pool already written this submission, a failed make retried at submission start. In-place until made. Previously exposed; now copied.RX_VK_MIRROR=0, GCN's default): every pool binds guest memory ⇒ every uniform buffer copied — byte-identical to the keying #1795 proposed (live-measured below).Unchanged on unset: mirror binds (submit-synced, in place), binds outside a recording, the async-import stream copies, unaligned/outside-pool binds (already copied), and a mirrored device with no refusals (live-measured: zero copies, as on main).
Switch semantics (a plain note, since one documented behavior is superseded)
On main, unset and
RX_VK_UB_SNAPSHOT=0both mean fully-off (in-place everywhere). After this, unset and=0both mean the per-binding rule, and=1still copies every uniform buffer without asking the pools. The in-place opt-out for a mirror-less device isRX_VK_MIRROR=1, whose submit-time sync makes it safe. #1795's "=0restores the in-place binding" semantic is superseded by this. Storage buffers, vertex and index binds are out of scope, as in #1795.Verification
tests/test_ub_snapshot_per_pool.pycompiles the production selection hunk (cut fromvk_draw.cpp) with the bind stubbed — 7 scenarios: mirror bind in place; mirror-less bind copied; outside-pools copied; misaligned copied;=1copies everything without asking the pools;=0is the per-binding default. Plus source needles (thelivetag, the three tagged direct returns count-checked, the!b.livecondition). 7/7 pass.6f7ab2a7: 440 passed / 1 failed / 33 skipped on this branch, pristine 439/1/33 — the 1 is upstream's owntest_env_onfailure (pre-existing on pristine, tracked in the thread); this branch adds exactly its 1 test. Build: 0 failed.RX_VK_UB_SNAPSHOT=1→ 1,275,001 copies, never asking the pools;RX_VK_MIRROR=0→ 1,280,001 copies — the global-off degenerate case, byte-identical volume to the keying #1795 proposed.Cost
Measured at parity on gameplay, not inferred: the
RX_VK_DGPU_TRIALS=0discriminator in the companion thread measured this snapshot path at +0.9% (inside run-to-run noise, adjacent warp-normalized pairs) while it was serving ~14M stream copies per run. Correctness fix, noise cost.Provenance & scope
6f7ab2a7. No policy machinery travels with this: no trials, no skip list, no counters, noRX_VK_DGPUgating — the diff reads as a refinement of #1795's own fix.This no longer merges. #2464 (
018a1d2e) has since landed in the same uniform_range hunk of gpu/vk/vk_draw.cpp, and vk_memory.cpp conflicts too, so I couldn't run the tests on a merge. #2464 made the snapshot the default on Intel when the pools have no mirror. It deliberately left AMD APUs, GCN and RX_VK_MIRROR=0 off "until it is measured there". This PR turns it on per binding for every GPU, the Steam Deck included. The only cost figure is from a mirrored RX 9070 XT, where it copies nothing. The devices it actually changes, and where every uniform buffer would be copied, have no frame-time measurement. A rebase onto #2464 needs that measurement on an APU, or the Deck, in Ocarina of Time.After this, RX_VK_UB_SNAPSHOT=0 no longer turns the snapshot off, which goes against the on/off rule the switches follow since #2651. Please keep =0 as off.
The mixed-state cases (a refused or wanted pool on a mirrored GPU) are a real gap and worth fixing. It also overlaps #1795 and #2338, which are both still open, so the maintainers should pick which way they want this to go.