diff --git a/pcsx2/Config.h b/pcsx2/Config.h index f7ea39a61a..fd7964f2a6 100644 --- a/pcsx2/Config.h +++ b/pcsx2/Config.h @@ -279,6 +279,7 @@ struct Pcsx2Config bool FrameLimitEnable; bool FrameSkipEnable; bool VsyncEnable; + bool ManagedVsync; // The region mode controls the default Maximum/Minimum FPS settings and also // regulates the vsync rates (which in turn control the IOP's SPU2 tick sync and ensure @@ -305,6 +306,7 @@ struct Pcsx2Config OpEqu( FrameSkipEnable ) && OpEqu( FrameLimitEnable ) && OpEqu( VsyncEnable ) && + OpEqu( ManagedVsync ) && OpEqu( LimitScalar ) && OpEqu( FramerateNTSC ) && diff --git a/pcsx2/Pcsx2Config.cpp b/pcsx2/Pcsx2Config.cpp index 42312172fc..d2a9d9a74f 100644 --- a/pcsx2/Pcsx2Config.cpp +++ b/pcsx2/Pcsx2Config.cpp @@ -202,6 +202,7 @@ Pcsx2Config::GSOptions::GSOptions() FrameLimitEnable = true; FrameSkipEnable = false; VsyncEnable = false; + ManagedVsync = false; SynchronousMTGS = false; DisableOutput = false; @@ -227,6 +228,7 @@ void Pcsx2Config::GSOptions::LoadSave( IniInterface& ini ) IniEntry( FrameLimitEnable ); IniEntry( FrameSkipEnable ); IniEntry( VsyncEnable ); + IniEntry( ManagedVsync ); IniEntry( LimitScalar ); IniEntry( FramerateNTSC ); diff --git a/pcsx2/gui/AppMain.cpp b/pcsx2/gui/AppMain.cpp index af9318dbd6..af4f6a60c7 100644 --- a/pcsx2/gui/AppMain.cpp +++ b/pcsx2/gui/AppMain.cpp @@ -16,6 +16,7 @@ #include "PrecompiledHeader.h" #include "MainFrame.h" #include "GSFrame.h" +#include "GS.h" #include "AppSaveStates.h" #include "AppGameDatabase.h" #include "AppAccelerators.h" @@ -435,7 +436,63 @@ void Pcsx2App::LogicalVsync() // Update / Calculate framerate! FpsManager.DoFrame(); + + if (EmuConfig.GS.ManagedVsync) + { + if ( g_LimiterMode == Limit_Nominal && EmuConfig.GS.VsyncEnable && g_Conf->EmuOptions.GS.FrameLimitEnable ) + { + static bool last_enabled = 0; + static int too_slow = 0; + static int fast_enough = 0; + float fps = (float)FpsManager.GetFramerate(); + + if( gsRegionMode == Region_NTSC ) + { + if (fps < 59.0f ) { + too_slow++; + fast_enough = 0; + if (too_slow > 4 && last_enabled == true) + { + last_enabled = false; + GSsetVsync( 0 ); + } + } + else { + fast_enough++; + too_slow = 0; + if (fast_enough > 12 && last_enabled == false) + { + last_enabled = true; + GSsetVsync( 1 ); + } + } + } + else + { + if (fps < 49.2f ) { + too_slow++; + fast_enough = 0; + if (too_slow > 3 && last_enabled == true) + { + last_enabled = false; + GSsetVsync( 0 ); + } + } + else { + fast_enough++; + too_slow = 0; + if (fast_enough > 15 && last_enabled == false) + { + last_enabled = true; + GSsetVsync( 1 ); + } + } + } + } + else + GSsetVsync( 0 ); + } // Only call PADupdate here if we're using GSopen2. Legacy GSopen plugins have the // GS window belonging to the MTGS thread. if( (PADupdate != NULL) && (GSopen2 != NULL) && (wxGetApp().GetGsFramePtr() != NULL) ) diff --git a/pcsx2/gui/Panels/ConfigurationPanels.h b/pcsx2/gui/Panels/ConfigurationPanels.h index bba67522cf..0c57097fe6 100644 --- a/pcsx2/gui/Panels/ConfigurationPanels.h +++ b/pcsx2/gui/Panels/ConfigurationPanels.h @@ -267,6 +267,7 @@ namespace Panels pxCheckBox* m_check_CloseGS; pxCheckBox* m_check_SizeLock; pxCheckBox* m_check_VsyncEnable; + pxCheckBox* m_check_ManagedVsync; pxCheckBox* m_check_Fullscreen; pxCheckBox* m_check_ExclusiveFS; pxCheckBox* m_check_HideMouse; diff --git a/pcsx2/gui/Panels/GSWindowPanel.cpp b/pcsx2/gui/Panels/GSWindowPanel.cpp index e97b2bfc24..2e86bba465 100644 --- a/pcsx2/gui/Panels/GSWindowPanel.cpp +++ b/pcsx2/gui/Panels/GSWindowPanel.cpp @@ -45,14 +45,23 @@ Panels::GSWindowSettingsPanel::GSWindowSettingsPanel( wxWindow* parent ) m_check_HideMouse = new pxCheckBox( this, _("Always hide mouse cursor") ); m_check_CloseGS = new pxCheckBox( this, _("Hide window on suspend") ); m_check_Fullscreen = new pxCheckBox( this, _("Default to fullscreen mode on open") ); - m_check_VsyncEnable = new pxCheckBox( this, _("Wait for vsync on refresh") ); - m_check_DclickFullscreen = new pxCheckBox( this, _("Double-click Toggles Full-Screen mode") ); + m_check_VsyncEnable = new pxCheckBox( this, _("Wait for Vsync on refresh") ); + m_check_ManagedVsync = new pxCheckBox( this, _("Dynamically toggle Vsync depending on frame rate (read tooltip!)") ); + m_check_DclickFullscreen = new pxCheckBox( this, _("Double-click toggles fullscreen mode") ); m_check_ExclusiveFS = new pxCheckBox( this, _("Use exclusive fullscreen mode (if available)") ); m_check_VsyncEnable->SetToolTip( pxEt( "!ContextTip:Window:Vsync", L"Vsync eliminates screen tearing but typically has a big performance hit. " L"It usually only applies to fullscreen mode, and may not work with all GS plugins." ) ); + + m_check_ManagedVsync->SetToolTip( pxEt( "!ContextTip:Window:ManagedVsync", + L"Enables Vsync when the framerate is exactly at full speed. " + L"Should it fall below that, Vsync gets disabled to avoid further performance penalties. " + L"Note: This currently only works well with GSdx as GS plugin and with it configured to use DX10/11 hardware rendering. " + L"Any other plugin or rendering mode will either ignore it or produce a black frame that blinks whenever the mode switches. " + L"It also requires Vsync to be enabled." + ) ); m_check_HideMouse->SetToolTip( pxEt( "!ContextTip:Window:HideMouse", L"Check this to force the mouse cursor invisible inside the GS window; useful if using " @@ -100,9 +109,11 @@ Panels::GSWindowSettingsPanel::GSWindowSettingsPanel( wxWindow* parent ) *this += m_check_Fullscreen; *this += m_check_DclickFullscreen;; - *this += m_check_ExclusiveFS; + *this += new wxStaticLine( this ) | StdExpand(); + *this += m_check_VsyncEnable; + *this += m_check_ManagedVsync; wxBoxSizer* centerSizer = new wxBoxSizer( wxVERTICAL ); *centerSizer += GetSizer() | pxCenter; @@ -130,6 +141,7 @@ void Panels::GSWindowSettingsPanel::ApplyConfigToGui( AppConfig& configToApply, m_combo_AspectRatio ->SetSelection( (int)conf.AspectRatio ); m_check_VsyncEnable ->SetValue( configToApply.EmuOptions.GS.VsyncEnable ); + m_check_ManagedVsync->SetValue( configToApply.EmuOptions.GS.ManagedVsync ); m_check_DclickFullscreen ->SetValue ( conf.IsToggleFullscreenOnDoubleClick ); @@ -138,6 +150,7 @@ void Panels::GSWindowSettingsPanel::ApplyConfigToGui( AppConfig& configToApply, } m_check_VsyncEnable->Enable(!configToApply.EnablePresets); + m_check_ManagedVsync->Enable(!configToApply.EnablePresets); } void Panels::GSWindowSettingsPanel::Apply() @@ -153,6 +166,7 @@ void Panels::GSWindowSettingsPanel::Apply() appconf.AspectRatio = (AspectRatioType)m_combo_AspectRatio->GetSelection(); gsconf.VsyncEnable = m_check_VsyncEnable->GetValue(); + gsconf.ManagedVsync = m_check_ManagedVsync->GetValue(); appconf.IsToggleFullscreenOnDoubleClick = m_check_DclickFullscreen->GetValue();