diff options
Diffstat (limited to 'src/plugins/platforms')
-rw-r--r-- | src/plugins/platforms/offscreen/qoffscreenintegration_x11.cpp | 2 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qglxintegration.cpp | 157 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qglxintegration.h | 9 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbintegration.cpp | 5 |
4 files changed, 154 insertions, 19 deletions
diff --git a/src/plugins/platforms/offscreen/qoffscreenintegration_x11.cpp b/src/plugins/platforms/offscreen/qoffscreenintegration_x11.cpp index 6c6c516a4e..3f959b859c 100644 --- a/src/plugins/platforms/offscreen/qoffscreenintegration_x11.cpp +++ b/src/plugins/platforms/offscreen/qoffscreenintegration_x11.cpp @@ -179,7 +179,7 @@ QOffscreenX11GLXContext::QOffscreenX11GLXContext(QOffscreenX11Info *x11, QOpenGL // Get the basic surface format details if (d->context) - qglx_surfaceFormatFromGLXFBConfig(&d->format, x11->display(), config, d->context); + qglx_surfaceFormatFromGLXFBConfig(&d->format, x11->display(), config); // Create a temporary window so that we can make the new context current d->window = createDummyWindow(x11, config); diff --git a/src/plugins/platforms/xcb/qglxintegration.cpp b/src/plugins/platforms/xcb/qglxintegration.cpp index c183deb3b8..de907f87df 100644 --- a/src/plugins/platforms/xcb/qglxintegration.cpp +++ b/src/plugins/platforms/xcb/qglxintegration.cpp @@ -54,6 +54,7 @@ #include "qglxintegration.h" #include <QtPlatformSupport/private/qglxconvenience_p.h> +#include <QtPlatformHeaders/QGLXNativeContext> #if defined(Q_OS_LINUX) || defined(Q_OS_BSD4) #include <dlfcn.h> @@ -83,31 +84,31 @@ typedef GLXContext (*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXC #define GL_CONTEXT_FLAG_DEBUG_BIT 0x00000002 #endif -static Window createDummyWindow(QXcbScreen *screen, XVisualInfo *visualInfo) +static Window createDummyWindow(Display *dpy, XVisualInfo *visualInfo, int screenNumber, Window rootWin) { - Colormap cmap = XCreateColormap(DISPLAY_FROM_XCB(screen), screen->root(), visualInfo->visual, AllocNone); + Colormap cmap = XCreateColormap(dpy, rootWin, 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.background_pixel = WhitePixel(dpy, screenNumber); + a.border_pixel = BlackPixel(dpy, screenNumber); a.colormap = cmap; - Window window = XCreateWindow(DISPLAY_FROM_XCB(screen), screen->root(), + Window window = XCreateWindow(dpy, rootWin, 0, 0, 100, 100, 0, visualInfo->depth, InputOutput, visualInfo->visual, CWBackPixel|CWBorderPixel|CWColormap, &a); #ifndef QT_NO_DEBUG - XStoreName(DISPLAY_FROM_XCB(screen), window, "Qt GLX dummy window"); + XStoreName(dpy, window, "Qt GLX dummy window"); #endif - XFreeColormap(DISPLAY_FROM_XCB(screen), cmap); + XFreeColormap(dpy, cmap); return window; } -static Window createDummyWindow(QXcbScreen *screen, GLXFBConfig config) +static Window createDummyWindow(Display *dpy, GLXFBConfig config, int screenNumber, Window rootWin) { - XVisualInfo *visualInfo = glXGetVisualFromFBConfig(DISPLAY_FROM_XCB(screen), config); + XVisualInfo *visualInfo = glXGetVisualFromFBConfig(dpy, config); if (!visualInfo) qFatal("Could not initialize GLX"); - Window window = createDummyWindow(screen, visualInfo); + Window window = createDummyWindow(dpy, visualInfo, screenNumber, rootWin); XFree(visualInfo); return window; } @@ -160,7 +161,8 @@ static void updateFormatFromContext(QSurfaceFormat &format) } } -QGLXContext::QGLXContext(QXcbScreen *screen, const QSurfaceFormat &format, QPlatformOpenGLContext *share) +QGLXContext::QGLXContext(QXcbScreen *screen, const QSurfaceFormat &format, QPlatformOpenGLContext *share, + const QVariant &nativeHandle) : QPlatformOpenGLContext() , m_screen(screen) , m_context(0) @@ -168,6 +170,15 @@ QGLXContext::QGLXContext(QXcbScreen *screen, const QSurfaceFormat &format, QPlat , 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); @@ -195,7 +206,7 @@ QGLXContext::QGLXContext(QXcbScreen *screen, const QSurfaceFormat &format, QPlat && (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 = format.majorVersion() * 10 + qMin(format.minorVersion(), 9); + const int requestedVersion = m_format.majorVersion() * 10 + qMin(m_format.minorVersion(), 9); QVector<int> glVersions; if (m_format.renderableType() == QSurfaceFormat::OpenGL) { @@ -282,10 +293,10 @@ QGLXContext::QGLXContext(QXcbScreen *screen, const QSurfaceFormat &format, QPlat // Get the basic surface format details if (m_context) - qglx_surfaceFormatFromGLXFBConfig(&m_format, DISPLAY_FROM_XCB(screen), config, 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(screen, config); + 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) @@ -303,7 +314,7 @@ QGLXContext::QGLXContext(QXcbScreen *screen, const QSurfaceFormat &format, QPlat } // Create a temporary window so that we can make the new context current - window = createDummyWindow(screen, visualInfo); + window = createDummyWindow(DISPLAY_FROM_XCB(screen), visualInfo, screen->screenNumber(), screen->root()); XFree(visualInfo); } @@ -320,9 +331,123 @@ QGLXContext::QGLXContext(QXcbScreen *screen, const QSurfaceFormat &format, QPlat XDestroyWindow(DISPLAY_FROM_XCB(screen), 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]; + } + + 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. + if (!glXMakeCurrent(dpy, window, context)) { + qWarning("QGLXContext: Failed to make provided context current"); + return; + } + m_format = QSurfaceFormat(); + m_format.setRenderableType(QOpenGLContext::openGLModuleType() == QOpenGLContext::DesktopGL + ? QSurfaceFormat::OpenGL : QSurfaceFormat::OpenGLES); + updateFormatFromContext(m_format); + if (vinfo) + qglx_surfaceFormatFromVisualInfo(&m_format, dpy, vinfo); + else + qglx_surfaceFormatFromGLXFBConfig(&m_format, dpy, config); + glXMakeCurrent(dpy, 0, 0); + 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() { - glXDestroyContext(DISPLAY_FROM_XCB(m_screen), m_context); + if (m_ownsContext) + glXDestroyContext(DISPLAY_FROM_XCB(m_screen), m_context); +} + +QVariant QGLXContext::nativeHandle() const +{ + return QVariant::fromValue<QGLXNativeContext>(QGLXNativeContext(m_context)); } bool QGLXContext::makeCurrent(QPlatformSurface *surface) diff --git a/src/plugins/platforms/xcb/qglxintegration.h b/src/plugins/platforms/xcb/qglxintegration.h index 00bba94ab3..a7787f5f86 100644 --- a/src/plugins/platforms/xcb/qglxintegration.h +++ b/src/plugins/platforms/xcb/qglxintegration.h @@ -58,7 +58,8 @@ QT_BEGIN_NAMESPACE class QGLXContext : public QPlatformOpenGLContext { public: - QGLXContext(QXcbScreen *xd, const QSurfaceFormat &format, QPlatformOpenGLContext *share); + QGLXContext(QXcbScreen *screen, const QSurfaceFormat &format, QPlatformOpenGLContext *share, + const QVariant &nativeHandle); ~QGLXContext(); bool makeCurrent(QPlatformSurface *surface); @@ -72,16 +73,22 @@ public: GLXContext glxContext() const { return m_context; } + QVariant nativeHandle() const; + static bool supportsThreading(); static void queryDummyContext(); private: + void init(QXcbScreen *screen, QPlatformOpenGLContext *share); + void init(QXcbScreen *screen, QPlatformOpenGLContext *share, const QVariant &nativeHandle); + QXcbScreen *m_screen; GLXContext m_context; GLXContext m_shareContext; QSurfaceFormat m_format; bool m_isPBufferCurrent; int m_swapInterval; + bool m_ownsContext; static bool m_queriedDummyContext; static bool m_supportsThreading; }; diff --git a/src/plugins/platforms/xcb/qxcbintegration.cpp b/src/plugins/platforms/xcb/qxcbintegration.cpp index 0bab341914..2d4c523a4b 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.cpp +++ b/src/plugins/platforms/xcb/qxcbintegration.cpp @@ -233,7 +233,10 @@ QPlatformOpenGLContext *QXcbIntegration::createPlatformOpenGLContext(QOpenGLCont { QXcbScreen *screen = static_cast<QXcbScreen *>(context->screen()->handle()); #if defined(XCB_USE_GLX) - return new QGLXContext(screen, context->format(), context->shareHandle()); + QGLXContext *platformContext = new QGLXContext(screen, context->format(), + context->shareHandle(), context->nativeHandle()); + context->setNativeHandle(platformContext->nativeHandle()); + return platformContext; #elif defined(XCB_USE_EGL) return new QEGLXcbPlatformContext(context->format(), context->shareHandle(), screen->connection()->egl_display(), screen->connection()); |