perf(vk): prevent VRAM paging surges across fast scene transitions #2467
Closed
Erfboom wants to merge 1 commit from
perf/vk-vram-surge-relief into main
pull from: perf/vk-vram-surge-relief
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
1 participant
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!2467
Loading…
Reference in a new issue
No description provided.
Delete branch "perf/vk-vram-surge-relief"
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?
When moving quickly between areas (e.g. Kokiri Forest <-> Hyrule Field <-> Market within < 60 frames),
min_unused = 60prevented eviction of newly idle textures from the previous scene while streaming in hundreds of megabytes of new textures. This caused texture allocations to surge past 170% of budget, pushing total GPU allocation past 6-8 GB VRAM capacity and causing severe 60-70 ms PCIe driver paging hitches.Changes
total_bytessurges overown + (own >> 3)(> 112.5% of texture budget), bypass the 10-frame gate intexture_frameto immediately initiate cache rebalancing.pool_cap(): Default to 128 MB (was 256 MB) on devices with <= 6.5 GB allowed VRAM.keep_finalized_max: Default to 192 MB (was 512 MB) on devices with <= 6.5 GB allowed VRAM.env_on("RX_VK_LOG_PARTIAL")to avoid spam during bursts of texture uploads.own(vk_texture.cpp:3875). If the excess can't be evicted (mostly GPU-written textures), the full budget pass runs every frame and never stops.:4262) evicts CPU-uploaded textures unused for only 8 frames and skips the compaction hold, so textures drawn every few frames can churn.pool_capdrops from 256 to 128 MB (:290) andkeep_finalized_maxfrom 512 to 192 MB (:4131). The finalized keep exists for the rainbow/garbage-texture issues #107 and #386, so this risks regressing exactly those cards.test_target_image_pool.pywas loosened rather than updated.RX_VK_LOG_PARTIALchange is unrelated.frame_no % 10gate as #2484.Thanks for going after the scene-change hitches. I agree with all of Joey-Magnus's points above (the gate that can stay open every frame, the 8-frame relief pass, the smaller finalized keep on cards up to 6.5 GB and the risk to #107/#386, the loosened test, the unrelated logging change, and the clash with #2484). I won't go over them again. A few things to add:
vk: ... textures retiredlines plus frame times for the Kokiri -> Field -> Market run) would show whether the gate, the relief pass or the two caps actually fixes it. Then the risky parts could be dropped. This changes behaviour on cards people actually play on, so it needs an in-game report.min_unusedexplains why it is 60: with a shorter age, about 300 textures in a few minutes of Kokiri were evicted and made again, 200 of them within 10 frames. Evicting CPU-uploaded textures after 8 frames brings back that pattern of re-uploads and re-decodes, just limited to the surge. See inline.vram_usage, and does the write-back batches, each of which is a submission plus a wait. Running it every present during a surge can put those waits on consecutive frames, in the very window this PR is trying to smooth out.keep_finalized_maxstill says "512 by default".About your other open PRs: #2469 also edits
vk_texture.cpp's staging andtexture_framecode, but in a different hunk, so I expect no textual conflict. #2484 rewrites the sameframe_no % 10gate and the same line intest_target_image_pool.py, so one of the two will need a rebase. That one is easier to reason about, since it only stays open while dead targets pile up.My suggestion: split this up. The first PR would be the gate and/or a relief pass that respects
min_unused, with measurements. Keep the default caps out unless a log shows they matter. For now this is a comment rather than an approval.This is measured against
own, while the relief pass below is measured againstbudget(which a preset, the 90% rule or the compaction hold can make smaller). If the surge is overbudgetbut notown, the relief only runs on every tenth present. And as Joey said, if the excess is textures this pass won't evict, it runs every present indefinitely. If you keep the bypass, a hysteresis or a cap (e.g. at most N extra passes after a gate trigger) would help.Nit: stale now. The default is 192 MB on cards of 6.5 GB or less.
8 frames is far below
min_unused(60), and the comment onmin_unuseddescribes exactly the churn this causes: 200 textures made again within 10 frames. A texture the game samples every few frames can be evicted and uploaded/decoded again on every surge pass. Could this at least respectRX_VK_EVICT_MIN_UNUSED, or use a much larger floor than 8?I tested this on Windows 11, RTX 3080 10 GB, i7-11700, 32 GB RAM, 1920x1080. The base is my fork build (
4a53c897+ zstd/BC7), texture budget 4 GB,RX_VK_COMPACT_PCT=90, with this PR cherry-picked onto it. Same exe, caches and save for both sides; the DLL is swapped between runs. Route: scripted fast teleports Kakariko -> Hyrule Field -> Lake Hylia every 10 s from 100 s to 200 s, 240 s per run; the same fixed save is restored before each run.memory sync, maxRX_VK_TEST_ALLOWED_MB=6500)memory sync, maxThe PR does lower the VRAM peak (and slightly lowers the retired count at 6.5 GB), which matches its goal. In my runs it did not improve the frame rate; at 6.5 GB the transition window had a long low stretch with this PR (the sample counts differ because the two runs took different times to reach the same present range).
Caveats: the PR's own base is
6842f21d, while this test is on4a53c897+ zstd/BC7;RX_VK_TEST_ALLOWED_MBsimulates the allowed-VRAM value and the eviction policy, not actual PCIe paging; one pair per configuration, and the transition route is noisy on this machine. If useful, I can repeat it on a clean latest-main build, or with a 6-8 GB card's actual paging, and with more interleaved runs. I have not changed the PR.For reference, the exact machine and test setup behind the table above:
4a53c897+ zstd/BC7 (v2.0.11-1024-g9bc83387), texture budget 4 GB,RX_VK_COMPACT_PCT=90,RX_VK_READBACK_NO_CATCHUP=1. The PR was cherry-picked onto that base for the test; the same exe, caches and fixed save were used for both sides.The result agrees with the review concerns above: this PR lowered the VRAM peak (9.55 -> 8.90 GB with the driver's 9 GB allowed; 6.85 -> 6.78 GB with
RX_VK_TEST_ALLOWED_MB=6500), but it did not improve the frame rate in these runs, and at 6.5 GB the transition window was worse (the relief pass/8-frame churn and the every-frame gate are the likely reasons). I did not change the PR; these are only measurements, with the caveats already noted (different base, simulated allowed VRAM, one pair per configuration).Thanks @DFN-master for the runs. That is the before/after I asked for, though on a 10 GB card with a simulated 6.5 GB limit instead of a real 6-8 GB card.
What they show: the VRAM peak goes down (9.55 -> 8.90 GB; 6.85 -> 6.78 GB with
RX_VK_TEST_ALLOWED_MB=6500), but the frame rate doesn't get better. With 6.5 GB simulated, the transition window drops from 41 to 15 fps. Thememory syncslow-submit maximum stays the same on both sides (~253-263 ms), so the stall this PR is aimed at doesn't shrink either.The simulated limit only changes what
vram_usagereports. It doesn't page anything. So the 41 -> 15 fps drop at 6.5 GB can't come from PCIe paging: it comes from the new policy itself, on the host side. That means the budget pass now runs on every present while textures are over 112.5% ofown(each pass sorts every texture, queries the budget and does write-back submissions with a CPU wait each), plus whatever the 8-frame relief pass and the smaller pool/finalized caps make again. The textures retired count is a little lower at 6.5 GB, so the extra cost seems to be the passes running more often rather than more evictions. Avk: slow submitphase breakdown from the two 6.5 GB runs would confirm which part it is.The code is unchanged since my last review (still
956ec66), so all the earlier points are still open: the gate compares againstownand the relief againstbudget, the gate can stay open every frame, the 8-frame age goes undermin_unused, the caps are lower on cards of 6.5 GB or less (the risk to #107/#386), the test was loosened, the logging change is unrelated, there's the clash with #2484, and the stale "512 by default" comment. CI still hasn't run on this head.Given these numbers, I'd still split it: a gate/relief change that respects
min_unusedand the 10-frame cadence, measured on a real 6-8 GB card, and no default cap changes unless a log shows they help. Still a comment, not an approval.Thank you @Joey-Magnus, @hckrman101, and especially @DFN-master for taking the time to test and provide concrete measurements.
The benchmark data across fast area transitions (Kakariko → Hyrule Field → Lake Hylia) with a 6.5 GB limit clearly demonstrates the issue: while peak VRAM was slightly reduced, running the budget pass on every frame past 112.5% caused heavy host-side submission stalls and the 8-frame relief pass induced re-upload churn, dropping transition performance from 41 FPS down to 15 FPS. On lower-spec hardware (6 GB VRAM laptops, Steam Deck), this is a noticeable regression rather than a performance win.
Given these findings, along with the overlap with #2484 and the potential risk to #107/#386 from lowering the finalized keep caps, I agree with closing this PR. Thanks again for the thorough review and testing!