1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the plugins 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 // We have to include this before the X11 headers dragged in by
41 // qglxconvenience_p.h.
42 #include <QtCore/QByteArray>
43 #include <QtCore/QScopedPointer>
44 
45 #include <QtCore/qmetatype.h>
46 #include <QtCore/qtextstream.h>
47 #include "qglxconvenience_p.h"
48 
49 #include <QtCore/QLoggingCategory>
50 #include <QtCore/QVector>
51 #include <QtCore/QVarLengthArray>
52 
53 #include <GL/glxext.h>
54 
55 Q_LOGGING_CATEGORY(lcGlx, "qt.glx")
56 
57 enum {
58     XFocusOut = FocusOut,
59     XFocusIn = FocusIn,
60     XKeyPress = KeyPress,
61     XKeyRelease = KeyRelease,
62     XNone = None,
63     XRevertToParent = RevertToParent,
64     XGrayScale = GrayScale,
65     XCursorShape = CursorShape
66 };
67 #undef FocusOut
68 #undef FocusIn
69 #undef KeyPress
70 #undef KeyRelease
71 #undef None
72 #undef RevertToParent
73 #undef GrayScale
74 #undef CursorShape
75 
76 #ifdef FontChange
77 #undef FontChange
78 #endif
79 
80 #ifndef GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB
81 #define GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20B2
82 #endif
83 
qglx_buildSpec(const QSurfaceFormat & format,int drawableBit,int flags)84 QVector<int> qglx_buildSpec(const QSurfaceFormat &format, int drawableBit, int flags)
85 {
86     QVector<int> spec;
87 
88     spec << GLX_LEVEL
89          << 0
90 
91          << GLX_RENDER_TYPE
92          << GLX_RGBA_BIT
93 
94          << GLX_RED_SIZE
95          << qMax(1, format.redBufferSize())
96 
97          << GLX_GREEN_SIZE
98          << qMax(1, format.greenBufferSize())
99 
100          << GLX_BLUE_SIZE
101          << qMax(1, format.blueBufferSize())
102 
103          << GLX_ALPHA_SIZE
104          << qMax(0, format.alphaBufferSize());
105 
106     if (format.swapBehavior() != QSurfaceFormat::SingleBuffer)
107         spec << GLX_DOUBLEBUFFER
108              << True;
109 
110     if (format.stereo())
111         spec << GLX_STEREO
112              << True;
113 
114     if (format.depthBufferSize() != -1)
115         spec << GLX_DEPTH_SIZE
116              << format.depthBufferSize();
117 
118     if (format.stencilBufferSize() != -1)
119         spec << GLX_STENCIL_SIZE
120              << format.stencilBufferSize();
121 
122     if (format.samples() > 1)
123         spec << GLX_SAMPLE_BUFFERS_ARB
124              << 1
125              << GLX_SAMPLES_ARB
126              << format.samples();
127 
128     if ((flags & QGLX_SUPPORTS_SRGB) && format.colorSpace() == QSurfaceFormat::sRGBColorSpace)
129         spec << GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB
130              << True;
131 
132     spec << GLX_DRAWABLE_TYPE
133          << drawableBit
134 
135          << XNone;
136 
137     return spec;
138 }
139 
140 namespace  {
141 struct QXcbSoftwareOpenGLEnforcer {
QXcbSoftwareOpenGLEnforcer__anon5a117b9f0211::QXcbSoftwareOpenGLEnforcer142     QXcbSoftwareOpenGLEnforcer() {
143         // Allow forcing LIBGL_ALWAYS_SOFTWARE for Qt 5 applications only.
144         // This is most useful with drivers that only support OpenGL 1.
145         // We need OpenGL 2, but the user probably doesn't want
146         // LIBGL_ALWAYS_SOFTWARE in OpenGL 1 apps.
147 
148         if (!checkedForceSoftwareOpenGL) {
149             // If LIBGL_ALWAYS_SOFTWARE is already set, don't mess with it.
150             // We want to unset LIBGL_ALWAYS_SOFTWARE at the end so it does not
151             // get inherited by other processes, of course only if it wasn't
152             // already set before.
153             if (!qEnvironmentVariableIsEmpty("QT_XCB_FORCE_SOFTWARE_OPENGL")
154                 && !qEnvironmentVariableIsSet("LIBGL_ALWAYS_SOFTWARE"))
155                 forceSoftwareOpenGL = true;
156 
157             checkedForceSoftwareOpenGL = true;
158         }
159 
160         if (forceSoftwareOpenGL)
161             qputenv("LIBGL_ALWAYS_SOFTWARE", QByteArrayLiteral("1"));
162     }
163 
~QXcbSoftwareOpenGLEnforcer__anon5a117b9f0211::QXcbSoftwareOpenGLEnforcer164     ~QXcbSoftwareOpenGLEnforcer() {
165         // unset LIBGL_ALWAYS_SOFTWARE now so other processes don't inherit it
166         if (forceSoftwareOpenGL)
167             qunsetenv("LIBGL_ALWAYS_SOFTWARE");
168     }
169 
170     static bool checkedForceSoftwareOpenGL;
171     static bool forceSoftwareOpenGL;
172 };
173 
174 bool QXcbSoftwareOpenGLEnforcer::checkedForceSoftwareOpenGL = false;
175 bool QXcbSoftwareOpenGLEnforcer::forceSoftwareOpenGL = false;
176 
177 template <class T>
178 struct QXlibScopedPointerDeleter {
cleanup__anon5a117b9f0211::QXlibScopedPointerDeleter179     static inline void cleanup(T *pointer) {
180         if (pointer)
181             XFree(pointer);
182     }
183 };
184 
185 template <class T>
186 using QXlibPointer = QScopedPointer<T, QXlibScopedPointerDeleter<T>>;
187 
188 template <class T>
189 using QXlibArrayPointer = QScopedArrayPointer<T, QXlibScopedPointerDeleter<T>>;
190 }
191 
qglx_findConfig(Display * display,int screen,QSurfaceFormat format,bool highestPixelFormat,int drawableBit,int flags)192 GLXFBConfig qglx_findConfig(Display *display, int screen , QSurfaceFormat format, bool highestPixelFormat, int drawableBit, int flags)
193 {
194     QXcbSoftwareOpenGLEnforcer softwareOpenGLEnforcer;
195 
196     GLXFBConfig config = nullptr;
197 
198     do {
199         const QVector<int> spec = qglx_buildSpec(format, drawableBit, flags);
200 
201         int confcount = 0;
202         QXlibArrayPointer<GLXFBConfig> configs(glXChooseFBConfig(display, screen, spec.constData(), &confcount));
203 
204         if (!config && confcount > 0) {
205             config = configs[0];
206             if (highestPixelFormat && !format.hasAlpha())
207                 break;
208         }
209 
210         const int requestedRed = qMax(0, format.redBufferSize());
211         const int requestedGreen = qMax(0, format.greenBufferSize());
212         const int requestedBlue = qMax(0, format.blueBufferSize());
213         const int requestedAlpha = qMax(0, format.alphaBufferSize());
214 
215         GLXFBConfig compatibleCandidate = nullptr;
216         for (int i = 0; i < confcount; i++) {
217             GLXFBConfig candidate = configs[i];
218 
219             if ((flags & QGLX_SUPPORTS_SRGB) && format.colorSpace() == QSurfaceFormat::sRGBColorSpace) {
220                 int srgbCapable = 0;
221                 glXGetFBConfigAttrib(display, candidate, GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB, &srgbCapable);
222                 if (!srgbCapable)
223                     continue;
224             }
225 
226             QXlibPointer<XVisualInfo> visual(glXGetVisualFromFBConfig(display, candidate));
227             if (!visual)
228                 continue;
229             int actualRed;
230             int actualGreen;
231             int actualBlue;
232             int actualAlpha;
233             glXGetFBConfigAttrib(display, candidate, GLX_RED_SIZE, &actualRed);
234             glXGetFBConfigAttrib(display, candidate, GLX_GREEN_SIZE, &actualGreen);
235             glXGetFBConfigAttrib(display, candidate, GLX_BLUE_SIZE, &actualBlue);
236             glXGetFBConfigAttrib(display, candidate, GLX_ALPHA_SIZE, &actualAlpha);
237             // Sometimes the visuals don't have a depth that includes the alpha channel.
238             actualAlpha = qMin(actualAlpha, visual->depth - actualRed - actualGreen - actualBlue);
239 
240             if (requestedRed && actualRed < requestedRed)
241                 continue;
242             if (requestedGreen && actualGreen < requestedGreen)
243                 continue;
244             if (requestedBlue && actualBlue < requestedBlue)
245                 continue;
246             if (requestedAlpha && actualAlpha < requestedAlpha)
247                 continue;
248             if (!compatibleCandidate) // Only pick up the first compatible one offered by the server
249                 compatibleCandidate = candidate;
250 
251             if (requestedRed && actualRed != requestedRed)
252                 continue;
253             if (requestedGreen && actualGreen != requestedGreen)
254                 continue;
255             if (requestedBlue && actualBlue != requestedBlue)
256                 continue;
257             if (requestedAlpha && actualAlpha != requestedAlpha)
258                 continue;
259 
260             return candidate;
261         }
262         if (compatibleCandidate) {
263             qCDebug(lcGlx) << "qglx_findConfig: Found non-matching but compatible FBConfig";
264             return compatibleCandidate;
265         }
266     } while (qglx_reduceFormat(&format));
267 
268     if (!config)
269         qCWarning(lcGlx) << "qglx_findConfig: Failed to finding matching FBConfig for" << format;
270 
271     return config;
272 }
273 
qglx_findVisualInfo(Display * display,int screen,QSurfaceFormat * format,int drawableBit,int flags)274 XVisualInfo *qglx_findVisualInfo(Display *display, int screen, QSurfaceFormat *format, int drawableBit, int flags)
275 {
276     Q_ASSERT(format);
277 
278     XVisualInfo *visualInfo = nullptr;
279 
280     GLXFBConfig config = qglx_findConfig(display, screen, *format, false, drawableBit, flags);
281     if (config)
282         visualInfo = glXGetVisualFromFBConfig(display, config);
283 
284     if (visualInfo) {
285         qglx_surfaceFormatFromGLXFBConfig(format, display, config, flags);
286         return visualInfo;
287     }
288 
289     // attempt to fall back to glXChooseVisual
290     do {
291         QVector<int> attribs = qglx_buildSpec(*format, drawableBit, flags);
292         visualInfo = glXChooseVisual(display, screen, attribs.data());
293 
294         if (visualInfo) {
295             qglx_surfaceFormatFromVisualInfo(format, display, visualInfo, flags);
296             return visualInfo;
297         }
298     } while (qglx_reduceFormat(format));
299 
300     return visualInfo;
301 }
302 
qglx_surfaceFormatFromGLXFBConfig(QSurfaceFormat * format,Display * display,GLXFBConfig config,int flags)303 void qglx_surfaceFormatFromGLXFBConfig(QSurfaceFormat *format, Display *display, GLXFBConfig config, int flags)
304 {
305     int redSize     = 0;
306     int greenSize   = 0;
307     int blueSize    = 0;
308     int alphaSize   = 0;
309     int depthSize   = 0;
310     int stencilSize = 0;
311     int sampleBuffers = 0;
312     int sampleCount = 0;
313     int stereo      = 0;
314     int srgbCapable = 0;
315 
316     glXGetFBConfigAttrib(display, config, GLX_RED_SIZE,     &redSize);
317     glXGetFBConfigAttrib(display, config, GLX_GREEN_SIZE,   &greenSize);
318     glXGetFBConfigAttrib(display, config, GLX_BLUE_SIZE,    &blueSize);
319     glXGetFBConfigAttrib(display, config, GLX_ALPHA_SIZE,   &alphaSize);
320     glXGetFBConfigAttrib(display, config, GLX_DEPTH_SIZE,   &depthSize);
321     glXGetFBConfigAttrib(display, config, GLX_STENCIL_SIZE, &stencilSize);
322     glXGetFBConfigAttrib(display, config, GLX_SAMPLE_BUFFERS_ARB, &sampleBuffers);
323     glXGetFBConfigAttrib(display, config, GLX_STEREO,       &stereo);
324     if (flags & QGLX_SUPPORTS_SRGB)
325         glXGetFBConfigAttrib(display, config, GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB, &srgbCapable);
326 
327     format->setRedBufferSize(redSize);
328     format->setGreenBufferSize(greenSize);
329     format->setBlueBufferSize(blueSize);
330     format->setAlphaBufferSize(alphaSize);
331     format->setDepthBufferSize(depthSize);
332     format->setStencilBufferSize(stencilSize);
333     if (sampleBuffers) {
334         glXGetFBConfigAttrib(display, config, GLX_SAMPLES_ARB, &sampleCount);
335         format->setSamples(sampleCount);
336     }
337     format->setColorSpace(srgbCapable ? QSurfaceFormat::sRGBColorSpace : QSurfaceFormat::DefaultColorSpace);
338 
339     format->setStereo(stereo);
340 }
341 
qglx_surfaceFormatFromVisualInfo(QSurfaceFormat * format,Display * display,XVisualInfo * visualInfo,int flags)342 void qglx_surfaceFormatFromVisualInfo(QSurfaceFormat *format, Display *display, XVisualInfo *visualInfo, int flags)
343 {
344     int redSize     = 0;
345     int greenSize   = 0;
346     int blueSize    = 0;
347     int alphaSize   = 0;
348     int depthSize   = 0;
349     int stencilSize = 0;
350     int sampleBuffers = 0;
351     int sampleCount = 0;
352     int stereo      = 0;
353     int srgbCapable = 0;
354 
355     glXGetConfig(display, visualInfo, GLX_RED_SIZE,     &redSize);
356     glXGetConfig(display, visualInfo, GLX_GREEN_SIZE,   &greenSize);
357     glXGetConfig(display, visualInfo, GLX_BLUE_SIZE,    &blueSize);
358     glXGetConfig(display, visualInfo, GLX_ALPHA_SIZE,   &alphaSize);
359     glXGetConfig(display, visualInfo, GLX_DEPTH_SIZE,   &depthSize);
360     glXGetConfig(display, visualInfo, GLX_STENCIL_SIZE, &stencilSize);
361     glXGetConfig(display, visualInfo, GLX_SAMPLE_BUFFERS_ARB, &sampleBuffers);
362     glXGetConfig(display, visualInfo, GLX_STEREO,       &stereo);
363     if (flags & QGLX_SUPPORTS_SRGB)
364         glXGetConfig(display, visualInfo, GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB, &srgbCapable);
365 
366     format->setRedBufferSize(redSize);
367     format->setGreenBufferSize(greenSize);
368     format->setBlueBufferSize(blueSize);
369     format->setAlphaBufferSize(alphaSize);
370     format->setDepthBufferSize(depthSize);
371     format->setStencilBufferSize(stencilSize);
372     if (sampleBuffers) {
373         glXGetConfig(display, visualInfo, GLX_SAMPLES_ARB, &sampleCount);
374         format->setSamples(sampleCount);
375     }
376     format->setColorSpace(srgbCapable ? QSurfaceFormat::sRGBColorSpace : QSurfaceFormat::DefaultColorSpace);
377 
378     format->setStereo(stereo);
379 }
380 
qglx_reduceFormat(QSurfaceFormat * format)381 bool qglx_reduceFormat(QSurfaceFormat *format)
382 {
383     Q_ASSERT(format);
384     if (std::max(std::max(format->redBufferSize(), format->greenBufferSize()), format->blueBufferSize()) > 8) {
385         if (format->alphaBufferSize() > 2) {
386             // First try to match 10 10 10 2
387             format->setAlphaBufferSize(2);
388             return true;
389         }
390 
391         format->setRedBufferSize(std::min(format->redBufferSize(), 8));
392         format->setGreenBufferSize(std::min(format->greenBufferSize(), 8));
393         format->setBlueBufferSize(std::min(format->blueBufferSize(), 8));
394         return true;
395     }
396 
397     if (format->redBufferSize() > 1) {
398         format->setRedBufferSize(1);
399         return true;
400     }
401 
402     if (format->greenBufferSize() > 1) {
403         format->setGreenBufferSize(1);
404         return true;
405     }
406 
407     if (format->blueBufferSize() > 1) {
408         format->setBlueBufferSize(1);
409         return true;
410     }
411 
412     if (format->swapBehavior() != QSurfaceFormat::SingleBuffer){
413         format->setSwapBehavior(QSurfaceFormat::SingleBuffer);
414         return true;
415     }
416 
417     if (format->samples() > 1) {
418         format->setSamples(qMin(16, format->samples() / 2));
419         return true;
420     }
421 
422     if (format->depthBufferSize() >= 32) {
423         format->setDepthBufferSize(24);
424         return true;
425     }
426 
427     if (format->depthBufferSize() > 1) {
428         format->setDepthBufferSize(1);
429         return true;
430     }
431 
432     if (format->depthBufferSize() > 0) {
433         format->setDepthBufferSize(0);
434         return true;
435     }
436 
437     if (format->hasAlpha()) {
438         format->setAlphaBufferSize(0);
439         return true;
440     }
441 
442     if (format->stencilBufferSize() > 1) {
443         format->setStencilBufferSize(1);
444         return true;
445     }
446 
447     if (format->stencilBufferSize() > 0) {
448         format->setStencilBufferSize(0);
449         return true;
450     }
451 
452     if (format->stereo()) {
453         format->setStereo(false);
454         return true;
455     }
456 
457     if (format->colorSpace() == QSurfaceFormat::sRGBColorSpace) {
458         format->setColorSpace(QSurfaceFormat::DefaultColorSpace);
459         return true;
460     }
461 
462     return false;
463 }
464