summaryrefslogtreecommitdiffstats
path: root/src/gui/kernel/qguiglcontext_qpa.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/kernel/qguiglcontext_qpa.cpp')
-rw-r--r--src/gui/kernel/qguiglcontext_qpa.cpp229
1 files changed, 198 insertions, 31 deletions
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);
+}
+