Repository navigation
perf(vk): import game memory in 4 MB chunks, not 16, so VRAM mirrors fit the game's pools - #2685
SadTransGirl wants to merge 1 commit into
Conversation
…fit the game's pools A pool's VRAM mirror covers its import's whole range, and imports are made by chunk around what was bound. With 16 MB chunks 28-39% of the mirrors' bytes were outside every game pool: 459 of 1,666 MB in a Hyrule Field walk at DLAA 2560x1440, up to 925 MB after Castle Town to the field. The default chunk is now 4 MB where the pools have VRAM mirrors (discrete cards). Without mirrors (iGPUs, GCN) a chunk's padding costs no VRAM, so they keep 16 MB and no extra imports. span_game_pools still takes a game pool across a chunk's end into one import. RX_VK_IMPORT_CHUNK_MB=16: as before. Measured on an RTX 4070 SUPER (Windows, DLAA 2560x1440, unattended): - Hyrule Field walk, two runs a side: mirrors 1,236-1,268 MB against 1,645-1,657 MB; 58.1 / 58.6 fps against 59.0 / 58.2. - Kokiri Forest: mirrors 843 MB against 1,154, VRAM 6,672 MB mean against 7,281; 58.2 fps against 57.0. - Castle Town to the field: VRAM 7,859 MB mean against 8,357; 50.5 against 50.4 fps. - A 6 GB allowance (RX_VK_TEST_ALLOWED_MB=6144), two runs a side: the VRAM peak 5,865-5,887 MB against 6,129-6,135, the GPU's longest frame 12.5-13.5 ms against 21.7-24.1; the frame rate either way (53.0 / 52.4 against 50.3 / 54.9 fps). - Imports: ~50% more (91-94 against 59-65 in five minutes), each shorter, 0.8 s of driver time in all against 0.7. tests/test_import_chunk_default.py fails on the old default. Assisted-by: Claude Opus 5.5 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Tested on an 8 GB card, where it matters most: in Castle Town Market it takes about 7 fps and most of the long frames away. Windows 11, RTX 3060 Ti 8 GB (driver 32.0.16.2114), Ryzen 5 5600X (12 threads), 2560x1440 DLSS.
The Market's GPU time moves between launches on this card, but all three 4 MB runs are above all three 16 MB ones. As in your walk, the freed VRAM goes to textures (the budget rises by ~250 MB); with fewer textures evicted and made again, the long frames drop. |
|
A follow-up that may help with the mirrors on 8 GB cards in general: on this card, the Market's frame rate from launch to launch follows how much the mirrors hold. Same machine as above (RTX 3060 Ti 8 GB, Windows). 37 runs in Castle Town Market today, across several builds (
Correlation between fps and mirror MB over the 37: -0.77. The slow launches are the ones whose mirrors reach the budget's 2 GB ( I could not find what makes a launch build 75 mirrors or 300: the save, the route and the build were the same, and the five fast launches came in a row at the end of the session. With this PR the fast case is more common (its 4 MB arm was at 1.66-1.77 GB against 1.97-2.00 GB for 16 MB), which fits the gain above. A lower mirror budget on 8 GB cards might also be worth a test, though the comment in |
Joey-Magnus
left a comment
There was a problem hiding this comment.
I merged this into current main and ran tests/test_import_chunk_default.py, nx2/test_import_windows.py (all three modes) and the import/mirror checks: all pass. mirror_on() reads dev.props, and the first import_chunk() call comes from an import, which is after device creation, so the cached default can't be decided before the GPU is known. iGPUs and GCN keep 16 MB, and span_game_pools still covers a pool across a chunk's end. Your table, plus klikso's independent A/B on an RTX 3060 Ti 8 GB in Castle Town Market (higher fps on all three 4 MB runs and about half the frames over 50 ms), is enough for me on NVIDIA. AMD RDNA is the tier to watch. It gets the new default too, the code's comments put an import there at 20-75 ms on the replay thread, and this makes ~50% more of them. If an AMD tester reports new hitches, RX_VK_IMPORT_CHUNK_MB=16 is the A/B. I found no other open PR that touches import_chunk. The docs row merges cleanly alongside #2684's.
A pool's VRAM mirror covers its whole import, and imports are made in 16 MB chunks, so 28-39% of the mirrors' bytes hold memory outside any game pool. Importing in 4 MB chunks cuts the mirrors by roughly a quarter with no frame-rate cost measured.
Cause. Imports are made by chunk (
import_chunk,RX_VK_IMPORT_CHUNK_MB) around what was bound, and a mirror copies its pool's whole range. A temporary measuring patch counted, for the live mirrors, the bytes outside every entry ofguest_pools: 459 of 1,666 MB in a Hyrule Field walk at DLAA 2560x1440, 463 of 1,360 MB in Kokiri Forest, and up to 925 of 2,400 MB after Castle Town to the field. It also found almost no mirrors with no game pool in them at all, so the waste is padding inside live mirrors, whichmirrors_give_backcan't reach.Change.
import_chunk()defaults to 4 MB where the pools have VRAM mirrors (mirror_on(): discrete cards, not GCN). Without mirrors a chunk's padding costs no VRAM, so iGPUs and GCN keep 16 MB and take no extra imports.span_game_poolsstill takes a game pool across a chunk's end into one import (the Kokiri hitch it was made for did not come back).RX_VK_IMPORT_CHUNK_MB=16gives the old size.docs/development.mdgets a row for the switch.Measured. RTX 4070 SUPER, Windows 11, DLAA 2560x1440, unattended, the same build (main 15646d1; the branch is rebased onto edaef2a) with and without
RX_VK_IMPORT_CHUNK_MB=16:RX_VK_TEST_ALLOWED_MB=6144), VRAM peakIn the walk the freed VRAM is taken up by textures, as the budget allows, so the process's VRAM mean only drops 90-240 MB there; where the allowance is tight it shows as a lower peak. The 6 GB frame rate went either way across two pairs, so I'm not claiming a frame-rate gain.
Tests.
tests/test_import_chunk_default.pychecks the default (4 with mirrors, 16 without), that the switch still sets it, and thatpool_lookupstill spans pools across a chunk's end; it fails on the old default.nx2/test_import_windows.py's fixture gets amirror_on()stub, since it compilesimport_chunk.Not tested. AMD (an import there cost 20-75 ms on the replay thread per the code's comments, so ~50% more of them may matter), Intel, Linux, a real 6 or 8 GB card.
🤖 Generated with Claude Code