Merge pull request #2000 from PCSX2/greg/vsync-take2

Greg/vsync take2
This commit is contained in:
Gregory Hainaut 2017-08-05 11:44:41 +02:00 committed by GitHub
commit 41bfb6e80a
16 changed files with 155 additions and 73 deletions

View File

@ -63,6 +63,13 @@ enum GamefixId
GamefixId_COUNT
};
enum class VsyncMode
{
Off,
On,
Adaptive,
};
// Template function for casting enumerations to their underlying type
template <typename Enumeration>
typename std::underlying_type<Enumeration>::type enum_cast(Enumeration E)
@ -291,9 +298,9 @@ struct Pcsx2Config
bool DisableOutput;
int VsyncQueueSize;
bool FrameLimitEnable;
bool FrameSkipEnable;
bool VsyncEnable;
bool FrameLimitEnable;
bool FrameSkipEnable;
VsyncMode VsyncEnable;
int FramesToDraw; // number of consecutive frames (fields) to render
int FramesToSkip; // number of consecutive frames (fields) to skip
@ -305,6 +312,8 @@ struct Pcsx2Config
GSOptions();
void LoadSave( IniInterface& conf );
int GetVsync() const;
bool operator ==( const GSOptions& right ) const
{
return

View File

@ -203,7 +203,7 @@ void SysMtgsThread::OpenPlugin()
result = GSopen( (void*)pDsp, "PCSX2", renderswitch ? 2 : 1 );
GSsetVsync(EmuConfig.GS.FrameLimitEnable && EmuConfig.GS.VsyncEnable);
GSsetVsync(EmuConfig.GS.GetVsync());
if( result != 0 )
{

View File

@ -20,6 +20,7 @@
#include "Utilities/IniInterface.h"
#include "Config.h"
#include "GS.h"
#include "gui/GSFrame.h"
void TraceLogFilters::LoadSave( IniInterface& ini )
{
@ -200,7 +201,7 @@ Pcsx2Config::GSOptions::GSOptions()
{
FrameLimitEnable = true;
FrameSkipEnable = false;
VsyncEnable = false;
VsyncEnable = VsyncMode::Off;
SynchronousMTGS = false;
DisableOutput = false;
@ -224,7 +225,7 @@ void Pcsx2Config::GSOptions::LoadSave( IniInterface& ini )
IniEntry( FrameLimitEnable );
IniEntry( FrameSkipEnable );
IniEntry( VsyncEnable );
ini.EnumEntry( L"VsyncEnable", VsyncEnable, NULL, VsyncEnable );
IniEntry( LimitScalar );
IniEntry( FramerateNTSC );
@ -234,6 +235,22 @@ void Pcsx2Config::GSOptions::LoadSave( IniInterface& ini )
IniEntry( FramesToSkip );
}
int Pcsx2Config::GSOptions::GetVsync() const
{
if (g_LimiterMode == Limit_Turbo)
return 0;
// D3D only support a boolean state. OpenGL waits a number of vsync
// interrupt (negative value for late vsync).
switch (VsyncEnable) {
case VsyncMode::Adaptive: return -1;
case VsyncMode::Off: return 0;
case VsyncMode::On: return 1;
default: return 0;
}
}
const wxChar *const tbl_GamefixNames[] =
{
L"VuAddSub",

View File

@ -359,9 +359,8 @@ bool AppCorePlugins::OpenPlugin_GS()
bool retval = _parent::OpenPlugin_GS();
if( g_LimiterMode == Limit_Turbo )
GSsetVsync( false );
GSsetVsync(EmuConfig.GS.GetVsync());
return retval;
}

View File

@ -356,7 +356,7 @@ static void _ApplySettings( const Pcsx2Config& src, Pcsx2Config& fixup )
if( overrides.ProfilingMode )
{
fixup.GS.FrameLimitEnable = false;
fixup.GS.VsyncEnable = false;
fixup.GS.VsyncEnable = VsyncMode::Off;
}
wxString gameCRC;

View File

@ -91,7 +91,6 @@ namespace Implementations
}
else if( g_LimiterMode == Limit_Turbo )
{
GSsetVsync( g_Conf->EmuOptions.GS.VsyncEnable );
g_LimiterMode = Limit_Nominal;
if ( g_Conf->Framerate.SkipOnLimit)
@ -107,7 +106,6 @@ namespace Implementations
}
else
{
GSsetVsync( false );
g_LimiterMode = Limit_Turbo;
if ( g_Conf->Framerate.SkipOnTurbo)
@ -121,7 +119,11 @@ namespace Implementations
g_Conf->EmuOptions.GS.FrameSkipEnable = false;
}
}
gsUpdateFrequency(g_Conf->EmuOptions);
GSsetVsync(g_Conf->EmuOptions.GS.GetVsync());
pauser.AllowResume();
}
@ -134,7 +136,6 @@ namespace Implementations
// out a better consistency approach... -air
ScopedCoreThreadPause pauser;
GSsetVsync( g_Conf->EmuOptions.GS.VsyncEnable );
if( g_LimiterMode == Limit_Slomo )
{
g_LimiterMode = Limit_Nominal;
@ -146,7 +147,11 @@ namespace Implementations
OSDlog( Color_StrongRed, true, "(FrameLimiter) SlowMotion ENABLED." );
g_Conf->EmuOptions.GS.FrameLimitEnable = true;
}
gsUpdateFrequency(g_Conf->EmuOptions);
GSsetVsync(g_Conf->EmuOptions.GS.GetVsync());
pauser.AllowResume();
}
@ -154,8 +159,17 @@ namespace Implementations
{
ScopedCoreThreadPause pauser;
g_Conf->EmuOptions.GS.FrameLimitEnable = !g_Conf->EmuOptions.GS.FrameLimitEnable;
GSsetVsync( g_Conf->EmuOptions.GS.FrameLimitEnable && g_Conf->EmuOptions.GS.VsyncEnable );
OSDlog( Color_StrongRed, true, "(FrameLimiter) %s.", g_Conf->EmuOptions.GS.FrameLimitEnable ? "ENABLED" : "DISABLED" );
// Turbo/Slowmo don't make sense when framelimiter is toggled
g_LimiterMode = Limit_Nominal;
// Disable Vsync when frame limited is disabled
if( g_Conf->EmuOptions.GS.FrameLimitEnable )
GSsetVsync(g_Conf->EmuOptions.GS.GetVsync());
else
GSsetVsync(0);
pauser.AllowResume();
}

View File

@ -267,6 +267,7 @@ namespace Panels
{
protected:
wxComboBox* m_combo_AspectRatio;
wxComboBox* m_combo_vsync;
wxTextCtrl* m_text_Zoom;

View File

@ -32,11 +32,22 @@ Panels::GSWindowSettingsPanel::GSWindowSettingsPanel( wxWindow* parent )
_("Widescreen (16:9)")
};
// Warning must match the order of the VsyncMode Enum
const wxString vsync_label[] =
{
_("Disabled"),
_("Standard"),
_("Adaptive"),
};
m_text_Zoom = CreateNumericalTextCtrl( this, 5 );
m_combo_AspectRatio = new wxComboBox( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize,
ArraySize(aspect_ratio_labels), aspect_ratio_labels, wxCB_READONLY );
m_combo_vsync = new wxComboBox( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize,
ArraySize(vsync_label), vsync_label, wxCB_READONLY );
m_text_WindowWidth = CreateNumericalTextCtrl( this, 5 );
m_text_WindowHeight = CreateNumericalTextCtrl( this, 5 );
@ -47,7 +58,6 @@ Panels::GSWindowSettingsPanel::GSWindowSettingsPanel( wxWindow* parent )
m_check_HideMouse = new pxCheckBox( this, _("Always hide mouse cursor") );
m_check_CloseGS = new pxCheckBox( this, _("Hide window when paused") );
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 fullscreen mode") );
m_check_AspectRatioSwitch = new pxCheckBox(this, _("Switch to 4:3 aspect ratio when an FMV plays"));
//m_check_ExclusiveFS = new pxCheckBox( this, _("Use exclusive fullscreen mode (if available)") );
@ -55,7 +65,7 @@ Panels::GSWindowSettingsPanel::GSWindowSettingsPanel( wxWindow* parent )
m_text_Zoom->SetToolTip( pxEt( L"Zoom = 100: Fit the entire image to the window without any cropping.\nAbove/Below 100: Zoom In/Out\n0: Automatic-Zoom-In untill the black-bars are gone (Aspect ratio is kept, some of the image goes out of screen).\n NOTE: Some games draw their own black-bars, which will not be removed with '0'.\n\nKeyboard: CTRL + NUMPAD-PLUS: Zoom-In, CTRL + NUMPAD-MINUS: Zoom-Out, CTRL + NUMPAD-*: Toggle 100/0"
) );
m_check_VsyncEnable->SetToolTip( pxEt( L"Vsync eliminates screen tearing but typically has a big performance hit. It usually only applies to fullscreen mode, and may not work with all GS plugins."
m_combo_vsync->SetToolTip( pxEt( L"Vsync eliminates screen tearing but typically has a big performance hit. It usually only applies to fullscreen mode, and may not work with all GS plugins."
) );
m_check_HideMouse->SetToolTip( pxEt( L"Check this to force the mouse cursor invisible inside the GS window; useful if using the mouse as a primary control device for gaming. By default the mouse auto-hides after 2 seconds of inactivity."
@ -91,6 +101,11 @@ Panels::GSWindowSettingsPanel::GSWindowSettingsPanel( wxWindow* parent )
s_AspectRatio += Label(_("Zoom:")) | StdExpand();
s_AspectRatio += m_text_Zoom;
wxFlexGridSizer& s_vsync( *new wxFlexGridSizer( 2, StdPadding, StdPadding ) );
s_vsync.AddGrowableCol( 1 );
s_vsync += Label(_("Wait for Vsync on refresh:")) | pxMiddle;
s_vsync += m_combo_vsync | pxExpand;
*this += s_AspectRatio | StdExpand();
*this += m_check_SizeLock;
@ -105,7 +120,7 @@ Panels::GSWindowSettingsPanel::GSWindowSettingsPanel( wxWindow* parent )
//*this += m_check_ExclusiveFS;
*this += new wxStaticLine( this ) | StdExpand();
*this += m_check_VsyncEnable;
*this += s_vsync;
wxBoxSizer* centerSizer = new wxBoxSizer( wxVERTICAL );
*centerSizer += GetSizer() | pxCenter;
@ -140,8 +155,8 @@ void Panels::GSWindowSettingsPanel::ApplyConfigToGui( AppConfig& configToApply,
m_text_WindowHeight ->ChangeValue( wxsFormat( L"%d", conf.WindowSize.GetHeight() ) );
}
m_check_VsyncEnable->SetValue( configToApply.EmuOptions.GS.VsyncEnable );
m_check_VsyncEnable->Enable ( !configToApply.EnablePresets );//grayed-out when presets are enabled
m_combo_vsync->SetSelection(enum_cast(configToApply.EmuOptions.GS.VsyncEnable));
m_combo_vsync->Enable( !configToApply.EnablePresets );//grayed-out when presets are enabled
}
void Panels::GSWindowSettingsPanel::Apply()
@ -157,7 +172,7 @@ void Panels::GSWindowSettingsPanel::Apply()
appconf.AspectRatio = (AspectRatioType)m_combo_AspectRatio->GetSelection();
appconf.Zoom = Fixed100::FromString( m_text_Zoom->GetValue() );
gsconf.VsyncEnable = m_check_VsyncEnable->GetValue();
gsconf.VsyncEnable = static_cast<VsyncMode>(m_combo_vsync->GetSelection());
appconf.IsToggleFullscreenOnDoubleClick = m_check_DclickFullscreen->GetValue();
appconf.IsToggleAspectRatioSwitch = m_check_AspectRatioSwitch->GetValue();

View File

@ -183,3 +183,21 @@ void GSWndGL::PopulateGlFunction()
// renderer/device
GLLoader::check_gl_requirements();
}
void GSWndGL::FullContextInit()
{
CreateContext(3, 3);
AttachContext();
PopulateGlFunction();
PopulateWndGlFunction();
}
void GSWndGL::SetVSync(int vsync)
{
if (!HasLateVsyncSupport() && vsync < 0)
m_vsync = -vsync; // Late vsync not supported, fallback to standard vsync
else
m_vsync = vsync;
SetSwapInterval(m_vsync);
}

View File

@ -60,11 +60,19 @@ class GSWndGL : public GSWnd
{
protected:
bool m_ctx_attached;
int m_vsync;
bool IsContextAttached() const { return m_ctx_attached; }
void PopulateGlFunction();
virtual void PopulateWndGlFunction() = 0;
void FullContextInit();
virtual void CreateContext(int major, int minor) = 0;
virtual void SetSwapInterval(int vsync) = 0;
virtual bool HasLateVsyncSupport() = 0;
public:
GSWndGL() : m_ctx_attached(false) {};
GSWndGL() : m_ctx_attached(false), m_vsync(0) {};
virtual ~GSWndGL() {};
virtual bool Create(const string& title, int w, int h) = 0;
@ -84,7 +92,5 @@ public:
virtual void Hide() = 0;
virtual void HideFrame() = 0;
virtual void Flip() = 0;
virtual void SetVSync(int vsync) = 0;
void PopulateGlFunction();
virtual void SetVSync(int vsync) final;
};

View File

@ -153,6 +153,10 @@ void GSWndEGL::DetachContext()
}
}
void GSWndEGL::PopulateWndGlFunction()
{
}
void GSWndEGL::BindAPI()
{
eglBindAPI(EGL_OPENGL_API);
@ -171,11 +175,7 @@ bool GSWndEGL::Attach(void* handle, bool managed)
OpenEGLDisplay();
CreateContext(3, 3);
AttachContext();
PopulateGlFunction();
FullContextInit();
return true;
}
@ -209,11 +209,7 @@ bool GSWndEGL::Create(const string& title, int w, int h)
m_native_window = CreateNativeWindow(w, h);
CreateContext(3, 3);
AttachContext();
PopulateGlFunction();
FullContextInit();
return true;
}
@ -239,7 +235,7 @@ GSVector4i GSWndEGL::GetClientRect()
return GSVector4i(0, 0, w, h);
}
void GSWndEGL::SetVSync(int vsync)
void GSWndEGL::SetSwapInterval(int vsync)
{
// 0 -> disable vsync
// n -> wait n frame

View File

@ -38,9 +38,13 @@ class GSWndEGL : public GSWndGL
int m_platform;
void PopulateWndGlFunction();
void CreateContext(int major, int minor);
void BindAPI();
void SetSwapInterval(int vsync) final;
bool HasLateVsyncSupport() final { return false; }
void OpenEGLDisplay();
void CloseEGLDisplay();
@ -65,7 +69,6 @@ public:
void* GetProcAddress(const char* name, bool opt = false) final;
void Flip() final;
void SetVSync(int vsync) final;
// Deprecated API
void Show() final {};

View File

@ -24,7 +24,7 @@
#if defined(__unix__)
GSWndOGL::GSWndOGL()
: m_NativeWindow(0), m_NativeDisplay(NULL), m_context(0), m_swapinterval_ext(NULL), m_swapinterval_mesa(NULL)
: m_NativeWindow(0), m_NativeDisplay(nullptr), m_context(0), m_has_late_vsync(false), m_swapinterval_ext(nullptr), m_swapinterval_mesa(nullptr)
{
}
@ -122,6 +122,15 @@ void GSWndOGL::DetachContext()
}
}
void GSWndOGL::PopulateWndGlFunction()
{
m_swapinterval_ext = (PFNGLXSWAPINTERVALEXTPROC) glXGetProcAddress((const GLubyte*) "glXSwapIntervalEXT");
m_swapinterval_mesa = (PFNGLXSWAPINTERVALMESAPROC)glXGetProcAddress((const GLubyte*) "glXSwapIntervalMESA");
const char* ext = glXQueryExtensionsString(m_NativeDisplay, DefaultScreen(m_NativeDisplay));
m_has_late_vsync = m_swapinterval_ext && ext && strstr(ext, "GLX_EXT_swap_control");
}
bool GSWndOGL::Attach(void* handle, bool managed)
{
m_NativeWindow = *(Window*)handle;
@ -129,14 +138,7 @@ bool GSWndOGL::Attach(void* handle, bool managed)
m_NativeDisplay = XOpenDisplay(NULL);
CreateContext(3, 3);
AttachContext();
m_swapinterval_ext = (PFNGLXSWAPINTERVALEXTPROC) glXGetProcAddress((const GLubyte*) "glXSwapIntervalEXT");
m_swapinterval_mesa = (PFNGLXSWAPINTERVALMESAPROC)glXGetProcAddress((const GLubyte*) "glXSwapIntervalMESA");
PopulateGlFunction();
FullContextInit();
return true;
}
@ -175,14 +177,7 @@ bool GSWndOGL::Create(const string& title, int w, int h)
if (m_NativeWindow == 0)
throw GSDXRecoverableError();
CreateContext(3, 3);
AttachContext();
m_swapinterval_ext = (PFNGLXSWAPINTERVALEXTPROC) glXGetProcAddress((const GLubyte*) "glXSwapIntervalEXT");
m_swapinterval_mesa = (PFNGLXSWAPINTERVALMESAPROC)glXGetProcAddress((const GLubyte*) "glXSwapIntervalMESA");
PopulateGlFunction();
FullContextInit();
return true;
}
@ -243,7 +238,7 @@ bool GSWndOGL::SetWindowText(const char* title)
return true;
}
void GSWndOGL::SetVSync(int vsync)
void GSWndOGL::SetSwapInterval(int vsync)
{
// m_swapinterval uses an integer as parameter
// 0 -> disable vsync

View File

@ -30,12 +30,17 @@ class GSWndOGL final : public GSWndGL
Window m_NativeWindow;
Display* m_NativeDisplay;
GLXContext m_context;
bool m_has_late_vsync;
PFNGLXSWAPINTERVALEXTPROC m_swapinterval_ext;
PFNGLXSWAPINTERVALMESAPROC m_swapinterval_mesa;
void PopulateWndGlFunction();
void CreateContext(int major, int minor);
void SetSwapInterval(int vsync);
bool HasLateVsyncSupport() { return m_has_late_vsync; }
public:
GSWndOGL();
virtual ~GSWndOGL() {};
@ -57,7 +62,6 @@ public:
void Hide();
void HideFrame();
void Flip();
void SetVSync(int vsync);
};
#endif

View File

@ -40,7 +40,7 @@ static void win_error(const char* msg, bool fatal = true)
GSWndWGL::GSWndWGL()
: m_NativeWindow(NULL), m_NativeDisplay(NULL), m_context(NULL)
: m_NativeWindow(nullptr), m_NativeDisplay(nullptr), m_context(nullptr), m_has_late_vsync(false)
{
}
@ -139,6 +139,20 @@ void GSWndWGL::DetachContext()
}
}
void GSWndWGL::PopulateWndGlFunction()
{
m_swapinterval = (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress("wglSwapIntervalEXT");
// To ease the process, extension management is itself an extension. Clever isn't it!
PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)wglGetProcAddress("wglGetExtensionsStringARB");
if (wglGetExtensionsStringARB) {
const char* ext = wglGetExtensionsStringARB(m_NativeDisplay);
m_has_late_vsync = m_swapinterval && ext && strstr(ext, "WGL_EXT_swap_control_tear");
} else {
m_has_late_vsync = false;
}
}
bool GSWndWGL::Attach(void* handle, bool managed)
{
m_NativeWindow = (HWND)handle;
@ -146,13 +160,7 @@ bool GSWndWGL::Attach(void* handle, bool managed)
OpenWGLDisplay();
CreateContext(3, 3);
AttachContext();
m_swapinterval = (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress("wglSwapIntervalEXT");
PopulateGlFunction();
FullContextInit();
UpdateWindow(m_NativeWindow);
@ -288,16 +296,9 @@ bool GSWndWGL::Create(const string& title, int w, int h)
OpenWGLDisplay();
CreateContext(3, 3);
AttachContext();
m_swapinterval = (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress("wglSwapIntervalEXT");
PopulateGlFunction();
FullContextInit();
return true;
}
//Same as DX
@ -323,7 +324,7 @@ void* GSWndWGL::GetProcAddress(const char* name, bool opt)
//TODO: check extensions supported or not
//FIXME : extension allocation
void GSWndWGL::SetVSync(int vsync)
void GSWndWGL::SetSwapInterval(int vsync)
{
// m_swapinterval uses an integer as parameter
// 0 -> disable vsync

View File

@ -28,14 +28,19 @@ class GSWndWGL : public GSWndGL
HWND m_NativeWindow;
HDC m_NativeDisplay;
HGLRC m_context;
bool m_has_late_vsync;
PFNWGLSWAPINTERVALEXTPROC m_swapinterval;
void PopulateWndGlFunction();
void CreateContext(int major, int minor);
void CloseWGLDisplay();
void OpenWGLDisplay();
void SetSwapInterval(int vsync);
bool HasLateVsyncSupport() { return m_has_late_vsync; }
static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
public:
@ -59,7 +64,6 @@ public:
void Hide();
void HideFrame();
void Flip();
void SetVSync(int vsync);
};
#endif