1/****************************************************************************
2**
3** Copyright (C) 2020 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtGui module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include <QtCore/qloggingcategory.h>
41#include "qxlibeglintegration_p.h"
42
43QT_BEGIN_NAMESPACE
44
45Q_LOGGING_CATEGORY(lcXlibEglDebug, "qt.egl.xlib.debug")
46
47VisualID QXlibEglIntegration::getCompatibleVisualId(Display *display, EGLDisplay eglDisplay, EGLConfig config)
48{
49 VisualID visualId = 0;
50 EGLint eglValue = 0;
51
52 EGLint configRedSize = 0;
53 eglGetConfigAttrib(eglDisplay, config, EGL_RED_SIZE, &configRedSize);
54
55 EGLint configGreenSize = 0;
56 eglGetConfigAttrib(eglDisplay, config, EGL_GREEN_SIZE, &configGreenSize);
57
58 EGLint configBlueSize = 0;
59 eglGetConfigAttrib(eglDisplay, config, EGL_BLUE_SIZE, &configBlueSize);
60
61 EGLint configAlphaSize = 0;
62 eglGetConfigAttrib(eglDisplay, config, EGL_ALPHA_SIZE, &configAlphaSize);
63
64 eglGetConfigAttrib(eglDisplay, config, EGL_CONFIG_ID, &eglValue);
65 int configId = eglValue;
66
67 // See if EGL provided a valid VisualID:
68 eglGetConfigAttrib(eglDisplay, config, EGL_NATIVE_VISUAL_ID, &eglValue);
69 visualId = (VisualID)eglValue;
70 if (visualId) {
71 // EGL has suggested a visual id, so get the rest of the visual info for that id:
72 XVisualInfo visualInfoTemplate;
73 memset(&visualInfoTemplate, 0, sizeof(XVisualInfo));
74 visualInfoTemplate.visualid = visualId;
75
76 XVisualInfo *chosenVisualInfo;
77 int matchingCount = 0;
78 chosenVisualInfo = XGetVisualInfo(display, VisualIDMask, &visualInfoTemplate, &matchingCount);
79 if (chosenVisualInfo) {
80 // Skip size checks if implementation supports non-matching visual
81 // and config (QTBUG-9444).
82 if (q_hasEglExtension(eglDisplay,"EGL_NV_post_convert_rounding")) {
83 XFree(chosenVisualInfo);
84 return visualId;
85 }
86 // Skip also for i.MX6 where 565 visuals are suggested for the default 444 configs and it works just fine.
87 const char *vendor = eglQueryString(eglDisplay, EGL_VENDOR);
88 if (vendor && strstr(vendor, "Vivante")) {
89 XFree(chosenVisualInfo);
90 return visualId;
91 }
92
93 int visualRedSize = qPopulationCount(chosenVisualInfo->red_mask);
94 int visualGreenSize = qPopulationCount(chosenVisualInfo->green_mask);
95 int visualBlueSize = qPopulationCount(chosenVisualInfo->blue_mask);
96 int visualAlphaSize = chosenVisualInfo->depth - visualRedSize - visualBlueSize - visualGreenSize;
97
98 const bool visualMatchesConfig = visualRedSize >= configRedSize
99 && visualGreenSize >= configGreenSize
100 && visualBlueSize >= configBlueSize
101 && visualAlphaSize >= configAlphaSize;
102
103 // In some cases EGL tends to suggest a 24-bit visual for 8888
104 // configs. In such a case we have to fall back to XGetVisualInfo.
105 if (!visualMatchesConfig) {
106 visualId = 0;
107 qCDebug(lcXlibEglDebug,
108 "EGL suggested using X Visual ID %d (%d %d %d %d depth %d) for EGL config %d"
109 "(%d %d %d %d), but this is incompatible",
110 (int)visualId, visualRedSize, visualGreenSize, visualBlueSize, visualAlphaSize, chosenVisualInfo->depth,
111 configId, configRedSize, configGreenSize, configBlueSize, configAlphaSize);
112 }
113 } else {
114 qCDebug(lcXlibEglDebug, "EGL suggested using X Visual ID %d for EGL config %d, but that isn't a valid ID",
115 (int)visualId, configId);
116 visualId = 0;
117 }
118 XFree(chosenVisualInfo);
119 }
120 else
121 qCDebug(lcXlibEglDebug, "EGL did not suggest a VisualID (EGL_NATIVE_VISUAL_ID was zero) for EGLConfig %d", configId);
122
123 if (visualId) {
124 qCDebug(lcXlibEglDebug, configAlphaSize > 0
125 ? "Using ARGB Visual ID %d provided by EGL for config %d"
126 : "Using Opaque Visual ID %d provided by EGL for config %d", (int)visualId, configId);
127 return visualId;
128 }
129
130 // Finally, try to use XGetVisualInfo and only use the bit depths to match on:
131 if (!visualId) {
132 XVisualInfo visualInfoTemplate;
133 memset(&visualInfoTemplate, 0, sizeof(XVisualInfo));
134 XVisualInfo *matchingVisuals;
135 int matchingCount = 0;
136
137 visualInfoTemplate.depth = configRedSize + configGreenSize + configBlueSize + configAlphaSize;
138 matchingVisuals = XGetVisualInfo(display,
139 VisualDepthMask,
140 &visualInfoTemplate,
141 &matchingCount);
142 if (!matchingVisuals) {
143 // Try again without taking the alpha channel into account:
144 visualInfoTemplate.depth = configRedSize + configGreenSize + configBlueSize;
145 matchingVisuals = XGetVisualInfo(display,
146 VisualDepthMask,
147 &visualInfoTemplate,
148 &matchingCount);
149 }
150
151 if (matchingVisuals) {
152 visualId = matchingVisuals[0].visualid;
153 XFree(matchingVisuals);
154 }
155 }
156
157 if (visualId) {
158 qCDebug(lcXlibEglDebug, "Using Visual ID %d provided by XGetVisualInfo for EGL config %d", (int)visualId, configId);
159 return visualId;
160 }
161
162 qWarning("Unable to find an X11 visual which matches EGL config %d", configId);
163 return (VisualID)0;
164}
165
166QT_END_NAMESPACE
167