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