diff options
14 files changed, 366 insertions, 290 deletions
diff --git a/src/platformsupport/glxconvenience/qglxconvenience.cpp b/src/platformsupport/glxconvenience/qglxconvenience.cpp index 870e746a53..7dc29fae6d 100644 --- a/src/platformsupport/glxconvenience/qglxconvenience.cpp +++ b/src/platformsupport/glxconvenience/qglxconvenience.cpp @@ -40,6 +40,7 @@ // We have to include this before the X11 headers dragged in by // qglxconvenience_p.h. #include <QtCore/QByteArray> +#include <QtCore/QScopedPointer> #include "qglxconvenience_p.h" @@ -77,174 +78,182 @@ enum { QVector<int> qglx_buildSpec(const QSurfaceFormat &format, int drawableBit) { - QVector<int> spec(48); - int i = 0; + QVector<int> spec; - spec[i++] = GLX_LEVEL; - spec[i++] = 0; - spec[i++] = GLX_DRAWABLE_TYPE; spec[i++] = drawableBit; + spec << GLX_LEVEL + << 0 - spec[i++] = GLX_RENDER_TYPE; spec[i++] = GLX_RGBA_BIT; + << GLX_RENDER_TYPE + << GLX_RGBA_BIT - spec[i++] = GLX_RED_SIZE; spec[i++] = (format.redBufferSize() == -1) ? 1 : format.redBufferSize(); - spec[i++] = GLX_GREEN_SIZE; spec[i++] = (format.greenBufferSize() == -1) ? 1 : format.greenBufferSize(); - spec[i++] = GLX_BLUE_SIZE; spec[i++] = (format.blueBufferSize() == -1) ? 1 : format.blueBufferSize(); - if (format.hasAlpha()) { - spec[i++] = GLX_ALPHA_SIZE; spec[i++] = format.alphaBufferSize(); - } + << GLX_RED_SIZE + << qMax(1, format.redBufferSize()) - spec[i++] = GLX_DOUBLEBUFFER; spec[i++] = format.swapBehavior() != QSurfaceFormat::SingleBuffer ? True : False; + << GLX_GREEN_SIZE + << qMax(1, format.greenBufferSize()) - spec[i++] = GLX_STEREO; spec[i++] = format.stereo() ? True : False; + << GLX_BLUE_SIZE + << qMax(1, format.blueBufferSize()) - if (format.depthBufferSize() > 0) { - spec[i++] = GLX_DEPTH_SIZE; spec[i++] = format.depthBufferSize(); - } + << GLX_ALPHA_SIZE + << qMax(0, format.alphaBufferSize()); - if (format.stencilBufferSize() > 0) { - spec[i++] = GLX_STENCIL_SIZE; spec[i++] = (format.stencilBufferSize() == -1) ? 1 : format.stencilBufferSize(); - } + if (format.swapBehavior() != QSurfaceFormat::SingleBuffer) + spec << GLX_DOUBLEBUFFER + << True; - if (format.samples() > 1) { - spec[i++] = GLX_SAMPLE_BUFFERS_ARB; - spec[i++] = 1; - spec[i++] = GLX_SAMPLES_ARB; - spec[i++] = format.samples(); - } + if (format.stereo()) + spec << GLX_STEREO + << True; + + if (format.depthBufferSize() != -1) + spec << GLX_DEPTH_SIZE + << format.depthBufferSize(); + + if (format.stencilBufferSize() != -1) + spec << GLX_STENCIL_SIZE + << format.stencilBufferSize(); + + if (format.samples() > 1) + spec << GLX_SAMPLE_BUFFERS_ARB + << 1 + << GLX_SAMPLES_ARB + << format.samples(); + + spec << GLX_DRAWABLE_TYPE + << drawableBit + + << XNone; - spec[i++] = XNone; return spec; } -GLXFBConfig qglx_findConfig(Display *display, int screen , const QSurfaceFormat &format, int drawableBit) -{ - // Allow forcing LIBGL_ALWAYS_SOFTWARE for Qt 5 applications only. - // This is most useful with drivers that only support OpenGL 1. - // We need OpenGL 2, but the user probably doesn't want - // LIBGL_ALWAYS_SOFTWARE in OpenGL 1 apps. - static bool checkedForceSoftwareOpenGL = false; - static bool forceSoftwareOpenGL = false; - if (!checkedForceSoftwareOpenGL) { - // If LIBGL_ALWAYS_SOFTWARE is already set, don't mess with it. - // We want to unset LIBGL_ALWAYS_SOFTWARE at the end so it does not - // get inherited by other processes, of course only if it wasn't - // already set before. - if (!qEnvironmentVariableIsEmpty("QT_XCB_FORCE_SOFTWARE_OPENGL") - && !qEnvironmentVariableIsSet("LIBGL_ALWAYS_SOFTWARE")) - forceSoftwareOpenGL = true; - - checkedForceSoftwareOpenGL = true; - } +namespace { +struct QXcbSoftwareOpenGLEnforcer { + QXcbSoftwareOpenGLEnforcer() { + // Allow forcing LIBGL_ALWAYS_SOFTWARE for Qt 5 applications only. + // This is most useful with drivers that only support OpenGL 1. + // We need OpenGL 2, but the user probably doesn't want + // LIBGL_ALWAYS_SOFTWARE in OpenGL 1 apps. + + if (!checkedForceSoftwareOpenGL) { + // If LIBGL_ALWAYS_SOFTWARE is already set, don't mess with it. + // We want to unset LIBGL_ALWAYS_SOFTWARE at the end so it does not + // get inherited by other processes, of course only if it wasn't + // already set before. + if (!qEnvironmentVariableIsEmpty("QT_XCB_FORCE_SOFTWARE_OPENGL") + && !qEnvironmentVariableIsSet("LIBGL_ALWAYS_SOFTWARE")) + forceSoftwareOpenGL = true; + + checkedForceSoftwareOpenGL = true; + } - if (forceSoftwareOpenGL) - qputenv("LIBGL_ALWAYS_SOFTWARE", QByteArrayLiteral("1")); + if (forceSoftwareOpenGL) + qputenv("LIBGL_ALWAYS_SOFTWARE", QByteArrayLiteral("1")); + } - bool reduced = true; - GLXFBConfig chosenConfig = 0; - QSurfaceFormat reducedFormat = format; - while (!chosenConfig && reduced) { - QVector<int> spec = qglx_buildSpec(reducedFormat, drawableBit); - int confcount = 0; - GLXFBConfig *configs; - configs = glXChooseFBConfig(display, screen,spec.constData(),&confcount); - if (confcount) - { - for (int i = 0; i < confcount; i++) { - chosenConfig = configs[i]; - // Make sure we try to get an ARGB visual if the format asked for an alpha: - if (reducedFormat.hasAlpha()) { - int alphaSize; - glXGetFBConfigAttrib(display,configs[i],GLX_ALPHA_SIZE,&alphaSize); - if (alphaSize > 0) { - XVisualInfo *visual = glXGetVisualFromFBConfig(display, chosenConfig); - bool hasAlpha = false; - -#if !defined(QT_NO_XRENDER) - XRenderPictFormat *pictFormat = XRenderFindVisualFormat(display, visual->visual); - hasAlpha = pictFormat->direct.alphaMask > 0; -#else - hasAlpha = visual->depth == 32; -#endif + ~QXcbSoftwareOpenGLEnforcer() { + // unset LIBGL_ALWAYS_SOFTWARE now so other processes don't inherit it + if (forceSoftwareOpenGL) + qunsetenv("LIBGL_ALWAYS_SOFTWARE"); + } - XFree(visual); + static bool checkedForceSoftwareOpenGL; + static bool forceSoftwareOpenGL; +}; - if (hasAlpha) - break; - } - } else { - break; // Just choose the first in the list if there's no alpha requested - } - } +bool QXcbSoftwareOpenGLEnforcer::checkedForceSoftwareOpenGL = false; +bool QXcbSoftwareOpenGLEnforcer::forceSoftwareOpenGL = false; - XFree(configs); - } - if (!chosenConfig) - reducedFormat = qglx_reduceSurfaceFormat(reducedFormat,&reduced); +template <class T> +struct QXlibScopedPointerDeleter { + static inline void cleanup(T *pointer) { + XFree(pointer); } +}; - // unset LIBGL_ALWAYS_SOFTWARE now so other processes don't inherit it - if (forceSoftwareOpenGL) - qunsetenv("LIBGL_ALWAYS_SOFTWARE"); +template <class T> +using QXlibPointer = QScopedPointer<T, QXlibScopedPointerDeleter<T>>; - return chosenConfig; +template <class T> +using QXlibArrayPointer = QScopedArrayPointer<T, QXlibScopedPointerDeleter<T>>; } -XVisualInfo *qglx_findVisualInfo(Display *display, int screen, QSurfaceFormat *format) +GLXFBConfig qglx_findConfig(Display *display, int screen , QSurfaceFormat format, bool highestPixelFormat, int drawableBit) { - Q_ASSERT(format); + QXcbSoftwareOpenGLEnforcer softwareOpenGLEnforcer; - XVisualInfo *visualInfo = 0; + GLXFBConfig config = 0; - GLXFBConfig config = qglx_findConfig(display,screen,*format); - if (config) { - visualInfo = glXGetVisualFromFBConfig(display, config); - qglx_surfaceFormatFromGLXFBConfig(format, display, config); - } + do { + const QVector<int> spec = qglx_buildSpec(format, drawableBit); - // attempt to fall back to glXChooseVisual - bool reduced = true; - QSurfaceFormat reducedFormat = *format; - while (!visualInfo && reduced) { - QVarLengthArray<int, 13> attribs; - attribs.append(GLX_RGBA); - - if (reducedFormat.redBufferSize() > 0) { - attribs.append(GLX_RED_SIZE); - attribs.append(reducedFormat.redBufferSize()); - } + int confcount = 0; + QXlibArrayPointer<GLXFBConfig> configs(glXChooseFBConfig(display, screen, spec.constData(), &confcount)); - if (reducedFormat.greenBufferSize() > 0) { - attribs.append(GLX_GREEN_SIZE); - attribs.append(reducedFormat.greenBufferSize()); + if (!config && confcount > 0) { + config = configs[0]; + if (highestPixelFormat && !format.hasAlpha()) + break; } - if (reducedFormat.blueBufferSize() > 0) { - attribs.append(GLX_BLUE_SIZE); - attribs.append(reducedFormat.blueBufferSize()); - } + const int requestedRed = qMax(0, format.redBufferSize()); + const int requestedGreen = qMax(0, format.greenBufferSize()); + const int requestedBlue = qMax(0, format.blueBufferSize()); + const int requestedAlpha = qMax(0, format.alphaBufferSize()); - if (reducedFormat.stencilBufferSize() > 0) { - attribs.append(GLX_STENCIL_SIZE); - attribs.append(reducedFormat.stencilBufferSize()); - } + for (int i = 0; i < confcount; i++) { + GLXFBConfig candidate = configs[i]; + + QXlibPointer<XVisualInfo> visual(glXGetVisualFromFBConfig(display, candidate)); - if (reducedFormat.depthBufferSize() > 0) { - attribs.append(GLX_DEPTH_SIZE); - attribs.append(reducedFormat.depthBufferSize()); + const int actualRed = qPopulationCount(visual->red_mask); + const int actualGreen = qPopulationCount(visual->green_mask); + const int actualBlue = qPopulationCount(visual->blue_mask); + const int actualAlpha = visual->depth - actualRed - actualGreen - actualBlue; + + if (requestedRed && actualRed != requestedRed) + continue; + if (requestedGreen && actualGreen != requestedGreen) + continue; + if (requestedBlue && actualBlue != requestedBlue) + continue; + if (requestedAlpha && actualAlpha != requestedAlpha) + continue; + + return candidate; } + } while (qglx_reduceFormat(&format)); + + return config; +} - if (reducedFormat.swapBehavior() != QSurfaceFormat::SingleBuffer) - attribs.append(GLX_DOUBLEBUFFER); +XVisualInfo *qglx_findVisualInfo(Display *display, int screen, QSurfaceFormat *format, int drawableBit) +{ + Q_ASSERT(format); - attribs.append(XNone); + XVisualInfo *visualInfo = 0; - visualInfo = glXChooseVisual(display, screen, attribs.data()); - if (visualInfo) - *format = reducedFormat; + GLXFBConfig config = qglx_findConfig(display, screen, *format, false, drawableBit); + if (config) + visualInfo = glXGetVisualFromFBConfig(display, config); - reducedFormat = qglx_reduceSurfaceFormat(reducedFormat, &reduced); + if (visualInfo) { + qglx_surfaceFormatFromGLXFBConfig(format, display, config); + return visualInfo; } + // attempt to fall back to glXChooseVisual + do { + QVector<int> attribs = qglx_buildSpec(*format, drawableBit); + visualInfo = glXChooseVisual(display, screen, attribs.data()); + + if (visualInfo) { + qglx_surfaceFormatFromVisualInfo(format, display, visualInfo); + return visualInfo; + } + } while (qglx_reduceFormat(format)); + return visualInfo; } @@ -318,33 +327,64 @@ void qglx_surfaceFormatFromVisualInfo(QSurfaceFormat *format, Display *display, format->setStereo(stereo); } -QSurfaceFormat qglx_reduceSurfaceFormat(const QSurfaceFormat &format, bool *reduced) +bool qglx_reduceFormat(QSurfaceFormat *format) { - QSurfaceFormat retFormat = format; - *reduced = true; - - if (retFormat.depthBufferSize() >= 32) { - retFormat.setDepthBufferSize(24); - } else if (retFormat.depthBufferSize() > 0) { - retFormat.setDepthBufferSize(0); - } else if (retFormat.redBufferSize() > 1) { - retFormat.setRedBufferSize(1); - } else if (retFormat.greenBufferSize() > 1) { - retFormat.setGreenBufferSize(1); - } else if (retFormat.blueBufferSize() > 1) { - retFormat.setBlueBufferSize(1); - } else if (retFormat.samples() > 1) { - retFormat.setSamples(qMin(retFormat.samples() / 2, 16)); - } else if (retFormat.stereo()) { - retFormat.setStereo(false); - }else if (retFormat.stencilBufferSize() > 0) { - retFormat.setStencilBufferSize(0); - }else if (retFormat.hasAlpha()) { - retFormat.setAlphaBufferSize(0); - }else if (retFormat.swapBehavior() != QSurfaceFormat::SingleBuffer) { - retFormat.setSwapBehavior(QSurfaceFormat::SingleBuffer); - }else{ - *reduced = false; + Q_ASSERT(format); + + if (format->redBufferSize() > 1) { + format->setRedBufferSize(1); + return true; + } + + if (format->greenBufferSize() > 1) { + format->setGreenBufferSize(1); + return true; + } + + if (format->blueBufferSize() > 1) { + format->setBlueBufferSize(1); + return true; } - return retFormat; + + if (format->swapBehavior() != QSurfaceFormat::SingleBuffer){ + format->setSwapBehavior(QSurfaceFormat::SingleBuffer); + return true; + } + + if (format->samples() > 1) { + format->setSamples(qMin(16, format->samples() / 2)); + return true; + } + + if (format->depthBufferSize() >= 32) { + format->setDepthBufferSize(24); + return true; + } + + if (format->depthBufferSize() > 1) { + format->setDepthBufferSize(1); + return true; + } + + if (format->depthBufferSize() > 0) { + format->setDepthBufferSize(0); + return true; + } + + if (format->hasAlpha()) { + format->setAlphaBufferSize(0); + return true; + } + + if (format->stencilBufferSize() > 1) { + format->setStencilBufferSize(1); + return true; + } + + if (format->stencilBufferSize() > 0) { + format->setStencilBufferSize(0); + return true; + } + + return false; } diff --git a/src/platformsupport/glxconvenience/qglxconvenience_p.h b/src/platformsupport/glxconvenience/qglxconvenience_p.h index 309974f357..d422668584 100644 --- a/src/platformsupport/glxconvenience/qglxconvenience_p.h +++ b/src/platformsupport/glxconvenience/qglxconvenience_p.h @@ -57,11 +57,11 @@ #include <X11/Xlib.h> #include <GL/glx.h> -XVisualInfo *qglx_findVisualInfo(Display *display, int screen, QSurfaceFormat *format); -GLXFBConfig qglx_findConfig(Display *display, int screen, const QSurfaceFormat &format, int drawableBit = GLX_WINDOW_BIT); +QVector<int> qglx_buildSpec(const QSurfaceFormat &format, int drawableBit = GLX_WINDOW_BIT); +XVisualInfo *qglx_findVisualInfo(Display *display, int screen, QSurfaceFormat *format, int drawableBit = GLX_WINDOW_BIT); +GLXFBConfig qglx_findConfig(Display *display, int screen, QSurfaceFormat format, bool highestPixelFormat = false, int drawableBit = GLX_WINDOW_BIT); void qglx_surfaceFormatFromGLXFBConfig(QSurfaceFormat *format, Display *display, GLXFBConfig config); void qglx_surfaceFormatFromVisualInfo(QSurfaceFormat *format, Display *display, XVisualInfo *visualInfo); -QVector<int> qglx_buildSpec(const QSurfaceFormat &format, int drawableBit = GLX_WINDOW_BIT); -QSurfaceFormat qglx_reduceSurfaceFormat(const QSurfaceFormat &format, bool *reduced); +bool qglx_reduceFormat(QSurfaceFormat *format); #endif // QGLXCONVENIENCE_H diff --git a/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglintegration.cpp b/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglintegration.cpp index f546cda4ad..079f0466dc 100644 --- a/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglintegration.cpp +++ b/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglintegration.cpp @@ -87,7 +87,7 @@ QXcbWindow *QXcbEglIntegration::createWindow(QWindow *window) const QPlatformOpenGLContext *QXcbEglIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const { QXcbScreen *screen = static_cast<QXcbScreen *>(context->screen()->handle()); - QXcbEglContext *platformContext = new QXcbEglContext(context->format(), + QXcbEglContext *platformContext = new QXcbEglContext(screen->surfaceFormatFor(context->format()), context->shareHandle(), eglDisplay(), screen->connection(), @@ -98,7 +98,8 @@ QPlatformOpenGLContext *QXcbEglIntegration::createPlatformOpenGLContext(QOpenGLC QPlatformOffscreenSurface *QXcbEglIntegration::createPlatformOffscreenSurface(QOffscreenSurface *surface) const { - return new QEGLPbuffer(eglDisplay(), surface->requestedFormat(), surface); + QXcbScreen *screen = static_cast<QXcbScreen *>(surface->screen()->handle()); + return new QEGLPbuffer(eglDisplay(), screen->surfaceFormatFor(surface->requestedFormat()), surface); } void *QXcbEglIntegration::xlib_display() const diff --git a/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglwindow.cpp b/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglwindow.cpp index 777dfac535..69b7dfbdbf 100644 --- a/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglwindow.cpp +++ b/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglwindow.cpp @@ -59,15 +59,19 @@ QXcbEglWindow::~QXcbEglWindow() eglDestroySurface(m_glIntegration->eglDisplay(), m_surface); } -void QXcbEglWindow::resolveFormat() +void QXcbEglWindow::resolveFormat(const QSurfaceFormat &format) { - m_config = q_configFromGLFormat(m_glIntegration->eglDisplay(), window()->requestedFormat(), true); - m_format = q_glFormatFromConfig(m_glIntegration->eglDisplay(), m_config, m_format); + m_config = q_configFromGLFormat(m_glIntegration->eglDisplay(), format); + m_format = q_glFormatFromConfig(m_glIntegration->eglDisplay(), m_config, format); } -void *QXcbEglWindow::createVisual() -{ #ifdef XCB_USE_XLIB +const xcb_visualtype_t *QXcbEglWindow::createVisual() +{ + QXcbScreen *scr = xcbScreen(); + if (!scr) + return QXcbWindow::createVisual(); + Display *xdpy = static_cast<Display *>(m_glIntegration->xlib_display()); VisualID id = QXlibEglIntegration::getCompatibleVisualId(xdpy, m_glIntegration->eglDisplay(), m_config); @@ -78,11 +82,12 @@ void *QXcbEglWindow::createVisual() XVisualInfo *visualInfo; int matchingCount = 0; visualInfo = XGetVisualInfo(xdpy, VisualIDMask, &visualInfoTemplate, &matchingCount); - return visualInfo; -#else - return QXcbWindow::createVisual(); -#endif + const xcb_visualtype_t *xcb_visualtype = scr->visualForId(visualInfo->visualid); + XFree(visualInfo); + + return xcb_visualtype; } +#endif void QXcbEglWindow::create() { diff --git a/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglwindow.h b/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglwindow.h index f36f53d168..48fc6dce70 100644 --- a/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglwindow.h +++ b/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglwindow.h @@ -60,8 +60,11 @@ public: protected: void create() Q_DECL_OVERRIDE; - void resolveFormat() Q_DECL_OVERRIDE; - void *createVisual() Q_DECL_OVERRIDE; + void resolveFormat(const QSurfaceFormat &format) Q_DECL_OVERRIDE; + +#ifdef XCB_USE_XLIB + const xcb_visualtype_t *createVisual() Q_DECL_OVERRIDE; +#endif private: QXcbEglIntegration *m_glIntegration; diff --git a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp index 4290ec54fc..5580f81a7a 100644 --- a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp +++ b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp @@ -715,8 +715,8 @@ bool QGLXContext::supportsThreading() QGLXPbuffer::QGLXPbuffer(QOffscreenSurface *offscreenSurface) : QPlatformOffscreenSurface(offscreenSurface) - , m_format(offscreenSurface->requestedFormat()) , m_screen(static_cast<QXcbScreen *>(offscreenSurface->screen()->handle())) + , m_format(m_screen->surfaceFormatFor(offscreenSurface->requestedFormat())) , m_pbuffer(0) { GLXFBConfig config = qglx_findConfig(DISPLAY_FROM_XCB(m_screen), m_screen->screenNumber(), m_format); diff --git a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.h b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.h index f00d96e6d5..bf1f1b324b 100644 --- a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.h +++ b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.h @@ -106,8 +106,8 @@ public: GLXPbuffer pbuffer() const { return m_pbuffer; } private: - QSurfaceFormat m_format; QXcbScreen *m_screen; + QSurfaceFormat m_format; GLXPbuffer m_pbuffer; }; diff --git a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxintegration.cpp b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxintegration.cpp index a3668df59a..d536121521 100644 --- a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxintegration.cpp +++ b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxintegration.cpp @@ -189,7 +189,7 @@ QXcbWindow *QXcbGlxIntegration::createWindow(QWindow *window) const QPlatformOpenGLContext *QXcbGlxIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const { QXcbScreen *screen = static_cast<QXcbScreen *>(context->screen()->handle()); - QGLXContext *platformContext = new QGLXContext(screen, context->format(), + QGLXContext *platformContext = new QGLXContext(screen, screen->surfaceFormatFor(context->format()), context->shareHandle(), context->nativeHandle()); context->setNativeHandle(platformContext->nativeHandle()); return platformContext; diff --git a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxwindow.cpp b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxwindow.cpp index 36503f4a7c..8ae83b8084 100644 --- a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxwindow.cpp +++ b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxwindow.cpp @@ -53,17 +53,15 @@ QXcbGlxWindow::~QXcbGlxWindow() { } -void QXcbGlxWindow::resolveFormat() -{ - m_format = window()->requestedFormat(); //qglx_findVisualInfo sets the resovled format -} - -void *QXcbGlxWindow::createVisual() +const xcb_visualtype_t *QXcbGlxWindow::createVisual() { QXcbScreen *scr = xcbScreen(); if (!scr) return Q_NULLPTR; - return qglx_findVisualInfo(DISPLAY_FROM_XCB(scr), scr->screenNumber(), &m_format); + XVisualInfo *visualInfo = qglx_findVisualInfo(DISPLAY_FROM_XCB(scr), scr->screenNumber(), &m_format); + const xcb_visualtype_t *xcb_visualtype = scr->visualForId(visualInfo->visualid); + XFree(visualInfo); + return xcb_visualtype; } QT_END_NAMESPACE diff --git a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxwindow.h b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxwindow.h index 1954f972f1..9519245130 100644 --- a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxwindow.h +++ b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxwindow.h @@ -52,8 +52,7 @@ public: ~QXcbGlxWindow(); protected: - void resolveFormat() Q_DECL_OVERRIDE; - void *createVisual() Q_DECL_OVERRIDE; + const xcb_visualtype_t *createVisual() Q_DECL_OVERRIDE; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/xcb/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp index 67a9b2f190..4cb1b29152 100644 --- a/src/plugins/platforms/xcb/qxcbscreen.cpp +++ b/src/plugins/platforms/xcb/qxcbscreen.cpp @@ -47,6 +47,7 @@ #include <stdio.h> #include <QDebug> +#include <QtAlgorithms> #include <qpa/qwindowsysteminterface.h> #include <private/qmath_p.h> @@ -359,6 +360,69 @@ void QXcbScreen::windowShown(QXcbWindow *window) } } +QSurfaceFormat QXcbScreen::surfaceFormatFor(const QSurfaceFormat &format) const +{ + const xcb_visualid_t xcb_visualid = connection()->hasDefaultVisualId() ? connection()->defaultVisualId() + : screen()->root_visual; + const xcb_visualtype_t *xcb_visualtype = visualForId(xcb_visualid); + + const int redSize = qPopulationCount(xcb_visualtype->red_mask); + const int greenSize = qPopulationCount(xcb_visualtype->green_mask); + const int blueSize = qPopulationCount(xcb_visualtype->blue_mask); + + QSurfaceFormat result = format; + + if (result.redBufferSize() < 0) + result.setRedBufferSize(redSize); + + if (result.greenBufferSize() < 0) + result.setGreenBufferSize(greenSize); + + if (result.blueBufferSize() < 0) + result.setBlueBufferSize(blueSize); + + return result; +} + +const xcb_visualtype_t *QXcbScreen::visualForFormat(const QSurfaceFormat &format) const +{ + QVector<const xcb_visualtype_t *> candidates; + + for (auto ii = m_visuals.constBegin(); ii != m_visuals.constEnd(); ++ii) { + const xcb_visualtype_t &xcb_visualtype = ii.value(); + + const int redSize = qPopulationCount(xcb_visualtype.red_mask); + const int greenSize = qPopulationCount(xcb_visualtype.green_mask); + const int blueSize = qPopulationCount(xcb_visualtype.blue_mask); + const int alphaSize = depthOfVisual(xcb_visualtype.visual_id) - redSize - greenSize - blueSize; + + if (format.redBufferSize() != -1 && redSize != format.redBufferSize()) + continue; + + if (format.greenBufferSize() != -1 && greenSize != format.greenBufferSize()) + continue; + + if (format.blueBufferSize() != -1 && blueSize != format.blueBufferSize()) + continue; + + if (format.alphaBufferSize() != -1 && alphaSize != format.alphaBufferSize()) + continue; + + candidates.append(&xcb_visualtype); + } + + if (candidates.isEmpty()) + return nullptr; + + // Try to find a RGB visual rather than e.g. BGR or GBR + for (const xcb_visualtype_t *candidate : qAsConst(candidates)) + if (qCountTrailingZeroBits(candidate->blue_mask) == 0) + return candidate; + + // Did not find anything we like, just grab the first one and hope for the best + return candidates.first(); +} + void QXcbScreen::sendStartupMessage(const QByteArray &message) const { xcb_window_t rootWindow = root(); @@ -403,7 +467,7 @@ quint8 QXcbScreen::depthOfVisual(xcb_visualid_t visualid) const QImage::Format QXcbScreen::format() const { - return QImage::Format_RGB32; + return qt_xcb_imageFormatForVisual(connection(), screen()->root_depth, visualForId(screen()->root_visual)); } QDpi QXcbScreen::virtualDpi() const diff --git a/src/plugins/platforms/xcb/qxcbscreen.h b/src/plugins/platforms/xcb/qxcbscreen.h index 30c5073459..8716af29b5 100644 --- a/src/plugins/platforms/xcb/qxcbscreen.h +++ b/src/plugins/platforms/xcb/qxcbscreen.h @@ -155,6 +155,9 @@ public: QString windowManagerName() const { return m_windowManagerName; } bool syncRequestSupported() const { return m_syncRequestSupported; } + QSurfaceFormat surfaceFormatFor(const QSurfaceFormat &format) const; + + const xcb_visualtype_t *visualForFormat(const QSurfaceFormat &format) const; const xcb_visualtype_t *visualForId(xcb_visualid_t) const; quint8 depthOfVisual(xcb_visualid_t) const; diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index 13eecbfb4f..a97420380c 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -382,18 +382,6 @@ void QXcbWindow::create() return; } - const quint32 mask = XCB_CW_BACK_PIXMAP | XCB_CW_OVERRIDE_REDIRECT | XCB_CW_SAVE_UNDER | XCB_CW_EVENT_MASK; - const quint32 values[] = { - // XCB_CW_BACK_PIXMAP - XCB_NONE, - // XCB_CW_OVERRIDE_REDIRECT - type == Qt::Popup || type == Qt::ToolTip || (window()->flags() & Qt::BypassWindowManagerHint), - // XCB_CW_SAVE_UNDER - type == Qt::Popup || type == Qt::Tool || type == Qt::SplashScreen || type == Qt::ToolTip || type == Qt::Drawer, - // XCB_CW_EVENT_MASK - defaultEventMask - }; - // Parameters to XCreateWindow() are frame corner + inner size. // This fits in case position policy is frame inclusive. There is // currently no way to implement it for frame-exclusive geometries. @@ -424,108 +412,76 @@ void QXcbWindow::create() } } - resolveFormat(); - -#ifdef XCB_USE_XLIB - if (window()->surfaceType() != QSurface::RasterSurface - && QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::OpenGL)) { - XVisualInfo *visualInfo = Q_NULLPTR; - if (connection()->hasDefaultVisualId()) - visualInfo = CREATE_VISUALINFO_FROM_DEFAULT_VISUALID(this); - if (!visualInfo) - visualInfo = static_cast<XVisualInfo *>(createVisual()); - - if (Q_UNLIKELY(!visualInfo && window()->surfaceType() == QSurface::OpenGLSurface)) - qFatal("Could not initialize OpenGL"); - - if (!visualInfo && window()->surfaceType() == QSurface::RasterGLSurface) { - qWarning("Could not initialize OpenGL for RasterGLSurface, reverting to RasterSurface."); - window()->setSurfaceType(QSurface::RasterSurface); - } - - if (visualInfo) { - m_depth = visualInfo->depth; - m_imageFormat = imageFormatForVisual(visualInfo->depth, visualInfo->red_mask, visualInfo->blue_mask, &m_imageRgbSwap); - Colormap cmap = XCreateColormap(DISPLAY_FROM_XCB(this), xcb_parent_id, visualInfo->visual, AllocNone); + resolveFormat(platformScreen->surfaceFormatFor(window()->requestedFormat())); - XSetWindowAttributes a; - a.background_pixel = WhitePixel(DISPLAY_FROM_XCB(this), platformScreen->screenNumber()); - a.border_pixel = BlackPixel(DISPLAY_FROM_XCB(this), platformScreen->screenNumber()); - a.colormap = cmap; + const xcb_visualtype_t *visual = Q_NULLPTR; - m_visualId = visualInfo->visualid; + if (connection()->hasDefaultVisualId()) { + visual = platformScreen->visualForId(connection()->defaultVisualId()); + if (!visual) + qWarning() << "Failed to use requested visual id."; + } - m_window = XCreateWindow(DISPLAY_FROM_XCB(this), xcb_parent_id, rect.x(), rect.y(), rect.width(), rect.height(), - 0, visualInfo->depth, InputOutput, visualInfo->visual, - CWBackPixel|CWBorderPixel|CWColormap, &a); + if (!visual) + visual = createVisual(); - XFree(visualInfo); - } + if (!visual) { + qWarning() << "Falling back to using screens root_visual."; + visual = platformScreen->visualForId(platformScreen->screen()->root_visual); } -#endif - if (!m_window) - { - m_window = xcb_generate_id(xcb_connection()); - m_visualId = UINT_MAX; - const xcb_visualtype_t *visual = Q_NULLPTR; - m_depth = platformScreen->screen()->root_depth; + Q_ASSERT(visual); - uint32_t mask = 0; - uint32_t values[3]; + m_visualId = visual->visual_id; + m_depth = platformScreen->depthOfVisual(m_visualId); + m_imageFormat = imageFormatForVisual(m_depth, visual->red_mask, visual->blue_mask, &m_imageRgbSwap); + xcb_colormap_t colormap = 0; - if (connection()->hasDefaultVisualId()) { - m_visualId = connection()->defaultVisualId(); - visual = platformScreen->visualForId(m_visualId); - } + quint32 mask = XCB_CW_BACK_PIXMAP + | XCB_CW_BORDER_PIXEL + | XCB_CW_BIT_GRAVITY + | XCB_CW_OVERRIDE_REDIRECT + | XCB_CW_SAVE_UNDER + | XCB_CW_EVENT_MASK; - if (!visual) { - if (connection()->hasDefaultVisualId()) - qWarning("Failed to use default visual id. Falling back to using screens root_visual"); - - m_visualId = platformScreen->screen()->root_visual; - - if (m_format.alphaBufferSize() == 8) { - xcb_depth_iterator_t depthIter = xcb_screen_allowed_depths_iterator(platformScreen->screen()); - while (depthIter.rem) { - if (depthIter.data->depth == 32) { - xcb_visualtype_iterator_t visualIter = xcb_depth_visuals_iterator(depthIter.data); - if (visualIter.rem) { - m_visualId = visualIter.data->visual_id; - m_depth = 32; - uint32_t colormap = xcb_generate_id(xcb_connection()); - xcb_create_colormap(xcb_connection(), XCB_COLORMAP_ALLOC_NONE, colormap, - xcb_parent_id, m_visualId); - mask |= XCB_CW_BACK_PIXEL | XCB_CW_BORDER_PIXEL | XCB_CW_COLORMAP; - values[0] = platformScreen->screen()->white_pixel; - values[1] = platformScreen->screen()->black_pixel; - values[2] = colormap; - break; - } - } - xcb_depth_next(&depthIter); - } - } + static const bool haveOpenGL = QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::OpenGL); - visual = platformScreen->visualForId(m_visualId); - } + if ((window()->supportsOpenGL() && haveOpenGL) || m_format.hasAlpha()) { + colormap = xcb_generate_id(xcb_connection()); + Q_XCB_CALL(xcb_create_colormap(xcb_connection(), + XCB_COLORMAP_ALLOC_NONE, + colormap, + xcb_parent_id, + m_visualId)); - m_imageFormat = imageFormatForVisual(m_depth, visual->red_mask, visual->blue_mask, &m_imageRgbSwap); - Q_XCB_CALL(xcb_create_window(xcb_connection(), - m_depth, - m_window, // window id - xcb_parent_id, // parent window id - rect.x(), - rect.y(), - rect.width(), - rect.height(), - 0, // border width - XCB_WINDOW_CLASS_INPUT_OUTPUT, // window class - m_visualId, // visual - mask, - values)); + mask |= XCB_CW_COLORMAP; } + quint32 values[] = { + XCB_BACK_PIXMAP_NONE, + platformScreen->screen()->black_pixel, + XCB_GRAVITY_NORTH_WEST, + type == Qt::Popup || type == Qt::ToolTip || (window()->flags() & Qt::BypassWindowManagerHint), + type == Qt::Popup || type == Qt::Tool || type == Qt::SplashScreen || type == Qt::ToolTip || type == Qt::Drawer, + defaultEventMask, + colormap + }; + + m_window = xcb_generate_id(xcb_connection()); + Q_XCB_CALL(xcb_create_window(xcb_connection(), + m_depth, + m_window, // window id + xcb_parent_id, // parent window id + rect.x(), + rect.y(), + rect.width(), + rect.height(), + 0, // border width + XCB_WINDOW_CLASS_INPUT_OUTPUT, // window class + m_visualId, // visual + mask, + values)); + connection()->addWindowEventListener(m_window, this); Q_XCB_CALL(xcb_change_window_attributes(xcb_connection(), m_window, mask, values)); @@ -2560,6 +2516,12 @@ void QXcbWindow::updateSyncRequestCounter() } } +const xcb_visualtype_t *QXcbWindow::createVisual() +{ + return xcbScreen() ? xcbScreen()->visualForFormat(m_format) + : nullptr; +} + bool QXcbWindow::setKeyboardGrabEnabled(bool grab) { if (grab && !connection()->canGrab()) @@ -2831,3 +2793,4 @@ QXcbScreen *QXcbWindow::xcbScreen() const } QT_END_NAMESPACE + diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h index 7b70dc2ef8..9ad0153ca2 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.h +++ b/src/plugins/platforms/xcb/qxcbwindow.h @@ -182,8 +182,8 @@ public Q_SLOTS: void updateSyncRequestCounter(); protected: - virtual void resolveFormat() { m_format = window()->requestedFormat(); } - virtual void *createVisual() { return Q_NULLPTR; } + virtual void resolveFormat(const QSurfaceFormat &format) { m_format = format; } + virtual const xcb_visualtype_t *createVisual(); QXcbScreen *parentScreen(); |