gl/vk: Implement tri-state Vsync setting

This commit is contained in:
kd-11 2026-03-18 21:46:49 +03:00 committed by kd-11
parent 253d4565f1
commit e690e7e458
12 changed files with 101 additions and 21 deletions

View file

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

View file

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

View file

@ -23,6 +23,8 @@ protected:
draw_context_t m_context = nullptr;
bool m_continuous_mode = false;
vsync_mode m_vsync_mode{};
public:
~GSRender() override;

View file

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

View file

@ -234,14 +234,19 @@ namespace vk
VkPresentModeKHR swapchain_present_mode = VK_PRESENT_MODE_FIFO_KHR;
std::vector<VkPresentModeKHR> 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;

View file

@ -127,6 +127,7 @@ struct cfg_root : cfg::node
cfg::_enum<msaa_level> antialiasing_level{ this, "MSAA", msaa_level::_auto };
cfg::_enum<shader_mode> shadermode{ this, "Shader Mode", shader_mode::async_recompiler };
cfg::_enum<gpu_preset_level> shader_precision{ this, "Shader Precision", gpu_preset_level::high };
cfg::_enum<vsync_mode> 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<vk_exclusive_fs_mode> exclusive_fullscreen_mode{ this, "Exclusive Fullscreen Mode", vk_exclusive_fs_mode::unspecified};
cfg::_bool asynchronous_texture_streaming{ this, "Asynchronous Texture Streaming", false };

View file

@ -734,3 +734,19 @@ void fmt_class_string<time_format>::format(std::string& out, u64 arg)
return unknown;
});
}
template <>
void fmt_class_string<vsync_mode>::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;
});
}

View file

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

View file

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

View file

@ -278,7 +278,7 @@ inline static const std::map<emu_settings_type, cfg_location> 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"}},

View file

@ -502,6 +502,9 @@ settings_dialog::settings_dialog(std::shared_ptr<gui_settings> 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> 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);

View file

@ -511,6 +511,36 @@
</layout>
</widget>
</item>
<item>
<widget class="QWidget" name="widget_gpu_4" native="true">
<layout class="QHBoxLayout" name="widget_gpu_4_layout" stretch="1,1">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QGroupBox" name="gbVsync">
<property name="title">
<string>Vsync</string>
</property>
<layout class="QVBoxLayout" name="gbVsync_layout">
<item>
<widget class="QComboBox" name="vsyncMode"/>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="gb_stereo">
<property name="title">
@ -908,13 +938,6 @@
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="vsync">
<property name="text">
<string>VSync</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="stretchToDisplayArea">
<property name="text">