fix(vk): sweep a pile of dead render targets every present, not every tenth #2484
Open
bunbeans2-arch wants to merge 1 commit from
bunbeans2-arch/fix/pile-of-dead-targets into main
pull from: bunbeans2-arch/fix/pile-of-dead-targets
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!2484
Loading…
Reference in a new issue
No description provided.
Delete branch "bunbeans2-arch/fix/pile-of-dead-targets"
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?
Entering one room (the guard room beside Castle Town's gate, about 15 pots) adds about 2 GB of video memory within a second on a 16 GB card and takes the game to 14.5-14.8 GB there. A session that froze in that room has the same jump at the end of its log (#2180). With this change the same room tops out at 12.2-12.6 GB.
Part of #2180
Read this first: the runs below are on v2.1.0 with this change, not on
main.mainhas moved in this pass since (#2198: the compaction on by default, its hold letting the dead targets go first), and that alone may change this room. A build ofmainmeans a new shader store on my PC, so I have not runmainin the game, with or without the change. The diff is made againstmainat6c8c1bfb. Theregpu/vk/vk_texture.cppcompiles with it (llvm-mingw, the back end's flags fromnx2/build.py; that one file, not a whole build), andtests/run_all.pygives the same result with and without it on my PC (below). If you would rather have the numbers onmainfirst, say so and I will bring them when I have a store for it; if you see from the code that #2198 already covers this, close it.What goes wrong
texture_framereturns on nine presents of ten before the pass that lets go of the dead render targets (the frame's scratch targets another target has drawn over).pool_trimgives back 16 images a present, 64 only when the driver's count is over 90% of the allowance.The change
texture_frame: a regular pass (every tenth present) that finds its ten presents let 64 or more shifted targets go, or made 64 or more target images new, turns a pile on for the next ten presents. While a pile is on, the presents in between run the pass too, as a sweep: dead targets alone, never a live texture, whatever the budget says. The budget's, the hold's and the driver's-limit passes keep their pace (by_holdneeds!sweep, and an extra pass is a sweep).RX_VK_PILE_FAST=0: as before.pool_trim: 64 images a present, not 16, while the pool holds more than twice its bound.RX_VK_POOL_DRAIN=0: as before.vk: a pile of dead render targets: N extra passes so far, M targets let go in them. Extra passes do not print thetextures retiredline (it would be about 60 lines a second while a pile lasts); their count is in the pile's line.RX_VK_X=0: as beforepattern (RX_VK_DEAD_TARGETS): the fix is on, the switch gives the old behaviour back. They are documented in their comments, as the dead targets' and the pool's other switches are;docs/development.mddoes not list those.Numbers
RX 9070 XT 16 GB (driver 0x8001a0 as the log prints it), i9-9900K, 32 GB RAM, Windows 11. v2.1.0 built from source, with and without the change, 3840x2160, frame generation on Auto, default texture budget (6144 MB),
RX_VK_PARALLEL=4, scripted input. "Game" is the game's own video memory, "adapter" everything on the card.The room, peak in MB (game / adapter):
The runs without the change were ended early, by one of my safety stops or by the script a few seconds after the door, so I have no fps in the room without it at this budget. With it the four runs stayed 298 s, 567 s, 366 s and 388 s in the room (the third and fourth with sword swings only):
The 234 ms gap is where four compute pipelines compiled in play.
A walk back and forth over the drawbridge (frame generation 2x, same route, one run each), for what the change costs where no pile lasts:
Extra passes ran on 1,368 of that walk's 17,192 presents (8.0%).
What this does not show
mainin the game (above).Test
python -I -B tests/test_target_image_pool.py: two of its checks named the lines this changes (the tenth-present return,pool_pressed ? 64 : 16) and are updated; a new check keeps the rule: an extra pass only while a pile is on, an extra pass is a sweep and comes before the hold'sby_hold, only a regular pass turns a pile on, an extra pass prints no retired line, and both switches are read. 10 of 10 pass with the change; 3 of 10 fail onmainwithout it.python -I -B tests/run_all.pyon Windows, onmainat6c8c1bfbwith the change: 375 passed, 6 failed, 31 skipped. Plainmain: 375 passed, 6 failed, 31 skipped, the same six (tests/test_fpx_sticky.py,tests/test_bake_portability.py,tests/test_vram_budget_row.py,nx2/test_nup_paths.py,nx2/test_nup_read_name.pyand the byte-compile). They are my PC's set-up, not this change: the ones I read stop at a file link Windows would not let my user make, and at a fixture my compiler could not build.The runs above were made with the build that still printed the retired line on extra passes; apart from the move from v2.1.0 to
main, that one condition is the only difference between the change as it ran and this diff.🤖 Generated with Claude Code
One more pair of runs on v2.1.0 (not
main): the drawbridge / market walk with frame generation 2x, the same build both times. Time is counted from the first second the game's video memory was over 11,000 MB, which is the area loaded.RX_VK_PILE_FAST=0andRX_VK_POOL_DRAIN=0: ended after 311 s by my stop on free commit (5,995 MB against a 6,000 MB line), in a second where the game's video memory jumped 1,123 MB to 14,605 MB.That stop is not a RAM leak. In five walks here the process's private bytes follow its dedicated video memory (about 17 GB plus 1.13 to 1.18 MB for each MB of video memory), so free commit drops in the second the video memory peaks.
One run each, so this is a hint, not a proof.
WIP: fix(vk): sweep a pile of dead render targets every present, not every tenthto fix(vk): sweep a pile of dead render targets every present, not every tenthTried this on NVIDIA with an 8 GB card, since the numbers so far are from a 16 GB AMD card. It helps a lot in Castle Town's market for me.
Setup: RTX 5060 Ti 8 GB, driver 610.88, Core Ultra 7 265F, Windows 11, 1080p. Built on main at
497060fwith #2482 merged, then the same build with this PR added on top. Same switches both times; this PR is the only difference.The market's crowd changes a lot (anywhere from 1,000 to 3,400 draws a frame), so I compared fps at the same draw count. Same route each time, Hyrule Field into the market:
What changed in the log in the market: VRAM was over the driver's limit in 3 of 4 reports before and 1 of 9 after. Rendered textures went from 900-1,019 MB to 694-875 MB, and dead targets left for a regular pass went from about 103 to 25 (41,363 let go in 2,664 extra passes over the session). Live textures evicted for the budget also dropped, from about 51 a pass to 27. It recovers from the entry dip a lot faster, and I didn't see any visual problems.
One more thing I noticed that this PR doesn't touch: on an 8 GB card the target pool is almost never used. It's given back while pressure is over 90% of the allowance, and an 8 GB card sits there nearly all the time (61 of 76 VRAM reports in Hyrule Field said "VRAM short: given back"). In the market that meant about 4,350 target images made new per 600 presents against about 370 reused. Maybe keeping a small pool of the shapes that come back every frame would cut that churn on smaller cards, but I haven't tried it.
(I used Claude to help read the logs; the playing and testing were mine.)