diff options
author | Laszlo Agocs <laszlo.agocs@theqtcompany.com> | 2015-03-24 16:57:23 +0100 |
---|---|---|
committer | Laszlo Agocs <laszlo.agocs@theqtcompany.com> | 2015-03-27 16:36:34 +0000 |
commit | 52781f2a7d4c63990c2484b267614450f80c5591 (patch) | |
tree | 1b393f62917899931ce2f0c6a76f76b4af445a5a /src/gui | |
parent | bc6e92bd2ed7e39dcb856c3e275886e1e69df4c3 (diff) |
Make versioned OpenGL functions working with the subclass pattern
QOpenGLFunctions allows both deriving from it and getting an instance
via QOpenGLContext::functions().
Unsurprisingly a large number of users attempt to use the versioned
function wrappers in the same way. Unfortunately this approach was
not that well supported.
Besides some potential base class exporting issues the real blocker for
QOpenGLWidget - or any versionfunction subclass whose associated context
changes during its lifetime - is that the functions instances could
only be initialized once. Unlike instances retrieved via
QOpenGLContext::versionFunctions(), instances created "manually" were not
deinitialized upon the destruction of the associated context because
context did not know about them.
A pattern like
initializeOpenGLFunctions();
delete context;
create new context and make it current
initializeOpenGLFunctions();
is working fine in QOpenGLFunctions-derived classes but not with the
versioned ones.
To overcome this, start registering such instances to the context too.
QOpenGLContext::destroy() can then reset the internal state so a
subsequent initializeOpenGLFunctions() will reinitialize properly instead
of bailing out mistakenly thinking that everything is ready to use.
Task-number: QTBUG-45199
Change-Id: Ia1420bcccb33c51508698b7a1b036c7544a66e74
Reviewed-by: Sean Harmer <sean.harmer@kdab.com>
Diffstat (limited to 'src/gui')
-rw-r--r-- | src/gui/kernel/qopenglcontext.cpp | 29 | ||||
-rw-r--r-- | src/gui/kernel/qopenglcontext.h | 2 | ||||
-rw-r--r-- | src/gui/kernel/qopenglcontext_p.h | 1 | ||||
-rw-r--r-- | src/gui/opengl/qopenglversionfunctions.cpp | 26 | ||||
-rw-r--r-- | src/gui/opengl/qopenglversionfunctions.h | 13 |
5 files changed, 69 insertions, 2 deletions
diff --git a/src/gui/kernel/qopenglcontext.cpp b/src/gui/kernel/qopenglcontext.cpp index 90c54c4039..7fc9cceb60 100644 --- a/src/gui/kernel/qopenglcontext.cpp +++ b/src/gui/kernel/qopenglcontext.cpp @@ -636,12 +636,21 @@ void QOpenGLContext::destroy() d->platformGLContext = 0; delete d->functions; d->functions = 0; + + foreach (QAbstractOpenGLFunctions *func, d->externalVersionFunctions) { + QAbstractOpenGLFunctionsPrivate *func_d = QAbstractOpenGLFunctionsPrivate::get(func); + func_d->owningContext = 0; + func_d->initialized = false; + } + d->externalVersionFunctions.clear(); qDeleteAll(d->versionFunctions); d->versionFunctions.clear(); qDeleteAll(d->versionFunctionsBackend); d->versionFunctionsBackend.clear(); + delete d->textureFunctions; d->textureFunctions = 0; + d->nativeHandle = QVariant(); } @@ -719,7 +728,7 @@ QOpenGLFunctions *QOpenGLContext::functions() const QAbstractOpenGLFunctions::initializeOpenGLFunctions() as long as this context is current. It is also possible to call this function when the context is not current, but in that case it is the caller's responsibility to ensure proper - intiialization by calling QAbstractOpenGLFunctions::initializeOpenGLFunctions() + initialization by calling QAbstractOpenGLFunctions::initializeOpenGLFunctions() afterwards. Usually one would use the template version of this function to automatically @@ -1259,6 +1268,24 @@ void QOpenGLContext::removeFunctionsBackend(const QOpenGLVersionStatus &v) /*! \internal + */ +void QOpenGLContext::insertExternalFunctions(QAbstractOpenGLFunctions *f) +{ + Q_D(QOpenGLContext); + d->externalVersionFunctions.insert(f); +} + +/*! + \internal + */ +void QOpenGLContext::removeExternalFunctions(QAbstractOpenGLFunctions *f) +{ + Q_D(QOpenGLContext); + d->externalVersionFunctions.remove(f); +} + +/*! + \internal */ QOpenGLTextureHelper* QOpenGLContext::textureFunctions() const { diff --git a/src/gui/kernel/qopenglcontext.h b/src/gui/kernel/qopenglcontext.h index 30a9bc3ad9..a529957ad6 100644 --- a/src/gui/kernel/qopenglcontext.h +++ b/src/gui/kernel/qopenglcontext.h @@ -229,6 +229,8 @@ private: void insertFunctionsBackend(const QOpenGLVersionStatus &v, QOpenGLVersionFunctionsBackend *backend); void removeFunctionsBackend(const QOpenGLVersionStatus &v); + void insertExternalFunctions(QAbstractOpenGLFunctions *f); + void removeExternalFunctions(QAbstractOpenGLFunctions *f); QOpenGLTextureHelper* textureFunctions() const; void setTextureFunctions(QOpenGLTextureHelper* textureFuncs); diff --git a/src/gui/kernel/qopenglcontext_p.h b/src/gui/kernel/qopenglcontext_p.h index 446efa369c..5004ed6a8e 100644 --- a/src/gui/kernel/qopenglcontext_p.h +++ b/src/gui/kernel/qopenglcontext_p.h @@ -216,6 +216,7 @@ public: mutable QHash<QOpenGLVersionProfile, QAbstractOpenGLFunctions *> versionFunctions; mutable QHash<QOpenGLVersionStatus, QOpenGLVersionFunctionsBackend *> versionFunctionsBackend; + mutable QSet<QAbstractOpenGLFunctions *> externalVersionFunctions; void *qGLContextHandle; void (*qGLContextDeleteFunction)(void *handle); diff --git a/src/gui/opengl/qopenglversionfunctions.cpp b/src/gui/opengl/qopenglversionfunctions.cpp index f3f709c3f0..346a526054 100644 --- a/src/gui/opengl/qopenglversionfunctions.cpp +++ b/src/gui/opengl/qopenglversionfunctions.cpp @@ -67,6 +67,17 @@ void QAbstractOpenGLFunctionsPrivate::removeFunctionsBackend(QOpenGLContext *con context->removeFunctionsBackend(v); } +void QAbstractOpenGLFunctionsPrivate::insertExternalFunctions(QOpenGLContext *context, QAbstractOpenGLFunctions *f) +{ + Q_ASSERT(context); + context->insertExternalFunctions(f); +} + +void QAbstractOpenGLFunctionsPrivate::removeExternalFunctions(QOpenGLContext *context, QAbstractOpenGLFunctions *f) +{ + Q_ASSERT(context); + context->removeExternalFunctions(f); +} /*! \class QAbstractOpenGLFunctions @@ -182,6 +193,9 @@ QAbstractOpenGLFunctions::QAbstractOpenGLFunctions() QAbstractOpenGLFunctions::~QAbstractOpenGLFunctions() { + Q_D(QAbstractOpenGLFunctions); + if (d->owningContext) + d->removeExternalFunctions(d->owningContext, this); delete d_ptr; } @@ -191,6 +205,18 @@ bool QAbstractOpenGLFunctions::initializeOpenGLFunctions() { Q_D(QAbstractOpenGLFunctions); d->initialized = true; + + // For a subclass whose instance is not created via + // QOpenGLContext::versionFunctions() owningContext is not set. Set it now + // and register such instances to the context as external ones. These are + // not owned by the context but still need certain cleanup when the context + // is destroyed. + if (!d->owningContext) { + d->owningContext = QOpenGLContext::currentContext(); + if (d->owningContext) + d->insertExternalFunctions(d->owningContext, this); + } + return true; } diff --git a/src/gui/opengl/qopenglversionfunctions.h b/src/gui/opengl/qopenglversionfunctions.h index 2ae0f429e5..fcf665f97e 100644 --- a/src/gui/opengl/qopenglversionfunctions.h +++ b/src/gui/opengl/qopenglversionfunctions.h @@ -114,6 +114,8 @@ public: QAtomicInt refs; }; +class QAbstractOpenGLFunctions; + class QAbstractOpenGLFunctionsPrivate { public: @@ -128,12 +130,16 @@ public: const QOpenGLVersionStatus &v, QOpenGLVersionFunctionsBackend *backend); static void removeFunctionsBackend(QOpenGLContext *context, const QOpenGLVersionStatus &v); + static void insertExternalFunctions(QOpenGLContext *context, QAbstractOpenGLFunctions *f); + static void removeExternalFunctions(QOpenGLContext *context, QAbstractOpenGLFunctions *f); + + static QAbstractOpenGLFunctionsPrivate *get(QAbstractOpenGLFunctions *q); QOpenGLContext *owningContext; bool initialized; }; -class QAbstractOpenGLFunctions +class Q_GUI_EXPORT QAbstractOpenGLFunctions { public: virtual ~QAbstractOpenGLFunctions(); @@ -154,6 +160,11 @@ protected: friend class QOpenGLContext; }; +inline QAbstractOpenGLFunctionsPrivate *QAbstractOpenGLFunctionsPrivate::get(QAbstractOpenGLFunctions *q) +{ + return q->d_func(); +} + #if !defined(QT_OPENGL_ES_2) class QOpenGLFunctions_1_0_CoreBackend : public QOpenGLVersionFunctionsBackend |