From de1cbf6edc6bbc2c93100aa215b081e27bdcb7df Mon Sep 17 00:00:00 2001 From: Martin Felke Date: Sun, 4 Jun 2023 17:35:47 +0200 Subject: [PATCH] Configurable RAM to VRAM percentage setting for integrated devices This shall allow to specify a certain percentage of RAM to use as VRAM on integrated / shared devices. Ideally this can help tuning the garbage collector to prevent out of memory crashes. On the other hand a too aggressive memory limitation may indeed affect rendering negatively I did experience this on the steam deck for example. Graphical glitches may be caused in low memory situations. --- src/common/settings.cpp | 24 +++++++++++++++++ src/common/settings.h | 3 +++ .../renderer_opengl/gl_buffer_cache.cpp | 2 +- src/video_core/renderer_opengl/gl_device.cpp | 16 +++++++++++- .../renderer_opengl/gl_texture_cache.cpp | 2 +- .../vulkan_common/vulkan_device.cpp | 3 ++- .../configure_graphics_advanced.cpp | 15 +++++++++++ .../configure_graphics_advanced.h | 1 + .../configure_graphics_advanced.ui | 26 +++++++++++++++++++ 9 files changed, 88 insertions(+), 4 deletions(-) diff --git a/src/common/settings.cpp b/src/common/settings.cpp index ff53e80bb4..c97784f17d 100644 --- a/src/common/settings.cpp +++ b/src/common/settings.cpp @@ -7,6 +7,7 @@ #include "common/fs/path_util.h" #include "common/logging/log.h" #include "common/settings.h" +#include "common/memory_detect.h" namespace Settings { @@ -67,6 +68,8 @@ void LogSettings() { log_setting("Renderer_ShaderBackend", values.shader_backend.GetValue()); log_setting("Renderer_UseAsynchronousShaders", values.use_asynchronous_shaders.GetValue()); log_setting("Renderer_AnisotropicFilteringLevel", values.max_anisotropy.GetValue()); + log_setting("Renderer_UseVRAMPercentage", values.use_vram_percentage.GetValue()); + log_setting("Renderer_VRAMPercentage", values.vram_percentage.GetValue()); log_setting("Audio_OutputEngine", values.sink_id.GetValue()); log_setting("Audio_OutputDevice", values.audio_output_device_id.GetValue()); log_setting("Audio_InputDevice", values.audio_input_device_id.GetValue()); @@ -235,6 +238,8 @@ void RestoreGlobalState(bool is_powered_on) { values.bg_green.SetGlobal(true); values.bg_blue.SetGlobal(true); values.enable_compute_pipelines.SetGlobal(true); + values.use_vram_percentage(true); + values.vram_percentage(25); // System values.language_index.SetGlobal(true); @@ -250,4 +255,23 @@ void RestoreGlobalState(bool is_powered_on) { values.motion_enabled.SetGlobal(true); } +// this function only makes sense with integrated devices + +u64 RAM_Percent_to_Byte(u8 percent) { + // total RAM in byte + u64 total_ram = Common::GetMemInfo().TotalPhysicalMemory; + + // clamp percentage between 10 and 90, so we dont run out of either RAM or VRAM + if (percent < 10) { + percent = 10; + } + + if (percent > 90) { + percent = 90; + } + + // percentage of total RAM in byte + return (total_ram * percent) / 100; +} + } // namespace Settings diff --git a/src/common/settings.h b/src/common/settings.h index 7f865b2a75..41a21871c4 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -487,6 +487,9 @@ struct Values { SwitchableSetting bg_green{0, "bg_green"}; SwitchableSetting bg_blue{0, "bg_blue"}; + SwitchableSetting use_vram_percentage{true, "use_vram_percentage"}; + SwitchableSetting vram_percentage{25, 10, 90, "vram_percentage"}; + // System SwitchableSetting> rng_seed{std::optional(), "rng_seed"}; Setting device_name{"Yuzu", "device_name"}; diff --git a/src/video_core/renderer_opengl/gl_buffer_cache.cpp b/src/video_core/renderer_opengl/gl_buffer_cache.cpp index 6d3bda1926..fa3c1aaa47 100644 --- a/src/video_core/renderer_opengl/gl_buffer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_buffer_cache.cpp @@ -134,7 +134,7 @@ BufferCacheRuntime::BufferCacheRuntime(const Device& device_) device_access_memory = [this]() -> u64 { if (device.CanReportMemoryUsage()) { - return device.GetCurrentDedicatedVideoMemory() + 512_MiB; + return device.GetTotalDedicatedVideoMemory(); } return 2_GiB; // Return minimum requirements }(); diff --git a/src/video_core/renderer_opengl/gl_device.cpp b/src/video_core/renderer_opengl/gl_device.cpp index 400c219814..2c8c4a3f53 100644 --- a/src/video_core/renderer_opengl/gl_device.cpp +++ b/src/video_core/renderer_opengl/gl_device.cpp @@ -284,9 +284,23 @@ void main() { })"); } +u64 Device::GetTotalDedicatedVideoMemory() const { + GLint tot_avail_mem_kb = 0; + // this should report the correct size of the VRAM, on integrated devices it shows the size of + // the UMA Framebuffer + glGetIntegerv(GL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX, &tot_avail_mem_kb); + // LOG_INFO(Render_OpenGL, "total VRAM: {} GB", tot_avail_mem_kb / f64{1_MiB}); + f64 percent = Settings::values.vram_percentage.GetValue(); + u64 vram = Settings::RAM_Percent_to_Byte(percent); + return static_cast(tot_avail_mem_kb) * 1_KiB + vram; +} + + u64 Device::GetCurrentDedicatedVideoMemory() const { GLint cur_avail_mem_kb = 0; - glGetIntegerv(GL_GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX, &cur_avail_mem_kb); + // this should report the currently available video memory + glGetIntegerv(GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, &cur_avail_mem_kb); + // LOG_INFO(Render_OpenGL, "current VRAM: {} GB", cur_avail_mem_kb / f64{1_MiB}); return static_cast(cur_avail_mem_kb) * 1_KiB; } diff --git a/src/video_core/renderer_opengl/gl_texture_cache.cpp b/src/video_core/renderer_opengl/gl_texture_cache.cpp index 56d0ff8698..33cfe020ef 100644 --- a/src/video_core/renderer_opengl/gl_texture_cache.cpp +++ b/src/video_core/renderer_opengl/gl_texture_cache.cpp @@ -546,7 +546,7 @@ TextureCacheRuntime::TextureCacheRuntime(const Device& device_, ProgramManager& device_access_memory = [this]() -> u64 { if (device.CanReportMemoryUsage()) { - return device.GetCurrentDedicatedVideoMemory() + 512_MiB; + return device.GetTotalDedicatedVideoMemory(); } return 2_GiB; // Return minimum requirements }(); diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index aea677cb37..7dd850d747 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp @@ -1039,9 +1039,10 @@ void Device::CollectPhysicalMemoryInfo() { device_access_memory = std::min(device_access_memory, normal_memory + scaler_memory); return; } + const u8 percent = Settings::values.vram_percentage.GetValue(); const s64 available_memory = static_cast(device_access_memory - device_initial_usage); device_access_memory = static_cast(std::max( - std::min(available_memory - 8_GiB, 4_GiB), std::min(local_memory, 4_GiB))); + std::min(available_memory - 8_GiB, 4_GiB), std::min(local_memory, Settings::RAM_Percent_to_Byte(percent))); } void Device::CollectToolingInfo() { diff --git a/src/yuzu/configuration/configure_graphics_advanced.cpp b/src/yuzu/configuration/configure_graphics_advanced.cpp index 896863f871..46e378514a 100644 --- a/src/yuzu/configuration/configure_graphics_advanced.cpp +++ b/src/yuzu/configuration/configure_graphics_advanced.cpp @@ -42,6 +42,9 @@ void ConfigureGraphicsAdvanced::SetConfiguration() { Settings::values.use_vulkan_driver_pipeline_cache.GetValue()); ui->enable_compute_pipelines_checkbox->setChecked( Settings::values.enable_compute_pipelines.GetValue()); + ui->use_vram_percentage->setChecked(Settings::values.use_vram_percentage.GetValue()); + ui->vram_percentage->setVisible(Settings::values.use_vram_percentage.GetValue()); + if (Settings::IsConfiguringGlobal()) { ui->gpu_accuracy->setCurrentIndex( @@ -91,6 +94,12 @@ void ConfigureGraphicsAdvanced::ApplyConfiguration() { ConfigurationShared::ApplyPerGameSetting(&Settings::values.enable_compute_pipelines, ui->enable_compute_pipelines_checkbox, enable_compute_pipelines); + ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_vram_percentage, + ui->use_vram_percentage, + use_vram_percentage); + ConfigurationShared::ApplyPerGameSetting(&Settings::values.vram_percentage, + ui->vram_percentage, + vram_percentage); } void ConfigureGraphicsAdvanced::changeEvent(QEvent* event) { @@ -158,6 +167,12 @@ void ConfigureGraphicsAdvanced::SetupPerGameUI() { ConfigurationShared::SetColoredComboBox( ui->astc_recompression_combobox, ui->label_astc_recompression, static_cast(Settings::values.astc_recompression.GetValue(true))); + ConfigurationShared::SetColoredTristate(ui->use_vram_percentage, + Settings::values.use_vram_percentage, + use_vram_percentage); + ConfigurationShared::SetColoredTristate(ui->vram_percentage, + Settings::values.vram_percentage, + vram_percentage); } void ConfigureGraphicsAdvanced::ExposeComputeOption() { diff --git a/src/yuzu/configuration/configure_graphics_advanced.h b/src/yuzu/configuration/configure_graphics_advanced.h index 1c7b636b96..f530384fac 100644 --- a/src/yuzu/configuration/configure_graphics_advanced.h +++ b/src/yuzu/configuration/configure_graphics_advanced.h @@ -47,6 +47,7 @@ private: ConfigurationShared::CheckState use_fast_gpu_time; ConfigurationShared::CheckState use_vulkan_driver_pipeline_cache; ConfigurationShared::CheckState enable_compute_pipelines; + ConfigurationShared::CheckState use_vram_percentage; const Core::System& system; }; diff --git a/src/yuzu/configuration/configure_graphics_advanced.ui b/src/yuzu/configuration/configure_graphics_advanced.ui index 37757a918a..904f284a5e 100644 --- a/src/yuzu/configuration/configure_graphics_advanced.ui +++ b/src/yuzu/configuration/configure_graphics_advanced.ui @@ -247,6 +247,32 @@ Compute pipelines are always enabled on all other drivers. + + + + Assign the given percentage of the total shared RAM as VRAM + + + Assign RAM percentage as VRAM (Integrated devices only) + + + + + + + % + + + 10 + + + 90 + + + 25 + + +