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>
bb10
Louai Al-Khanji 2016-03-03 14:16:29 -08:00
parent 8903460093
commit 5f39a0ef8d
14 changed files with 376 additions and 300 deletions

View File

@ -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,173 +78,181 @@ 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;
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.
checkedForceSoftwareOpenGL = true;
}
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;
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
XFree(visual);
if (hasAlpha)
break;
}
} else {
break; // Just choose the first in the list if there's no alpha requested
}
}
XFree(configs);
checkedForceSoftwareOpenGL = true;
}
if (!chosenConfig)
reducedFormat = qglx_reduceSurfaceFormat(reducedFormat,&reduced);
if (forceSoftwareOpenGL)
qputenv("LIBGL_ALWAYS_SOFTWARE", QByteArrayLiteral("1"));
}
// unset LIBGL_ALWAYS_SOFTWARE now so other processes don't inherit it
if (forceSoftwareOpenGL)
qunsetenv("LIBGL_ALWAYS_SOFTWARE");
~QXcbSoftwareOpenGLEnforcer() {
// unset LIBGL_ALWAYS_SOFTWARE now so other processes don't inherit it
if (forceSoftwareOpenGL)
qunsetenv("LIBGL_ALWAYS_SOFTWARE");
}
return chosenConfig;
static bool checkedForceSoftwareOpenGL;
static bool forceSoftwareOpenGL;
};
bool QXcbSoftwareOpenGLEnforcer::checkedForceSoftwareOpenGL = false;
bool QXcbSoftwareOpenGLEnforcer::forceSoftwareOpenGL = false;
template <class T>
struct QXlibScopedPointerDeleter {
static inline void cleanup(T *pointer) {
XFree(pointer);
}
};
template <class T>
using QXlibPointer = QScopedPointer<T, QXlibScopedPointerDeleter<T>>;
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)
{
QXcbSoftwareOpenGLEnforcer softwareOpenGLEnforcer;
GLXFBConfig config = 0;
do {
const QVector<int> spec = qglx_buildSpec(format, drawableBit);
int confcount = 0;
QXlibArrayPointer<GLXFBConfig> configs(glXChooseFBConfig(display, screen, spec.constData(), &confcount));
if (!config && confcount > 0) {
config = configs[0];
if (highestPixelFormat && !format.hasAlpha())
break;
}
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());
for (int i = 0; i < confcount; i++) {
GLXFBConfig candidate = configs[i];
QXlibPointer<XVisualInfo> visual(glXGetVisualFromFBConfig(display, candidate));
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;
}
XVisualInfo *qglx_findVisualInfo(Display *display, int screen, QSurfaceFormat *format, int drawableBit)
{
Q_ASSERT(format);
XVisualInfo *visualInfo = 0;
GLXFBConfig config = qglx_findConfig(display,screen,*format);
if (config) {
GLXFBConfig config = qglx_findConfig(display, screen, *format, false, drawableBit);
if (config)
visualInfo = glXGetVisualFromFBConfig(display, config);
if (visualInfo) {
qglx_surfaceFormatFromGLXFBConfig(format, display, config);
return visualInfo;
}
// 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());
}
if (reducedFormat.greenBufferSize() > 0) {
attribs.append(GLX_GREEN_SIZE);
attribs.append(reducedFormat.greenBufferSize());
}
if (reducedFormat.blueBufferSize() > 0) {
attribs.append(GLX_BLUE_SIZE);
attribs.append(reducedFormat.blueBufferSize());
}
if (reducedFormat.stencilBufferSize() > 0) {
attribs.append(GLX_STENCIL_SIZE);
attribs.append(reducedFormat.stencilBufferSize());
}
if (reducedFormat.depthBufferSize() > 0) {
attribs.append(GLX_DEPTH_SIZE);
attribs.append(reducedFormat.depthBufferSize());
}
if (reducedFormat.swapBehavior() != QSurfaceFormat::SingleBuffer)
attribs.append(GLX_DOUBLEBUFFER);
attribs.append(XNone);
do {
QVector<int> attribs = qglx_buildSpec(*format, drawableBit);
visualInfo = glXChooseVisual(display, screen, attribs.data());
if (visualInfo)
*format = reducedFormat;
reducedFormat = qglx_reduceSurfaceFormat(reducedFormat, &reduced);
}
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;
Q_ASSERT(format);
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;
if (format->redBufferSize() > 1) {
format->setRedBufferSize(1);
return true;
}
return retFormat;
if (format->greenBufferSize() > 1) {
format->setGreenBufferSize(1);
return true;
}
if (format->blueBufferSize() > 1) {
format->setBlueBufferSize(1);
return true;
}
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;
}

View File

@ -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

View File

@ -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

View File

@ -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()
{

View File

@ -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;

View File

@ -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);

View File

@ -106,8 +106,8 @@ public:
GLXPbuffer pbuffer() const { return m_pbuffer; }
private:
QSurfaceFormat m_format;
QXcbScreen *m_screen;
QSurfaceFormat m_format;
GLXPbuffer m_pbuffer;
};

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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();
resolveFormat(platformScreen->surfaceFormatFor(window()->requestedFormat()));
#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());
const xcb_visualtype_t *visual = Q_NULLPTR;
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);
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;
m_visualId = visualInfo->visualid;
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);
XFree(visualInfo);
}
if (connection()->hasDefaultVisualId()) {
visual = platformScreen->visualForId(connection()->defaultVisualId());
if (!visual)
qWarning() << "Failed to use requested visual id.";
}
#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;
if (!visual)
visual = createVisual();
uint32_t mask = 0;
uint32_t values[3];
if (connection()->hasDefaultVisualId()) {
m_visualId = connection()->defaultVisualId();
visual = platformScreen->visualForId(m_visualId);
}
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);
}
}
visual = platformScreen->visualForId(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));
if (!visual) {
qWarning() << "Falling back to using screens root_visual.";
visual = platformScreen->visualForId(platformScreen->screen()->root_visual);
}
Q_ASSERT(visual);
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;
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;
static const bool haveOpenGL = QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::OpenGL);
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));
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

View File

@ -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();