From aad58ac87e371129ee61168effd9daa491b476ab Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Tue, 18 Sep 2012 17:05:01 +0100 Subject: [PATCH] XCB: Correctly report the created OpenGL context version and profile MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit This commit fixes the xcb qpa plugin such that it now correctly reports the version and profile of the created OpenGL context in the QOpenGLSurfaceFormat. To do this we have to create a temporary X window so that we can make our new context current. We also handle the buggy nVidia drivers which incorrectly report 0 for the GL_CONTEXT_PROFILE_MASK query. The reduced format is also copied back from qglx_findVisualInfo. Change-Id: I6f34fe1c6130aebbb6b40c36df4acc216069d2b1 Reviewed-by: Samuel Rødal --- src/gui/kernel/qplatformopenglcontext.cpp | 34 ++++++++++ src/gui/kernel/qplatformopenglcontext.h | 2 + .../glxconvenience/qglxconvenience.cpp | 2 + src/plugins/platforms/xcb/qglxintegration.cpp | 77 +++++++++++++++++++--- 4 files changed, 107 insertions(+), 8 deletions(-) diff --git a/src/gui/kernel/qplatformopenglcontext.cpp b/src/gui/kernel/qplatformopenglcontext.cpp index ed8ab09..8e6a9da 100644 --- a/src/gui/kernel/qplatformopenglcontext.cpp +++ b/src/gui/kernel/qplatformopenglcontext.cpp @@ -118,4 +118,38 @@ void QPlatformOpenGLContext::setContext(QOpenGLContext *context) d->context = context; } +bool QPlatformOpenGLContext::parseOpenGLVersion(const QString& versionString, int &major, int &minor) +{ + bool majorOk = false; + bool minorOk = false; + QStringList parts = versionString.split(QLatin1Char(' ')); + if (versionString.startsWith(QLatin1String("OpenGL ES"))) { + if (parts.size() >= 3) { + QStringList versionParts = parts.at(2).split(QLatin1Char('.')); + if (versionParts.size() >= 2) { + major = versionParts.at(0).toInt(&majorOk); + minor = versionParts.at(1).toInt(&minorOk); + } else { + qWarning("Unrecognized OpenGL ES version"); + } + } else { + // If < 3 parts to the name, it is an unrecognised OpenGL ES + qWarning("Unrecognised OpenGL ES version"); + } + } else { + // Not OpenGL ES, but regular OpenGL, the version numbers are first in the string + QStringList versionParts = parts.at(0).split(QLatin1Char('.')); + if (versionParts.size() >= 2) { + major = versionParts.at(0).toInt(&majorOk); + minor = versionParts.at(1).toInt(&minorOk); + } else { + qWarning("Unrecognized OpenGL version"); + } + } + + if (!majorOk || !minorOk) + qWarning("Unrecognized OpenGL version"); + return (majorOk && minorOk); +} + QT_END_NAMESPACE diff --git a/src/gui/kernel/qplatformopenglcontext.h b/src/gui/kernel/qplatformopenglcontext.h index ffdfaba..bed83b0 100644 --- a/src/gui/kernel/qplatformopenglcontext.h +++ b/src/gui/kernel/qplatformopenglcontext.h @@ -88,6 +88,8 @@ public: QOpenGLContext *context() const; + static bool parseOpenGLVersion(const QString& versionString, int &major, int &minor); + private: friend class QOpenGLContext; diff --git a/src/platformsupport/glxconvenience/qglxconvenience.cpp b/src/platformsupport/glxconvenience/qglxconvenience.cpp index a11af43..ca5c1cb 100644 --- a/src/platformsupport/glxconvenience/qglxconvenience.cpp +++ b/src/platformsupport/glxconvenience/qglxconvenience.cpp @@ -210,6 +210,8 @@ XVisualInfo *qglx_findVisualInfo(Display *display, int screen, QSurfaceFormat *f attribs.append(XNone); visualInfo = glXChooseVisual(display, screen, attribs.data()); + if (visualInfo) + *format = reducedFormat; reducedFormat = qglx_reduceSurfaceFormat(reducedFormat, &reduced); } diff --git a/src/plugins/platforms/xcb/qglxintegration.cpp b/src/plugins/platforms/xcb/qglxintegration.cpp index d1a21c9..089bca8 100644 --- a/src/plugins/platforms/xcb/qglxintegration.cpp +++ b/src/plugins/platforms/xcb/qglxintegration.cpp @@ -74,7 +74,6 @@ typedef GLXContext (*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXC #define GLX_CONTEXT_PROFILE_MASK_ARB 0x9126 #endif - QGLXContext::QGLXContext(QXcbScreen *screen, const QSurfaceFormat &format, QPlatformOpenGLContext *share) : QPlatformOpenGLContext() , m_screen(screen) @@ -86,18 +85,22 @@ QGLXContext::QGLXContext(QXcbScreen *screen, const QSurfaceFormat &format, QPlat m_shareContext = static_cast(share)->glxContext(); GLXFBConfig config = qglx_findConfig(DISPLAY_FROM_XCB(screen),screen->screenNumber(),format); + XVisualInfo *visualInfo = 0; + Window window = 0; // Temporary window used to query OpenGL context if (config) { // Resolve entry point for glXCreateContextAttribsARB glXCreateContextAttribsARBProc glXCreateContextAttribsARB = 0; glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc) glXGetProcAddress((const GLubyte*)"glXCreateContextAttribsARB"); + // Use glXCreateContextAttribsARB if is available if (glXCreateContextAttribsARB != 0) { QVector contextAttributes; contextAttributes << GLX_CONTEXT_MAJOR_VERSION_ARB << m_format.majorVersion() << GLX_CONTEXT_MINOR_VERSION_ARB << m_format.minorVersion(); + // If asking for OpenGL 3.2 or newer we should also specify a profile if (m_format.majorVersion() > 3 || (m_format.majorVersion() == 3 && m_format.minorVersion() > 1)) { if (m_format.profile() == QSurfaceFormat::CoreProfile) { contextAttributes << GLX_CONTEXT_FLAGS_ARB << GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB @@ -129,14 +132,17 @@ QGLXContext::QGLXContext(QXcbScreen *screen, const QSurfaceFormat &format, QPlat } } - if (m_context) { + // Get the basic surface format details + if (m_context) m_format = qglx_surfaceFormatFromGLXFBConfig(DISPLAY_FROM_XCB(screen), config, m_context); - m_format.setMajorVersion(format.majorVersion()); - m_format.setMinorVersion(format.minorVersion()); - m_format.setProfile(format.profile()); - } + + // Used for creating the temporary window + visualInfo = glXGetVisualFromFBConfig(DISPLAY_FROM_XCB(screen), config); + if (!visualInfo) + qFatal("Could not initialize GLX"); } else { - XVisualInfo *visualInfo = qglx_findVisualInfo(DISPLAY_FROM_XCB(m_screen), screen->screenNumber(), &m_format); + // Note that m_format gets updated with the used surface format + visualInfo = qglx_findVisualInfo(DISPLAY_FROM_XCB(screen), screen->screenNumber(), &m_format); if (!visualInfo) qFatal("Could not initialize GLX"); m_context = glXCreateContext(DISPLAY_FROM_XCB(screen), visualInfo, m_shareContext, true); @@ -145,8 +151,63 @@ QGLXContext::QGLXContext(QXcbScreen *screen, const QSurfaceFormat &format, QPlat m_shareContext = 0; m_context = glXCreateContext(DISPLAY_FROM_XCB(screen), visualInfo, 0, true); } - XFree(visualInfo); } + + // Create a temporary window so that we can make the new context current + Colormap cmap = XCreateColormap(DISPLAY_FROM_XCB(screen), screen->root(), visualInfo->visual, AllocNone); + XSetWindowAttributes a; + a.background_pixel = WhitePixel(DISPLAY_FROM_XCB(screen), screen->screenNumber()); + a.border_pixel = BlackPixel(DISPLAY_FROM_XCB(screen), screen->screenNumber()); + a.colormap = cmap; + + window = XCreateWindow(DISPLAY_FROM_XCB(screen), screen->root(), + 0, 0, 100, 100, + 0, visualInfo->depth, InputOutput, visualInfo->visual, + CWBackPixel|CWBorderPixel|CWColormap, &a); + + XFree(visualInfo); + + // Query the OpenGL version and profile + if (m_context && window) { + glXMakeCurrent(DISPLAY_FROM_XCB(screen), window, m_context); + + int major = 0, minor = 0; + QString versionString(QLatin1String(reinterpret_cast(glGetString(GL_VERSION)))); + if (parseOpenGLVersion(versionString, major, minor)) { + m_format.setMajorVersion(major); + m_format.setMinorVersion(minor); + } + + // If we have OpenGL 3.2 or newer we also need to query the profile in use + if (m_format.majorVersion() > 3 || (m_format.majorVersion() == 3 && m_format.minorVersion() > 1)) { + // nVidia drivers have a bug where querying GL_CONTEXT_PROFILE_MASK always returns 0. + // In this case let's assume that we got the profile that we asked for since nvidia implements + // both Core and Compatibility profiles + if (versionString.contains(QStringLiteral("NVIDIA"))) { + m_format.setProfile(format.profile()); + } else { + GLint profileMask; + glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &profileMask); + switch (profileMask) { + case GLX_CONTEXT_CORE_PROFILE_BIT_ARB: + m_format.setProfile(QSurfaceFormat::CoreProfile); + break; + + case GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB: + default: + m_format.setProfile(QSurfaceFormat::CompatibilityProfile); + } + } + } else { + m_format.setProfile(QSurfaceFormat::NoProfile); + } + + // Make our context non-current + glXMakeCurrent(DISPLAY_FROM_XCB(screen), 0, 0); + } + + // Destroy our temporary window + XDestroyWindow(DISPLAY_FROM_XCB(screen), window); } QGLXContext::~QGLXContext() -- 2.7.4