~gabriel1984sibiu/minitube/qt5.6

« back to all changes in this revision

Viewing changes to src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp

  • Committer: Grevutiu Gabriel
  • Date: 2017-06-13 08:43:17 UTC
  • Revision ID: gabriel1984sibiu@gmail.com-20170613084317-ek0zqe0u9g3ocvi8
OriginalĀ upstreamĀ code

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
#include <QDebug>
 
41
#include <QLibrary>
 
42
 
 
43
#include "qxcbwindow.h"
 
44
#include "qxcbscreen.h"
 
45
 
 
46
#include <X11/Xlib.h>
 
47
#include <X11/Xutil.h>
 
48
#include <GL/glx.h>
 
49
 
 
50
#include <QtGui/QOpenGLContext>
 
51
#include <QtGui/QOffscreenSurface>
 
52
 
 
53
#include "qglxintegration.h"
 
54
#include <QtPlatformSupport/private/qglxconvenience_p.h>
 
55
#include <QtPlatformHeaders/QGLXNativeContext>
 
56
 
 
57
#if defined(Q_OS_LINUX) || defined(Q_OS_BSD4)
 
58
#include <dlfcn.h>
 
59
#endif
 
60
 
 
61
QT_BEGIN_NAMESPACE
 
62
 
 
63
typedef GLXContext (*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXContext, Bool, const int*);
 
64
 
 
65
#ifndef GLX_CONTEXT_CORE_PROFILE_BIT_ARB
 
66
#define GLX_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001
 
67
#endif
 
68
 
 
69
#ifndef GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB
 
70
#define GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
 
71
#endif
 
72
 
 
73
#ifndef GLX_CONTEXT_ES2_PROFILE_BIT_EXT
 
74
#define GLX_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000004
 
75
#endif
 
76
 
 
77
#ifndef GLX_CONTEXT_PROFILE_MASK_ARB
 
78
#define GLX_CONTEXT_PROFILE_MASK_ARB 0x9126
 
79
#endif
 
80
 
 
81
#ifndef GL_CONTEXT_FLAG_DEBUG_BIT
 
82
#define GL_CONTEXT_FLAG_DEBUG_BIT 0x00000002
 
83
#endif
 
84
 
 
85
static Window createDummyWindow(Display *dpy, XVisualInfo *visualInfo, int screenNumber, Window rootWin)
 
86
{
 
87
    Colormap cmap = XCreateColormap(dpy, rootWin, visualInfo->visual, AllocNone);
 
88
    XSetWindowAttributes a;
 
89
    a.background_pixel = WhitePixel(dpy, screenNumber);
 
90
    a.border_pixel = BlackPixel(dpy, screenNumber);
 
91
    a.colormap = cmap;
 
92
    a.override_redirect = true;
 
93
 
 
94
    Window window = XCreateWindow(dpy, rootWin,
 
95
                                  0, 0, 100, 100,
 
96
                                  0, visualInfo->depth, InputOutput, visualInfo->visual,
 
97
                                  CWBackPixel|CWBorderPixel|CWColormap|CWOverrideRedirect, &a);
 
98
#ifndef QT_NO_DEBUG
 
99
    XStoreName(dpy, window, "Qt GLX dummy window");
 
100
#endif
 
101
    XFreeColormap(dpy, cmap);
 
102
    return window;
 
103
}
 
104
 
 
105
static Window createDummyWindow(Display *dpy, GLXFBConfig config, int screenNumber, Window rootWin)
 
106
{
 
107
    XVisualInfo *visualInfo = glXGetVisualFromFBConfig(dpy, config);
 
108
    if (Q_UNLIKELY(!visualInfo))
 
109
        qFatal("Could not initialize GLX");
 
110
    Window window = createDummyWindow(dpy, visualInfo, screenNumber, rootWin);
 
111
    XFree(visualInfo);
 
112
    return window;
 
113
}
 
114
 
 
115
static inline QByteArray getGlString(GLenum param)
 
116
{
 
117
    if (const GLubyte *s = glGetString(param))
 
118
        return QByteArray(reinterpret_cast<const char*>(s));
 
119
    return QByteArray();
 
120
}
 
121
 
 
122
static void updateFormatFromContext(QSurfaceFormat &format)
 
123
{
 
124
    // Update the version, profile, and context bit of the format
 
125
    int major = 0, minor = 0;
 
126
    QByteArray versionString(getGlString(GL_VERSION));
 
127
    if (QPlatformOpenGLContext::parseOpenGLVersion(versionString, major, minor)) {
 
128
        format.setMajorVersion(major);
 
129
        format.setMinorVersion(minor);
 
130
    }
 
131
 
 
132
    format.setProfile(QSurfaceFormat::NoProfile);
 
133
    format.setOptions(QSurfaceFormat::FormatOptions());
 
134
 
 
135
    if (format.renderableType() == QSurfaceFormat::OpenGL) {
 
136
        if (format.version() < qMakePair(3, 0)) {
 
137
            format.setOption(QSurfaceFormat::DeprecatedFunctions);
 
138
            return;
 
139
        }
 
140
 
 
141
        // Version 3.0 onwards - check if it includes deprecated functionality or is
 
142
        // a debug context
 
143
        GLint value = 0;
 
144
        glGetIntegerv(GL_CONTEXT_FLAGS, &value);
 
145
        if (!(value & GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT))
 
146
            format.setOption(QSurfaceFormat::DeprecatedFunctions);
 
147
        if (value & GL_CONTEXT_FLAG_DEBUG_BIT)
 
148
            format.setOption(QSurfaceFormat::DebugContext);
 
149
        if (format.version() < qMakePair(3, 2))
 
150
            return;
 
151
 
 
152
        // Version 3.2 and newer have a profile
 
153
        value = 0;
 
154
        glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &value);
 
155
 
 
156
        if (value & GL_CONTEXT_CORE_PROFILE_BIT)
 
157
            format.setProfile(QSurfaceFormat::CoreProfile);
 
158
        else if (value & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT)
 
159
            format.setProfile(QSurfaceFormat::CompatibilityProfile);
 
160
    }
 
161
}
 
162
 
 
163
QGLXContext::QGLXContext(QXcbScreen *screen, const QSurfaceFormat &format, QPlatformOpenGLContext *share,
 
164
                         const QVariant &nativeHandle)
 
165
    : QPlatformOpenGLContext()
 
166
    , m_display(DISPLAY_FROM_XCB(screen))
 
167
    , m_config(0)
 
168
    , m_context(0)
 
169
    , m_shareContext(0)
 
170
    , m_format(format)
 
171
    , m_isPBufferCurrent(false)
 
172
    , m_swapInterval(-1)
 
173
    , m_ownsContext(nativeHandle.isNull())
 
174
{
 
175
    if (nativeHandle.isNull())
 
176
        init(screen, share);
 
177
    else
 
178
        init(screen, share, nativeHandle);
 
179
}
 
180
 
 
181
void QGLXContext::init(QXcbScreen *screen, QPlatformOpenGLContext *share)
 
182
{
 
183
    if (m_format.renderableType() == QSurfaceFormat::DefaultRenderableType)
 
184
#if defined(QT_OPENGL_ES_2)
 
185
        m_format.setRenderableType(QSurfaceFormat::OpenGLES);
 
186
#else
 
187
        m_format.setRenderableType(QSurfaceFormat::OpenGL);
 
188
#endif
 
189
    if (m_format.renderableType() != QSurfaceFormat::OpenGL && m_format.renderableType() != QSurfaceFormat::OpenGLES)
 
190
        return;
 
191
 
 
192
    if (share)
 
193
        m_shareContext = static_cast<const QGLXContext*>(share)->glxContext();
 
194
 
 
195
    GLXFBConfig config = qglx_findConfig(DISPLAY_FROM_XCB(screen),screen->screenNumber(),m_format);
 
196
    m_config = config;
 
197
    XVisualInfo *visualInfo = 0;
 
198
    Window window = 0; // Temporary window used to query OpenGL context
 
199
 
 
200
    if (config) {
 
201
        const QByteArrayList glxExt = QByteArray(glXQueryExtensionsString(m_display, screen->screenNumber())).split(' ');
 
202
 
 
203
        // Resolve entry point for glXCreateContextAttribsARB
 
204
        glXCreateContextAttribsARBProc glXCreateContextAttribsARB = 0;
 
205
        if (glxExt.contains("GLX_ARB_create_context"))
 
206
            glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc) glXGetProcAddress((const GLubyte*)"glXCreateContextAttribsARB");
 
207
 
 
208
        const bool supportsProfiles = glxExt.contains("GLX_ARB_create_context_profile");
 
209
 
 
210
        // Use glXCreateContextAttribsARB if available
 
211
        // Also, GL ES context creation requires GLX_EXT_create_context_es2_profile
 
212
        if (glXCreateContextAttribsARB != 0
 
213
                && (m_format.renderableType() != QSurfaceFormat::OpenGLES || (supportsProfiles && glxExt.contains("GLX_EXT_create_context_es2_profile")))) {
 
214
            // Try to create an OpenGL context for each known OpenGL version in descending
 
215
            // order from the requested version.
 
216
            const int requestedVersion = m_format.majorVersion() * 10 + qMin(m_format.minorVersion(), 9);
 
217
 
 
218
            QVector<int> glVersions;
 
219
            if (m_format.renderableType() == QSurfaceFormat::OpenGL) {
 
220
                if (requestedVersion > 45)
 
221
                    glVersions << requestedVersion;
 
222
 
 
223
                // Don't bother with versions below 2.0
 
224
                glVersions << 45 << 44 << 43 << 42 << 41 << 40 << 33 << 32 << 31 << 30 << 21 << 20;
 
225
            } else if (m_format.renderableType() == QSurfaceFormat::OpenGLES) {
 
226
                if (requestedVersion > 31)
 
227
                    glVersions << requestedVersion;
 
228
 
 
229
                // Don't bother with versions below ES 2.0
 
230
                glVersions << 31 << 30 << 20;
 
231
                // ES does not support any format option
 
232
                m_format.setOptions(QSurfaceFormat::FormatOptions());
 
233
            }
 
234
 
 
235
            Q_ASSERT(glVersions.count() > 0);
 
236
 
 
237
            for (int i = 0; !m_context && i < glVersions.count(); i++) {
 
238
                const int version = glVersions[i];
 
239
                if (version > requestedVersion)
 
240
                    continue;
 
241
 
 
242
                const int majorVersion = version / 10;
 
243
                const int minorVersion = version % 10;
 
244
 
 
245
                QVector<int> contextAttributes;
 
246
                contextAttributes << GLX_CONTEXT_MAJOR_VERSION_ARB << majorVersion
 
247
                                  << GLX_CONTEXT_MINOR_VERSION_ARB << minorVersion;
 
248
 
 
249
 
 
250
                if (m_format.renderableType() == QSurfaceFormat::OpenGL) {
 
251
                    // If asking for OpenGL 3.2 or newer we should also specify a profile
 
252
                    if (version >= 32 && supportsProfiles) {
 
253
                        if (m_format.profile() == QSurfaceFormat::CoreProfile)
 
254
                            contextAttributes << GLX_CONTEXT_PROFILE_MASK_ARB << GLX_CONTEXT_CORE_PROFILE_BIT_ARB;
 
255
                        else
 
256
                            contextAttributes << GLX_CONTEXT_PROFILE_MASK_ARB << GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB;
 
257
                    }
 
258
 
 
259
                    int flags = 0;
 
260
 
 
261
                    if (m_format.testOption(QSurfaceFormat::DebugContext))
 
262
                        flags |= GLX_CONTEXT_DEBUG_BIT_ARB;
 
263
 
 
264
                    // A forward-compatible context may be requested for 3.0 and later
 
265
                    if (version >= 30 && !m_format.testOption(QSurfaceFormat::DeprecatedFunctions))
 
266
                        flags |= GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
 
267
 
 
268
                    if (flags != 0)
 
269
                        contextAttributes << GLX_CONTEXT_FLAGS_ARB << flags;
 
270
                } else if (m_format.renderableType() == QSurfaceFormat::OpenGLES) {
 
271
                    contextAttributes << GLX_CONTEXT_PROFILE_MASK_ARB << GLX_CONTEXT_ES2_PROFILE_BIT_EXT;
 
272
                }
 
273
 
 
274
                contextAttributes << None;
 
275
 
 
276
                m_context = glXCreateContextAttribsARB(m_display, config, m_shareContext, true, contextAttributes.data());
 
277
                if (!m_context && m_shareContext) {
 
278
                    // re-try without a shared glx context
 
279
                    m_context = glXCreateContextAttribsARB(m_display, config, 0, true, contextAttributes.data());
 
280
                    if (m_context)
 
281
                        m_shareContext = 0;
 
282
                }
 
283
            }
 
284
        }
 
285
 
 
286
        // Could not create a context using glXCreateContextAttribsARB, falling back to glXCreateNewContext.
 
287
        if (!m_context) {
 
288
            // requesting an OpenGL ES context requires glXCreateContextAttribsARB, so bail out
 
289
            if (m_format.renderableType() == QSurfaceFormat::OpenGLES)
 
290
                return;
 
291
 
 
292
            m_context = glXCreateNewContext(m_display, config, GLX_RGBA_TYPE, m_shareContext, true);
 
293
            if (!m_context && m_shareContext) {
 
294
                // re-try without a shared glx context
 
295
                m_context = glXCreateNewContext(m_display, config, GLX_RGBA_TYPE, 0, true);
 
296
                if (m_context)
 
297
                    m_shareContext = 0;
 
298
            }
 
299
        }
 
300
 
 
301
        // Get the basic surface format details
 
302
        if (m_context)
 
303
            qglx_surfaceFormatFromGLXFBConfig(&m_format, DISPLAY_FROM_XCB(screen), config);
 
304
 
 
305
        // Create a temporary window so that we can make the new context current
 
306
        window = createDummyWindow(DISPLAY_FROM_XCB(screen), config, screen->screenNumber(), screen->root());
 
307
    } else {
 
308
        // requesting an OpenGL ES context requires glXCreateContextAttribsARB, so bail out
 
309
        if (m_format.renderableType() == QSurfaceFormat::OpenGLES)
 
310
            return;
 
311
 
 
312
        // Note that m_format gets updated with the used surface format
 
313
        visualInfo = qglx_findVisualInfo(m_display, screen->screenNumber(), &m_format);
 
314
        if (Q_UNLIKELY(!visualInfo))
 
315
            qFatal("Could not initialize GLX");
 
316
        m_context = glXCreateContext(m_display, visualInfo, m_shareContext, true);
 
317
        if (!m_context && m_shareContext) {
 
318
            // re-try without a shared glx context
 
319
            m_shareContext = 0;
 
320
            m_context = glXCreateContext(m_display, visualInfo, Q_NULLPTR, true);
 
321
        }
 
322
 
 
323
        // Create a temporary window so that we can make the new context current
 
324
        window = createDummyWindow(DISPLAY_FROM_XCB(screen), visualInfo, screen->screenNumber(), screen->root());
 
325
        XFree(visualInfo);
 
326
    }
 
327
 
 
328
    // Query the OpenGL version and profile
 
329
    if (m_context && window) {
 
330
        GLXContext prevContext = glXGetCurrentContext();
 
331
        GLXDrawable prevDrawable = glXGetCurrentDrawable();
 
332
        glXMakeCurrent(m_display, window, m_context);
 
333
        updateFormatFromContext(m_format);
 
334
 
 
335
        // Make our context non-current
 
336
        glXMakeCurrent(m_display, prevDrawable, prevContext);
 
337
    }
 
338
 
 
339
    // Destroy our temporary window
 
340
    XDestroyWindow(m_display, window);
 
341
}
 
342
 
 
343
void QGLXContext::init(QXcbScreen *screen, QPlatformOpenGLContext *share, const QVariant &nativeHandle)
 
344
{
 
345
    if (!nativeHandle.canConvert<QGLXNativeContext>()) {
 
346
        qWarning("QGLXContext: Requires a QGLXNativeContext");
 
347
        return;
 
348
    }
 
349
    QGLXNativeContext handle = nativeHandle.value<QGLXNativeContext>();
 
350
    GLXContext context = handle.context();
 
351
    if (!context) {
 
352
        qWarning("QGLXContext: No GLXContext given");
 
353
        return;
 
354
    }
 
355
 
 
356
    // Use the provided Display, if available. If not, use our own. It may still work.
 
357
    Display *dpy = handle.display();
 
358
    if (!dpy)
 
359
        dpy = DISPLAY_FROM_XCB(screen);
 
360
 
 
361
    // Legacy contexts created using glXCreateContext are created using a visual
 
362
    // and the FBConfig cannot be queried. The only way to adapt these contexts
 
363
    // is to figure out the visual id.
 
364
    XVisualInfo *vinfo = 0;
 
365
    // If the VisualID is provided use it.
 
366
    VisualID vid = handle.visualId();
 
367
    if (!vid) {
 
368
        // In the absence of the VisualID figure it out from the window.
 
369
        Window wnd = handle.window();
 
370
        if (wnd) {
 
371
            XWindowAttributes attrs;
 
372
            XGetWindowAttributes(dpy, wnd, &attrs);
 
373
            vid = XVisualIDFromVisual(attrs.visual);
 
374
        }
 
375
    }
 
376
    if (vid) {
 
377
        XVisualInfo v;
 
378
        v.screen = screen->screenNumber();
 
379
        v.visualid = vid;
 
380
        int n = 0;
 
381
        vinfo = XGetVisualInfo(dpy, VisualScreenMask | VisualIDMask, &v, &n);
 
382
        if (n < 1) {
 
383
            XFree(vinfo);
 
384
            vinfo = 0;
 
385
        }
 
386
    }
 
387
 
 
388
    // For contexts created with an FBConfig using the modern functions providing the
 
389
    // visual or window is not mandatory. Just query the config from the context.
 
390
    GLXFBConfig config = 0;
 
391
    if (!vinfo) {
 
392
        int configId = 0;
 
393
        if (glXQueryContext(dpy, context, GLX_FBCONFIG_ID, &configId) != Success) {
 
394
            qWarning("QGLXContext: Failed to query config from the provided context");
 
395
            return;
 
396
        }
 
397
 
 
398
        GLXFBConfig *configs;
 
399
        int numConfigs = 0;
 
400
        static const int attribs[] = { GLX_FBCONFIG_ID, configId, None };
 
401
        configs = glXChooseFBConfig(dpy, screen->screenNumber(), attribs, &numConfigs);
 
402
        if (!configs || numConfigs < 1) {
 
403
            qWarning("QGLXContext: Failed to find config");
 
404
            return;
 
405
        }
 
406
        if (configs && numConfigs > 1) // this is suspicious so warn but let it continue
 
407
            qWarning("QGLXContext: Multiple configs for FBConfig ID %d", configId);
 
408
 
 
409
        config = configs[0];
 
410
        // Store the config.
 
411
        m_config = config;
 
412
    }
 
413
 
 
414
    Q_ASSERT(vinfo || config);
 
415
 
 
416
    int screenNumber = DefaultScreen(dpy);
 
417
    Window window;
 
418
    if (vinfo)
 
419
        window = createDummyWindow(dpy, vinfo, screenNumber, RootWindow(dpy, screenNumber));
 
420
    else
 
421
        window = createDummyWindow(dpy, config, screenNumber, RootWindow(dpy, screenNumber));
 
422
    if (!window) {
 
423
        qWarning("QGLXContext: Failed to create dummy window");
 
424
        return;
 
425
    }
 
426
 
 
427
    // Update OpenGL version and buffer sizes in our format.
 
428
    GLXContext prevContext = glXGetCurrentContext();
 
429
    GLXDrawable prevDrawable = glXGetCurrentDrawable();
 
430
    if (!glXMakeCurrent(dpy, window, context)) {
 
431
        qWarning("QGLXContext: Failed to make provided context current");
 
432
        return;
 
433
    }
 
434
    m_format = QSurfaceFormat();
 
435
    m_format.setRenderableType(QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGL
 
436
                               ? QSurfaceFormat::OpenGL : QSurfaceFormat::OpenGLES);
 
437
    updateFormatFromContext(m_format);
 
438
    if (vinfo)
 
439
        qglx_surfaceFormatFromVisualInfo(&m_format, dpy, vinfo);
 
440
    else
 
441
        qglx_surfaceFormatFromGLXFBConfig(&m_format, dpy, config);
 
442
    glXMakeCurrent(dpy, prevDrawable, prevContext);
 
443
    XDestroyWindow(dpy, window);
 
444
 
 
445
    if (vinfo)
 
446
        XFree(vinfo);
 
447
 
 
448
    // Success. Store the context. From this point on isValid() is true.
 
449
    m_context = context;
 
450
 
 
451
    if (share)
 
452
        m_shareContext = static_cast<const QGLXContext*>(share)->glxContext();
 
453
}
 
454
 
 
455
QGLXContext::~QGLXContext()
 
456
{
 
457
    if (m_ownsContext)
 
458
        glXDestroyContext(m_display, m_context);
 
459
}
 
460
 
 
461
static QXcbScreen *screenForPlatformSurface(QPlatformSurface *surface)
 
462
{
 
463
    QSurface::SurfaceClass surfaceClass = surface->surface()->surfaceClass();
 
464
    if (surfaceClass == QSurface::Window) {
 
465
        return static_cast<QXcbScreen *>(static_cast<QXcbWindow *>(surface)->screen());
 
466
    } else if (surfaceClass == QSurface::Offscreen) {
 
467
        return static_cast<QXcbScreen *>(static_cast<QGLXPbuffer *>(surface)->screen());
 
468
    }
 
469
    return Q_NULLPTR;
 
470
}
 
471
 
 
472
QVariant QGLXContext::nativeHandle() const
 
473
{
 
474
    return QVariant::fromValue<QGLXNativeContext>(QGLXNativeContext(m_context));
 
475
}
 
476
 
 
477
bool QGLXContext::makeCurrent(QPlatformSurface *surface)
 
478
{
 
479
    bool success = false;
 
480
    Q_ASSERT(surface->surface()->supportsOpenGL());
 
481
 
 
482
    GLXDrawable glxDrawable = 0;
 
483
    QSurface::SurfaceClass surfaceClass = surface->surface()->surfaceClass();
 
484
    if (surfaceClass == QSurface::Window) {
 
485
        m_isPBufferCurrent = false;
 
486
        QXcbWindow *window = static_cast<QXcbWindow *>(surface);
 
487
        glxDrawable = window->xcb_window();
 
488
        success = glXMakeCurrent(m_display, glxDrawable, m_context);
 
489
    } else if (surfaceClass == QSurface::Offscreen) {
 
490
        m_isPBufferCurrent = true;
 
491
        QGLXPbuffer *pbuffer = static_cast<QGLXPbuffer *>(surface);
 
492
        glxDrawable = pbuffer->pbuffer();
 
493
        success = glXMakeContextCurrent(m_display, glxDrawable, glxDrawable, m_context);
 
494
    }
 
495
 
 
496
    if (success && surfaceClass == QSurface::Window) {
 
497
        int interval = surface->format().swapInterval();
 
498
        QXcbScreen *screen = screenForPlatformSurface(surface);
 
499
        if (interval >= 0 && m_swapInterval != interval && screen) {
 
500
            m_swapInterval = interval;
 
501
            typedef void (*qt_glXSwapIntervalEXT)(Display *, GLXDrawable, int);
 
502
            typedef void (*qt_glXSwapIntervalMESA)(unsigned int);
 
503
            static qt_glXSwapIntervalEXT glXSwapIntervalEXT = 0;
 
504
            static qt_glXSwapIntervalMESA glXSwapIntervalMESA = 0;
 
505
            static bool resolved = false;
 
506
            if (!resolved) {
 
507
                resolved = true;
 
508
                QList<QByteArray> glxExt = QByteArray(glXQueryExtensionsString(m_display,
 
509
                                                                               screen->screenNumber())).split(' ');
 
510
                if (glxExt.contains("GLX_EXT_swap_control"))
 
511
                    glXSwapIntervalEXT = (qt_glXSwapIntervalEXT) getProcAddress("glXSwapIntervalEXT");
 
512
                if (glxExt.contains("GLX_MESA_swap_control"))
 
513
                    glXSwapIntervalMESA = (qt_glXSwapIntervalMESA) getProcAddress("glXSwapIntervalMESA");
 
514
            }
 
515
            if (glXSwapIntervalEXT)
 
516
                glXSwapIntervalEXT(m_display, glxDrawable, interval);
 
517
            else if (glXSwapIntervalMESA)
 
518
                glXSwapIntervalMESA(interval);
 
519
        }
 
520
    }
 
521
 
 
522
    return success;
 
523
}
 
524
 
 
525
void QGLXContext::doneCurrent()
 
526
{
 
527
    if (m_isPBufferCurrent)
 
528
        glXMakeContextCurrent(m_display, 0, 0, 0);
 
529
    else
 
530
        glXMakeCurrent(m_display, 0, 0);
 
531
    m_isPBufferCurrent = false;
 
532
}
 
533
 
 
534
void QGLXContext::swapBuffers(QPlatformSurface *surface)
 
535
{
 
536
    GLXDrawable glxDrawable = 0;
 
537
    if (surface->surface()->surfaceClass() == QSurface::Offscreen)
 
538
        glxDrawable = static_cast<QGLXPbuffer *>(surface)->pbuffer();
 
539
    else
 
540
        glxDrawable = static_cast<QXcbWindow *>(surface)->xcb_window();
 
541
    glXSwapBuffers(m_display, glxDrawable);
 
542
 
 
543
    if (surface->surface()->surfaceClass() == QSurface::Window) {
 
544
        QXcbWindow *platformWindow = static_cast<QXcbWindow *>(surface);
 
545
        // OpenGL context might be bound to a non-gui thread use QueuedConnection to sync
 
546
        // the window from the platformWindow's thread as QXcbWindow is no QObject, an
 
547
        // event is sent to QXcbConnection. (this is faster than a metacall)
 
548
        if (platformWindow->needsSync())
 
549
            platformWindow->postSyncWindowRequest();
 
550
    }
 
551
}
 
552
 
 
553
QFunctionPointer QGLXContext::getProcAddress(const char *procName)
 
554
{
 
555
#ifdef QT_STATIC
 
556
    return glXGetProcAddressARB(reinterpret_cast<const GLubyte *>(procName));
 
557
#else
 
558
    typedef void *(*qt_glXGetProcAddressARB)(const GLubyte *);
 
559
    static qt_glXGetProcAddressARB glXGetProcAddressARB = 0;
 
560
    static bool resolved = false;
 
561
 
 
562
    if (resolved && !glXGetProcAddressARB)
 
563
        return 0;
 
564
    if (!glXGetProcAddressARB) {
 
565
        QList<QByteArray> glxExt = QByteArray(glXGetClientString(m_display, GLX_EXTENSIONS)).split(' ');
 
566
        if (glxExt.contains("GLX_ARB_get_proc_address")) {
 
567
#if defined(Q_OS_LINUX) || defined(Q_OS_BSD4)
 
568
            void *handle = dlopen(NULL, RTLD_LAZY);
 
569
            if (handle) {
 
570
                glXGetProcAddressARB = (qt_glXGetProcAddressARB) dlsym(handle, "glXGetProcAddressARB");
 
571
                dlclose(handle);
 
572
            }
 
573
            if (!glXGetProcAddressARB)
 
574
#endif
 
575
            {
 
576
#ifndef QT_NO_LIBRARY
 
577
                extern const QString qt_gl_library_name();
 
578
//                QLibrary lib(qt_gl_library_name());
 
579
                QLibrary lib(QLatin1String("GL"));
 
580
                glXGetProcAddressARB = (qt_glXGetProcAddressARB) lib.resolve("glXGetProcAddressARB");
 
581
#endif
 
582
            }
 
583
        }
 
584
        resolved = true;
 
585
    }
 
586
    if (!glXGetProcAddressARB)
 
587
        return 0;
 
588
    return (void (*)())glXGetProcAddressARB(reinterpret_cast<const GLubyte *>(procName));
 
589
#endif
 
590
}
 
591
 
 
592
QSurfaceFormat QGLXContext::format() const
 
593
{
 
594
    return m_format;
 
595
}
 
596
 
 
597
bool QGLXContext::isSharing() const
 
598
{
 
599
    return m_shareContext != 0;
 
600
}
 
601
 
 
602
bool QGLXContext::isValid() const
 
603
{
 
604
    return m_context != 0;
 
605
}
 
606
 
 
607
bool QGLXContext::m_queriedDummyContext = false;
 
608
bool QGLXContext::m_supportsThreading = true;
 
609
 
 
610
 
 
611
// If this list grows to any significant size, change it a
 
612
// proper string table and make the implementation below use
 
613
// binary search.
 
614
static const char *qglx_threadedgl_blacklist_renderer[] = {
 
615
    "Chromium",                             // QTBUG-32225 (initialization fails)
 
616
    0
 
617
};
 
618
 
 
619
// This disables threaded rendering on anything using mesa, e.g.
 
620
// - nvidia/nouveau
 
621
// - amd/gallium
 
622
// - intel
 
623
// - some software opengl implementations
 
624
//
 
625
// The client glx vendor string is used to identify those setups as that seems to show the least
 
626
// variance between the bad configurations. It's always "Mesa Project and SGI". There are some
 
627
// configurations which don't use mesa and which can do threaded rendering (amd and nvidia chips
 
628
// with their own proprietary drivers).
 
629
//
 
630
// This, of course, is very broad and disables threaded rendering on a lot of devices which would
 
631
// be able to use it. However, the bugs listed below don't follow any easily recognizable pattern
 
632
// and we should rather be safe.
 
633
//
 
634
// http://cgit.freedesktop.org/xcb/libxcb/commit/?id=be0fe56c3bcad5124dcc6c47a2fad01acd16f71a will
 
635
// fix some of the issues. Basically, the proprietary drivers seem to have a way of working around
 
636
// a fundamental flaw with multithreaded access to xcb, but mesa doesn't. The blacklist should be
 
637
// reevaluated once that patch is released in some version of xcb.
 
638
static const char *qglx_threadedgl_blacklist_vendor[] = {
 
639
    "Mesa Project and SGI",                // QTCREATORBUG-10875 (crash in creator)
 
640
                                           // QTBUG-34492 (flickering in fullscreen)
 
641
                                           // QTBUG-38221
 
642
    0
 
643
};
 
644
 
 
645
void QGLXContext::queryDummyContext()
 
646
{
 
647
    if (m_queriedDummyContext)
 
648
        return;
 
649
    m_queriedDummyContext = true;
 
650
 
 
651
    static bool skip = qEnvironmentVariableIsSet("QT_OPENGL_NO_SANITY_CHECK");
 
652
    if (skip)
 
653
        return;
 
654
 
 
655
    QOpenGLContext *oldContext = QOpenGLContext::currentContext();
 
656
    QSurface *oldSurface = 0;
 
657
    if (oldContext)
 
658
        oldSurface = oldContext->surface();
 
659
 
 
660
    QScopedPointer<QSurface> surface;
 
661
    Display *display = glXGetCurrentDisplay();
 
662
    if (!display) {
 
663
        // FIXME: Since Qt 5.6 we don't need to check whether primary screen is NULL
 
664
        if (QScreen *screen = QGuiApplication::primaryScreen())
 
665
            display = DISPLAY_FROM_XCB(static_cast<QXcbScreen *>(screen->handle()));
 
666
    }
 
667
    const char *glxvendor = glXGetClientString(display, GLX_VENDOR);
 
668
    if (glxvendor && !strcmp(glxvendor, "ATI")) {
 
669
        QWindow *window = new QWindow;
 
670
        window->resize(64, 64);
 
671
        window->setSurfaceType(QSurface::OpenGLSurface);
 
672
        window->create();
 
673
        surface.reset(window);
 
674
    } else {
 
675
        QOffscreenSurface *offSurface = new QOffscreenSurface;
 
676
        offSurface->create();
 
677
        surface.reset(offSurface);
 
678
    }
 
679
 
 
680
    QOpenGLContext context;
 
681
    context.create();
 
682
    context.makeCurrent(surface.data());
 
683
 
 
684
    m_supportsThreading = true;
 
685
 
 
686
    if (const char *renderer = (const char *) glGetString(GL_RENDERER)) {
 
687
        for (int i = 0; qglx_threadedgl_blacklist_renderer[i]; ++i) {
 
688
            if (strstr(renderer, qglx_threadedgl_blacklist_renderer[i]) != 0) {
 
689
                m_supportsThreading = false;
 
690
                break;
 
691
            }
 
692
        }
 
693
    }
 
694
 
 
695
    if (glxvendor) {
 
696
        for (int i = 0; qglx_threadedgl_blacklist_vendor[i]; ++i) {
 
697
            if (strstr(glxvendor, qglx_threadedgl_blacklist_vendor[i]) != 0) {
 
698
                m_supportsThreading = false;
 
699
                break;
 
700
            }
 
701
        }
 
702
    }
 
703
 
 
704
    context.doneCurrent();
 
705
    if (oldContext && oldSurface)
 
706
        oldContext->makeCurrent(oldSurface);
 
707
}
 
708
 
 
709
bool QGLXContext::supportsThreading()
 
710
{
 
711
    if (!m_queriedDummyContext)
 
712
        queryDummyContext();
 
713
    return m_supportsThreading;
 
714
}
 
715
 
 
716
QGLXPbuffer::QGLXPbuffer(QOffscreenSurface *offscreenSurface)
 
717
    : QPlatformOffscreenSurface(offscreenSurface)
 
718
    , m_screen(static_cast<QXcbScreen *>(offscreenSurface->screen()->handle()))
 
719
    , m_format(m_screen->surfaceFormatFor(offscreenSurface->requestedFormat()))
 
720
    , m_pbuffer(0)
 
721
{
 
722
    GLXFBConfig config = qglx_findConfig(DISPLAY_FROM_XCB(m_screen), m_screen->screenNumber(), m_format);
 
723
 
 
724
    if (config) {
 
725
        const int attributes[] = {
 
726
            GLX_PBUFFER_WIDTH, offscreenSurface->size().width(),
 
727
            GLX_PBUFFER_HEIGHT, offscreenSurface->size().height(),
 
728
            GLX_LARGEST_PBUFFER, False,
 
729
            GLX_PRESERVED_CONTENTS, False,
 
730
            None
 
731
        };
 
732
 
 
733
        m_pbuffer = glXCreatePbuffer(DISPLAY_FROM_XCB(m_screen), config, attributes);
 
734
 
 
735
        if (m_pbuffer)
 
736
            qglx_surfaceFormatFromGLXFBConfig(&m_format, DISPLAY_FROM_XCB(m_screen), config);
 
737
    }
 
738
}
 
739
 
 
740
QGLXPbuffer::~QGLXPbuffer()
 
741
{
 
742
    if (m_pbuffer)
 
743
        glXDestroyPbuffer(DISPLAY_FROM_XCB(m_screen), m_pbuffer);
 
744
}
 
745
 
 
746
 
 
747
QT_END_NAMESPACE