Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qopenglcontext.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// Qt-Security score:significant reason:default
4
5#include <qpa/qplatformopenglcontext.h>
6#include <qpa/qplatformintegration.h>
9#include "qwindow.h"
10
11#include <QtCore/QThreadStorage>
12#include <QtCore/QThread>
13#include <QtCore/private/qlocking_p.h>
14
15#include <QtGui/private/qguiapplication_p.h>
16#include <QtGui/private/qopengl_p.h>
17#include <QtGui/private/qwindow_p.h>
18#include <QtGui/QScreen>
19#include <qpa/qplatformnativeinterface.h>
20
21#include <private/qopenglextensions_p.h>
22
23#include <QDebug>
24
26
28{
29public:
31 : context(nullptr)
32 {
33 }
35 if (context)
36 context->doneCurrent();
37 }
38 QOpenGLContext *context;
39};
40
42static QOpenGLContext *global_share_context = nullptr;
43
44#ifndef QT_NO_DEBUG
45QHash<QOpenGLContext *, bool> QOpenGLContextPrivate::makeCurrentTracker;
46Q_CONSTINIT QMutex QOpenGLContextPrivate::makeCurrentTrackerMutex;
47#endif
48
49/*!
50 \internal
51
52 This function is used by Qt::AA_ShareOpenGLContexts and the Qt
53 WebEngine to set up context sharing across multiple windows. Do
54 not use it for any other purpose.
55
56 Please maintain the binary compatibility of these functions.
57*/
58void qt_gl_set_global_share_context(QOpenGLContext *context)
59{
60 global_share_context = context;
61}
62
63/*!
64 \internal
65*/
67{
69}
70
71/*!
72 \class QOpenGLContext
73 \ingroup painting-3D
74 \inmodule QtGui
75 \since 5.0
76 \brief The QOpenGLContext class represents a native OpenGL context, enabling
77 OpenGL rendering on a QSurface.
78
79 QOpenGLContext represents the OpenGL state of an underlying OpenGL context.
80 To set up a context, set its screen and format such that they match those
81 of the surface or surfaces with which the context is meant to be used, if
82 necessary make it share resources with other contexts with
83 setShareContext(), and finally call create(). Use the return value or isValid()
84 to check if the context was successfully initialized.
85
86 A context can be made current against a given surface by calling
87 makeCurrent(). When OpenGL rendering is done, call swapBuffers() to swap
88 the front and back buffers of the surface, so that the newly rendered
89 content becomes visible. To be able to support certain platforms,
90 QOpenGLContext requires that you call makeCurrent() again before starting
91 rendering a new frame, after calling swapBuffers().
92
93 If the context is temporarily not needed, such as when the application is
94 not rendering, it can be useful to delete it in order to free resources.
95 You can connect to the aboutToBeDestroyed() signal to clean up any
96 resources that have been allocated with different ownership from the
97 QOpenGLContext itself.
98
99 Once a QOpenGLContext has been made current, you can render to it in a
100 platform independent way by using Qt's OpenGL enablers such as
101 QOpenGLFunctions, QOpenGLBuffer, QOpenGLShaderProgram, and
102 QOpenGLFramebufferObject. It is also possible to use the platform's OpenGL
103 API directly, without using the Qt enablers, although potentially at the
104 cost of portability. The latter is necessary when wanting to use OpenGL 1.x
105 or OpenGL ES 1.x.
106
107 For more information about the OpenGL API, refer to the official
108 \l{http://www.opengl.org}{OpenGL documentation}.
109
110 For an example of how to use QOpenGLContext see the
111 \l{OpenGL Window Example}{OpenGL Window} example.
112
113 \section1 Thread Affinity
114
115 QOpenGLContext can be moved to a different thread with moveToThread(). Do
116 not call makeCurrent() from a different thread than the one to which the
117 QOpenGLContext object belongs. A context can only be current in one thread
118 and against one surface at a time, and a thread only has one context
119 current at a time.
120
121 \section1 Context Resource Sharing
122
123 Resources such as textures and vertex buffer objects
124 can be shared between contexts. Use setShareContext() before calling
125 create() to specify that the contexts should share these resources.
126 QOpenGLContext internally keeps track of a QOpenGLContextGroup object which
127 can be accessed with shareGroup(), and which can be used to find all the
128 contexts in a given share group. A share group consists of all contexts that
129 have been successfully initialized and are sharing with an existing context in
130 the share group. A non-sharing context has a share group consisting of a
131 single context.
132
133 \section1 Default Framebuffer
134
135 On certain platforms, a framebuffer other than 0 might be the default frame
136 buffer depending on the current surface. Instead of calling
137 glBindFramebuffer(0), it is recommended that you use
138 glBindFramebuffer(ctx->defaultFramebufferObject()), to ensure that your
139 application is portable between different platforms. However, if you use
140 QOpenGLFunctions::glBindFramebuffer(), this is done automatically for you.
141
142 \warning WebAssembly
143
144 We recommend that only one QOpenGLContext is made current with a QSurface,
145 for the entire lifetime of the QSurface. Should more than once context be used,
146 it is important to understand that multiple QOpenGLContext instances may be
147 backed by the same native context underneath with the WebAssembly platform.
148 Therefore, calling makeCurrent() with the same QSurface on two QOpenGLContext
149 objects may not switch to a different native context in the second call. As
150 a result, any OpenGL state changes done after the second makeCurrent() may
151 alter the state of the first QOpenGLContext as well, as they are all backed
152 by the same native context.
153
154 \note This means that when targeting WebAssembly with existing OpenGL-based
155 Qt code, some porting may be required to cater to these limitations.
156
157 \section1 Security Considerations
158
159 All data consumed by QOpenGLContext and the classes building on it, such as
160 QOpenGLFunctions, the QtOpenGL module classes, and QRhi with its OpenGL
161 backend, is expected to be trusted content. This includes shader source
162 code, vertex and index data, textures and other pixel data, and all
163 parameters passed to OpenGL functions. Qt does not validate or sanitize any
164 of it.
165
166 Note also that getProcAddress() returns a raw function pointer resolved by
167 name from the OpenGL implementation. Qt cannot check that the signature the
168 caller casts it to matches the one the implementation provides; getting this
169 wrong results in undefined behavior.
170
171 The OpenGL implementation, meaning the driver and, on platforms that have
172 one, the library that dispatches to it, is a trusted, in-process platform
173 dependency. Qt loads it and calls into it directly, without any sandboxing
174 or verification, in the same way as it treats the Vulkan implementation.
175
176 Which library is loaded is decided by the platform's ordinary shared library
177 search order and, on some platforms, by environment variables. That
178 selection is part of the deployment's trusted configuration: a deployment
179 that does not control it does not control which native code runs inside the
180 process.
181
182 \warning Application developers are advised to carefully consider the
183 potential implications before allowing the feeding of user-provided content
184 that is not part of the application and is not under the developers'
185 control.
186
187 \sa QOpenGLFunctions, QOpenGLBuffer, QOpenGLShaderProgram, QOpenGLFramebufferObject
188*/
189
190/*!
191 \internal
192
193 Set the current context. Returns the previously current context.
194*/
195QOpenGLContext *QOpenGLContextPrivate::setCurrentContext(QOpenGLContext *context)
196{
197 QGuiGLThreadContext *threadContext = qwindow_context_storage()->localData();
198 if (!threadContext) {
199 if (!context)
200 return nullptr;
201
202 threadContext = new QGuiGLThreadContext;
203 qwindow_context_storage()->setLocalData(threadContext);
204 }
205 QOpenGLContext *previous = threadContext->context;
206 threadContext->context = context;
207 return previous;
208}
209
210int QOpenGLContextPrivate::maxTextureSize()
211{
212 if (max_texture_size != -1)
213 return max_texture_size;
214
215 Q_Q(QOpenGLContext);
216 QOpenGLFunctions *funcs = q->functions();
217 funcs->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size);
218
219#if !QT_CONFIG(opengles2)
220 if (!q->isOpenGLES()) {
221 GLenum proxy = GL_PROXY_TEXTURE_2D;
222
223 GLint size;
224 GLint next = 64;
225 funcs->glTexImage2D(proxy, 0, GL_RGBA, next, next, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
226
227 QOpenGLExtraFunctions *extraFuncs = q->extraFunctions();
228 extraFuncs->glGetTexLevelParameteriv(proxy, 0, GL_TEXTURE_WIDTH, &size);
229
230 if (size == 0) {
231 return max_texture_size;
232 }
233 do {
234 size = next;
235 next = size * 2;
236
237 if (next > max_texture_size)
238 break;
239 funcs->glTexImage2D(proxy, 0, GL_RGBA, next, next, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
240 extraFuncs->glGetTexLevelParameteriv(proxy, 0, GL_TEXTURE_WIDTH, &next);
241 } while (next > size);
242
243 max_texture_size = size;
244 }
245#endif // QT_CONFIG(opengles2)
246
247 return max_texture_size;
248}
249
250/*!
251 Returns the last context which called makeCurrent in the current thread,
252 or \nullptr, if no context is current.
253*/
254QOpenGLContext* QOpenGLContext::currentContext()
255{
256 QGuiGLThreadContext *threadContext = qwindow_context_storage()->localData();
257 if (threadContext)
258 return threadContext->context;
259 return nullptr;
260}
261
262/*!
263 Returns \c true if the \a first and \a second contexts are sharing OpenGL resources.
264*/
265bool QOpenGLContext::areSharing(QOpenGLContext *first, QOpenGLContext *second)
266{
267 return first->shareGroup() == second->shareGroup();
268}
269
270/*!
271 Returns the underlying platform context.
272
273 \internal
274*/
275QPlatformOpenGLContext *QOpenGLContext::handle() const
276{
277 Q_D(const QOpenGLContext);
278 return d->platformGLContext;
279}
280
281/*!
282 Returns the underlying platform context with which this context is sharing.
283
284 \internal
285*/
286
287QPlatformOpenGLContext *QOpenGLContext::shareHandle() const
288{
289 Q_D(const QOpenGLContext);
290 if (d->shareContext)
291 return d->shareContext->handle();
292 return nullptr;
293}
294
295/*!
296 Creates a new OpenGL context instance with parent object \a parent.
297
298 Before it can be used you need to set the proper format and call create().
299
300 \sa create(), makeCurrent()
301*/
302QOpenGLContext::QOpenGLContext(QObject *parent)
303 : QObject(*new QOpenGLContextPrivate(), parent)
304{
305 setScreen(QGuiApplication::primaryScreen());
306}
307
308/*!
309 Sets the \a format the OpenGL context should be compatible with. You need
310 to call create() before it takes effect.
311
312 When the format is not explicitly set via this function, the format returned
313 by QSurfaceFormat::defaultFormat() will be used. This means that when having
314 multiple contexts, individual calls to this function can be replaced by one
315 single call to QSurfaceFormat::setDefaultFormat() before creating the first
316 context.
317*/
318void QOpenGLContext::setFormat(const QSurfaceFormat &format)
319{
320 Q_D(QOpenGLContext);
321 d->requestedFormat = format;
322}
323
324/*!
325 Makes this context share textures, shaders, and other OpenGL resources
326 with \a shareContext. You need to call create() before it takes effect.
327*/
328void QOpenGLContext::setShareContext(QOpenGLContext *shareContext)
329{
330 Q_D(QOpenGLContext);
331 d->shareContext = shareContext;
332}
333
334/*!
335 Sets the \a screen the OpenGL context should be valid for. You need to call
336 create() before it takes effect.
337*/
338void QOpenGLContext::setScreen(QScreen *screen)
339{
340 Q_D(QOpenGLContext);
341 if (d->screen)
342 disconnect(d->screen, SIGNAL(destroyed(QObject*)), this, SLOT(_q_screenDestroyed(QObject*)));
343 d->screen = screen;
344 if (!d->screen)
345 d->screen = QGuiApplication::primaryScreen();
346 if (d->screen)
347 connect(d->screen, SIGNAL(destroyed(QObject*)), this, SLOT(_q_screenDestroyed(QObject*)));
348}
349
350void QOpenGLContextPrivate::_q_screenDestroyed(QObject *object)
351{
352 Q_Q(QOpenGLContext);
353 if (object == static_cast<QObject *>(screen)) {
354 screen = nullptr;
355 q->setScreen(nullptr);
356 }
357}
358
359/*!
360 \fn template <typename QNativeInterface> QNativeInterface *QOpenGLContext::nativeInterface() const
361
362 Returns a native interface of the given type for the context.
363
364 This function provides access to platform specific functionality
365 of QOpenGLContext, as defined in the QNativeInterface namespace:
366
367 \annotatedlist native-interfaces-qopenglcontext
368
369 If the requested interface is not available a \nullptr is returned.
370 */
371
372/*!
373 Attempts to create the OpenGL context with the current configuration.
374
375 The current configuration includes the format, the share context, and the
376 screen.
377
378 If the OpenGL implementation on your system does not support the requested
379 version of OpenGL context, then QOpenGLContext will try to create the closest
380 matching version. The actual created context properties can be queried
381 using the QSurfaceFormat returned by the format() function. For example, if
382 you request a context that supports OpenGL 4.3 Core profile but the driver
383 and/or hardware only supports version 3.2 Core profile contexts then you will
384 get a 3.2 Core profile context.
385
386 Returns \c true if the native context was successfully created and is ready to
387 be used with makeCurrent(), swapBuffers(), etc.
388
389 \note If the context already exists, this function destroys the existing
390 context first, and then creates a new one.
391
392 \sa makeCurrent(), format()
393*/
394bool QOpenGLContext::create()
395{
396 Q_D(QOpenGLContext);
397 if (d->platformGLContext)
398 destroy();
399
400 auto *platformContext = QGuiApplicationPrivate::platformIntegration()->createPlatformOpenGLContext(this);
401 if (!platformContext)
402 return false;
403
404 d->adopt(platformContext);
405
406 return isValid();
407}
408
409QOpenGLContextPrivate::~QOpenGLContextPrivate()
410{
411}
412
413void QOpenGLContextPrivate::adopt(QPlatformOpenGLContext *context)
414{
415 Q_Q(QOpenGLContext);
416
417 platformGLContext = context;
418 platformGLContext->setContext(q);
419 platformGLContext->initialize();
420
421 if (!platformGLContext->isSharing())
422 shareContext = nullptr;
423 shareGroup = shareContext ? shareContext->shareGroup() : new QOpenGLContextGroup;
424 shareGroup->d_func()->addContext(q);
425}
426
427/*!
428 \internal
429
430 Destroy the underlying platform context associated with this context.
431
432 If any other context is directly or indirectly sharing resources with this
433 context, the shared resources, which includes vertex buffer objects, shader
434 objects, textures, and framebuffer objects, are not freed. However,
435 destroying the underlying platform context frees any state associated with
436 the context.
437
438 After \c destroy() has been called, you must call create() if you wish to
439 use the context again.
440
441 \note This implicitly calls doneCurrent() if the context is current.
442
443 \sa create()
444*/
445void QOpenGLContext::destroy()
446{
447 Q_D(QOpenGLContext);
448
449 // Notify that the native context and the QPlatformOpenGLContext are going
450 // to go away.
451 if (d->platformGLContext)
452 emit aboutToBeDestroyed();
453
454 // Invoke callbacks for helpers and invalidate.
455 if (d->textureFunctionsDestroyCallback) {
456 d->textureFunctionsDestroyCallback();
457 d->textureFunctionsDestroyCallback = nullptr;
458 }
459 d->textureFunctions = nullptr;
460
461 delete d->versionFunctions;
462 d->versionFunctions = nullptr;
463
464 if (d->vaoHelperDestroyCallback) {
465 Q_ASSERT(d->vaoHelper);
466 d->vaoHelperDestroyCallback(d->vaoHelper);
467 d->vaoHelperDestroyCallback = nullptr;
468 }
469 d->vaoHelper = nullptr;
470
471 // Tear down function wrappers.
472 delete d->versionFunctions;
473 d->versionFunctions = nullptr;
474
475 delete d->functions;
476 d->functions = nullptr;
477
478 // Clean up and destroy the native context machinery.
479 if (QOpenGLContext::currentContext() == this)
480 doneCurrent();
481
482 if (d->shareGroup)
483 d->shareGroup->d_func()->removeContext(this);
484
485 d->shareGroup = nullptr;
486
487 delete d->platformGLContext;
488 d->platformGLContext = nullptr;
489}
490
491/*!
492 \fn void QOpenGLContext::aboutToBeDestroyed()
493
494 This signal is emitted before the underlying native OpenGL context is
495 destroyed, such that users may clean up OpenGL resources that might
496 otherwise be left dangling in the case of shared OpenGL contexts.
497
498 If you wish to make the context current in order to do clean-up, make sure
499 to only connect to the signal using a direct connection.
500
501 \note In Qt for Python, this signal will not be received when emitted
502 from the destructor of QOpenGLWidget or QOpenGLWindow due to the Python
503 instance already being destroyed. We recommend doing cleanups
504 in QWidget::hideEvent() instead.
505*/
506
507/*!
508 Destroys the QOpenGLContext object.
509
510 If this is the current context for the thread, doneCurrent() is also called.
511*/
512QOpenGLContext::~QOpenGLContext()
513{
514 destroy();
515
516#ifndef QT_NO_DEBUG
517 QOpenGLContextPrivate::cleanMakeCurrentTracker(this);
518#endif
519}
520
521/*!
522 Returns if this context is valid, i.e. has been successfully created.
523
524 On some platforms the return value of \c false for a context that was
525 successfully created previously indicates that the OpenGL context was lost.
526
527 The typical way to handle context loss scenarios in applications is to
528 check via this function whenever makeCurrent() fails and returns \c false.
529 If this function then returns \c false, recreate the underlying native
530 OpenGL context by calling create(), call makeCurrent() again and then
531 reinitialize all OpenGL resources.
532
533 On some platforms context loss situations is not something that can
534 avoided. On others however, they may need to be opted-in to. This can be
535 done by enabling \l{QSurfaceFormat::ResetNotification}{ResetNotification} in
536 the QSurfaceFormat. This will lead to setting
537 \c{RESET_NOTIFICATION_STRATEGY_EXT} to \c{LOSE_CONTEXT_ON_RESET_EXT} in the
538 underlying native OpenGL context. QOpenGLContext will then monitor the
539 status via \c{glGetGraphicsResetStatusEXT()} in every makeCurrent().
540
541 \sa create()
542*/
543bool QOpenGLContext::isValid() const
544{
545 Q_D(const QOpenGLContext);
546 return d->platformGLContext && d->platformGLContext->isValid();
547}
548
549/*!
550 Get the QOpenGLFunctions instance for this context.
551
552 QOpenGLContext offers this as a convenient way to access QOpenGLFunctions
553 without having to manage it manually.
554
555 The context or a sharing context must be current.
556
557 The returned QOpenGLFunctions instance is ready to be used and it
558 does not need initializeOpenGLFunctions() to be called.
559*/
560QOpenGLFunctions *QOpenGLContext::functions() const
561{
562 Q_D(const QOpenGLContext);
563 if (!d->functions)
564 const_cast<QOpenGLFunctions *&>(d->functions) = new QOpenGLExtensions(QOpenGLContext::currentContext());
565 return d->functions;
566}
567
568/*!
569 Get the QOpenGLExtraFunctions instance for this context.
570
571 QOpenGLContext offers this as a convenient way to access QOpenGLExtraFunctions
572 without having to manage it manually.
573
574 The context or a sharing context must be current.
575
576 The returned QOpenGLExtraFunctions instance is ready to be used and it
577 does not need initializeOpenGLFunctions() to be called.
578
579 \note QOpenGLExtraFunctions contains functionality that is not guaranteed to
580 be available at runtime. Runtime availability depends on the platform,
581 graphics driver, and the OpenGL version requested by the application.
582
583 \sa QOpenGLFunctions, QOpenGLExtraFunctions
584*/
585QOpenGLExtraFunctions *QOpenGLContext::extraFunctions() const
586{
587 return static_cast<QOpenGLExtraFunctions *>(functions());
588}
589
590/*!
591 Returns the set of OpenGL extensions supported by this context.
592
593 The context or a sharing context must be current.
594
595 \sa hasExtension()
596*/
597QSet<QByteArray> QOpenGLContext::extensions() const
598{
599 Q_D(const QOpenGLContext);
600 if (d->extensionNames.isEmpty()) {
601 QOpenGLExtensionMatcher matcher;
602 d->extensionNames = matcher.extensions();
603 }
604
605 return d->extensionNames;
606}
607
608/*!
609 Returns \c true if this OpenGL context supports the specified OpenGL
610 \a extension, \c false otherwise.
611
612 The context or a sharing context must be current.
613
614 \sa extensions()
615*/
616bool QOpenGLContext::hasExtension(const QByteArray &extension) const
617{
618 return extensions().contains(extension);
619}
620
621/*!
622 Call this to get the default framebuffer object for the current surface.
623
624 On some platforms (for instance, iOS) the default framebuffer object depends
625 on the surface being rendered to, and might be different from 0. Thus,
626 instead of calling glBindFramebuffer(0), you should call
627 glBindFramebuffer(ctx->defaultFramebufferObject()) if you want your
628 application to work across different Qt platforms.
629
630 If you use the glBindFramebuffer() in QOpenGLFunctions you do not have to
631 worry about this, as it automatically binds the current context's
632 defaultFramebufferObject() when 0 is passed.
633
634 \note Widgets that render via framebuffer objects, like QOpenGLWidget and
635 QQuickWidget, will override the value returned from this function when
636 painting is active, because at that time the correct "default" framebuffer
637 is the widget's associated backing framebuffer, not the platform-specific
638 one belonging to the top-level window's surface. This ensures the expected
639 behavior for this function and other classes relying on it (for example,
640 QOpenGLFramebufferObject::bindDefault() or
641 QOpenGLFramebufferObject::release()).
642
643 \sa QOpenGLFramebufferObject
644*/
645GLuint QOpenGLContext::defaultFramebufferObject() const
646{
647 if (!isValid())
648 return 0;
649
650 Q_D(const QOpenGLContext);
651 if (!d->surface || !d->surface->surfaceHandle())
652 return 0;
653
654 if (d->defaultFboRedirect)
655 return d->defaultFboRedirect;
656
657 return d->platformGLContext->defaultFramebufferObject(d->surface->surfaceHandle());
658}
659
660/*!
661 Makes the context current in the current thread, against the given
662 \a surface. Returns \c true if successful; otherwise returns \c false.
663 The latter may happen if the surface is not exposed, or the graphics
664 hardware is not available due to e.g. the application being suspended.
665
666 If \a surface is \nullptr this is equivalent to calling doneCurrent().
667
668 Avoid calling this function from a different thread than the one the
669 QOpenGLContext instance lives in. If you wish to use QOpenGLContext from a
670 different thread you should first make sure it's not current in the
671 current thread, by calling doneCurrent() if necessary. Then call
672 moveToThread(otherThread) before using it in the other thread.
673
674 By default Qt employs a check that enforces the above condition on the
675 thread affinity. It is still possible to disable this check by setting the
676 \c{Qt::AA_DontCheckOpenGLContextThreadAffinity} application attribute. Be
677 sure to understand the consequences of using QObjects from outside
678 the thread they live in, as explained in the
679 \l{QObject#Thread Affinity}{QObject thread affinity} documentation.
680
681 \sa functions(), doneCurrent(), Qt::AA_DontCheckOpenGLContextThreadAffinity
682*/
683bool QOpenGLContext::makeCurrent(QSurface *surface)
684{
685 Q_D(QOpenGLContext);
686 if (!isValid())
687 return false;
688
689 if (Q_UNLIKELY(!qApp->testAttribute(Qt::AA_DontCheckOpenGLContextThreadAffinity))) {
690 QThread *thr = thread();
691 if (thr && !thr->isCurrentThread())
692 qFatal("Cannot make QOpenGLContext current in a different thread");
693 }
694
695 if (!surface) {
696 doneCurrent();
697 return true;
698 }
699
700 if (!surface->surfaceHandle())
701 return false;
702 if (!surface->supportsOpenGL()) {
703 qWarning() << "QOpenGLContext::makeCurrent() called with non-opengl surface" << surface;
704 return false;
705 }
706
707 if (!d->platformGLContext->makeCurrent(surface->surfaceHandle()))
708 return false;
709
710 QOpenGLContextPrivate::setCurrentContext(this);
711#ifndef QT_NO_DEBUG
712 QOpenGLContextPrivate::toggleMakeCurrentTracker(this, true);
713#endif
714
715 d->surface = surface;
716
717 static bool needsWorkaroundSet = false;
718 static bool needsWorkaround = false;
719
720 if (!needsWorkaroundSet) {
721 QByteArray env;
722#ifdef Q_OS_ANDROID
723 env = qgetenv(QByteArrayLiteral("QT_ANDROID_DISABLE_GLYPH_CACHE_WORKAROUND"));
724 needsWorkaround = env.isEmpty() || env == QByteArrayLiteral("0") || env == QByteArrayLiteral("false");
725#endif
726 env = qgetenv(QByteArrayLiteral("QT_ENABLE_GLYPH_CACHE_WORKAROUND"));
727 if (env == QByteArrayLiteral("1") || env == QByteArrayLiteral("true"))
728 needsWorkaround = true;
729
730 if (!needsWorkaround) {
731 const char *rendererString = reinterpret_cast<const char *>(functions()->glGetString(GL_RENDERER));
732 if (rendererString)
733 needsWorkaround =
734 qstrncmp(rendererString, "Mali-4xx", 6) == 0 // Mali-400, Mali-450
735 || qstrcmp(rendererString, "Mali-T880") == 0
736 || qstrncmp(rendererString, "Adreno (TM) 2xx", 13) == 0 // Adreno 200, 203, 205
737 || qstrncmp(rendererString, "Adreno 2xx", 8) == 0 // Same as above but without the '(TM)'
738 || qstrncmp(rendererString, "Adreno (TM) 3xx", 13) == 0 // Adreno 302, 305, 320, 330
739 || qstrncmp(rendererString, "Adreno 3xx", 8) == 0 // Same as above but without the '(TM)'
740 || qstrncmp(rendererString, "Adreno (TM) 4xx", 13) == 0 // Adreno 405, 418, 420, 430
741 || qstrncmp(rendererString, "Adreno 4xx", 8) == 0 // Same as above but without the '(TM)'
742 || qstrncmp(rendererString, "Adreno (TM) 5xx", 13) == 0 // Adreno 505, 506, 510, 530, 540
743 || qstrncmp(rendererString, "Adreno 5xx", 8) == 0 // Same as above but without the '(TM)'
744 || qstrncmp(rendererString, "Adreno (TM) 6xx", 13) == 0 // Adreno 610, 620, 630
745 || qstrncmp(rendererString, "Adreno 6xx", 8) == 0 // Same as above but without the '(TM)'
746 || qstrcmp(rendererString, "GC800 core") == 0
747 || qstrcmp(rendererString, "GC1000 core") == 0
748 || strstr(rendererString, "GC2000") != nullptr
749 || qstrcmp(rendererString, "Immersion.16") == 0
750 || qstrncmp(rendererString, "Apple Mx", 7) == 0;
751 }
752 needsWorkaroundSet = true;
753 }
754
755 if (needsWorkaround)
756 d->workaround_brokenFBOReadBack = true;
757
758 d->shareGroup->d_func()->deletePendingResources(this);
759
760 return true;
761}
762
763/*!
764 Convenience function for calling makeCurrent with a 0 surface.
765
766 This results in no context being current in the current thread.
767
768 \sa makeCurrent(), currentContext()
769*/
770void QOpenGLContext::doneCurrent()
771{
772 Q_D(QOpenGLContext);
773
774 if (isValid()) {
775 if (QOpenGLContext::currentContext() == this)
776 d->shareGroup->d_func()->deletePendingResources(this);
777 d->platformGLContext->doneCurrent();
778 }
779
780 QOpenGLContextPrivate::setCurrentContext(nullptr);
781
782 d->surface = nullptr;
783}
784
785/*!
786 Returns the surface the context has been made current with.
787
788 This is the surface passed as an argument to makeCurrent().
789*/
790QSurface *QOpenGLContext::surface() const
791{
792 Q_D(const QOpenGLContext);
793 return d->surface;
794}
795
796
797/*!
798 Swap the back and front buffers of \a surface.
799
800 Call this to finish a frame of OpenGL rendering, and make sure to
801 call makeCurrent() again before issuing any further OpenGL commands,
802 for example as part of a new frame.
803*/
804void QOpenGLContext::swapBuffers(QSurface *surface)
805{
806 Q_D(QOpenGLContext);
807 if (!isValid())
808 return;
809
810 if (!surface) {
811 qWarning("QOpenGLContext::swapBuffers() called with null argument");
812 return;
813 }
814
815 if (!surface->supportsOpenGL()) {
816 qWarning("QOpenGLContext::swapBuffers() called with non-opengl surface");
817 return;
818 }
819
820 QPlatformSurface *surfaceHandle = surface->surfaceHandle();
821 if (!surfaceHandle)
822 return;
823
824#if !defined(QT_NO_DEBUG)
825 if (!QOpenGLContextPrivate::toggleMakeCurrentTracker(this, false))
826 qWarning("QOpenGLContext::swapBuffers() called without corresponding makeCurrent()");
827#endif
828 if (surface->format().swapBehavior() == QSurfaceFormat::SingleBuffer)
829 functions()->glFlush();
830 d->platformGLContext->swapBuffers(surfaceHandle);
831}
832
833/*!
834 Resolves the function pointer to an OpenGL extension function, identified by \a procName.
835
836 Use this function to access OpenGL extension functions or core functions
837 that may not be available as linked symbols on all platforms.
838
839 The returned pointer may be platform-dependent. Some systems may return a
840 pointer that is not \nullptr even if the function is not valid or supported.
841
842 To reliably check function availability, test for extension support by calling
843 \l QOpenGLContext::hasExtension(). For core functions, check the current context's
844 version via \l{QSurfaceFormat::}{version()} in the QSurfaceFormat returned by
845 \l QOpenGLContext::format().
846*/
847QFunctionPointer QOpenGLContext::getProcAddress(const QByteArray &procName) const
848{
849 return getProcAddress(procName.constData());
850}
851
852/*!
853 \overload
854 \since 5.8
855 */
856QFunctionPointer QOpenGLContext::getProcAddress(const char *procName) const
857{
858 Q_D(const QOpenGLContext);
859 if (!d->platformGLContext)
860 return nullptr;
861 return d->platformGLContext->getProcAddress(procName);
862}
863
864/*!
865 Returns the format of the underlying platform context, if create() has been called.
866
867 Otherwise, returns the requested format.
868
869 The requested and the actual format may differ. Requesting a given OpenGL version does
870 not mean the resulting context will target exactly the requested version. It is only
871 guaranteed that the version/profile/options combination for the created context is
872 compatible with the request, as long as the driver is able to provide such a context.
873
874 For example, requesting an OpenGL version 3.x core profile context may result in an
875 OpenGL 4.x core profile context. Similarly, a request for OpenGL 2.1 may result in an
876 OpenGL 3.0 context with deprecated functions enabled. Finally, depending on the
877 driver, unsupported versions may result in either a context creation failure or in a
878 context for the highest supported version.
879
880 Similar differences are possible in the buffer sizes, for example, the resulting
881 context may have a larger depth buffer than requested. This is perfectly normal.
882*/
883QSurfaceFormat QOpenGLContext::format() const
884{
885 Q_D(const QOpenGLContext);
886 if (!d->platformGLContext)
887 return d->requestedFormat;
888 return d->platformGLContext->format();
889}
890
891/*!
892 Returns the share group this context belongs to.
893*/
894QOpenGLContextGroup *QOpenGLContext::shareGroup() const
895{
896 Q_D(const QOpenGLContext);
897 return d->shareGroup;
898}
899
900/*!
901 Returns the share context this context was created with.
902
903 If the underlying platform was not able to support the requested
904 sharing, this will return 0.
905*/
906QOpenGLContext *QOpenGLContext::shareContext() const
907{
908 Q_D(const QOpenGLContext);
909 return d->shareContext;
910}
911
912/*!
913 Returns the screen the context was created for.
914*/
915QScreen *QOpenGLContext::screen() const
916{
917 Q_D(const QOpenGLContext);
918 return d->screen;
919}
920
921/*!
922 \enum QOpenGLContext::OpenGLModuleType
923 This enum defines the type of the underlying OpenGL implementation.
924
925 \value LibGL OpenGL
926 \value LibGLES OpenGL ES 2.0 or higher
927
928 \since 5.3
929*/
930
931/*!
932 Returns the underlying OpenGL implementation type.
933
934 On platforms where the OpenGL implementation is not dynamically
935 loaded, the return value is determined during compile time and never
936 changes.
937
938 \note A desktop OpenGL implementation may be capable of creating
939 ES-compatible contexts too. Therefore in most cases it is more
940 appropriate to check QSurfaceFormat::renderableType() or use
941 the convenience function isOpenGLES().
942
943 \note This function requires that the QGuiApplication instance is already created.
944
945 \since 5.3
946 */
947QOpenGLContext::OpenGLModuleType QOpenGLContext::openGLModuleType()
948{
949#if defined(QT_OPENGL_DYNAMIC)
950 Q_ASSERT(qGuiApp);
951 return QGuiApplicationPrivate::instance()->platformIntegration()->openGLModuleType();
952#elif QT_CONFIG(opengles2)
953 return LibGLES;
954#else
955 return LibGL;
956#endif
957}
958
959/*!
960 Returns true if the context is an OpenGL ES context.
961
962 If the context has not yet been created, the result is based on the
963 requested format set via setFormat().
964
965 \sa create(), format(), setFormat()
966
967 \since 5.3
968 */
969bool QOpenGLContext::isOpenGLES() const
970{
971 return format().renderableType() == QSurfaceFormat::OpenGLES;
972}
973
974/*!
975 Returns \c true if the platform supports OpenGL rendering outside the main (gui)
976 thread.
977
978 The value is controlled by the platform plugin in use and may also depend on the
979 graphics drivers.
980
981 \since 5.5
982 */
983bool QOpenGLContext::supportsThreadedOpenGL()
984{
985 Q_ASSERT(qGuiApp);
986 return QGuiApplicationPrivate::instance()->platformIntegration()->hasCapability(QPlatformIntegration::ThreadedOpenGL);
987}
988
989/*!
990 \since 5.5
991
992 Returns the application-wide shared OpenGL context, if present.
993 Otherwise, returns \nullptr.
994
995 This is useful if you need to upload OpenGL objects (buffers, textures,
996 etc.) before creating or showing a QOpenGLWidget or QQuickWidget.
997
998 \warning Do not attempt to make the context returned by this function
999 current on any surface. Instead, you can create a new context which shares
1000 with the global one, and then make the new context current.
1001
1002 \sa Qt::AA_ShareOpenGLContexts, setShareContext(), makeCurrent()
1003*/
1004QOpenGLContext *QOpenGLContext::globalShareContext()
1005{
1006 Q_ASSERT(qGuiApp);
1007
1008 static QMutex mutex;
1009 QMutexLocker locker(&mutex);
1010
1011 // Lazily create a global share context when enabled unless there is already one
1012 if (!qt_gl_global_share_context() && qGuiApp->testAttribute(Qt::AA_ShareOpenGLContexts)) {
1013 QOpenGLContext *ctx = new QOpenGLContext;
1014 ctx->setFormat(QSurfaceFormat::defaultFormat());
1015 ctx->create();
1016 ctx->moveToThread(qGuiApp->thread());
1017 qt_gl_set_global_share_context(ctx);
1018 QGuiApplicationPrivate::instance()->ownGlobalShareContext = true;
1019 }
1020 return qt_gl_global_share_context();
1021}
1022
1023/*!
1024 \internal
1025*/
1026QOpenGLTextureHelper* QOpenGLContext::textureFunctions() const
1027{
1028 Q_D(const QOpenGLContext);
1029 return d->textureFunctions;
1030}
1031
1032/*!
1033 \internal
1034*/
1035void QOpenGLContext::setTextureFunctions(QOpenGLTextureHelper* textureFuncs, std::function<void()> destroyCallback)
1036{
1037 Q_D(QOpenGLContext);
1038 d->textureFunctions = textureFuncs;
1039 d->textureFunctionsDestroyCallback = destroyCallback;
1040}
1041
1042/*!
1043 \class QOpenGLContextGroup
1044 \since 5.0
1045 \brief The QOpenGLContextGroup class represents a group of contexts sharing
1046 OpenGL resources.
1047 \inmodule QtGui
1048
1049 QOpenGLContextGroup is automatically created and managed by QOpenGLContext
1050 instances. Its purpose is to identify all the contexts that are sharing
1051 resources.
1052
1053 \sa QOpenGLContext::shareGroup()
1054*/
1055QOpenGLContextGroup::QOpenGLContextGroup()
1056 : QObject(*new QOpenGLContextGroupPrivate())
1057{
1058}
1059
1060/*!
1061 \internal
1062*/
1063QOpenGLContextGroup::~QOpenGLContextGroup()
1064{
1065 Q_D(QOpenGLContextGroup);
1066 d->cleanup();
1067}
1068
1069/*!
1070 Returns all the QOpenGLContext objects in this share group.
1071*/
1072QList<QOpenGLContext *> QOpenGLContextGroup::shares() const
1073{
1074 Q_D(const QOpenGLContextGroup);
1075 return d->m_shares;
1076}
1077
1078/*!
1079 Returns the QOpenGLContextGroup corresponding to the current context.
1080
1081 \sa QOpenGLContext::currentContext()
1082*/
1083QOpenGLContextGroup *QOpenGLContextGroup::currentContextGroup()
1084{
1085 QOpenGLContext *current = QOpenGLContext::currentContext();
1086 return current ? current->shareGroup() : nullptr;
1087}
1088
1089QOpenGLContextGroupPrivate::~QOpenGLContextGroupPrivate()
1090 = default;
1091
1092void QOpenGLContextGroupPrivate::addContext(QOpenGLContext *ctx)
1093{
1094 const auto locker = qt_scoped_lock(m_mutex);
1095 m_refs.ref();
1096 m_shares << ctx;
1097}
1098
1099void QOpenGLContextGroupPrivate::removeContext(QOpenGLContext *ctx)
1100{
1101 Q_Q(QOpenGLContextGroup);
1102
1103 bool deleteObject = false;
1104
1105 {
1106 const auto locker = qt_scoped_lock(m_mutex);
1107 m_shares.removeOne(ctx);
1108
1109 if (ctx == m_context && !m_shares.isEmpty())
1110 m_context = m_shares.constFirst();
1111
1112 if (!m_refs.deref()) {
1113 cleanup();
1114 deleteObject = true;
1115 }
1116 }
1117
1118 if (deleteObject)
1119 QObjectPrivate::deleteInOwnThread(q);
1120}
1121
1122void QOpenGLContextGroupPrivate::cleanup()
1123{
1124 Q_Q(QOpenGLContextGroup);
1125 {
1126 QHash<QOpenGLMultiGroupSharedResource *, QOpenGLSharedResource *>::const_iterator it, end;
1127 end = m_resources.constEnd();
1128 for (it = m_resources.constBegin(); it != end; ++it)
1129 it.key()->cleanup(q, it.value());
1130 m_resources.clear();
1131 }
1132
1133 QList<QOpenGLSharedResource *>::iterator it = m_sharedResources.begin();
1134 QList<QOpenGLSharedResource *>::iterator end = m_sharedResources.end();
1135
1136 while (it != end) {
1137 (*it)->invalidateResource();
1138 (*it)->m_group = nullptr;
1139 ++it;
1140 }
1141
1142 m_sharedResources.clear();
1143
1144 qDeleteAll(m_pendingDeletion.begin(), m_pendingDeletion.end());
1145 m_pendingDeletion.clear();
1146}
1147
1148void QOpenGLContextGroupPrivate::deletePendingResources(QOpenGLContext *ctx)
1149{
1150 const auto locker = qt_scoped_lock(m_mutex);
1151
1152 const QList<QOpenGLSharedResource *> pending = m_pendingDeletion;
1153 m_pendingDeletion.clear();
1154
1155 QList<QOpenGLSharedResource *>::const_iterator it = pending.begin();
1156 QList<QOpenGLSharedResource *>::const_iterator end = pending.end();
1157 while (it != end) {
1158 (*it)->freeResource(ctx);
1159 delete *it;
1160 ++it;
1161 }
1162}
1163
1164/*!
1165 \class QOpenGLSharedResource
1166 \internal
1167 \since 5.0
1168 \brief The QOpenGLSharedResource class is used to keep track of resources
1169 that are shared between OpenGL contexts (like textures, framebuffer
1170 objects, shader programs, etc), and clean them up in a safe way when
1171 they're no longer needed.
1172 \inmodule QtGui
1173
1174 The QOpenGLSharedResource instance should never be deleted, instead free()
1175 should be called when it's no longer needed. Thus it will be put on a queue
1176 and freed at an appropriate time (when a context in the share group becomes
1177 current).
1178
1179 The sub-class needs to implement two pure virtual functions. The first,
1180 freeResource() must be implemented to actually do the freeing, for example
1181 call glDeleteTextures() on a texture id. Qt makes sure a valid context in
1182 the resource's share group is current at the time. The other,
1183 invalidateResource(), is called by Qt in the circumstance when the last
1184 context in the share group is destroyed before free() has been called. The
1185 implementation of invalidateResource() should set any identifiers to 0 or
1186 set a flag to prevent them from being used later on.
1187*/
1188QOpenGLSharedResource::QOpenGLSharedResource(QOpenGLContextGroup *group)
1189 : m_group(group)
1190{
1191 const auto locker = qt_scoped_lock(m_group->d_func()->m_mutex);
1192 m_group->d_func()->m_sharedResources << this;
1193}
1194
1195QOpenGLSharedResource::~QOpenGLSharedResource()
1196{
1197}
1198
1199// schedule the resource for deletion at an appropriate time
1200void QOpenGLSharedResource::free()
1201{
1202 if (!m_group) {
1203 delete this;
1204 return;
1205 }
1206
1207 const auto locker = qt_scoped_lock(m_group->d_func()->m_mutex);
1208 m_group->d_func()->m_sharedResources.removeOne(this);
1209 m_group->d_func()->m_pendingDeletion << this;
1210
1211 // can we delete right away?
1212 QOpenGLContext *current = QOpenGLContext::currentContext();
1213 if (current && current->shareGroup() == m_group) {
1214 m_group->d_func()->deletePendingResources(current);
1215 }
1216}
1217
1218/*!
1219 \class QOpenGLSharedResourceGuard
1220 \internal
1221 \since 5.0
1222 \brief The QOpenGLSharedResourceGuard class is a convenience sub-class of
1223 QOpenGLSharedResource to be used to track a single OpenGL object with a
1224 GLuint identifier. The constructor takes a function pointer to a function
1225 that will be used to free the resource if and when necessary.
1226 \inmodule QtGui
1227
1228*/
1229
1230QOpenGLSharedResourceGuard::~QOpenGLSharedResourceGuard()
1231 = default;
1232
1233void QOpenGLSharedResourceGuard::freeResource(QOpenGLContext *context)
1234{
1235 if (m_id) {
1236 QOpenGLFunctions functions(context);
1237 m_func(&functions, m_id);
1238 m_id = 0;
1239 }
1240}
1241
1242/*!
1243 \class QOpenGLMultiGroupSharedResource
1244 \internal
1245 \since 5.0
1246 \brief The QOpenGLMultiGroupSharedResource keeps track of a shared resource
1247 that might be needed from multiple contexts, like a glyph cache or gradient
1248 cache. One instance of the object is created for each group when necessary.
1249 The shared resource instance should have a constructor that takes a
1250 QOpenGLContext *. To get an instance for a given context one calls
1251 T *QOpenGLMultiGroupSharedResource::value<T>(context), where T is a sub-class
1252 of QOpenGLSharedResource.
1253 \inmodule QtGui
1254
1255 You should not call free() on QOpenGLSharedResources owned by a
1256 QOpenGLMultiGroupSharedResource instance.
1257*/
1258QOpenGLMultiGroupSharedResource::QOpenGLMultiGroupSharedResource()
1259 : active(0)
1260{
1261#ifdef QT_GL_CONTEXT_RESOURCE_DEBUG
1262 qDebug("Creating context group resource object %p.", this);
1263#endif
1264}
1265
1266QOpenGLMultiGroupSharedResource::~QOpenGLMultiGroupSharedResource()
1267{
1268#ifdef QT_GL_CONTEXT_RESOURCE_DEBUG
1269 qDebug("Deleting context group resource %p. Group size: %d.", this, m_groups.size());
1270#endif
1271 for (int i = 0; i < m_groups.size(); ++i) {
1272 if (!m_groups.at(i)->shares().isEmpty()) {
1273 QOpenGLContext *context = m_groups.at(i)->shares().constFirst();
1274 QOpenGLSharedResource *resource = value(context);
1275 if (resource)
1276 resource->free();
1277 }
1278 m_groups.at(i)->d_func()->m_resources.remove(this);
1279 active.deref();
1280 }
1281#ifndef QT_NO_DEBUG
1282 if (active.loadRelaxed() != 0) {
1283 qWarning("QtGui: Resources are still available at program shutdown.\n"
1284 " This is possibly caused by a leaked QOpenGLWidget, \n"
1285 " QOpenGLFramebufferObject or QOpenGLPixelBuffer.");
1286 }
1287#endif
1288}
1289
1290void QOpenGLMultiGroupSharedResource::insert(QOpenGLContext *context, QOpenGLSharedResource *value)
1291{
1292#ifdef QT_GL_CONTEXT_RESOURCE_DEBUG
1293 qDebug("Inserting context group resource %p for context %p, managed by %p.", value, context, this);
1294#endif
1295 QOpenGLContextGroup *group = context->shareGroup();
1296 Q_ASSERT(!group->d_func()->m_resources.contains(this));
1297 group->d_func()->m_resources.insert(this, value);
1298 m_groups.append(group);
1299 active.ref();
1300}
1301
1302QOpenGLSharedResource *QOpenGLMultiGroupSharedResource::value(QOpenGLContext *context)
1303{
1304 QOpenGLContextGroup *group = context->shareGroup();
1305 return group->d_func()->m_resources.value(this, nullptr);
1306}
1307
1308QList<QOpenGLSharedResource *> QOpenGLMultiGroupSharedResource::resources() const
1309{
1310 QList<QOpenGLSharedResource *> result;
1311 for (QList<QOpenGLContextGroup *>::const_iterator it = m_groups.constBegin(); it != m_groups.constEnd(); ++it) {
1312 QOpenGLSharedResource *resource = (*it)->d_func()->m_resources.value(const_cast<QOpenGLMultiGroupSharedResource *>(this), nullptr);
1313 if (resource)
1314 result << resource;
1315 }
1316 return result;
1317}
1318
1319void QOpenGLMultiGroupSharedResource::cleanup(QOpenGLContextGroup *group, QOpenGLSharedResource *value)
1320{
1321#ifdef QT_GL_CONTEXT_RESOURCE_DEBUG
1322 qDebug("Cleaning up context group resource %p, for group %p in thread %p.", this, group, QThread::currentThread());
1323#endif
1324 value->invalidateResource();
1325 value->free();
1326 active.deref();
1327
1328 Q_ASSERT(m_groups.contains(group));
1329 m_groups.removeOne(group);
1330}
1331
1332QOpenGLContextVersionFunctionHelper::~QOpenGLContextVersionFunctionHelper()
1333 = default;
1334
1335#ifndef QT_NO_DEBUG_STREAM
1336QDebug operator<<(QDebug debug, const QOpenGLContext *ctx)
1337{
1338 QDebugStateSaver saver(debug);
1339 debug.nospace();
1340 debug.noquote();
1341 debug << "QOpenGLContext(";
1342 if (ctx) {
1343 debug << static_cast<const void *>(ctx);
1344 if (ctx->isValid()) {
1345 debug << ", format=" << ctx->format();
1346 if (const QSurface *sf = ctx->surface())
1347 debug << ", surface=" << sf;
1348 if (const QScreen *s = ctx->screen())
1349 debug << ", screen=\"" << s->name() << '"';
1350 } else {
1351 debug << ", invalid";
1352 }
1353 } else {
1354 debug << "0x0";
1355 }
1356 debug << ')';
1357 return debug;
1358}
1359
1360QDebug operator<<(QDebug debug, const QOpenGLContextGroup *cg)
1361{
1362 QDebugStateSaver saver(debug);
1363 debug.nospace();
1364 debug << "QOpenGLContextGroup(";
1365 if (cg)
1366 debug << cg->shares();
1367 else
1368 debug << "0x0";
1369 debug << ')';
1370 return debug;
1371}
1372#endif // QT_NO_DEBUG_STREAM
1373
1374using namespace QNativeInterface;
1375
1376void *QOpenGLContext::resolveInterface(const char *name, int revision) const
1377{
1378 Q_UNUSED(name); Q_UNUSED(revision);
1379
1380 auto *platformContext = handle();
1381 Q_UNUSED(platformContext);
1382
1383#if defined(Q_OS_MACOS)
1384 QT_NATIVE_INTERFACE_RETURN_IF(QCocoaGLContext, platformContext);
1385#endif
1386#if defined(Q_OS_WIN)
1387 QT_NATIVE_INTERFACE_RETURN_IF(QWGLContext, platformContext);
1388#endif
1389#if QT_CONFIG(xcb_glx_plugin)
1390 QT_NATIVE_INTERFACE_RETURN_IF(QGLXContext, platformContext);
1391#endif
1392#if QT_CONFIG(egl)
1393 QT_NATIVE_INTERFACE_RETURN_IF(QEGLContext, platformContext);
1394#endif
1395
1396 return nullptr;
1397}
1398
1399QT_END_NAMESPACE
1400
1401#include "moc_qopenglcontext.cpp"
QOpenGLContext * context
Combined button and popup list for selecting options.
Q_GLOBAL_STATIC(QReadWriteLock, g_updateMutex)
QOpenGLContext * qt_gl_global_share_context()
void qt_gl_set_global_share_context(QOpenGLContext *context)
static QOpenGLContext * global_share_context