From 6f0929df82be77f116988cf16cde4ebbc5f978dc Mon Sep 17 00:00:00 2001 From: lat9nq <22451773+lat9nq@users.noreply.github.com> Date: Sun, 30 Apr 2023 15:39:00 -0400 Subject: [PATCH] configuration: Expose separate swap present modes Previously, yuzu would try and guess which vsync mode to use given different scenarios, but apparently we didn't always get it right. This exposes the separate modes in a drop-down the user can select. If a mode isn't available in Vulkan, it defaults to FIFO. --- src/common/settings.cpp | 3 +- src/common/settings.h | 9 +++- src/core/telemetry_session.cpp | 15 +++++- .../renderer_vulkan/vk_swapchain.cpp | 27 +++++----- src/yuzu/bootmanager.cpp | 13 ++++- src/yuzu/configuration/config.cpp | 10 +++- src/yuzu/configuration/configure_graphics.cpp | 9 ++++ src/yuzu/configuration/configure_graphics.ui | 49 ++++++++++++++++++- .../configure_graphics_advanced.cpp | 5 -- .../configure_graphics_advanced.ui | 10 ---- src/yuzu_cmd/config.cpp | 2 +- 11 files changed, 115 insertions(+), 37 deletions(-) diff --git a/src/common/settings.cpp b/src/common/settings.cpp index 77ff21128..92794f4a2 100644 --- a/src/common/settings.cpp +++ b/src/common/settings.cpp @@ -60,7 +60,7 @@ void LogSettings() { log_setting("Renderer_NvdecEmulation", values.nvdec_emulation.GetValue()); log_setting("Renderer_AccelerateASTC", values.accelerate_astc.GetValue()); log_setting("Renderer_AsyncASTC", values.async_astc.GetValue()); - log_setting("Renderer_UseVsync", values.use_vsync.GetValue()); + log_setting("Renderer_UseVsync", values.vsync_mode.GetValue()); 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()); @@ -222,7 +222,6 @@ void RestoreGlobalState(bool is_powered_on) { values.nvdec_emulation.SetGlobal(true); values.accelerate_astc.SetGlobal(true); values.async_astc.SetGlobal(true); - values.use_vsync.SetGlobal(true); values.shader_backend.SetGlobal(true); values.use_asynchronous_shaders.SetGlobal(true); values.use_fast_gpu_time.SetGlobal(true); diff --git a/src/common/settings.h b/src/common/settings.h index 5379d0dd5..2371495e4 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -16,6 +16,12 @@ namespace Settings { +enum class VSyncMode : u32 { + Immediate, + FIFO, + Mailbox, +}; + enum class RendererBackend : u32 { OpenGL = 0, Vulkan = 1, @@ -455,7 +461,8 @@ struct Values { SwitchableSetting nvdec_emulation{NvdecEmulation::GPU, "nvdec_emulation"}; SwitchableSetting accelerate_astc{true, "accelerate_astc"}; SwitchableSetting async_astc{false, "async_astc"}; - SwitchableSetting use_vsync{true, "use_vsync"}; + Setting vsync_mode{VSyncMode::FIFO, VSyncMode::Immediate, VSyncMode::Mailbox, + "use_vsync"}; SwitchableSetting shader_backend{ShaderBackend::GLSL, ShaderBackend::GLSL, ShaderBackend::SPIRV, "shader_backend"}; SwitchableSetting use_asynchronous_shaders{false, "use_asynchronous_shaders"}; diff --git a/src/core/telemetry_session.cpp b/src/core/telemetry_session.cpp index 9178b00ca..6ec8e440c 100644 --- a/src/core/telemetry_session.cpp +++ b/src/core/telemetry_session.cpp @@ -85,6 +85,18 @@ static const char* TranslateNvdecEmulation(Settings::NvdecEmulation backend) { return "Unknown"; } +constexpr const char* TranslateVSyncMode(Settings::VSyncMode mode) { + switch (mode) { + case Settings::VSyncMode::Immediate: + return "Immediate"; + case Settings::VSyncMode::FIFO: + return "FIFO"; + case Settings::VSyncMode::Mailbox: + return "Mailbox"; + } + return "Unknown"; +} + u64 GetTelemetryId() { u64 telemetry_id{}; const auto filename = Common::FS::GetYuzuPath(Common::FS::YuzuPath::ConfigDir) / "telemetry_id"; @@ -241,7 +253,8 @@ void TelemetrySession::AddInitialInfo(Loader::AppLoader& app_loader, AddField(field_type, "Renderer_NvdecEmulation", TranslateNvdecEmulation(Settings::values.nvdec_emulation.GetValue())); AddField(field_type, "Renderer_AccelerateASTC", Settings::values.accelerate_astc.GetValue()); - AddField(field_type, "Renderer_UseVsync", Settings::values.use_vsync.GetValue()); + AddField(field_type, "Renderer_UseVsync", + TranslateVSyncMode(Settings::values.vsync_mode.GetValue())); AddField(field_type, "Renderer_ShaderBackend", static_cast(Settings::values.shader_backend.GetValue())); AddField(field_type, "Renderer_UseAsynchronousShaders", diff --git a/src/video_core/renderer_vulkan/vk_swapchain.cpp b/src/video_core/renderer_vulkan/vk_swapchain.cpp index 23bbea7f1..08d82769c 100644 --- a/src/video_core/renderer_vulkan/vk_swapchain.cpp +++ b/src/video_core/renderer_vulkan/vk_swapchain.cpp @@ -34,21 +34,22 @@ VkSurfaceFormatKHR ChooseSwapSurfaceFormat(vk::Span formats) } VkPresentModeKHR ChooseSwapPresentMode(vk::Span modes) { - // Mailbox (triple buffering) doesn't lock the application like fifo (vsync), - // prefer it if vsync option is not selected - const auto found_mailbox = std::find(modes.begin(), modes.end(), VK_PRESENT_MODE_MAILBOX_KHR); - if (Settings::values.fullscreen_mode.GetValue() == Settings::FullscreenMode::Borderless && - found_mailbox != modes.end() && !Settings::values.use_vsync.GetValue()) { + // Mailbox (triple buffering) doesn't lock the application like FIFO (vsync) + // FIFO present mode locks the framerate to the monitor's refresh rate + const bool has_mailbox = + std::find(modes.begin(), modes.end(), VK_PRESENT_MODE_MAILBOX_KHR) != modes.end(); + const bool has_imm = + std::find(modes.begin(), modes.end(), VK_PRESENT_MODE_IMMEDIATE_KHR) != modes.end(); + const Settings::VSyncMode mode = Settings::values.vsync_mode.GetValue(); + + if (mode == Settings::VSyncMode::Immediate && has_imm) { + LOG_INFO(Render_Vulkan, "Using swap present mode Immediate"); + return VK_PRESENT_MODE_IMMEDIATE_KHR; + } else if (mode == Settings::VSyncMode::Mailbox && has_mailbox) { + LOG_INFO(Render_Vulkan, "Using swap present mode Mailbox"); return VK_PRESENT_MODE_MAILBOX_KHR; } - if (!Settings::values.use_speed_limit.GetValue()) { - // FIFO present mode locks the framerate to the monitor's refresh rate, - // Find an alternative to surpass this limitation if FPS is unlocked. - const auto found_imm = std::find(modes.begin(), modes.end(), VK_PRESENT_MODE_IMMEDIATE_KHR); - if (found_imm != modes.end()) { - return VK_PRESENT_MODE_IMMEDIATE_KHR; - } - } + LOG_INFO(Render_Vulkan, "Using swap present mode FIFO"); return VK_PRESENT_MODE_FIFO_KHR; } diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index 4c7bf28d8..01dc51cff 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp @@ -154,7 +154,18 @@ public: // disable vsync for any shared contexts auto format = share_context->format(); - format.setSwapInterval(main_surface ? Settings::values.use_vsync.GetValue() : 0); + const int swap_interval = [&]() { + switch (Settings::values.vsync_mode.GetValue()) { + case Settings::VSyncMode::Immediate: + return 0; + case Settings::VSyncMode::FIFO: + return 1; + case Settings::VSyncMode::Mailbox: + return 2; + } + }(); + + format.setSwapInterval(main_surface ? swap_interval : 0); context = std::make_unique(); context->setShareContext(share_context); diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index 305891d18..4a8436e5c 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp @@ -6,6 +6,7 @@ #include #include "common/fs/fs.h" #include "common/fs/path_util.h" +#include "common/settings.h" #include "core/core.h" #include "core/hle/service/acc/profile_manager.h" #include "core/hle/service/hid/controllers/npad.h" @@ -709,7 +710,6 @@ void Config::ReadRendererValues() { ReadGlobalSetting(Settings::values.nvdec_emulation); ReadGlobalSetting(Settings::values.accelerate_astc); ReadGlobalSetting(Settings::values.async_astc); - ReadGlobalSetting(Settings::values.use_vsync); ReadGlobalSetting(Settings::values.shader_backend); ReadGlobalSetting(Settings::values.use_asynchronous_shaders); ReadGlobalSetting(Settings::values.use_fast_gpu_time); @@ -720,6 +720,10 @@ void Config::ReadRendererValues() { ReadGlobalSetting(Settings::values.bg_blue); if (global) { + Settings::values.vsync_mode.SetValue(static_cast( + ReadSetting(QString::fromStdString(Settings::values.vsync_mode.GetLabel()), + static_cast(Settings::values.vsync_mode.GetDefault())) + .value())); ReadBasicSetting(Settings::values.renderer_debug); ReadBasicSetting(Settings::values.renderer_shader_feedback); ReadBasicSetting(Settings::values.enable_nsight_aftermath); @@ -1352,7 +1356,6 @@ void Config::SaveRendererValues() { Settings::values.nvdec_emulation.UsingGlobal()); WriteGlobalSetting(Settings::values.accelerate_astc); WriteGlobalSetting(Settings::values.async_astc); - WriteGlobalSetting(Settings::values.use_vsync); WriteSetting(QString::fromStdString(Settings::values.shader_backend.GetLabel()), static_cast(Settings::values.shader_backend.GetValue(global)), static_cast(Settings::values.shader_backend.GetDefault()), @@ -1366,6 +1369,9 @@ void Config::SaveRendererValues() { WriteGlobalSetting(Settings::values.bg_blue); if (global) { + WriteSetting(QString::fromStdString(Settings::values.vsync_mode.GetLabel()), + static_cast(Settings::values.vsync_mode.GetValue()), + static_cast(Settings::values.vsync_mode.GetDefault())); WriteBasicSetting(Settings::values.renderer_debug); WriteBasicSetting(Settings::values.renderer_shader_feedback); WriteBasicSetting(Settings::values.enable_nsight_aftermath); diff --git a/src/yuzu/configuration/configure_graphics.cpp b/src/yuzu/configuration/configure_graphics.cpp index e9388daad..17a54f0f4 100644 --- a/src/yuzu/configuration/configure_graphics.cpp +++ b/src/yuzu/configuration/configure_graphics.cpp @@ -99,6 +99,7 @@ void ConfigureGraphics::SetConfiguration() { ui->nvdec_emulation_widget->setEnabled(runtime_lock); ui->resolution_combobox->setEnabled(runtime_lock); ui->accelerate_astc->setEnabled(runtime_lock); + ui->vsync_mode_combobox->setEnabled(runtime_lock); ui->use_disk_shader_cache->setChecked(Settings::values.use_disk_shader_cache.GetValue()); ui->use_asynchronous_gpu_emulation->setChecked( Settings::values.use_asynchronous_gpu_emulation.GetValue()); @@ -118,6 +119,9 @@ void ConfigureGraphics::SetConfiguration() { ui->fsr_sharpening_slider->setValue(Settings::values.fsr_sharpening_slider.GetValue()); ui->anti_aliasing_combobox->setCurrentIndex( static_cast(Settings::values.anti_aliasing.GetValue())); + + ui->vsync_mode_combobox->setCurrentIndex( + static_cast(Settings::values.vsync_mode.GetValue())); } else { ConfigurationShared::SetPerGameSetting(ui->api, &Settings::values.renderer_backend); ConfigurationShared::SetHighlight(ui->api_widget, @@ -232,6 +236,9 @@ void ConfigureGraphics::ApplyConfiguration() { Settings::values.anti_aliasing.SetValue(anti_aliasing); } Settings::values.fsr_sharpening_slider.SetValue(ui->fsr_sharpening_slider->value()); + + Settings::values.vsync_mode.SetValue( + static_cast(ui->vsync_mode_combobox->currentIndex())); } else { if (ui->resolution_combobox->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) { Settings::values.resolution_setup.SetGlobal(true); @@ -465,4 +472,6 @@ void ConfigureGraphics::SetupPerGameUI() { ui->api, static_cast(Settings::values.renderer_backend.GetValue(true))); ConfigurationShared::InsertGlobalItem( ui->nvdec_emulation, static_cast(Settings::values.nvdec_emulation.GetValue(true))); + + ui->vsync_mode_layout->setVisible(false); } diff --git a/src/yuzu/configuration/configure_graphics.ui b/src/yuzu/configuration/configure_graphics.ui index a45ec69ec..4c241e247 100644 --- a/src/yuzu/configuration/configure_graphics.ui +++ b/src/yuzu/configuration/configure_graphics.ui @@ -188,6 +188,53 @@ + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + VSync Mode + + + + + + + Off (Immediate) + + + + Off (Immediate) + + + + + Double Buffering (FIFO) + + + + + Triple Buffering (Mailbox) + + + + + + + @@ -366,7 +413,7 @@ - 1.5X (1080p/1620p) [EXPERIMENTAL] + 1.5X (1080p/1620p) [EXPERIMENTAL] diff --git a/src/yuzu/configuration/configure_graphics_advanced.cpp b/src/yuzu/configuration/configure_graphics_advanced.cpp index 7f7bf0e4d..4072ce145 100644 --- a/src/yuzu/configuration/configure_graphics_advanced.cpp +++ b/src/yuzu/configuration/configure_graphics_advanced.cpp @@ -21,7 +21,6 @@ ConfigureGraphicsAdvanced::~ConfigureGraphicsAdvanced() = default; void ConfigureGraphicsAdvanced::SetConfiguration() { const bool runtime_lock = !system.IsPoweredOn(); - ui->use_vsync->setEnabled(runtime_lock); ui->async_present->setEnabled(runtime_lock); ui->renderer_force_max_clock->setEnabled(runtime_lock); ui->async_astc->setEnabled(runtime_lock); @@ -30,7 +29,6 @@ void ConfigureGraphicsAdvanced::SetConfiguration() { ui->async_present->setChecked(Settings::values.async_presentation.GetValue()); ui->renderer_force_max_clock->setChecked(Settings::values.renderer_force_max_clock.GetValue()); - ui->use_vsync->setChecked(Settings::values.use_vsync.GetValue()); ui->async_astc->setChecked(Settings::values.async_astc.GetValue()); ui->use_asynchronous_shaders->setChecked(Settings::values.use_asynchronous_shaders.GetValue()); ui->use_fast_gpu_time->setChecked(Settings::values.use_fast_gpu_time.GetValue()); @@ -63,7 +61,6 @@ void ConfigureGraphicsAdvanced::ApplyConfiguration() { renderer_force_max_clock); ConfigurationShared::ApplyPerGameSetting(&Settings::values.max_anisotropy, ui->anisotropic_filtering_combobox); - ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_vsync, ui->use_vsync, use_vsync); ConfigurationShared::ApplyPerGameSetting(&Settings::values.async_astc, ui->async_astc, async_astc); ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_asynchronous_shaders, @@ -97,7 +94,6 @@ void ConfigureGraphicsAdvanced::SetupPerGameUI() { ui->async_present->setEnabled(Settings::values.async_presentation.UsingGlobal()); ui->renderer_force_max_clock->setEnabled( Settings::values.renderer_force_max_clock.UsingGlobal()); - ui->use_vsync->setEnabled(Settings::values.use_vsync.UsingGlobal()); ui->async_astc->setEnabled(Settings::values.async_astc.UsingGlobal()); ui->use_asynchronous_shaders->setEnabled( Settings::values.use_asynchronous_shaders.UsingGlobal()); @@ -117,7 +113,6 @@ void ConfigureGraphicsAdvanced::SetupPerGameUI() { ConfigurationShared::SetColoredTristate(ui->renderer_force_max_clock, Settings::values.renderer_force_max_clock, renderer_force_max_clock); - ConfigurationShared::SetColoredTristate(ui->use_vsync, Settings::values.use_vsync, use_vsync); ConfigurationShared::SetColoredTristate(ui->async_astc, Settings::values.async_astc, async_astc); ConfigurationShared::SetColoredTristate(ui->use_asynchronous_shaders, diff --git a/src/yuzu/configuration/configure_graphics_advanced.ui b/src/yuzu/configuration/configure_graphics_advanced.ui index d7ec18939..134023032 100644 --- a/src/yuzu/configuration/configure_graphics_advanced.ui +++ b/src/yuzu/configuration/configure_graphics_advanced.ui @@ -86,16 +86,6 @@ - - - - VSync prevents the screen from tearing, but some graphics cards have lower performance with VSync enabled. Keep it enabled if you don't notice a performance difference. - - - Use VSync - - - diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp index fa347fb8c..a692ef809 100644 --- a/src/yuzu_cmd/config.cpp +++ b/src/yuzu_cmd/config.cpp @@ -320,7 +320,7 @@ void Config::ReadValues() { ReadSetting("Renderer", Settings::values.use_disk_shader_cache); ReadSetting("Renderer", Settings::values.gpu_accuracy); ReadSetting("Renderer", Settings::values.use_asynchronous_gpu_emulation); - ReadSetting("Renderer", Settings::values.use_vsync); + ReadSetting("Renderer", Settings::values.vsync_mode); ReadSetting("Renderer", Settings::values.shader_backend); ReadSetting("Renderer", Settings::values.use_asynchronous_shaders); ReadSetting("Renderer", Settings::values.nvdec_emulation);