WIP: perf(vk): below 60 fps the eviction's waits are seconds, not presents: the compaction's hold and the GPU-drawn textures' keep #875
No reviewers
Labels
No labels
area/accessibility
area/audio
area/input
area/install
area/menu
area/renderer
area/saves
area/upscaling
beanstalk: approved @ 1697603
beanstalk: approved @ 2c5a62e
beanstalk: approved @ 4fd82b7
beanstalk: approved @ 64d6d09
beanstalk: approved @ 6f91fae
beanstalk: approved @ 70a78f9
beanstalk: approved @ 8d361dc
beanstalk: approved @ 9d8356e
beanstalk: approved @ abf2227
beanstalk: approved @ d82f202
beanstalk: approved @ e5f1e40
beanstalk: approved @ ee8ab5f
ci: approved
good first issue
gpu/amd
gpu/igpu
gpu/intel
gpu/nvidia
help wanted
kind
bug
kind
chore
kind
docs
kind
feature
kind
performance
kind
question
needs measurements
platform/linux
platform/macos
platform/steam-deck
platform/windows
preview
priority
critical
priority
high
priority
low
regression
status
blocked
status
confirmed
status
duplicate
status
invalid
status
needs-info
status
wontfix
testing wanted
ci: approved
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
MagicBeanDev/Longshot!875
Loading…
Reference in a new issue
No description provided.
Delete branch "HumanBean/Longshot:perf/evict-seconds-again"
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?
Type: perf · Risk: low · Tested on: Windows 11, game-free checks (no game run) · Needs: Windows, a GPU under 60 fps with VRAM near its limit (an integrated GPU or a 4-8 GB card)
Why
When video memory runs short, the compaction lets go of textures nobody has drawn for ten seconds, and of more once they are thirty seconds old. Those times are written as ten and thirty seconds, but they are counted as 600 and 1800 frames, which is only right at 60 fps. Below 60 fps the wait gets longer: at 20 fps it is 30 s and 90 s, and at 3.5 fps (Unity's UHD Graphics laptop, an i3-1115G4) it is three and nine minutes. That laptop held 1,776 MB of textures against a budget of 1,299 MB, and the compaction freed 0 to 13 textures a pass. Textures the GPU drew have a wait of their own, a minute (3600 frames; 600 near the driver's limit), which nothing frees sooner: at 3.5 fps that is 17 minutes, and on that laptop 1,011 MB of the 1,776 MB were GPU-drawn, with 47 MB of all textures used in the last 8 frames. Players below 60 fps are the ones with the least VRAM to spare, the same players behind the worklist's top row (memory filling up over play, worst on 4-8 GB cards). See NotRexed/Hookshot#993.
What changed
The compaction's two waits and the GPU-drawn textures' keep now go by time, from the frame rate over the last ten seconds. At 60 fps or more nothing changes. The keep never goes under 120 frames, and the eviction's own one-second wait stays counted in frames, because the game samples some GPU-drawn textures every so many of its own frames (a terrain normal map every 40) and one let go between two samples comes back empty.
age_at_60ingpu/vk/vram_compact.h(a texture's unused presents as at 60 fps; unchanged at 60 fps or more or with no rate known; under 2 fps counted as 2 fps, so a load's stall does not age every texture at once).texture_frameingpu/vk/vk_texture.cppkeeps a mark (time, present count) at each budget look (every 10 presents) and measures the presents a second over the last ten seconds; the hold's pass callsvram_compact::hold_targetwithage_at_60(frame_no - last, present_rate). The eviction's own wait stays in presents:RX_VK_EVICT_MIN_UNUSED(60).at_rateingpu/vk/keep_rendered.h(the keep as many presents as it is seconds at 60 fps, 120 at least), used wheretexture_frametakeskeep_rendered::presents.tests/test_keep_rendered.cppand.py(at_rateat 60, 30, 3.5 and 0.5 fps and its floor; the call),tests/test_vram_compact.cpp(age_at_60andhold_targetwith it, Unity's 3.5 fps),tests/test_vram_compact.py(the call, the rate, the switch, and the eviction's own wait still in presents).docs/development.md(RX_VK_EVICT_BY_PRESENTS).Measurements
Verdict: the game-free checks pass; nothing was measured in the game. This PC runs the game at well over 60 fps, where the change does nothing, and has no game data in this worktree. The in-game run is under Must be tested.
Hardware: Windows 11, llvm-mingw clang 20261104 (the nightly's toolchain), Python 3
Scene: none (the checks need no game). The 3.5 fps and the textures and budget come from Unity's
nightly-132-5e072fc8logs (UHD Graphics, i3-1115G4, 16 GB, 7.2 GB allowed)Method:
tests/test_vram_compact.py(compilesvram_compact.hand runs its rules, and readstexture_frame's source) against main's source and this PR's;tests/run_all.pyon both, one after the otherHow to reproduce:
python -I -B tests/test_vram_compact.py; for main, copy this PR'stests/test_vram_compact.*into a worktree ataa95d35fand run itaa95d35fa8a41ddftests/test_vram_compact.pyandtests/test_keep_rendered.py(this PR's versions)tests/run_all.pyFlags and settings
One new switch, to go back to counting in presents for both.
RX_VK_EVICT_BY_PRESENTS=1Testing
Tested: On this PC (Windows 11), the game-free checks:
tests/test_vram_compact.pyandtests/test_keep_rendered.pyfail on main's source and pass here;tests/test_texture_squeeze.pyandtests/test_blocks_at_start.pypass;tests/run_all.pyon main and on this PR (Measurements). The renderer (longshot_vk.dll) builds with llvm-mingw.Not tested: The game, on any GPU. Not measured: how many more textures go, and come back as uploads, on a PC below 60 fps; whether ten seconds is still the right wait at 20-30 fps (it was measured at 60). Not built on Linux (the change is portable C++:
std::chrono,std::deque).Must be tested:
VRAM:lines' textures to come down to their budget on this PR (on main they stay over it), and no more than a fewtextures madea frame more (by hand: thevk: VRAM:,textures retiredanda frame:lines inlongshot_log.txt; test request T-JA2B, waiting for the testing wanted label)Risks
What could break: Below 60 fps, with VRAM over the compaction's lines, textures unused for 10 or 30 seconds now go where they stayed for minutes; one seen again is uploaded again, a hitch on a slow PC. Textures the GPU drew now go after a minute below 60 fps too; the 120-present floor and the eviction's own 60 are what keep a periodically sampled one from coming back empty, and a game texture sampled less often than every 120 of its frames but drawn only once would not be covered (none is known). A frame rate measured too low (a load) could age textures faster: the age goes as at 2 fps at most.
Turning it off:
RX_VK_EVICT_BY_PRESENTS=1, or revert the commits.Compatibility: Nothing changes: no save, options, cache or interface change.
Issues
See NotRexed/Hookshot#993 (memory filling up over play, the worklist's top row)
Checklist
Everyone
type(scope): description) of the status line's type.main.python -I -B tests/run_all.pypasses (any failure that also fails onmainis named).third_party/untouched (a new folder with aPROVENANCE.mdinstead).When it applies
Assisted-by:/Co-Authored-By:trailers.mainand passing here.tests/that reads changed source updated in this PR, not weakened.🤖 Generated with Claude Code
fb37e32208b573d3c656b573d3c656d51401bc37Rebased onto main @
b9e95173now that the revert (#873) has merged: the diff is #771's change again, 8 files, +71/-7, the same as #771's merge. No tests were run here. The review's fix comes next.View command line instructions
Checkout
From your project repository, check out a new branch and test the changes.