Repository navigation
fix(vk): sweep a pile of dead render targets every present, not every tenth - #2484
bunbeans2-arch wants to merge 1 commit into
Conversation
… tenth Entering Castle Town's guard room adds about 2 GB of video memory within a second on a 16 GB card: texture_frame lets the dead render targets go on every tenth present only, and pool_trim gives back 16 images a present. While a regular pass finds a pile (64 or more shifted targets let go in its ten presents, or 64 or more target images made new), the presents in between run the pass too, as a sweep: dead targets alone, never a live texture. pool_trim takes 64 images a present while the pool holds more than twice its bound. RX_VK_PILE_FAST=0 and RX_VK_POOL_DRAIN=0: as before. Measured on v2.1.0 with the change, not on main (the pull request says so). Part of NotRexed#2180 Assisted-by: Claude Fable 5.2 Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
|
One more pair of runs on v2.1.0 (not
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. |
|
Tried 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 497060f with #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.) |
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 againstmainat 6c8c1bf. 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, onmainat 6c8c1bf with 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