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.
This commit is contained in:
Martin Felke 2023-06-04 17:35:47 +02:00
parent e931bb8c44
commit de1cbf6edc
9 changed files with 88 additions and 4 deletions

View file

@ -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

View file

@ -487,6 +487,9 @@ struct Values {
SwitchableSetting<u8> bg_green{0, "bg_green"};
SwitchableSetting<u8> bg_blue{0, "bg_blue"};
SwitchableSetting<bool, true> use_vram_percentage{true, "use_vram_percentage"};
SwitchableSetting<u8, true> vram_percentage{25, 10, 90, "vram_percentage"};
// System
SwitchableSetting<std::optional<u32>> rng_seed{std::optional<u32>(), "rng_seed"};
Setting<std::string> device_name{"Yuzu", "device_name"};

View file

@ -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
}();

View file

@ -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<u64>(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<u64>(cur_avail_mem_kb) * 1_KiB;
}

View file

@ -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
}();

View file

@ -1039,9 +1039,10 @@ void Device::CollectPhysicalMemoryInfo() {
device_access_memory = std::min<u64>(device_access_memory, normal_memory + scaler_memory);
return;
}
const u8 percent = Settings::values.vram_percentage.GetValue();
const s64 available_memory = static_cast<s64>(device_access_memory - device_initial_usage);
device_access_memory = static_cast<u64>(std::max<s64>(
std::min<s64>(available_memory - 8_GiB, 4_GiB), std::min<s64>(local_memory, 4_GiB)));
std::min<s64>(available_memory - 8_GiB, 4_GiB), std::min<s64>(local_memory, Settings::RAM_Percent_to_Byte(percent)));
}
void Device::CollectToolingInfo() {

View file

@ -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<int>(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() {

View file

@ -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;
};

View file

@ -247,6 +247,32 @@ Compute pipelines are always enabled on all other drivers.</string>
</item>
</widget>
</item>
<item>
<widget class="QCheckBox" name="use_vram_percentage">
<property name="toolTip">
<string>Assign the given percentage of the total shared RAM as VRAM</string>
</property>
<property name="text">
<string>Assign RAM percentage as VRAM (Integrated devices only)</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="vram_percentage">
<property name="suffix">
<string>%</string>
</property>
<property name="minimum">
<number>10</number>
</property>
<property name="maximum">
<number>90</number>
</property>
<property name="value">
<number>25</number>
</property>
</widget>
</item>
</layout>
</widget>
</item>