From e690e7e45865ace0008f4f8f8afe2c3a49c02911 Mon Sep 17 00:00:00 2001 From: kd-11 Date: Wed, 18 Mar 2026 21:46:49 +0300 Subject: [PATCH] gl/vk: Implement tri-state Vsync setting --- rpcs3/Emu/RSX/GL/GLGSRender.cpp | 15 ++++++++++- rpcs3/Emu/RSX/GSRender.cpp | 2 ++ rpcs3/Emu/RSX/GSRender.h | 2 ++ rpcs3/Emu/RSX/VK/VKPresent.cpp | 6 +++++ rpcs3/Emu/RSX/VK/vkutils/swapchain.cpp | 19 ++++++++----- rpcs3/Emu/system_config.h | 3 +-- rpcs3/Emu/system_config_types.cpp | 16 +++++++++++ rpcs3/Emu/system_config_types.h | 7 +++++ rpcs3/rpcs3qt/emu_settings.cpp | 7 +++++ rpcs3/rpcs3qt/emu_settings_type.h | 2 +- rpcs3/rpcs3qt/settings_dialog.cpp | 6 ++--- rpcs3/rpcs3qt/settings_dialog.ui | 37 +++++++++++++++++++++----- 12 files changed, 101 insertions(+), 21 deletions(-) diff --git a/rpcs3/Emu/RSX/GL/GLGSRender.cpp b/rpcs3/Emu/RSX/GL/GLGSRender.cpp index 4ad9619d7f..973123fc82 100644 --- a/rpcs3/Emu/RSX/GL/GLGSRender.cpp +++ b/rpcs3/Emu/RSX/GL/GLGSRender.cpp @@ -139,7 +139,20 @@ void GLGSRender::on_init_thread() gl::set_command_context(gl_state); // Enable adaptive vsync if vsync is requested - gl::set_swapinterval(g_cfg.video.vsync ? -1 : 0); + int swap_interval = 0; + switch (g_cfg.video.vsync) + { + default: + case vsync_mode::off: + break; + case vsync_mode::adaptive: + swap_interval = -1; + break; + case vsync_mode::full: + swap_interval = 1; + break; + } + gl::set_swapinterval(swap_interval); if (g_cfg.video.debug_output) gl::enable_debugging(); diff --git a/rpcs3/Emu/RSX/GSRender.cpp b/rpcs3/Emu/RSX/GSRender.cpp index e9e859952e..f09f4704da 100644 --- a/rpcs3/Emu/RSX/GSRender.cpp +++ b/rpcs3/Emu/RSX/GSRender.cpp @@ -13,6 +13,8 @@ GSRender::GSRender(utils::serial* ar) noexcept : rsx::thread(ar) { m_frame = nullptr; } + + m_vsync_mode = g_cfg.video.vsync; } GSRender::~GSRender() diff --git a/rpcs3/Emu/RSX/GSRender.h b/rpcs3/Emu/RSX/GSRender.h index d2a6fd9c5f..f597b5562b 100644 --- a/rpcs3/Emu/RSX/GSRender.h +++ b/rpcs3/Emu/RSX/GSRender.h @@ -23,6 +23,8 @@ protected: draw_context_t m_context = nullptr; bool m_continuous_mode = false; + vsync_mode m_vsync_mode{}; + public: ~GSRender() override; diff --git a/rpcs3/Emu/RSX/VK/VKPresent.cpp b/rpcs3/Emu/RSX/VK/VKPresent.cpp index 5761a99120..f8345726ef 100644 --- a/rpcs3/Emu/RSX/VK/VKPresent.cpp +++ b/rpcs3/Emu/RSX/VK/VKPresent.cpp @@ -135,6 +135,7 @@ bool VKGSRender::reinitialize_swapchain() swapchain_unavailable = false; should_reinitialize_swapchain = false; + m_vsync_mode = g_cfg.video.vsync; return true; } @@ -425,6 +426,11 @@ void VKGSRender::flip(const rsx::display_flip_info_t& info) } } + if (m_vsync_mode != g_cfg.video.vsync) + { + swapchain_unavailable = true; + } + if (swapchain_unavailable || should_reinitialize_swapchain) { // Reinitializing the swapchain is a failable operation. However, not all failures are fatal (e.g minimized window). diff --git a/rpcs3/Emu/RSX/VK/vkutils/swapchain.cpp b/rpcs3/Emu/RSX/VK/vkutils/swapchain.cpp index a296e393e2..fe4464cb03 100644 --- a/rpcs3/Emu/RSX/VK/vkutils/swapchain.cpp +++ b/rpcs3/Emu/RSX/VK/vkutils/swapchain.cpp @@ -234,14 +234,19 @@ namespace vk VkPresentModeKHR swapchain_present_mode = VK_PRESENT_MODE_FIFO_KHR; std::vector preferred_modes; - if (!g_cfg.video.vk.force_fifo) + switch (g_cfg.video.vsync) { - // List of preferred modes in decreasing desirability - // NOTE: Always picks "triple-buffered vsync" types if possible - if (!g_cfg.video.vsync) - { - preferred_modes = { VK_PRESENT_MODE_IMMEDIATE_KHR, VK_PRESENT_MODE_MAILBOX_KHR, VK_PRESENT_MODE_FIFO_RELAXED_KHR }; - } + case vsync_mode::off: + preferred_modes = { VK_PRESENT_MODE_IMMEDIATE_KHR, VK_PRESENT_MODE_MAILBOX_KHR, VK_PRESENT_MODE_FIFO_RELAXED_KHR }; + break; + case vsync_mode::adaptive: + preferred_modes = { VK_PRESENT_MODE_MAILBOX_KHR, VK_PRESENT_MODE_FIFO_RELAXED_KHR }; + break; + case vsync_mode::full: + default: + // FIFO is guaranteed to be supported, no need to go through a preference chain + preferred_modes = {}; + break; } bool mode_found = false; diff --git a/rpcs3/Emu/system_config.h b/rpcs3/Emu/system_config.h index 11c350215d..058eda2f12 100644 --- a/rpcs3/Emu/system_config.h +++ b/rpcs3/Emu/system_config.h @@ -127,6 +127,7 @@ struct cfg_root : cfg::node cfg::_enum antialiasing_level{ this, "MSAA", msaa_level::_auto }; cfg::_enum shadermode{ this, "Shader Mode", shader_mode::async_recompiler }; cfg::_enum shader_precision{ this, "Shader Precision", gpu_preset_level::high }; + cfg::_enum vsync{ this, "VSync Mode", vsync_mode::off, true }; cfg::_bool write_color_buffers{ this, "Write Color Buffers" }; cfg::_bool write_depth_buffer{ this, "Write Depth Buffer" }; @@ -134,7 +135,6 @@ struct cfg_root : cfg::node cfg::_bool read_depth_buffer{ this, "Read Depth Buffer" }; cfg::_bool handle_tiled_memory{ this, "Handle RSX Memory Tiling", false, true }; cfg::_bool log_programs{ this, "Log shader programs" }; - cfg::_bool vsync{ this, "VSync" }; cfg::_bool debug_output{ this, "Debug output" }; cfg::_bool debug_overlay{ this, "Debug overlay", false, true }; cfg::_bool renderdoc_compatiblity{ this, "Renderdoc Compatibility Mode" }; @@ -184,7 +184,6 @@ struct cfg_root : cfg::node node_vk(cfg::node* _this) : cfg::node(_this, "Vulkan") {} cfg::string adapter{ this, "Adapter" }; - cfg::_bool force_fifo{ this, "Force FIFO present mode" }; cfg::_bool force_primitive_restart{ this, "Force primitive restart flag" }; cfg::_enum exclusive_fullscreen_mode{ this, "Exclusive Fullscreen Mode", vk_exclusive_fs_mode::unspecified}; cfg::_bool asynchronous_texture_streaming{ this, "Asynchronous Texture Streaming", false }; diff --git a/rpcs3/Emu/system_config_types.cpp b/rpcs3/Emu/system_config_types.cpp index beb13db4d5..daefd49a42 100644 --- a/rpcs3/Emu/system_config_types.cpp +++ b/rpcs3/Emu/system_config_types.cpp @@ -734,3 +734,19 @@ void fmt_class_string::format(std::string& out, u64 arg) return unknown; }); } + +template <> +void fmt_class_string::format(std::string& out, u64 arg) +{ + format_enum(out, arg, [](vsync_mode value) + { + switch (value) + { + case vsync_mode::off: return "Disabled"; + case vsync_mode::adaptive: return "Adaptive"; + case vsync_mode::full: return "Full"; + } + + return unknown; + }); +} diff --git a/rpcs3/Emu/system_config_types.h b/rpcs3/Emu/system_config_types.h index d58e8664fa..f11e9caa3f 100644 --- a/rpcs3/Emu/system_config_types.h +++ b/rpcs3/Emu/system_config_types.h @@ -363,3 +363,10 @@ enum class xfloat_accuracy relaxed, // Approximate accuracy for only the "FCGT", "FNMS", "FREST" AND "FRSQEST" instructions inaccurate }; + +enum class vsync_mode +{ + off, + adaptive, + full, +}; diff --git a/rpcs3/rpcs3qt/emu_settings.cpp b/rpcs3/rpcs3qt/emu_settings.cpp index 22cf9b4032..30860e10f5 100644 --- a/rpcs3/rpcs3qt/emu_settings.cpp +++ b/rpcs3/rpcs3qt/emu_settings.cpp @@ -1499,6 +1499,13 @@ QString emu_settings::GetLocalizedSetting(const QString& original, emu_settings_ case xfloat_accuracy::inaccurate: return tr("Inaccurate XFloat"); } break; + case emu_settings_type::VSync: + switch (static_cast(index)) + { + case vsync_mode::off: return tr("Disabled", "VSync Mode"); + case vsync_mode::adaptive: return tr("Adaptive", "VSync Mode"); + case vsync_mode::full: return tr("Full", "VSync Mode"); + } default: break; } diff --git a/rpcs3/rpcs3qt/emu_settings_type.h b/rpcs3/rpcs3qt/emu_settings_type.h index a3e47fe733..fccc13a0dd 100644 --- a/rpcs3/rpcs3qt/emu_settings_type.h +++ b/rpcs3/rpcs3qt/emu_settings_type.h @@ -278,7 +278,7 @@ inline static const std::map settings_location { emu_settings_type::ReadColorBuffers, { "Video", "Read Color Buffers"}}, { emu_settings_type::ReadDepthBuffer, { "Video", "Read Depth Buffer"}}, { emu_settings_type::HandleRSXTiledMemory, { "Video", "Handle RSX Memory Tiling"}}, - { emu_settings_type::VSync, { "Video", "VSync"}}, + { emu_settings_type::VSync, { "Video", "VSync Mode"}}, { emu_settings_type::DebugOutput, { "Video", "Debug output"}}, { emu_settings_type::DebugOverlay, { "Video", "Debug overlay"}}, { emu_settings_type::RenderdocCompatibility, { "Video", "Renderdoc Compatibility Mode"}}, diff --git a/rpcs3/rpcs3qt/settings_dialog.cpp b/rpcs3/rpcs3qt/settings_dialog.cpp index d25d3ad9fb..19fee331fb 100644 --- a/rpcs3/rpcs3qt/settings_dialog.cpp +++ b/rpcs3/rpcs3qt/settings_dialog.cpp @@ -502,6 +502,9 @@ settings_dialog::settings_dialog(std::shared_ptr gui_settings, std } } + m_emu_settings->EnhanceComboBox(ui->vsyncMode, emu_settings_type::VSync); + SubscribeTooltip(ui->vsyncMode, tooltips.settings.vsync); + m_emu_settings->EnhanceComboBox(ui->antiAliasing, emu_settings_type::MSAA); SubscribeTooltip(ui->gb_antiAliasing, tooltips.settings.anti_aliasing); @@ -604,9 +607,6 @@ settings_dialog::settings_dialog(std::shared_ptr gui_settings, std m_emu_settings->EnhanceCheckBox(ui->dumpColor, emu_settings_type::WriteColorBuffers); SubscribeTooltip(ui->dumpColor, tooltips.settings.dump_color); - m_emu_settings->EnhanceCheckBox(ui->vsync, emu_settings_type::VSync); - SubscribeTooltip(ui->vsync, tooltips.settings.vsync); - m_emu_settings->EnhanceCheckBox(ui->stretchToDisplayArea, emu_settings_type::StretchToDisplayArea); SubscribeTooltip(ui->stretchToDisplayArea, tooltips.settings.stretch_to_display_area); diff --git a/rpcs3/rpcs3qt/settings_dialog.ui b/rpcs3/rpcs3qt/settings_dialog.ui index 30100b7935..c5a5378f4c 100644 --- a/rpcs3/rpcs3qt/settings_dialog.ui +++ b/rpcs3/rpcs3qt/settings_dialog.ui @@ -511,6 +511,36 @@ + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Vsync + + + + + + + + + + + @@ -908,13 +938,6 @@ - - - - VSync - - -