#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,
: 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",
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(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()
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())
++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();
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)
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));
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