Don't store texture references after the view has gone away
authorGunnar Sletta <gunnar.sletta@nokia.com>
Mon, 23 May 2011 10:45:12 +0000 (12:45 +0200)
committerGunnar Sletta <gunnar.sletta@nokia.com>
Mon, 23 May 2011 11:45:15 +0000 (13:45 +0200)
This is a partial fix only. We will eventually need to get
proper sharing of resources across multiple GL contexts, but this
fixes the autotest and will work for most usecases.

The task QTBUG-19455 has been created to solve it properly.

src/declarative/items/qsgborderimage.cpp
src/declarative/items/qsgcanvas.cpp
src/declarative/items/qsgimage.cpp
src/declarative/util/qdeclarativepixmapcache.cpp
src/declarative/util/qdeclarativepixmapcache_p.h
src/imports/particles/pictureaffector.cpp

index 108d87e..9a8a881 100644 (file)
@@ -322,7 +322,9 @@ QSGNode *QSGBorderImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *
 {
     Q_D(QSGBorderImage);
 
-    if (!d->pix.texture() || width() <= 0 || height() <= 0) {
+    QSGTexture *texture = d->pix.texture(d->sceneGraphContext());
+
+    if (!texture || width() <= 0 || height() <= 0) {
         delete oldNode;
         return 0;
     }
@@ -333,7 +335,7 @@ QSGNode *QSGBorderImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *
         node = new QSGNinePatchNode();
     }
 
-    node->setTexture(d->pix.texture());
+    node->setTexture(texture);
 
     const QSGScaleGrid *border = d->getScaleGrid();
     node->setInnerRect(QRectF(border->left(),
index d17df05..c0a5cef 100644 (file)
@@ -959,7 +959,19 @@ QSGCanvas::~QSGCanvas()
     delete d->rootItem; d->rootItem = 0;
     d->cleanupNodes();
 
+
+    // We need to remove all references to textures pointing to "our" QSGContext
+    // from the QDeclarativePixmapCache. Call into the cache to remove the GL / Scene Graph
+    // part of those cache entries.
+    // To "play nice" with other GL apps that are potentially running in the GUI thread,
+    // We get the current context and only temporarily make our own current
+    QGLContext *currentContext = const_cast<QGLContext *>(QGLContext::currentContext());
+    makeCurrent();
+    extern void qt_declarative_pixmapstore_clean(QSGContext *context);
+    qt_declarative_pixmapstore_clean(d->context);
     delete d->context;
+    if (currentContext)
+        currentContext->makeCurrent();
 }
 
 QSGItem *QSGCanvas::rootItem() const
index c77f7a4..706aaa7 100644 (file)
@@ -178,7 +178,7 @@ QRectF QSGImage::boundingRect() const
 QSGTexture *QSGImage::texture() const
 {
     Q_D(const QSGImage);
-    QSGTexture *t = d->pix.texture();
+    QSGTexture *t = d->pix.texture(d->sceneGraphContext());
     if (t) {
         t->setFiltering(QSGItemPrivate::get(this)->smooth ? QSGTexture::Linear : QSGTexture::Nearest);
         t->setMipmapFiltering(QSGTexture::None);
@@ -192,7 +192,9 @@ QSGNode *QSGImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
 {
     Q_D(QSGImage);
 
-    if (!d->pix.texture() || width() <= 0 || height() <= 0) {
+    QSGTexture *texture = d->pix.texture(d->sceneGraphContext());
+
+    if (!texture || width() <= 0 || height() <= 0) {
         delete oldNode;
         return 0;
     }
@@ -201,15 +203,14 @@ QSGNode *QSGImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
     if (!node) { 
         d->pixmapChanged = true;
         node = d->sceneGraphContext()->createImageNode();
-        node->setTexture(d->pix.texture());
+        node->setTexture(texture);
     }
 
     if (d->pixmapChanged) {
         // force update the texture in the node to trigger reconstruction of
         // geometry and the likes when a atlas segment has changed.
-        QSGTexture *t = d->pix.texture();
         node->setTexture(0);
-        node->setTexture(t);
+        node->setTexture(texture);
         d->pixmapChanged = false;
     }
 
index ef0c422..ddb0032 100644 (file)
@@ -103,7 +103,7 @@ public:
     class Event : public QEvent {
     public:
         Event(ReadError, const QString &, const QSize &, const QImage &image);
-        Event(ReadError, const QString &, const QSize &, QSGTexture *t, QSGContext *context);
+        Event(ReadError, const QString &, const QSize &, QSGTexture *t, QSGContext *context, const QImage &image);
 
         ReadError error;
         QString errorString;
@@ -113,7 +113,7 @@ public:
         QSGContext *context;
     };
     void postReply(ReadError, const QString &, const QSize &, const QImage &);
-    void postReply(ReadError, const QString &, const QSize &, QSGTexture *t, QSGContext *context);
+    void postReply(ReadError, const QString &, const QSize &, QSGTexture *t, QSGContext *context, const QImage &image);
 
 
 Q_SIGNALS:
@@ -211,9 +211,9 @@ public:
     {
     }
 
-    QDeclarativePixmapData(const QUrl &u, QSGTexture *t, QSGContext *c, const QSize &s, const QSize &r)
+    QDeclarativePixmapData(const QUrl &u, QSGTexture *t, QSGContext *c, const QPixmap &p, const QSize &s, const QSize &r)
     : refCount(1), inCache(false), privatePixmap(false), pixmapStatus(QDeclarativePixmap::Ready),
-      url(u), implicitSize(s), requestSize(r), texture(t), context(c), reply(0), prevUnreferenced(0),
+      url(u), pixmap(p), implicitSize(s), requestSize(r), texture(t), context(c), reply(0), prevUnreferenced(0),
       prevUnreferencedPtr(0), nextUnreferenced(0)
     {
     }
@@ -282,10 +282,10 @@ void QDeclarativePixmapReply::postReply(ReadError error, const QString &errorStr
 
 void QDeclarativePixmapReply::postReply(ReadError error, const QString &errorString,
                                         const QSize &implicitSize, QSGTexture *texture,
-                                        QSGContext *context)
+                                        QSGContext *context, const QImage &image)
 {
     loading = false;
-    QCoreApplication::postEvent(this, new Event(error, errorString, implicitSize, texture, context));
+    QCoreApplication::postEvent(this, new Event(error, errorString, implicitSize, texture, context, image));
 }
 
 QDeclarativePixmapReply::Event::Event(ReadError e, const QString &s, const QSize &iSize, const QImage &i)
@@ -293,8 +293,8 @@ QDeclarativePixmapReply::Event::Event(ReadError e, const QString &s, const QSize
 {
 }
 
-QDeclarativePixmapReply::Event::Event(ReadError e, const QString &s, const QSize &iSize, QSGTexture *t, QSGContext *c)
-    : QEvent(QEvent::User), error(e), errorString(s), implicitSize(iSize), texture(t), context(c)
+QDeclarativePixmapReply::Event::Event(ReadError e, const QString &s, const QSize &iSize, QSGTexture *t, QSGContext *c, const QImage &i)
+    : QEvent(QEvent::User), error(e), errorString(s), implicitSize(iSize), image(i), texture(t), context(c)
 {
 }
 
@@ -419,7 +419,7 @@ void QDeclarativePixmapReader::networkRequestDone(QNetworkReply *reply)
         mutex.lock();
         if (!cancelled.contains(job)) {
             if (texture)
-                job->postReply(error, errorString, readSize, texture, ctx);
+                job->postReply(error, errorString, readSize, texture, ctx, image);
             else
                 job->postReply(error, errorString, readSize, image);
         } else {
@@ -514,7 +514,7 @@ void QDeclarativePixmapReader::processJob(QDeclarativePixmapReply *runningJob, c
             mutex.lock();
             if (!cancelled.contains(runningJob)) {
                 if (sgContext)
-                    runningJob->postReply(errorCode, errorStr, readSize, sgContext->createTexture(image), sgContext);
+                    runningJob->postReply(errorCode, errorStr, readSize, sgContext->createTexture(image), sgContext, image);
                 else
                     runningJob->postReply(errorCode, errorStr, readSize, image);
             }
@@ -530,7 +530,7 @@ void QDeclarativePixmapReader::processJob(QDeclarativePixmapReply *runningJob, c
             mutex.lock();
             if (!cancelled.contains(runningJob)) {
                 if (sgContext)
-                    runningJob->postReply(errorCode, errorStr, readSize, sgContext->createTexture(image), sgContext);
+                    runningJob->postReply(errorCode, errorStr, readSize, sgContext->createTexture(image), sgContext, image);
                 else
                     runningJob->postReply(errorCode, errorStr, readSize, image);
             }
@@ -545,7 +545,7 @@ void QDeclarativePixmapReader::processJob(QDeclarativePixmapReply *runningJob, c
             }
             mutex.lock();
             if (!cancelled.contains(runningJob))
-                runningJob->postReply(errorCode, errorStr, readSize, t, sgContext);
+                runningJob->postReply(errorCode, errorStr, readSize, t, sgContext, QImage());
             mutex.unlock();
 
         }
@@ -577,7 +577,7 @@ void QDeclarativePixmapReader::processJob(QDeclarativePixmapReply *runningJob, c
             mutex.lock();
             if (!cancelled.contains(runningJob)) {
                 if (texture)
-                    runningJob->postReply(errorCode, errorStr, readSize, texture, sgContext);
+                    runningJob->postReply(errorCode, errorStr, readSize, texture, sgContext, image);
                 else
                     runningJob->postReply(errorCode, errorStr, readSize, image);
             } else {
@@ -678,6 +678,8 @@ inline uint qHash(const QDeclarativePixmapKey &key)
     return qHash(*key.url) ^ key.size->width() ^ key.size->height();
 }
 
+class QSGContext;
+
 class QDeclarativePixmapStore : public QObject
 {
     Q_OBJECT
@@ -693,6 +695,9 @@ protected:
 public:
     QHash<QDeclarativePixmapKey, QDeclarativePixmapData *> m_cache;
 
+    void cleanTexturesForContext(QSGContext *context);
+    void cleanTextureForContext(QDeclarativePixmapData *data);
+
 private:
     void shrinkCache(int remove);
 
@@ -704,11 +709,52 @@ private:
 };
 Q_GLOBAL_STATIC(QDeclarativePixmapStore, pixmapStore);
 
+
+void qt_declarative_pixmapstore_clean(QSGContext *context)
+{
+    pixmapStore()->cleanTexturesForContext(context);
+}
+
+
 QDeclarativePixmapStore::QDeclarativePixmapStore()
 : m_unreferencedPixmaps(0), m_lastUnreferencedPixmap(0), m_unreferencedCost(0), m_timerId(-1)
 {
 }
 
+void QDeclarativePixmapStore::cleanTextureForContext(QDeclarativePixmapData *data)
+{
+    if (data->context) {
+        Q_ASSERT(QGLContext::currentContext());
+        delete data->texture;
+        data->context = 0;
+        data->texture = 0;
+    }
+}
+
+void QDeclarativePixmapStore::cleanTexturesForContext(QSGContext *context)
+{
+    QDeclarativePixmapData *data = m_unreferencedPixmaps;
+    while (data) {
+        if (data->context == context)
+            cleanTextureForContext(data);
+        if (data == m_lastUnreferencedPixmap)
+            break;
+        data = data->nextUnreferenced;
+    }
+
+    QHash<QDeclarativePixmapKey, QDeclarativePixmapData *>::iterator it = m_cache.begin();
+    while (it != m_cache.end()) {
+        data = *it;
+        if (data->context == context) {
+            cleanTextureForContext(data);
+        }
+        ++it;
+    }
+
+}
+
+
+
 void QDeclarativePixmapStore::unreferencePixmap(QDeclarativePixmapData *data)
 {
     Q_ASSERT(data->prevUnreferenced == 0);
@@ -896,7 +942,7 @@ static QDeclarativePixmapData* createPixmapDataSync(QDeclarativeEngine *engine,
                 QSGTexture *texture = ep->getTextureFromProvider(url, &readSize, requestSize);
                 if (texture) {
                     *ok = true;
-                    return new QDeclarativePixmapData(url, texture, sgContext, readSize, requestSize);
+                    return new QDeclarativePixmapData(url, texture, sgContext, QPixmap(), readSize, requestSize);
                 }
             }
 
@@ -907,7 +953,7 @@ static QDeclarativePixmapData* createPixmapDataSync(QDeclarativeEngine *engine,
                     *ok = true;
                     if (sgContext) {
                         QSGTexture *t = sgContext->createTexture(image);
-                        return new QDeclarativePixmapData(url, t, sgContext,readSize, requestSize);
+                        return new QDeclarativePixmapData(url, t, sgContext, QPixmap::fromImage(image), readSize, requestSize);
                     }
                     return new QDeclarativePixmapData(url, QPixmap::fromImage(image), readSize, requestSize);
                 }
@@ -919,7 +965,7 @@ static QDeclarativePixmapData* createPixmapDataSync(QDeclarativeEngine *engine,
                     *ok = true;
                     if (sgContext) {
                         QSGTexture *t = sgContext->createTexture(pixmap.toImage());
-                        return new QDeclarativePixmapData(url, t, sgContext,readSize, requestSize);
+                        return new QDeclarativePixmapData(url, t, sgContext, pixmap, readSize, requestSize);
                     }
                     return new QDeclarativePixmapData(url, pixmap, readSize, requestSize);
                 }
@@ -959,7 +1005,7 @@ static QDeclarativePixmapData* createPixmapDataSync(QDeclarativeEngine *engine,
         }
 
         if (texture)
-            return new QDeclarativePixmapData(url, texture, ctx, readSize, requestSize);
+            return new QDeclarativePixmapData(url, texture, ctx, QPixmap::fromImage(image), readSize, requestSize);
         else
             return new QDeclarativePixmapData(url, QPixmap::fromImage(image), readSize, requestSize);
 
@@ -1062,9 +1108,17 @@ const QSize &QDeclarativePixmap::requestSize() const
         return nullPixmap()->size;
 }
 
-QSGTexture *QDeclarativePixmap::texture() const
+QSGTexture *QDeclarativePixmap::texture(QSGContext *context) const
 {
-    return d ? d->texture : 0;
+    if (d) {
+        if (d->texture)
+            return d->texture;
+        else if (d->pixmapStatus == Ready) {
+            d->texture = context->createTexture(d->pixmap.toImage());
+            return d->texture;
+        }
+    }
+    return 0;
 }
 
 const QPixmap &QDeclarativePixmap::pixmap() const
index b917693..84d22d6 100644 (file)
@@ -56,6 +56,7 @@ QT_MODULE(Declarative)
 class QDeclarativeEngine;
 class QDeclarativePixmapData;
 class QSGTexture;
+class QSGContext;
 
 class Q_DECLARATIVE_EXPORT QDeclarativePixmap
 {
@@ -87,7 +88,7 @@ public:
     const QPixmap &pixmap() const;
     void setPixmap(const QPixmap &);
 
-    QSGTexture *texture() const;
+    QSGTexture *texture(QSGContext *context) const;
 
     QRect rect() const;
     int width() const;
index d684b3f..636e26b 100644 (file)
@@ -72,9 +72,7 @@ void PictureAffector::startLoadImage()
 }
 void PictureAffector::loadImage()
 {
-    QSGPlainTexture* ptext = qobject_cast<QSGPlainTexture*>(m_pix->texture());
-    if(ptext)
-        m_loadedImage = ptext->image();
+    m_loadedImage = m_pix->pixmap().toImage();
     if(m_loadedImage.isNull())
         qWarning() << "PictureAffector could not load picture " << m_image;
 }