feat(video_core): implement comprehensive VRAM management system

Add automatic VRAM leak prevention with configurable garbage collection
to prevent device loss crashes during extended play sessions.

New Settings:
- vram_limit_mb: Configurable VRAM limit (0 = auto-detect 80%)
- gc_aggressiveness: Off/Light/Moderate/Heavy/Extreme levels
- texture_eviction_frames: Frames before texture eviction (default 2)
- buffer_eviction_frames: Frames before buffer eviction (default 5)
- sparse_texture_priority_eviction: Prioritize large sparse textures
- log_vram_usage: Enable VRAM statistics logging

Core Changes:
- Enhanced texture cache with LRU eviction and sparse texture priority
- Enhanced buffer cache with configurable eviction thresholds
- Added VRAM pressure monitoring using VK_EXT_memory_budget
- Emergency GC triggers at 90%/95% VRAM usage thresholds

Platform Support:
- Desktop: Settings in Graphics > Advanced tab
- Android: Settings in Zep Zone category

Fixes VRAM climbing steadily during gameplay until device loss.
Target: Stable VRAM usage below configured limit for 2+ hours.

Signed-off-by: Zephyron <zephyron@citron-emu.org>
This commit is contained in:
Zephyron
2026-01-25 15:21:02 +10:00
parent 44f9cb6347
commit 3e2137a470
16 changed files with 938 additions and 48 deletions

View File

@@ -32,7 +32,11 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {
SHOW_SHADER_BUILDING_OVERLAY("show_shader_building_overlay"),
SHOW_PERFORMANCE_GRAPH("show_performance_graph"),
USE_CONDITIONAL_RENDERING("use_conditional_rendering"),
AIRPLANE_MODE("airplane_mode");
AIRPLANE_MODE("airplane_mode"),
// VRAM Management settings (FIXED: VRAM leak prevention)
SPARSE_TEXTURE_PRIORITY_EVICTION("sparse_texture_priority_eviction"),
LOG_VRAM_USAGE("log_vram_usage");
override fun getBoolean(needsGlobal: Boolean): Boolean =
NativeConfig.getBoolean(key, needsGlobal)

View File

@@ -40,6 +40,12 @@ enum class IntSetting(override val key: String) : AbstractIntSetting {
VRAM_USAGE_MODE("vram_usage_mode"),
EXTENDED_DYNAMIC_STATE("extended_dynamic_state"),
// VRAM Management settings (FIXED: VRAM leak prevention)
VRAM_LIMIT_MB("vram_limit_mb"),
GC_AGGRESSIVENESS("gc_aggressiveness"),
TEXTURE_EVICTION_FRAMES("texture_eviction_frames"),
BUFFER_EVICTION_FRAMES("buffer_eviction_frames"),
// Applet Mode settings
CABINET_APPLET_MODE("cabinet_applet_mode"),
CONTROLLER_APPLET_MODE("controller_applet_mode"),

View File

@@ -479,6 +479,61 @@ abstract class SettingsItem(
)
)
// VRAM Management Settings (FIXED: VRAM leak prevention)
put(
SliderSetting(
IntSetting.VRAM_LIMIT_MB,
titleId = R.string.vram_limit_mb,
descriptionId = R.string.vram_limit_mb_description,
min = 0,
max = 16384,
units = " MB"
)
)
put(
SingleChoiceSetting(
IntSetting.GC_AGGRESSIVENESS,
titleId = R.string.gc_aggressiveness,
descriptionId = R.string.gc_aggressiveness_description,
choicesId = R.array.gcAggressivenessNames,
valuesId = R.array.gcAggressivenessValues
)
)
put(
SliderSetting(
IntSetting.TEXTURE_EVICTION_FRAMES,
titleId = R.string.texture_eviction_frames,
descriptionId = R.string.texture_eviction_frames_description,
min = 1,
max = 60,
units = " frames"
)
)
put(
SliderSetting(
IntSetting.BUFFER_EVICTION_FRAMES,
titleId = R.string.buffer_eviction_frames,
descriptionId = R.string.buffer_eviction_frames_description,
min = 1,
max = 120,
units = " frames"
)
)
put(
SwitchSetting(
BooleanSetting.SPARSE_TEXTURE_PRIORITY_EVICTION,
titleId = R.string.sparse_texture_priority_eviction,
descriptionId = R.string.sparse_texture_priority_eviction_description
)
)
put(
SwitchSetting(
BooleanSetting.LOG_VRAM_USAGE,
titleId = R.string.log_vram_usage,
descriptionId = R.string.log_vram_usage_description
)
)
// Applet Mode Settings
put(
SingleChoiceSetting(

View File

@@ -1036,6 +1036,15 @@ class SettingsFragmentPresenter(
add(HeaderSetting(R.string.frame_skipping_header))
add(IntSetting.FRAME_SKIPPING.key)
add(IntSetting.FRAME_SKIPPING_MODE.key)
// VRAM Management settings (FIXED: VRAM leak prevention)
add(HeaderSetting(R.string.vram_management_header))
add(IntSetting.VRAM_LIMIT_MB.key)
add(IntSetting.GC_AGGRESSIVENESS.key)
add(IntSetting.TEXTURE_EVICTION_FRAMES.key)
add(IntSetting.BUFFER_EVICTION_FRAMES.key)
add(BooleanSetting.SPARSE_TEXTURE_PRIORITY_EVICTION.key)
add(BooleanSetting.LOG_VRAM_USAGE.key)
}
}

View File

@@ -440,6 +440,23 @@
<item>3</item>
</integer-array>
<!-- VRAM Management setting arrays (FIXED: VRAM leak prevention) -->
<string-array name="gcAggressivenessNames">
<item>@string/gc_aggressiveness_off</item>
<item>@string/gc_aggressiveness_light</item>
<item>@string/gc_aggressiveness_moderate</item>
<item>@string/gc_aggressiveness_heavy</item>
<item>@string/gc_aggressiveness_extreme</item>
</string-array>
<integer-array name="gcAggressivenessValues">
<item>0</item>
<item>1</item>
<item>2</item>
<item>3</item>
<item>4</item>
</integer-array>
<!-- Applet Mode setting arrays -->
<string-array name="appletModeNames">
<item>HLE (High-Level Emulation)</item>

View File

@@ -448,6 +448,7 @@
<string name="memory_layout_header">Memory Layout</string>
<string name="astc_settings_header">ASTC Settings</string>
<string name="advanced_graphics_header">Advanced Graphics</string>
<string name="vram_management_header">VRAM Management</string>
<string name="applet_settings_header">Applet Settings</string>
<!-- Applet Mode Settings -->
@@ -1273,6 +1274,25 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
<string name="frame_skipping_enabled">Enabled</string>
<string name="frame_skipping_mode_adaptive">Adaptive</string>
<string name="frame_skipping_mode_fixed">Fixed</string>
<!-- VRAM Management settings (FIXED: VRAM leak prevention) -->
<string name="vram_limit_mb">VRAM Limit (MB)</string>
<string name="vram_limit_mb_description">Maximum VRAM usage limit in megabytes. Set to 0 for auto-detection (80%% of available VRAM). Recommended: 6144 for 8GB GPUs, 4096 for 6GB GPUs.</string>
<string name="gc_aggressiveness">GC Aggressiveness</string>
<string name="gc_aggressiveness_description">Controls how aggressively the emulator evicts unused textures and buffers from VRAM. Higher levels free memory faster but may cause more texture reloading.</string>
<string name="texture_eviction_frames">Texture Eviction Frames</string>
<string name="texture_eviction_frames_description">Number of frames a texture must be unused before it can be evicted. Lower values free VRAM faster but may cause more texture reloading.</string>
<string name="buffer_eviction_frames">Buffer Eviction Frames</string>
<string name="buffer_eviction_frames_description">Number of frames a buffer must be unused before it can be evicted. Lower values free VRAM faster but may cause more buffer reloading.</string>
<string name="sparse_texture_priority_eviction">Sparse Texture Priority Eviction</string>
<string name="sparse_texture_priority_eviction_description">Prioritize evicting large sparse textures when VRAM pressure is high. Helps prevent VRAM exhaustion in games with large texture atlases.</string>
<string name="log_vram_usage">Log VRAM Usage</string>
<string name="log_vram_usage_description">Enable logging of VRAM usage statistics for debugging purposes.</string>
<string name="gc_aggressiveness_off">Off (Not Recommended)</string>
<string name="gc_aggressiveness_light">Light</string>
<string name="gc_aggressiveness_moderate">Moderate (Recommended)</string>
<string name="gc_aggressiveness_heavy">Heavy (Low VRAM)</string>
<string name="gc_aggressiveness_extreme">Extreme (4GB VRAM)</string>
<string name="frame_skipping_header">Frame Skipping</string>
</resources>