Repository navigation
Evict unused non-model textures from the GPU between missions - #7878
dustinspace217 wants to merge 2 commits into
Conversation
bm_page_in_stop() pages out a bitmap the new mission does not preload with bm_unload_fast(), which frees only the system-RAM copy. The OpenGL texture object stayed resident until exit: gr_opengl_bm_free_data() frees it only on release, and the per-mission opengl_tcache_flush() has been commented out since 2007. Only model textures ever left, through bm_release(). A mod with large per-setting effect sets accumulates every explosion, impact and particle animation it has ever shown, exhausts VRAM after a few missions, and the driver spills into system RAM. Track per bitmap whether it was drawn or locked since the last page-in, and how many consecutive page-ins it has gone without being preloaded, drawn or locked. At the tabled count (default 1) the GPU copy is freed, whole animations at a time so a shared texture array is never left half alive. Textures the next mission preloads keep their GPU copy, so shared content is not re-uploaded; anything drawn last mission survives one more; mission restarts keep everything. The marks are cleared in a pass after the page-in loop, because preloading a later frame binds it and would re-mark a first frame the loop had already visited. Eviction runs only on OpenGL: Vulkan already drops every texture at page-in start, and its free deletes the slot's backend object. game_settings.tbl: $Evict Unused GPU Textures After Missions: N (OpenGL only; 0 or less restores the old keep-until-exit behavior; values above 255 clamp). Debug builds log each evicted animation and the per-mission count. The new test suite drives bm_page_in_start/stop with the stub renderer and a recording free hook: the table knob, N=0/1/2 semantics, the used mark, preload, locks held across a page-in, whole-animation frees, user and volume bitmaps, non-array animations, the renderer gate, and the stale-mark case. Fixes scp-fs2open#7873
|
If the issue with copying the current vulkan approach is the mid-mission re-upload, why can't that be fixed? Is it even an issue? Is it even particularly slow to load from RAM to gpu memory on mission load? It certainly seems a lot simpler and intuitive than adding a new table value to adjust how long a texture is kept for, and having that applied to one backend only. |
|
Fair question. I went back and measured the hitch. It was all of 12ms from a couple explosions. Converting to the simpler approach: full eviction of non-preloaded non-model textures. |
Replaces the per-bitmap use mark, the unused-mission counter and the $Evict Unused GPU Textures After Missions: table key with the design qazwsxal asked about on scp-fs2open#7878: at bm_page_in_stop every bitmap the new mission does not preload loses its GPU copy along with its RAM copy, the way the Vulkan backend already flushes at page-in. Textures a mission draws lazily are re-uploaded on first use; measured on an RTX 5080 that upload stays inside normal frame time (12.6 vs 12.4 ms worst frame in the fight window of a revisited mission). Whole animations are freed or kept together, locked bitmaps and user or volume bitmaps are skipped, and Vulkan is untouched. The irradiance pass and the envmap dump read the environment cubemap's texture id straight from its slot; they now bind it through the texture cache first, which recreates a freed file cubemap (and uploads a fresh one, which also fixes the first mission that uses a file cubemap, where the pass used to bind texture 0).
|
The streaming-animation case from the review (an EFF stream that resets to its first frame after a texture free) is handled in #7886, which gives EFF streams their own buffer and user bitmap like the ANI and APNG streams. This PR stays as the eviction alone. |
What?
Textures a mission does not preload are now freed from the GPU at mission load, instead of staying until you quit. OpenGL only. Adds the first unit tests for bmpman's mission-load logic.
Why?
In OpenGL, VRAM use only ever grows during a campaign. Every explosion, impact and particle animation any mission has shown stays loaded, because the mission-load cleanup frees the system-RAM copy but not the GPU one. Mods with big effect sets hit the wall after a few missions: loads slow down, then the game dies. Fixes #7873.
How?
At the end of mission load the engine already walks every bitmap and drops the RAM copy of anything the new mission does not preload. The GPU copy now goes with it. Whole animations are freed together, since their frames can share one texture array; locked bitmaps and user or volume bitmaps are skipped; Vulkan is untouched because it already flushes at mission load. A texture the mission later draws without having preloaded it is read and uploaded again on first use, the same path as its first use ever.
The first version of this PR kept anything drawn last mission for one more mission and added a table key for that. qazwsxal asked why not do what Vulkan does. I measured the re-upload and it is not visible: the worst frame in a fight on a revisited mission was 12.6 ms against 12.4 ms on the first visit (RTX 5080, FS2 with MediaVPs 5.0.2), so this version does what Vulkan does.
One consumer read a texture id straight out of its slot instead of going through the texture cache: the irradiance pass, when a mission names a file cubemap with
$Environment Map:. It now binds through the cache like the deferred pass does, which also fixes the first mission that uses a file cubemap, where the pass used to bind texture 0.Known limit, shared with Vulkan: a streaming EFF animation that a mod script keeps across a mission load shows its first frame until it next advances. A follow-up PR will give EFF streams a user bitmap of their own, the way ANI and APNG streams already work, so the current frame survives any flush.
Testing?
Linux, Release and Debug, headless, one process chained through missions, MediaVPs 5.0.2. FS2 four missions and A,B,C,A on master and this branch; a combat A,B,A with two wingmen destroyed each mission; Star Fox Event Horizon four missions and A,B,C,A; screenshots of four missions plus the main hall after each, two runs per build; Vulkan on an RTX 5080; a scratch mission with
$Environment Map: cubemapplayed, left, and replayed with the irradiance pass logging the texture it binds. 13 unit tests, suites green in Release and Debug.Anything Else?
Written with Claude Code; the measurements, review and testing ran on my machine.
Resident GPU texture bytes as the engine counts them after each mission load (OpenGL rows are software-rendered; VRAM is per process from nvidia-smi on the Vulkan rows). Loads are wall time from start to gameplay, single runs.
$Environment Map: cubemapmission, SM1-02, same mission