diff options
-rw-r--r-- | src/gui/kernel/qplatformopenglcontext.cpp | 34 | ||||
-rw-r--r-- | src/gui/kernel/qplatformopenglcontext.h | 2 | ||||
-rw-r--r-- | src/platformsupport/glxconvenience/qglxconvenience.cpp | 2 | ||||
-rw-r--r-- | 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 ed8ab09479..8e6a9da562 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 ffdfaba15e..bed83b0913 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 a11af43671..ca5c1cb39d 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 d1a21c9c4f..089bca8a63 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<const QGLXContext*>(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<int> 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<const char*>(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() |