GLInterface: Use EXT_swap_control or MESA_swap_control over SGI

The SGI extension does not define calling SwapInterval with a parameter
of zero as valid. It was just lucky that drivers interpreted this as
vsync off. The EXT_swap_control extension defines zero as a valid value.

Mesa does not appear to support the EXT variant, so we fall back to
MESA_swap_control here, which also supports zero.
This commit is contained in:
Stenzek 2018-03-26 22:09:22 +10:00
parent 97e4d3d56f
commit c82be53d5c

View File

@ -13,10 +13,12 @@
typedef GLXContext (*PFNGLXCREATECONTEXTATTRIBSPROC)(Display*, GLXFBConfig, GLXContext, Bool, typedef GLXContext (*PFNGLXCREATECONTEXTATTRIBSPROC)(Display*, GLXFBConfig, GLXContext, Bool,
const int*); const int*);
typedef int (*PFNGLXSWAPINTERVALSGIPROC)(int interval); typedef void (*PFNGLXSWAPINTERVALEXTPROC)(Display*, GLXDrawable, int);
typedef int (*PFNGLXSWAPINTERVALMESAPROC)(unsigned int);
static PFNGLXCREATECONTEXTATTRIBSPROC glXCreateContextAttribs = nullptr; static PFNGLXCREATECONTEXTATTRIBSPROC glXCreateContextAttribs = nullptr;
static PFNGLXSWAPINTERVALSGIPROC glXSwapIntervalSGI = nullptr; static PFNGLXSWAPINTERVALEXTPROC glXSwapIntervalEXTPtr = nullptr;
static PFNGLXSWAPINTERVALMESAPROC glXSwapIntervalMESAPtr = nullptr;
static PFNGLXCREATEGLXPBUFFERSGIXPROC glXCreateGLXPbufferSGIX = nullptr; static PFNGLXCREATEGLXPBUFFERSGIXPROC glXCreateGLXPbufferSGIX = nullptr;
static PFNGLXDESTROYGLXPBUFFERSGIXPROC glXDestroyGLXPbufferSGIX = nullptr; static PFNGLXDESTROYGLXPBUFFERSGIXPROC glXDestroyGLXPbufferSGIX = nullptr;
@ -30,11 +32,18 @@ static int ctxErrorHandler(Display* dpy, XErrorEvent* ev)
void cInterfaceGLX::SwapInterval(int Interval) void cInterfaceGLX::SwapInterval(int Interval)
{ {
if (glXSwapIntervalSGI && m_has_handle) if (!m_has_handle)
glXSwapIntervalSGI(Interval); return;
// Try EXT_swap_control, then MESA_swap_control.
if (glXSwapIntervalEXTPtr)
glXSwapIntervalEXTPtr(dpy, win, Interval);
else if (glXSwapIntervalMESAPtr)
glXSwapIntervalMESAPtr(static_cast<unsigned int>(Interval));
else else
ERROR_LOG(VIDEO, "No support for SwapInterval (framerate clamped to monitor refresh rate)."); ERROR_LOG(VIDEO, "No support for SwapInterval (framerate clamped to monitor refresh rate).");
} }
void* cInterfaceGLX::GetFuncAddress(const std::string& name) void* cInterfaceGLX::GetFuncAddress(const std::string& name)
{ {
return (void*)glXGetProcAddress((const GLubyte*)name.c_str()); return (void*)glXGetProcAddress((const GLubyte*)name.c_str());
@ -152,21 +161,34 @@ bool cInterfaceGLX::Create(void* window_handle, bool stereo, bool core)
return false; return false;
} }
glXSwapIntervalEXTPtr = nullptr;
glXSwapIntervalMESAPtr = nullptr;
glXCreateGLXPbufferSGIX = nullptr;
glXDestroyGLXPbufferSGIX = nullptr;
m_supports_pbuffer = false;
std::string tmp; std::string tmp;
std::istringstream buffer(glXQueryExtensionsString(dpy, screen)); std::istringstream buffer(glXQueryExtensionsString(dpy, screen));
while (buffer >> tmp) while (buffer >> tmp)
{ {
if (tmp == "GLX_SGIX_pbuffer") if (tmp == "GLX_SGIX_pbuffer")
m_supports_pbuffer = true;
}
if (m_supports_pbuffer)
{ {
// Get the function pointers we require glXCreateGLXPbufferSGIX = reinterpret_cast<PFNGLXCREATEGLXPBUFFERSGIXPROC>(
glXCreateGLXPbufferSGIX = GetFuncAddress("glXCreateGLXPbufferSGIX"));
(PFNGLXCREATEGLXPBUFFERSGIXPROC)GetFuncAddress("glXCreateGLXPbufferSGIX"); glXDestroyGLXPbufferSGIX = reinterpret_cast<PFNGLXDESTROYGLXPBUFFERSGIXPROC>(
glXDestroyGLXPbufferSGIX = GetFuncAddress("glXDestroyGLXPbufferSGIX"));
(PFNGLXDESTROYGLXPBUFFERSGIXPROC)GetFuncAddress("glXDestroyGLXPbufferSGIX"); m_supports_pbuffer = glXCreateGLXPbufferSGIX && glXDestroyGLXPbufferSGIX;
}
else if (tmp == "GLX_EXT_swap_control")
{
glXSwapIntervalEXTPtr =
reinterpret_cast<PFNGLXSWAPINTERVALEXTPROC>(GetFuncAddress("glXSwapIntervalEXT"));
}
else if (tmp == "GLX_MESA_swap_control")
{
glXSwapIntervalMESAPtr =
reinterpret_cast<PFNGLXSWAPINTERVALMESAPROC>(GetFuncAddress("glXSwapIntervalMESA"));
}
} }
if (!CreateWindowSurface()) if (!CreateWindowSurface())
@ -267,14 +289,7 @@ void cInterfaceGLX::DestroyWindowSurface()
bool cInterfaceGLX::MakeCurrent() bool cInterfaceGLX::MakeCurrent()
{ {
bool success = glXMakeCurrent(dpy, win, ctx); return glXMakeCurrent(dpy, win, ctx);
if (success && !glXSwapIntervalSGI)
{
// load this function based on the current bound context
glXSwapIntervalSGI =
(PFNGLXSWAPINTERVALSGIPROC)GLInterface->GetFuncAddress("glXSwapIntervalSGI");
}
return success;
} }
bool cInterfaceGLX::ClearCurrent() bool cInterfaceGLX::ClearCurrent()