From 97bafaa7b8157c3ca0fe7bc5ce36aea9fe14d9b9 Mon Sep 17 00:00:00 2001 From: JW Date: Fri, 24 Jan 2020 14:12:38 -0800 Subject: [PATCH] Check for GLX vblank extensions more properly. Previously, the code checked for an extension by checking if the pointer returned from glXGetProcAddress was NULL or not. But in truth, you can get a non-NULL pointer even if that extension is not supported. Now, we parse the glXQueryExtensionsString() results. GLFW code that does similar checks, for reference: https://github.com/glfw/glfw/blob/51bb76c7c3de934b2dd3affcdc297a32e4817835/src/glx_context.c#L208 fixes #1367 --- src/glcontext_glx.cpp | 62 +++++++++++++++++++++++++++++++++---------- 1 file changed, 48 insertions(+), 14 deletions(-) diff --git a/src/glcontext_glx.cpp b/src/glcontext_glx.cpp index 60bd7c0b1..2af41fdeb 100644 --- a/src/glcontext_glx.cpp +++ b/src/glcontext_glx.cpp @@ -57,6 +57,32 @@ namespace bgfx { namespace gl GLXContext m_context; }; + static bool haveGlxExtension(const char* _ext, const char* _extList) + { + // _extList is assumed to be a space-separated, null-terminated list of + // extension names, and no extension name ever contains a space. + const char* end = _extList + bx::strLen(_extList); + const char* searchStart = _extList; + for(;;) + { + bx::StringView found = bx::strFind(searchStart, _ext); + if (found.isEmpty()) + { + return false; + } + + // We found the substring, but need an exact match, with a word + // boundary at both the front and back of the found spot. + if ((found.getPtr() == _extList || *(found.getPtr() - 1) == ' ') + && (found.getTerm() == end || *found.getTerm() == ' ')) + { + return true; + } + // else, keep searching + searchStart = found.getTerm(); + } + } + void GlContext::create(uint32_t _width, uint32_t _height) { BX_UNUSED(_width, _height); @@ -196,27 +222,35 @@ namespace bgfx { namespace gl glXMakeCurrent(m_display, (::Window)g_platformData.nwh, m_context); m_current = NULL; - glXSwapIntervalEXT = (PFNGLXSWAPINTERVALEXTPROC)glXGetProcAddress( (const GLubyte*)"glXSwapIntervalEXT"); - if (NULL != glXSwapIntervalEXT) + const char* extensions = glXQueryExtensionsString(m_display, DefaultScreen(m_display)); + if (NULL != extensions) { - BX_TRACE("Using glXSwapIntervalEXT."); - glXSwapIntervalEXT(m_display, (::Window)g_platformData.nwh, 0); - } - else - { - glXSwapIntervalMESA = (PFNGLXSWAPINTERVALMESAPROC)glXGetProcAddress( (const GLubyte*)"glXSwapIntervalMESA"); - if (NULL != glXSwapIntervalMESA) - { - BX_TRACE("Using glXSwapIntervalMESA."); - glXSwapIntervalMESA(0); + bool foundSwapControl = false; + if (haveGlxExtension("GLX_EXT_swap_control", extensions)) { + glXSwapIntervalEXT = (PFNGLXSWAPINTERVALEXTPROC)glXGetProcAddress( (const GLubyte*)"glXSwapIntervalEXT"); + if (NULL != glXSwapIntervalEXT) + { + BX_TRACE("Using glXSwapIntervalEXT."); + glXSwapIntervalEXT(m_display, (::Window)g_platformData.nwh, 0); + foundSwapControl = true; + } } - else - { + if (!foundSwapControl && haveGlxExtension("GLX_MESA_swap_control", extensions)) { + glXSwapIntervalMESA = (PFNGLXSWAPINTERVALMESAPROC)glXGetProcAddress( (const GLubyte*)"glXSwapIntervalMESA"); + if (NULL != glXSwapIntervalMESA) + { + BX_TRACE("Using glXSwapIntervalMESA."); + glXSwapIntervalMESA(0); + foundSwapControl = true; + } + } + if (!foundSwapControl && haveGlxExtension("GLX_SGI_swap_control", extensions)) { glXSwapIntervalSGI = (PFNGLXSWAPINTERVALSGIPROC)glXGetProcAddress( (const GLubyte*)"glXSwapIntervalSGI"); if (NULL != glXSwapIntervalSGI) { BX_TRACE("Using glXSwapIntervalSGI."); glXSwapIntervalSGI(0); + foundSwapControl = true; } } }