summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLouai Al-Khanji <louai.al-khanji@theqtcompany.com>2016-03-03 14:16:29 -0800
committerLouai Al-Khanji <louai.al-khanji@theqtcompany.com>2016-04-09 05:17:27 +0000
commit5f39a0ef8d037ed8d1fa19d5514308ed4a2ca161 (patch)
treea9d0d69ba8add9ef11384a577ec5f9692aeed709 /src
parent89034600939bbfe241ba3d6136abf7bb6961db52 (diff)
X11: Better support non-32bit visuals
This patch improves support for non-32bit screen configurations on X. The patch mostly touches the xcb platform plugin but the changes to the glx convenience functions do affect e.g. the offscreen plugin as well. Since QWindow instances are now by default of type RasterGL instead of Raster the majority of all windows are in fact instances of QXcbGlxWindow. This means that the eventual QSurfaceFormat that we use is chosen based on the available OpenGL configurations. Here the GLX config resolution code did not do a very good job in trying to find the closest match relative to the requested QSurfaceFormat, instead preferring higher bit depths. This is an issue since many configurations support 32-bit windows even if the screen itself has a root window with depth 16. In particular, servers supporting both GLX and Render are very likely to have such visuals. Particularly affected are remote X connections - even if the application itself makes no use of OpenGL at all! The changes introduced by this patch are as follows: 1. Improve the GLX visual selection logic 2. Improve the xcb visual selection logic 3. Remove duplicated visual lookup for OpenGL-enabled windows 4. Configure the default QSurfaceFormat to match the primary screen depth Change-Id: Id1c176359e63a4581410e20350db5ac2c083e1cf Reviewed-by: Lars Knoll <lars.knoll@theqtcompany.com> Reviewed-by: Laszlo Agocs <laszlo.agocs@theqtcompany.com>
Diffstat (limited to 'src')
-rw-r--r--src/platformsupport/glxconvenience/qglxconvenience.cpp354
-rw-r--r--src/platformsupport/glxconvenience/qglxconvenience_p.h8
-rw-r--r--src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglintegration.cpp5
-rw-r--r--src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglwindow.cpp23
-rw-r--r--src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglwindow.h7
-rw-r--r--src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp2
-rw-r--r--src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.h2
-rw-r--r--src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxintegration.cpp2
-rw-r--r--src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxwindow.cpp12
-rw-r--r--src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxwindow.h3
-rw-r--r--src/plugins/platforms/xcb/qxcbscreen.cpp66
-rw-r--r--src/plugins/platforms/xcb/qxcbscreen.h3
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.cpp165
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.h4
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();