~ubuntu-branches/ubuntu/wily/qtbase-opensource-src/wily

« back to all changes in this revision

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

  • Committer: Package Import Robot
  • Author(s): Timo Jyrinki
  • Date: 2013-02-05 12:46:17 UTC
  • Revision ID: package-import@ubuntu.com-20130205124617-c8jouts182j002fx
Tags: upstream-5.0.1+dfsg
ImportĀ upstreamĀ versionĀ 5.0.1+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/****************************************************************************
 
2
**
 
3
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
 
4
** Contact: http://www.qt-project.org/legal
 
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 Digia.  For licensing terms and
 
14
** conditions see http://qt.digia.com/licensing.  For further information
 
15
** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
 
20
** Foundation and appearing in the file LICENSE.LGPL included in the
 
21
** packaging of this file.  Please review the following information to
 
22
** ensure the GNU Lesser General Public License version 2.1 requirements
 
23
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
 
24
**
 
25
** In addition, as a special exception, Digia gives you certain additional
 
26
** rights.  These rights are described in the Digia Qt LGPL Exception
 
27
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
 
28
**
 
29
** GNU General Public License Usage
 
30
** Alternatively, this file may be used under the terms of the GNU
 
31
** General Public License version 3.0 as published by the Free Software
 
32
** Foundation and appearing in the file LICENSE.GPL included in the
 
33
** packaging of this file.  Please review the following information to
 
34
** ensure the GNU General Public License version 3.0 requirements will be
 
35
** met: http://www.gnu.org/copyleft/gpl.html.
 
36
**
 
37
**
 
38
** $QT_END_LICENSE$
 
39
**
 
40
****************************************************************************/
 
41
 
 
42
#include <QDebug>
 
43
#include <QLibrary>
 
44
 
 
45
#include "qxcbwindow.h"
 
46
#include "qxcbscreen.h"
 
47
 
 
48
#include <X11/Xlib.h>
 
49
#include <X11/Xutil.h>
 
50
#include <GL/glx.h>
 
51
 
 
52
#include <QtGui/QOpenGLContext>
 
53
 
 
54
#include "qglxintegration.h"
 
55
#include <QtPlatformSupport/private/qglxconvenience_p.h>
 
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_PROFILE_MASK_ARB
 
74
#define GLX_CONTEXT_PROFILE_MASK_ARB 0x9126
 
75
#endif
 
76
 
 
77
static Window createDummyWindow(QXcbScreen *screen, XVisualInfo *visualInfo)
 
78
{
 
79
    Colormap cmap = XCreateColormap(DISPLAY_FROM_XCB(screen), screen->root(), visualInfo->visual, AllocNone);
 
80
    XSetWindowAttributes a;
 
81
    a.background_pixel = WhitePixel(DISPLAY_FROM_XCB(screen), screen->screenNumber());
 
82
    a.border_pixel = BlackPixel(DISPLAY_FROM_XCB(screen), screen->screenNumber());
 
83
    a.colormap = cmap;
 
84
 
 
85
    Window window = XCreateWindow(DISPLAY_FROM_XCB(screen), screen->root(),
 
86
                                  0, 0, 100, 100,
 
87
                                  0, visualInfo->depth, InputOutput, visualInfo->visual,
 
88
                                  CWBackPixel|CWBorderPixel|CWColormap, &a);
 
89
    XFreeColormap(DISPLAY_FROM_XCB(screen), cmap);
 
90
    return window;
 
91
}
 
92
 
 
93
static Window createDummyWindow(QXcbScreen *screen, GLXFBConfig config)
 
94
{
 
95
    XVisualInfo *visualInfo = glXGetVisualFromFBConfig(DISPLAY_FROM_XCB(screen), config);
 
96
    if (!visualInfo)
 
97
        qFatal("Could not initialize GLX");
 
98
    Window window = createDummyWindow(screen, visualInfo);
 
99
    XFree(visualInfo);
 
100
    return window;
 
101
}
 
102
 
 
103
// Per-window data for active OpenGL contexts.
 
104
struct QOpenGLContextData
 
105
{
 
106
    QOpenGLContextData(Display *display, Window window, GLXContext context)
 
107
        : m_display(display),
 
108
          m_window(window),
 
109
          m_context(context)
 
110
    {}
 
111
 
 
112
    QOpenGLContextData()
 
113
        : m_display(0),
 
114
          m_window(0),
 
115
          m_context(0)
 
116
    {}
 
117
 
 
118
    Display *m_display;
 
119
    Window m_window;
 
120
    GLXContext m_context;
 
121
};
 
122
 
 
123
static inline QOpenGLContextData currentOpenGLContextData()
 
124
{
 
125
    QOpenGLContextData result;
 
126
    result.m_display = glXGetCurrentDisplay();
 
127
    result.m_window = glXGetCurrentDrawable();
 
128
    result.m_context = glXGetCurrentContext();
 
129
    return result;
 
130
}
 
131
 
 
132
static inline QOpenGLContextData createDummyWindowOpenGLContextData(QXcbScreen *screen)
 
133
{
 
134
    QOpenGLContextData result;
 
135
    result.m_display = DISPLAY_FROM_XCB(screen);
 
136
 
 
137
    QSurfaceFormat format;
 
138
    GLXFBConfig config = qglx_findConfig(DISPLAY_FROM_XCB(screen), screen->screenNumber(), format);
 
139
    if (config) {
 
140
        result.m_context = glXCreateNewContext(DISPLAY_FROM_XCB(screen), config, GLX_RGBA_TYPE, 0, true);
 
141
        result.m_window = createDummyWindow(screen, config);
 
142
    } else {
 
143
        XVisualInfo *visualInfo = qglx_findVisualInfo(DISPLAY_FROM_XCB(screen), screen->screenNumber(), &format);
 
144
        if (!visualInfo)
 
145
            qFatal("Could not initialize GLX");
 
146
        result.m_context = glXCreateContext(DISPLAY_FROM_XCB(screen), visualInfo, 0, true);
 
147
        result.m_window = createDummyWindow(screen, visualInfo);
 
148
        XFree(visualInfo);
 
149
    }
 
150
 
 
151
    return result;
 
152
}
 
153
 
 
154
static inline QByteArray getGlString(GLenum param)
 
155
{
 
156
    if (const GLubyte *s = glGetString(param))
 
157
        return QByteArray(reinterpret_cast<const char*>(s));
 
158
    return QByteArray();
 
159
}
 
160
 
 
161
static void updateFormatFromContext(QSurfaceFormat &format)
 
162
{
 
163
    // Update the version, profile, and context bit of the format
 
164
    int major = 0, minor = 0;
 
165
    QByteArray versionString(getGlString(GL_VERSION));
 
166
    if (QPlatformOpenGLContext::parseOpenGLVersion(versionString, major, minor)) {
 
167
        format.setMajorVersion(major);
 
168
        format.setMinorVersion(minor);
 
169
    }
 
170
 
 
171
    const int version = (major << 8) + minor;
 
172
    if (version < 0x0300) {
 
173
        format.setProfile(QSurfaceFormat::NoProfile);
 
174
        format.setOption(QSurfaceFormat::DeprecatedFunctions);
 
175
        return;
 
176
    }
 
177
 
 
178
    // Version 3.0 onwards - check if it includes deprecated functionality or is
 
179
    // a debug context
 
180
    GLint value = 0;
 
181
    glGetIntegerv(GL_CONTEXT_FLAGS, &value);
 
182
    if (value & ~GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT)
 
183
        format.setOption(QSurfaceFormat::DeprecatedFunctions);
 
184
    if (value & GLX_CONTEXT_DEBUG_BIT_ARB)
 
185
        format.setOption(QSurfaceFormat::DebugContext);
 
186
    if (version < 0x0302)
 
187
        return;
 
188
 
 
189
    // Version 3.2 and newer have a profile
 
190
    value = 0;
 
191
    glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &value);
 
192
    switch (value) {
 
193
    case GLX_CONTEXT_CORE_PROFILE_BIT_ARB:
 
194
        format.setProfile(QSurfaceFormat::CoreProfile);
 
195
        break;
 
196
    case GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB:
 
197
        format.setProfile(QSurfaceFormat::CompatibilityProfile);
 
198
        break;
 
199
    default:
 
200
        format.setProfile(QSurfaceFormat::NoProfile);
 
201
        break;
 
202
    }
 
203
}
 
204
 
 
205
/*!
 
206
    \class QOpenGLTemporaryContext
 
207
    \brief A temporary context that can be instantiated on the stack.
 
208
 
 
209
    Functions like glGetString() only work if there is a current GL context.
 
210
 
 
211
    \internal
 
212
    \ingroup qt-lighthouse-xcb
 
213
*/
 
214
class QOpenGLTemporaryContext
 
215
{
 
216
    Q_DISABLE_COPY(QOpenGLTemporaryContext)
 
217
public:
 
218
    QOpenGLTemporaryContext(QXcbScreen *screen);
 
219
    ~QOpenGLTemporaryContext();
 
220
 
 
221
private:
 
222
    const QOpenGLContextData m_previous;
 
223
    const QOpenGLContextData m_current;
 
224
};
 
225
 
 
226
QOpenGLTemporaryContext::QOpenGLTemporaryContext(QXcbScreen *screen)
 
227
    : m_previous(currentOpenGLContextData()),
 
228
      m_current(createDummyWindowOpenGLContextData(screen))
 
229
{
 
230
    // Make our temporary context current on our temporary window
 
231
    glXMakeCurrent(m_current.m_display, m_current.m_window, m_current.m_context);
 
232
}
 
233
 
 
234
QOpenGLTemporaryContext::~QOpenGLTemporaryContext()
 
235
{
 
236
    // Restore the previous context if possible, otherwise just release our temporary context
 
237
    if (m_previous.m_display)
 
238
        glXMakeCurrent(m_previous.m_display, m_previous.m_window, m_previous.m_context);
 
239
    else
 
240
        glXMakeCurrent(m_current.m_display, 0, 0);
 
241
 
 
242
    // Destroy our temporary window
 
243
    XDestroyWindow(m_current.m_display, m_current.m_window);
 
244
 
 
245
    // Finally destroy our temporary context itself
 
246
    glXDestroyContext(m_current.m_display, m_current.m_context);
 
247
}
 
248
 
 
249
QOpenGLDefaultContextInfo::QOpenGLDefaultContextInfo()
 
250
    : vendor(getGlString(GL_VENDOR)),
 
251
      renderer(getGlString(GL_RENDERER))
 
252
{
 
253
    updateFormatFromContext(format);
 
254
}
 
255
 
 
256
QOpenGLDefaultContextInfo *QOpenGLDefaultContextInfo::create(QXcbScreen *screen)
 
257
{
 
258
    // We need a current context for getGLString() to work. To have
 
259
    // the QOpenGLDefaultContextInfo contain the latest supported
 
260
    // context version, we rely upon the QOpenGLTemporaryContext to
 
261
    // correctly obtain a context with the latest version
 
262
    QScopedPointer<QOpenGLTemporaryContext> temporaryContext(new QOpenGLTemporaryContext(screen));
 
263
    QOpenGLDefaultContextInfo *result = new QOpenGLDefaultContextInfo;
 
264
    return result;
 
265
}
 
266
 
 
267
 
 
268
QGLXContext::QGLXContext(QXcbScreen *screen, const QSurfaceFormat &format, QPlatformOpenGLContext *share, QOpenGLDefaultContextInfo *defaultContextInfo)
 
269
    : QPlatformOpenGLContext()
 
270
    , m_screen(screen)
 
271
    , m_context(0)
 
272
    , m_format(format)
 
273
{
 
274
    m_shareContext = 0;
 
275
    if (share)
 
276
        m_shareContext = static_cast<const QGLXContext*>(share)->glxContext();
 
277
 
 
278
    GLXFBConfig config = qglx_findConfig(DISPLAY_FROM_XCB(screen),screen->screenNumber(),format);
 
279
    XVisualInfo *visualInfo = 0;
 
280
    Window window = 0; // Temporary window used to query OpenGL context
 
281
 
 
282
    if (config) {
 
283
        // Resolve entry point for glXCreateContextAttribsARB
 
284
        glXCreateContextAttribsARBProc glXCreateContextAttribsARB = 0;
 
285
        glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc) glXGetProcAddress((const GLubyte*)"glXCreateContextAttribsARB");
 
286
 
 
287
        // Use glXCreateContextAttribsARB if is available
 
288
        if (glXCreateContextAttribsARB != 0) {
 
289
            // We limit the requested version by the version of the static context as
 
290
            // glXCreateContextAttribsARB fails and returns NULL if the requested context
 
291
            // version is not supported. This means that we will get the closest supported
 
292
            // context format that that which was requested and is supported by the driver
 
293
            const int maxSupportedVersion = (defaultContextInfo->format.majorVersion() << 8)
 
294
                                          + defaultContextInfo->format.minorVersion();
 
295
            const int requestedVersion = qMin((format.majorVersion() << 8) + format.minorVersion(),
 
296
                                               maxSupportedVersion);
 
297
            const int majorVersion = requestedVersion >> 8;
 
298
            const int minorVersion = requestedVersion & 0xFF;
 
299
 
 
300
            QVector<int> contextAttributes;
 
301
            contextAttributes << GLX_CONTEXT_MAJOR_VERSION_ARB << majorVersion
 
302
                              << GLX_CONTEXT_MINOR_VERSION_ARB << minorVersion;
 
303
 
 
304
            // If asking for OpenGL 3.2 or newer we should also specify a profile
 
305
            if (m_format.majorVersion() > 3 || (m_format.majorVersion() == 3 && m_format.minorVersion() > 1)) {
 
306
                if (m_format.profile() == QSurfaceFormat::CoreProfile) {
 
307
                    contextAttributes << GLX_CONTEXT_FLAGS_ARB << GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB
 
308
                                      << GLX_CONTEXT_PROFILE_MASK_ARB << GLX_CONTEXT_CORE_PROFILE_BIT_ARB;
 
309
                } else {
 
310
                    contextAttributes << GLX_CONTEXT_PROFILE_MASK_ARB << GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB;
 
311
                }
 
312
            }
 
313
 
 
314
            contextAttributes << None;
 
315
 
 
316
            m_context = glXCreateContextAttribsARB(DISPLAY_FROM_XCB(screen), config, m_shareContext, true, contextAttributes.data());
 
317
            if (!m_context && m_shareContext) {
 
318
                // re-try without a shared glx context
 
319
                m_context = glXCreateContextAttribsARB(DISPLAY_FROM_XCB(screen), config, 0, true, contextAttributes.data());
 
320
                if (m_context)
 
321
                    m_shareContext = 0;
 
322
            }
 
323
        }
 
324
 
 
325
        // Could not create a context using glXCreateContextAttribsARB, falling back to glXCreateNewContext.
 
326
        if (!m_context) {
 
327
            m_context = glXCreateNewContext(DISPLAY_FROM_XCB(screen), config, GLX_RGBA_TYPE, m_shareContext, true);
 
328
            if (!m_context && m_shareContext) {
 
329
                // re-try without a shared glx context
 
330
                m_context = glXCreateNewContext(DISPLAY_FROM_XCB(screen), config, GLX_RGBA_TYPE, 0, true);
 
331
                if (m_context)
 
332
                    m_shareContext = 0;
 
333
            }
 
334
        }
 
335
 
 
336
        // Get the basic surface format details
 
337
        if (m_context)
 
338
            m_format = qglx_surfaceFormatFromGLXFBConfig(DISPLAY_FROM_XCB(screen), config, m_context);
 
339
 
 
340
        // Create a temporary window so that we can make the new context current
 
341
        window = createDummyWindow(screen, config);
 
342
    } else {
 
343
        // Note that m_format gets updated with the used surface format
 
344
        visualInfo = qglx_findVisualInfo(DISPLAY_FROM_XCB(screen), screen->screenNumber(), &m_format);
 
345
        if (!visualInfo)
 
346
            qFatal("Could not initialize GLX");
 
347
        m_context = glXCreateContext(DISPLAY_FROM_XCB(screen), visualInfo, m_shareContext, true);
 
348
        if (!m_context && m_shareContext) {
 
349
            // re-try without a shared glx context
 
350
            m_shareContext = 0;
 
351
            m_context = glXCreateContext(DISPLAY_FROM_XCB(screen), visualInfo, 0, true);
 
352
        }
 
353
 
 
354
        // Create a temporary window so that we can make the new context current
 
355
        window = createDummyWindow(screen, visualInfo);
 
356
        XFree(visualInfo);
 
357
    }
 
358
 
 
359
    // Query the OpenGL version and profile
 
360
    if (m_context && window) {
 
361
        glXMakeCurrent(DISPLAY_FROM_XCB(screen), window, m_context);
 
362
        updateFormatFromContext(m_format);
 
363
 
 
364
        // Make our context non-current
 
365
        glXMakeCurrent(DISPLAY_FROM_XCB(screen), 0, 0);
 
366
    }
 
367
 
 
368
    // Destroy our temporary window
 
369
    XDestroyWindow(DISPLAY_FROM_XCB(screen), window);
 
370
}
 
371
 
 
372
QGLXContext::~QGLXContext()
 
373
{
 
374
    glXDestroyContext(DISPLAY_FROM_XCB(m_screen), m_context);
 
375
}
 
376
 
 
377
bool QGLXContext::makeCurrent(QPlatformSurface *surface)
 
378
{
 
379
    Q_ASSERT(surface->surface()->surfaceType() == QSurface::OpenGLSurface);
 
380
 
 
381
    GLXDrawable glxDrawable = static_cast<QXcbWindow *>(surface)->xcb_window();
 
382
 
 
383
    return glXMakeCurrent(DISPLAY_FROM_XCB(m_screen), glxDrawable, m_context);
 
384
}
 
385
 
 
386
void QGLXContext::doneCurrent()
 
387
{
 
388
    glXMakeCurrent(DISPLAY_FROM_XCB(m_screen), 0, 0);
 
389
}
 
390
 
 
391
void QGLXContext::swapBuffers(QPlatformSurface *surface)
 
392
{
 
393
    GLXDrawable glxDrawable = static_cast<QXcbWindow *>(surface)->xcb_window();
 
394
    glXSwapBuffers(DISPLAY_FROM_XCB(m_screen), glxDrawable);
 
395
}
 
396
 
 
397
void (*QGLXContext::getProcAddress(const QByteArray &procName)) ()
 
398
{
 
399
    typedef void *(*qt_glXGetProcAddressARB)(const GLubyte *);
 
400
    static qt_glXGetProcAddressARB glXGetProcAddressARB = 0;
 
401
    static bool resolved = false;
 
402
 
 
403
    if (resolved && !glXGetProcAddressARB)
 
404
        return 0;
 
405
    if (!glXGetProcAddressARB) {
 
406
        QList<QByteArray> glxExt = QByteArray(glXGetClientString(DISPLAY_FROM_XCB(m_screen), GLX_EXTENSIONS)).split(' ');
 
407
        if (glxExt.contains("GLX_ARB_get_proc_address")) {
 
408
#if defined(Q_OS_LINUX) || defined(Q_OS_BSD4)
 
409
            void *handle = dlopen(NULL, RTLD_LAZY);
 
410
            if (handle) {
 
411
                glXGetProcAddressARB = (qt_glXGetProcAddressARB) dlsym(handle, "glXGetProcAddressARB");
 
412
                dlclose(handle);
 
413
            }
 
414
            if (!glXGetProcAddressARB)
 
415
#endif
 
416
            {
 
417
                extern const QString qt_gl_library_name();
 
418
//                QLibrary lib(qt_gl_library_name());
 
419
                QLibrary lib(QLatin1String("GL"));
 
420
                glXGetProcAddressARB = (qt_glXGetProcAddressARB) lib.resolve("glXGetProcAddressARB");
 
421
            }
 
422
        }
 
423
        resolved = true;
 
424
    }
 
425
    if (!glXGetProcAddressARB)
 
426
        return 0;
 
427
    return (void (*)())glXGetProcAddressARB(reinterpret_cast<const GLubyte *>(procName.constData()));
 
428
}
 
429
 
 
430
QSurfaceFormat QGLXContext::format() const
 
431
{
 
432
    return m_format;
 
433
}
 
434
 
 
435
bool QGLXContext::isSharing() const
 
436
{
 
437
    return m_shareContext != 0;
 
438
}
 
439
 
 
440
bool QGLXContext::isValid() const
 
441
{
 
442
    return m_context != 0;
 
443
}
 
444
 
 
445
QT_END_NAMESPACE