diff options
author | Kim Motoyoshi Kalland <kim.kalland@nokia.com> | 2009-07-20 10:41:47 (GMT) |
---|---|---|
committer | Kim Motoyoshi Kalland <kim.kalland@nokia.com> | 2009-07-21 13:54:48 (GMT) |
commit | 8c97cd7a91e99a2665e871efe1bf577e33eaff3a (patch) | |
tree | 3464c28b1f850d6d1d194bb881f3cdecaa9daab1 /src/opengl/qgl.cpp | |
parent | 40649c420601bcc1f639fc8b337bfd7375d2b37e (diff) | |
download | Qt-8c97cd7a91e99a2665e871efe1bf577e33eaff3a.zip Qt-8c97cd7a91e99a2665e871efe1bf577e33eaff3a.tar.gz Qt-8c97cd7a91e99a2665e871efe1bf577e33eaff3a.tar.bz2 |
Fixed GL2 engine shader manager to work with more than one context.
I added a QGLContextResource class which can be used internally in Qt
for sharing resources between contexts. The QGLContextResource is a
hash map where the context is used as 'key', and the resource is the
'value'. All the sharing contexts point to the same resource, and the
resource is automatically deleted when it is not referenced any more.
Now, the shader manager uses the QGLContextResource class.
I also added a pointer to a struct in the QGLContextPrivate class. The
struct is shared between all the sharing contexts and is deleted
automatically. Currently, the struct only contains the resolved OpenGL
function pointers.
The shared context register code has been simplified.
Reviewed-by: Tom
Diffstat (limited to 'src/opengl/qgl.cpp')
-rw-r--r-- | src/opengl/qgl.cpp | 159 |
1 files changed, 158 insertions, 1 deletions
diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp index 0169ea2..f51b271 100644 --- a/src/opengl/qgl.cpp +++ b/src/opengl/qgl.cpp @@ -3363,8 +3363,13 @@ bool QGLWidget::event(QEvent *e) #elif defined(Q_WS_WIN) if (e->type() == QEvent::ParentChange) { QGLContext *newContext = new QGLContext(d->glcx->requestedFormat(), this); - qgl_share_reg()->replaceShare(d->glcx, newContext); + QList<const QGLContext *> shares = qgl_share_reg()->shares(d->glcx); setContext(newContext); + for (int i = 0; i < shares.size(); ++i) { + if (newContext != shares.at(i)) + qgl_share_reg()->addShare(newContext, shares.at(i)); + } + // the overlay needs to be recreated as well delete d->olcx; if (isValid() && context()->format().hasOverlay()) { @@ -4612,4 +4617,156 @@ bool QGLDrawable::autoFillBackground() const return false; } + +bool QGLShareRegister::checkSharing(const QGLContext *context1, const QGLContext *context2) { + bool sharing = (context1 && context2 && context1->d_ptr->groupResources == context2->d_ptr->groupResources); + return sharing; +} + +void QGLShareRegister::addShare(const QGLContext *context, const QGLContext *share) { + Q_ASSERT(context && share); + if (context->d_ptr->groupResources == share->d_ptr->groupResources) + return; + + // Make sure 'context' is not already shared with another group of contexts. + Q_ASSERT(reg.find(context->d_ptr->groupResources) == reg.end()); + Q_ASSERT(context->d_ptr->groupResources->refs == 1); + + // Free 'context' group resources and make it use the same resources as 'share'. + delete context->d_ptr->groupResources; + context->d_ptr->groupResources = share->d_ptr->groupResources; + context->d_ptr->groupResources->refs.ref(); + + // Maintain a list of all the contexts in each group of sharing contexts. + SharingHash::iterator it = reg.find(share->d_ptr->groupResources); + if (it == reg.end()) + it = reg.insert(share->d_ptr->groupResources, ContextList() << share); + it.value() << context; +} + +QList<const QGLContext *> QGLShareRegister::shares(const QGLContext *context) { + SharingHash::const_iterator it = reg.find(context->d_ptr->groupResources); + if (it == reg.end()) + return ContextList(); + return it.value(); +} + +void QGLShareRegister::removeShare(const QGLContext *context) { + SharingHash::iterator it = reg.find(context->d_ptr->groupResources); + if (it == reg.end()) + return; + + int count = it.value().removeAll(context); + Q_ASSERT(count == 1); + + Q_ASSERT(it.value().size() != 0); + if (it.value().size() == 1) + reg.erase(it); +} + +QGLContextResource::QGLContextResource(FreeFunc f, QObject *parent) + : QObject(parent), free(f) +{ + connect(QGLSignalProxy::instance(), SIGNAL(aboutToDestroyContext(const QGLContext *)), this, SLOT(aboutToDestroyContext(const QGLContext *))); +} + +QGLContextResource::~QGLContextResource() +{ + while (!m_resources.empty()) + remove(m_resources.begin().key()); +} + +void QGLContextResource::insert(const QGLContext *key, void *value) +{ + QList<const QGLContext *> shares = qgl_share_reg()->shares(key); + if (shares.size() == 0) + shares.append(key); + void *oldValue = 0; + for (int i = 0; i < shares.size(); ++i) { + ResourceHash::iterator it = m_resources.find(shares.at(i)); + if (it != m_resources.end()) { + Q_ASSERT(oldValue == 0 || oldValue == it.value()); + oldValue = it.value(); + it.value() = value; + } else { + m_resources.insert(shares.at(i), value); + } + } + if (oldValue != 0 && oldValue != value) { + QGLContext *oldContext = const_cast<QGLContext *>(QGLContext::currentContext()); + if (oldContext != key) + const_cast<QGLContext *>(key)->makeCurrent(); + free(oldValue); + if (oldContext && oldContext != key) + oldContext->makeCurrent(); + } +} + +void *QGLContextResource::value(const QGLContext *key) +{ + ResourceHash::const_iterator it = m_resources.find(key); + // Check if there is a value associated with 'key'. + if (it != m_resources.end()) + return it.value(); + // Check if there is a value associated with sharing contexts. + QList<const QGLContext *> shares = qgl_share_reg()->shares(key); + for (int i = 0; i < shares.size() && it == m_resources.end(); ++i) + it = m_resources.find(shares.at(i)); + if (it == m_resources.end()) + return 0; // Didn't find anything. + + // Found something! Share this info with all the buddies. + for (int i = 0; i < shares.size(); ++i) + m_resources.insert(shares.at(i), it.value()); + return it.value(); +} + +void QGLContextResource::remove(const QGLContext *key) +{ + QList<const QGLContext *> shares = qgl_share_reg()->shares(key); + if (shares.size() == 0) + shares.append(key); + void *oldValue = 0; + for (int i = 0; i < shares.size(); ++i) { + ResourceHash::iterator it = m_resources.find(shares.at(i)); + if (it != m_resources.end()) { + Q_ASSERT(oldValue == 0 || oldValue == it.value()); + oldValue = it.value(); + m_resources.erase(it); + } + } + if (oldValue != 0) { + QGLContext *oldContext = const_cast<QGLContext *>(QGLContext::currentContext()); + if (oldContext != key) + const_cast<QGLContext *>(key)->makeCurrent(); + free(oldValue); + if (oldContext && oldContext != key) + oldContext->makeCurrent(); + } +} + +void QGLContextResource::aboutToDestroyContext(const QGLContext *key) +{ + ResourceHash::iterator it = m_resources.find(key); + if (it == m_resources.end()) + return; + + QList<const QGLContext *> shares = qgl_share_reg()->shares(key); + if (shares.size() > 1) { + Q_ASSERT(key->isSharing()); + // At least one of the shared contexts must stay in the cache. + // Otherwise, the value pointer is lost. + for (int i = 0; i < 2/*shares.size()*/; ++i) + m_resources.insert(shares.at(i), it.value()); + } else { + QGLContext *oldContext = const_cast<QGLContext *>(QGLContext::currentContext()); + if (oldContext != key) + const_cast<QGLContext *>(key)->makeCurrent(); + free(it.value()); + if (oldContext && oldContext != key) + oldContext->makeCurrent(); + } + m_resources.erase(it); +} + QT_END_NAMESPACE |