diff options
Diffstat (limited to 'src/quick/scenegraph')
19 files changed, 194 insertions, 874 deletions
diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp index 42b9f526d0..8632ea0b52 100644 --- a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp +++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp @@ -198,9 +198,9 @@ ShaderManager::Shader *ShaderManager::prepareMaterialNoRewrite(QSGMaterial *mate void ShaderManager::invalidated() { - qDeleteAll(stockShaders.values()); + qDeleteAll(stockShaders); stockShaders.clear(); - qDeleteAll(rewrittenShaders.values()); + qDeleteAll(rewrittenShaders); rewrittenShaders.clear(); delete blitProgram; blitProgram = 0; @@ -487,6 +487,11 @@ void Updater::visitGeometryNode(Node *n) if (e->batch) renderer->invalidateBatchAndOverlappingRenderOrders(e->batch); } + if (n->dirtyState & QSGNode::DirtyMaterial) { + Element *e = n->element(); + if (e->batch && e->batch->isMaterialCompatible(e) == BatchBreaksOnCompare) + renderer->invalidateBatchAndOverlappingRenderOrders(e->batch); + } } SHADOWNODE_TRAVERSE(n) visitNode(*child); @@ -1081,6 +1086,9 @@ void Renderer::nodeWasRemoved(Node *node) if (e) { e->removed = true; m_elementsToDelete.add(e); + + if (m_renderNodeElements.isEmpty()) + m_useDepthBuffer = context()->openglContext()->format().depthBufferSize() > 0; } } @@ -1213,10 +1221,7 @@ void Renderer::nodeChanged(QSGNode *node, QSGNode::DirtyState state) if (e->isMaterialBlended != blended) { m_rebuild |= Renderer::FullRebuild; e->isMaterialBlended = blended; - } else if (e->batch) { - if (e->batch->isMaterialCompatible(e) == BatchBreaksOnCompare) - invalidateBatchAndOverlappingRenderOrders(e->batch); - } else { + } else if (!e->batch) { m_rebuild |= Renderer::BuildBatches; } } @@ -2554,8 +2559,15 @@ void Renderer::render() QSGNodeDumper::dump(rootNode()); } - if (Q_UNLIKELY(debug_render() || debug_build())) { + QElapsedTimer timer; + quint64 timeRenderLists = 0; + quint64 timePrepareOpaque = 0; + quint64 timePrepareAlpha = 0; + quint64 timeSorting = 0; + quint64 timeUploadOpaque = 0; + quint64 timeUploadAlpha = 0; + if (Q_UNLIKELY(debug_render() || debug_build())) { QByteArray type("rebuild:"); if (m_rebuild == 0) type += " none"; @@ -2571,6 +2583,7 @@ void Renderer::render() } qDebug() << "Renderer::render()" << this << type; + timer.start(); } if (m_vao) @@ -2597,6 +2610,7 @@ void Renderer::render() } } } + if (Q_UNLIKELY(debug_render())) timeRenderLists = timer.restart(); for (int i=0; i<m_opaqueBatches.size(); ++i) m_opaqueBatches.at(i)->cleanupRemovedElements(); @@ -2609,7 +2623,9 @@ void Renderer::render() if (m_rebuild & BuildBatches) { prepareOpaqueBatches(); + if (Q_UNLIKELY(debug_render())) timePrepareOpaque = timer.restart(); prepareAlphaBatches(); + if (Q_UNLIKELY(debug_render())) timePrepareAlpha = timer.restart(); if (Q_UNLIKELY(debug_build())) { qDebug() << "Opaque Batches:"; @@ -2629,8 +2645,11 @@ void Renderer::render() } } } + } else { + if (Q_UNLIKELY(debug_render())) timePrepareOpaque = timePrepareAlpha = timer.restart(); } + deleteRemovedElements(); if (m_rebuild != 0) { @@ -2646,6 +2665,8 @@ void Renderer::render() m_zRange = 1.0 / (m_nextRenderOrder); } + if (Q_UNLIKELY(debug_render())) timeSorting = timer.restart(); + int largestVBO = 0; #ifdef QSG_SEPARATE_INDEX_BUFFER int largestIBO = 0; @@ -2660,6 +2681,8 @@ void Renderer::render() #endif uploadBatch(b); } + if (Q_UNLIKELY(debug_render())) timeUploadOpaque = timer.restart(); + if (Q_UNLIKELY(debug_upload())) qDebug() << "Uploading Alpha Batches:"; for (int i=0; i<m_alphaBatches.size(); ++i) { @@ -2670,6 +2693,7 @@ void Renderer::render() largestIBO = qMax(b->ibo.size, largestIBO); #endif } + if (Q_UNLIKELY(debug_render())) timeUploadAlpha = timer.restart(); if (largestVBO * 2 < m_vertexUploadPool.size()) m_vertexUploadPool.resize(largestVBO * 2); @@ -2680,6 +2704,15 @@ void Renderer::render() renderBatches(); + if (Q_UNLIKELY(debug_render())) { + qDebug(" -> times: build: %d, prepare(opaque/alpha): %d/%d, sorting: %d, upload(opaque/alpha): %d/%d, render: %d", + (int) timeRenderLists, + (int) timePrepareOpaque, (int) timePrepareAlpha, + (int) timeSorting, + (int) timeUploadOpaque, (int) timeUploadAlpha, + (int) timer.elapsed()); + } + m_rebuild = 0; m_renderOrderRebuildLower = -1; m_renderOrderRebuildUpper = -1; diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h index 6b494dbaeb..d19fa0e17d 100644 --- a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h +++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h @@ -100,6 +100,7 @@ template <typename Type, int PageSize> class Allocator { public: Allocator() + : m_freePage(0) { pages.push_back(new AllocatorPage<Type, PageSize>()); } @@ -112,14 +113,21 @@ public: Type *allocate() { AllocatorPage<Type, PageSize> *p = 0; - for (int i=0; i<pages.size(); ++i) { + for (int i = m_freePage; i < pages.size(); i++) { if (pages.at(i)->available > 0) { p = pages.at(i); + m_freePage = i; break; } } + + // we couldn't find a free page from m_freePage to the last page. + // either there is no free pages, or there weren't any in the area we + // scanned: rescanning is expensive, so let's just assume there isn't + // one. when an item is released, we'll reset m_freePage anyway. if (!p) { p = new AllocatorPage<Type, PageSize>(); + m_freePage = pages.count(); pages.push_back(p); } uint pos = p->blocks[PageSize - p->available]; @@ -151,6 +159,9 @@ public: delete page; page = pages.back(); } + + // Reset the free page to force a scan for a new free point. + m_freePage = 0; } void release(Type *t) @@ -172,6 +183,7 @@ public: } QVector<AllocatorPage<Type, PageSize> *> pages; + int m_freePage; }; @@ -500,8 +512,8 @@ public: ShaderManager(QSGRenderContext *ctx) : blitProgram(0), visualizeProgram(0), context(ctx) { } ~ShaderManager() { - qDeleteAll(rewrittenShaders.values()); - qDeleteAll(stockShaders.values()); + qDeleteAll(rewrittenShaders); + qDeleteAll(stockShaders); } public Q_SLOTS: diff --git a/src/quick/scenegraph/qsgadaptationlayer.cpp b/src/quick/scenegraph/qsgadaptationlayer.cpp index 4f5c4efe14..bf97133e97 100644 --- a/src/quick/scenegraph/qsgadaptationlayer.cpp +++ b/src/quick/scenegraph/qsgadaptationlayer.cpp @@ -165,7 +165,9 @@ void QSGDistanceFieldGlyphCache::update() Q_QUICK_SG_PROFILE_START(QQuickProfiler::SceneGraphAdaptationLayerFrame); QList<QDistanceField> distanceFields; - for (int i = 0; i < m_pendingGlyphs.size(); ++i) { + const int pendingGlyphsSize = m_pendingGlyphs.size(); + distanceFields.reserve(pendingGlyphsSize); + for (int i = 0; i < pendingGlyphsSize; ++i) { GlyphData &gd = glyphData(m_pendingGlyphs.at(i)); distanceFields.append(QDistanceField(gd.path, m_pendingGlyphs.at(i), diff --git a/src/quick/scenegraph/qsgcontext.cpp b/src/quick/scenegraph/qsgcontext.cpp index 418d571ae6..150f8475d8 100644 --- a/src/quick/scenegraph/qsgcontext.cpp +++ b/src/quick/scenegraph/qsgcontext.cpp @@ -41,7 +41,6 @@ #include <QtQuick/private/qsgdefaultglyphnode_p.h> #include <QtQuick/private/qsgdistancefieldglyphnode_p.h> #include <QtQuick/private/qsgdistancefieldglyphnode_p_p.h> -#include <QtQuick/private/qsgshareddistancefieldglyphcache_p.h> #include <QtQuick/private/qsgatlastexture_p.h> #include <QtQuick/private/qsgrenderloop_p.h> #include <QtQuick/private/qsgdefaultlayer_p.h> @@ -60,15 +59,10 @@ #include <QtQuick/private/qsgtexture_p.h> #include <QtGui/private/qguiapplication_p.h> #include <QtCore/private/qabstractanimation_p.h> -#include <qpa/qplatformintegration.h> - -#include <qpa/qplatformsharedgraphicscache.h> #include <private/qobject_p.h> #include <qmutex.h> -#include <private/qqmlprofilerservice_p.h> - DEFINE_BOOL_CONFIG_OPTION(qmlDisableDistanceField, QML_DISABLE_DISTANCEFIELD) /* @@ -572,35 +566,7 @@ QSGDistanceFieldGlyphCache *QSGRenderContext::distanceFieldGlyphCache(const QRaw QSGDistanceFieldGlyphCache *cache = m_distanceFieldCacheManager->cache(font); if (!cache) { - QPlatformIntegration *platformIntegration = QGuiApplicationPrivate::platformIntegration(); - if (platformIntegration != 0 - && platformIntegration->hasCapability(QPlatformIntegration::SharedGraphicsCache)) { - QFontEngine *fe = QRawFontPrivate::get(font)->fontEngine; - if (!fe->faceId().filename.isEmpty()) { - QByteArray keyName = fe->faceId().filename; - if (font.style() != QFont::StyleNormal) - keyName += QByteArray(" I"); - if (font.weight() != QFont::Normal) - keyName += ' ' + QByteArray::number(font.weight()); - keyName += QByteArray(" DF"); - QPlatformSharedGraphicsCache *sharedGraphicsCache = - platformIntegration->createPlatformSharedGraphicsCache(keyName); - - if (sharedGraphicsCache != 0) { - sharedGraphicsCache->ensureCacheInitialized(keyName, - QPlatformSharedGraphicsCache::OpenGLTexture, - QPlatformSharedGraphicsCache::Alpha8); - - cache = new QSGSharedDistanceFieldGlyphCache(keyName, - sharedGraphicsCache, - m_distanceFieldCacheManager, - openglContext(), - font); - } - } - } - if (!cache) - cache = new QSGDefaultDistanceFieldGlyphCache(m_distanceFieldCacheManager, openglContext(), font); + cache = new QSGDefaultDistanceFieldGlyphCache(m_distanceFieldCacheManager, openglContext(), font); m_distanceFieldCacheManager->insertCache(font, cache); } @@ -676,7 +642,7 @@ void QSGRenderContext::invalidate() qDeleteAll(m_texturesToDelete); m_texturesToDelete.clear(); - qDeleteAll(m_textures.values()); + qDeleteAll(m_textures); m_textures.clear(); /* The cleanup of the atlas textures is a bit intriguing. @@ -767,22 +733,26 @@ QSGDepthStencilBufferManager *QSGRenderContext::depthStencilBufferManager() will be called with \a image as argument. */ -QSGTexture *QSGRenderContext::createTexture(const QImage &image) const +QSGTexture *QSGRenderContext::createTexture(const QImage &image, uint flags) const { - if (!openglContext()) - return 0; - QSGTexture *t = m_atlasManager->create(image); - if (t) - return t; - return createTextureNoAtlas(image); -} + bool atlas = flags & CreateTexture_Atlas; + bool mipmap = flags & CreateTexture_Mipmap; + bool alpha = flags & CreateTexture_Alpha; -QSGTexture *QSGRenderContext::createTextureNoAtlas(const QImage &image) const -{ - QSGPlainTexture *t = new QSGPlainTexture(); - if (!image.isNull()) - t->setImage(image); - return t; + // The atlas implementation is only supported from the render thread and + // does not support mipmaps. + if (!mipmap && atlas && openglContext() && QThread::currentThread() == openglContext()->thread()) { + QSGTexture *t = m_atlasManager->create(image, alpha); + if (t) + return t; + } + + QSGPlainTexture *texture = new QSGPlainTexture(); + texture->setImage(image); + if (texture->hasAlphaChannel() && !alpha) + texture->setHasAlphaChannel(false); + + return texture; } /*! diff --git a/src/quick/scenegraph/qsgcontext_p.h b/src/quick/scenegraph/qsgcontext_p.h index d1897f20f9..49b6f6e2a0 100644 --- a/src/quick/scenegraph/qsgcontext_p.h +++ b/src/quick/scenegraph/qsgcontext_p.h @@ -88,6 +88,12 @@ class Q_QUICK_PRIVATE_EXPORT QSGRenderContext : public QObject { Q_OBJECT public: + enum CreateTextureFlags { + CreateTexture_Alpha = 0x1, + CreateTexture_Atlas = 0x2, + CreateTexture_Mipmap = 0x4 + }; + QSGRenderContext(QSGContext *context); ~QSGRenderContext(); @@ -107,8 +113,8 @@ public: virtual QSGDistanceFieldGlyphCache *distanceFieldGlyphCache(const QRawFont &font); QSGTexture *textureForFactory(QQuickTextureFactory *factory, QQuickWindow *window); - virtual QSGTexture *createTexture(const QImage &image) const; - virtual QSGTexture *createTextureNoAtlas(const QImage &image) const; + virtual QSGTexture *createTexture(const QImage &image, uint flags = CreateTexture_Alpha) const; + virtual QSGRenderer *createRenderer(); virtual void compile(QSGMaterialShader *shader, QSGMaterial *material, const char *vertexCode = 0, const char *fragmentCode = 0); diff --git a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp index c84e6628a5..14bc0fad07 100644 --- a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp +++ b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp @@ -104,8 +104,11 @@ char const *const *QSGTextMaskShader::attributeNames() const } QSGTextMaskShader::QSGTextMaskShader(QFontEngine::GlyphFormat glyphFormat) - : QSGMaterialShader(*new QSGMaterialShaderPrivate), - m_glyphFormat(glyphFormat) + : QSGMaterialShader(*new QSGMaterialShaderPrivate) + , m_matrix_id(-1) + , m_color_id(-1) + , m_textureScale_id(-1) + , m_glyphFormat(glyphFormat) { setShaderSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/scenegraph/shaders/textmask.vert")); setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/scenegraph/shaders/textmask.frag")); @@ -435,7 +438,9 @@ void QSGTextMaskMaterial::populate(const QPointF &p, { Q_ASSERT(m_font.isValid()); QVector<QFixedPoint> fixedPointPositions; - for (int i=0; i<glyphPositions.size(); ++i) + const int glyphPositionsSize = glyphPositions.size(); + fixedPointPositions.reserve(glyphPositionsSize); + for (int i=0; i < glyphPositionsSize; ++i) fixedPointPositions.append(QFixedPoint::fromPointF(glyphPositions.at(i))); QTextureGlyphCache *cache = glyphCache(); diff --git a/src/quick/scenegraph/qsgdistancefieldglyphnode.cpp b/src/quick/scenegraph/qsgdistancefieldglyphnode.cpp index 7e602fc0bd..4630e45ecf 100644 --- a/src/quick/scenegraph/qsgdistancefieldglyphnode.cpp +++ b/src/quick/scenegraph/qsgdistancefieldglyphnode.cpp @@ -200,9 +200,11 @@ void QSGDistanceFieldGlyphNode::updateGeometry() const QVector<QPointF> positions = m_glyphs.positions(); qreal fontPixelSize = m_glyphs.rawFont().pixelSize(); - QVector<QSGGeometry::TexturedPoint2D> vp; + // The template parameters here are assuming that most strings are short, 64 + // characters or less. + QVarLengthArray<QSGGeometry::TexturedPoint2D, 256> vp; vp.reserve(indexes.size() * 4); - QVector<ushort> ip; + QVarLengthArray<ushort, 384> ip; ip.reserve(indexes.size() * 6); qreal maxTexMargin = m_glyph_cache->distanceFieldRadius(); diff --git a/src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp b/src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp index 422e31ad96..6f4b85a5b9 100644 --- a/src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp +++ b/src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp @@ -80,6 +80,11 @@ QSGDistanceFieldTextMaterialShader::QSGDistanceFieldTextMaterialShader() : QSGMaterialShader(), m_fontScale(1.0) , m_matrixScale(1.0) + , m_matrix_id(-1) + , m_textureScale_id(-1) + , m_alphaMin_id(-1) + , m_alphaMax_id(-1) + , m_color_id(-1) , m_lastAlphaMin(-1) , m_lastAlphaMax(-1) { @@ -260,6 +265,7 @@ protected: DistanceFieldStyledTextMaterialShader::DistanceFieldStyledTextMaterialShader() : QSGDistanceFieldTextMaterialShader() + , m_styleColor_id(-1) { } @@ -330,6 +336,8 @@ protected: DistanceFieldOutlineTextMaterialShader::DistanceFieldOutlineTextMaterialShader() : DistanceFieldStyledTextMaterialShader() + , m_outlineAlphaMax0_id(-1) + , m_outlineAlphaMax1_id(-1) { setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/scenegraph/shaders/distancefieldoutlinetext.frag")); } @@ -411,6 +419,7 @@ protected: DistanceFieldShiftedStyleTextMaterialShader::DistanceFieldShiftedStyleTextMaterialShader() : DistanceFieldStyledTextMaterialShader() + , m_shift_id(-1) { setShaderSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/scenegraph/shaders/distancefieldshiftedtext.vert")); setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/scenegraph/shaders/distancefieldshiftedtext.frag")); @@ -489,6 +498,8 @@ private: QSGHiQSubPixelDistanceFieldTextMaterialShader::QSGHiQSubPixelDistanceFieldTextMaterialShader() : QSGDistanceFieldTextMaterialShader() + , m_fontScale_id(-1) + , m_vecDelta_id(-1) { setShaderSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/scenegraph/shaders/hiqsubpixeldistancefieldtext.vert")); setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/scenegraph/shaders/hiqsubpixeldistancefieldtext.frag")); diff --git a/src/quick/scenegraph/qsgrenderloop.cpp b/src/quick/scenegraph/qsgrenderloop.cpp index 4d3f34c71c..3059b750f2 100644 --- a/src/quick/scenegraph/qsgrenderloop.cpp +++ b/src/quick/scenegraph/qsgrenderloop.cpp @@ -102,6 +102,22 @@ void QSGRenderLoop::cleanup() s_instance = 0; } +/*! + * Non-threaded render loops immediately run the job if there is a context. + */ +void QSGRenderLoop::postJob(QQuickWindow *window, QRunnable *job) +{ + Q_ASSERT(window); + Q_ASSERT(job); + + if (window->openglContext()) { + window->openglContext()->makeCurrent(window); + job->run(); + } + + delete job; +} + class QSGGuiThreadRenderLoop : public QSGRenderLoop { Q_OBJECT diff --git a/src/quick/scenegraph/qsgrenderloop_p.h b/src/quick/scenegraph/qsgrenderloop_p.h index 4293015b96..3336731fda 100644 --- a/src/quick/scenegraph/qsgrenderloop_p.h +++ b/src/quick/scenegraph/qsgrenderloop_p.h @@ -45,6 +45,7 @@ class QQuickWindow; class QSGContext; class QSGRenderContext; class QAnimationDriver; +class QRunnable; class Q_QUICK_PRIVATE_EXPORT QSGRenderLoop : public QObject { @@ -72,6 +73,7 @@ public: virtual QSGRenderContext *createRenderContext(QSGContext *) const = 0; virtual void releaseResources(QQuickWindow *window) = 0; + virtual void postJob(QQuickWindow *window, QRunnable *job); void addWindow(QQuickWindow *win) { m_windows.insert(win); } void removeWindow(QQuickWindow *win) { m_windows.remove(win); } diff --git a/src/quick/scenegraph/qsgshareddistancefieldglyphcache.cpp b/src/quick/scenegraph/qsgshareddistancefieldglyphcache.cpp deleted file mode 100644 index f1cc9d1a86..0000000000 --- a/src/quick/scenegraph/qsgshareddistancefieldglyphcache.cpp +++ /dev/null @@ -1,655 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtQuick module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#define EGL_EGLEXT_PROTOTYPES -#define GL_GLEXT_PROTOTYPES -#if defined(QSGSHAREDDISTANCEFIELDGLYPHCACHE_DEBUG) -#include <GLES2/gl2.h> -#include <GLES2/gl2ext.h> -#endif - -#include "qsgshareddistancefieldglyphcache_p.h" - -#include <QtCore/qhash.h> -#include <QtCore/qthread.h> -#include <QtCore/qcoreapplication.h> - -#include <qpa/qplatformsharedgraphicscache.h> - -#include <QtQuick/qquickwindow.h> - -// #define QSGSHAREDDISTANCEFIELDGLYPHCACHE_DEBUG - -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, - QOpenGLContext *c, - const QRawFont &font) - : 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", - cacheId.constData(), QThread::currentThreadId()); -#endif - - Q_ASSERT(sizeof(glyph_t) == sizeof(quint32)); - Q_ASSERT(sharedGraphicsCache != 0); - - connect(sharedGraphicsCache, SIGNAL(itemsMissing(QByteArray,QVector<quint32>)), - this, SLOT(reportItemsMissing(QByteArray,QVector<quint32>)), - Qt::DirectConnection); - 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*,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); - - Q_ASSERT(c); - 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() -{ - { - QHash<glyph_t, void *>::const_iterator it = m_bufferForGlyph.constBegin(); - while (it != m_bufferForGlyph.constEnd()) { - m_sharedGraphicsCache->dereferenceBuffer(it.value()); - ++it; - } - } - - { - QHash<quint32, PendingGlyph>::const_iterator it = m_pendingReadyGlyphs.constBegin(); - while (it != m_pendingReadyGlyphs.constEnd()) { - m_sharedGraphicsCache->dereferenceBuffer(it.value().buffer); - ++it; - } - } -} - -void QSGSharedDistanceFieldGlyphCache::requestGlyphs(const QSet<glyph_t> &glyphs) -{ - typedef QSet<glyph_t>::const_iterator GlyphSetConstIt; - - QMutexLocker locker(&m_pendingGlyphsMutex); - -#if defined(QSGSHAREDDISTANCEFIELDGLYPHCACHE_DEBUG) - qDebug("QSGSharedDistanceFieldGlyphCache::requestGlyphs() called for %s (%d glyphs)", - m_cacheId.constData(), glyphs.size()); -#endif - - m_requestedGlyphsThatHaveNotBeenReturned.unite(glyphs); - m_requestedGlyphs.unite(glyphs); - - QVector<quint32> glyphsVector; - glyphsVector.reserve(glyphs.size()); - - for (GlyphSetConstIt it = glyphs.constBegin(), cend = glyphs.constEnd(); it != cend; ++it) { - Q_ASSERT(!m_bufferForGlyph.contains(*it)); - glyphsVector.append(*it); - } - - 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()) - m_pendingGlyphsCondition.wait(&m_pendingGlyphsMutex); - } -} - -void QSGSharedDistanceFieldGlyphCache::storeGlyphs(const QList<QDistanceField> &glyphs) -{ - { - QMutexLocker locker(&m_pendingGlyphsMutex); -#if defined(QSGSHAREDDISTANCEFIELDGLYPHCACHE_DEBUG) - qDebug("QSGSharedDistanceFieldGlyphCache::storeGlyphs() called for %s (%d glyphs)", - m_cacheId.constData(), glyphs.size()); -#endif - - int glyphCount = glyphs.size(); - QVector<quint32> glyphIds(glyphCount); - QVector<QImage> images(glyphCount); - for (int i = 0; i < glyphs.size(); ++i) { - const QDistanceField &df = glyphs.at(i); - m_requestedGlyphsThatHaveNotBeenReturned.insert(df.glyph()); - glyphIds[i] = df.glyph(); - // ### TODO: Handle QDistanceField in QPlatformSharedGraphicsCache - images[i] = df.toImage(QImage::Format_Indexed8); - } - - m_hasPostedEvents = true; - QSGMainThreadInvoker *invoker = QSGMainThreadInvoker::instance(); - QCoreApplication::postEvent(invoker, new QSGInsertItemsEvent(m_sharedGraphicsCache, - m_cacheId, - glyphIds, - images, - m_isInSceneGraphUpdate)); - } - - processPendingGlyphs(); -} - -void QSGSharedDistanceFieldGlyphCache::referenceGlyphs(const QSet<glyph_t> &glyphs) -{ - Q_UNUSED(glyphs); - - // Intentionally empty. Not required in this implementation, since the glyphs are reference - // counted outside and releaseGlyphs() will only be called when there are no more references. -} - -void QSGSharedDistanceFieldGlyphCache::releaseGlyphs(const QSet<glyph_t> &glyphs) -{ - typedef QSet<glyph_t>::const_iterator GlyphSetConstIt; - -#if defined(QSGSHAREDDISTANCEFIELDGLYPHCACHE_DEBUG) - qDebug("QSGSharedDistanceFieldGlyphCache::releaseGlyphs() called for %s (%d glyphs)", - m_cacheId.constData(), glyphs.size()); -#endif - - m_requestedGlyphs.subtract(glyphs); - - QVector<quint32> glyphsVector; - glyphsVector.reserve(glyphs.size()); - - for (GlyphSetConstIt glyphsIt = glyphs.constBegin(), cend = glyphs.constEnd(); glyphsIt != cend; ++glyphsIt) { - QHash<glyph_t, void *>::iterator bufferIt = m_bufferForGlyph.find(*glyphsIt); - if (bufferIt != m_bufferForGlyph.end()) { - void *buffer = bufferIt.value(); - removeGlyph(*glyphsIt); - m_bufferForGlyph.erase(bufferIt); - Q_ASSERT(!m_bufferForGlyph.contains(*glyphsIt)); - - if (!m_sharedGraphicsCache->dereferenceBuffer(buffer)) { -#if !defined(QT_NO_DEBUG) - bufferIt = m_bufferForGlyph.begin(); - while (bufferIt != m_bufferForGlyph.end()) { - Q_ASSERT(bufferIt.value() != buffer); - ++bufferIt; - } -#endif - } - } - - glyphsVector.append(*glyphsIt); - } - - m_hasPostedEvents = true; - QSGMainThreadInvoker *mainThreadInvoker = QSGMainThreadInvoker::instance(); - QCoreApplication::postEvent(mainThreadInvoker, new QSGReleaseItemsEvent(m_sharedGraphicsCache, - m_cacheId, - glyphsVector, - m_isInSceneGraphUpdate)); -} - -void QSGSharedDistanceFieldGlyphCache::registerOwnerElement(QQuickItem *ownerElement) -{ - 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) -{ - 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); - } -} - -namespace { - struct TextureContent { - QSize size; - QVector<glyph_t> glyphs; - }; -} - -void QSGSharedDistanceFieldGlyphCache::processPendingGlyphs() -{ - Q_ASSERT(QThread::currentThread() == thread()); - - waitForGlyphs(); - - { - QMutexLocker locker(&m_pendingGlyphsMutex); - if (m_pendingMissingGlyphs.isEmpty() - && m_pendingReadyGlyphs.isEmpty() - && m_pendingInvalidatedGlyphs.isEmpty()) { - return; - } - - { - QVector<glyph_t> pendingMissingGlyphs; - pendingMissingGlyphs.reserve(m_pendingMissingGlyphs.size()); - - QSet<glyph_t>::const_iterator it = m_pendingMissingGlyphs.constBegin(); - while (it != m_pendingMissingGlyphs.constEnd()) { - pendingMissingGlyphs.append(*it); - ++it; - } - - markGlyphsToRender(pendingMissingGlyphs); - } - - { - QVector<glyph_t> filteredPendingInvalidatedGlyphs; - filteredPendingInvalidatedGlyphs.reserve(m_pendingInvalidatedGlyphs.size()); - - QSet<glyph_t>::const_iterator it = m_pendingInvalidatedGlyphs.constBegin(); - while (it != m_pendingInvalidatedGlyphs.constEnd()) { - bool rerequestGlyph = false; - - // The glyph was invalidated right after being posted as ready, we throw away - // the ready glyph and rerequest it to be certain - QHash<quint32, PendingGlyph>::iterator pendingGlyphIt = m_pendingReadyGlyphs.find(*it); - if (pendingGlyphIt != m_pendingReadyGlyphs.end()) { - m_sharedGraphicsCache->dereferenceBuffer(pendingGlyphIt.value().buffer); - pendingGlyphIt = m_pendingReadyGlyphs.erase(pendingGlyphIt); - rerequestGlyph = true; - } - - void *bufferId = m_bufferForGlyph.value(*it, 0); - if (bufferId != 0) { - m_sharedGraphicsCache->dereferenceBuffer(bufferId); - m_bufferForGlyph.remove(*it); - rerequestGlyph = true; - } - - if (rerequestGlyph) - filteredPendingInvalidatedGlyphs.append(*it); - - ++it; - } - - // If this cache is still using the glyphs, reset the texture held by them, and mark them - // to be rendered again since they are still needed. - if (!filteredPendingInvalidatedGlyphs.isEmpty()) { - setGlyphsTexture(filteredPendingInvalidatedGlyphs, Texture()); - markGlyphsToRender(filteredPendingInvalidatedGlyphs); - } - } - - { - QList<GlyphPosition> glyphPositions; - - QHash<void *, TextureContent> textureContentForBuffer; - { - QHash<quint32, PendingGlyph>::iterator it = m_pendingReadyGlyphs.begin(); - while (it != m_pendingReadyGlyphs.end()) { - void *currentGlyphBuffer = m_bufferForGlyph.value(it.key(), 0); - if (currentGlyphBuffer != 0) { - if (!m_sharedGraphicsCache->dereferenceBuffer(currentGlyphBuffer)) { - Q_ASSERT(!textureContentForBuffer.contains(currentGlyphBuffer)); - } - } - - PendingGlyph &pendingGlyph = it.value(); - - // We don't ref or deref the buffer here, since it was already referenced when - // added to the pending ready glyphs - m_bufferForGlyph[it.key()] = pendingGlyph.buffer; - - textureContentForBuffer[pendingGlyph.buffer].size = pendingGlyph.bufferSize; - textureContentForBuffer[pendingGlyph.buffer].glyphs.append(it.key()); - - GlyphPosition glyphPosition; - glyphPosition.glyph = it.key(); - glyphPosition.position = pendingGlyph.position; - - glyphPositions.append(glyphPosition); - - ++it; - } - } - - setGlyphsPosition(glyphPositions); - - { - QHash<void *, TextureContent>::const_iterator it = textureContentForBuffer.constBegin(); - while (it != textureContentForBuffer.constEnd()) { - Texture texture; - texture.textureId = m_sharedGraphicsCache->textureIdForBuffer(it.key()); - texture.size = m_sharedGraphicsCache->sizeOfBuffer(it.key()); - - setGlyphsTexture(it.value().glyphs, texture); - - ++it; - } - } - } - - m_pendingMissingGlyphs.clear(); - m_pendingInvalidatedGlyphs.clear(); - m_pendingReadyGlyphs.clear(); - } -} - -void QSGSharedDistanceFieldGlyphCache::reportItemsAvailable(const QByteArray &cacheId, - 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); - if (m_cacheId != cacheId) - return; - - Q_ASSERT(itemIds.size() == positions.size()); - -#if defined(QSGSHAREDDISTANCEFIELDGLYPHCACHE_DEBUG) - qDebug("QSGSharedDistanceFieldGlyphCache::reportItemsUpdated() called for %s (%d glyphs)", - cacheId.constData(), itemIds.size()); -#endif - - for (int i=0; i<itemIds.size(); ++i) { - 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); - - m_sharedGraphicsCache->referenceBuffer(bufferId); - if (oldBuffer != 0) - m_sharedGraphicsCache->dereferenceBuffer(oldBuffer); - - m_requestedGlyphsThatHaveNotBeenReturned.remove(itemIds.at(i)); - } - } - } - - m_pendingGlyphsCondition.wakeAll(); - emit glyphsPending(); -} - -void QSGSharedDistanceFieldGlyphCache::reportItemsInvalidated(const QByteArray &cacheId, - const QVector<quint32> &itemIds) -{ - { - QMutexLocker locker(&m_pendingGlyphsMutex); - if (m_cacheId != cacheId) - return; - - for (int i=0; i<itemIds.size(); ++i) { - if (m_requestedGlyphs.contains(itemIds.at(i))) - m_pendingInvalidatedGlyphs.insert(itemIds.at(i)); - } - } - - emit glyphsPending(); -} - - -void QSGSharedDistanceFieldGlyphCache::reportItemsMissing(const QByteArray &cacheId, - const QVector<quint32> &itemIds) -{ - { - QMutexLocker locker(&m_pendingGlyphsMutex); - if (m_cacheId != cacheId) - return; - -#if defined(QSGSHAREDDISTANCEFIELDGLYPHCACHE_DEBUG) - qDebug("QSGSharedDistanceFieldGlyphCache::reportItemsMissing() called for %s (%d glyphs)", - cacheId.constData(), itemIds.size()); -#endif - - for (int i=0; i<itemIds.size(); ++i) { - if (m_requestedGlyphsThatHaveNotBeenReturned.remove(itemIds.at(i))) - m_pendingMissingGlyphs.insert(itemIds.at(i)); - } - } - - m_pendingGlyphsCondition.wakeAll(); - 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 diff --git a/src/quick/scenegraph/qsgshareddistancefieldglyphcache_p.h b/src/quick/scenegraph/qsgshareddistancefieldglyphcache_p.h deleted file mode 100644 index aee77c49c6..0000000000 --- a/src/quick/scenegraph/qsgshareddistancefieldglyphcache_p.h +++ /dev/null @@ -1,124 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtQuick module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QSGSHAREDDISTANCEFIELDGLYPHCACHE_H -#define QSGSHAREDDISTANCEFIELDGLYPHCACHE_H - -#include <QtCore/qwaitcondition.h> -#include <private/qsgadaptationlayer_p.h> - -QT_BEGIN_NAMESPACE - -class QPlatformSharedGraphicsCache; -class QSGSharedDistanceFieldGlyphCache : public QObject, public QSGDistanceFieldGlyphCache -{ - Q_OBJECT -public: - explicit QSGSharedDistanceFieldGlyphCache(const QByteArray &cacheId, - QPlatformSharedGraphicsCache *sharedGraphicsCache, - QSGDistanceFieldGlyphCacheManager *man, - QOpenGLContext *c, - const QRawFont &font); - ~QSGSharedDistanceFieldGlyphCache(); - - void registerOwnerElement(QQuickItem *ownerElement); - void unregisterOwnerElement(QQuickItem *ownerElement); - void processPendingGlyphs(); - - void requestGlyphs(const QSet<glyph_t> &glyphs); - void referenceGlyphs(const QSet<glyph_t> &glyphs); - void storeGlyphs(const QList<QDistanceField> &glyphs); - void releaseGlyphs(const QSet<glyph_t> &glyphs); - -Q_SIGNALS: - void glyphsPending(); - -private Q_SLOTS: - void reportItemsMissing(const QByteArray &cacheId, const QVector<quint32> &itemIds); - void reportItemsAvailable(const QByteArray &cacheId, - void *bufferId, - const QVector<quint32> &itemIds, - const QVector<QPoint> &positions); - void reportItemsUpdated(const QByteArray &cacheId, - void *bufferId, - const QVector<quint32> &itemIds, - const QVector<QPoint> &positions); - void reportItemsInvalidated(const QByteArray &cacheId, const QVector<quint32> &itemIds); - - void sceneGraphUpdateStarted(); - void sceneGraphUpdateDone(); - -private: - void waitForGlyphs(); - void saveTexture(GLuint textureId, int width, int height); - - QSet<quint32> m_requestedGlyphsThatHaveNotBeenReturned; - QSet<quint32> m_requestedGlyphs; - QWaitCondition m_pendingGlyphsCondition; - QByteArray m_cacheId; - QPlatformSharedGraphicsCache *m_sharedGraphicsCache; - QMutex m_pendingGlyphsMutex; - - QSet<glyph_t> m_pendingInvalidatedGlyphs; - QSet<glyph_t> m_pendingMissingGlyphs; - - struct PendingGlyph - { - PendingGlyph() : buffer(0) {} - - void *buffer; - QSize bufferSize; - QPoint position; - }; - - struct Owner - { - Owner() : ref(0) {} - Owner(const Owner &o) : item(o.item), ref(o.ref) {} - Owner &operator =(const Owner &o) { item = o.item; ref = o.ref; return *this; } - - QPointer<QQuickItem> item; - int ref; - }; - - QHash<quint32, PendingGlyph> m_pendingReadyGlyphs; - QHash<glyph_t, void *> m_bufferForGlyph; - QHash<QQuickItem *, Owner> m_registeredOwners; - - bool m_isInSceneGraphUpdate; - bool m_hasPostedEvents; -}; - -QT_END_NAMESPACE - -#endif // QSGSHAREDDISTANCEFIELDGLYPHCACHE_H diff --git a/src/quick/scenegraph/qsgthreadedrenderloop.cpp b/src/quick/scenegraph/qsgthreadedrenderloop.cpp index 2cebbaf484..4b78fefa99 100644 --- a/src/quick/scenegraph/qsgthreadedrenderloop.cpp +++ b/src/quick/scenegraph/qsgthreadedrenderloop.cpp @@ -54,7 +54,8 @@ #include <private/qquickanimatorcontroller_p.h> #include <private/qquickprofiler_p.h> -#include <private/qqmldebugservice_p.h> +#include <private/qqmldebugserviceinterfaces_p.h> +#include <private/qqmldebugconnector_p.h> #include <private/qquickshadereffectnode_p.h> @@ -147,6 +148,9 @@ const QEvent::Type WM_TryRelease = QEvent::Type(QEvent::User + 4); // called. const QEvent::Type WM_Grab = QEvent::Type(QEvent::User + 5); +// Passed by the window when there is a render job to run +const QEvent::Type WM_PostJob = QEvent::Type(QEvent::User + 6); + template <typename T> T *windowFor(const QList<T> &list, QQuickWindow *window) { for (int i=0; i<list.size(); ++i) { @@ -200,6 +204,14 @@ public: QImage *image; }; +class WMJobEvent : public WMWindowEvent +{ +public: + WMJobEvent(QQuickWindow *c, QRunnable *postedJob) + : WMWindowEvent(c, WM_PostJob), job(postedJob) {} + ~WMJobEvent() { delete job; } + QRunnable *job; +}; class QSGRenderThreadEventQueue : public QQueue<QEvent *> { @@ -345,7 +357,6 @@ bool QSGRenderThread::event(QEvent *e) if (window) { QQuickWindowPrivate::get(window)->fireAboutToStop(); qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- window removed"; - gl->doneCurrent(); window = 0; } waitCondition.wakeOne(); @@ -396,20 +407,21 @@ bool QSGRenderThread::event(QEvent *e) case WM_Grab: { qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "WM_Grab"; WMGrabEvent *ce = static_cast<WMGrabEvent *>(e); - Q_ASSERT(ce->window == window); + Q_ASSERT(ce->window); + Q_ASSERT(ce->window == window || !window); mutex.lock(); - if (window) { - gl->makeCurrent(window); + if (ce->window) { + gl->makeCurrent(ce->window); qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- sync scene graph"; - QQuickWindowPrivate *d = QQuickWindowPrivate::get(window); + QQuickWindowPrivate *d = QQuickWindowPrivate::get(ce->window); d->syncSceneGraph(); qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- rendering scene graph"; - QQuickWindowPrivate::get(window)->renderSceneGraph(windowSize); + QQuickWindowPrivate::get(ce->window)->renderSceneGraph(ce->window->size()); qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- grabbing result"; - *ce->image = qt_gl_read_framebuffer(windowSize * window->effectiveDevicePixelRatio(), false, false); + *ce->image = qt_gl_read_framebuffer(windowSize * ce->window->effectiveDevicePixelRatio(), false, false); } qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- waking gui to handle result"; waitCondition.wakeOne(); @@ -417,6 +429,20 @@ bool QSGRenderThread::event(QEvent *e) return true; } + case WM_PostJob: { + qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "WM_PostJob"; + WMJobEvent *ce = static_cast<WMJobEvent *>(e); + Q_ASSERT(ce->window == window); + if (window) { + gl->makeCurrent(window); + ce->job->run(); + delete ce->job; + ce->job = 0; + qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- job done"; + } + return true; + } + case WM_RequestRepaint: qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "WM_RequestPaint"; // When GUI posts this event, it is followed by a polishAndSync, so we mustn't @@ -666,7 +692,7 @@ void QSGRenderThread::run() qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "run()"; animatorDriver = sgrc->sceneGraphContext()->createAnimationDriver(0); animatorDriver->install(); - if (QQmlDebugService::isDebuggingEnabled()) + if (QQmlDebugConnector::service<QQmlProfilerService>()) QQuickProfiler::registerAnimationCallback(); while (active) { @@ -993,20 +1019,20 @@ void QSGThreadedRenderLoop::maybeUpdate(Window *w) if (!QCoreApplication::instance()) return; + if (!w || !w->thread->isRunning()) + return; + QThread *current = QThread::currentThread(); if (current != QCoreApplication::instance()->thread() && (current != w->thread || !m_lockedForSync)) { qWarning() << "Updates can only be scheduled from GUI thread or from QQuickItem::updatePaintNode()"; return; } - if (!w || !w->thread->isRunning()) { - return; - } qCDebug(QSG_LOG_RENDERLOOP) << "update from item" << w->window; // Call this function from the Gui thread later as startTimer cannot be // called from the render thread. - if (QThread::currentThread() == w->thread) { + if (current == w->thread) { qCDebug(QSG_LOG_RENDERLOOP) << "- on render thread"; w->updateDuringSync = true; return; @@ -1242,6 +1268,18 @@ QImage QSGThreadedRenderLoop::grab(QQuickWindow *window) return result; } +/*! + * Posts a new job event to the render thread. + * Returns true if posting succeeded. + */ +void QSGThreadedRenderLoop::postJob(QQuickWindow *window, QRunnable *job) +{ + Window *w = windowFor(m_windows, window); + if (w && w->thread && w->thread->window) + w->thread->postEvent(new WMJobEvent(window, job)); + else + delete job; +} #include "qsgthreadedrenderloop.moc" diff --git a/src/quick/scenegraph/qsgthreadedrenderloop_p.h b/src/quick/scenegraph/qsgthreadedrenderloop_p.h index d5ffbf10a3..67df9dcd31 100644 --- a/src/quick/scenegraph/qsgthreadedrenderloop_p.h +++ b/src/quick/scenegraph/qsgthreadedrenderloop_p.h @@ -71,6 +71,7 @@ public: void releaseResources(QQuickWindow *window); bool event(QEvent *); + void postJob(QQuickWindow *window, QRunnable *job); bool interleaveIncubation() const; diff --git a/src/quick/scenegraph/scenegraph.pri b/src/quick/scenegraph/scenegraph.pri index 480ac5e569..84cc2ba135 100644 --- a/src/quick/scenegraph/scenegraph.pri +++ b/src/quick/scenegraph/scenegraph.pri @@ -79,7 +79,6 @@ HEADERS += \ $$PWD/qsgdefaultglyphnode_p_p.h \ $$PWD/qsgdefaultimagenode_p.h \ $$PWD/qsgdefaultrectanglenode_p.h \ - $$PWD/qsgshareddistancefieldglyphcache_p.h \ $$PWD/qsgrenderloop_p.h \ $$PWD/qsgthreadedrenderloop_p.h \ $$PWD/qsgwindowsrenderloop_p.h \ @@ -96,7 +95,6 @@ SOURCES += \ $$PWD/qsgdistancefieldglyphnode_p.cpp \ $$PWD/qsgdefaultimagenode.cpp \ $$PWD/qsgdefaultrectanglenode.cpp \ - $$PWD/qsgshareddistancefieldglyphcache.cpp \ $$PWD/qsgrenderloop.cpp \ $$PWD/qsgthreadedrenderloop.cpp \ $$PWD/qsgwindowsrenderloop.cpp \ diff --git a/src/quick/scenegraph/util/qsgatlastexture.cpp b/src/quick/scenegraph/util/qsgatlastexture.cpp index b862fa6a2b..8c649fb6bd 100644 --- a/src/quick/scenegraph/util/qsgatlastexture.cpp +++ b/src/quick/scenegraph/util/qsgatlastexture.cpp @@ -112,13 +112,15 @@ void Manager::invalidate() } } -QSGTexture *Manager::create(const QImage &image) +QSGTexture *Manager::create(const QImage &image, bool hasAlphaChannel) { - QSGTexture *t = 0; + Texture *t = 0; if (image.width() < m_atlas_size_limit && image.height() < m_atlas_size_limit) { if (!m_atlas) m_atlas = new Atlas(m_atlas_size); t = m_atlas->create(image); + if (!hasAlphaChannel && t->hasAlphaChannel()) + t->setHasAlphaChannel(false); } return t; } diff --git a/src/quick/scenegraph/util/qsgatlastexture_p.h b/src/quick/scenegraph/util/qsgatlastexture_p.h index 399d5fd669..c0f6ab912d 100644 --- a/src/quick/scenegraph/util/qsgatlastexture_p.h +++ b/src/quick/scenegraph/util/qsgatlastexture_p.h @@ -58,7 +58,7 @@ public: Manager(); ~Manager(); - QSGTexture *create(const QImage &image); + QSGTexture *create(const QImage &image, bool hasAlphaChannel); void invalidate(); private: @@ -114,6 +114,7 @@ public: int textureId() const { return m_atlas->textureId(); } QSize textureSize() const { return atlasSubRectWithoutPadding().size(); } + void setHasAlphaChannel(bool alpha) { m_has_alpha = alpha; } bool hasAlphaChannel() const { return m_has_alpha; } bool hasMipmaps() const { return false; } bool isAtlasTexture() const { return true; } diff --git a/src/quick/scenegraph/util/qsgengine.cpp b/src/quick/scenegraph/util/qsgengine.cpp index c0ddf25765..8622f8edc1 100644 --- a/src/quick/scenegraph/util/qsgengine.cpp +++ b/src/quick/scenegraph/util/qsgengine.cpp @@ -150,7 +150,7 @@ QSGAbstractRenderer *QSGEngine::createRenderer() const /*! Creates a texture using the data of \a image - Valid \a options are TextureCanUseAtlas + Valid \a options are TextureCanUseAtlas and TextureIsOpaque. The caller takes ownership of the texture and the texture should only be used with this engine. @@ -160,13 +160,12 @@ QSGAbstractRenderer *QSGEngine::createRenderer() const QSGTexture *QSGEngine::createTextureFromImage(const QImage &image, CreateTextureOptions options) const { Q_D(const QSGEngine); - if (!d->sgRenderContext->isValid()) - return 0; - - if (options & TextureCanUseAtlas) - return d->sgRenderContext->createTexture(image); - else - return d->sgRenderContext->createTextureNoAtlas(image); + if (!d->sgRenderContext->isValid()) + return 0; + uint flags = 0; + if (options & TextureCanUseAtlas) flags |= QSGRenderContext::CreateTexture_Atlas; + if (!(options & TextureIsOpaque)) flags |= QSGRenderContext::CreateTexture_Alpha; + return d->sgRenderContext->createTexture(image, flags); } /*! diff --git a/src/quick/scenegraph/util/qsgengine.h b/src/quick/scenegraph/util/qsgengine.h index 9a74a02aa1..325d3a9ca2 100644 --- a/src/quick/scenegraph/util/qsgengine.h +++ b/src/quick/scenegraph/util/qsgengine.h @@ -52,7 +52,8 @@ public: enum CreateTextureOption { TextureHasAlphaChannel = 0x0001, TextureOwnsGLTexture = 0x0004, - TextureCanUseAtlas = 0x0008 + TextureCanUseAtlas = 0x0008, + TextureIsOpaque = 0x0010 }; Q_DECLARE_FLAGS(CreateTextureOptions, CreateTextureOption) |