Reintroduce the QSGTextureProvider as a separate object
authorGunnar Sletta <gunnar.sletta@nokia.com>
Mon, 22 Aug 2011 07:25:51 +0000 (09:25 +0200)
committerKim M. Kalland <kim.kalland@nokia.com>
Mon, 22 Aug 2011 10:16:26 +0000 (12:16 +0200)
The texture provider needs to live completely in the rendering thread
and needs to be selfcontained during rendering. During the items
updatePaintNode() all needed state is copied into the texture
provider. Texture providers have thread affinity in the rendering
thread and are deleted there using deleteLater() and the added
processEvents() in the rendering loop.

This fixes the bug where a QSGItem is deleted as a result from an
animation while the same item is being used as a texture provider in
the rendering thread.

There is also a small optimzation to QSGShaderEffectSource
in that we don't create a paint node when the shader source is
not going to be shown.

Change-Id: I6b9bc1da2a0f55d3d5356d4091fd6af6a7ea6f01
Reviewed-on: http://codereview.qt.nokia.com/3293
Reviewed-by: Qt Sanity Bot <qt_sanity_bot@ovi.com>
Reviewed-by: Kim M. Kalland <kim.kalland@nokia.com>
13 files changed:
src/declarative/items/qsgcanvas.cpp
src/declarative/items/qsgimage.cpp
src/declarative/items/qsgimage_p.h
src/declarative/items/qsgimage_p_p.h
src/declarative/items/qsgshadereffect.cpp
src/declarative/items/qsgshadereffect_p.h
src/declarative/items/qsgshadereffectnode.cpp
src/declarative/items/qsgshadereffectnode_p.h
src/declarative/items/qsgshadereffectsource.cpp
src/declarative/items/qsgshadereffectsource_p.h
src/declarative/particles/qsgcustomparticle.cpp
src/declarative/scenegraph/util/qsgtextureprovider.cpp
src/declarative/scenegraph/util/qsgtextureprovider_p.h

index 48ed443..1caee4f 100644 (file)
@@ -1963,6 +1963,9 @@ void QSGCanvasRenderThread::run()
         }
 
         unlock();
+
+        // Process any "deleteLater" objects...
+        QCoreApplication::processEvents();
     }
 
 #ifdef THREAD_DEBUG
index ed55104..48cefb5 100644 (file)
@@ -42,6 +42,8 @@
 #include "qsgimage_p.h"
 #include "qsgimage_p_p.h"
 
+#include <private/qsgtextureprovider_p.h>
+
 #include <private/qsgcontext_p.h>
 #include <private/qsgadaptationlayer_p.h>
 
 
 QT_BEGIN_NAMESPACE
 
+class QSGImageTextureProvider : public QSGTextureProvider
+{
+    Q_OBJECT
+public:
+    QSGImageTextureProvider(const QSGImage *imageItem)
+        : d((QSGImagePrivate *) QSGItemPrivate::get(imageItem))
+        , m_texture(0)
+        , m_smooth(false)
+    {
+    }
+
+    QSGTexture *texture() const {
+        if (m_texture) {
+            m_texture->setFiltering(m_smooth ? QSGTexture::Linear : QSGTexture::Nearest);
+            m_texture->setMipmapFiltering(QSGTexture::Nearest);
+            m_texture->setHorizontalWrapMode(QSGTexture::ClampToEdge);
+            m_texture->setVerticalWrapMode(QSGTexture::ClampToEdge);
+        }
+        return m_texture;
+    }
+
+    friend class QSGImage;
+
+    QSGImagePrivate *d;
+    QSGTexture *m_texture;
+    bool m_smooth;
+};
+
+#include "qsgimage.moc"
+
 QSGImagePrivate::QSGImagePrivate()
     : fillMode(QSGImage::Stretch)
     , paintedWidth(0)
@@ -57,6 +89,7 @@ QSGImagePrivate::QSGImagePrivate()
     , pixmapChanged(false)
     , hAlign(QSGImage::AlignHCenter)
     , vAlign(QSGImage::AlignVCenter)
+    , provider(0)
 {
 }
 
@@ -128,6 +161,9 @@ QSGImage::QSGImage(QSGImagePrivate &dd, QSGItem *parent)
 
 QSGImage::~QSGImage()
 {
+    Q_D(QSGImage);
+    if (d->provider)
+        d->provider->deleteLater();
 }
 
 void QSGImagePrivate::setPixmap(const QPixmap &pixmap)
@@ -504,17 +540,19 @@ QRectF QSGImage::boundingRect() const
     return QRectF(0, 0, qMax(width(), d->paintedWidth), qMax(height(), d->paintedHeight));
 }
 
-QSGTexture *QSGImage::texture() const
+QSGTextureProvider *QSGImage::textureProvider() const
 {
     Q_D(const QSGImage);
-    QSGTexture *t = d->pix.texture(d->sceneGraphContext());
-    if (t) {
-        t->setFiltering(QSGItemPrivate::get(this)->smooth ? QSGTexture::Linear : QSGTexture::Nearest);
-        t->setMipmapFiltering(QSGTexture::None);
-        t->setHorizontalWrapMode(QSGTexture::ClampToEdge);
-        t->setVerticalWrapMode(QSGTexture::ClampToEdge);
+    if (!d->provider) {
+        Q_ASSERT(d->sceneGraphContext());
+        // Make sure it gets thread affinity on the rendering thread so deletion works properly..
+        Q_ASSERT_X(QThread::currentThread() == d->sceneGraphContext()->thread(),
+                   "QSGImage::textureProvider",
+                   "Cannot be used outside the GUI thread");
+        const_cast<QSGImagePrivate *>(d)->provider = new QSGImageTextureProvider(this);
     }
-    return t;
+
+    return d->provider;
 }
 
 QSGNode *QSGImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
@@ -523,6 +561,12 @@ QSGNode *QSGImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
 
     QSGTexture *texture = d->pix.texture(d->sceneGraphContext());
 
+    // Copy over the current texture state into the texture provider...
+    if (d->provider) {
+        d->provider->m_smooth = d->smooth;
+        d->provider->m_texture = texture;
+    }
+
     if (!texture || width() <= 0 || height() <= 0) {
         delete oldNode;
         return 0;
index 4faf96d..b49447f 100644 (file)
@@ -53,7 +53,7 @@ QT_BEGIN_NAMESPACE
 QT_MODULE(Declarative)
 
 class QSGImagePrivate;
-class Q_AUTOTEST_EXPORT QSGImage : public QSGImageBase, public QSGTextureProvider
+class Q_AUTOTEST_EXPORT QSGImage : public QSGImageBase
 {
     Q_OBJECT
     Q_ENUMS(FillMode)
@@ -63,12 +63,9 @@ class Q_AUTOTEST_EXPORT QSGImage : public QSGImageBase, public QSGTextureProvide
     Q_PROPERTY(FillMode fillMode READ fillMode WRITE setFillMode NOTIFY fillModeChanged)
     Q_PROPERTY(qreal paintedWidth READ paintedWidth NOTIFY paintedGeometryChanged)
     Q_PROPERTY(qreal paintedHeight READ paintedHeight NOTIFY paintedGeometryChanged)
-    Q_PROPERTY(QSGTexture *texture READ texture)
     Q_PROPERTY(HAlignment horizontalAlignment READ horizontalAlignment WRITE setHorizontalAlignment NOTIFY horizontalAlignmentChanged)
     Q_PROPERTY(VAlignment verticalAlignment READ verticalAlignment WRITE setVerticalAlignment NOTIFY verticalAlignmentChanged)
 
-    Q_INTERFACES(QSGTextureProvider)
-
 public:
     QSGImage(QSGItem *parent=0);
     ~QSGImage();
@@ -90,14 +87,14 @@ public:
 
     QRectF boundingRect() const;
 
-    virtual QSGTexture *texture() const;
-
     HAlignment horizontalAlignment() const;
     void setHorizontalAlignment(HAlignment align);
 
     VAlignment verticalAlignment() const;
     void setVerticalAlignment(VAlignment align);
 
+    QSGTextureProvider *textureProvider() const;
+
 Q_SIGNALS:
     void fillModeChanged();
     void paintedGeometryChanged();
index d0b1099..9f8b971 100644 (file)
@@ -59,7 +59,7 @@
 
 QT_BEGIN_NAMESPACE
 
-class QSGImagePrivate;
+class QSGImageTextureProvider;
 
 class QSGImagePrivate : public QSGImageBasePrivate
 {
@@ -76,6 +76,8 @@ public:
     bool pixmapChanged : 1;
     QSGImage::HAlignment hAlign;
     QSGImage::VAlignment vAlign;
+
+    QSGImageTextureProvider *provider;
 };
 
 QT_END_NAMESPACE
index 97fe249..97cc898 100644 (file)
@@ -49,6 +49,9 @@
 #include <private/qsgtextureprovider_p.h>
 #include "qsgcanvas.h"
 
+#include <qsgimage_p.h>
+#include <qsgshadereffectsource_p.h>
+
 #include <QtCore/qsignalmapper.h>
 #include <QtOpenGL/qglframebufferobject.h>
 
@@ -402,7 +405,7 @@ void QSGShaderEffect::setSource(const QVariant &var, int index)
 
     SourceData &source = m_sources[index];
 
-    source.item = 0;
+    source.sourceObject = 0;
     if (var.isNull()) {
         return;
     } else if (!qVariantCanConvert<QObject *>(var)) {
@@ -411,21 +414,23 @@ void QSGShaderEffect::setSource(const QVariant &var, int index)
     }
 
     QObject *obj = qVariantValue<QObject *>(var);
-
-    QSGTextureProvider *int3rface = QSGTextureProvider::from(obj);
-    if (!int3rface) {
-        qWarning("Could not assign property '%s', did not implement QSGTextureProvider.", source.name.constData());
+    if (!QSGTextureProvider::from(obj)) {
+        qWarning("ShaderEffect: source uniform [%s] is not assigned a valid texture provider: %s [%s]",
+                 qPrintable(source.name), qPrintable(obj->objectName()), obj->metaObject()->className());
+        return;
     }
 
-    source.item = qobject_cast<QSGItem *>(obj);
+    source.sourceObject = obj;
+
+    QSGItem *item = qobject_cast<QSGItem *>(obj);
 
     // TODO: Find better solution.
-    // 'source.item' needs a canvas to get a scenegraph node.
+    // 'item' needs a canvas to get a scenegraph node.
     // The easiest way to make sure it gets a canvas is to
     // make it a part of the same item tree as 'this'.
-    if (source.item && source.item->parentItem() == 0) {
-        source.item->setParentItem(this);
-        source.item->setVisible(false);
+    if (item && item->parentItem() == 0) {
+        item->setParentItem(this);
+        item->setVisible(false);
     }
 }
 
@@ -484,8 +489,9 @@ void QSGShaderEffect::reset()
     for (int i = 0; i < m_sources.size(); ++i) {
         const SourceData &source = m_sources.at(i);
         delete source.mapper;
-        if (source.item && source.item->parentItem() == this)
-            source.item->setParentItem(0);
+        QSGItem *item = qobject_cast<QSGItem *>(source.sourceObject);
+        if (item && item->parentItem() == this)
+            item->setParentItem(0);
     }
     m_sources.clear();
 
@@ -558,7 +564,7 @@ void QSGShaderEffect::lookThroughShaderCode(const QByteArray &code)
                     SourceData d;
                     d.mapper = new QSignalMapper;
                     d.name = name;
-                    d.item = 0;
+                    d.sourceObject = 0;
                     m_sources.append(d);
                 }
             }
@@ -635,24 +641,24 @@ QSGNode *QSGShaderEffect::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData
 
     if (m_dirtyData) {
         QVector<QPair<QByteArray, QVariant> > values;
-        QVector<QPair<QByteArray, QPointer<QSGItem> > > textures;
-        const QVector<QPair<QByteArray, QPointer<QSGItem> > > &oldTextures = material->textureProviders();
+        QVector<QPair<QByteArray, QSGTextureProvider *> > textures;
+        const QVector<QPair<QByteArray, QSGTextureProvider *> > &oldTextures = material->textureProviders();
 
         for (QSet<QByteArray>::const_iterator it = m_source.uniformNames.begin(); 
              it != m_source.uniformNames.end(); ++it) {
             values.append(qMakePair(*it, property(*it)));
         }
         for (int i = 0; i < oldTextures.size(); ++i) {
-            QSGTextureProvider *oldSource = QSGTextureProvider::from(oldTextures.at(i).second);
-            if (oldSource && oldSource->textureChangedSignal())
-                disconnect(oldTextures.at(i).second, oldSource->textureChangedSignal(), node, SLOT(markDirtyTexture()));
+            QSGTextureProvider *t = oldTextures.at(i).second;
+            if (t)
+                disconnect(t, SIGNAL(textureChanged()), node, SLOT(markDirtyTexture()));
         }
         for (int i = 0; i < m_sources.size(); ++i) {
             const SourceData &source = m_sources.at(i);
-            textures.append(qMakePair(source.name, source.item));
-            QSGTextureProvider *t = QSGTextureProvider::from(source.item);
-            if (t && t->textureChangedSignal())
-                connect(source.item, t->textureChangedSignal(), node, SLOT(markDirtyTexture()), Qt::DirectConnection);
+            QSGTextureProvider *t = QSGTextureProvider::from(source.sourceObject);
+            textures.append(qMakePair(source.name, t));
+            if (t)
+                connect(t, SIGNAL(textureChanged()), node, SLOT(markDirtyTexture()), Qt::DirectConnection);
         }
         material->setUniforms(values);
         material->setTextureProviders(textures);
index c72441c..556ff9b 100644 (file)
@@ -138,7 +138,7 @@ private:
     struct SourceData
     {
         QSignalMapper *mapper;
-        QPointer<QSGItem> item;
+        QPointer<QObject> sourceObject;
         QByteArray name;
     };
     QVector<SourceData> m_sources;
index f86b4cb..d51317a 100644 (file)
@@ -110,15 +110,15 @@ void QSGCustomMaterialShader::updateState(const RenderState &state, QSGMaterial
 
     QGLFunctions *functions = state.context()->functions();
     for (int i = material->m_textures.size() - 1; i >= 0; --i) {
-        QPointer<QSGItem> source = material->m_textures.at(i).second;
-        QSGTextureProvider *provider = QSGTextureProvider::from(source);
-        QSGTexture *texture = provider ? provider->texture() : 0;
-        if (!source || !provider || !texture) {
-            qWarning("ShaderEffectItem: source or provider missing when binding textures");
-            continue;
-        }
         functions->glActiveTexture(GL_TEXTURE0 + i);
-        provider->texture()->bind();
+        if (QSGTextureProvider *provider = material->m_textures.at(i).second) {
+            if (QSGTexture *texture = provider->texture()) {
+                texture->bind();
+                continue;
+            }
+        }
+        qWarning("ShaderEffectItem: source or provider missing when binding textures");
+        glBindTexture(GL_TEXTURE_2D, 0);
     }
 
     if (material->m_source.respectsOpacity)
@@ -271,12 +271,12 @@ void QSGShaderEffectMaterial::setUniforms(const QVector<QPair<QByteArray, QVaria
     m_uniformValues = uniformValues;
 }
 
-void QSGShaderEffectMaterial::setTextureProviders(const QVector<QPair<QByteArray, QPointer<QSGItem> > > &textures)
+void QSGShaderEffectMaterial::setTextureProviders(const QVector<QPair<QByteArray, QSGTextureProvider *> > &textures)
 {
     m_textures = textures;
 }
 
-const QVector<QPair<QByteArray, QPointer<QSGItem> > > &QSGShaderEffectMaterial::textureProviders() const
+const QVector<QPair<QByteArray, QSGTextureProvider *> > &QSGShaderEffectMaterial::textureProviders() const
 {
     return m_textures;
 }
@@ -284,20 +284,9 @@ const QVector<QPair<QByteArray, QPointer<QSGItem> > > &QSGShaderEffectMaterial::
 void QSGShaderEffectMaterial::updateTextures() const
 {
     for (int i = 0; i < m_textures.size(); ++i) {
-        QSGItem *item = m_textures.at(i).second;
-        if (item) {
-            QSGTextureProvider *provider = QSGTextureProvider::from(item);
-            if (provider) {
-                QSGTexture *texture = provider->texture();
-                if (!texture) {
-                    qWarning("QSGShaderEffectMaterial: no texture from %s [%s]",
-                             qPrintable(item->objectName()),
-                             item->metaObject()->className());
-                }
-                if (QSGDynamicTexture *t = qobject_cast<QSGDynamicTexture *>(provider->texture())) {
-                    t->updateTexture();
-                }
-            }
+        if (QSGTextureProvider *provider = m_textures.at(i).second) {
+            if (QSGDynamicTexture *texture = qobject_cast<QSGDynamicTexture *>(provider->texture()))
+                texture->updateTexture();
         }
     }
 }
index 4623cac..d95dfaf 100644 (file)
@@ -100,8 +100,8 @@ public:
 
     void setProgramSource(const QSGShaderEffectProgram &);
     void setUniforms(const QVector<QPair<QByteArray, QVariant> > &uniformValues);
-    void setTextureProviders(const QVector<QPair<QByteArray, QPointer<QSGItem> > > &textures);
-    const QVector<QPair<QByteArray, QPointer<QSGItem> > > &textureProviders() const;
+    void setTextureProviders(const QVector<QPair<QByteArray, QSGTextureProvider *> > &textures);
+    const QVector<QPair<QByteArray, QSGTextureProvider *> > &textureProviders() const;
     void updateTextures() const;
 
 protected:
@@ -118,7 +118,7 @@ protected:
 
     QSGShaderEffectProgram m_source;
     QVector<QPair<QByteArray, QVariant> > m_uniformValues;
-    QVector<QPair<QByteArray, QPointer<QSGItem> > > m_textures;
+    QVector<QPair<QByteArray, QSGTextureProvider *> > m_textures;
     CullMode m_cullMode;
 
     static QHash<QSGShaderEffectMaterialKey, QSharedPointer<QSGMaterialType> > materialMap;
@@ -143,8 +143,6 @@ private Q_SLOTS:
 
 private:
     QSGShaderEffectMaterial m_material;
-
-
 };
 
 QT_END_NAMESPACE
index d2854e6..2458007 100644 (file)
@@ -54,6 +54,33 @@ QT_BEGIN_NAMESPACE
 
 DEFINE_BOOL_CONFIG_OPTION(qmlFboOverlay, QML_FBO_OVERLAY)
 
+class QSGShaderEffectSourceTextureProvider : public QSGTextureProvider
+{
+    Q_OBJECT
+public:
+    QSGShaderEffectSourceTextureProvider()
+        : sourceTexture(0)
+    {
+    }
+
+    QSGTexture *texture() const {
+        sourceTexture->setMipmapFiltering(mipmapFiltering);
+        sourceTexture->setFiltering(filtering);
+        sourceTexture->setHorizontalWrapMode(horizontalWrap);
+        sourceTexture->setVerticalWrapMode(verticalWrap);
+        return sourceTexture;
+    }
+
+    QSGShaderEffectTexture *sourceTexture;
+
+    QSGTexture::Filtering mipmapFiltering;
+    QSGTexture::Filtering filtering;
+    QSGTexture::WrapMode horizontalWrap;
+    QSGTexture::WrapMode verticalWrap;
+};
+#include "qsgshadereffectsource.moc"
+
+
 QSGShaderEffectSourceNode::QSGShaderEffectSourceNode()
 {
     setFlag(UsePreprocess, true);
@@ -458,6 +485,7 @@ void QSGShaderEffectTexture::grab()
 
 QSGShaderEffectSource::QSGShaderEffectSource(QSGItem *parent)
     : QSGItem(parent)
+    , m_provider(0)
     , m_wrapMode(ClampToEdge)
     , m_sourceItem(0)
     , m_textureSize(0, 0)
@@ -470,7 +498,6 @@ QSGShaderEffectSource::QSGShaderEffectSource(QSGItem *parent)
 {
     setFlag(ItemHasContents);
     m_texture = new QSGShaderEffectTexture(this);
-    connect(m_texture, SIGNAL(textureChanged()), this, SIGNAL(textureChanged()), Qt::DirectConnection);
     connect(m_texture, SIGNAL(textureChanged()), this, SLOT(update()));
 }
 
@@ -478,10 +505,28 @@ QSGShaderEffectSource::~QSGShaderEffectSource()
 {
     m_texture->scheduleForCleanup();
 
+    if (m_provider)
+        m_provider->deleteLater();
+
     if (m_sourceItem)
         QSGItemPrivate::get(m_sourceItem)->derefFromEffectItem(m_hideSource);
 }
 
+QSGTextureProvider *QSGShaderEffectSource::textureProvider() const
+{
+    if (!m_provider) {
+        Q_ASSERT(QSGItemPrivate::get(this)->sceneGraphContext());
+        // Make sure it gets thread affinity on the rendering thread so deletion works properly..
+        Q_ASSERT_X(QThread::currentThread() == QSGItemPrivate::get(this)->sceneGraphContext()->thread(),
+                   "QSGShaderEffectSource::textureProvider",
+                   "Cannot be used outside the GUI thread");
+        const_cast<QSGShaderEffectSource *>(this)->m_provider = new QSGShaderEffectSourceTextureProvider();
+        connect(m_texture, SIGNAL(textureChanged()), m_provider, SIGNAL(textureChanged()), Qt::DirectConnection);
+        m_provider->sourceTexture = m_texture;
+    }
+    return m_provider;
+}
+
 /*!
     \qmlproperty enumeration ShaderEffectSource::wrapMode
 
@@ -764,17 +809,6 @@ static void get_wrap_mode(QSGShaderEffectSource::WrapMode mode, QSGTexture::Wrap
 }
 
 
-QSGTexture *QSGShaderEffectSource::texture() const
-{
-    m_texture->setMipmapFiltering(m_mipmap ? QSGTexture::Linear : QSGTexture::None);
-    m_texture->setFiltering(QSGItemPrivate::get(this)->smooth ? QSGTexture::Linear : QSGTexture::Nearest);
-    QSGTexture::WrapMode h, v;
-    get_wrap_mode(m_wrapMode, &h, &v);
-    m_texture->setHorizontalWrapMode(h);
-    m_texture->setVerticalWrapMode(v);
-    return m_texture;
-}
-
 QSGNode *QSGShaderEffectSource::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
 {
     if (!m_sourceItem) {
@@ -782,19 +816,7 @@ QSGNode *QSGShaderEffectSource::updatePaintNode(QSGNode *oldNode, UpdatePaintNod
         return 0;
     }
 
-    QSGShaderEffectSourceNode *node = static_cast<QSGShaderEffectSourceNode *>(oldNode);
-    if (!node) {
-        node = new QSGShaderEffectSourceNode;
-        node->setTexture(m_texture);
-        connect(m_texture, SIGNAL(textureChanged()), node, SLOT(markDirtyTexture()), Qt::DirectConnection);
-    }
-
-    // If live and recursive, update continuously.
-    if (m_live && m_recursive)
-        node->markDirty(QSGNode::DirtyMaterial);
-
     QSGShaderEffectTexture *tex = qobject_cast<QSGShaderEffectTexture *>(m_texture);
-
     tex->setLive(m_live);
     tex->setItem(QSGItemPrivate::get(m_sourceItem)->itemNode());
     QRectF sourceRect = m_sourceRect.isNull()
@@ -817,12 +839,35 @@ QSGNode *QSGShaderEffectSource::updatePaintNode(QSGNode *oldNode, UpdatePaintNod
                                             ? QSGTexture::Linear
                                             : QSGTexture::Nearest;
     QSGTexture::Filtering mmFiltering = m_mipmap ? filtering : QSGTexture::None;
-    node->setMipmapFiltering(mmFiltering);
-    node->setFiltering(filtering);
-
     QSGTexture::WrapMode hWrap, vWrap;
     get_wrap_mode(m_wrapMode, &hWrap, &vWrap);
 
+    if (m_provider) {
+        m_provider->mipmapFiltering = mmFiltering;
+        m_provider->filtering = filtering;
+        m_provider->horizontalWrap = hWrap;
+        m_provider->verticalWrap = vWrap;
+    }
+
+    // Don't create the paint node if we're not spanning any area
+    if (width() == 0 || height() == 0) {
+        delete oldNode;
+        return 0;
+    }
+
+    QSGShaderEffectSourceNode *node = static_cast<QSGShaderEffectSourceNode *>(oldNode);
+    if (!node) {
+        node = new QSGShaderEffectSourceNode;
+        node->setTexture(m_texture);
+        connect(m_texture, SIGNAL(textureChanged()), node, SLOT(markDirtyTexture()), Qt::DirectConnection);
+    }
+
+    // If live and recursive, update continuously.
+    if (m_live && m_recursive)
+        node->markDirty(QSGNode::DirtyMaterial);
+
+    node->setMipmapFiltering(mmFiltering);
+    node->setFiltering(filtering);
     node->setHorizontalWrapMode(hWrap);
     node->setVerticalWrapMode(vWrap);
     node->setTargetRect(QRectF(0, 0, width(), height()));
index 1108e8c..ff9359f 100644 (file)
@@ -64,6 +64,8 @@ class QSGNode;
 class UpdatePaintNodeData;
 class QGLFramebufferObject;
 
+class QSGShaderEffectSourceTextureProvider;
+
 class QSGShaderEffectSourceNode : public QObject, public QSGDefaultImageNode
 {
     Q_OBJECT
@@ -150,7 +152,7 @@ private:
     uint m_grab : 1;
 };
 
-class QSGShaderEffectSource : public QSGItem, public QSGTextureProvider
+class QSGShaderEffectSource : public QSGItem
 {
     Q_OBJECT
     Q_PROPERTY(WrapMode wrapMode READ wrapMode WRITE setWrapMode NOTIFY wrapModeChanged)
@@ -162,7 +164,7 @@ class QSGShaderEffectSource : public QSGItem, public QSGTextureProvider
     Q_PROPERTY(bool hideSource READ hideSource WRITE setHideSource NOTIFY hideSourceChanged)
     Q_PROPERTY(bool mipmap READ mipmap WRITE setMipmap NOTIFY mipmapChanged)
     Q_PROPERTY(bool recursive READ recursive WRITE setRecursive NOTIFY recursiveChanged)
-    Q_INTERFACES(QSGTextureProvider)
+
     Q_ENUMS(Format WrapMode)
 public:
     enum WrapMode {
@@ -208,8 +210,7 @@ public:
     bool recursive() const;
     void setRecursive(bool enabled);
 
-    QSGTexture *texture() const;
-    const char *textureChangedSignal() const { return SIGNAL(textureChanged()); }
+    QSGTextureProvider *textureProvider() const;
 
     Q_INVOKABLE void scheduleUpdate();
 
@@ -230,6 +231,7 @@ protected:
     virtual QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *);
 
 private:
+    QSGShaderEffectSourceTextureProvider *m_provider;
     QSGShaderEffectTexture *m_texture;
     WrapMode m_wrapMode;
     QPointer<QSGItem> m_sourceItem;
index 7397fc6..770c5fd 100644 (file)
@@ -490,21 +490,21 @@ void QSGCustomParticle::buildData()
     if (!m_rootNode)
         return;
     QVector<QPair<QByteArray, QVariant> > values;
-    QVector<QPair<QByteArray, QPointer<QSGItem> > > textures;
-    const QVector<QPair<QByteArray, QPointer<QSGItem> > > &oldTextures = m_material.textureProviders();
+    QVector<QPair<QByteArray, QSGTextureProvider *> > textures;
+    const QVector<QPair<QByteArray, QSGTextureProvider *> > &oldTextures = m_material.textureProviders();
     for (int i = 0; i < oldTextures.size(); ++i) {
-        QSGTextureProvider *oldSource = QSGTextureProvider::from(oldTextures.at(i).second);
-        if (oldSource && oldSource->textureChangedSignal())
+        QSGTextureProvider *t = oldTextures.at(i).second;
+        if (t)
             foreach (QSGShaderEffectNode* node, m_nodes)
-                disconnect(oldTextures.at(i).second, oldSource->textureChangedSignal(), node, SLOT(markDirtyTexture()));
+                disconnect(t, SIGNAL(textureChanged()), node, SLOT(markDirtyTexture()));
     }
     for (int i = 0; i < m_sources.size(); ++i) {
         const SourceData &source = m_sources.at(i);
-        textures.append(qMakePair(source.name, source.item));
         QSGTextureProvider *t = QSGTextureProvider::from(source.item);
-        if (t && t->textureChangedSignal())
+        textures.append(qMakePair(source.name, t));
+        if (t)
             foreach (QSGShaderEffectNode* node, m_nodes)
-                connect(source.item, t->textureChangedSignal(), node, SLOT(markDirtyTexture()), Qt::DirectConnection);
+                connect(t, SIGNAL(textureChanged()), node, SLOT(markDirtyTexture()), Qt::DirectConnection);
     }
     for (QSet<QByteArray>::const_iterator it = m_source.uniformNames.begin();
          it != m_source.uniformNames.end(); ++it) {
index abaf96e..cc88854 100644 (file)
@@ -41,6 +41,9 @@
 
 #include "qsgtextureprovider_p.h"
 
+#include <qsgimage_p.h>
+#include <qsgshadereffectsource_p.h>
+
 #ifndef GL_CLAMP_TO_EDGE
 #define GL_CLAMP_TO_EDGE 0x812F
 #endif
@@ -50,6 +53,8 @@ QT_BEGIN_NAMESPACE
 /*!
     \class QSGTextureProvider
     \brief The QSGTextureProvider class encapsulates texture based entities in QML.
+
+    The QSGTextureProvider lives primarily in the scene graph rendering thread.
  */
 
 
@@ -58,7 +63,15 @@ QT_BEGIN_NAMESPACE
  */
 QSGTextureProvider *QSGTextureProvider::from(QObject *object)
 {
-    return object ? static_cast<QSGTextureProvider *>(object->qt_metacast("QSGTextureProvider")) : 0;
+    if (QSGImage *image = qobject_cast<QSGImage*>(object))
+        return image->textureProvider();
+    else if (QSGShaderEffectSource *source = qobject_cast<QSGShaderEffectSource *>(object))
+        return source->textureProvider();
+    else if (QSGTextureProvider *provider = qobject_cast<QSGTextureProvider *>(object))
+        return provider;
+
+    qDebug() << "QSGTextureProvider::from() not a texture provider" << object;
+    return 0;
 }
 
 
index 756f1c6..3720394 100644 (file)
@@ -42,8 +42,6 @@
 #ifndef QSGTEXTUREPROVIDER_H
 #define QSGTEXTUREPROVIDER_H
 
-#include <qgl.h>
-
 #include "qsgtexture.h"
 #include "qobject.h"
 
@@ -53,15 +51,17 @@ QT_BEGIN_NAMESPACE
 
 QT_MODULE(Declarative)
 
-class QSGTextureProvider
+class QSGTextureProvider : public QObject
 {
+    Q_OBJECT
 public:
     virtual QSGTexture *texture() const = 0;
-    virtual const char *textureChangedSignal() const { return 0; }
 
     static QSGTextureProvider *from(QObject *object);
+
+Q_SIGNALS:
+    void textureChanged();
 };
-Q_DECLARE_INTERFACE(QSGTextureProvider, "QSGTextureProvider")
 
 QT_END_NAMESPACE