Make textureProvider() a virtual accessor in QSGItem.
authorGunnar Sletta <gunnar.sletta@nokia.com>
Mon, 22 Aug 2011 11:48:13 +0000 (13:48 +0200)
committerKim M. Kalland <kim.kalland@nokia.com>
Mon, 22 Aug 2011 12:01:52 +0000 (14:01 +0200)
This gets us one step closer to a public QSGTextureProvider
API.

This patch also includes a fix to the material ownership in
QSGCustomParticle.

Change-Id: I620e3006816db0c37eedf3a20a0d4cbe7a783b82
Reviewed-on: http://codereview.qt.nokia.com/3317
Reviewed-by: Qt Sanity Bot <qt_sanity_bot@ovi.com>
Reviewed-by: Kim M. Kalland <kim.kalland@nokia.com>
12 files changed:
src/declarative/items/qsgimage.cpp
src/declarative/items/qsgimage_p.h
src/declarative/items/qsgitem.cpp
src/declarative/items/qsgitem.h
src/declarative/items/qsgshadereffect.cpp
src/declarative/items/qsgshadereffect_p.h
src/declarative/items/qsgshadereffectsource.cpp
src/declarative/items/qsgshadereffectsource_p.h
src/declarative/particles/qsgcustomparticle.cpp
src/declarative/particles/qsgcustomparticle_p.h
src/declarative/scenegraph/util/qsgtextureprovider.cpp
src/declarative/scenegraph/util/qsgtextureprovider_p.h

index 48cefb5..dc5c8d1 100644 (file)
@@ -544,9 +544,10 @@ QSGTextureProvider *QSGImage::textureProvider() const
 {
     Q_D(const QSGImage);
     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(),
+        Q_ASSERT_X(d->canvas
+                   && d->sceneGraphContext()
+                   && QThread::currentThread() == d->sceneGraphContext()->thread(),
                    "QSGImage::textureProvider",
                    "Cannot be used outside the GUI thread");
         const_cast<QSGImagePrivate *>(d)->provider = new QSGImageTextureProvider(this);
index b49447f..9bf1d91 100644 (file)
@@ -93,6 +93,7 @@ public:
     VAlignment verticalAlignment() const;
     void setVerticalAlignment(VAlignment align);
 
+    bool isTextureProvider() const { return true; }
     QSGTextureProvider *textureProvider() const;
 
 Q_SIGNALS:
index a0ccf74..163cec1 100644 (file)
@@ -3198,6 +3198,24 @@ qint64 QSGItemPrivate::restart(QElapsedTimer &t)
         return ((QElapsedTimerConsistentTimeHack*)&t)->restart();
 }
 
+/*!
+    \fn bool QSGItem::isTextureProvider() const
+
+    Returns true if this item is a texture provider. The default
+    implementation returns false.
+
+    This function can be called from any thread.
+ */
+
+/*!
+    \fn QSGTextureProvider *QSGItem::textureProvider() const
+
+    Returns the texture provider for an item. The default implementation
+    returns 0.
+
+    This function may only be called on the rendering thread.
+ */
+
 QT_END_NAMESPACE
 
 #include <moc_qsgitem.cpp>
index 7dc43fb..f8e52cf 100644 (file)
@@ -95,6 +95,8 @@ class QSGEngine;
 class QTouchEvent;
 class QSGNode;
 class QSGTransformNode;
+class QSGTextureProvider;
+
 class Q_DECLARATIVE_EXPORT QSGItem : public QObject, public QDeclarativeParserStatus
 {
     Q_OBJECT
@@ -305,6 +307,9 @@ public:
        UpdatePaintNodeData();
     };
 
+    virtual bool isTextureProvider() const { return false; }
+    virtual QSGTextureProvider *textureProvider() const { return 0; }
+
 public Q_SLOTS:
     void update();
     void updateMicroFocus();
index 97cc898..6649dc9 100644 (file)
@@ -414,15 +414,15 @@ void QSGShaderEffect::setSource(const QVariant &var, int index)
     }
 
     QObject *obj = qVariantValue<QObject *>(var);
-    if (!QSGTextureProvider::from(obj)) {
+    QSGItem *item = qobject_cast<QSGItem *>(obj);
+    if (!item || !item->isTextureProvider()) {
         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.sourceObject = obj;
+    source.sourceObject = item;
 
-    QSGItem *item = qobject_cast<QSGItem *>(obj);
 
     // TODO: Find better solution.
     // 'item' needs a canvas to get a scenegraph node.
@@ -655,7 +655,7 @@ QSGNode *QSGShaderEffect::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData
         }
         for (int i = 0; i < m_sources.size(); ++i) {
             const SourceData &source = m_sources.at(i);
-            QSGTextureProvider *t = QSGTextureProvider::from(source.sourceObject);
+            QSGTextureProvider *t = source.sourceObject->textureProvider();
             textures.append(qMakePair(source.name, t));
             if (t)
                 connect(t, SIGNAL(textureChanged()), node, SLOT(markDirtyTexture()), Qt::DirectConnection);
index 556ff9b..5d90fe0 100644 (file)
@@ -138,7 +138,7 @@ private:
     struct SourceData
     {
         QSignalMapper *mapper;
-        QPointer<QObject> sourceObject;
+        QPointer<QSGItem> sourceObject;
         QByteArray name;
     };
     QVector<SourceData> m_sources;
index 2458007..f9dbfe5 100644 (file)
@@ -515,9 +515,10 @@ QSGShaderEffectSource::~QSGShaderEffectSource()
 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(),
+        Q_ASSERT_X(QSGItemPrivate::get(this)->canvas
+                   && QSGItemPrivate::get(this)->sceneGraphContext()
+                   && QThread::currentThread() == QSGItemPrivate::get(this)->sceneGraphContext()->thread(),
                    "QSGShaderEffectSource::textureProvider",
                    "Cannot be used outside the GUI thread");
         const_cast<QSGShaderEffectSource *>(this)->m_provider = new QSGShaderEffectSourceTextureProvider();
index ff9359f..92a4ce8 100644 (file)
@@ -210,6 +210,7 @@ public:
     bool recursive() const;
     void setRecursive(bool enabled);
 
+    bool isTextureProvider() const { return true; }
     QSGTextureProvider *textureProvider() const;
 
     Q_INVOKABLE void scheduleUpdate();
index 770c5fd..53cb131 100644 (file)
@@ -132,11 +132,20 @@ QSGCustomParticle::QSGCustomParticle(QSGItem* parent)
     : QSGParticlePainter(parent)
     , m_pleaseReset(true)
     , m_dirtyData(true)
+    , m_material(0)
     , m_rootNode(0)
 {
     setFlag(QSGItem::ItemHasContents);
 }
 
+class QSGShaderEffectMaterialObject : public QObject, public QSGShaderEffectMaterial { };
+
+QSGCustomParticle::~QSGCustomParticle()
+{
+    if (m_material)
+        m_material->deleteLater();
+}
+
 void QSGCustomParticle::componentComplete()
 {
     reset();
@@ -236,13 +245,12 @@ void QSGCustomParticle::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());
-    }
-
     source.item = qobject_cast<QSGItem *>(obj);
+    if (!source.item || !source.item->isTextureProvider()) {
+        qWarning("ShaderEffect: source uniform [%s] is not assigned a valid texture provider: %s [%s]",
+                 qPrintable(source.name), qPrintable(obj->objectName()), obj->metaObject()->className());
+        return;
+    }
 
     // TODO: Copy better solution in QSGShaderEffect when they find it.
     // 'source.item' needs a canvas to get a scenegraph node.
@@ -429,7 +437,12 @@ QSGShaderEffectNode* QSGCustomParticle::buildCustomNodes()
         s.fragmentCode = qt_particles_default_fragment_code;
     if (s.vertexCode.isEmpty())
         s.vertexCode = qt_particles_default_vertex_code;
-    m_material.setProgramSource(s);
+
+    if (!m_material) {
+        m_material = new QSGShaderEffectMaterialObject;
+    }
+
+    m_material->setProgramSource(s);
     foreach (const QString &str, m_particles){
         int gIdx = m_system->m_groupIds[str];
         int count = m_system->m_groupData[gIdx]->size();
@@ -469,7 +482,7 @@ QSGShaderEffectNode* QSGCustomParticle::buildCustomNodes()
         QSGShaderEffectNode* node = new QSGShaderEffectNode();
 
         node->setGeometry(g);
-        node->setMaterial(&m_material);
+        node->setMaterial(m_material);
         node->markDirty(QSGNode::DirtyMaterial);
 
         m_nodes.insert(gIdx, node);
@@ -491,7 +504,7 @@ void QSGCustomParticle::buildData()
         return;
     QVector<QPair<QByteArray, QVariant> > values;
     QVector<QPair<QByteArray, QSGTextureProvider *> > textures;
-    const QVector<QPair<QByteArray, QSGTextureProvider *> > &oldTextures = m_material.textureProviders();
+    const QVector<QPair<QByteArray, QSGTextureProvider *> > &oldTextures = m_material->textureProviders();
     for (int i = 0; i < oldTextures.size(); ++i) {
         QSGTextureProvider *t = oldTextures.at(i).second;
         if (t)
@@ -500,7 +513,7 @@ void QSGCustomParticle::buildData()
     }
     for (int i = 0; i < m_sources.size(); ++i) {
         const SourceData &source = m_sources.at(i);
-        QSGTextureProvider *t = QSGTextureProvider::from(source.item);
+        QSGTextureProvider *t = source.item->textureProvider();
         textures.append(qMakePair(source.name, t));
         if (t)
             foreach (QSGShaderEffectNode* node, m_nodes)
@@ -511,8 +524,8 @@ void QSGCustomParticle::buildData()
         values.append(qMakePair(*it, property(*it)));
     }
     values.append(qMakePair(timestampName, QVariant(m_lastTime)));
-    m_material.setUniforms(values);
-    m_material.setTextureProviders(textures);
+    m_material->setUniforms(values);
+    m_material->setTextureProviders(textures);
     m_dirtyData = false;
     foreach (QSGShaderEffectNode* node, m_nodes)
         node->markDirty(QSGNode::DirtyMaterial);
index 1fec963..f51e576 100644 (file)
@@ -53,6 +53,9 @@ QT_MODULE(Declarative)
 
 class QSGNode;
 struct PlainVertices;
+
+class QSGShaderEffectMaterialObject;
+
 //Genealogy: Hybrid of UltraParticle and ShaderEffect
 class QSGCustomParticle : public QSGParticlePainter
 {
@@ -62,6 +65,7 @@ class QSGCustomParticle : public QSGParticlePainter
 
 public:
     explicit QSGCustomParticle(QSGItem* parent=0);
+    ~QSGCustomParticle();
 
     QByteArray fragmentShader() const { return m_source.fragmentCode; }
     void setFragmentShader(const QByteArray &code);
@@ -105,7 +109,7 @@ private:
         QByteArray name;
     };
     QVector<SourceData> m_sources;
-    QSGShaderEffectMaterial m_material;
+    QSGShaderEffectMaterialObject *m_material;
     QSGShaderEffectNode* m_rootNode;
     QHash<int, QSGShaderEffectNode*> m_nodes;
     qreal m_lastTime;
index cc88854..49d157d 100644 (file)
@@ -58,21 +58,5 @@ QT_BEGIN_NAMESPACE
  */
 
 
-/*!
-    Convenience function for casting a QObject to a QSGTextureProvider
- */
-QSGTextureProvider *QSGTextureProvider::from(QObject *object)
-{
-    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;
-}
-
 
 QT_END_NAMESPACE
index 3720394..e1e08a5 100644 (file)
@@ -57,8 +57,6 @@ class QSGTextureProvider : public QObject
 public:
     virtual QSGTexture *texture() const = 0;
 
-    static QSGTextureProvider *from(QObject *object);
-
 Q_SIGNALS:
     void textureChanged();
 };