System: Combine VRR and Optimal Frame Pacing
GSync/FreeSync display users should: - DISABLE VSync. - ENABLE Optimal Frame Pacing.
This commit is contained in:
@@ -4180,11 +4180,10 @@ void FullscreenUI::DrawDisplaySettingsPage()
|
||||
"GPU", "UseSoftwareRendererForReadbacks", false);
|
||||
}
|
||||
|
||||
DrawEnumSetting(
|
||||
bsi, FSUI_CSTR("VSync"),
|
||||
FSUI_CSTR("Synchronizes presentation of the console's frames to the host. Enable for smoother animations."),
|
||||
"Display", "SyncMode", Settings::DEFAULT_DISPLAY_SYNC_MODE, &Settings::ParseDisplaySyncMode,
|
||||
&Settings::GetDisplaySyncModeName, &Settings::GetDisplaySyncModeDisplayName, DisplaySyncMode::Count);
|
||||
DrawToggleSetting(bsi, FSUI_CSTR("VSync"),
|
||||
FSUI_CSTR("Synchronizes presentation of the console's frames to the host. GSync/FreeSync users "
|
||||
"should enable Optimal Frame Pacing instead."),
|
||||
"Display", "VSync", false);
|
||||
|
||||
DrawToggleSetting(
|
||||
bsi, FSUI_CSTR("Sync To Host Refresh Rate"),
|
||||
@@ -4192,10 +4191,11 @@ void FullscreenUI::DrawDisplaySettingsPage()
|
||||
"Resampling are enabled."),
|
||||
"Main", "SyncToHostRefreshRate", false);
|
||||
|
||||
DrawToggleSetting(bsi, FSUI_CSTR("Optimal Frame Pacing"),
|
||||
FSUI_CSTR("Ensures every frame generated is displayed for optimal pacing. Disable if you are "
|
||||
"having speed or sound issues."),
|
||||
"Display", "DisplayAllFrames", false);
|
||||
DrawToggleSetting(
|
||||
bsi, FSUI_CSTR("Optimal Frame Pacing"),
|
||||
FSUI_CSTR("Ensures every frame generated is displayed for optimal pacing. Enable for variable refresh displays, "
|
||||
"such as GSync/FreeSync. Disable if you are having speed or sound issues."),
|
||||
"Display", "OptimalFramePacing", false);
|
||||
|
||||
MenuHeading(FSUI_CSTR("Rendering"));
|
||||
|
||||
|
||||
@@ -296,7 +296,7 @@ bool Host::CreateGPUDevice(RenderAPI api)
|
||||
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::GetEffectiveDisplaySyncMode(),
|
||||
SHADER_CACHE_VERSION, g_settings.gpu_use_debug_device, System::IsVSyncEffectivelyEnabled(),
|
||||
g_settings.gpu_threaded_presentation, exclusive_fullscreen_control,
|
||||
static_cast<GPUDevice::FeatureMask>(disabled_features), &error))
|
||||
{
|
||||
|
||||
@@ -248,10 +248,6 @@ void Settings::Load(SettingsInterface& si)
|
||||
display_scaling =
|
||||
ParseDisplayScaling(si.GetStringValue("Display", "Scaling", GetDisplayScalingName(DEFAULT_DISPLAY_SCALING)).c_str())
|
||||
.value_or(DEFAULT_DISPLAY_SCALING);
|
||||
display_sync_mode =
|
||||
ParseDisplaySyncMode(
|
||||
si.GetStringValue("Display", "SyncMode", GetDisplaySyncModeName(DEFAULT_DISPLAY_SYNC_MODE)).c_str())
|
||||
.value_or(DEFAULT_DISPLAY_SYNC_MODE);
|
||||
display_exclusive_fullscreen_control =
|
||||
ParseDisplayExclusiveFullscreenControl(
|
||||
si.GetStringValue("Display", "ExclusiveFullscreenControl",
|
||||
@@ -270,6 +266,8 @@ void Settings::Load(SettingsInterface& si)
|
||||
.value_or(DEFAULT_DISPLAY_SCREENSHOT_FORMAT);
|
||||
display_screenshot_quality = static_cast<u8>(
|
||||
std::clamp<u32>(si.GetUIntValue("Display", "ScreenshotQuality", DEFAULT_DISPLAY_SCREENSHOT_QUALITY), 1, 100));
|
||||
display_optimal_frame_pacing = si.GetBoolValue("Display", "OptimalFramePacing", false);
|
||||
display_vsync = si.GetBoolValue("Display", "VSync", false);
|
||||
display_force_4_3_for_24bit = si.GetBoolValue("Display", "Force4_3For24Bit", false);
|
||||
display_active_start_offset = static_cast<s16>(si.GetIntValue("Display", "ActiveStartOffset", 0));
|
||||
display_active_end_offset = static_cast<s16>(si.GetIntValue("Display", "ActiveEndOffset", 0));
|
||||
@@ -286,7 +284,6 @@ void Settings::Load(SettingsInterface& si)
|
||||
display_show_status_indicators = si.GetBoolValue("Display", "ShowStatusIndicators", true);
|
||||
display_show_inputs = si.GetBoolValue("Display", "ShowInputs", false);
|
||||
display_show_enhancements = si.GetBoolValue("Display", "ShowEnhancements", false);
|
||||
display_all_frames = si.GetBoolValue("Display", "DisplayAllFrames", false);
|
||||
display_stretch_vertically = si.GetBoolValue("Display", "StretchVertically", false);
|
||||
display_max_fps = si.GetFloatValue("Display", "MaxFPS", DEFAULT_DISPLAY_MAX_FPS);
|
||||
display_osd_scale = si.GetFloatValue("Display", "OSDScale", DEFAULT_OSD_SCALE);
|
||||
@@ -523,7 +520,8 @@ void Settings::Save(SettingsInterface& si, bool ignore_base) const
|
||||
si.SetStringValue("Display", "AspectRatio", GetDisplayAspectRatioName(display_aspect_ratio));
|
||||
si.SetStringValue("Display", "Alignment", GetDisplayAlignmentName(display_alignment));
|
||||
si.SetStringValue("Display", "Scaling", GetDisplayScalingName(display_scaling));
|
||||
si.SetStringValue("Display", "SyncMode", GetDisplaySyncModeName(display_sync_mode));
|
||||
si.SetBoolValue("Display", "OptimalFramePacing", display_optimal_frame_pacing);
|
||||
si.SetBoolValue("Display", "VSync", display_vsync);
|
||||
si.SetStringValue("Display", "ExclusiveFullscreenControl",
|
||||
GetDisplayExclusiveFullscreenControlName(display_exclusive_fullscreen_control));
|
||||
si.SetStringValue("Display", "ScreenshotMode", GetDisplayScreenshotModeName(display_screenshot_mode));
|
||||
@@ -547,7 +545,6 @@ void Settings::Save(SettingsInterface& si, bool ignore_base) const
|
||||
si.SetFloatValue("Display", "OSDScale", display_osd_scale);
|
||||
}
|
||||
|
||||
si.SetBoolValue("Display", "DisplayAllFrames", display_all_frames);
|
||||
si.SetBoolValue("Display", "StretchVertically", display_stretch_vertically);
|
||||
si.SetFloatValue("Display", "MaxFPS", display_max_fps);
|
||||
|
||||
@@ -1452,43 +1449,6 @@ const char* Settings::GetDisplayScalingDisplayName(DisplayScalingMode mode)
|
||||
return Host::TranslateToCString("DisplayScalingMode", s_display_scaling_display_names[static_cast<int>(mode)]);
|
||||
}
|
||||
|
||||
static constexpr const std::array s_display_sync_mode_names = {
|
||||
"Disabled",
|
||||
"VSync",
|
||||
"VSyncRelaxed",
|
||||
"VRR",
|
||||
};
|
||||
static constexpr const std::array s_display_sync_mode_display_names = {
|
||||
TRANSLATE_NOOP("Settings", "Disabled"),
|
||||
TRANSLATE_NOOP("Settings", "VSync"),
|
||||
TRANSLATE_NOOP("Settings", "Relaxed VSync"),
|
||||
TRANSLATE_NOOP("Settings", "VRR/FreeSync/GSync"),
|
||||
};
|
||||
|
||||
std::optional<DisplaySyncMode> Settings::ParseDisplaySyncMode(const char* str)
|
||||
{
|
||||
int index = 0;
|
||||
for (const char* name : s_display_sync_mode_names)
|
||||
{
|
||||
if (StringUtil::Strcasecmp(name, str) == 0)
|
||||
return static_cast<DisplaySyncMode>(index);
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
const char* Settings::GetDisplaySyncModeName(DisplaySyncMode mode)
|
||||
{
|
||||
return s_display_sync_mode_names[static_cast<size_t>(mode)];
|
||||
}
|
||||
|
||||
const char* Settings::GetDisplaySyncModeDisplayName(DisplaySyncMode mode)
|
||||
{
|
||||
return Host::TranslateToCString("Settings", s_display_sync_mode_display_names[static_cast<size_t>(mode)]);
|
||||
}
|
||||
|
||||
static constexpr const std::array s_display_exclusive_fullscreen_mode_names = {
|
||||
"Automatic",
|
||||
"Disallowed",
|
||||
|
||||
@@ -134,7 +134,6 @@ struct Settings
|
||||
DisplayAspectRatio display_aspect_ratio = DEFAULT_DISPLAY_ASPECT_RATIO;
|
||||
DisplayAlignment display_alignment = DEFAULT_DISPLAY_ALIGNMENT;
|
||||
DisplayScalingMode display_scaling = DEFAULT_DISPLAY_SCALING;
|
||||
DisplaySyncMode display_sync_mode = DEFAULT_DISPLAY_SYNC_MODE;
|
||||
DisplayExclusiveFullscreenControl display_exclusive_fullscreen_control = DEFAULT_DISPLAY_EXCLUSIVE_FULLSCREEN_CONTROL;
|
||||
DisplayScreenshotMode display_screenshot_mode = DEFAULT_DISPLAY_SCREENSHOT_MODE;
|
||||
DisplayScreenshotFormat display_screenshot_format = DEFAULT_DISPLAY_SCREENSHOT_FORMAT;
|
||||
@@ -145,6 +144,8 @@ struct Settings
|
||||
s16 display_active_end_offset = 0;
|
||||
s8 display_line_start_offset = 0;
|
||||
s8 display_line_end_offset = 0;
|
||||
bool display_optimal_frame_pacing : 1 = false;
|
||||
bool display_vsync : 1 = false;
|
||||
bool display_force_4_3_for_24bit : 1 = false;
|
||||
bool gpu_24bit_chroma_smoothing : 1 = false;
|
||||
bool display_show_osd_messages : 1 = true;
|
||||
@@ -158,7 +159,6 @@ struct Settings
|
||||
bool display_show_status_indicators : 1 = true;
|
||||
bool display_show_inputs : 1 = false;
|
||||
bool display_show_enhancements : 1 = false;
|
||||
bool display_all_frames : 1 = false;
|
||||
bool display_stretch_vertically : 1 = false;
|
||||
float display_osd_scale = 100.0f;
|
||||
float display_max_fps = DEFAULT_DISPLAY_MAX_FPS;
|
||||
@@ -416,10 +416,6 @@ struct Settings
|
||||
static const char* GetDisplayScalingName(DisplayScalingMode mode);
|
||||
static const char* GetDisplayScalingDisplayName(DisplayScalingMode mode);
|
||||
|
||||
static std::optional<DisplaySyncMode> ParseDisplaySyncMode(const char* str);
|
||||
static const char* GetDisplaySyncModeName(DisplaySyncMode mode);
|
||||
static const char* GetDisplaySyncModeDisplayName(DisplaySyncMode mode);
|
||||
|
||||
static std::optional<DisplayExclusiveFullscreenControl> ParseDisplayExclusiveFullscreenControl(const char* str);
|
||||
static const char* GetDisplayExclusiveFullscreenControlName(DisplayExclusiveFullscreenControl mode);
|
||||
static const char* GetDisplayExclusiveFullscreenControlDisplayName(DisplayExclusiveFullscreenControl mode);
|
||||
@@ -496,7 +492,6 @@ struct Settings
|
||||
static constexpr DisplayAspectRatio DEFAULT_DISPLAY_ASPECT_RATIO = DisplayAspectRatio::Auto;
|
||||
static constexpr DisplayAlignment DEFAULT_DISPLAY_ALIGNMENT = DisplayAlignment::Center;
|
||||
static constexpr DisplayScalingMode DEFAULT_DISPLAY_SCALING = DisplayScalingMode::BilinearSmooth;
|
||||
static constexpr DisplaySyncMode DEFAULT_DISPLAY_SYNC_MODE = DisplaySyncMode::Disabled;
|
||||
static constexpr DisplayExclusiveFullscreenControl DEFAULT_DISPLAY_EXCLUSIVE_FULLSCREEN_CONTROL =
|
||||
DisplayExclusiveFullscreenControl::Automatic;
|
||||
static constexpr DisplayScreenshotMode DEFAULT_DISPLAY_SCREENSHOT_MODE = DisplayScreenshotMode::ScreenResolution;
|
||||
|
||||
@@ -166,8 +166,8 @@ static const GameDatabase::Entry* s_running_game_entry = nullptr;
|
||||
static System::GameHash s_running_game_hash;
|
||||
static bool s_was_fast_booted;
|
||||
|
||||
static float s_throttle_frequency = 60.0f;
|
||||
static float s_target_speed = 1.0f;
|
||||
static float s_throttle_frequency = 0.0f;
|
||||
static float s_target_speed = 0.0f;
|
||||
static Common::Timer::Value s_frame_period = 0;
|
||||
static Common::Timer::Value s_next_frame_time = 0;
|
||||
static bool s_last_frame_skipped = false;
|
||||
@@ -177,8 +177,8 @@ static bool s_system_interrupted = false;
|
||||
static bool s_frame_step_request = false;
|
||||
static bool s_fast_forward_enabled = false;
|
||||
static bool s_turbo_enabled = false;
|
||||
static bool s_throttler_enabled = true;
|
||||
static bool s_display_all_frames = true;
|
||||
static bool s_throttler_enabled = false;
|
||||
static bool s_optimal_frame_pacing = false;
|
||||
static bool s_syncing_to_host = false;
|
||||
|
||||
static float s_average_frame_time_accumulator = 0.0f;
|
||||
@@ -1862,13 +1862,11 @@ void System::FrameDone()
|
||||
}
|
||||
|
||||
// TODO: Kick cmdbuffer early
|
||||
const DisplaySyncMode sync_mode = g_gpu_device->GetSyncMode();
|
||||
const bool throttle_after_present = (sync_mode == DisplaySyncMode::Disabled);
|
||||
if (!throttle_after_present && s_throttler_enabled && !IsExecutionInterrupted())
|
||||
if (s_optimal_frame_pacing && s_throttler_enabled && !IsExecutionInterrupted())
|
||||
Throttle();
|
||||
|
||||
const Common::Timer::Value current_time = Common::Timer::GetCurrentValue();
|
||||
if (current_time < s_next_frame_time || s_display_all_frames || s_last_frame_skipped)
|
||||
if (current_time < s_next_frame_time || s_syncing_to_host || s_optimal_frame_pacing || s_last_frame_skipped)
|
||||
{
|
||||
s_last_frame_skipped = !PresentDisplay(true);
|
||||
}
|
||||
@@ -1878,7 +1876,7 @@ void System::FrameDone()
|
||||
s_last_frame_skipped = true;
|
||||
}
|
||||
|
||||
if (throttle_after_present && s_throttler_enabled && !IsExecutionInterrupted())
|
||||
if (!s_optimal_frame_pacing && s_throttler_enabled && !IsExecutionInterrupted())
|
||||
Throttle();
|
||||
|
||||
// Input poll already done above
|
||||
@@ -1949,7 +1947,7 @@ void System::Throttle()
|
||||
// Use a spinwait if we undersleep for all platforms except android.. don't want to burn battery.
|
||||
// Linux also seems to do a much better job of waking up at the requested time.
|
||||
#if !defined(__linux__) && !defined(__ANDROID__)
|
||||
Common::Timer::SleepUntil(s_next_frame_time, g_settings.display_all_frames);
|
||||
Common::Timer::SleepUntil(s_next_frame_time, g_settings.display_optimal_frame_pacing);
|
||||
#else
|
||||
Common::Timer::SleepUntil(s_next_frame_time, false);
|
||||
#endif
|
||||
@@ -2648,7 +2646,7 @@ void System::UpdateSpeedLimiterState()
|
||||
g_settings.turbo_speed :
|
||||
(s_fast_forward_enabled ? g_settings.fast_forward_speed : g_settings.emulation_speed);
|
||||
s_throttler_enabled = (s_target_speed != 0.0f);
|
||||
s_display_all_frames = !s_throttler_enabled || g_settings.display_all_frames;
|
||||
s_optimal_frame_pacing = s_throttler_enabled && g_settings.display_optimal_frame_pacing;
|
||||
|
||||
s_syncing_to_host = false;
|
||||
if (g_settings.sync_to_host_refresh_rate && (g_settings.audio_stretch_mode != AudioStretchMode::Off) &&
|
||||
@@ -2667,14 +2665,10 @@ void System::UpdateSpeedLimiterState()
|
||||
}
|
||||
|
||||
// When syncing to host and using vsync, we don't need to sleep.
|
||||
if (s_syncing_to_host && s_display_all_frames)
|
||||
if (s_syncing_to_host && IsVSyncEffectivelyEnabled())
|
||||
{
|
||||
const DisplaySyncMode effective_sync_mode = GetEffectiveDisplaySyncMode();
|
||||
if (effective_sync_mode == DisplaySyncMode::VSync || effective_sync_mode == DisplaySyncMode::VSyncRelaxed)
|
||||
{
|
||||
Log_InfoPrintf("Using host vsync for throttling.");
|
||||
s_throttler_enabled = false;
|
||||
}
|
||||
Log_InfoPrintf("Using host vsync for throttling.");
|
||||
s_throttler_enabled = false;
|
||||
}
|
||||
|
||||
Log_VerbosePrintf("Target speed: %f%%", s_target_speed * 100.0f);
|
||||
@@ -2707,25 +2701,22 @@ void System::UpdateSpeedLimiterState()
|
||||
|
||||
void System::UpdateDisplaySync()
|
||||
{
|
||||
const DisplaySyncMode display_sync_mode = GetEffectiveDisplaySyncMode();
|
||||
const bool syncing_to_host_vsync =
|
||||
(s_syncing_to_host &&
|
||||
(display_sync_mode == DisplaySyncMode::VSync || display_sync_mode == DisplaySyncMode::VSyncRelaxed) &&
|
||||
s_display_all_frames);
|
||||
const bool vsync_enabled = IsVSyncEffectivelyEnabled();
|
||||
const bool syncing_to_host_vsync = (s_syncing_to_host && vsync_enabled);
|
||||
const float max_display_fps = (s_throttler_enabled || s_syncing_to_host) ? 0.0f : g_settings.display_max_fps;
|
||||
Log_VerbosePrintf("Display sync: %s%s", Settings::GetDisplaySyncModeDisplayName(display_sync_mode),
|
||||
syncing_to_host_vsync ? " (for throttling)" : "");
|
||||
Log_VerbosePrintf("Max display fps: %f (%s)", max_display_fps,
|
||||
s_display_all_frames ? "displaying all frames" : "skipping displaying frames when needed");
|
||||
Log_VerboseFmt("VSync: {}{}", vsync_enabled ? "Enabled" : "Disabled",
|
||||
syncing_to_host_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->SetSyncMode(display_sync_mode);
|
||||
g_gpu_device->SetVSyncEnabled(vsync_enabled);
|
||||
}
|
||||
|
||||
DisplaySyncMode System::GetEffectiveDisplaySyncMode()
|
||||
bool System::IsVSyncEffectivelyEnabled()
|
||||
{
|
||||
// Disable vsync if running outside 100%.
|
||||
return (IsValid() && IsRunningAtNonStandardSpeed()) ? DisplaySyncMode::Disabled : g_settings.display_sync_mode;
|
||||
return (g_settings.display_vsync && IsValid() && !IsRunningAtNonStandardSpeed());
|
||||
}
|
||||
|
||||
bool System::IsFastForwardEnabled()
|
||||
@@ -3780,12 +3771,12 @@ void System::CheckForSettingsChanges(const Settings& old_settings)
|
||||
DMA::SetHaltTicks(g_settings.dma_halt_ticks);
|
||||
|
||||
if (g_settings.audio_backend != old_settings.audio_backend ||
|
||||
g_settings.display_sync_mode != old_settings.display_sync_mode ||
|
||||
g_settings.increase_timer_resolution != old_settings.increase_timer_resolution ||
|
||||
g_settings.emulation_speed != old_settings.emulation_speed ||
|
||||
g_settings.fast_forward_speed != old_settings.fast_forward_speed ||
|
||||
g_settings.display_max_fps != old_settings.display_max_fps ||
|
||||
g_settings.display_all_frames != old_settings.display_all_frames ||
|
||||
g_settings.display_optimal_frame_pacing != old_settings.display_optimal_frame_pacing ||
|
||||
g_settings.display_vsync != old_settings.display_vsync ||
|
||||
g_settings.sync_to_host_refresh_rate != old_settings.sync_to_host_refresh_rate)
|
||||
{
|
||||
UpdateSpeedLimiterState();
|
||||
|
||||
@@ -453,7 +453,7 @@ void ToggleWidescreen();
|
||||
bool IsRunningAtNonStandardSpeed();
|
||||
|
||||
/// Returns true if vsync should be used.
|
||||
DisplaySyncMode GetEffectiveDisplaySyncMode();
|
||||
bool IsVSyncEffectivelyEnabled();
|
||||
|
||||
/// Quick switch between software and hardware rendering.
|
||||
void ToggleSoftwareRendering();
|
||||
|
||||
Reference in New Issue
Block a user