1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtGui module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include <qpa/qplatformopenglcontext.h>
43 #include <qpa/qplatformintegration.h>
44 #include "qopenglcontext.h"
45 #include "qopenglcontext_p.h"
48 #include <QtCore/QThreadStorage>
49 #include <QtCore/QThread>
51 #include <QtGui/private/qguiapplication_p.h>
52 #include <QtGui/private/qopengl_p.h>
53 #include <QtGui/private/qwindow_p.h>
54 #include <QtGui/QScreen>
56 #include <private/qopenglextensions_p.h>
62 class QGuiGLThreadContext
65 ~QGuiGLThreadContext() {
67 context->doneCurrent();
69 QOpenGLContext *context;
72 static QThreadStorage<QGuiGLThreadContext *> qwindow_context_storage;
75 QHash<QOpenGLContext *, bool> QOpenGLContextPrivate::makeCurrentTracker;
76 QMutex QOpenGLContextPrivate::makeCurrentTrackerMutex;
83 \brief The QOpenGLContext class represents a native OpenGL context, enabling
84 OpenGL rendering on a QSurface.
86 QOpenGLContext represents the OpenGL state of an underlying OpenGL context.
87 To set up a context, set its screen and format such that they match those
88 of the surface or surfaces with which the context is meant to be used, if
89 necessary make it share resources with other contexts with
90 setShareContext(), and finally call create(). Use isValid() to check if the
91 context was successfully initialized.
93 A context can be made current against a given surface by calling
94 makeCurrent(). When OpenGL rendering is done, call swapBuffers() to swap
95 the front and back buffers of the surface, so that the newly rendered
96 content becomes visible. To be able to support certain platforms,
97 QOpenGLContext requires that you call makeCurrent() again before starting
98 rendering a new frame, after calling swapBuffers().
100 If the context is temporarily not needed, such as when the application is
101 not rendering, it can be useful to call destroy() to free resources.
102 However, if you do so you will need to call create() again before the
103 context can be used, and you might need to recreate any OpenGL resources
104 and reinitialize the OpenGL state. You can connect to the
105 aboutToBeDestroyed() signal to clean up any resources that have been
106 allocated with different ownership from the QOpenGLContext itself.
108 Once a QOpenGLContext has been made current, you can render to it in a
109 platform independent way by using Qt's OpenGL enablers such as
110 QOpenGLFunctions, QOpenGLBuffer, QOpenGLShaderProgram, and
111 QOpenGLFramebufferObject. It is also possible to use the platform's OpenGL
112 API directly, without using the Qt enablers, although potentially at the
113 cost of portability. The latter is necessary when wanting to use OpenGL 1.x
116 For more information about the OpenGL API, refer to the official
117 \l{OpenGL documentation}.
119 \section1 Thread affinity
121 QOpenGLContext can be moved to a different thread with moveToThread(). Do
122 not call makeCurrent() from a different thread than the one to which the
123 QOpenGLContext object belongs. A context can only be current in one thread
124 and against one surface at a time, and a thread only has one context
127 \section1 Context resource sharing
129 Resources, such as framebuffer objects, textures, and vertex buffer objects
130 can be shared between contexts. Use setShareContext() before calling
131 create() to specify that the contexts should share these resources.
132 QOpenGLContext internally keeps track of a QOpenGLContextGroup object which
133 can be accessed with shareGroup(), and which can be used to find all the
134 contexts in a given share group. A share group consists of all contexts that
135 have been successfully initialized and are sharing with an existing context in
136 the share group. A non-sharing context has a share group consisting of a
139 \section1 Default framebuffer
141 On certain platforms, a framebuffer other than 0 might be the default frame
142 buffer depending on the current surface. Instead of calling
143 glBindFramebuffer(0), it is recommended that you use
144 glBindFramebuffer(ctx->defaultFramebufferObject()), to ensure that your
145 application is portable between different platforms. However, if you use
146 QOpenGLFunctions::glBindFramebuffer(), this is done automatically for you.
148 \sa QOpenGLFunctions, QOpenGLBuffer, QOpenGLShaderProgram, QOpenGLFramebufferObject
151 void QOpenGLContextPrivate::setCurrentContext(QOpenGLContext *context)
153 QGuiGLThreadContext *threadContext = qwindow_context_storage.localData();
154 if (!threadContext) {
155 if (!QThread::currentThread()) {
156 qWarning("No QTLS available. currentContext wont work");
159 threadContext = new QGuiGLThreadContext;
160 qwindow_context_storage.setLocalData(threadContext);
162 threadContext->context = context;
165 int QOpenGLContextPrivate::maxTextureSize()
167 if (max_texture_size != -1)
168 return max_texture_size;
170 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size);
172 #if defined(QT_OPENGL_ES)
173 return max_texture_size;
175 GLenum proxy = GL_PROXY_TEXTURE_2D;
179 glTexImage2D(proxy, 0, GL_RGBA, next, next, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
180 glGetTexLevelParameteriv(proxy, 0, GL_TEXTURE_WIDTH, &size);
182 return max_texture_size;
188 if (next > max_texture_size)
190 glTexImage2D(proxy, 0, GL_RGBA, next, next, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
191 glGetTexLevelParameteriv(proxy, 0, GL_TEXTURE_WIDTH, &next);
192 } while (next > size);
194 max_texture_size = size;
195 return max_texture_size;
200 Returns the last context which called makeCurrent in the current thread,
201 or 0, if no context is current.
203 QOpenGLContext* QOpenGLContext::currentContext()
205 QGuiGLThreadContext *threadContext = qwindow_context_storage.localData();
207 return threadContext->context;
213 Returns true if the \a first and \a second contexts are sharing OpenGL resources.
215 bool QOpenGLContext::areSharing(QOpenGLContext *first, QOpenGLContext *second)
217 return first->shareGroup() == second->shareGroup();
221 Returns the underlying platform context.
225 QPlatformOpenGLContext *QOpenGLContext::handle() const
227 Q_D(const QOpenGLContext);
228 return d->platformGLContext;
232 Returns the underlying platform context with which this context is sharing.
237 QPlatformOpenGLContext *QOpenGLContext::shareHandle() const
239 Q_D(const QOpenGLContext);
241 return d->shareContext->handle();
246 Creates a new OpenGL context instance with parent object \a parent.
248 Before it can be used you need to set the proper format and call create().
250 \sa create(), makeCurrent()
252 QOpenGLContext::QOpenGLContext(QObject *parent)
253 : QObject(*new QOpenGLContextPrivate(), parent)
256 d->screen = QGuiApplication::primaryScreen();
260 Sets the \a format the OpenGL context should be compatible with. You need
261 to call create() before it takes effect.
263 void QOpenGLContext::setFormat(const QSurfaceFormat &format)
266 d->requestedFormat = format;
270 Makes this context share textures, shaders, and other OpenGL resources
271 with \a shareContext. You need to call create() before it takes effect.
273 void QOpenGLContext::setShareContext(QOpenGLContext *shareContext)
276 d->shareContext = shareContext;
280 Sets the \a screen the OpenGL context should be valid for. You need to call
281 create() before it takes effect.
283 void QOpenGLContext::setScreen(QScreen *screen)
288 d->screen = QGuiApplication::primaryScreen();
292 Attempts to create the OpenGL context with the current configuration.
294 The current configuration includes the format, the share context, and the
297 Returns true if the native context was successfully created and is ready to
298 be used with makeCurrent(), swapBuffers(), etc.
300 \sa makeCurrent(), destroy()
302 bool QOpenGLContext::create()
307 d->platformGLContext = QGuiApplicationPrivate::platformIntegration()->createPlatformOpenGLContext(this);
308 if (!d->platformGLContext)
310 d->platformGLContext->setContext(this);
311 if (!d->platformGLContext->isSharing())
313 d->shareGroup = d->shareContext ? d->shareContext->shareGroup() : new QOpenGLContextGroup;
314 d->shareGroup->d_func()->addContext(this);
315 return d->platformGLContext;
319 Destroy the underlying platform context associated with this context.
321 If any other context is directly or indirectly sharing resources with this
322 context, the shared resources, which includes vertex buffer objects, shader
323 objects, textures, and framebuffer objects, are not freed. However,
324 destroying the underlying platform context frees any state associated with
327 After destroy() has been called, you must call create() if you wish to
328 use the context again.
330 \note This implicitly calls doneCurrent() if the context is current.
334 void QOpenGLContext::destroy()
337 if (d->platformGLContext)
338 emit aboutToBeDestroyed();
339 if (QOpenGLContext::currentContext() == this)
342 d->shareGroup->d_func()->removeContext(this);
344 delete d->platformGLContext;
345 d->platformGLContext = 0;
351 \fn void QOpenGLContext::aboutToBeDestroyed()
353 This signal is emitted before the underlying native OpenGL context is
354 destroyed, such that users may clean up OpenGL resources that might
355 otherwise be left dangling in the case of shared OpenGL contexts.
357 If you wish to make the context current in order to do clean-up, make sure
358 to only connect to the signal using a direct connection.
362 Destroys the QOpenGLContext object.
364 This implicitly calls destroy(), so if this is the current context for the
365 thread, doneCurrent() is also called.
369 QOpenGLContext::~QOpenGLContext()
374 QOpenGLContextPrivate::cleanMakeCurrentTracker(this);
379 Returns if this context is valid, i.e. has been successfully created.
383 bool QOpenGLContext::isValid() const
385 Q_D(const QOpenGLContext);
386 return d->platformGLContext && d->platformGLContext->isValid();
390 Get the QOpenGLFunctions instance for this context.
392 QOpenGLContext offers this as a convenient way to access QOpenGLFunctions
393 without having to manage it manually.
395 The context or a sharing context must be current.
397 QOpenGLFunctions *QOpenGLContext::functions() const
399 Q_D(const QOpenGLContext);
401 const_cast<QOpenGLFunctions *&>(d->functions) = new QOpenGLExtensions(QOpenGLContext::currentContext());
406 Returns the set of OpenGL extensions supported by this context.
408 The context or a sharing context must be current.
412 QSet<QByteArray> QOpenGLContext::extensions() const
414 Q_D(const QOpenGLContext);
415 if (d->extensionNames.isEmpty()) {
416 QOpenGLExtensionMatcher matcher;
417 d->extensionNames = matcher.extensions();
420 return d->extensionNames;
424 Returns true if this OpenGL context supports the specified OpenGL
425 \a extension, false otherwise.
427 The context or a sharing context must be current.
431 bool QOpenGLContext::hasExtension(const QByteArray &extension) const
433 return extensions().contains(extension);
437 Call this to get the default framebuffer object for the current surface.
439 On some platforms the default framebuffer object depends on the surface
440 being rendered to, and might be different from 0. Thus, instead of calling
441 glBindFramebuffer(0), you should call
442 glBindFramebuffer(ctx->defaultFramebufferObject()) if you want your
443 application to work across different Qt platforms.
445 If you use the glBindFramebuffer() in QOpenGLFunctions you do not have to
446 worry about this, as it automatically binds the current context's
447 defaultFramebufferObject() when 0 is passed.
449 GLuint QOpenGLContext::defaultFramebufferObject() const
454 Q_D(const QOpenGLContext);
455 if (!d->surface || !d->surface->surfaceHandle())
458 return d->platformGLContext->defaultFramebufferObject(d->surface->surfaceHandle());
462 Makes the context current in the current thread, against the given
463 \a surface. Returns true if successful.
465 If \a surface is 0 this is equivalent to calling doneCurrent().
467 Do not call this function from a different thread than the one the
468 QOpenGLContext instance lives in. If you wish to use QOpenGLContext from a
469 different thread you should first call make sure it's not current in the
470 current thread, by calling doneCurrent() if necessary. Then call
471 moveToThread(otherThread) before using it in the other thread.
473 \sa functions(), doneCurrent()
475 bool QOpenGLContext::makeCurrent(QSurface *surface)
481 if (thread() != QThread::currentThread())
482 qFatal("Cannot make QOpenGLContext current in a different thread");
489 if (!surface->surfaceHandle())
492 if (surface->surfaceType() != QSurface::OpenGLSurface) {
493 qWarning() << "QOpenGLContext::makeCurrent() called with non-opengl surface";
498 if (d->platformGLContext->makeCurrent(surface->surfaceHandle())) {
499 QOpenGLContextPrivate::setCurrentContext(this);
500 d->surface = surface;
502 d->shareGroup->d_func()->deletePendingResources(this);
505 QOpenGLContextPrivate::toggleMakeCurrentTracker(this, true);
515 Convenience function for calling makeCurrent with a 0 surface.
517 This results in no context being current in the current thread.
519 \sa makeCurrent(), currentContext()
521 void QOpenGLContext::doneCurrent()
527 if (QOpenGLContext::currentContext() == this)
528 d->shareGroup->d_func()->deletePendingResources(this);
530 d->platformGLContext->doneCurrent();
531 QOpenGLContextPrivate::setCurrentContext(0);
537 Returns the surface the context has been made current with.
539 This is the surface passed as an argument to makeCurrent().
541 QSurface *QOpenGLContext::surface() const
543 Q_D(const QOpenGLContext);
549 Swap the back and front buffers of \a surface.
551 Call this to finish a frame of OpenGL rendering, and make sure to
552 call makeCurrent() again before you begin a new frame.
554 If you have bound a non-default framebuffer object, you need to
555 use bindDefaultFramebufferObject() to make sure that the default
556 framebuffer object is bound before calling swapBuffers(), as
557 some Qt platforms assume that the default framebuffer object is bound.
559 void QOpenGLContext::swapBuffers(QSurface *surface)
566 qWarning() << "QOpenGLContext::swapBuffers() called with null argument";
570 if (surface->surfaceType() != QSurface::OpenGLSurface) {
571 qWarning() << "QOpenGLContext::swapBuffers() called with non-opengl surface";
575 if (surface->surfaceClass() == QSurface::Window
576 && !qt_window_private(static_cast<QWindow *>(surface))->receivedExpose)
578 qWarning() << "QOpenGLContext::swapBuffers() called with non-exposed window, behavior is undefined";
581 QPlatformSurface *surfaceHandle = surface->surfaceHandle();
585 #if !defined(QT_NO_DEBUG)
586 if (currentContext() != this)
587 qWarning() << "QOpenGLContext::swapBuffers() called with non-current surface";
588 else if (!QOpenGLContextPrivate::toggleMakeCurrentTracker(this, false))
589 qWarning() << "QOpenGLContext::swapBuffers() called without corresponding makeCurrent()";
591 GLint framebufferBinding = 0;
592 glGetIntegerv(GL_FRAMEBUFFER_BINDING, &framebufferBinding);
594 GLint platformFramebuffer = GLint(d->platformGLContext->defaultFramebufferObject(surfaceHandle));
595 if (framebufferBinding != platformFramebuffer)
596 qWarning() << "QOpenGLContext::swapBuffers() called with non-default framebuffer object bound";
598 if (surface->format().swapBehavior() == QSurfaceFormat::SingleBuffer)
600 d->platformGLContext->swapBuffers(surfaceHandle);
604 Resolves the function pointer to an OpenGL extension function, identified by \a procName
606 Returns 0 if no such function can be found.
608 QFunctionPointer QOpenGLContext::getProcAddress(const QByteArray &procName) const
610 Q_D(const QOpenGLContext);
611 if (!d->platformGLContext)
613 return d->platformGLContext->getProcAddress(procName);
617 Returns the format of the underlying platform context, if create() has been called.
619 Otherwise, returns the requested format.
621 QSurfaceFormat QOpenGLContext::format() const
623 Q_D(const QOpenGLContext);
624 if (!d->platformGLContext)
625 return d->requestedFormat;
626 return d->platformGLContext->format();
630 Returns the share group this context belongs to.
632 QOpenGLContextGroup *QOpenGLContext::shareGroup() const
634 Q_D(const QOpenGLContext);
635 return d->shareGroup;
639 Returns the share context this context was created with.
641 If the underlying platform was not able to support the requested
642 sharing, this will return 0.
644 QOpenGLContext *QOpenGLContext::shareContext() const
646 Q_D(const QOpenGLContext);
647 return d->shareContext;
651 Returns the screen the context was created for.
653 QScreen *QOpenGLContext::screen() const
655 Q_D(const QOpenGLContext);
660 internal: Needs to have a pointer to qGLContext. But since this is in QtGui we cant
661 have any type information.
665 void *QOpenGLContext::qGLContextHandle() const
667 Q_D(const QOpenGLContext);
668 return d->qGLContextHandle;
674 void QOpenGLContext::setQGLContextHandle(void *handle,void (*qGLContextDeleteFunction)(void *))
677 d->qGLContextHandle = handle;
678 d->qGLContextDeleteFunction = qGLContextDeleteFunction;
684 void QOpenGLContext::deleteQGLContext()
687 if (d->qGLContextDeleteFunction && d->qGLContextHandle) {
688 d->qGLContextDeleteFunction(d->qGLContextHandle);
689 d->qGLContextDeleteFunction = 0;
690 d->qGLContextHandle = 0;
695 \class QOpenGLContextGroup
697 \brief The QOpenGLContextGroup class represents a group of contexts sharing
701 QOpenGLContextGroup is automatically created and managed by QOpenGLContext
702 instances. Its purpose is to identify all the contexts that are sharing
705 \sa QOpenGLContext::shareGroup()
707 QOpenGLContextGroup::QOpenGLContextGroup()
708 : QObject(*new QOpenGLContextGroupPrivate())
715 QOpenGLContextGroup::~QOpenGLContextGroup()
717 Q_D(QOpenGLContextGroup);
722 Returns all the QOpenGLContext objects in this share group.
724 QList<QOpenGLContext *> QOpenGLContextGroup::shares() const
726 Q_D(const QOpenGLContextGroup);
731 Returns the QOpenGLContextGroup corresponding to the current context.
733 \sa QOpenGLContext::currentContext()
735 QOpenGLContextGroup *QOpenGLContextGroup::currentContextGroup()
737 QOpenGLContext *current = QOpenGLContext::currentContext();
738 return current ? current->shareGroup() : 0;
741 void QOpenGLContextGroupPrivate::addContext(QOpenGLContext *ctx)
743 QMutexLocker locker(&m_mutex);
748 void QOpenGLContextGroupPrivate::removeContext(QOpenGLContext *ctx)
750 Q_Q(QOpenGLContextGroup);
752 QMutexLocker locker(&m_mutex);
753 m_shares.removeOne(ctx);
755 if (ctx == m_context && !m_shares.isEmpty())
756 m_context = m_shares.first();
758 if (!m_refs.deref()) {
764 void QOpenGLContextGroupPrivate::cleanup()
766 Q_Q(QOpenGLContextGroup);
768 QHash<QOpenGLMultiGroupSharedResource *, QOpenGLSharedResource *>::const_iterator it, end;
769 end = m_resources.constEnd();
770 for (it = m_resources.constBegin(); it != end; ++it)
771 it.key()->cleanup(q, it.value());
775 QList<QOpenGLSharedResource *>::iterator it = m_sharedResources.begin();
776 QList<QOpenGLSharedResource *>::iterator end = m_sharedResources.end();
779 (*it)->invalidateResource();
784 m_sharedResources.clear();
786 qDeleteAll(m_pendingDeletion.begin(), m_pendingDeletion.end());
787 m_pendingDeletion.clear();
790 void QOpenGLContextGroupPrivate::deletePendingResources(QOpenGLContext *ctx)
792 QMutexLocker locker(&m_mutex);
794 QList<QOpenGLSharedResource *> pending = m_pendingDeletion;
795 m_pendingDeletion.clear();
797 QList<QOpenGLSharedResource *>::iterator it = pending.begin();
798 QList<QOpenGLSharedResource *>::iterator end = pending.end();
800 (*it)->freeResource(ctx);
807 \class QOpenGLSharedResource
810 \brief The QOpenGLSharedResource class is used to keep track of resources
811 that are shared between OpenGL contexts (like textures, framebuffer
812 objects, shader programs, etc), and clean them up in a safe way when
813 they're no longer needed.
816 The QOpenGLSharedResource instance should never be deleted, instead free()
817 should be called when it's no longer needed. Thus it will be put on a queue
818 and freed at an appropriate time (when a context in the share group becomes
821 The sub-class needs to implement two pure virtual functions. The first,
822 freeResource() must be implemented to actually do the freeing, for example
823 call glDeleteTextures() on a texture id. Qt makes sure a valid context in
824 the resource's share group is current at the time. The other,
825 invalidateResource(), is called by Qt in the circumstance when the last
826 context in the share group is destroyed before free() has been called. The
827 implementation of invalidateResource() should set any identifiers to 0 or
828 set a flag to prevent them from being used later on.
830 QOpenGLSharedResource::QOpenGLSharedResource(QOpenGLContextGroup *group)
833 QMutexLocker locker(&m_group->d_func()->m_mutex);
834 m_group->d_func()->m_sharedResources << this;
837 QOpenGLSharedResource::~QOpenGLSharedResource()
841 // schedule the resource for deletion at an appropriate time
842 void QOpenGLSharedResource::free()
849 QMutexLocker locker(&m_group->d_func()->m_mutex);
850 m_group->d_func()->m_sharedResources.removeOne(this);
851 m_group->d_func()->m_pendingDeletion << this;
853 // can we delete right away?
854 QOpenGLContext *current = QOpenGLContext::currentContext();
855 if (current && current->shareGroup() == m_group) {
856 m_group->d_func()->deletePendingResources(current);
861 \class QOpenGLSharedResourceGuard
864 \brief The QOpenGLSharedResourceGuard class is a convenience sub-class of
865 QOpenGLSharedResource to be used to track a single OpenGL object with a
866 GLuint identifier. The constructor takes a function pointer to a function
867 that will be used to free the resource if and when necessary.
871 void QOpenGLSharedResourceGuard::freeResource(QOpenGLContext *context)
874 QOpenGLFunctions functions(context);
875 m_func(&functions, m_id);
881 \class QOpenGLMultiGroupSharedResource
884 \brief The QOpenGLMultiGroupSharedResource keeps track of a shared resource
885 that might be needed from multiple contexts, like a glyph cache or gradient
886 cache. One instance of the object is created for each group when necessary.
887 The shared resource instance should have a constructor that takes a
888 QOpenGLContext *. To get an instance for a given context one calls
889 T *QOpenGLMultiGroupSharedResource::value<T>(context), where T is a sub-class
890 of QOpenGLSharedResource.
893 You should not call free() on QOpenGLSharedResources owned by a
894 QOpenGLMultiGroupSharedResource instance.
896 QOpenGLMultiGroupSharedResource::QOpenGLMultiGroupSharedResource()
899 #ifdef QT_GL_CONTEXT_RESOURCE_DEBUG
900 qDebug("Creating context group resource object %p.", this);
904 QOpenGLMultiGroupSharedResource::~QOpenGLMultiGroupSharedResource()
906 #ifdef QT_GL_CONTEXT_RESOURCE_DEBUG
907 qDebug("Deleting context group resource %p. Group size: %d.", this, m_groups.size());
909 for (int i = 0; i < m_groups.size(); ++i) {
910 if (!m_groups.at(i)->shares().isEmpty()) {
911 QOpenGLContext *context = m_groups.at(i)->shares().first();
912 QOpenGLSharedResource *resource = value(context);
916 m_groups.at(i)->d_func()->m_resources.remove(this);
920 if (active.load() != 0) {
921 qWarning("QtGui: Resources are still available at program shutdown.\n"
922 " This is possibly caused by a leaked QOpenGLWidget, \n"
923 " QOpenGLFramebufferObject or QOpenGLPixelBuffer.");
928 void QOpenGLMultiGroupSharedResource::insert(QOpenGLContext *context, QOpenGLSharedResource *value)
930 #ifdef QT_GL_CONTEXT_RESOURCE_DEBUG
931 qDebug("Inserting context group resource %p for context %p, managed by %p.", value, context, this);
933 QOpenGLContextGroup *group = context->shareGroup();
934 Q_ASSERT(!group->d_func()->m_resources.contains(this));
935 group->d_func()->m_resources.insert(this, value);
936 m_groups.append(group);
940 QOpenGLSharedResource *QOpenGLMultiGroupSharedResource::value(QOpenGLContext *context)
942 QOpenGLContextGroup *group = context->shareGroup();
943 return group->d_func()->m_resources.value(this, 0);
946 QList<QOpenGLSharedResource *> QOpenGLMultiGroupSharedResource::resources() const
948 QList<QOpenGLSharedResource *> result;
949 for (QList<QOpenGLContextGroup *>::const_iterator it = m_groups.constBegin(); it != m_groups.constEnd(); ++it) {
950 QOpenGLSharedResource *resource = (*it)->d_func()->m_resources.value(const_cast<QOpenGLMultiGroupSharedResource *>(this), 0);
957 void QOpenGLMultiGroupSharedResource::cleanup(QOpenGLContextGroup *group, QOpenGLSharedResource *value)
959 #ifdef QT_GL_CONTEXT_RESOURCE_DEBUG
960 qDebug("Cleaning up context group resource %p, for group %p in thread %p.", this, group, QThread::currentThread());
962 value->invalidateResource();
966 Q_ASSERT(m_groups.contains(group));
967 m_groups.removeOne(group);