diff options
author | Jørgen Lind <jorgen.lind@digia.com> | 2014-09-10 16:31:32 +0200 |
---|---|---|
committer | Jørgen Lind <jorgen.lind@theqtcompany.com> | 2014-12-20 06:09:01 +0100 |
commit | 8758f532ae6209bcf9447e27edc4fd412c0f173d (patch) | |
tree | 082d8e259d6de5a783ad0b2ddcf7d405ad550ba8 /src/plugins/platforms/xcb/qglxintegration.cpp | |
parent | eb2014382be588ea92e172d8b36385b8b86b64de (diff) |
Make GLX and EGL dynamic dependencies for xcb
[ChangeLog][QPA][Xcb] GLX and EGL code paths are now dynamically
resolved, making it possible for one build of a plugin to use both code
paths. Default is to use the GLX code path if available. This can be
overwritten by specifying QT_XCB_GL_INTEGRATION=xcb_egl as an
evnironment variable. Enable qt.xcb.glintegration.debug to get debug log
output of what integration is used
Change-Id: Ia9fa95fcca3d901b91dadb8c98a695fea0ae3b1e
Reviewed-by: Laszlo Agocs <laszlo.agocs@theqtcompany.com>
Diffstat (limited to 'src/plugins/platforms/xcb/qglxintegration.cpp')
-rw-r--r-- | src/plugins/platforms/xcb/qglxintegration.cpp | 723 |
1 files changed, 0 insertions, 723 deletions
diff --git a/src/plugins/platforms/xcb/qglxintegration.cpp b/src/plugins/platforms/xcb/qglxintegration.cpp deleted file mode 100644 index c0be836bce..0000000000 --- a/src/plugins/platforms/xcb/qglxintegration.cpp +++ /dev/null @@ -1,723 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include <QDebug> -#include <QLibrary> - -#include "qxcbwindow.h" -#include "qxcbscreen.h" - -#include <X11/Xlib.h> -#include <X11/Xutil.h> -#include <GL/glx.h> - -#include <QtGui/QOpenGLContext> -#include <QtGui/QOffscreenSurface> - -#include "qglxintegration.h" -#include <QtPlatformSupport/private/qglxconvenience_p.h> -#include <QtPlatformHeaders/QGLXNativeContext> - -#if defined(Q_OS_LINUX) || defined(Q_OS_BSD4) -#include <dlfcn.h> -#endif - -QT_BEGIN_NAMESPACE - -typedef GLXContext (*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXContext, Bool, const int*); - -#ifndef GLX_CONTEXT_CORE_PROFILE_BIT_ARB -#define GLX_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 -#endif - -#ifndef GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB -#define GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 -#endif - -#ifndef GLX_CONTEXT_ES2_PROFILE_BIT_EXT -#define GLX_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000004 -#endif - -#ifndef GLX_CONTEXT_PROFILE_MASK_ARB -#define GLX_CONTEXT_PROFILE_MASK_ARB 0x9126 -#endif - -#ifndef GL_CONTEXT_FLAG_DEBUG_BIT -#define GL_CONTEXT_FLAG_DEBUG_BIT 0x00000002 -#endif - -static Window createDummyWindow(Display *dpy, XVisualInfo *visualInfo, int screenNumber, Window rootWin) -{ - Colormap cmap = XCreateColormap(dpy, rootWin, visualInfo->visual, AllocNone); - XSetWindowAttributes a; - a.background_pixel = WhitePixel(dpy, screenNumber); - a.border_pixel = BlackPixel(dpy, screenNumber); - a.colormap = cmap; - a.override_redirect = true; - - Window window = XCreateWindow(dpy, rootWin, - 0, 0, 100, 100, - 0, visualInfo->depth, InputOutput, visualInfo->visual, - CWBackPixel|CWBorderPixel|CWColormap|CWOverrideRedirect, &a); -#ifndef QT_NO_DEBUG - XStoreName(dpy, window, "Qt GLX dummy window"); -#endif - XFreeColormap(dpy, cmap); - return window; -} - -static Window createDummyWindow(Display *dpy, GLXFBConfig config, int screenNumber, Window rootWin) -{ - XVisualInfo *visualInfo = glXGetVisualFromFBConfig(dpy, config); - if (!visualInfo) - qFatal("Could not initialize GLX"); - Window window = createDummyWindow(dpy, visualInfo, screenNumber, rootWin); - XFree(visualInfo); - return window; -} - -static inline QByteArray getGlString(GLenum param) -{ - if (const GLubyte *s = glGetString(param)) - return QByteArray(reinterpret_cast<const char*>(s)); - return QByteArray(); -} - -static void updateFormatFromContext(QSurfaceFormat &format) -{ - // Update the version, profile, and context bit of the format - int major = 0, minor = 0; - QByteArray versionString(getGlString(GL_VERSION)); - if (QPlatformOpenGLContext::parseOpenGLVersion(versionString, major, minor)) { - format.setMajorVersion(major); - format.setMinorVersion(minor); - } - - format.setProfile(QSurfaceFormat::NoProfile); - format.setOptions(QSurfaceFormat::FormatOptions()); - - if (format.renderableType() == QSurfaceFormat::OpenGL) { - if (format.version() < qMakePair(3, 0)) { - format.setOption(QSurfaceFormat::DeprecatedFunctions); - return; - } - - // Version 3.0 onwards - check if it includes deprecated functionality or is - // a debug context - GLint value = 0; - glGetIntegerv(GL_CONTEXT_FLAGS, &value); - if (!(value & GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT)) - format.setOption(QSurfaceFormat::DeprecatedFunctions); - if (value & GL_CONTEXT_FLAG_DEBUG_BIT) - format.setOption(QSurfaceFormat::DebugContext); - if (format.version() < qMakePair(3, 2)) - return; - - // Version 3.2 and newer have a profile - value = 0; - glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &value); - - if (value & GL_CONTEXT_CORE_PROFILE_BIT) - format.setProfile(QSurfaceFormat::CoreProfile); - else if (value & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT) - format.setProfile(QSurfaceFormat::CompatibilityProfile); - } -} - -QGLXContext::QGLXContext(QXcbScreen *screen, const QSurfaceFormat &format, QPlatformOpenGLContext *share, - const QVariant &nativeHandle) - : QPlatformOpenGLContext() - , m_display(DISPLAY_FROM_XCB(screen)) - , m_config(0) - , m_context(0) - , m_shareContext(0) - , m_format(format) - , m_isPBufferCurrent(false) - , m_swapInterval(-1) - , m_ownsContext(nativeHandle.isNull()) -{ - if (nativeHandle.isNull()) - init(screen, share); - else - init(screen, share, nativeHandle); -} - -void QGLXContext::init(QXcbScreen *screen, QPlatformOpenGLContext *share) -{ - if (m_format.renderableType() == QSurfaceFormat::DefaultRenderableType) - m_format.setRenderableType(QSurfaceFormat::OpenGL); - if (m_format.renderableType() != QSurfaceFormat::OpenGL && m_format.renderableType() != QSurfaceFormat::OpenGLES) - return; - - if (share) - m_shareContext = static_cast<const QGLXContext*>(share)->glxContext(); - - GLXFBConfig config = qglx_findConfig(DISPLAY_FROM_XCB(screen),screen->screenNumber(),m_format); - m_config = config; - 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"); - - QList<QByteArray> glxExt = QByteArray(glXQueryExtensionsString(m_display, screen->screenNumber())).split(' '); - bool supportsProfiles = glxExt.contains("GLX_ARB_create_context_profile"); - - // Use glXCreateContextAttribsARB if available - // Also, GL ES context creation requires GLX_EXT_create_context_es2_profile - if (glxExt.contains("GLX_ARB_create_context") && glXCreateContextAttribsARB != 0 - && (m_format.renderableType() != QSurfaceFormat::OpenGLES || (supportsProfiles && glxExt.contains("GLX_EXT_create_context_es2_profile")))) { - // Try to create an OpenGL context for each known OpenGL version in descending - // order from the requested version. - const int requestedVersion = m_format.majorVersion() * 10 + qMin(m_format.minorVersion(), 9); - - QVector<int> glVersions; - if (m_format.renderableType() == QSurfaceFormat::OpenGL) { - if (requestedVersion > 45) - glVersions << requestedVersion; - - // Don't bother with versions below 2.0 - glVersions << 45 << 44 << 43 << 42 << 41 << 40 << 33 << 32 << 31 << 30 << 21 << 20; - } else if (m_format.renderableType() == QSurfaceFormat::OpenGLES) { - if (requestedVersion > 31) - glVersions << requestedVersion; - - // Don't bother with versions below ES 2.0 - glVersions << 31 << 30 << 20; - // ES does not support any format option - m_format.setOptions(QSurfaceFormat::FormatOptions()); - } - - Q_ASSERT(glVersions.count() > 0); - - for (int i = 0; !m_context && i < glVersions.count(); i++) { - const int version = glVersions[i]; - if (version > requestedVersion) - continue; - - const int majorVersion = version / 10; - const int minorVersion = version % 10; - - QVector<int> contextAttributes; - contextAttributes << GLX_CONTEXT_MAJOR_VERSION_ARB << majorVersion - << GLX_CONTEXT_MINOR_VERSION_ARB << minorVersion; - - - if (m_format.renderableType() == QSurfaceFormat::OpenGL) { - // If asking for OpenGL 3.2 or newer we should also specify a profile - if (version >= 32 && supportsProfiles) { - if (m_format.profile() == QSurfaceFormat::CoreProfile) - contextAttributes << GLX_CONTEXT_PROFILE_MASK_ARB << GLX_CONTEXT_CORE_PROFILE_BIT_ARB; - else - contextAttributes << GLX_CONTEXT_PROFILE_MASK_ARB << GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; - } - - int flags = 0; - - if (m_format.testOption(QSurfaceFormat::DebugContext)) - flags |= GLX_CONTEXT_DEBUG_BIT_ARB; - - // A forward-compatible context may be requested for 3.0 and later - if (version >= 30 && !m_format.testOption(QSurfaceFormat::DeprecatedFunctions)) - flags |= GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB; - - if (flags != 0) - contextAttributes << GLX_CONTEXT_FLAGS_ARB << flags; - } else if (m_format.renderableType() == QSurfaceFormat::OpenGLES) { - contextAttributes << GLX_CONTEXT_PROFILE_MASK_ARB << GLX_CONTEXT_ES2_PROFILE_BIT_EXT; - } - - contextAttributes << None; - - m_context = glXCreateContextAttribsARB(m_display, config, m_shareContext, true, contextAttributes.data()); - if (!m_context && m_shareContext) { - // re-try without a shared glx context - m_context = glXCreateContextAttribsARB(m_display, config, 0, true, contextAttributes.data()); - if (m_context) - m_shareContext = 0; - } - } - } - - // Could not create a context using glXCreateContextAttribsARB, falling back to glXCreateNewContext. - if (!m_context) { - // requesting an OpenGL ES context requires glXCreateContextAttribsARB, so bail out - if (m_format.renderableType() == QSurfaceFormat::OpenGLES) - return; - - m_context = glXCreateNewContext(m_display, config, GLX_RGBA_TYPE, m_shareContext, true); - if (!m_context && m_shareContext) { - // re-try without a shared glx context - m_context = glXCreateNewContext(m_display, config, GLX_RGBA_TYPE, 0, true); - if (m_context) - m_shareContext = 0; - } - } - - // Get the basic surface format details - if (m_context) - qglx_surfaceFormatFromGLXFBConfig(&m_format, DISPLAY_FROM_XCB(screen), config); - - // Create a temporary window so that we can make the new context current - window = createDummyWindow(DISPLAY_FROM_XCB(screen), config, screen->screenNumber(), screen->root()); - } else { - // requesting an OpenGL ES context requires glXCreateContextAttribsARB, so bail out - if (m_format.renderableType() == QSurfaceFormat::OpenGLES) - return; - - // Note that m_format gets updated with the used surface format - visualInfo = qglx_findVisualInfo(m_display, screen->screenNumber(), &m_format); - if (!visualInfo) - qFatal("Could not initialize GLX"); - m_context = glXCreateContext(m_display, visualInfo, m_shareContext, true); - if (!m_context && m_shareContext) { - // re-try without a shared glx context - m_shareContext = 0; - m_context = glXCreateContext(m_display, visualInfo, Q_NULLPTR, true); - } - - // Create a temporary window so that we can make the new context current - window = createDummyWindow(DISPLAY_FROM_XCB(screen), visualInfo, screen->screenNumber(), screen->root()); - XFree(visualInfo); - } - - // Query the OpenGL version and profile - if (m_context && window) { - GLXContext prevContext = glXGetCurrentContext(); - GLXDrawable prevDrawable = glXGetCurrentDrawable(); - glXMakeCurrent(m_display, window, m_context); - updateFormatFromContext(m_format); - - // Make our context non-current - glXMakeCurrent(m_display, prevDrawable, prevContext); - } - - // Destroy our temporary window - XDestroyWindow(m_display, window); -} - -void QGLXContext::init(QXcbScreen *screen, QPlatformOpenGLContext *share, const QVariant &nativeHandle) -{ - if (!nativeHandle.canConvert<QGLXNativeContext>()) { - qWarning("QGLXContext: Requires a QGLXNativeContext"); - return; - } - QGLXNativeContext handle = nativeHandle.value<QGLXNativeContext>(); - GLXContext context = handle.context(); - if (!context) { - qWarning("QGLXContext: No GLXContext given"); - return; - } - - // Use the provided Display, if available. If not, use our own. It may still work. - Display *dpy = handle.display(); - if (!dpy) - dpy = DISPLAY_FROM_XCB(screen); - - // Legacy contexts created using glXCreateContext are created using a visual - // and the FBConfig cannot be queried. The only way to adapt these contexts - // is to figure out the visual id. - XVisualInfo *vinfo = 0; - // If the VisualID is provided use it. - VisualID vid = handle.visualId(); - if (!vid) { - // In the absence of the VisualID figure it out from the window. - Window wnd = handle.window(); - if (wnd) { - XWindowAttributes attrs; - XGetWindowAttributes(dpy, wnd, &attrs); - vid = XVisualIDFromVisual(attrs.visual); - } - } - if (vid) { - XVisualInfo v; - v.screen = screen->screenNumber(); - v.visualid = vid; - int n = 0; - vinfo = XGetVisualInfo(dpy, VisualScreenMask | VisualIDMask, &v, &n); - if (n < 1) { - XFree(vinfo); - vinfo = 0; - } - } - - // For contexts created with an FBConfig using the modern functions providing the - // visual or window is not mandatory. Just query the config from the context. - GLXFBConfig config = 0; - if (!vinfo) { - int configId = 0; - if (glXQueryContext(dpy, context, GLX_FBCONFIG_ID, &configId) != Success) { - qWarning("QGLXContext: Failed to query config from the provided context"); - return; - } - - GLXFBConfig *configs; - int numConfigs = 0; - static const int attribs[] = { GLX_FBCONFIG_ID, configId, None }; - configs = glXChooseFBConfig(dpy, screen->screenNumber(), attribs, &numConfigs); - if (!configs || numConfigs < 1) { - qWarning("QGLXContext: Failed to find config"); - return; - } - if (configs && numConfigs > 1) // this is suspicious so warn but let it continue - qWarning("QGLXContext: Multiple configs for FBConfig ID %d", configId); - - config = configs[0]; - // Store the config. - m_config = config; - } - - Q_ASSERT(vinfo || config); - - int screenNumber = DefaultScreen(dpy); - Window window; - if (vinfo) - window = createDummyWindow(dpy, vinfo, screenNumber, RootWindow(dpy, screenNumber)); - else - window = createDummyWindow(dpy, config, screenNumber, RootWindow(dpy, screenNumber)); - if (!window) { - qWarning("QGLXContext: Failed to create dummy window"); - return; - } - - // Update OpenGL version and buffer sizes in our format. - GLXContext prevContext = glXGetCurrentContext(); - GLXDrawable prevDrawable = glXGetCurrentDrawable(); - if (!glXMakeCurrent(dpy, window, context)) { - qWarning("QGLXContext: Failed to make provided context current"); - return; - } - m_format = QSurfaceFormat(); - m_format.setRenderableType(QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGL - ? QSurfaceFormat::OpenGL : QSurfaceFormat::OpenGLES); - updateFormatFromContext(m_format); - if (vinfo) - qglx_surfaceFormatFromVisualInfo(&m_format, dpy, vinfo); - else - qglx_surfaceFormatFromGLXFBConfig(&m_format, dpy, config); - glXMakeCurrent(dpy, prevDrawable, prevContext); - XDestroyWindow(dpy, window); - - if (vinfo) - XFree(vinfo); - - // Success. Store the context. From this point on isValid() is true. - m_context = context; - - if (share) - m_shareContext = static_cast<const QGLXContext*>(share)->glxContext(); -} - -QGLXContext::~QGLXContext() -{ - if (m_ownsContext) - glXDestroyContext(m_display, m_context); -} - -static QXcbScreen *screenForPlatformSurface(QPlatformSurface *surface) -{ - QSurface::SurfaceClass surfaceClass = surface->surface()->surfaceClass(); - if (surfaceClass == QSurface::Window) { - return static_cast<QXcbScreen *>(static_cast<QXcbWindow *>(surface)->screen()); - } else if (surfaceClass == QSurface::Offscreen) { - return static_cast<QXcbScreen *>(static_cast<QGLXPbuffer *>(surface)->screen()); - } - return Q_NULLPTR; -} - -QVariant QGLXContext::nativeHandle() const -{ - return QVariant::fromValue<QGLXNativeContext>(QGLXNativeContext(m_context)); -} - -bool QGLXContext::makeCurrent(QPlatformSurface *surface) -{ - bool success = false; - Q_ASSERT(surface->surface()->supportsOpenGL()); - - GLXDrawable glxDrawable = 0; - QSurface::SurfaceClass surfaceClass = surface->surface()->surfaceClass(); - if (surfaceClass == QSurface::Window) { - m_isPBufferCurrent = false; - QXcbWindow *window = static_cast<QXcbWindow *>(surface); - glxDrawable = window->xcb_window(); - success = glXMakeCurrent(m_display, glxDrawable, m_context); - } else if (surfaceClass == QSurface::Offscreen) { - m_isPBufferCurrent = true; - QGLXPbuffer *pbuffer = static_cast<QGLXPbuffer *>(surface); - glxDrawable = pbuffer->pbuffer(); - success = glXMakeContextCurrent(m_display, glxDrawable, glxDrawable, m_context); - } - - if (success) { - int interval = surface->format().swapInterval(); - QXcbScreen *screen = screenForPlatformSurface(surface); - if (interval >= 0 && m_swapInterval != interval && screen) { - m_swapInterval = interval; - typedef void (*qt_glXSwapIntervalEXT)(Display *, GLXDrawable, int); - typedef void (*qt_glXSwapIntervalMESA)(unsigned int); - static qt_glXSwapIntervalEXT glXSwapIntervalEXT = 0; - static qt_glXSwapIntervalMESA glXSwapIntervalMESA = 0; - static bool resolved = false; - if (!resolved) { - resolved = true; - QList<QByteArray> glxExt = QByteArray(glXQueryExtensionsString(m_display, - screen->screenNumber())).split(' '); - if (glxExt.contains("GLX_EXT_swap_control")) - glXSwapIntervalEXT = (qt_glXSwapIntervalEXT) getProcAddress("glXSwapIntervalEXT"); - if (glxExt.contains("GLX_MESA_swap_control")) - glXSwapIntervalMESA = (qt_glXSwapIntervalMESA) getProcAddress("glXSwapIntervalMESA"); - } - if (glXSwapIntervalEXT) - glXSwapIntervalEXT(m_display, glxDrawable, interval); - else if (glXSwapIntervalMESA) - glXSwapIntervalMESA(interval); - } - } - - return success; -} - -void QGLXContext::doneCurrent() -{ - if (m_isPBufferCurrent) - glXMakeContextCurrent(m_display, 0, 0, 0); - else - glXMakeCurrent(m_display, 0, 0); - m_isPBufferCurrent = false; -} - -void QGLXContext::swapBuffers(QPlatformSurface *surface) -{ - GLXDrawable glxDrawable = 0; - if (surface->surface()->surfaceClass() == QSurface::Offscreen) - glxDrawable = static_cast<QGLXPbuffer *>(surface)->pbuffer(); - else - glxDrawable = static_cast<QXcbWindow *>(surface)->xcb_window(); - glXSwapBuffers(m_display, glxDrawable); - - if (surface->surface()->surfaceClass() == QSurface::Window) { - QXcbWindow *platformWindow = static_cast<QXcbWindow *>(surface); - // OpenGL context might be bound to a non-gui thread use QueuedConnection to sync - // the window from the platformWindow's thread as QXcbWindow is no QObject, an - // event is sent to QXcbConnection. (this is faster than a metacall) - if (platformWindow->needsSync()) - platformWindow->postSyncWindowRequest(); - } -} - -void (*QGLXContext::getProcAddress(const QByteArray &procName)) () -{ - typedef void *(*qt_glXGetProcAddressARB)(const GLubyte *); - static qt_glXGetProcAddressARB glXGetProcAddressARB = 0; - static bool resolved = false; - - if (resolved && !glXGetProcAddressARB) - return 0; - if (!glXGetProcAddressARB) { - QList<QByteArray> glxExt = QByteArray(glXGetClientString(m_display, GLX_EXTENSIONS)).split(' '); - if (glxExt.contains("GLX_ARB_get_proc_address")) { -#if defined(Q_OS_LINUX) || defined(Q_OS_BSD4) - void *handle = dlopen(NULL, RTLD_LAZY); - if (handle) { - glXGetProcAddressARB = (qt_glXGetProcAddressARB) dlsym(handle, "glXGetProcAddressARB"); - dlclose(handle); - } - if (!glXGetProcAddressARB) -#endif - { - extern const QString qt_gl_library_name(); -// QLibrary lib(qt_gl_library_name()); - QLibrary lib(QLatin1String("GL")); - glXGetProcAddressARB = (qt_glXGetProcAddressARB) lib.resolve("glXGetProcAddressARB"); - } - } - resolved = true; - } - if (!glXGetProcAddressARB) - return 0; - return (void (*)())glXGetProcAddressARB(reinterpret_cast<const GLubyte *>(procName.constData())); -} - -QSurfaceFormat QGLXContext::format() const -{ - return m_format; -} - -bool QGLXContext::isSharing() const -{ - return m_shareContext != 0; -} - -bool QGLXContext::isValid() const -{ - return m_context != 0; -} - -bool QGLXContext::m_queriedDummyContext = false; -bool QGLXContext::m_supportsThreading = true; - - -// If this list grows to any significant size, change it a -// proper string table and make the implementation below use -// binary search. -static const char *qglx_threadedgl_blacklist_renderer[] = { - "Chromium", // QTBUG-32225 (initialization fails) - 0 -}; - -// This disables threaded rendering on anything using mesa, e.g. -// - nvidia/nouveau -// - amd/gallium -// - intel -// - some software opengl implementations -// -// The client glx vendor string is used to identify those setups as that seems to show the least -// variance between the bad configurations. It's always "Mesa Project and SGI". There are some -// configurations which don't use mesa and which can do threaded rendering (amd and nvidia chips -// with their own proprietary drivers). -// -// This, of course, is very broad and disables threaded rendering on a lot of devices which would -// be able to use it. However, the bugs listed below don't follow any easily recognizable pattern -// and we should rather be safe. -// -// http://cgit.freedesktop.org/xcb/libxcb/commit/?id=be0fe56c3bcad5124dcc6c47a2fad01acd16f71a will -// fix some of the issues. Basically, the proprietary drivers seem to have a way of working around -// a fundamental flaw with multithreaded access to xcb, but mesa doesn't. The blacklist should be -// reevaluated once that patch is released in some version of xcb. -static const char *qglx_threadedgl_blacklist_vendor[] = { - "Mesa Project and SGI", // QTCREATORBUG-10875 (crash in creator) - // QTBUG-34492 (flickering in fullscreen) - // QTBUG-38221 - 0 -}; - -void QGLXContext::queryDummyContext() -{ - if (m_queriedDummyContext) - return; - m_queriedDummyContext = true; - - static bool skip = qEnvironmentVariableIsSet("QT_OPENGL_NO_SANITY_CHECK"); - if (skip) - return; - - QOpenGLContext *oldContext = QOpenGLContext::currentContext(); - QSurface *oldSurface = 0; - if (oldContext) - oldSurface = oldContext->surface(); - - QScopedPointer<QSurface> surface; - const char *glxvendor = glXGetClientString(glXGetCurrentDisplay(), GLX_VENDOR); - if (glxvendor && !strcmp(glxvendor, "ATI")) { - QWindow *window = new QWindow; - window->resize(64, 64); - window->setSurfaceType(QSurface::OpenGLSurface); - window->create(); - surface.reset(window); - } else { - QOffscreenSurface *offSurface = new QOffscreenSurface; - offSurface->create(); - surface.reset(offSurface); - } - - QOpenGLContext context; - context.create(); - context.makeCurrent(surface.data()); - - m_supportsThreading = true; - - if (const char *renderer = (const char *) glGetString(GL_RENDERER)) { - for (int i = 0; qglx_threadedgl_blacklist_renderer[i]; ++i) { - if (strstr(renderer, qglx_threadedgl_blacklist_renderer[i]) != 0) { - m_supportsThreading = false; - break; - } - } - } - - if (glxvendor) { - for (int i = 0; qglx_threadedgl_blacklist_vendor[i]; ++i) { - if (strstr(glxvendor, qglx_threadedgl_blacklist_vendor[i]) != 0) { - m_supportsThreading = false; - break; - } - } - } - - context.doneCurrent(); - if (oldContext && oldSurface) - oldContext->makeCurrent(oldSurface); -} - -bool QGLXContext::supportsThreading() -{ - if (!m_queriedDummyContext) - queryDummyContext(); - return m_supportsThreading; -} - -QGLXPbuffer::QGLXPbuffer(QOffscreenSurface *offscreenSurface) - : QPlatformOffscreenSurface(offscreenSurface) - , m_format(offscreenSurface->requestedFormat()) - , m_screen(static_cast<QXcbScreen *>(offscreenSurface->screen()->handle())) - , m_pbuffer(0) -{ - GLXFBConfig config = qglx_findConfig(DISPLAY_FROM_XCB(m_screen), m_screen->screenNumber(), m_format); - - if (config) { - const int attributes[] = { - GLX_PBUFFER_WIDTH, offscreenSurface->size().width(), - GLX_PBUFFER_HEIGHT, offscreenSurface->size().height(), - GLX_LARGEST_PBUFFER, False, - GLX_PRESERVED_CONTENTS, False, - None - }; - - m_pbuffer = glXCreatePbuffer(DISPLAY_FROM_XCB(m_screen), config, attributes); - - if (m_pbuffer) - qglx_surfaceFormatFromGLXFBConfig(&m_format, DISPLAY_FROM_XCB(m_screen), config); - } -} - -QGLXPbuffer::~QGLXPbuffer() -{ - if (m_pbuffer) - glXDestroyPbuffer(DISPLAY_FROM_XCB(m_screen), m_pbuffer); -} - - -QT_END_NAMESPACE |