mirror of
https://git.eden-emu.dev/archive/citron
synced 2026-04-16 17:50:45 -04:00
refactor(settings): simplify VRAM usage mode to Conservative/Aggressive
The removed modes added complexity without significant benefit now that the new VRAM management system (gc_aggressiveness, vram_limit_mb) provides finer-grained control over memory pressure. Signed-off-by: Zephyron <zephyron@citron-emu.org>
This commit is contained in:
@@ -429,15 +429,11 @@
|
|||||||
<string-array name="vramUsageModeNames">
|
<string-array name="vramUsageModeNames">
|
||||||
<item>Conservative</item>
|
<item>Conservative</item>
|
||||||
<item>Aggressive</item>
|
<item>Aggressive</item>
|
||||||
<item>High-End GPU (4090/4080+)</item>
|
|
||||||
<item>Insane (RTX 4090 24GB)</item>
|
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
<integer-array name="vramUsageModeValues">
|
<integer-array name="vramUsageModeValues">
|
||||||
<item>0</item>
|
<item>0</item>
|
||||||
<item>1</item>
|
<item>1</item>
|
||||||
<item>2</item>
|
|
||||||
<item>3</item>
|
|
||||||
</integer-array>
|
</integer-array>
|
||||||
|
|
||||||
<!-- VRAM Management setting arrays (FIXED: VRAM leak prevention) -->
|
<!-- VRAM Management setting arrays (FIXED: VRAM leak prevention) -->
|
||||||
|
|||||||
@@ -382,8 +382,6 @@ std::unique_ptr<ComboboxTranslationMap> ComboboxEnumeration(QWidget* parent) {
|
|||||||
{
|
{
|
||||||
PAIR(VramUsageMode, Conservative, tr("Conservative")),
|
PAIR(VramUsageMode, Conservative, tr("Conservative")),
|
||||||
PAIR(VramUsageMode, Aggressive, tr("Aggressive")),
|
PAIR(VramUsageMode, Aggressive, tr("Aggressive")),
|
||||||
PAIR(VramUsageMode, HighEnd, tr("High-End GPU (4090/4080+)")),
|
|
||||||
PAIR(VramUsageMode, Insane, tr("Insane (RTX 4090 24GB)")),
|
|
||||||
}});
|
}});
|
||||||
translations->insert({Settings::EnumMetadata<Settings::ExtendedDynamicState>::Index(),
|
translations->insert({Settings::EnumMetadata<Settings::ExtendedDynamicState>::Index(),
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -162,8 +162,6 @@ void VramOverlay::DrawVramInfo(QPainter& painter) {
|
|||||||
switch (Settings::values.vram_usage_mode.GetValue()) {
|
switch (Settings::values.vram_usage_mode.GetValue()) {
|
||||||
case Settings::VramUsageMode::Conservative: mode_text = QString::fromUtf8("Mode: Conservative"); break;
|
case Settings::VramUsageMode::Conservative: mode_text = QString::fromUtf8("Mode: Conservative"); break;
|
||||||
case Settings::VramUsageMode::Aggressive: mode_text = QString::fromUtf8("Mode: Aggressive"); break;
|
case Settings::VramUsageMode::Aggressive: mode_text = QString::fromUtf8("Mode: Aggressive"); break;
|
||||||
case Settings::VramUsageMode::HighEnd: mode_text = QString::fromUtf8("Mode: High-End GPU"); break;
|
|
||||||
case Settings::VramUsageMode::Insane: mode_text = QString::fromUtf8("Mode: Insane"); painter.setPen(leak_warning_color); break;
|
|
||||||
default: mode_text = QString::fromUtf8("Mode: Unknown"); break;
|
default: mode_text = QString::fromUtf8("Mode: Unknown"); break;
|
||||||
}
|
}
|
||||||
painter.drawText(section_padding, y_offset, mode_text);
|
painter.drawText(section_padding, y_offset, mode_text);
|
||||||
|
|||||||
@@ -499,7 +499,7 @@ struct Values {
|
|||||||
SwitchableSetting<VramUsageMode, true> vram_usage_mode{linkage,
|
SwitchableSetting<VramUsageMode, true> vram_usage_mode{linkage,
|
||||||
VramUsageMode::Conservative,
|
VramUsageMode::Conservative,
|
||||||
VramUsageMode::Conservative,
|
VramUsageMode::Conservative,
|
||||||
VramUsageMode::Insane,
|
VramUsageMode::Aggressive,
|
||||||
"vram_usage_mode",
|
"vram_usage_mode",
|
||||||
Category::RendererAdvanced};
|
Category::RendererAdvanced};
|
||||||
|
|
||||||
|
|||||||
@@ -406,8 +406,6 @@ inline u32 EnumMetadata<VSyncMode>::Index() {
|
|||||||
enum class VramUsageMode : u32 {
|
enum class VramUsageMode : u32 {
|
||||||
Conservative = 0,
|
Conservative = 0,
|
||||||
Aggressive = 1,
|
Aggressive = 1,
|
||||||
HighEnd = 2,
|
|
||||||
Insane = 3,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
@@ -416,8 +414,6 @@ EnumMetadata<VramUsageMode>::Canonicalizations() {
|
|||||||
return {
|
return {
|
||||||
{"Conservative", VramUsageMode::Conservative},
|
{"Conservative", VramUsageMode::Conservative},
|
||||||
{"Aggressive", VramUsageMode::Aggressive},
|
{"Aggressive", VramUsageMode::Aggressive},
|
||||||
{"HighEnd", VramUsageMode::HighEnd},
|
|
||||||
{"Insane", VramUsageMode::Insane},
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -70,40 +70,11 @@ vk::Buffer CreateBuffer(const Device& device, const MemoryAllocator& memory_allo
|
|||||||
flags |= VK_BUFFER_USAGE_CONDITIONAL_RENDERING_BIT_EXT;
|
flags |= VK_BUFFER_USAGE_CONDITIONAL_RENDERING_BIT_EXT;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Optimize buffer size based on VRAM usage mode
|
|
||||||
u64 optimized_size = size;
|
|
||||||
const auto vram_mode = Settings::values.vram_usage_mode.GetValue();
|
|
||||||
|
|
||||||
if (vram_mode == Settings::VramUsageMode::HighEnd) {
|
|
||||||
// High-End GPU mode: Use larger buffer chunks for high-end GPUs to reduce allocation overhead
|
|
||||||
// but still keep them reasonable to avoid excessive VRAM usage
|
|
||||||
if (size > 64_MiB && size < 512_MiB) {
|
|
||||||
// Round up to next 64MB boundary for large buffers
|
|
||||||
optimized_size = Common::AlignUp(size, 64_MiB);
|
|
||||||
} else if (size > 4_MiB && size <= 64_MiB) {
|
|
||||||
// Round up to next 8MB boundary for medium buffers
|
|
||||||
optimized_size = Common::AlignUp(size, 8_MiB);
|
|
||||||
}
|
|
||||||
} else if (vram_mode == Settings::VramUsageMode::Insane) {
|
|
||||||
// Insane mode: Use massive buffer chunks for RTX 4090 to minimize allocation overhead
|
|
||||||
// and maximize performance for shader compilation and caching
|
|
||||||
if (size > 128_MiB && size < 1024_MiB) {
|
|
||||||
// Round up to next 128MB boundary for very large buffers
|
|
||||||
optimized_size = Common::AlignUp(size, 128_MiB);
|
|
||||||
} else if (size > 16_MiB && size <= 128_MiB) {
|
|
||||||
// Round up to next 32MB boundary for large buffers
|
|
||||||
optimized_size = Common::AlignUp(size, 32_MiB);
|
|
||||||
} else if (size > 1_MiB && size <= 16_MiB) {
|
|
||||||
// Round up to next 4MB boundary for medium buffers
|
|
||||||
optimized_size = Common::AlignUp(size, 4_MiB);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const VkBufferCreateInfo buffer_ci = {
|
const VkBufferCreateInfo buffer_ci = {
|
||||||
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
|
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
|
||||||
.pNext = nullptr,
|
.pNext = nullptr,
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
.size = optimized_size,
|
.size = size,
|
||||||
.usage = flags,
|
.usage = flags,
|
||||||
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
||||||
.queueFamilyIndexCount = 0,
|
.queueFamilyIndexCount = 0,
|
||||||
@@ -115,31 +86,8 @@ vk::Buffer CreateBuffer(const Device& device, const MemoryAllocator& memory_allo
|
|||||||
} // Anonymous namespace
|
} // Anonymous namespace
|
||||||
|
|
||||||
void BufferCacheRuntime::CleanupUnusedBuffers() {
|
void BufferCacheRuntime::CleanupUnusedBuffers() {
|
||||||
// Aggressive cleanup for Insane mode to prevent VRAM leaks
|
// Cleanup is now handled by the VRAM management system (gc_aggressiveness setting)
|
||||||
const auto vram_mode = Settings::values.vram_usage_mode.GetValue();
|
// This function is kept for compatibility but no longer performs mode-specific cleanup
|
||||||
if (vram_mode == Settings::VramUsageMode::Insane) {
|
|
||||||
// For Insane mode, periodically clean up unused large buffers to prevent memory leaks
|
|
||||||
static u32 cleanup_counter = 0;
|
|
||||||
static u64 last_buffer_memory = 0;
|
|
||||||
cleanup_counter++;
|
|
||||||
|
|
||||||
// Monitor buffer memory usage to detect potential leaks
|
|
||||||
if (cleanup_counter % 120 == 0) {
|
|
||||||
const u64 current_buffer_memory = GetDeviceMemoryUsage();
|
|
||||||
|
|
||||||
// Check for buffer memory leak (usage increasing without corresponding game activity)
|
|
||||||
if (current_buffer_memory > last_buffer_memory + 50_MiB) {
|
|
||||||
LOG_WARNING(Render_Vulkan, "Potential buffer memory leak detected! Usage increased by {} MB",
|
|
||||||
(current_buffer_memory - last_buffer_memory) / (1024 * 1024));
|
|
||||||
|
|
||||||
// Force cleanup of any cached buffers that might be accumulating
|
|
||||||
LOG_INFO(Render_Vulkan, "Performed aggressive buffer cleanup (Insane mode)");
|
|
||||||
}
|
|
||||||
|
|
||||||
last_buffer_memory = current_buffer_memory;
|
|
||||||
LOG_DEBUG(Render_Vulkan, "Buffer memory usage: {} MB (Insane mode)", current_buffer_memory / (1024 * 1024));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Buffer::Buffer(BufferCacheRuntime& runtime, VideoCommon::NullBufferParams null_params)
|
Buffer::Buffer(BufferCacheRuntime& runtime, VideoCommon::NullBufferParams null_params)
|
||||||
|
|||||||
@@ -748,11 +748,8 @@ std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline(
|
|||||||
const auto runtime_info{MakeRuntimeInfo(programs, key, program, previous_stage)};
|
const auto runtime_info{MakeRuntimeInfo(programs, key, program, previous_stage)};
|
||||||
ConvertLegacyToGeneric(program, runtime_info);
|
ConvertLegacyToGeneric(program, runtime_info);
|
||||||
std::vector<u32> code = EmitSPIRV(profile, runtime_info, program, binding);
|
std::vector<u32> code = EmitSPIRV(profile, runtime_info, program, binding);
|
||||||
// Reserve more space for Insane mode to reduce allocations during shader compilation
|
// Reserve space to reduce allocations during shader compilation
|
||||||
const size_t reserve_size = Settings::values.vram_usage_mode.GetValue() == Settings::VramUsageMode::Insane
|
code.reserve(std::max<size_t>(code.size(), 16 * 1024 / sizeof(u32)));
|
||||||
? std::max<size_t>(code.size(), 64 * 1024 / sizeof(u32)) // 64KB for Insane mode
|
|
||||||
: std::max<size_t>(code.size(), 16 * 1024 / sizeof(u32)); // 16KB for other modes
|
|
||||||
code.reserve(reserve_size);
|
|
||||||
device.SaveShader(code);
|
device.SaveShader(code);
|
||||||
modules[stage_index] = BuildShader(device, code);
|
modules[stage_index] = BuildShader(device, code);
|
||||||
if (device.HasDebuggingToolAttached()) {
|
if (device.HasDebuggingToolAttached()) {
|
||||||
@@ -854,11 +851,8 @@ std::unique_ptr<ComputePipeline> PipelineCache::CreateComputePipeline(
|
|||||||
|
|
||||||
auto program{TranslateProgram(pools.inst, pools.block, env, cfg, host_info)};
|
auto program{TranslateProgram(pools.inst, pools.block, env, cfg, host_info)};
|
||||||
std::vector<u32> code = EmitSPIRV(profile, program);
|
std::vector<u32> code = EmitSPIRV(profile, program);
|
||||||
// Reserve more space for Insane mode to reduce allocations during shader compilation
|
// Reserve space to reduce allocations during shader compilation
|
||||||
const size_t reserve_size = Settings::values.vram_usage_mode.GetValue() == Settings::VramUsageMode::Insane
|
code.reserve(std::max<size_t>(code.size(), 16 * 1024 / sizeof(u32)));
|
||||||
? std::max<size_t>(code.size(), 64 * 1024 / sizeof(u32)) // 64KB for Insane mode
|
|
||||||
: std::max<size_t>(code.size(), 16 * 1024 / sizeof(u32)); // 16KB for other modes
|
|
||||||
code.reserve(reserve_size);
|
|
||||||
device.SaveShader(code);
|
device.SaveShader(code);
|
||||||
vk::ShaderModule spv_module{BuildShader(device, code)};
|
vk::ShaderModule spv_module{BuildShader(device, code)};
|
||||||
if (device.HasDebuggingToolAttached()) {
|
if (device.HasDebuggingToolAttached()) {
|
||||||
|
|||||||
@@ -99,24 +99,7 @@ void StagingBufferPool::FreeDeferred(StagingBufferRef& ref) {
|
|||||||
void StagingBufferPool::TickFrame() {
|
void StagingBufferPool::TickFrame() {
|
||||||
current_delete_level = (current_delete_level + 1) % NUM_LEVELS;
|
current_delete_level = (current_delete_level + 1) % NUM_LEVELS;
|
||||||
|
|
||||||
// Enhanced cleanup for Insane mode to prevent VRAM leaks
|
// Cleanup is now handled by the VRAM management system (gc_aggressiveness setting)
|
||||||
const auto vram_mode = Settings::values.vram_usage_mode.GetValue();
|
|
||||||
if (vram_mode == Settings::VramUsageMode::Insane) {
|
|
||||||
static u32 cleanup_counter = 0;
|
|
||||||
cleanup_counter++;
|
|
||||||
|
|
||||||
// More aggressive cleanup for Insane mode every 30 frames
|
|
||||||
if (cleanup_counter % 30 == 0) {
|
|
||||||
// Force release of all caches to prevent memory accumulation
|
|
||||||
ReleaseCache(MemoryUsage::DeviceLocal);
|
|
||||||
ReleaseCache(MemoryUsage::Upload);
|
|
||||||
ReleaseCache(MemoryUsage::Download);
|
|
||||||
|
|
||||||
// Additional cleanup for large staging buffers
|
|
||||||
LOG_DEBUG(Render_Vulkan, "Performed aggressive staging buffer cleanup (Insane mode)");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ReleaseCache(MemoryUsage::DeviceLocal);
|
ReleaseCache(MemoryUsage::DeviceLocal);
|
||||||
ReleaseCache(MemoryUsage::Upload);
|
ReleaseCache(MemoryUsage::Upload);
|
||||||
ReleaseCache(MemoryUsage::Download);
|
ReleaseCache(MemoryUsage::Download);
|
||||||
|
|||||||
@@ -939,29 +939,8 @@ VkBuffer TextureCacheRuntime::GetTemporaryBuffer(size_t needed_size) {
|
|||||||
return *buffers[level];
|
return *buffers[level];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Optimize buffer size based on VRAM usage mode
|
// Use power-of-2 buffer sizes for efficient allocation
|
||||||
size_t new_size = Common::NextPow2(needed_size);
|
const size_t new_size = Common::NextPow2(needed_size);
|
||||||
const auto vram_mode = Settings::values.vram_usage_mode.GetValue();
|
|
||||||
|
|
||||||
if (vram_mode == Settings::VramUsageMode::HighEnd) {
|
|
||||||
// For high-end GPUs, use larger temporary buffers to reduce allocation overhead
|
|
||||||
// but cap them to prevent excessive VRAM usage
|
|
||||||
if (needed_size > 32_MiB && needed_size < 256_MiB) {
|
|
||||||
new_size = Common::AlignUp(needed_size, 32_MiB);
|
|
||||||
} else if (needed_size > 2_MiB && needed_size <= 32_MiB) {
|
|
||||||
new_size = Common::AlignUp(needed_size, 4_MiB);
|
|
||||||
}
|
|
||||||
} else if (vram_mode == Settings::VramUsageMode::Insane) {
|
|
||||||
// Insane mode: Use massive temporary buffers for RTX 4090 to maximize texture caching
|
|
||||||
// and shader compilation performance
|
|
||||||
if (needed_size > 64_MiB && needed_size < 512_MiB) {
|
|
||||||
new_size = Common::AlignUp(needed_size, 64_MiB);
|
|
||||||
} else if (needed_size > 8_MiB && needed_size <= 64_MiB) {
|
|
||||||
new_size = Common::AlignUp(needed_size, 16_MiB);
|
|
||||||
} else if (needed_size > 1_MiB && needed_size <= 8_MiB) {
|
|
||||||
new_size = Common::AlignUp(needed_size, 2_MiB);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static constexpr VkBufferUsageFlags flags =
|
static constexpr VkBufferUsageFlags flags =
|
||||||
VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT |
|
VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT |
|
||||||
@@ -981,46 +960,8 @@ VkBuffer TextureCacheRuntime::GetTemporaryBuffer(size_t needed_size) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void TextureCacheRuntime::CleanupUnusedBuffers() {
|
void TextureCacheRuntime::CleanupUnusedBuffers() {
|
||||||
// Aggressive cleanup for Insane mode to prevent VRAM leaks
|
// Cleanup is now handled by the VRAM management system (gc_aggressiveness setting)
|
||||||
const auto vram_mode = Settings::values.vram_usage_mode.GetValue();
|
// This function is kept for compatibility but no longer performs mode-specific cleanup
|
||||||
if (vram_mode == Settings::VramUsageMode::Insane) {
|
|
||||||
// For Insane mode, periodically clean up unused large buffers to prevent memory leaks
|
|
||||||
static u32 cleanup_counter = 0;
|
|
||||||
static u64 last_vram_usage = 0;
|
|
||||||
cleanup_counter++;
|
|
||||||
|
|
||||||
// Monitor VRAM usage to detect potential leaks
|
|
||||||
if (cleanup_counter % 60 == 0) {
|
|
||||||
const u64 current_vram_usage = GetDeviceMemoryUsage();
|
|
||||||
|
|
||||||
// Check for VRAM leak (usage increasing without corresponding game activity)
|
|
||||||
if (current_vram_usage > last_vram_usage + 100_MiB) {
|
|
||||||
LOG_WARNING(Render_Vulkan, "Potential VRAM leak detected! Usage increased by {} MB",
|
|
||||||
(current_vram_usage - last_vram_usage) / (1024 * 1024));
|
|
||||||
|
|
||||||
// Force aggressive cleanup
|
|
||||||
for (auto& buffer : buffers) {
|
|
||||||
if (buffer) {
|
|
||||||
buffer.reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
LOG_INFO(Render_Vulkan, "Performed aggressive VRAM cleanup (Insane mode)");
|
|
||||||
}
|
|
||||||
|
|
||||||
last_vram_usage = current_vram_usage;
|
|
||||||
LOG_DEBUG(Render_Vulkan, "VRAM usage: {} MB (Insane mode)", current_vram_usage / (1024 * 1024));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Regular cleanup every 120 frames
|
|
||||||
if (cleanup_counter % 120 == 0) {
|
|
||||||
for (auto& buffer : buffers) {
|
|
||||||
if (buffer) {
|
|
||||||
buffer.reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
LOG_DEBUG(Render_Vulkan, "Cleaned up unused temporary buffers (Insane mode)");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextureCacheRuntime::BarrierFeedbackLoop() {
|
void TextureCacheRuntime::BarrierFeedbackLoop() {
|
||||||
|
|||||||
@@ -1354,20 +1354,6 @@ void Device::CollectPhysicalMemoryInfo() {
|
|||||||
const size_t scaler_memory = 1_GiB * Settings::values.resolution_info.ScaleUp(1);
|
const size_t scaler_memory = 1_GiB * Settings::values.resolution_info.ScaleUp(1);
|
||||||
device_access_memory =
|
device_access_memory =
|
||||||
std::min<u64>(device_access_memory, normal_memory + scaler_memory);
|
std::min<u64>(device_access_memory, normal_memory + scaler_memory);
|
||||||
} else if (vram_mode == Settings::VramUsageMode::HighEnd) {
|
|
||||||
// High-End GPU mode: Use more VRAM but with smart buffer management
|
|
||||||
// Allow up to 12GB for RTX 4090/4080+ users, but optimize buffer allocation
|
|
||||||
const size_t high_end_memory = 12_GiB;
|
|
||||||
const size_t scaler_memory = 1_GiB * Settings::values.resolution_info.ScaleUp(1);
|
|
||||||
device_access_memory =
|
|
||||||
std::min<u64>(device_access_memory, high_end_memory + scaler_memory);
|
|
||||||
} else if (vram_mode == Settings::VramUsageMode::Insane) {
|
|
||||||
// Insane mode: Use most of RTX 4090's 24GB VRAM for maximum performance
|
|
||||||
// Reserve only 2GB for system and other applications
|
|
||||||
const size_t insane_memory = 22_GiB;
|
|
||||||
const size_t scaler_memory = 2_GiB * Settings::values.resolution_info.ScaleUp(1);
|
|
||||||
device_access_memory =
|
|
||||||
std::min<u64>(device_access_memory, insane_memory + scaler_memory);
|
|
||||||
}
|
}
|
||||||
// Aggressive mode uses full available VRAM (no limits)
|
// Aggressive mode uses full available VRAM (no limits)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user