summaryrefslogtreecommitdiffstats
path: root/src/gui/kernel
diff options
context:
space:
mode:
authorSamuel Rødal <samuel.rodal@nokia.com>2011-08-16 09:29:44 +0200
committerSamuel Rødal <samuel.rodal@nokia.com>2011-08-29 10:24:55 +0200
commitaaa4a26f82f99fa8724841eba91bad029306e0ce (patch)
tree3d24e874bff00efc0e73af610bc80e645d14f789 /src/gui/kernel
parent00fd783a39d55d2365ddead4fab2cc06091c119f (diff)
Move GL resource handling enablers to QtGui.
Made resource handling more robust by attempting to free GL resources in the correct thread, and not forcing a context to become current to free resources. Change-Id: Ie81d4005b608972375755571d9b50ce82080709b Reviewed-on: http://codereview.qt.nokia.com/3258 Reviewed-by: Qt Sanity Bot <qt_sanity_bot@ovi.com> Reviewed-by: Gunnar Sletta <gunnar.sletta@nokia.com>
Diffstat (limited to 'src/gui/kernel')
-rw-r--r--src/gui/kernel/kernel.pri1
-rw-r--r--src/gui/kernel/qguiglcontext_qpa.cpp229
-rw-r--r--src/gui/kernel/qguiglcontext_qpa.h33
-rw-r--r--src/gui/kernel/qguiglcontext_qpa_p.h181
-rw-r--r--src/gui/kernel/qplatformglcontext_qpa.cpp2
5 files changed, 409 insertions, 37 deletions
diff --git a/src/gui/kernel/kernel.pri b/src/gui/kernel/kernel.pri
index 58291f5237..44d039512f 100644
--- a/src/gui/kernel/kernel.pri
+++ b/src/gui/kernel/kernel.pri
@@ -51,6 +51,7 @@ qpa {
kernel/qplatformwindow_qpa.h \
kernel/qplatformglcontext_qpa.h \
kernel/qguiglcontext_qpa.h \
+ kernel/qguiglcontext_qpa_p.h \
kernel/qplatformcursor_qpa.h \
kernel/qplatformclipboard_qpa.h \
kernel/qplatformnativeinterface_qpa.h \
diff --git a/src/gui/kernel/qguiglcontext_qpa.cpp b/src/gui/kernel/qguiglcontext_qpa.cpp
index 2c43befbc9..71c830174e 100644
--- a/src/gui/kernel/qguiglcontext_qpa.cpp
+++ b/src/gui/kernel/qguiglcontext_qpa.cpp
@@ -41,6 +41,7 @@
#include "qplatformglcontext_qpa.h"
#include "qguiglcontext_qpa.h"
+#include "qguiglcontext_qpa_p.h"
#include "qwindow.h"
#include <QtCore/QThreadStorage>
@@ -63,35 +64,6 @@ public:
static QThreadStorage<QGuiGLThreadContext *> qwindow_context_storage;
-class QGuiGLContextPrivate
-{
-public:
- QGuiGLContextPrivate()
- : qGLContextHandle(0)
- , platformGLContext(0)
- , shareContext(0)
- , screen(0)
- , surface(0)
- {
- }
-
- virtual ~QGuiGLContextPrivate()
- {
- //do not delete the QGLContext handle here as it is deleted in
- //QWidgetPrivate::deleteTLSysExtra()
- }
- void *qGLContextHandle;
- void (*qGLContextDeleteFunction)(void *handle);
-
- QSurfaceFormat requestedFormat;
- QPlatformGLContext *platformGLContext;
- QGuiGLContext *shareContext;
- QScreen *screen;
- QSurface *surface;
-
- static void setCurrentContext(QGuiGLContext *context);
-};
-
void QGuiGLContextPrivate::setCurrentContext(QGuiGLContext *context)
{
QGuiGLThreadContext *threadContext = qwindow_context_storage.localData();
@@ -118,6 +90,11 @@ QGuiGLContext* QGuiGLContext::currentContext()
return 0;
}
+bool QGuiGLContext::areSharing(QGuiGLContext *first, QGuiGLContext *second)
+{
+ return first->shareGroup() == second->shareGroup();
+}
+
QPlatformGLContext *QGuiGLContext::handle() const
{
Q_D(const QGuiGLContext);
@@ -136,7 +113,7 @@ QPlatformGLContext *QGuiGLContext::shareHandle() const
Creates a new GL context instance, you need to call create() before it can be used.
*/
QGuiGLContext::QGuiGLContext()
- : d_ptr(new QGuiGLContextPrivate())
+ : QObject(*new QGuiGLContextPrivate())
{
Q_D(QGuiGLContext);
d->screen = QGuiApplication::primaryScreen();
@@ -174,7 +151,7 @@ void QGuiGLContext::setScreen(QScreen *screen)
/*!
Attempts to create the GL context with the desired parameters.
- Returns true if the native context was successfully created and is ready to be used.d
+ Returns true if the native context was successfully created and is ready to be used.
*/
bool QGuiGLContext::create()
{
@@ -183,6 +160,8 @@ bool QGuiGLContext::create()
Q_D(QGuiGLContext);
d->platformGLContext = QGuiApplicationPrivate::platformIntegration()->createPlatformGLContext(this);
d->platformGLContext->setContext(this);
+ d->shareGroup = d->shareContext ? d->shareContext->shareGroup() : new QGuiGLContextGroup;
+ d->shareGroup->d_func()->addContext(this);
return d->platformGLContext;
}
@@ -191,6 +170,9 @@ void QGuiGLContext::destroy()
Q_D(QGuiGLContext);
if (QGuiGLContext::currentContext() == this)
doneCurrent();
+ if (d->shareGroup)
+ d->shareGroup->d_func()->removeContext(this);
+ d->shareGroup = 0;
delete d->platformGLContext;
d->platformGLContext = 0;
}
@@ -232,6 +214,9 @@ bool QGuiGLContext::makeCurrent(QSurface *surface)
if (d->platformGLContext->makeCurrent(surface->surfaceHandle())) {
QGuiGLContextPrivate::setCurrentContext(this);
d->surface = surface;
+
+ d->shareGroup->d_func()->deletePendingResources(this);
+
return true;
}
@@ -247,6 +232,9 @@ void QGuiGLContext::doneCurrent()
if (!d->platformGLContext)
return;
+ if (QGuiGLContext::currentContext() == this)
+ d->shareGroup->d_func()->deletePendingResources(this);
+
d->platformGLContext->doneCurrent();
QGuiGLContextPrivate::setCurrentContext(0);
@@ -293,6 +281,12 @@ QSurfaceFormat QGuiGLContext::format() const
return d->platformGLContext->format();
}
+QGuiGLContextGroup *QGuiGLContext::shareGroup() const
+{
+ Q_D(const QGuiGLContext);
+ return d->shareGroup;
+}
+
QGuiGLContext *QGuiGLContext::shareContext() const
{
Q_D(const QGuiGLContext);
@@ -331,3 +325,176 @@ void QGuiGLContext::deleteQGLContext()
d->qGLContextHandle = 0;
}
}
+
+QGuiGLContextGroup::QGuiGLContextGroup()
+ : QObject(*new QGuiGLContextGroupPrivate())
+{
+}
+
+QGuiGLContextGroup::~QGuiGLContextGroup()
+{
+ Q_D(QGuiGLContextGroup);
+
+ QList<QGLSharedResource *>::iterator it = d->m_sharedResources.begin();
+ QList<QGLSharedResource *>::iterator end = d->m_sharedResources.end();
+
+ while (it != end) {
+ (*it)->invalidateResource();
+ (*it)->m_group = 0;
+ ++it;
+ }
+
+ qDeleteAll(d->m_pendingDeletion.begin(), d->m_pendingDeletion.end());
+}
+
+QList<QGuiGLContext *> QGuiGLContextGroup::shares() const
+{
+ Q_D(const QGuiGLContextGroup);
+ return d->m_shares;
+}
+
+QGuiGLContextGroup *QGuiGLContextGroup::currentContextGroup()
+{
+ QGuiGLContext *current = QGuiGLContext::currentContext();
+ return current ? current->shareGroup() : 0;
+}
+
+void QGuiGLContextGroupPrivate::addContext(QGuiGLContext *ctx)
+{
+ QMutexLocker locker(&m_mutex);
+ m_refs.ref();
+ m_shares << ctx;
+}
+
+void QGuiGLContextGroupPrivate::removeContext(QGuiGLContext *ctx)
+{
+ Q_Q(QGuiGLContextGroup);
+
+ QMutexLocker locker(&m_mutex);
+ m_shares.removeOne(ctx);
+
+ if (ctx == m_context && !m_shares.isEmpty())
+ m_context = m_shares.first();
+
+ if (!m_refs.deref())
+ q->deleteLater();
+}
+
+void QGuiGLContextGroupPrivate::deletePendingResources(QGuiGLContext *ctx)
+{
+ QMutexLocker locker(&m_mutex);
+
+ QList<QGLSharedResource *>::iterator it = m_pendingDeletion.begin();
+ QList<QGLSharedResource *>::iterator end = m_pendingDeletion.end();
+ while (it != end) {
+ (*it)->freeResource(ctx);
+ delete *it;
+ ++it;
+ }
+ m_pendingDeletion.clear();
+}
+
+QGLSharedResource::QGLSharedResource(QGuiGLContextGroup *group)
+ : m_group(group)
+{
+ QMutexLocker locker(&m_group->d_func()->m_mutex);
+ m_group->d_func()->m_sharedResources << this;
+}
+
+QGLSharedResource::~QGLSharedResource()
+{
+}
+
+// schedule the resource for deletion at an appropriate time
+void QGLSharedResource::free()
+{
+ if (!m_group) {
+ delete this;
+ return;
+ }
+
+ QMutexLocker locker(&m_group->d_func()->m_mutex);
+ m_group->d_func()->m_sharedResources.removeOne(this);
+ m_group->d_func()->m_pendingDeletion << this;
+
+ // can we delete right away?
+ QGuiGLContext *current = QGuiGLContext::currentContext();
+ if (current && current->shareGroup() == m_group) {
+ m_group->d_func()->deletePendingResources(current);
+ }
+}
+
+QGLMultiGroupSharedResource::QGLMultiGroupSharedResource()
+ : active(0)
+{
+#ifdef QT_GL_CONTEXT_RESOURCE_DEBUG
+ qDebug("Creating context group resource object %p.", this);
+#endif
+}
+
+QGLMultiGroupSharedResource::~QGLMultiGroupSharedResource()
+{
+#ifdef QT_GL_CONTEXT_RESOURCE_DEBUG
+ qDebug("Deleting context group resource %p. Group size: %d.", this, m_groups.size());
+#endif
+ for (int i = 0; i < m_groups.size(); ++i) {
+ QGuiGLContext *context = m_groups.at(i)->shares().first();
+ QGLSharedResource *resource = value(context);
+ if (resource)
+ resource->free();
+ m_groups.at(i)->d_func()->m_resources.remove(this);
+ active.deref();
+ }
+#ifndef QT_NO_DEBUG
+ if (active != 0) {
+ qWarning("QtOpenGL: Resources are still available at program shutdown.\n"
+ " This is possibly caused by a leaked QGLWidget, \n"
+ " QGLFramebufferObject or QGLPixelBuffer.");
+ }
+#endif
+}
+
+void QGLMultiGroupSharedResource::insert(QGuiGLContext *context, QGLSharedResource *value)
+{
+#ifdef QT_GL_CONTEXT_RESOURCE_DEBUG
+ qDebug("Inserting context group resource %p for context %p, managed by %p.", value, context, this);
+#endif
+ QGuiGLContextGroup *group = context->shareGroup();
+ Q_ASSERT(!group->d_func()->m_resources.contains(this));
+ group->d_func()->m_resources.insert(this, value);
+ m_groups.append(group);
+ active.ref();
+}
+
+QGLSharedResource *QGLMultiGroupSharedResource::value(QGuiGLContext *context)
+{
+ QGuiGLContextGroup *group = context->shareGroup();
+ return group->d_func()->m_resources.value(this, 0);
+}
+
+void QGLMultiGroupSharedResource::cleanup(QGuiGLContext *ctx)
+{
+ QGLSharedResource *resource = value(ctx);
+
+ if (resource != 0) {
+ resource->free();
+
+ QGuiGLContextGroup *group = ctx->shareGroup();
+ group->d_func()->m_resources.remove(this);
+ m_groups.removeOne(group);
+ active.deref();
+ }
+}
+
+void QGLMultiGroupSharedResource::cleanup(QGuiGLContext *ctx, QGLSharedResource *value)
+{
+#ifdef QT_GL_CONTEXT_RESOURCE_DEBUG
+ qDebug("Cleaning up context group resource %p, for context %p in thread %p.", this, ctx, QThread::currentThread());
+#endif
+ value->free();
+ active.deref();
+
+ QGuiGLContextGroup *group = ctx->shareGroup();
+ m_groups.removeOne(group);
+}
+
diff --git a/src/gui/kernel/qguiglcontext_qpa.h b/src/gui/kernel/qguiglcontext_qpa.h
index 11a7e16a82..a234bd3cb6 100644
--- a/src/gui/kernel/qguiglcontext_qpa.h
+++ b/src/gui/kernel/qguiglcontext_qpa.h
@@ -54,12 +54,34 @@ QT_BEGIN_NAMESPACE
QT_MODULE(Gui)
class QGuiGLContextPrivate;
+class QGuiGLContextGroupPrivate;
class QPlatformGLContext;
class QSurface;
-class Q_GUI_EXPORT QGuiGLContext
+class Q_GUI_EXPORT QGuiGLContextGroup : public QObject
{
-Q_DECLARE_PRIVATE(QGuiGLContext);
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QGuiGLContextGroup)
+public:
+ ~QGuiGLContextGroup();
+
+ QList<QGuiGLContext *> shares() const;
+
+ static QGuiGLContextGroup *currentContextGroup();
+
+private:
+ QGuiGLContextGroup();
+
+ friend class QGuiGLContext;
+ friend class QGLContextGroupResourceBase;
+ friend class QGLSharedResource;
+ friend class QGLMultiGroupSharedResource;
+};
+
+class Q_GUI_EXPORT QGuiGLContext : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QGuiGLContext);
public:
QGuiGLContext();
~QGuiGLContext();
@@ -73,6 +95,7 @@ public:
QSurfaceFormat format() const;
QGuiGLContext *shareContext() const;
+ QGuiGLContextGroup *shareGroup() const;
QScreen *screen() const;
bool makeCurrent(QSurface *surface);
@@ -84,15 +107,15 @@ public:
QSurface *surface() const;
static QGuiGLContext *currentContext();
+ static bool areSharing(QGuiGLContext *first, QGuiGLContext *second);
QPlatformGLContext *handle() const;
QPlatformGLContext *shareHandle() const;
private:
- QScopedPointer<QGuiGLContextPrivate> d_ptr;
-
//hack to make it work with QGLContext::CurrentContext
friend class QGLContext;
+ friend class QGLContextResourceBase;
friend class QWidgetPrivate;
void *qGLContextHandle() const;
@@ -100,8 +123,6 @@ private:
void deleteQGLContext();
void destroy();
-
- Q_DISABLE_COPY(QGuiGLContext);
};
QT_END_NAMESPACE
diff --git a/src/gui/kernel/qguiglcontext_qpa_p.h b/src/gui/kernel/qguiglcontext_qpa_p.h
new file mode 100644
index 0000000000..a9c8f5c75e
--- /dev/null
+++ b/src/gui/kernel/qguiglcontext_qpa_p.h
@@ -0,0 +1,181 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtOpenGL module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGUIGLCONTEXT_P_H
+#define QGUIGLCONTEXT_P_H
+
+#include "qguiglcontext_qpa.h"
+#include <private/qobject_p.h>
+#include <qmutex.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+class QGuiGLContext;
+class QGLMultiGroupSharedResource;
+
+class Q_GUI_EXPORT QGLSharedResource
+{
+public:
+ QGLSharedResource(QGuiGLContextGroup *group);
+ virtual ~QGLSharedResource() = 0;
+
+ QGuiGLContextGroup *group() const { return m_group; }
+
+ // schedule the resource for deletion at an appropriate time
+ void free();
+
+protected:
+ // the resource's share group no longer exists, invalidate the resource
+ virtual void invalidateResource() = 0;
+
+ // a valid context in the group is current, free the resource
+ virtual void freeResource(QGuiGLContext *context) = 0;
+
+private:
+ QGuiGLContextGroup *m_group;
+
+ friend class QGuiGLContextGroup;
+ friend class QGuiGLContextGroupPrivate;
+
+ Q_DISABLE_COPY(QGLSharedResource);
+};
+
+class Q_GUI_EXPORT QGuiGLContextGroupPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QGuiGLContextGroup);
+public:
+ QGuiGLContextGroupPrivate()
+ : m_context(0)
+ , m_mutex(QMutex::Recursive)
+ , m_refs(0)
+ {
+ }
+
+ void addContext(QGuiGLContext *ctx);
+ void removeContext(QGuiGLContext *ctx);
+
+ void deletePendingResources(QGuiGLContext *ctx);
+
+ QGuiGLContext *m_context;
+
+ QList<QGuiGLContext *> m_shares;
+ QMutex m_mutex;
+
+ QHash<QGLMultiGroupSharedResource *, QGLSharedResource *> m_resources;
+ QAtomicInt m_refs;
+
+ QList<QGLSharedResource *> m_sharedResources;
+ QList<QGLSharedResource *> m_pendingDeletion;
+
+ void cleanupResources(QGuiGLContext *ctx);
+};
+
+class Q_GUI_EXPORT QGLMultiGroupSharedResource
+{
+public:
+ QGLMultiGroupSharedResource();
+ ~QGLMultiGroupSharedResource();
+
+ void insert(QGuiGLContext *context, QGLSharedResource *value);
+ void cleanup(QGuiGLContext *context);
+ void cleanup(QGuiGLContext *context, QGLSharedResource *value);
+
+ QGLSharedResource *value(QGuiGLContext *context);
+
+ template <typename T>
+ T *value(QGuiGLContext *context) {
+ QGuiGLContextGroup *group = context->shareGroup();
+ T *resource = static_cast<T *>(group->d_func()->m_resources.value(this, 0));
+ if (!resource) {
+ resource = new T(context);
+ insert(context, resource);
+ }
+ return resource;
+ }
+
+private:
+ QAtomicInt active;
+ QList<QGuiGLContextGroup *> m_groups;
+};
+
+class Q_GUI_EXPORT QGuiGLContextPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QGuiGLContext);
+public:
+ QGuiGLContextPrivate()
+ : qGLContextHandle(0)
+ , platformGLContext(0)
+ , shareContext(0)
+ , shareGroup(0)
+ , screen(0)
+ , surface(0)
+ {
+ }
+
+ virtual ~QGuiGLContextPrivate()
+ {
+ //do not delete the QGLContext handle here as it is deleted in
+ //QWidgetPrivate::deleteTLSysExtra()
+ }
+ void *qGLContextHandle;
+ void (*qGLContextDeleteFunction)(void *handle);
+
+ QSurfaceFormat requestedFormat;
+ QPlatformGLContext *platformGLContext;
+ QGuiGLContext *shareContext;
+ QGuiGLContextGroup *shareGroup;
+ QScreen *screen;
+ QSurface *surface;
+
+ QHash<QGLMultiGroupSharedResource *, void *> m_resources;
+
+ static void setCurrentContext(QGuiGLContext *context);
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QGUIGLCONTEXT_P_H
diff --git a/src/gui/kernel/qplatformglcontext_qpa.cpp b/src/gui/kernel/qplatformglcontext_qpa.cpp
index 81030b8cfe..5ce7db09e2 100644
--- a/src/gui/kernel/qplatformglcontext_qpa.cpp
+++ b/src/gui/kernel/qplatformglcontext_qpa.cpp
@@ -65,6 +65,8 @@
/*! \fn void QPlatformGLContext::swapBuffers()
Reimplement in subclass to native swap buffers calls
+
+ The implementation must support being called in a thread different than the gui-thread.
*/
/*! \fn void *QPlatformGLContext::getProcAddress(const QString &procName)