QQuickCanvas renames
[profile/ivi/qtdeclarative.git] / src / quick / scenegraph / qsgshareddistancefieldglyphcache.cpp
index 799d354..dcbff84 100644 (file)
 
 #include <QtCore/qhash.h>
 #include <QtCore/qthread.h>
-#include <QtGui/qplatformsharedgraphicscache_qpa.h>
+#include <QtCore/qcoreapplication.h>
 
-#include <QtQuick/qquickcanvas.h>
+#include <qpa/qplatformsharedgraphicscache.h>
 
-#include <QtOpenGL/qglframebufferobject.h>
+#include <QtQuick/qquickwindow.h>
 
 // #define QSGSHAREDDISTANCEFIELDGLYPHCACHE_DEBUG
 
-Q_DECLARE_METATYPE(QVector<quint32>)
-Q_DECLARE_METATYPE(QVector<QImage>)
-
 QT_BEGIN_NAMESPACE
 
+namespace {
+
+    class QSGInvokeEvent: public QEvent
+    {
+    public:
+        QSGInvokeEvent(QPlatformSharedGraphicsCache *cache,
+                       const QByteArray &cacheId = QByteArray(),
+                       const QVector<quint32> &glyphIds = QVector<quint32>(),
+                       bool inSceneGraphUpdate = false)
+            : QEvent(User)
+            , m_cache(cache)
+            , m_cacheId(cacheId)
+            , m_glyphIds(glyphIds)
+            , m_inSceneGraphUpdate(inSceneGraphUpdate)
+        {}
+
+        bool inSceneGraphUpdate() const { return m_inSceneGraphUpdate; }
+        QPlatformSharedGraphicsCache *cache() const { return m_cache; }
+
+        virtual void invoke() = 0;
+    protected:
+        QPlatformSharedGraphicsCache *m_cache;
+        QByteArray m_cacheId;
+        QVector<quint32> m_glyphIds;
+        bool m_inSceneGraphUpdate;
+    };
+
+    class QSGReleaseItemsEvent: public QSGInvokeEvent
+    {
+    public:
+        QSGReleaseItemsEvent(QPlatformSharedGraphicsCache *cache,
+                             const QByteArray &cacheId,
+                             const QVector<quint32> &glyphIds,
+                             bool inSceneGraphUpdate)
+            : QSGInvokeEvent(cache, cacheId, glyphIds, inSceneGraphUpdate)
+        {
+        }
+
+        void invoke()
+        {
+            m_cache->releaseItems(m_cacheId, m_glyphIds);
+        }
+    };
+
+    class QSGRequestItemsEvent: public QSGInvokeEvent
+    {
+    public:
+        QSGRequestItemsEvent(QPlatformSharedGraphicsCache *cache,
+                             const QByteArray &cacheId,
+                             const QVector<quint32> &glyphIds,
+                             bool inSceneGraphUpdate)
+            : QSGInvokeEvent(cache, cacheId, glyphIds, inSceneGraphUpdate)
+        {
+        }
+
+        void invoke()
+        {
+            m_cache->requestItems(m_cacheId, m_glyphIds);
+        }
+    };
+
+    class QSGInsertItemsEvent: public QSGInvokeEvent
+    {
+    public:
+        QSGInsertItemsEvent(QPlatformSharedGraphicsCache *cache,
+                            const QByteArray &cacheId,
+                            const QVector<quint32> &glyphIds,
+                            const QVector<QImage> &images,
+                            bool inSceneGraphUpdate)
+            : QSGInvokeEvent(cache, cacheId, glyphIds, inSceneGraphUpdate)
+            , m_images(images)
+        {
+        }
+
+        void invoke()
+        {
+            m_cache->insertItems(m_cacheId, m_glyphIds, m_images);
+        }
+
+    private:
+        QVector<QImage> m_images;
+    };
+
+    class QSGEndRequestBatchEvent: public QSGInvokeEvent
+    {
+    public:
+        QSGEndRequestBatchEvent(QPlatformSharedGraphicsCache *cache)
+            : QSGInvokeEvent(cache)
+        {
+        }
+
+        void invoke()
+        {
+            if (m_cache->requestBatchStarted())
+                m_cache->endRequestBatch();
+        }
+    };
+
+    class QSGMainThreadInvoker: public QObject
+    {
+    public:
+        bool event(QEvent *e)
+        {
+            if (e->type() == QEvent::User) {
+                Q_ASSERT(QThread::currentThread() == QCoreApplication::instance()->thread());
+
+                QSGInvokeEvent *invokeEvent = static_cast<QSGInvokeEvent *>(e);
+                if (invokeEvent->inSceneGraphUpdate()) {
+                    QPlatformSharedGraphicsCache *cache = invokeEvent->cache();
+                    if (!cache->requestBatchStarted())
+                        cache->beginRequestBatch();
+                }
+
+                static_cast<QSGInvokeEvent *>(e)->invoke();
+                return true;
+            }
+            return QObject::event(e);
+        }
+
+        static QSGMainThreadInvoker *instance()
+        {
+            if (m_invoker == 0) {
+                m_invoker = new QSGMainThreadInvoker;
+                m_invoker->moveToThread(QCoreApplication::instance()->thread());
+            }
+
+            return m_invoker;
+        }
+
+    private:
+        static QSGMainThreadInvoker *m_invoker;
+    };
+
+    QSGMainThreadInvoker* QSGMainThreadInvoker::m_invoker = 0;
+}
+
 QSGSharedDistanceFieldGlyphCache::QSGSharedDistanceFieldGlyphCache(const QByteArray &cacheId,
                                                                    QPlatformSharedGraphicsCache *sharedGraphicsCache,
                                                                    QSGDistanceFieldGlyphCacheManager *man,
@@ -71,6 +204,8 @@ QSGSharedDistanceFieldGlyphCache::QSGSharedDistanceFieldGlyphCache(const QByteAr
     : QSGDistanceFieldGlyphCache(man, c, font)
     , m_cacheId(cacheId)
     , m_sharedGraphicsCache(sharedGraphicsCache)
+    , m_isInSceneGraphUpdate(false)
+    , m_hasPostedEvents(false)
 {
 #if defined(QSGSHAREDDISTANCEFIELDGLYPHCACHE_DEBUG)
     qDebug("QSGSharedDistanceFieldGlyphCache with id %s created in thread %p",
@@ -80,21 +215,26 @@ QSGSharedDistanceFieldGlyphCache::QSGSharedDistanceFieldGlyphCache(const QByteAr
     Q_ASSERT(sizeof(glyph_t) == sizeof(quint32));
     Q_ASSERT(sharedGraphicsCache != 0);
 
-    qRegisterMetaType<QVector<quint32> >();
-    qRegisterMetaType<QVector<QImage> >();
-
     connect(sharedGraphicsCache, SIGNAL(itemsMissing(QByteArray,QVector<quint32>)),
             this, SLOT(reportItemsMissing(QByteArray,QVector<quint32>)),
             Qt::DirectConnection);
-    connect(sharedGraphicsCache, SIGNAL(itemsAvailable(QByteArray,void*,QSize,QVector<quint32>,QVector<QPoint>)),
-            this, SLOT(reportItemsAvailable(QByteArray,void*,QSize,QVector<quint32>,QVector<QPoint>)),
+    connect(sharedGraphicsCache, SIGNAL(itemsAvailable(QByteArray,void*,QVector<quint32>,QVector<QPoint>)),
+            this, SLOT(reportItemsAvailable(QByteArray,void*,QVector<quint32>,QVector<QPoint>)),
             Qt::DirectConnection);
-    connect(sharedGraphicsCache, SIGNAL(itemsUpdated(QByteArray,void*,QSize,QVector<quint32>,QVector<QPoint>)),
-            this, SLOT(reportItemsAvailable(QByteArray,void*,QSize,QVector<quint32>,QVector<QPoint>)),
+    connect(sharedGraphicsCache, SIGNAL(itemsUpdated(QByteArray,void*,QVector<quint32>,QVector<QPoint>)),
+            this, SLOT(reportItemsUpdated(QByteArray,void*,QVector<quint32>,QVector<QPoint>)),
             Qt::DirectConnection);
     connect(sharedGraphicsCache, SIGNAL(itemsInvalidated(QByteArray,QVector<quint32>)),
             this, SLOT(reportItemsInvalidated(QByteArray,QVector<quint32>)),
             Qt::DirectConnection);
+
+    QQuickWindow *window = static_cast<QQuickWindow *>(c->surface());
+    Q_ASSERT(window != 0);
+
+    connect(window, SIGNAL(beforeSynchronizing()), this, SLOT(sceneGraphUpdateStarted()),
+            Qt::DirectConnection);
+    connect(window, SIGNAL(beforeRendering()), this, SLOT(sceneGraphUpdateDone()),
+            Qt::DirectConnection);
 }
 
 QSGSharedDistanceFieldGlyphCache::~QSGSharedDistanceFieldGlyphCache()
@@ -126,6 +266,7 @@ void QSGSharedDistanceFieldGlyphCache::requestGlyphs(const QSet<glyph_t> &glyphs
 #endif
 
     m_requestedGlyphsThatHaveNotBeenReturned.unite(glyphs);
+    m_requestedGlyphs.unite(glyphs);
 
     QVector<quint32> glyphsVector;
     glyphsVector.reserve(glyphs.size());
@@ -136,15 +277,22 @@ void QSGSharedDistanceFieldGlyphCache::requestGlyphs(const QSet<glyph_t> &glyphs
         glyphsVector.append(*it);
     }
 
-    // Invoke method on queued connection to make sure it's called asynchronously on the
-    // correct thread (requestGlyphs() is called from the rendering thread.)
-    QMetaObject::invokeMethod(m_sharedGraphicsCache, "requestItems", Qt::QueuedConnection,
-                              Q_ARG(QByteArray, m_cacheId),
-                              Q_ARG(QVector<quint32>, glyphsVector));
+    m_hasPostedEvents = true;
+    QSGMainThreadInvoker *invoker = QSGMainThreadInvoker::instance();
+    QCoreApplication::postEvent(invoker, new QSGRequestItemsEvent(m_sharedGraphicsCache,
+                                                                  m_cacheId,
+                                                                  glyphsVector,
+                                                                  m_isInSceneGraphUpdate));
 }
 
 void QSGSharedDistanceFieldGlyphCache::waitForGlyphs()
 {
+    Q_ASSERT(!m_isInSceneGraphUpdate);
+    if (m_isInSceneGraphUpdate) {
+        qWarning("QSGSharedDistanceFieldGlyphCache::waitForGlyphs: Called from inside "
+                 "scenegraph update. Will freeze.");
+    }
+
     {
         QMutexLocker locker(&m_pendingGlyphsMutex);
         while (!m_requestedGlyphsThatHaveNotBeenReturned.isEmpty())
@@ -174,10 +322,13 @@ void QSGSharedDistanceFieldGlyphCache::storeGlyphs(const QHash<glyph_t, QImage>
             ++it; ++i;
         }
 
-        QMetaObject::invokeMethod(m_sharedGraphicsCache, "insertItems", Qt::QueuedConnection,
-                                  Q_ARG(QByteArray, m_cacheId),
-                                  Q_ARG(QVector<quint32>, glyphIds),
-                                  Q_ARG(QVector<QImage>, images));
+        m_hasPostedEvents = true;
+        QSGMainThreadInvoker *invoker = QSGMainThreadInvoker::instance();
+        QCoreApplication::postEvent(invoker, new QSGInsertItemsEvent(m_sharedGraphicsCache,
+                                                                     m_cacheId,
+                                                                     glyphIds,
+                                                                     images,
+                                                                     m_isInSceneGraphUpdate));
     }
 
     processPendingGlyphs();
@@ -198,6 +349,8 @@ void QSGSharedDistanceFieldGlyphCache::releaseGlyphs(const QSet<glyph_t> &glyphs
            m_cacheId.constData(), glyphs.size());
 #endif
 
+    m_requestedGlyphs.subtract(glyphs);
+
     QVector<quint32> glyphsVector;
     glyphsVector.reserve(glyphs.size());
 
@@ -224,21 +377,35 @@ void QSGSharedDistanceFieldGlyphCache::releaseGlyphs(const QSet<glyph_t> &glyphs
         glyphsVector.append(*glyphsIt);
     }
 
-    QMetaObject::invokeMethod(m_sharedGraphicsCache, "releaseItems", Qt::QueuedConnection,
-                              Q_ARG(QByteArray, m_cacheId),
-                              Q_ARG(QVector<quint32>, glyphsVector));
+    m_hasPostedEvents = true;
+    QSGMainThreadInvoker *mainThreadInvoker = QSGMainThreadInvoker::instance();
+    QCoreApplication::postEvent(mainThreadInvoker, new QSGReleaseItemsEvent(m_sharedGraphicsCache,
+                                                                            m_cacheId,
+                                                                            glyphsVector,
+                                                                            m_isInSceneGraphUpdate));
 }
 
 void QSGSharedDistanceFieldGlyphCache::registerOwnerElement(QQuickItem *ownerElement)
 {
-    bool ok = connect(this, SIGNAL(glyphsPending()), ownerElement, SLOT(triggerPreprocess()));
-    Q_ASSERT_X(ok, Q_FUNC_INFO, "QML element that owns a glyph node must have triggerPreprocess() slot");
-    Q_UNUSED(ok);
+    Owner &owner = m_registeredOwners[ownerElement];
+    if (owner.ref == 0) {
+        owner.item = ownerElement;
+
+        bool ok = connect(this, SIGNAL(glyphsPending()), ownerElement, SLOT(triggerPreprocess()));
+        Q_ASSERT_X(ok, Q_FUNC_INFO, "QML element that owns a glyph node must have triggerPreprocess() slot");
+        Q_UNUSED(ok);
+    }
+    ++owner.ref;
 }
 
 void QSGSharedDistanceFieldGlyphCache::unregisterOwnerElement(QQuickItem *ownerElement)
 {
-    disconnect(this, SIGNAL(glyphsPending()), ownerElement, SLOT(triggerPreprocess()));
+    QHash<QQuickItem *, Owner>::iterator it = m_registeredOwners.find(ownerElement);
+    if (it != m_registeredOwners.end() && --it->ref <= 0) {
+        if (it->item)
+            disconnect(this, SIGNAL(glyphsPending()), ownerElement, SLOT(triggerPreprocess()));
+        m_registeredOwners.erase(it);
+    }
 }
 
 #if defined(QSGSHAREDDISTANCEFIELDGLYPHCACHE_DEBUG_)
@@ -389,7 +556,7 @@ void QSGSharedDistanceFieldGlyphCache::saveTexture(GLuint textureId, int width,
     for (int i=0; i<width*height; ++i)
         dest[i] = qRgba(0xff, 0xff, 0xff, data[i]);
 
-    QByteArray fileName = m_cacheId + " " + QByteArray::number(textureId);
+    QByteArray fileName = m_cacheId + ' ' + QByteArray::number(textureId);
     fileName = fileName.replace('/', '_').replace(' ', '_') + ".png";
     image.save(QString::fromLocal8Bit(fileName));
 
@@ -523,7 +690,7 @@ void QSGSharedDistanceFieldGlyphCache::processPendingGlyphs()
                 while (it != textureContentForBuffer.constEnd()) {
                     Texture texture;
                     texture.textureId = m_sharedGraphicsCache->textureIdForBuffer(it.key());
-                    texture.size = it.value().size;
+                    texture.size = m_sharedGraphicsCache->sizeOfBuffer(it.key());
 
 #if defined(QSGSHAREDDISTANCEFIELDGLYPHCACHE_DEBUG_)
                     saveTexture(texture.textureId, texture.size.width(), texture.size.height());
@@ -542,9 +709,37 @@ void QSGSharedDistanceFieldGlyphCache::processPendingGlyphs()
 }
 
 void QSGSharedDistanceFieldGlyphCache::reportItemsAvailable(const QByteArray &cacheId,
-                                                        void *bufferId, const QSize &bufferSize,
-                                                        const QVector<quint32> &itemIds,
-                                                        const QVector<QPoint> &positions)
+                                                            void *bufferId,
+                                                            const QVector<quint32> &itemIds,
+                                                            const QVector<QPoint> &positions)
+{
+    bool requestedItemsInList = false;
+    {
+        QMutexLocker locker(&m_pendingGlyphsMutex);
+        if (m_cacheId != cacheId)
+            return;
+
+#if defined(QSGSHAREDDISTANCEFIELDGLYPHCACHE_DEBUG)
+            qDebug("QSGSharedDistanceFieldGlyphCache::reportItemsAvailable() called for %s (%d glyphs)",
+                   cacheId.constData(), itemIds.size());
+#endif
+
+        for (int i=0; i<itemIds.size(); ++i) {
+            if (m_requestedGlyphsThatHaveNotBeenReturned.contains(itemIds.at(i))) {
+                requestedItemsInList = true;
+                break;
+            }
+        }
+    }
+
+    if (requestedItemsInList)
+        reportItemsUpdated(cacheId, bufferId,itemIds, positions);
+}
+
+void QSGSharedDistanceFieldGlyphCache::reportItemsUpdated(const QByteArray &cacheId,
+                                                          void *bufferId,
+                                                          const QVector<quint32> &itemIds,
+                                                          const QVector<QPoint> &positions)
 {
     {
         QMutexLocker locker(&m_pendingGlyphsMutex);
@@ -554,24 +749,24 @@ void QSGSharedDistanceFieldGlyphCache::reportItemsAvailable(const QByteArray &ca
         Q_ASSERT(itemIds.size() == positions.size());
 
 #if defined(QSGSHAREDDISTANCEFIELDGLYPHCACHE_DEBUG)
-        qDebug("QSGSharedDistanceFieldGlyphCache::reportItemsAvailable() called for %s (%d glyphs, bufferSize: %dx%d)",
-               cacheId.constData(), itemIds.size(), bufferSize.width(), bufferSize.height());
+        qDebug("QSGSharedDistanceFieldGlyphCache::reportItemsUpdated() called for %s (%d glyphs)",
+               cacheId.constData(), itemIds.size());
 #endif
 
         for (int i=0; i<itemIds.size(); ++i) {
-            PendingGlyph &pendingGlyph = m_pendingReadyGlyphs[itemIds.at(i)];
-            void *oldBuffer = pendingGlyph.buffer;
-            Q_ASSERT(bufferSize.height() >= pendingGlyph.bufferSize.height());
+            if (m_requestedGlyphs.contains(itemIds.at(i))) {
+                PendingGlyph &pendingGlyph = m_pendingReadyGlyphs[itemIds.at(i)];
+                void *oldBuffer = pendingGlyph.buffer;
 
-            pendingGlyph.buffer = bufferId;
-            pendingGlyph.position = positions.at(i);
-            pendingGlyph.bufferSize = bufferSize;
+                pendingGlyph.buffer = bufferId;
+                pendingGlyph.position = positions.at(i);
 
-            m_sharedGraphicsCache->referenceBuffer(bufferId);
-            if (oldBuffer != 0)
-                m_sharedGraphicsCache->dereferenceBuffer(oldBuffer);
+                m_sharedGraphicsCache->referenceBuffer(bufferId);
+                if (oldBuffer != 0)
+                    m_sharedGraphicsCache->dereferenceBuffer(oldBuffer);
 
-            m_requestedGlyphsThatHaveNotBeenReturned.remove(itemIds.at(i));
+                m_requestedGlyphsThatHaveNotBeenReturned.remove(itemIds.at(i));
+            }
         }
     }
 
@@ -587,8 +782,10 @@ void QSGSharedDistanceFieldGlyphCache::reportItemsInvalidated(const QByteArray &
         if (m_cacheId != cacheId)
             return;
 
-        for (int i=0; i<itemIds.size(); ++i)
-            m_pendingInvalidatedGlyphs.insert(itemIds.at(i));
+        for (int i=0; i<itemIds.size(); ++i) {
+            if (m_requestedGlyphs.contains(itemIds.at(i)))
+                m_pendingInvalidatedGlyphs.insert(itemIds.at(i));
+        }
     }
 
     emit glyphsPending();
@@ -609,8 +806,8 @@ void QSGSharedDistanceFieldGlyphCache::reportItemsMissing(const QByteArray &cach
 #endif
 
         for (int i=0; i<itemIds.size(); ++i) {
-            m_pendingMissingGlyphs.insert(itemIds.at(i));
-            m_requestedGlyphsThatHaveNotBeenReturned.remove(itemIds.at(i));
+            if (m_requestedGlyphsThatHaveNotBeenReturned.remove(itemIds.at(i)))
+                m_pendingMissingGlyphs.insert(itemIds.at(i));
         }
     }
 
@@ -618,4 +815,21 @@ void QSGSharedDistanceFieldGlyphCache::reportItemsMissing(const QByteArray &cach
     emit glyphsPending();
 }
 
+void QSGSharedDistanceFieldGlyphCache::sceneGraphUpdateStarted()
+{
+    m_isInSceneGraphUpdate = true;
+    m_hasPostedEvents = false;
+}
+
+void QSGSharedDistanceFieldGlyphCache::sceneGraphUpdateDone()
+{
+    m_isInSceneGraphUpdate = false;
+
+    if (m_hasPostedEvents) {
+        QSGMainThreadInvoker *invoker = QSGMainThreadInvoker::instance();
+        QCoreApplication::postEvent(invoker, new QSGEndRequestBatchEvent(m_sharedGraphicsCache));
+        m_hasPostedEvents = false;
+    }
+}
+
 QT_END_NAMESPACE