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 For an example of how to use QOpenGLContext see the
120 \l{gui/openglwindow}{OpenGL Window} example.
122 \section1 Thread affinity
124 QOpenGLContext can be moved to a different thread with moveToThread(). Do
125 not call makeCurrent() from a different thread than the one to which the
126 QOpenGLContext object belongs. A context can only be current in one thread
127 and against one surface at a time, and a thread only has one context
130 \section1 Context resource sharing
132 Resources, such as framebuffer objects, textures, and vertex buffer objects
133 can be shared between contexts. Use setShareContext() before calling
134 create() to specify that the contexts should share these resources.
135 QOpenGLContext internally keeps track of a QOpenGLContextGroup object which
136 can be accessed with shareGroup(), and which can be used to find all the
137 contexts in a given share group. A share group consists of all contexts that
138 have been successfully initialized and are sharing with an existing context in
139 the share group. A non-sharing context has a share group consisting of a
142 \section1 Default framebuffer
144 On certain platforms, a framebuffer other than 0 might be the default frame
145 buffer depending on the current surface. Instead of calling
146 glBindFramebuffer(0), it is recommended that you use
147 glBindFramebuffer(ctx->defaultFramebufferObject()), to ensure that your
148 application is portable between different platforms. However, if you use
149 QOpenGLFunctions::glBindFramebuffer(), this is done automatically for you.
151 \sa QOpenGLFunctions, QOpenGLBuffer, QOpenGLShaderProgram, QOpenGLFramebufferObject
154 void QOpenGLContextPrivate::setCurrentContext(QOpenGLContext *context)
156 QGuiGLThreadContext *threadContext = qwindow_context_storage.localData();
157 if (!threadContext) {
158 if (!QThread::currentThread()) {
159 qWarning("No QTLS available. currentContext wont work");
162 threadContext = new QGuiGLThreadContext;
163 qwindow_context_storage.setLocalData(threadContext);
165 threadContext->context = context;
168 int QOpenGLContextPrivate::maxTextureSize()
170 if (max_texture_size != -1)
171 return max_texture_size;
173 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size);
175 #if defined(QT_OPENGL_ES)
176 return max_texture_size;
178 GLenum proxy = GL_PROXY_TEXTURE_2D;
182 glTexImage2D(proxy, 0, GL_RGBA, next, next, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
183 glGetTexLevelParameteriv(proxy, 0, GL_TEXTURE_WIDTH, &size);
185 return max_texture_size;
191 if (next > max_texture_size)
193 glTexImage2D(proxy, 0, GL_RGBA, next, next, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
194 glGetTexLevelParameteriv(proxy, 0, GL_TEXTURE_WIDTH, &next);
195 } while (next > size);
197 max_texture_size = size;
198 return max_texture_size;
203 Returns the last context which called makeCurrent in the current thread,
204 or 0, if no context is current.
206 QOpenGLContext* QOpenGLContext::currentContext()
208 QGuiGLThreadContext *threadContext = qwindow_context_storage.localData();
210 return threadContext->context;
216 Returns true if the \a first and \a second contexts are sharing OpenGL resources.
218 bool QOpenGLContext::areSharing(QOpenGLContext *first, QOpenGLContext *second)
220 return first->shareGroup() == second->shareGroup();
224 Returns the underlying platform context.
228 QPlatformOpenGLContext *QOpenGLContext::handle() const
230 Q_D(const QOpenGLContext);
231 return d->platformGLContext;
235 Returns the underlying platform context with which this context is sharing.
240 QPlatformOpenGLContext *QOpenGLContext::shareHandle() const
242 Q_D(const QOpenGLContext);
244 return d->shareContext->handle();
249 Creates a new OpenGL context instance with parent object \a parent.
251 Before it can be used you need to set the proper format and call create().
253 \sa create(), makeCurrent()
255 QOpenGLContext::QOpenGLContext(QObject *parent)
256 : QObject(*new QOpenGLContextPrivate(), parent)
259 d->screen = QGuiApplication::primaryScreen();
263 Sets the \a format the OpenGL context should be compatible with. You need
264 to call create() before it takes effect.
266 void QOpenGLContext::setFormat(const QSurfaceFormat &format)
269 d->requestedFormat = format;
273 Makes this context share textures, shaders, and other OpenGL resources
274 with \a shareContext. You need to call create() before it takes effect.
276 void QOpenGLContext::setShareContext(QOpenGLContext *shareContext)
279 d->shareContext = shareContext;
283 Sets the \a screen the OpenGL context should be valid for. You need to call
284 create() before it takes effect.
286 void QOpenGLContext::setScreen(QScreen *screen)
291 d->screen = QGuiApplication::primaryScreen();
295 Attempts to create the OpenGL context with the current configuration.
297 The current configuration includes the format, the share context, and the
300 Returns true if the native context was successfully created and is ready to
301 be used with makeCurrent(), swapBuffers(), etc.
303 \sa makeCurrent(), destroy()
305 bool QOpenGLContext::create()
310 d->platformGLContext = QGuiApplicationPrivate::platformIntegration()->createPlatformOpenGLContext(this);
311 if (!d->platformGLContext)
313 d->platformGLContext->setContext(this);
314 if (!d->platformGLContext->isSharing())
316 d->shareGroup = d->shareContext ? d->shareContext->shareGroup() : new QOpenGLContextGroup;
317 d->shareGroup->d_func()->addContext(this);
318 return d->platformGLContext;
322 Destroy the underlying platform context associated with this context.
324 If any other context is directly or indirectly sharing resources with this
325 context, the shared resources, which includes vertex buffer objects, shader
326 objects, textures, and framebuffer objects, are not freed. However,
327 destroying the underlying platform context frees any state associated with
330 After destroy() has been called, you must call create() if you wish to
331 use the context again.
333 \note This implicitly calls doneCurrent() if the context is current.
337 void QOpenGLContext::destroy()
340 if (d->platformGLContext)
341 emit aboutToBeDestroyed();
342 if (QOpenGLContext::currentContext() == this)
345 d->shareGroup->d_func()->removeContext(this);
347 delete d->platformGLContext;
348 d->platformGLContext = 0;
354 \fn void QOpenGLContext::aboutToBeDestroyed()
356 This signal is emitted before the underlying native OpenGL context is
357 destroyed, such that users may clean up OpenGL resources that might
358 otherwise be left dangling in the case of shared OpenGL contexts.
360 If you wish to make the context current in order to do clean-up, make sure
361 to only connect to the signal using a direct connection.
365 Destroys the QOpenGLContext object.
367 This implicitly calls destroy(), so if this is the current context for the
368 thread, doneCurrent() is also called.
372 QOpenGLContext::~QOpenGLContext()
377 QOpenGLContextPrivate::cleanMakeCurrentTracker(this);
382 Returns if this context is valid, i.e. has been successfully created.
386 bool QOpenGLContext::isValid() const
388 Q_D(const QOpenGLContext);
389 return d->platformGLContext && d->platformGLContext->isValid();
393 Get the QOpenGLFunctions instance for this context.
395 QOpenGLContext offers this as a convenient way to access QOpenGLFunctions
396 without having to manage it manually.
398 The context or a sharing context must be current.
400 QOpenGLFunctions *QOpenGLContext::functions() const
402 Q_D(const QOpenGLContext);
404 const_cast<QOpenGLFunctions *&>(d->functions) = new QOpenGLExtensions(QOpenGLContext::currentContext());
409 Returns the set of OpenGL extensions supported by this context.
411 The context or a sharing context must be current.
415 QSet<QByteArray> QOpenGLContext::extensions() const
417 Q_D(const QOpenGLContext);
418 if (d->extensionNames.isEmpty()) {
419 QOpenGLExtensionMatcher matcher;
420 d->extensionNames = matcher.extensions();
423 return d->extensionNames;
427 Returns true if this OpenGL context supports the specified OpenGL
428 \a extension, false otherwise.
430 The context or a sharing context must be current.
434 bool QOpenGLContext::hasExtension(const QByteArray &extension) const
436 return extensions().contains(extension);
440 Call this to get the default framebuffer object for the current surface.
442 On some platforms the default framebuffer object depends on the surface
443 being rendered to, and might be different from 0. Thus, instead of calling
444 glBindFramebuffer(0), you should call
445 glBindFramebuffer(ctx->defaultFramebufferObject()) if you want your
446 application to work across different Qt platforms.
448 If you use the glBindFramebuffer() in QOpenGLFunctions you do not have to
449 worry about this, as it automatically binds the current context's
450 defaultFramebufferObject() when 0 is passed.
452 GLuint QOpenGLContext::defaultFramebufferObject() const
457 Q_D(const QOpenGLContext);
458 if (!d->surface || !d->surface->surfaceHandle())
461 return d->platformGLContext->defaultFramebufferObject(d->surface->surfaceHandle());
465 Makes the context current in the current thread, against the given
466 \a surface. Returns true if successful.
468 If \a surface is 0 this is equivalent to calling doneCurrent().
470 Do not call this function from a different thread than the one the
471 QOpenGLContext instance lives in. If you wish to use QOpenGLContext from a
472 different thread you should first call make sure it's not current in the
473 current thread, by calling doneCurrent() if necessary. Then call
474 moveToThread(otherThread) before using it in the other thread.
476 \sa functions(), doneCurrent()
478 bool QOpenGLContext::makeCurrent(QSurface *surface)
484 if (thread() != QThread::currentThread())
485 qFatal("Cannot make QOpenGLContext current in a different thread");
492 if (!surface->surfaceHandle())
495 if (surface->surfaceType() != QSurface::OpenGLSurface) {
496 qWarning() << "QOpenGLContext::makeCurrent() called with non-opengl surface";
501 if (d->platformGLContext->makeCurrent(surface->surfaceHandle())) {
502 QOpenGLContextPrivate::setCurrentContext(this);
503 d->surface = surface;
505 d->shareGroup->d_func()->deletePendingResources(this);
508 QOpenGLContextPrivate::toggleMakeCurrentTracker(this, true);
518 Convenience function for calling makeCurrent with a 0 surface.
520 This results in no context being current in the current thread.
522 \sa makeCurrent(), currentContext()
524 void QOpenGLContext::doneCurrent()
530 if (QOpenGLContext::currentContext() == this)
531 d->shareGroup->d_func()->deletePendingResources(this);
533 d->platformGLContext->doneCurrent();
534 QOpenGLContextPrivate::setCurrentContext(0);
540 Returns the surface the context has been made current with.
542 This is the surface passed as an argument to makeCurrent().
544 QSurface *QOpenGLContext::surface() const
546 Q_D(const QOpenGLContext);
552 Swap the back and front buffers of \a surface.
554 Call this to finish a frame of OpenGL rendering, and make sure to
555 call makeCurrent() again before you begin a new frame.
557 If you have bound a non-default framebuffer object, you need to
558 use bindDefaultFramebufferObject() to make sure that the default
559 framebuffer object is bound before calling swapBuffers(), as
560 some Qt platforms assume that the default framebuffer object is bound.
562 void QOpenGLContext::swapBuffers(QSurface *surface)
569 qWarning() << "QOpenGLContext::swapBuffers() called with null argument";
573 if (surface->surfaceType() != QSurface::OpenGLSurface) {
574 qWarning() << "QOpenGLContext::swapBuffers() called with non-opengl surface";
578 if (surface->surfaceClass() == QSurface::Window
579 && !qt_window_private(static_cast<QWindow *>(surface))->receivedExpose)
581 qWarning() << "QOpenGLContext::swapBuffers() called with non-exposed window, behavior is undefined";
584 QPlatformSurface *surfaceHandle = surface->surfaceHandle();
588 #if !defined(QT_NO_DEBUG)
589 if (currentContext() != this)
590 qWarning() << "QOpenGLContext::swapBuffers() called with non-current surface";
591 else if (!QOpenGLContextPrivate::toggleMakeCurrentTracker(this, false))
592 qWarning() << "QOpenGLContext::swapBuffers() called without corresponding makeCurrent()";
594 GLint framebufferBinding = 0;
595 glGetIntegerv(GL_FRAMEBUFFER_BINDING, &framebufferBinding);
597 GLint platformFramebuffer = GLint(d->platformGLContext->defaultFramebufferObject(surfaceHandle));
598 if (framebufferBinding != platformFramebuffer)
599 qWarning() << "QOpenGLContext::swapBuffers() called with non-default framebuffer object bound";
601 if (surface->format().swapBehavior() == QSurfaceFormat::SingleBuffer)
603 d->platformGLContext->swapBuffers(surfaceHandle);
607 Resolves the function pointer to an OpenGL extension function, identified by \a procName
609 Returns 0 if no such function can be found.
611 QFunctionPointer QOpenGLContext::getProcAddress(const QByteArray &procName) const
613 Q_D(const QOpenGLContext);
614 if (!d->platformGLContext)
616 return d->platformGLContext->getProcAddress(procName);
620 Returns the format of the underlying platform context, if create() has been called.
622 Otherwise, returns the requested format.
624 QSurfaceFormat QOpenGLContext::format() const
626 Q_D(const QOpenGLContext);
627 if (!d->platformGLContext)
628 return d->requestedFormat;
629 return d->platformGLContext->format();
633 Returns the share group this context belongs to.
635 QOpenGLContextGroup *QOpenGLContext::shareGroup() const
637 Q_D(const QOpenGLContext);
638 return d->shareGroup;
642 Returns the share context this context was created with.
644 If the underlying platform was not able to support the requested
645 sharing, this will return 0.
647 QOpenGLContext *QOpenGLContext::shareContext() const
649 Q_D(const QOpenGLContext);
650 return d->shareContext;
654 Returns the screen the context was created for.
656 QScreen *QOpenGLContext::screen() const
658 Q_D(const QOpenGLContext);
663 internal: Needs to have a pointer to qGLContext. But since this is in QtGui we cant
664 have any type information.
668 void *QOpenGLContext::qGLContextHandle() const
670 Q_D(const QOpenGLContext);
671 return d->qGLContextHandle;
677 void QOpenGLContext::setQGLContextHandle(void *handle,void (*qGLContextDeleteFunction)(void *))
680 d->qGLContextHandle = handle;
681 d->qGLContextDeleteFunction = qGLContextDeleteFunction;
687 void QOpenGLContext::deleteQGLContext()
690 if (d->qGLContextDeleteFunction && d->qGLContextHandle) {
691 d->qGLContextDeleteFunction(d->qGLContextHandle);
692 d->qGLContextDeleteFunction = 0;
693 d->qGLContextHandle = 0;
698 \class QOpenGLContextGroup
700 \brief The QOpenGLContextGroup class represents a group of contexts sharing
704 QOpenGLContextGroup is automatically created and managed by QOpenGLContext
705 instances. Its purpose is to identify all the contexts that are sharing
708 \sa QOpenGLContext::shareGroup()
710 QOpenGLContextGroup::QOpenGLContextGroup()
711 : QObject(*new QOpenGLContextGroupPrivate())
718 QOpenGLContextGroup::~QOpenGLContextGroup()
720 Q_D(QOpenGLContextGroup);
725 Returns all the QOpenGLContext objects in this share group.
727 QList<QOpenGLContext *> QOpenGLContextGroup::shares() const
729 Q_D(const QOpenGLContextGroup);
734 Returns the QOpenGLContextGroup corresponding to the current context.
736 \sa QOpenGLContext::currentContext()
738 QOpenGLContextGroup *QOpenGLContextGroup::currentContextGroup()
740 QOpenGLContext *current = QOpenGLContext::currentContext();
741 return current ? current->shareGroup() : 0;
744 void QOpenGLContextGroupPrivate::addContext(QOpenGLContext *ctx)
746 QMutexLocker locker(&m_mutex);
751 void QOpenGLContextGroupPrivate::removeContext(QOpenGLContext *ctx)
753 Q_Q(QOpenGLContextGroup);
755 QMutexLocker locker(&m_mutex);
756 m_shares.removeOne(ctx);
758 if (ctx == m_context && !m_shares.isEmpty())
759 m_context = m_shares.first();
761 if (!m_refs.deref()) {
767 void QOpenGLContextGroupPrivate::cleanup()
769 Q_Q(QOpenGLContextGroup);
771 QHash<QOpenGLMultiGroupSharedResource *, QOpenGLSharedResource *>::const_iterator it, end;
772 end = m_resources.constEnd();
773 for (it = m_resources.constBegin(); it != end; ++it)
774 it.key()->cleanup(q, it.value());
778 QList<QOpenGLSharedResource *>::iterator it = m_sharedResources.begin();
779 QList<QOpenGLSharedResource *>::iterator end = m_sharedResources.end();
782 (*it)->invalidateResource();
787 m_sharedResources.clear();
789 qDeleteAll(m_pendingDeletion.begin(), m_pendingDeletion.end());
790 m_pendingDeletion.clear();
793 void QOpenGLContextGroupPrivate::deletePendingResources(QOpenGLContext *ctx)
795 QMutexLocker locker(&m_mutex);
797 QList<QOpenGLSharedResource *> pending = m_pendingDeletion;
798 m_pendingDeletion.clear();
800 QList<QOpenGLSharedResource *>::iterator it = pending.begin();
801 QList<QOpenGLSharedResource *>::iterator end = pending.end();
803 (*it)->freeResource(ctx);
810 \class QOpenGLSharedResource
813 \brief The QOpenGLSharedResource class is used to keep track of resources
814 that are shared between OpenGL contexts (like textures, framebuffer
815 objects, shader programs, etc), and clean them up in a safe way when
816 they're no longer needed.
819 The QOpenGLSharedResource instance should never be deleted, instead free()
820 should be called when it's no longer needed. Thus it will be put on a queue
821 and freed at an appropriate time (when a context in the share group becomes
824 The sub-class needs to implement two pure virtual functions. The first,
825 freeResource() must be implemented to actually do the freeing, for example
826 call glDeleteTextures() on a texture id. Qt makes sure a valid context in
827 the resource's share group is current at the time. The other,
828 invalidateResource(), is called by Qt in the circumstance when the last
829 context in the share group is destroyed before free() has been called. The
830 implementation of invalidateResource() should set any identifiers to 0 or
831 set a flag to prevent them from being used later on.
833 QOpenGLSharedResource::QOpenGLSharedResource(QOpenGLContextGroup *group)
836 QMutexLocker locker(&m_group->d_func()->m_mutex);
837 m_group->d_func()->m_sharedResources << this;
840 QOpenGLSharedResource::~QOpenGLSharedResource()
844 // schedule the resource for deletion at an appropriate time
845 void QOpenGLSharedResource::free()
852 QMutexLocker locker(&m_group->d_func()->m_mutex);
853 m_group->d_func()->m_sharedResources.removeOne(this);
854 m_group->d_func()->m_pendingDeletion << this;
856 // can we delete right away?
857 QOpenGLContext *current = QOpenGLContext::currentContext();
858 if (current && current->shareGroup() == m_group) {
859 m_group->d_func()->deletePendingResources(current);
864 \class QOpenGLSharedResourceGuard
867 \brief The QOpenGLSharedResourceGuard class is a convenience sub-class of
868 QOpenGLSharedResource to be used to track a single OpenGL object with a
869 GLuint identifier. The constructor takes a function pointer to a function
870 that will be used to free the resource if and when necessary.
874 void QOpenGLSharedResourceGuard::freeResource(QOpenGLContext *context)
877 QOpenGLFunctions functions(context);
878 m_func(&functions, m_id);
884 \class QOpenGLMultiGroupSharedResource
887 \brief The QOpenGLMultiGroupSharedResource keeps track of a shared resource
888 that might be needed from multiple contexts, like a glyph cache or gradient
889 cache. One instance of the object is created for each group when necessary.
890 The shared resource instance should have a constructor that takes a
891 QOpenGLContext *. To get an instance for a given context one calls
892 T *QOpenGLMultiGroupSharedResource::value<T>(context), where T is a sub-class
893 of QOpenGLSharedResource.
896 You should not call free() on QOpenGLSharedResources owned by a
897 QOpenGLMultiGroupSharedResource instance.
899 QOpenGLMultiGroupSharedResource::QOpenGLMultiGroupSharedResource()
902 #ifdef QT_GL_CONTEXT_RESOURCE_DEBUG
903 qDebug("Creating context group resource object %p.", this);
907 QOpenGLMultiGroupSharedResource::~QOpenGLMultiGroupSharedResource()
909 #ifdef QT_GL_CONTEXT_RESOURCE_DEBUG
910 qDebug("Deleting context group resource %p. Group size: %d.", this, m_groups.size());
912 for (int i = 0; i < m_groups.size(); ++i) {
913 if (!m_groups.at(i)->shares().isEmpty()) {
914 QOpenGLContext *context = m_groups.at(i)->shares().first();
915 QOpenGLSharedResource *resource = value(context);
919 m_groups.at(i)->d_func()->m_resources.remove(this);
923 if (active.load() != 0) {
924 qWarning("QtGui: Resources are still available at program shutdown.\n"
925 " This is possibly caused by a leaked QOpenGLWidget, \n"
926 " QOpenGLFramebufferObject or QOpenGLPixelBuffer.");
931 void QOpenGLMultiGroupSharedResource::insert(QOpenGLContext *context, QOpenGLSharedResource *value)
933 #ifdef QT_GL_CONTEXT_RESOURCE_DEBUG
934 qDebug("Inserting context group resource %p for context %p, managed by %p.", value, context, this);
936 QOpenGLContextGroup *group = context->shareGroup();
937 Q_ASSERT(!group->d_func()->m_resources.contains(this));
938 group->d_func()->m_resources.insert(this, value);
939 m_groups.append(group);
943 QOpenGLSharedResource *QOpenGLMultiGroupSharedResource::value(QOpenGLContext *context)
945 QOpenGLContextGroup *group = context->shareGroup();
946 return group->d_func()->m_resources.value(this, 0);
949 QList<QOpenGLSharedResource *> QOpenGLMultiGroupSharedResource::resources() const
951 QList<QOpenGLSharedResource *> result;
952 for (QList<QOpenGLContextGroup *>::const_iterator it = m_groups.constBegin(); it != m_groups.constEnd(); ++it) {
953 QOpenGLSharedResource *resource = (*it)->d_func()->m_resources.value(const_cast<QOpenGLMultiGroupSharedResource *>(this), 0);
960 void QOpenGLMultiGroupSharedResource::cleanup(QOpenGLContextGroup *group, QOpenGLSharedResource *value)
962 #ifdef QT_GL_CONTEXT_RESOURCE_DEBUG
963 qDebug("Cleaning up context group resource %p, for group %p in thread %p.", this, group, QThread::currentThread());
965 value->invalidateResource();
969 Q_ASSERT(m_groups.contains(group));
970 m_groups.removeOne(group);