From f18b5bd1588e43f2e46325646b36247e4ba473f0 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Tue, 15 May 2012 14:37:37 +0200 Subject: [PATCH] Optimize cross-thread calls into the shared graphics cache QMetaObject::invokeMethod() is quite slow compared to just posting events, since we don't really require deep copies of the input data as long as it's read-only. Change-Id: Ib5c0a14e1aac3120871a9bcf4aee8804e7d8b287 Reviewed-by: Gunnar Sletta --- .../qsgshareddistancefieldglyphcache.cpp | 137 ++++++++++++++++++--- 1 file changed, 119 insertions(+), 18 deletions(-) diff --git a/src/quick/scenegraph/qsgshareddistancefieldglyphcache.cpp b/src/quick/scenegraph/qsgshareddistancefieldglyphcache.cpp index cece95d..2dd8729 100644 --- a/src/quick/scenegraph/qsgshareddistancefieldglyphcache.cpp +++ b/src/quick/scenegraph/qsgshareddistancefieldglyphcache.cpp @@ -50,17 +50,120 @@ #include #include +#include + #include #include // #define QSGSHAREDDISTANCEFIELDGLYPHCACHE_DEBUG -Q_DECLARE_METATYPE(QVector) -Q_DECLARE_METATYPE(QVector) - QT_BEGIN_NAMESPACE +namespace { + + class QSGInvokeEvent: public QEvent + { + public: + QSGInvokeEvent(QPlatformSharedGraphicsCache *cache, + const QByteArray &cacheId, + const QVector &glyphIds) + : QEvent(User) + , m_cache(cache) + , m_cacheId(cacheId) + , m_glyphIds(glyphIds) + {} + + virtual void invoke() = 0; + protected: + QPlatformSharedGraphicsCache *m_cache; + QByteArray m_cacheId; + QVector m_glyphIds; + }; + + class QSGReleaseItemsEvent: public QSGInvokeEvent + { + public: + QSGReleaseItemsEvent(QPlatformSharedGraphicsCache *cache, + const QByteArray &cacheId, + const QVector &glyphIds) + : QSGInvokeEvent(cache, cacheId, glyphIds) + { + } + + void invoke() + { + m_cache->releaseItems(m_cacheId, m_glyphIds); + } + }; + + class QSGRequestItemsEvent: public QSGInvokeEvent + { + public: + QSGRequestItemsEvent(QPlatformSharedGraphicsCache *cache, + const QByteArray &cacheId, + const QVector &glyphIds) + : QSGInvokeEvent(cache, cacheId, glyphIds) + { + } + + void invoke() + { + m_cache->requestItems(m_cacheId, m_glyphIds); + } + }; + + class QSGInsertItemsEvent: public QSGInvokeEvent + { + public: + QSGInsertItemsEvent(QPlatformSharedGraphicsCache *cache, + const QByteArray &cacheId, + const QVector &glyphIds, + const QVector &images) + : QSGInvokeEvent(cache, cacheId, glyphIds) + , m_images(images) + { + } + + void invoke() + { + m_cache->insertItems(m_cacheId, m_glyphIds, m_images); + } + + private: + QVector m_images; + }; + + class QSGMainThreadInvoker: public QObject + { + public: + bool event(QEvent *e) + { + if (e->type() == QEvent::User) { + Q_ASSERT(QThread::currentThread() == QCoreApplication::instance()->thread()); + static_cast(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, @@ -78,9 +181,6 @@ QSGSharedDistanceFieldGlyphCache::QSGSharedDistanceFieldGlyphCache(const QByteAr Q_ASSERT(sizeof(glyph_t) == sizeof(quint32)); Q_ASSERT(sharedGraphicsCache != 0); - qRegisterMetaType >(); - qRegisterMetaType >(); - connect(sharedGraphicsCache, SIGNAL(itemsMissing(QByteArray,QVector)), this, SLOT(reportItemsMissing(QByteArray,QVector)), Qt::DirectConnection); @@ -135,11 +235,10 @@ void QSGSharedDistanceFieldGlyphCache::requestGlyphs(const QSet &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, glyphsVector)); + QSGMainThreadInvoker *invoker = QSGMainThreadInvoker::instance(); + QCoreApplication::postEvent(invoker, new QSGRequestItemsEvent(m_sharedGraphicsCache, + m_cacheId, + glyphsVector)); } void QSGSharedDistanceFieldGlyphCache::waitForGlyphs() @@ -173,10 +272,11 @@ void QSGSharedDistanceFieldGlyphCache::storeGlyphs(const QHash ++it; ++i; } - QMetaObject::invokeMethod(m_sharedGraphicsCache, "insertItems", Qt::QueuedConnection, - Q_ARG(QByteArray, m_cacheId), - Q_ARG(QVector, glyphIds), - Q_ARG(QVector, images)); + QSGMainThreadInvoker *invoker = QSGMainThreadInvoker::instance(); + QCoreApplication::postEvent(invoker, new QSGInsertItemsEvent(m_sharedGraphicsCache, + m_cacheId, + glyphIds, + images)); } processPendingGlyphs(); @@ -225,9 +325,10 @@ void QSGSharedDistanceFieldGlyphCache::releaseGlyphs(const QSet &glyphs glyphsVector.append(*glyphsIt); } - QMetaObject::invokeMethod(m_sharedGraphicsCache, "releaseItems", Qt::QueuedConnection, - Q_ARG(QByteArray, m_cacheId), - Q_ARG(QVector, glyphsVector)); + QSGMainThreadInvoker *mainThreadInvoker = QSGMainThreadInvoker::instance(); + QCoreApplication::postEvent(mainThreadInvoker, new QSGReleaseItemsEvent(m_sharedGraphicsCache, + m_cacheId, + glyphsVector)); } void QSGSharedDistanceFieldGlyphCache::registerOwnerElement(QQuickItem *ownerElement) -- 2.7.4