diff options
author | Ilya Fedin <fedin-ilja2010@ya.ru> | 2021-10-04 10:32:38 +0400 |
---|---|---|
committer | Liang Qi <liang.qi@qt.io> | 2022-06-20 15:53:33 +0000 |
commit | c3e624eb50ff56dd0d172999a49c454f37ca62cd (patch) | |
tree | 4d1919fb65e0e0cefc5395af6ee311f0ee1319d5 /src/plugins/platforms/xcb | |
parent | 1c106b37c75adc96df33cd59e8a5e3822385b099 (diff) |
Port QXlibEglIntegration::getCompatibleVisualId to xcb
In combination with EGL_EXT_platform_xcb support, this allows xcb_egl
to be used without xlib. Without EGL_EXT_platform_xcb support, this
still reduces amount of code using xlib.
Pick-to: 6.4
Change-Id: I29e2b29f7ef8ea34320887f62697f84232b86fba
Reviewed-by: Liang Qi <liang.qi@qt.io>
Diffstat (limited to 'src/plugins/platforms/xcb')
4 files changed, 142 insertions, 20 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 2ab89f07d6..08c34cc495 100644 --- a/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglintegration.cpp +++ b/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglintegration.cpp @@ -6,12 +6,55 @@ #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) @@ -93,4 +136,99 @@ void *QXcbEglIntegration::xlib_display() const #endif } +xcb_visualid_t QXcbEglIntegration::getCompatibleVisualId(xcb_screen_t *screen, EGLConfig config) const +{ + 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 diff --git a/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglintegration.h b/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglintegration.h index 5ea37c0924..194b6d6e77 100644 --- a/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglintegration.h +++ b/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglintegration.h @@ -39,6 +39,8 @@ public: EGLDisplay eglDisplay() const { return m_egl_display; } void *xlib_display() const; + + xcb_visualid_t getCompatibleVisualId(xcb_screen_t *screen, EGLConfig config) const; private: QXcbConnection *m_connection; EGLDisplay m_egl_display; 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 e5ca2b4864..4d87b08db8 100644 --- a/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglwindow.cpp +++ b/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglwindow.cpp @@ -6,7 +6,6 @@ #include "qxcbeglintegration.h" #include <QtGui/private/qeglconvenience_p.h> -#include <QtGui/private/qxlibeglintegration_p.h> QT_BEGIN_NAMESPACE @@ -29,29 +28,15 @@ void QXcbEglWindow::resolveFormat(const QSurfaceFormat &format) m_format = q_glFormatFromConfig(m_glIntegration->eglDisplay(), m_config, format); } -#if QT_CONFIG(xcb_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); - - XVisualInfo visualInfoTemplate; - memset(&visualInfoTemplate, 0, sizeof(XVisualInfo)); - visualInfoTemplate.visualid = id; - - XVisualInfo *visualInfo; - int matchingCount = 0; - visualInfo = XGetVisualInfo(xdpy, VisualIDMask, &visualInfoTemplate, &matchingCount); - const xcb_visualtype_t *xcb_visualtype = scr->visualForId(visualInfo->visualid); - XFree(visualInfo); - - return xcb_visualtype; + xcb_visualid_t id = m_glIntegration->getCompatibleVisualId(scr->screen(), m_config); + return scr->visualForId(id); } -#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 79f1df0493..935a0c6d43 100644 --- a/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglwindow.h +++ b/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglwindow.h @@ -25,10 +25,7 @@ public: protected: void create() override; void resolveFormat(const QSurfaceFormat &format) override; - -#if QT_CONFIG(xcb_xlib) const xcb_visualtype_t *createVisual() override; -#endif private: QXcbEglIntegration *m_glIntegration; |