mirror of
https://git.citron-emu.org/citron/emulator
synced 2025-12-19 18:53:32 +00:00
feat: add High-End and Insane VRAM modes with leak prevention
- Add HighEnd and Insane VRAM usage modes for RTX 4090/4080+ users - Implement VRAM limits: HighEnd (12GB), Insane (22GB) with scaling - Optimize buffer allocation with larger chunks for high-end GPUs - Add VRAM leak detection and aggressive cleanup for Insane mode - Increase shader compilation buffer sizes for better performance - Add VRAM monitoring functions to Vulkan rasterizer - Implement memory usage tracking for staging buffers Signed-off-by: Zephyron <zephyron@citron-emu.org>
This commit is contained in:
@@ -401,11 +401,15 @@
|
||||
<string-array name="vramUsageModeNames">
|
||||
<item>Conservative</item>
|
||||
<item>Aggressive</item>
|
||||
<item>High-End GPU (4090/4080+)</item>
|
||||
<item>Insane (RTX 4090 24GB)</item>
|
||||
</string-array>
|
||||
|
||||
<integer-array name="vramUsageModeValues">
|
||||
<item>0</item>
|
||||
<item>1</item>
|
||||
<item>2</item>
|
||||
<item>3</item>
|
||||
</integer-array>
|
||||
|
||||
<!-- Applet Mode setting arrays -->
|
||||
|
||||
@@ -332,6 +332,8 @@ std::unique_ptr<ComboboxTranslationMap> ComboboxEnumeration(QWidget* parent) {
|
||||
{
|
||||
PAIR(VramUsageMode, Conservative, tr("Conservative")),
|
||||
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::RendererBackend>::Index(),
|
||||
{
|
||||
|
||||
@@ -420,7 +420,7 @@ struct Values {
|
||||
SwitchableSetting<VramUsageMode, true> vram_usage_mode{linkage,
|
||||
VramUsageMode::Conservative,
|
||||
VramUsageMode::Conservative,
|
||||
VramUsageMode::Aggressive,
|
||||
VramUsageMode::HighEnd,
|
||||
"vram_usage_mode",
|
||||
Category::RendererAdvanced};
|
||||
SwitchableSetting<bool> async_presentation{linkage,
|
||||
|
||||
@@ -124,7 +124,7 @@ ENUM(AstcRecompression, Uncompressed, Bc1, Bc3);
|
||||
|
||||
ENUM(VSyncMode, Immediate, Mailbox, Fifo, FifoRelaxed);
|
||||
|
||||
ENUM(VramUsageMode, Conservative, Aggressive);
|
||||
ENUM(VramUsageMode, Conservative, Aggressive, HighEnd, Insane);
|
||||
|
||||
ENUM(RendererBackend, OpenGL, Vulkan, Null);
|
||||
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
#include <span>
|
||||
#include <vector>
|
||||
|
||||
#include "common/alignment.h"
|
||||
#include "common/literals.h"
|
||||
#include "common/common_types.h"
|
||||
#include "video_core/renderer_vulkan/vk_buffer_cache.h"
|
||||
|
||||
#include "video_core/renderer_vulkan/maxwell_to_vk.h"
|
||||
@@ -17,6 +20,8 @@
|
||||
#include "video_core/vulkan_common/vulkan_memory_allocator.h"
|
||||
#include "video_core/vulkan_common/vulkan_wrapper.h"
|
||||
|
||||
using namespace Common::Literals;
|
||||
|
||||
namespace Vulkan {
|
||||
namespace {
|
||||
VkBufferCopy MakeBufferCopy(const VideoCommon::BufferCopy& copy) {
|
||||
@@ -64,11 +69,41 @@ vk::Buffer CreateBuffer(const Device& device, const MemoryAllocator& memory_allo
|
||||
if (device.IsExtConditionalRendering()) {
|
||||
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 = {
|
||||
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
|
||||
.pNext = nullptr,
|
||||
.flags = 0,
|
||||
.size = size,
|
||||
.size = optimized_size,
|
||||
.usage = flags,
|
||||
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
||||
.queueFamilyIndexCount = 0,
|
||||
@@ -76,8 +111,37 @@ vk::Buffer CreateBuffer(const Device& device, const MemoryAllocator& memory_allo
|
||||
};
|
||||
return memory_allocator.CreateBuffer(buffer_ci, MemoryUsage::DeviceLocal);
|
||||
}
|
||||
|
||||
} // Anonymous namespace
|
||||
|
||||
void BufferCacheRuntime::CleanupUnusedBuffers() {
|
||||
// Aggressive cleanup for Insane mode to prevent VRAM leaks
|
||||
const auto vram_mode = Settings::values.vram_usage_mode.GetValue();
|
||||
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)
|
||||
: VideoCommon::BufferBase(null_params), tracker{4096} {
|
||||
if (runtime.device.HasNullDescriptor()) {
|
||||
|
||||
@@ -89,6 +89,8 @@ public:
|
||||
|
||||
u64 GetDeviceMemoryUsage() const;
|
||||
|
||||
void CleanupUnusedBuffers();
|
||||
|
||||
bool CanReportMemoryUsage() const;
|
||||
|
||||
u32 GetStorageBufferAlignment() const;
|
||||
|
||||
@@ -678,7 +678,11 @@ std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline(
|
||||
const auto runtime_info{MakeRuntimeInfo(programs, key, program, previous_stage)};
|
||||
ConvertLegacyToGeneric(program, runtime_info);
|
||||
std::vector<u32> code = EmitSPIRV(profile, runtime_info, program, binding);
|
||||
code.reserve(std::max<size_t>(code.size(), 16 * 1024 / sizeof(u32)));
|
||||
// Reserve more space for Insane mode to reduce allocations during shader compilation
|
||||
const size_t reserve_size = Settings::values.vram_usage_mode.GetValue() == Settings::VramUsageMode::Insane
|
||||
? 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);
|
||||
modules[stage_index] = BuildShader(device, code);
|
||||
if (device.HasDebuggingToolAttached()) {
|
||||
@@ -773,7 +777,11 @@ std::unique_ptr<ComputePipeline> PipelineCache::CreateComputePipeline(
|
||||
|
||||
auto program{TranslateProgram(pools.inst, pools.block, env, cfg, host_info)};
|
||||
std::vector<u32> code = EmitSPIRV(profile, program);
|
||||
code.reserve(std::max<size_t>(code.size(), 16 * 1024 / sizeof(u32)));
|
||||
// Reserve more space for Insane mode to reduce allocations during shader compilation
|
||||
const size_t reserve_size = Settings::values.vram_usage_mode.GetValue() == Settings::VramUsageMode::Insane
|
||||
? 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);
|
||||
vk::ShaderModule spv_module{BuildShader(device, code)};
|
||||
if (device.HasDebuggingToolAttached()) {
|
||||
|
||||
@@ -769,10 +769,59 @@ void RasterizerVulkan::TickFrame() {
|
||||
{
|
||||
std::scoped_lock lock{texture_cache.mutex};
|
||||
texture_cache.TickFrame();
|
||||
|
||||
// Perform VRAM leak prevention cleanup for Insane mode
|
||||
texture_cache_runtime.CleanupUnusedBuffers();
|
||||
}
|
||||
{
|
||||
std::scoped_lock lock{buffer_cache.mutex};
|
||||
buffer_cache.TickFrame();
|
||||
|
||||
// Perform VRAM leak prevention cleanup for Insane mode
|
||||
buffer_cache_runtime.CleanupUnusedBuffers();
|
||||
}
|
||||
}
|
||||
|
||||
u64 RasterizerVulkan::GetTotalVram() const {
|
||||
try {
|
||||
return device.GetDeviceMemoryUsage();
|
||||
} catch (...) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
u64 RasterizerVulkan::GetUsedVram() const {
|
||||
try {
|
||||
u64 buffer_usage = buffer_cache_runtime.GetDeviceMemoryUsage();
|
||||
u64 texture_usage = texture_cache_runtime.GetDeviceMemoryUsage();
|
||||
u64 staging_usage = staging_pool.GetMemoryUsage();
|
||||
return buffer_usage + texture_usage + staging_usage;
|
||||
} catch (...) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
u64 RasterizerVulkan::GetBufferMemoryUsage() const {
|
||||
try {
|
||||
return buffer_cache_runtime.GetDeviceMemoryUsage();
|
||||
} catch (...) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
u64 RasterizerVulkan::GetTextureMemoryUsage() const {
|
||||
try {
|
||||
return texture_cache_runtime.GetDeviceMemoryUsage();
|
||||
} catch (...) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
u64 RasterizerVulkan::GetStagingMemoryUsage() const {
|
||||
try {
|
||||
return staging_pool.GetMemoryUsage();
|
||||
} catch (...) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -118,6 +118,13 @@ public:
|
||||
void TiledCacheBarrier() override;
|
||||
void FlushCommands() override;
|
||||
void TickFrame() override;
|
||||
|
||||
// VRAM monitoring functions
|
||||
u64 GetTotalVram() const;
|
||||
u64 GetUsedVram() const;
|
||||
u64 GetBufferMemoryUsage() const;
|
||||
u64 GetTextureMemoryUsage() const;
|
||||
u64 GetStagingMemoryUsage() const;
|
||||
bool AccelerateConditionalRendering() override;
|
||||
bool AccelerateSurfaceCopy(const Tegra::Engines::Fermi2D::Surface& src,
|
||||
const Tegra::Engines::Fermi2D::Surface& dst,
|
||||
|
||||
@@ -97,9 +97,66 @@ void StagingBufferPool::FreeDeferred(StagingBufferRef& ref) {
|
||||
void StagingBufferPool::TickFrame() {
|
||||
current_delete_level = (current_delete_level + 1) % NUM_LEVELS;
|
||||
|
||||
// Enhanced cleanup for Insane mode to prevent VRAM leaks
|
||||
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::Upload);
|
||||
ReleaseCache(MemoryUsage::Download);
|
||||
}
|
||||
|
||||
u64 StagingBufferPool::GetMemoryUsage() const {
|
||||
u64 total_usage = stream_buffer_size;
|
||||
|
||||
// Add usage from all staging buffer caches
|
||||
const auto& device_local_entries = device_local_cache;
|
||||
const auto& upload_entries = upload_cache;
|
||||
const auto& download_entries = download_cache;
|
||||
|
||||
for (const auto& level_entries : device_local_entries) {
|
||||
for (const auto& entry : level_entries.entries) {
|
||||
if (entry.buffer) {
|
||||
// Estimate buffer size from log2 level
|
||||
u64 buffer_size = 1ULL << entry.log2_level;
|
||||
total_usage += buffer_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& level_entries : upload_entries) {
|
||||
for (const auto& entry : level_entries.entries) {
|
||||
if (entry.buffer) {
|
||||
u64 buffer_size = 1ULL << entry.log2_level;
|
||||
total_usage += buffer_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& level_entries : download_entries) {
|
||||
for (const auto& entry : level_entries.entries) {
|
||||
if (entry.buffer) {
|
||||
u64 buffer_size = 1ULL << entry.log2_level;
|
||||
total_usage += buffer_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return total_usage;
|
||||
}
|
||||
|
||||
StagingBufferRef StagingBufferPool::GetStreamBuffer(size_t size) {
|
||||
|
||||
@@ -42,6 +42,8 @@ public:
|
||||
|
||||
void TickFrame();
|
||||
|
||||
u64 GetMemoryUsage() const;
|
||||
|
||||
private:
|
||||
struct StreamBufferCommit {
|
||||
size_t upper_bound;
|
||||
|
||||
@@ -7,8 +7,11 @@
|
||||
#include <vector>
|
||||
#include <boost/container/small_vector.hpp>
|
||||
|
||||
#include "common/alignment.h"
|
||||
#include "common/bit_cast.h"
|
||||
#include "common/bit_util.h"
|
||||
#include "common/literals.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/settings.h"
|
||||
|
||||
#include "video_core/renderer_vulkan/vk_texture_cache.h"
|
||||
@@ -27,6 +30,8 @@
|
||||
#include "video_core/vulkan_common/vulkan_memory_allocator.h"
|
||||
#include "video_core/vulkan_common/vulkan_wrapper.h"
|
||||
|
||||
using namespace Common::Literals;
|
||||
|
||||
namespace Vulkan {
|
||||
|
||||
using Tegra::Engines::Fermi2D;
|
||||
@@ -927,7 +932,31 @@ VkBuffer TextureCacheRuntime::GetTemporaryBuffer(size_t needed_size) {
|
||||
if (buffers[level]) {
|
||||
return *buffers[level];
|
||||
}
|
||||
const auto new_size = Common::NextPow2(needed_size);
|
||||
|
||||
// Optimize buffer size based on VRAM usage mode
|
||||
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 =
|
||||
VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT |
|
||||
VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT;
|
||||
@@ -945,6 +974,49 @@ VkBuffer TextureCacheRuntime::GetTemporaryBuffer(size_t needed_size) {
|
||||
return *buffers[level];
|
||||
}
|
||||
|
||||
void TextureCacheRuntime::CleanupUnusedBuffers() {
|
||||
// Aggressive cleanup for Insane mode to prevent VRAM leaks
|
||||
const auto vram_mode = Settings::values.vram_usage_mode.GetValue();
|
||||
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() {
|
||||
scheduler.RequestOutsideRenderPassOperationContext();
|
||||
}
|
||||
|
||||
@@ -105,6 +105,7 @@ public:
|
||||
}
|
||||
|
||||
[[nodiscard]] VkBuffer GetTemporaryBuffer(size_t needed_size);
|
||||
void CleanupUnusedBuffers();
|
||||
|
||||
std::span<const VkFormat> ViewFormats(PixelFormat format) {
|
||||
return view_formats[static_cast<std::size_t>(format)];
|
||||
|
||||
@@ -1336,13 +1336,29 @@ void Device::CollectPhysicalMemoryInfo() {
|
||||
const u64 reserve_memory = std::min<u64>(device_access_memory / 8, 1_GiB);
|
||||
device_access_memory -= reserve_memory;
|
||||
|
||||
if (Settings::values.vram_usage_mode.GetValue() != Settings::VramUsageMode::Aggressive) {
|
||||
// Account for resolution scaling in memory limits
|
||||
const auto vram_mode = Settings::values.vram_usage_mode.GetValue();
|
||||
if (vram_mode == Settings::VramUsageMode::Conservative) {
|
||||
// Conservative mode: Limit to 6GB + scaling memory
|
||||
const size_t normal_memory = 6_GiB;
|
||||
const size_t scaler_memory = 1_GiB * Settings::values.resolution_info.ScaleUp(1);
|
||||
device_access_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)
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user