Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qglxintegration.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include <QDebug>
5
6#include "qxcbwindow.h"
7#include "qxcbscreen.h"
8
9#define register /* C++17 deprecated register */
10#include <X11/Xlib.h>
11#include <X11/Xutil.h>
12#undef register
13#include <GL/glx.h>
14
15#if QT_CONFIG(regularexpression)
16# include <QtCore/QRegularExpression>
17#endif
18#include <QtGui/qguiapplication.h>
19#include <QtGui/QOpenGLContext>
20#include <QtGui/QOffscreenSurface>
21
22#include "qglxintegration.h"
23#include <QtGui/private/qglxconvenience_p.h>
24
25#include "qxcbglintegration.h"
26
28
29typedef GLXContext (*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXContext, Bool, const int*);
30typedef const GLubyte *(*glGetStringiProc)(GLenum, GLuint);
31
32#ifndef GLX_CONTEXT_CORE_PROFILE_BIT_ARB
33#define GLX_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001
34#endif
35
36#ifndef GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB
37#define GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
38#endif
39
40#ifndef GLX_CONTEXT_ES2_PROFILE_BIT_EXT
41#define GLX_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000004
42#endif
43
44#ifndef GLX_CONTEXT_PROFILE_MASK_ARB
45#define GLX_CONTEXT_PROFILE_MASK_ARB 0x9126
46#endif
47
48#ifndef GL_CONTEXT_FLAG_DEBUG_BIT
49#define GL_CONTEXT_FLAG_DEBUG_BIT 0x00000002
50#endif
51
52#ifndef GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB
53#define GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004
54#endif
55
56#ifndef GL_RESET_NOTIFICATION_STRATEGY_ARB
57#define GL_RESET_NOTIFICATION_STRATEGY_ARB 0x8256
58#endif
59
60#ifndef GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB
61#define GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256
62#endif
63
64#ifndef GL_LOSE_CONTEXT_ON_RESET_ARB
65#define GL_LOSE_CONTEXT_ON_RESET_ARB 0x8252
66#endif
67
68#ifndef GLX_LOSE_CONTEXT_ON_RESET_ARB
69#define GLX_LOSE_CONTEXT_ON_RESET_ARB 0x8252
70#endif
71
72#ifndef GLX_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV
73#define GLX_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV 0x20F7
74#endif
75
76static Window createDummyWindow(Display *dpy, XVisualInfo *visualInfo, int screenNumber, Window rootWin)
77{
78 Colormap cmap = XCreateColormap(dpy, rootWin, visualInfo->visual, AllocNone);
79 XSetWindowAttributes a;
80 a.background_pixel = WhitePixel(dpy, screenNumber);
81 a.border_pixel = BlackPixel(dpy, screenNumber);
82 a.colormap = cmap;
83 a.override_redirect = true;
84
85 Window window = XCreateWindow(dpy, rootWin,
86 0, 0, 100, 100,
87 0, visualInfo->depth, InputOutput, visualInfo->visual,
88 CWBackPixel|CWBorderPixel|CWColormap|CWOverrideRedirect, &a);
89#ifndef QT_NO_DEBUG
90 XStoreName(dpy, window, "Qt GLX dummy window");
91#endif
92 XFreeColormap(dpy, cmap);
93 return window;
94}
95
96static Window createDummyWindow(Display *dpy, GLXFBConfig config, int screenNumber, Window rootWin)
97{
98 XVisualInfo *visualInfo = glXGetVisualFromFBConfig(dpy, config);
99 if (Q_UNLIKELY(!visualInfo))
100 qFatal("Could not initialize GLX");
101 Window window = createDummyWindow(dpy, visualInfo, screenNumber, rootWin);
102 XFree(visualInfo);
103 return window;
104}
105
107{
108 if (const GLubyte *s = glGetString(param))
109 return QByteArray(reinterpret_cast<const char*>(s));
110 return QByteArray();
111}
112
113static bool hasGlExtension(const QSurfaceFormat &format, const char *ext)
114{
115 if (format.majorVersion() < 3) {
116 auto exts = reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS));
117 return exts && strstr(exts, ext);
118 } else {
119 auto glGetStringi = reinterpret_cast<glGetStringiProc>(
120 glXGetProcAddress(reinterpret_cast<const GLubyte*>("glGetStringi")));
121 if (glGetStringi) {
122 GLint n = 0;
123 glGetIntegerv(GL_NUM_EXTENSIONS, &n);
124 for (GLint i = 0; i < n; ++i) {
125 const char *p = reinterpret_cast<const char *>(glGetStringi(GL_EXTENSIONS, i));
126 if (p && !strcmp(p, ext))
127 return true;
128 }
129 }
130 return false;
131 }
132}
133
135{
136 // Update the version, profile, and context bit of the format
137 int major = 0, minor = 0;
138 QByteArray versionString(getGlString(GL_VERSION));
139 if (QPlatformOpenGLContext::parseOpenGLVersion(versionString, major, minor)) {
140 format.setMajorVersion(major);
141 format.setMinorVersion(minor);
142 }
143
145 const bool isStereo = format.testOption(QSurfaceFormat::StereoBuffers);
146 format.setOptions(QSurfaceFormat::FormatOptions());
147 // Restore flags that come from the VisualInfo/FBConfig.
148 if (isStereo)
150
151 if (format.renderableType() == QSurfaceFormat::OpenGL) {
152 if (hasGlExtension(format, "GL_ARB_robustness")) {
153 GLint value = 0;
157 }
158
159 if (format.version() < qMakePair(3, 0)) {
161 return;
162 }
163
164 // Version 3.0 onwards - check if it includes deprecated functionality or is
165 // a debug context
166 GLint value = 0;
167 glGetIntegerv(GL_CONTEXT_FLAGS, &value);
172 if (format.version() < qMakePair(3, 2))
173 return;
174
175 // Version 3.2 and newer have a profile
176 value = 0;
177 glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &value);
178
183 }
184}
185
188 , m_display(display)
189 , m_format(format)
190 , m_ownsContext(true)
191{
196 return;
197
198 if (share)
199 m_shareContext = static_cast<const QGLXContext*>(share)->glxContext();
200
201 GLXFBConfig config = qglx_findConfig(m_display, screen->screenNumber(), m_format);
202 m_config = config;
203 XVisualInfo *visualInfo = nullptr;
204 Window window = 0; // Temporary window used to query OpenGL context
205
206 if (config) {
207 const QByteArrayList glxExt = QByteArray(glXQueryExtensionsString(m_display, screen->screenNumber())).split(' ');
208
209 // Resolve entry point for glXCreateContextAttribsARB
210 glXCreateContextAttribsARBProc glXCreateContextAttribsARB = nullptr;
211 if (glxExt.contains("GLX_ARB_create_context"))
212 glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc) glXGetProcAddress((const GLubyte*)"glXCreateContextAttribsARB");
213
214 const bool supportsProfiles = glxExt.contains("GLX_ARB_create_context_profile");
215 const bool supportsRobustness = glxExt.contains("GLX_ARB_create_context_robustness");
216 const bool supportsVideoMemoryPurge = glxExt.contains("GLX_NV_robustness_video_memory_purge");
217
218 // Use glXCreateContextAttribsARB if available
219 // Also, GL ES context creation requires GLX_EXT_create_context_es2_profile
220 if (glXCreateContextAttribsARB != nullptr
221 && (m_format.renderableType() != QSurfaceFormat::OpenGLES || (supportsProfiles && glxExt.contains("GLX_EXT_create_context_es2_profile")))) {
222 // Try to create an OpenGL context for each known OpenGL version in descending
223 // order from the requested version.
224 const int requestedVersion = m_format.majorVersion() * 10 + qMin(m_format.minorVersion(), 9);
225
226 QList<int> glVersions;
227 if (m_format.renderableType() == QSurfaceFormat::OpenGL) {
228 if (requestedVersion > 46)
229 glVersions << requestedVersion;
230
231 // Don't bother with versions below 2.0
232 glVersions << 46 << 45 << 44 << 43 << 42 << 41 << 40 << 33 << 32 << 31 << 30 << 21 << 20;
233 } else if (m_format.renderableType() == QSurfaceFormat::OpenGLES) {
234 if (requestedVersion > 32)
235 glVersions << requestedVersion;
236
237 // Don't bother with versions below ES 2.0
238 glVersions << 32 << 31 << 30 << 20;
239 // ES does not support any format option
240 m_format.setOptions(QSurfaceFormat::FormatOptions());
241 }
242 // Robustness must match that of the shared context.
243 if (share && share->format().testOption(QSurfaceFormat::ResetNotification))
245 Q_ASSERT(glVersions.size() > 0);
246
247 for (int i = 0; !m_context && i < glVersions.size(); i++) {
248 const int version = glVersions[i];
249 if (version > requestedVersion)
250 continue;
251
252 const int majorVersion = version / 10;
253 const int minorVersion = version % 10;
254
255 QList<int> contextAttributes;
256 contextAttributes << GLX_CONTEXT_MAJOR_VERSION_ARB << majorVersion
257 << GLX_CONTEXT_MINOR_VERSION_ARB << minorVersion;
258
259
260 if (m_format.renderableType() == QSurfaceFormat::OpenGL) {
261 // If asking for OpenGL 3.2 or newer we should also specify a profile
262 if (version >= 32 && supportsProfiles) {
263 if (m_format.profile() == QSurfaceFormat::CoreProfile)
265 else
267 }
268
269 int flags = 0;
270
271 if (supportsRobustness)
273
275 flags |= GLX_CONTEXT_DEBUG_BIT_ARB;
276
277 // A forward-compatible context may be requested for 3.0 and later
278 if (version >= 30 && !m_format.testOption(QSurfaceFormat::DeprecatedFunctions))
279 flags |= GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
280
281 if (flags != 0)
282 contextAttributes << GLX_CONTEXT_FLAGS_ARB << flags;
283 } else if (m_format.renderableType() == QSurfaceFormat::OpenGLES) {
285 }
286
287 if (supportsRobustness && m_format.testOption(QSurfaceFormat::ResetNotification)) {
288 QList<int> contextAttributesWithRobustness = contextAttributes;
290 if (supportsVideoMemoryPurge)
291 contextAttributesWithRobustness << GLX_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV << GL_TRUE;
292
293 contextAttributesWithRobustness << None;
294 m_context = glXCreateContextAttribsARB(m_display, config, m_shareContext, true,
295 contextAttributesWithRobustness.data());
296 // Context creation against a shared context may fail specifically due to this request, so try
297 // without before dropping sharing.
298 }
299
300 if (m_context) {
301 m_getGraphicsResetStatus = reinterpret_cast<GLenum (QOPENGLF_APIENTRYP)()>(getProcAddress("glGetGraphicsResetStatusARB"));
302 } else {
303 contextAttributes << None;
304 m_context = glXCreateContextAttribsARB(m_display, config, m_shareContext, true, contextAttributes.data());
305 if (!m_context && m_shareContext) {
306 // re-try without a shared glx context
307 m_context = glXCreateContextAttribsARB(m_display, config, nullptr, true, contextAttributes.data());
308 if (m_context)
309 m_shareContext = nullptr;
310 }
311 }
312 }
313 }
314
315 // Could not create a context using glXCreateContextAttribsARB, falling back to glXCreateNewContext.
316 if (!m_context) {
317 // requesting an OpenGL ES context requires glXCreateContextAttribsARB, so bail out
319 return;
320
321 m_context = glXCreateNewContext(m_display, config, GLX_RGBA_TYPE, m_shareContext, true);
322 if (!m_context && m_shareContext) {
323 // re-try without a shared glx context
324 m_context = glXCreateNewContext(m_display, config, GLX_RGBA_TYPE, nullptr, true);
325 if (m_context)
326 m_shareContext = nullptr;
327 }
328 }
329
330 // Get the basic surface format details
331 if (m_context)
332 qglx_surfaceFormatFromGLXFBConfig(&m_format, m_display, config);
333
334 // Create a temporary window so that we can make the new context current
335 window = createDummyWindow(m_display, config, screen->screenNumber(), screen->root());
336 } else {
337 // requesting an OpenGL ES context requires glXCreateContextAttribsARB, so bail out
339 return;
340
341 // Note that m_format gets updated with the used surface format
342 visualInfo = qglx_findVisualInfo(m_display, screen->screenNumber(), &m_format);
343 if (Q_UNLIKELY(!visualInfo))
344 qFatal("Could not initialize GLX");
345 m_context = glXCreateContext(m_display, visualInfo, m_shareContext, true);
346 if (!m_context && m_shareContext) {
347 // re-try without a shared glx context
348 m_shareContext = nullptr;
349 m_context = glXCreateContext(m_display, visualInfo, nullptr, true);
350 }
351
352 // Create a temporary window so that we can make the new context current
353 window = createDummyWindow(m_display, visualInfo, screen->screenNumber(), screen->root());
354 XFree(visualInfo);
355 }
356
357 // Query the OpenGL version and profile
358 if (m_context && window) {
359 GLXContext prevContext = glXGetCurrentContext();
360 GLXDrawable prevDrawable = glXGetCurrentDrawable();
361 glXMakeCurrent(m_display, window, m_context);
362 updateFormatFromContext(m_format);
363
364 // Make our context non-current
365 glXMakeCurrent(m_display, prevDrawable, prevContext);
366 }
367
368 // Destroy our temporary window
369 XDestroyWindow(m_display, window);
370}
371
374 , m_display(display)
375{
376 // Legacy contexts created using glXCreateContext are created using a
377 // XVisualInfo. If the user passed one we should use that.
378 XVisualInfo *vinfo = static_cast<XVisualInfo*>(visualInfo);
379
380 // Otherwise assume the context was created with an FBConfig using the modern functions
381 if (!vinfo) {
382 int configId = 0;
383 if (glXQueryContext(m_display, context, GLX_FBCONFIG_ID, &configId) != Success) {
384 qWarning("QGLXContext: Failed to query config from the provided context");
385 return;
386 }
387
388 int screenNumber = 0;
389 if (glXQueryContext(m_display, context, GLX_SCREEN, &screenNumber) != Success) {
390 qWarning("QGLXContext: Failed to query screen from the provided context");
391 screenNumber = DefaultScreen(m_display);
392 }
393
394 GLXFBConfig *configs;
395 int numConfigs = 0;
396 static const int attribs[] = { GLX_FBCONFIG_ID, configId, None };
397 configs = glXChooseFBConfig(m_display, screenNumber, attribs, &numConfigs);
398 if (!configs) {
399 qWarning("QGLXContext: Failed to find config(invalid arguments for glXChooseFBConfig)");
400 return;
401 } else if (numConfigs < 1) {
402 qWarning("QGLXContext: Failed to find config");
403 XFree(configs);
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 m_config = configs[0];
410 XFree(configs);
411 }
412
413 Q_ASSERT(vinfo || m_config);
414
415 int screenNumber = DefaultScreen(m_display);
417 if (vinfo)
418 window = createDummyWindow(m_display, vinfo, screenNumber, RootWindow(m_display, screenNumber));
419 else
420 window = createDummyWindow(m_display, m_config, screenNumber, RootWindow(m_display, screenNumber));
421 if (!window) {
422 qWarning("QGLXContext: Failed to create dummy window");
423 return;
424 }
425
426 // Update OpenGL version and buffer sizes in our format.
427 GLXContext prevContext = glXGetCurrentContext();
428 GLXDrawable prevDrawable = glXGetCurrentDrawable();
429 if (!glXMakeCurrent(m_display, window, context)) {
430 qWarning("QGLXContext: Failed to make provided context current");
431 return;
432 }
433 m_format = QSurfaceFormat();
436 updateFormatFromContext(m_format);
437 if (vinfo)
438 qglx_surfaceFormatFromVisualInfo(&m_format, m_display, vinfo);
439 else
440 qglx_surfaceFormatFromGLXFBConfig(&m_format, m_display, m_config);
441 glXMakeCurrent(m_display, prevDrawable, prevContext);
442 XDestroyWindow(m_display, window);
443
444 if (vinfo)
445 XFree(vinfo);
446
447 // Success. Store the context. From this point on isValid() is true.
448 m_context = context;
449
450 if (share)
451 m_shareContext = static_cast<const QGLXContext*>(share)->glxContext();
452}
453
455{
456 if (m_ownsContext)
457 glXDestroyContext(m_display, m_context);
458}
459
461{
462 QSurface::SurfaceClass surfaceClass = surface->surface()->surfaceClass();
463 if (surfaceClass == QSurface::Window) {
464 return static_cast<QXcbScreen *>(static_cast<QXcbWindow *>(surface)->screen());
465 } else if (surfaceClass == QSurface::Offscreen) {
466 return static_cast<QXcbScreen *>(static_cast<QGLXPbuffer *>(surface)->screen());
467 }
468 return nullptr;
469}
470
472{
473 bool success = false;
474 Q_ASSERT(surface->surface()->supportsOpenGL());
475
476 GLXDrawable glxDrawable = 0;
477 QSurface::SurfaceClass surfaceClass = surface->surface()->surfaceClass();
478 if (surfaceClass == QSurface::Window) {
479 m_isPBufferCurrent = false;
480 QXcbWindow *window = static_cast<QXcbWindow *>(surface);
481 glxDrawable = window->xcb_window();
482 success = glXMakeCurrent(m_display, glxDrawable, m_context);
483 m_lost = false;
484 if (m_getGraphicsResetStatus && m_getGraphicsResetStatus() != GL_NO_ERROR) {
485 m_lost = true;
486 success = false;
487 // Drop the surface. Will recreate on the next makeCurrent.
488 window->invalidateSurface();
489 }
490 } else if (surfaceClass == QSurface::Offscreen) {
491 m_isPBufferCurrent = true;
492 QGLXPbuffer *pbuffer = static_cast<QGLXPbuffer *>(surface);
493 glxDrawable = pbuffer->pbuffer();
494 success = glXMakeContextCurrent(m_display, glxDrawable, glxDrawable, m_context);
495 m_lost = false;
496 if (m_getGraphicsResetStatus && m_getGraphicsResetStatus() != GL_NO_ERROR) {
497 m_lost = true;
498 success = false;
499 }
500 }
501
502 if (success && surfaceClass == QSurface::Window) {
503 int interval = surface->format().swapInterval();
504 QXcbWindow *window = static_cast<QXcbWindow *>(surface);
506 if (interval >= 0 && interval != window->swapInterval() && screen) {
507 typedef void (*qt_glXSwapIntervalEXT)(Display *, GLXDrawable, int);
508 typedef void (*qt_glXSwapIntervalMESA)(unsigned int);
509 static qt_glXSwapIntervalEXT glXSwapIntervalEXT = nullptr;
510 static qt_glXSwapIntervalMESA glXSwapIntervalMESA = nullptr;
511 static bool resolved = false;
512 if (!resolved) {
513 resolved = true;
514 QList<QByteArray> glxExt = QByteArray(glXQueryExtensionsString(m_display,
515 screen->screenNumber())).split(' ');
516 if (glxExt.contains("GLX_EXT_swap_control"))
517 glXSwapIntervalEXT = (qt_glXSwapIntervalEXT) getProcAddress("glXSwapIntervalEXT");
518 if (glxExt.contains("GLX_MESA_swap_control"))
519 glXSwapIntervalMESA = (qt_glXSwapIntervalMESA) getProcAddress("glXSwapIntervalMESA");
520 }
521 if (glXSwapIntervalEXT)
522 glXSwapIntervalEXT(m_display, glxDrawable, interval);
523 else if (glXSwapIntervalMESA)
524 glXSwapIntervalMESA(interval);
525 window->setSwapInterval(interval);
526 }
527 }
528
529 return success;
530}
531
533{
534 if (m_isPBufferCurrent)
535 glXMakeContextCurrent(m_display, 0, 0, nullptr);
536 else
537 glXMakeCurrent(m_display, 0, nullptr);
538 m_isPBufferCurrent = false;
539}
540
542{
543 GLXDrawable glxDrawable = 0;
544 if (surface->surface()->surfaceClass() == QSurface::Offscreen)
545 glxDrawable = static_cast<QGLXPbuffer *>(surface)->pbuffer();
546 else
547 glxDrawable = static_cast<QXcbWindow *>(surface)->xcb_window();
548 glXSwapBuffers(m_display, glxDrawable);
549
550 if (surface->surface()->surfaceClass() == QSurface::Window) {
551 QXcbWindow *platformWindow = static_cast<QXcbWindow *>(surface);
552 // OpenGL context might be bound to a non-gui thread use QueuedConnection to sync
553 // the window from the platformWindow's thread as QXcbWindow is no QObject, an
554 // event is sent to QXcbConnection. (this is faster than a metacall)
555 if (platformWindow->needsSync())
556 platformWindow->postSyncWindowRequest();
557 }
558}
559
560QFunctionPointer QGLXContext::getProcAddress(const char *procName)
561{
562 return glXGetProcAddress(reinterpret_cast<const GLubyte *>(procName));
563}
564
566{
567 return m_format;
568}
569
571{
572 return m_shareContext != nullptr;
573}
574
576{
577 return m_context != nullptr && !m_lost;
578}
579
580bool QGLXContext::m_queriedDummyContext = false;
581bool QGLXContext::m_supportsThreading = true;
582
583
584// If this list grows to any significant size, change it a
585// proper string table and make the implementation below use
586// binary search.
588 "Chromium", // QTBUG-32225 (initialization fails)
589 nullptr
590};
591
592static const char *qglx_threadedgl_blacklist_vendor[] = {
593 "llvmpipe", // QTCREATORBUG-10666
594 "nouveau", // https://bugs.freedesktop.org/show_bug.cgi?id=91632
595 nullptr
596};
597
599{
600 if (m_queriedDummyContext)
601 return;
602 m_queriedDummyContext = true;
603
604 static bool skip = qEnvironmentVariableIsSet("QT_OPENGL_NO_SANITY_CHECK");
605 if (skip)
606 return;
607
609 QSurface *oldSurface = nullptr;
610 if (oldContext)
611 oldSurface = oldContext->surface();
612
613 QScopedPointer<QSurface> surface;
614 Display *display = glXGetCurrentDisplay();
615 if (!display) {
616 // FIXME: Since Qt 5.6 we don't need to check whether primary screen is NULL
618 QXcbScreen *xcbScreen = static_cast<QXcbScreen *>(screen->handle());
619 display = static_cast<Display *>(xcbScreen->connection()->xlib_display());
620 }
621 }
622 const char *glxvendor = glXGetClientString(display, GLX_VENDOR);
623 if (glxvendor && !strcmp(glxvendor, "ATI")) {
624 QWindow *window = new QWindow;
625 window->resize(64, 64);
626 window->setSurfaceType(QSurface::OpenGLSurface);
627 window->create();
628 surface.reset(window);
629 } else {
630 QOffscreenSurface *offSurface = new QOffscreenSurface;
631 offSurface->create();
632 surface.reset(offSurface);
633 }
634
636 if (!context.create() || !context.makeCurrent(surface.data())) {
637 qWarning("QGLXContext: Failed to create dummy context");
638 m_supportsThreading = false;
639 return;
640 }
641
642 m_supportsThreading = true;
643
644 if (const char *renderer = (const char *) glGetString(GL_RENDERER)) {
645 for (int i = 0; qglx_threadedgl_blacklist_renderer[i]; ++i) {
646 if (strstr(renderer, qglx_threadedgl_blacklist_renderer[i]) != nullptr) {
647 qCDebug(lcQpaGl).nospace() << "Multithreaded OpenGL disabled: "
648 "blacklisted renderer \""
650 << "\"";
651 m_supportsThreading = false;
652 break;
653 }
654 }
655 }
656 if (const char *vendor = (const char *) glGetString(GL_VENDOR)) {
657 for (int i = 0; qglx_threadedgl_blacklist_vendor[i]; ++i) {
658 if (strstr(vendor, qglx_threadedgl_blacklist_vendor[i]) != nullptr) {
659 qCDebug(lcQpaGl).nospace() << "Multithreaded OpenGL disabled: "
660 "blacklisted vendor \""
662 << "\"";
663 m_supportsThreading = false;
664 break;
665 }
666 }
667 }
668
669 if (glxvendor && m_supportsThreading) {
670 // Blacklist Mesa drivers due to QTCREATORBUG-10875 (crash in creator),
671 // QTBUG-34492 (flickering in fullscreen) and QTBUG-38221
672 const char *mesaVersionStr = nullptr;
673 if (strstr(glxvendor, "Mesa Project") != nullptr) {
674 mesaVersionStr = (const char *) glGetString(GL_VERSION);
675 m_supportsThreading = false;
676 }
677
678 if (mesaVersionStr) {
679 // The issue was fixed in Xcb 1.11, but we can't check for that
680 // at runtime, so instead assume it fixed with recent Mesa versions
681 // released several years after the Xcb fix.
682#if QT_CONFIG(regularexpression)
683 QRegularExpression versionTest(QStringLiteral("Mesa (\\d+)"));
684 QRegularExpressionMatch result = versionTest.match(QString::fromLatin1(mesaVersionStr));
685 int versionNr = 0;
686 if (result.hasMatch())
687 versionNr = result.captured(1).toInt();
688 if (versionNr >= 17) {
689 // White-listed
690 m_supportsThreading = true;
691 }
692#endif
693 }
694 if (!m_supportsThreading) {
695 qCDebug(lcQpaGl).nospace() << "Multithreaded OpenGL disabled: "
696 "blacklisted vendor \"Mesa Project\"";
697 }
698 }
699
700 static bool nomultithread = qEnvironmentVariableIsSet("QT_XCB_NO_THREADED_OPENGL");
701 if (nomultithread)
702 m_supportsThreading = false;
703
705 if (oldContext && oldSurface)
706 oldContext->makeCurrent(oldSurface);
707
708 if (!m_supportsThreading) {
709 qCDebug(lcQpaGl) << "Force-enable multithreaded OpenGL by setting "
710 "environment variable QT_OPENGL_NO_SANITY_CHECK";
711 }
712}
713
715{
717 return m_supportsThreading;
718}
719
721 : QPlatformOffscreenSurface(offscreenSurface)
722 , m_screen(static_cast<QXcbScreen *>(offscreenSurface->screen()->handle()))
723 , m_format(m_screen->surfaceFormatFor(offscreenSurface->requestedFormat()))
724 , m_display(static_cast<Display *>(m_screen->connection()->xlib_display()))
725 , m_pbuffer(0)
726{
727 GLXFBConfig config = qglx_findConfig(m_display, m_screen->screenNumber(), m_format);
728
729 if (config) {
730 const int attributes[] = {
731 GLX_PBUFFER_WIDTH, offscreenSurface->size().width(),
732 GLX_PBUFFER_HEIGHT, offscreenSurface->size().height(),
733 GLX_LARGEST_PBUFFER, False,
734 GLX_PRESERVED_CONTENTS, False,
735 None
736 };
737
738 m_pbuffer = glXCreatePbuffer(m_display, config, attributes);
739
740 if (m_pbuffer)
741 qglx_surfaceFormatFromGLXFBConfig(&m_format, m_display, config);
742 }
743}
744
746{
747 if (m_pbuffer)
748 glXDestroyPbuffer(m_display, m_pbuffer);
749}
750
751
\inmodule QtCore
\inmodule QtCore
Definition qbytearray.h:57
bool makeCurrent(QPlatformSurface *surface) override
QSurfaceFormat format() const override
QGLXContext(Display *display, QXcbScreen *screen, const QSurfaceFormat &format, QPlatformOpenGLContext *share)
static bool supportsThreading()
bool isValid() const override
void swapBuffers(QPlatformSurface *surface) override
Reimplement in subclass to native swap buffers calls.
static void queryDummyContext()
void doneCurrent() override
QFunctionPointer getProcAddress(const char *procName) override
Reimplement in subclass to allow dynamic querying of OpenGL symbols.
bool isSharing() const override
GLXContext glxContext() const
QGLXPbuffer(QOffscreenSurface *offscreenSurface)
GLXPbuffer pbuffer() const
QScreen * primaryScreen
the primary (or default) screen of the application.
\inmodule QtGui
void create()
Allocates the platform resources associated with the offscreen surface.
QSize size() const override
Returns the size of the offscreen surface.
\inmodule QtGui
bool create()
Attempts to create the OpenGL context with the current configuration.
bool makeCurrent(QSurface *surface)
Makes the context current in the current thread, against the given surface.
static OpenGLModuleType openGLModuleType()
Returns the underlying OpenGL implementation type.
static QOpenGLContext * currentContext()
Returns the last context which called makeCurrent in the current thread, or \nullptr,...
void doneCurrent()
Convenience function for calling makeCurrent with a 0 surface.
QOffscreenSurface * offscreenSurface() const
The QPlatformOpenGLContext class provides an abstraction for native GL contexts.
QOpenGLContext * context() const
static bool parseOpenGLVersion(const QByteArray &versionString, int &major, int &minor)
The QPlatformSurface class provides an abstraction for a surface.
QSurface * surface() const
virtual QSurfaceFormat format() const =0
\inmodule QtCore \reentrant
QString captured(int nth=0) const
Returns the substring captured by the nth capturing group.
\inmodule QtCore \reentrant
The QScreen class is used to query screen properties. \inmodule QtGui.
Definition qscreen.h:32
QPlatformScreen * handle() const
Get the platform screen handle.
Definition qscreen.cpp:83
constexpr int height() const noexcept
Returns the height.
Definition qsize.h:133
constexpr int width() const noexcept
Returns the width.
Definition qsize.h:130
int toInt(bool *ok=nullptr, int base=10) const
Returns the string converted to an int using base base, which is 10 by default and must be between 2 ...
Definition qstring.h:731
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5871
The QSurfaceFormat class represents the format of a QSurface. \inmodule QtGui.
int minorVersion() const
Returns the minor OpenGL version.
void setRenderableType(RenderableType type)
Sets the desired renderable type.
void setOptions(QSurfaceFormat::FormatOptions options)
OpenGLContextProfile profile() const
Get the configured OpenGL context profile.
int majorVersion() const
Returns the major OpenGL version.
RenderableType renderableType() const
Gets the renderable type.
void setOption(FormatOption option, bool on=true)
bool testOption(FormatOption option) const
\inmodule QtGui
Definition qsurface.h:21
SurfaceClass surfaceClass() const
Returns the surface class of this surface.
Definition qsurface.cpp:121
bool supportsOpenGL() const
Returns true if the surface is OpenGL compatible and can be used in conjunction with QOpenGLContext; ...
Definition qsurface.cpp:70
@ OpenGLSurface
Definition qsurface.h:32
SurfaceClass
The SurfaceClass enum describes the actual subclass of the surface.
Definition qsurface.h:24
@ Offscreen
Definition qsurface.h:26
\inmodule QtGui
Definition qwindow.h:63
QXcbConnection * connection() const
Definition qxcbobject.h:17
int screenNumber() const
Definition qxcbscreen.h:149
void postSyncWindowRequest()
bool needsSync() const
[Window class with invokable method]
Definition window.h:11
struct wl_display * display
Definition linuxdmabuf.h:41
Combined button and popup list for selecting options.
static void * context
#define Q_UNLIKELY(x)
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char return DBusMessage dbus_bool_t return DBusMessage dbus_uint32_t return DBusMessage void
DBusConnection * connection
typedef QByteArray(EGLAPIENTRYP PFNQGSGETDISPLAYSPROC)()
#define GL_CONTEXT_PROFILE_MASK
#define GL_CONTEXT_COMPATIBILITY_PROFILE_BIT
#define GL_CONTEXT_CORE_PROFILE_BIT
#define GL_CONTEXT_FLAGS
#define GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT
EGLConfig config
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
void qglx_surfaceFormatFromGLXFBConfig(QSurfaceFormat *format, Display *display, GLXFBConfig config, int flags)
void qglx_surfaceFormatFromVisualInfo(QSurfaceFormat *format, Display *display, XVisualInfo *visualInfo, int flags)
GLXFBConfig qglx_findConfig(Display *display, int screen, QSurfaceFormat format, bool highestPixelFormat, int drawableBit, int flags)
XVisualInfo * qglx_findVisualInfo(Display *display, int screen, QSurfaceFormat *format, int drawableBit, int flags)
#define GL_RESET_NOTIFICATION_STRATEGY_ARB
#define GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB
const GLubyte *(* glGetStringiProc)(GLenum, GLuint)
static Window createDummyWindow(Display *dpy, XVisualInfo *visualInfo, int screenNumber, Window rootWin)
#define GLX_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV
static void updateFormatFromContext(QSurfaceFormat &format)
QT_BEGIN_NAMESPACE typedef GLXContext(* glXCreateContextAttribsARBProc)(Display *, GLXFBConfig, GLXContext, Bool, const int *)
static QByteArray getGlString(GLenum param)
static const char * qglx_threadedgl_blacklist_vendor[]
static bool hasGlExtension(const QSurfaceFormat &format, const char *ext)
#define GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB
static QXcbScreen * screenForPlatformSurface(QPlatformSurface *surface)
#define GL_LOSE_CONTEXT_ON_RESET_ARB
#define GLX_CONTEXT_PROFILE_MASK_ARB
static const char * qglx_threadedgl_blacklist_renderer[]
#define GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB
#define GL_CONTEXT_FLAG_DEBUG_BIT
#define GLX_CONTEXT_CORE_PROFILE_BIT_ARB
#define GLX_CONTEXT_ES2_PROFILE_BIT_EXT
#define GLX_LOSE_CONTEXT_ON_RESET_ARB
@ None
Definition qhash.cpp:531
#define qWarning
Definition qlogging.h:166
#define qFatal
Definition qlogging.h:168
#define qCDebug(category,...)
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
#define QOPENGLF_APIENTRYP
Definition qopengl.h:275
typedef GLint(GL_APIENTRYP PFNGLGETPROGRAMRESOURCELOCATIONINDEXEXTPROC)(GLuint program
GLuint64 GLenum void * handle
GLboolean GLboolean GLboolean GLboolean a
[7]
typedef GLenum(GL_APIENTRYP PFNGLGETGRAPHICSRESETSTATUSKHRPROC)(void)
GLbitfield flags
GLenum const GLint * param
GLfloat n
GLint GLsizei GLsizei GLenum format
GLdouble s
[6]
Definition qopenglext.h:235
const void * getProcAddress
GLuint64EXT * result
[6]
GLfloat GLfloat p
[1]
const GLint * attribs
#define GL_NUM_EXTENSIONS
Definition qopenglext.h:906
QT_BEGIN_NAMESPACE constexpr decltype(auto) qMakePair(T1 &&value1, T2 &&value2) noexcept(noexcept(std::make_pair(std::forward< T1 >(value1), std::forward< T2 >(value2))))
Definition qpair.h:19
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define GLuint
#define QStringLiteral(str)
@ Success
Definition main.cpp:3325
QScreen * screen
[1]
Definition main.cpp:29
Q_CORE_EXPORT bool qEnvironmentVariableIsSet(const char *varName) noexcept
struct _XDisplay Display
static xcb_window_t xcb_window(QPlatformWindow *w)
Definition qxcbdrag.cpp:35
XID Colormap
aWidget window() -> setWindowTitle("New Window Title")
[2]
QSvgRenderer * renderer
[0]