summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglintegration.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglintegration.cpp')
-rw-r--r--src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglintegration.cpp201
1 files changed, 155 insertions, 46 deletions
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 f3630d57b9..133b992cd9 100644
--- a/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglintegration.cpp
+++ b/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglintegration.cpp
@@ -1,56 +1,64 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the plugins of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qxcbeglintegration.h"
#include "qxcbeglcontext.h"
#include <QtGui/QOffscreenSurface>
+#include <QtGui/private/qeglconvenience_p.h>
#include <QtGui/private/qeglstreamconvenience_p.h>
+#include <optional>
#include "qxcbeglnativeinterfacehandler.h"
QT_BEGIN_NAMESPACE
+namespace {
+
+struct VisualInfo
+{
+ xcb_visualtype_t visualType;
+ uint8_t depth;
+};
+
+std::optional<VisualInfo> getVisualInfo(xcb_screen_t *screen,
+ std::optional<xcb_visualid_t> requestedVisualId,
+ std::optional<uint8_t> requestedDepth = std::nullopt)
+{
+ xcb_depth_iterator_t depthIterator = xcb_screen_allowed_depths_iterator(screen);
+
+ while (depthIterator.rem) {
+ xcb_depth_t *depth = depthIterator.data;
+ xcb_visualtype_iterator_t visualTypeIterator = xcb_depth_visuals_iterator(depth);
+
+ while (visualTypeIterator.rem) {
+ xcb_visualtype_t *visualType = visualTypeIterator.data;
+ if (requestedVisualId && visualType->visual_id != *requestedVisualId) {
+ xcb_visualtype_next(&visualTypeIterator);
+ continue;
+ }
+
+ if (requestedDepth && depth->depth != *requestedDepth) {
+ xcb_visualtype_next(&visualTypeIterator);
+ continue;
+ }
+
+ return VisualInfo{ *visualType, depth->depth };
+ }
+
+ xcb_depth_next(&depthIterator);
+ }
+
+ return std::nullopt;
+}
+
+} // namespace
+
QXcbEglIntegration::QXcbEglIntegration()
: m_connection(nullptr)
, m_egl_display(EGL_NO_DISPLAY)
+ , m_using_platform_display(false)
{
qCDebug(lcQpaGl) << "Xcb EGL gl-integration created";
}
@@ -67,23 +75,38 @@ bool QXcbEglIntegration::initialize(QXcbConnection *connection)
const char *extensions = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
+#if QT_CONFIG(xcb_xlib)
if (extensions && strstr(extensions, "EGL_EXT_platform_x11")) {
QEGLStreamConvenience streamFuncs;
m_egl_display = streamFuncs.get_platform_display(EGL_PLATFORM_X11_KHR,
- xlib_display(),
+ m_connection->xlib_display(),
nullptr);
+ m_using_platform_display = true;
}
+#if QT_CONFIG(egl_x11)
if (!m_egl_display)
- m_egl_display = eglGetDisplay(reinterpret_cast<EGLNativeDisplayType>(xlib_display()));
+ m_egl_display = eglGetDisplay(reinterpret_cast<EGLNativeDisplayType>(m_connection->xlib_display()));
+#endif
+#else
+ if (extensions && (strstr(extensions, "EGL_EXT_platform_xcb") || strstr(extensions, "EGL_MESA_platform_xcb"))) {
+ QEGLStreamConvenience streamFuncs;
+ m_egl_display = streamFuncs.get_platform_display(EGL_PLATFORM_XCB_KHR,
+ reinterpret_cast<void *>(connection->xcb_connection()),
+ nullptr);
+ m_using_platform_display = true;
+ }
+#endif
EGLint major, minor;
bool success = eglInitialize(m_egl_display, &major, &minor);
+#if QT_CONFIG(egl_x11)
if (!success) {
m_egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
qCDebug(lcQpaGl) << "Xcb EGL gl-integration retrying with display" << m_egl_display;
success = eglInitialize(m_egl_display, &major, &minor);
}
+#endif
m_native_interface_handler.reset(new QXcbEglNativeInterfaceHandler(connection->nativeInterface()));
@@ -120,13 +143,99 @@ QPlatformOffscreenSurface *QXcbEglIntegration::createPlatformOffscreenSurface(QO
return new QEGLPbuffer(eglDisplay(), screen->surfaceFormatFor(surface->requestedFormat()), surface);
}
-void *QXcbEglIntegration::xlib_display() const
+xcb_visualid_t QXcbEglIntegration::getCompatibleVisualId(xcb_screen_t *screen, EGLConfig config) const
{
-#if QT_CONFIG(xcb_xlib)
- return m_connection->xlib_display();
-#else
- return EGL_DEFAULT_DISPLAY;
-#endif
+ xcb_visualid_t visualId = 0;
+ EGLint eglValue = 0;
+
+ EGLint configRedSize = 0;
+ eglGetConfigAttrib(eglDisplay(), config, EGL_RED_SIZE, &configRedSize);
+
+ EGLint configGreenSize = 0;
+ eglGetConfigAttrib(eglDisplay(), config, EGL_GREEN_SIZE, &configGreenSize);
+
+ EGLint configBlueSize = 0;
+ eglGetConfigAttrib(eglDisplay(), config, EGL_BLUE_SIZE, &configBlueSize);
+
+ EGLint configAlphaSize = 0;
+ eglGetConfigAttrib(eglDisplay(), config, EGL_ALPHA_SIZE, &configAlphaSize);
+
+ eglGetConfigAttrib(eglDisplay(), config, EGL_CONFIG_ID, &eglValue);
+ int configId = eglValue;
+
+ // See if EGL provided a valid VisualID:
+ eglGetConfigAttrib(eglDisplay(), config, EGL_NATIVE_VISUAL_ID, &eglValue);
+ visualId = eglValue;
+ if (visualId) {
+ // EGL has suggested a visual id, so get the rest of the visual info for that id:
+ std::optional<VisualInfo> chosenVisualInfo = getVisualInfo(screen, visualId);
+ if (chosenVisualInfo) {
+ // Skip size checks if implementation supports non-matching visual
+ // and config (QTBUG-9444).
+ if (q_hasEglExtension(eglDisplay(), "EGL_NV_post_convert_rounding"))
+ return visualId;
+ // Skip also for i.MX6 where 565 visuals are suggested for the default 444 configs and it works just fine.
+ const char *vendor = eglQueryString(eglDisplay(), EGL_VENDOR);
+ if (vendor && strstr(vendor, "Vivante"))
+ return visualId;
+
+ int visualRedSize = qPopulationCount(chosenVisualInfo->visualType.red_mask);
+ int visualGreenSize = qPopulationCount(chosenVisualInfo->visualType.green_mask);
+ int visualBlueSize = qPopulationCount(chosenVisualInfo->visualType.blue_mask);
+ int visualAlphaSize = chosenVisualInfo->depth - visualRedSize - visualBlueSize - visualGreenSize;
+
+ const bool visualMatchesConfig = visualRedSize >= configRedSize
+ && visualGreenSize >= configGreenSize
+ && visualBlueSize >= configBlueSize
+ && visualAlphaSize >= configAlphaSize;
+
+ // In some cases EGL tends to suggest a 24-bit visual for 8888
+ // configs. In such a case we have to fall back to getVisualInfo.
+ if (!visualMatchesConfig) {
+ visualId = 0;
+ qCDebug(lcQpaGl,
+ "EGL suggested using X Visual ID %d (%d %d %d %d depth %d) for EGL config %d"
+ "(%d %d %d %d), but this is incompatible",
+ visualId, visualRedSize, visualGreenSize, visualBlueSize, visualAlphaSize, chosenVisualInfo->depth,
+ configId, configRedSize, configGreenSize, configBlueSize, configAlphaSize);
+ }
+ } else {
+ qCDebug(lcQpaGl, "EGL suggested using X Visual ID %d for EGL config %d, but that isn't a valid ID",
+ visualId, configId);
+ visualId = 0;
+ }
+ }
+ else
+ qCDebug(lcQpaGl, "EGL did not suggest a VisualID (EGL_NATIVE_VISUAL_ID was zero) for EGLConfig %d", configId);
+
+ if (visualId) {
+ qCDebug(lcQpaGl, configAlphaSize > 0
+ ? "Using ARGB Visual ID %d provided by EGL for config %d"
+ : "Using Opaque Visual ID %d provided by EGL for config %d", visualId, configId);
+ return visualId;
+ }
+
+ // Finally, try to use getVisualInfo and only use the bit depths to match on:
+ if (!visualId) {
+ uint8_t depth = configRedSize + configGreenSize + configBlueSize + configAlphaSize;
+ std::optional<VisualInfo> matchingVisual = getVisualInfo(screen, std::nullopt, depth);
+ if (!matchingVisual) {
+ // Try again without taking the alpha channel into account:
+ depth = configRedSize + configGreenSize + configBlueSize;
+ matchingVisual = getVisualInfo(screen, std::nullopt, depth);
+ }
+
+ if (matchingVisual)
+ visualId = matchingVisual->visualType.visual_id;
+ }
+
+ if (visualId) {
+ qCDebug(lcQpaGl, "Using Visual ID %d provided by getVisualInfo for EGL config %d", visualId, configId);
+ return visualId;
+ }
+
+ qWarning("Unable to find an X11 visual which matches EGL config %d", configId);
+ return 0;
}
QT_END_NAMESPACE