GPUDevice: Make vsync actually tear-free

Apparently users prefer stutter over tearing...
This commit is contained in:
Stenzek
2024-05-23 13:52:24 +10:00
parent dd98b630ea
commit 6cad97b404
17 changed files with 178 additions and 87 deletions

View File

@ -288,7 +288,8 @@ bool Host::CreateGPUDevice(RenderAPI api, Error* error)
if (!g_gpu_device || !g_gpu_device->Create(
g_settings.gpu_adapter,
g_settings.gpu_disable_shader_cache ? std::string_view() : std::string_view(EmuFolders::Cache),
SHADER_CACHE_VERSION, g_settings.gpu_use_debug_device, System::IsVSyncEffectivelyEnabled(),
SHADER_CACHE_VERSION, g_settings.gpu_use_debug_device, System::IsHostVSyncEffectivelyEnabled(),
System::IsHostVSyncEffectivelyEnabled() && !System::IsHostVSyncUsedForTiming(),
g_settings.gpu_threaded_presentation, exclusive_fullscreen_control,
static_cast<GPUDevice::FeatureMask>(disabled_features), &create_error))
{
@ -331,9 +332,15 @@ void Host::UpdateDisplayWindow()
ImGuiManager::WindowResized();
// If we're paused, re-present the current frame at the new window size.
if (System::IsValid() && System::IsPaused())
System::InvalidateDisplay();
if (System::IsValid())
{
// Fix up vsync etc.
System::UpdateSpeedLimiterState();
// If we're paused, re-present the current frame at the new window size.
if (System::IsPaused())
System::InvalidateDisplay();
}
}
void Host::ResizeDisplayWindow(s32 width, s32 height, float scale)

View File

@ -2835,7 +2835,6 @@ void System::UpdateSpeedLimiterState()
{
DebugAssert(IsValid());
const float old_target_speed = s_target_speed;
s_target_speed = s_turbo_enabled ?
g_settings.turbo_speed :
(s_fast_forward_enabled ? g_settings.fast_forward_speed : g_settings.emulation_speed);
@ -2862,7 +2861,7 @@ void System::UpdateSpeedLimiterState()
}
// When syncing to host and using vsync, we don't need to sleep.
s_syncing_to_host_with_vsync = (s_syncing_to_host && IsVSyncEffectivelyEnabled());
s_syncing_to_host_with_vsync = (s_syncing_to_host && IsHostVSyncEffectivelyEnabled());
if (s_syncing_to_host_with_vsync)
{
Log_InfoPrintf("Using host vsync for throttling.");
@ -2886,22 +2885,27 @@ void System::UpdateSpeedLimiterState()
void System::UpdateDisplaySync()
{
const bool vsync_enabled = IsVSyncEffectivelyEnabled();
const bool syncing_to_host_vsync = (s_syncing_to_host && vsync_enabled);
const bool vsync_enabled = IsHostVSyncEffectivelyEnabled();
const float max_display_fps = (s_throttler_enabled || s_syncing_to_host) ? 0.0f : g_settings.display_max_fps;
Log_VerboseFmt("VSync: {}{}", vsync_enabled ? "Enabled" : "Disabled",
syncing_to_host_vsync ? " (for throttling)" : "");
s_syncing_to_host_with_vsync ? " (for throttling)" : "");
Log_VerboseFmt("Max display fps: {}", max_display_fps);
Log_VerboseFmt("Preset timing: {}", s_optimal_frame_pacing ? "consistent" : "immediate");
g_gpu_device->SetDisplayMaxFPS(max_display_fps);
g_gpu_device->SetVSyncEnabled(vsync_enabled);
g_gpu_device->SetVSyncEnabled(vsync_enabled, vsync_enabled && !IsHostVSyncUsedForTiming());
}
bool System::IsVSyncEffectivelyEnabled()
bool System::IsHostVSyncEffectivelyEnabled()
{
// Disable vsync if running outside 100%.
return (g_settings.display_vsync && IsValid() && !IsRunningAtNonStandardSpeed());
return (g_settings.display_vsync && (s_state != State::Shutdown && s_state != State::Stopping) &&
!IsRunningAtNonStandardSpeed());
}
bool System::IsHostVSyncUsedForTiming()
{
return (IsHostVSyncEffectivelyEnabled() && s_syncing_to_host_with_vsync);
}
bool System::IsFastForwardEnabled()
@ -4505,7 +4509,7 @@ bool System::IsRunningAtNonStandardSpeed()
if (!IsValid())
return false;
const float target_speed = System::GetTargetSpeed();
const float target_speed = GetTargetSpeed();
return (target_speed <= 0.95f || target_speed >= 1.05f);
}

View File

@ -466,7 +466,10 @@ void ToggleWidescreen();
bool IsRunningAtNonStandardSpeed();
/// Returns true if vsync should be used.
bool IsVSyncEffectivelyEnabled();
bool IsHostVSyncEffectivelyEnabled();
/// Returns true if vsync is being used for frame pacing.
bool IsHostVSyncUsedForTiming();
/// Quick switch between software and hardware rendering.
void ToggleSoftwareRendering();