diff options
Diffstat (limited to 'src/quick/scenegraph')
55 files changed, 709 insertions, 998 deletions
diff --git a/src/quick/scenegraph/coreapi/qsgabstractrenderer_p.h b/src/quick/scenegraph/coreapi/qsgabstractrenderer_p.h index c5504513f4..17de89bf11 100644 --- a/src/quick/scenegraph/coreapi/qsgabstractrenderer_p.h +++ b/src/quick/scenegraph/coreapi/qsgabstractrenderer_p.h @@ -34,6 +34,17 @@ #ifndef QSGABSTRACTRENDERER_P_H #define QSGABSTRACTRENDERER_P_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include "qsgabstractrenderer.h" #include "qsgnode.h" diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp index 4b0bc683c2..b1792d27a7 100644 --- a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp +++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp @@ -61,6 +61,8 @@ QT_BEGIN_NAMESPACE extern QByteArray qsgShaderRewriter_insertZAttributes(const char *input, QSurfaceFormat::OpenGLContextProfile profile); +int qt_sg_envInt(const char *name, int defaultValue); + namespace QSGBatchRenderer { @@ -198,9 +200,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 +489,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); @@ -780,30 +787,17 @@ Renderer::Renderer(QSGRenderContext *ctx) } m_bufferStrategy = GL_STATIC_DRAW; - QByteArray strategy = qgetenv("QSG_RENDERER_BUFFER_STRATEGY"); - if (strategy == "dynamic") { - m_bufferStrategy = GL_DYNAMIC_DRAW; - } else if (strategy == "stream") { - m_bufferStrategy = GL_STREAM_DRAW; - } - - m_batchNodeThreshold = 64; - QByteArray alternateThreshold = qgetenv("QSG_RENDERER_BATCH_NODE_THRESHOLD"); - if (alternateThreshold.length() > 0) { - bool ok = false; - int threshold = alternateThreshold.toInt(&ok); - if (ok) - m_batchNodeThreshold = threshold; - } - - m_batchVertexThreshold = 1024; - alternateThreshold = qgetenv("QSG_RENDERER_BATCH_VERTEX_THRESHOLD"); - if (alternateThreshold.length() > 0) { - bool ok = false; - int threshold = alternateThreshold.toInt(&ok); - if (ok) - m_batchVertexThreshold = threshold; + if (Q_UNLIKELY(qEnvironmentVariableIsSet("QSG_RENDERER_BUFFER_STRATEGY"))) { + const QByteArray strategy = qgetenv("QSG_RENDERER_BUFFER_STRATEGY"); + if (strategy == "dynamic") + m_bufferStrategy = GL_DYNAMIC_DRAW; + else if (strategy == "stream") + m_bufferStrategy = GL_STREAM_DRAW; } + + m_batchNodeThreshold = qt_sg_envInt("QSG_RENDERER_BATCH_NODE_THRESHOLD", 64); + m_batchVertexThreshold = qt_sg_envInt("QSG_RENDERER_BATCH_VERTEX_THRESHOLD", 1024); + if (Q_UNLIKELY(debug_build() || debug_render())) { qDebug() << "Batch thresholds: nodes:" << m_batchNodeThreshold << " vertices:" << m_batchVertexThreshold; qDebug() << "Using buffer strategy:" << (m_bufferStrategy == GL_STATIC_DRAW ? "static" : (m_bufferStrategy == GL_DYNAMIC_DRAW ? "dynamic" : "stream")); @@ -816,7 +810,8 @@ Renderer::Renderer(QSGRenderContext *ctx) m_vao->create(); } - m_useDepthBuffer = ctx->openglContext()->format().depthBufferSize() > 0; + bool useDepth = qEnvironmentVariableIsEmpty("QSG_NO_DEPTH_BUFFER"); + m_useDepthBuffer = useDepth && ctx->openglContext()->format().depthBufferSize() > 0; } static void qsg_wipeBuffer(Buffer *buffer, QOpenGLFunctions *funcs) @@ -1081,6 +1076,11 @@ void Renderer::nodeWasRemoved(Node *node) if (e) { e->removed = true; m_elementsToDelete.add(e); + + if (m_renderNodeElements.isEmpty()) { + static bool useDepth = qEnvironmentVariableIsEmpty("QSG_NO_DEPTH_BUFFER"); + m_useDepthBuffer = useDepth && context()->openglContext()->format().depthBufferSize() > 0; + } } } @@ -1213,10 +1213,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 +2551,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 +2575,7 @@ void Renderer::render() } qDebug() << "Renderer::render()" << this << type; + timer.start(); } if (m_vao) @@ -2597,6 +2602,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 +2615,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 +2637,11 @@ void Renderer::render() } } } + } else { + if (Q_UNLIKELY(debug_render())) timePrepareOpaque = timePrepareAlpha = timer.restart(); } + deleteRemovedElements(); if (m_rebuild != 0) { @@ -2646,6 +2657,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 +2673,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 +2685,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 +2696,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..8cd9e7e3ff 100644 --- a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h +++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h @@ -34,6 +34,17 @@ #ifndef QSGBATCHRENDERER_P_H #define QSGBATCHRENDERER_P_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include <private/qsgrenderer_p.h> #include <private/qsgnodeupdater_p.h> #include <private/qdatabuffer_p.h> @@ -100,6 +111,7 @@ template <typename Type, int PageSize> class Allocator { public: Allocator() + : m_freePage(0) { pages.push_back(new AllocatorPage<Type, PageSize>()); } @@ -112,14 +124,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 +170,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 +194,7 @@ public: } QVector<AllocatorPage<Type, PageSize> *> pages; + int m_freePage; }; @@ -500,8 +523,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: @@ -534,8 +557,8 @@ public: }; protected: - void nodeChanged(QSGNode *node, QSGNode::DirtyState state); - void render(); + void nodeChanged(QSGNode *node, QSGNode::DirtyState state) Q_DECL_OVERRIDE; + void render() Q_DECL_OVERRIDE; private: enum ClipTypeBit @@ -604,7 +627,7 @@ private: void visualizeOverdraw(); void visualizeOverdraw_helper(Node *node); void visualizeDrawGeometry(const QSGGeometry *g); - void setCustomRenderMode(const QByteArray &mode); + void setCustomRenderMode(const QByteArray &mode) Q_DECL_OVERRIDE; QSet<Node *> m_taggedRoots; QDataBuffer<Element *> m_opaqueRenderList; diff --git a/src/quick/scenegraph/coreapi/qsggeometry_p.h b/src/quick/scenegraph/coreapi/qsggeometry_p.h index c52a45b25b..152fcb3427 100644 --- a/src/quick/scenegraph/coreapi/qsggeometry_p.h +++ b/src/quick/scenegraph/coreapi/qsggeometry_p.h @@ -34,6 +34,17 @@ #ifndef QSGGEOMETRY_P_H #define QSGGEOMETRY_P_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include "qsggeometry.h" QT_BEGIN_NAMESPACE diff --git a/src/quick/scenegraph/coreapi/qsgmaterial.cpp b/src/quick/scenegraph/coreapi/qsgmaterial.cpp index 367c0b1ee5..5fb0a9867e 100644 --- a/src/quick/scenegraph/coreapi/qsgmaterial.cpp +++ b/src/quick/scenegraph/coreapi/qsgmaterial.cpp @@ -64,7 +64,7 @@ const char *QSGMaterialShaderPrivate::loadShaderSource(QOpenGLShader::ShaderType } #ifndef QT_NO_DEBUG -static bool qsg_leak_check = !qgetenv("QML_LEAK_CHECK").isEmpty(); +static const bool qsg_leak_check = !qEnvironmentVariableIsEmpty("QML_LEAK_CHECK"); #endif /*! diff --git a/src/quick/scenegraph/coreapi/qsgmaterialshader_p.h b/src/quick/scenegraph/coreapi/qsgmaterialshader_p.h index fab6d00f84..6b31e406ca 100644 --- a/src/quick/scenegraph/coreapi/qsgmaterialshader_p.h +++ b/src/quick/scenegraph/coreapi/qsgmaterialshader_p.h @@ -34,6 +34,17 @@ #ifndef QSGMATERIALSHADER_P_H #define QSGMATERIALSHADER_P_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include <private/qtquickglobal_p.h> #include <QOpenGLShader> diff --git a/src/quick/scenegraph/coreapi/qsgnode.cpp b/src/quick/scenegraph/coreapi/qsgnode.cpp index 51f3976ed9..c09af7c0a3 100644 --- a/src/quick/scenegraph/coreapi/qsgnode.cpp +++ b/src/quick/scenegraph/coreapi/qsgnode.cpp @@ -42,7 +42,7 @@ QT_BEGIN_NAMESPACE #ifndef QT_NO_DEBUG -static bool qsg_leak_check = !qgetenv("QML_LEAK_CHECK").isEmpty(); +static const bool qsg_leak_check = !qEnvironmentVariableIsEmpty("QML_LEAK_CHECK"); static int qt_node_count = 0; static void qt_print_node_count() diff --git a/src/quick/scenegraph/coreapi/qsgnode_p.h b/src/quick/scenegraph/coreapi/qsgnode_p.h index c455e342c8..7fbb65ef81 100644 --- a/src/quick/scenegraph/coreapi/qsgnode_p.h +++ b/src/quick/scenegraph/coreapi/qsgnode_p.h @@ -34,6 +34,17 @@ #ifndef QSGNODE_P_H #define QSGNODE_P_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include <qglobal.h> #include "qsgnode.h" diff --git a/src/quick/scenegraph/coreapi/qsgnodeupdater.cpp b/src/quick/scenegraph/coreapi/qsgnodeupdater.cpp index 8293c106b5..f7c9fe7fae 100644 --- a/src/quick/scenegraph/coreapi/qsgnodeupdater.cpp +++ b/src/quick/scenegraph/coreapi/qsgnodeupdater.cpp @@ -63,24 +63,6 @@ void QSGNodeUpdater::updateStates(QSGNode *n) visitNode(n); } -/*! - \fn void QSGNodeUpdater::setToplevelOpacity(qreal opacity) - - Sets the toplevel opacity that will be multiplied with the - - The default opacity is 1. Any other value will cause artifacts, and is - primarily useful for debug purposes. - - The changing the value during an update pass will have undefined results - */ - -/*! - \fn qreal QSGNodeUpdater::toplevelOpacity() const - - Returns the toplevel opacity for the node updater. The default - value is 1. - */ - /*! Returns true if \a node is has something that blocks it in the chain from diff --git a/src/quick/scenegraph/coreapi/qsgnodeupdater_p.h b/src/quick/scenegraph/coreapi/qsgnodeupdater_p.h index e578586a19..2e408d0dbe 100644 --- a/src/quick/scenegraph/coreapi/qsgnodeupdater_p.h +++ b/src/quick/scenegraph/coreapi/qsgnodeupdater_p.h @@ -34,6 +34,17 @@ #ifndef QSGNODEUPDATER_P_H #define QSGNODEUPDATER_P_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include <private/qtquickglobal_p.h> #include <QtGui/private/qdatabuffer_p.h> diff --git a/src/quick/scenegraph/coreapi/qsgrenderer.cpp b/src/quick/scenegraph/coreapi/qsgrenderer.cpp index a9752cb9a9..775277e588 100644 --- a/src/quick/scenegraph/coreapi/qsgrenderer.cpp +++ b/src/quick/scenegraph/coreapi/qsgrenderer.cpp @@ -40,12 +40,21 @@ QT_BEGIN_NAMESPACE -static bool qsg_sanity_check = qgetenv("QSG_SANITY_CHECK").toInt(); +static const bool qsg_sanity_check = qEnvironmentVariableIntValue("QSG_SANITY_CHECK"); static QElapsedTimer frameTimer; static qint64 preprocessTime; static qint64 updatePassTime; +int qt_sg_envInt(const char *name, int defaultValue) +{ + if (Q_LIKELY(!qEnvironmentVariableIsSet(name))) + return defaultValue; + bool ok = false; + int value = qgetenv(name).toInt(&ok); + return ok ? value : defaultValue; +} + void QSGBindable::clear(QSGAbstractRenderer::ClearMode mode) const { GLuint bits = 0; diff --git a/src/quick/scenegraph/coreapi/qsgrenderer_p.h b/src/quick/scenegraph/coreapi/qsgrenderer_p.h index 7e4d52730a..319d0a46b6 100644 --- a/src/quick/scenegraph/coreapi/qsgrenderer_p.h +++ b/src/quick/scenegraph/coreapi/qsgrenderer_p.h @@ -34,6 +34,17 @@ #ifndef QSGRENDERER_P_H #define QSGRENDERER_P_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include "qsgabstractrenderer.h" #include "qsgabstractrenderer_p.h" #include "qsgnode.h" 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/qsgadaptationlayer_p.h b/src/quick/scenegraph/qsgadaptationlayer_p.h index 1253711a94..c7ed398d1b 100644 --- a/src/quick/scenegraph/qsgadaptationlayer_p.h +++ b/src/quick/scenegraph/qsgadaptationlayer_p.h @@ -34,6 +34,17 @@ #ifndef QSGADAPTATIONLAYER_P_H #define QSGADAPTATIONLAYER_P_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include <QtQuick/qsgnode.h> #include <QtQuick/qsgtexture.h> #include <QtCore/qobject.h> @@ -160,6 +171,7 @@ public: virtual void setFillColor(const QColor &c) = 0; virtual void setContentsScale(qreal s) = 0; virtual void setFastFBOResizing(bool dynamic) = 0; + virtual void setTextureSize(const QSize &size) = 0; virtual QImage toImage() const = 0; virtual void update() = 0; @@ -195,6 +207,8 @@ public: virtual void setFormat(GLenum format) = 0; virtual void setHasMipmaps(bool mipmap) = 0; virtual void setDevicePixelRatio(qreal ratio) = 0; + virtual void setMirrorHorizontal(bool mirror) = 0; + virtual void setMirrorVertical(bool mirror) = 0; Q_SLOT virtual void markDirtyTexture() = 0; Q_SLOT virtual void invalidated() = 0; diff --git a/src/quick/scenegraph/qsgcontext.cpp b/src/quick/scenegraph/qsgcontext.cpp index 418d571ae6..dd6977e42e 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) /* @@ -140,8 +134,8 @@ static bool qsg_useConsistentTiming() { static int use = -1; if (use < 0) { - QByteArray fixed = qgetenv("QSG_FIXED_ANIMATION_STEP"); - use = !(fixed.isEmpty() || fixed == "no"); + use = !qEnvironmentVariableIsEmpty("QSG_FIXED_ANIMATION_STEP") && qgetenv("QSG_FIXED_ANIMATION_STEP") != "no" + ? 1 : 0; qCDebug(QSG_LOG_INFO, "Using %s", bool(use) ? "fixed animation steps" : "sg animation driver"); } return bool(use); @@ -303,15 +297,16 @@ QSGContext::QSGContext(QObject *parent) : QObject(*(new QSGContextPrivate), parent) { Q_D(QSGContext); - QByteArray mode = qgetenv("QSG_DISTANCEFIELD_ANTIALIASING"); - if (!mode.isEmpty()) + if (Q_UNLIKELY(!qEnvironmentVariableIsEmpty("QSG_DISTANCEFIELD_ANTIALIASING"))) { + const QByteArray mode = qgetenv("QSG_DISTANCEFIELD_ANTIALIASING"); d->distanceFieldAntialiasingDecided = true; - if (mode == "subpixel") - d->distanceFieldAntialiasing = QSGGlyphNode::HighQualitySubPixelAntialiasing; - else if (mode == "subpixel-lowq") - d->distanceFieldAntialiasing = QSGGlyphNode::LowQualitySubPixelAntialiasing; - else if (mode == "gray") - d->distanceFieldAntialiasing = QSGGlyphNode::GrayAntialiasing; + if (mode == "subpixel") + d->distanceFieldAntialiasing = QSGGlyphNode::HighQualitySubPixelAntialiasing; + else if (mode == "subpixel-lowq") + d->distanceFieldAntialiasing = QSGGlyphNode::LowQualitySubPixelAntialiasing; + else if (mode == "gray") + d->distanceFieldAntialiasing = QSGGlyphNode::GrayAntialiasing; + } // Adds compatibility with Qt 5.3 and earlier's QSG_RENDER_TIMING if (qEnvironmentVariableIsSet("QSG_RENDER_TIMING")) { @@ -339,12 +334,14 @@ void QSGContext::renderContextInitialized(QSGRenderContext *renderContext) d->mutex.lock(); if (d->antialiasingMethod == UndecidedAntialiasing) { - QByteArray aaType = qgetenv("QSG_ANTIALIASING_METHOD"); - if (aaType == "msaa") { - d->antialiasingMethod = MsaaAntialiasing; - } else if (aaType == "vertex") { - d->antialiasingMethod = VertexAntialiasing; - } else { + if (Q_UNLIKELY(qEnvironmentVariableIsSet("QSG_ANTIALIASING_METHOD"))) { + const QByteArray aaType = qgetenv("QSG_ANTIALIASING_METHOD"); + if (aaType == "msaa") + d->antialiasingMethod = MsaaAntialiasing; + else if (aaType == "vertex") + d->antialiasingMethod = VertexAntialiasing; + } + if (d->antialiasingMethod == UndecidedAntialiasing) { if (renderContext->openglContext()->format().samples() > 0) d->antialiasingMethod = MsaaAntialiasing; else @@ -572,35 +569,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 +645,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 +736,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..b1900cba76 100644 --- a/src/quick/scenegraph/qsgcontext_p.h +++ b/src/quick/scenegraph/qsgcontext_p.h @@ -34,6 +34,17 @@ #ifndef QSGCONTEXT_H #define QSGCONTEXT_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include <QtCore/QObject> #include <QtCore/qabstractanimation.h> @@ -88,6 +99,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 +124,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/qsgcontextplugin_p.h b/src/quick/scenegraph/qsgcontextplugin_p.h index 66f28f3ac0..eb30ed18a4 100644 --- a/src/quick/scenegraph/qsgcontextplugin_p.h +++ b/src/quick/scenegraph/qsgcontextplugin_p.h @@ -34,6 +34,17 @@ #ifndef QSGCONTEXTPLUGIN_H #define QSGCONTEXTPLUGIN_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include <private/qtquickglobal_p.h> #include <QtQuick/qquickimageprovider.h> #include <QtCore/qplugin.h> diff --git a/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache_p.h b/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache_p.h index cffe02330a..59fa9850bc 100644 --- a/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache_p.h +++ b/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache_p.h @@ -34,6 +34,17 @@ #ifndef QSGDEFAULTDISTANCEFIELDGLYPHCACHE_H #define QSGDEFAULTDISTANCEFIELDGLYPHCACHE_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include "qsgadaptationlayer_p.h" #include <QtGui/qopenglfunctions.h> #include <qopenglshaderprogram.h> diff --git a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp index c84e6628a5..9f8788123b 100644 --- a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp +++ b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp @@ -73,7 +73,7 @@ static inline int qsg_device_pixel_ratio(QOpenGLContext *ctx) else devicePixelRatio = w->devicePixelRatio(); } else { - devicePixelRatio = ctx->screen()->devicePixelRatio(); + devicePixelRatio = ctx->screen() ? ctx->screen()->devicePixelRatio() : qGuiApp->devicePixelRatio(); } return devicePixelRatio; } @@ -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/qsgdefaultglyphnode_p.h b/src/quick/scenegraph/qsgdefaultglyphnode_p.h index 157c5f480c..cd178b932d 100644 --- a/src/quick/scenegraph/qsgdefaultglyphnode_p.h +++ b/src/quick/scenegraph/qsgdefaultglyphnode_p.h @@ -34,6 +34,17 @@ #ifndef QSGDEFAULTGLYPHNODE_P_H #define QSGDEFAULTGLYPHNODE_P_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include <private/qsgadaptationlayer_p.h> #include <QtQuick/qsgnode.h> diff --git a/src/quick/scenegraph/qsgdefaultglyphnode_p_p.h b/src/quick/scenegraph/qsgdefaultglyphnode_p_p.h index 736b2de9ea..64d7116bbd 100644 --- a/src/quick/scenegraph/qsgdefaultglyphnode_p_p.h +++ b/src/quick/scenegraph/qsgdefaultglyphnode_p_p.h @@ -34,6 +34,17 @@ #ifndef QSGDEFAULTGLYPHNODE_P_P_H #define QSGDEFAULTGLYPHNODE_P_P_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include <qcolor.h> #include <QtGui/private/qopengltextureglyphcache_p.h> #include <QtQuick/qsgmaterial.h> diff --git a/src/quick/scenegraph/qsgdefaultimagenode.cpp b/src/quick/scenegraph/qsgdefaultimagenode.cpp index db79804908..0591d0fe2f 100644 --- a/src/quick/scenegraph/qsgdefaultimagenode.cpp +++ b/src/quick/scenegraph/qsgdefaultimagenode.cpp @@ -284,7 +284,7 @@ void QSGDefaultImageNode::update() void QSGDefaultImageNode::preprocess() { bool doDirty = false; - QSGLayer *t = qobject_cast<QSGLayer *>(m_material.texture()); + QSGDynamicTexture *t = qobject_cast<QSGDynamicTexture *>(m_material.texture()); if (t) { doDirty = t->updateTexture(); updateGeometry(); diff --git a/src/quick/scenegraph/qsgdefaultimagenode_p.h b/src/quick/scenegraph/qsgdefaultimagenode_p.h index c77321ae51..ff611e102b 100644 --- a/src/quick/scenegraph/qsgdefaultimagenode_p.h +++ b/src/quick/scenegraph/qsgdefaultimagenode_p.h @@ -35,6 +35,17 @@ #ifndef QSGDEFAULTIMAGENODE_P_H #define QSGDEFAULTIMAGENODE_P_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include <private/qsgadaptationlayer_p.h> #include <QtQuick/qsgtexturematerial.h> diff --git a/src/quick/scenegraph/qsgdefaultlayer.cpp b/src/quick/scenegraph/qsgdefaultlayer.cpp index cca0712ece..fa69f911dd 100644 --- a/src/quick/scenegraph/qsgdefaultlayer.cpp +++ b/src/quick/scenegraph/qsgdefaultlayer.cpp @@ -97,6 +97,8 @@ QSGDefaultLayer::QSGDefaultLayer(QSGRenderContext *context) , m_multisamplingChecked(false) , m_multisampling(false) , m_grab(false) + , m_mirrorHorizontal(false) + , m_mirrorVertical(true) { } @@ -259,6 +261,16 @@ void QSGDefaultLayer::setRecursive(bool recursive) m_recursive = recursive; } +void QSGDefaultLayer::setMirrorHorizontal(bool mirror) +{ + m_mirrorHorizontal = mirror; +} + +void QSGDefaultLayer::setMirrorVertical(bool mirror) +{ + m_mirrorVertical = mirror; +} + void QSGDefaultLayer::markDirtyTexture() { m_dirtyTexture = true; @@ -365,7 +377,10 @@ void QSGDefaultLayer::grab() m_renderer->setDeviceRect(m_size); m_renderer->setViewportRect(m_size); - QRectF mirrored(m_rect.left(), m_rect.bottom(), m_rect.width(), -m_rect.height()); + QRectF mirrored(m_mirrorHorizontal ? m_rect.right() : m_rect.left(), + m_mirrorVertical ? m_rect.bottom() : m_rect.top(), + m_mirrorHorizontal ? -m_rect.width() : m_rect.width(), + m_mirrorVertical ? -m_rect.height() : m_rect.height()); m_renderer->setProjectionMatrixToRect(mirrored); m_renderer->setClearColor(Qt::transparent); @@ -428,3 +443,11 @@ QImage QSGDefaultLayer::toImage() const return QImage(); } + +QRectF QSGDefaultLayer::normalizedTextureSubRect() const +{ + return QRectF(m_mirrorHorizontal ? 1 : 0, + m_mirrorVertical ? 0 : 1, + m_mirrorHorizontal ? -1 : 1, + m_mirrorVertical ? 1 : -1); +} diff --git a/src/quick/scenegraph/qsgdefaultlayer_p.h b/src/quick/scenegraph/qsgdefaultlayer_p.h index 0ba7109ef6..7fb30436d1 100644 --- a/src/quick/scenegraph/qsgdefaultlayer_p.h +++ b/src/quick/scenegraph/qsgdefaultlayer_p.h @@ -33,6 +33,17 @@ #ifndef QSGDEFAULTLAYER_P_H #define QSGDEFAULTLAYER_P_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include <private/qsgadaptationlayer_p.h> #include <private/qsgcontext_p.h> #include <qsgsimplerectnode.h> @@ -78,10 +89,18 @@ public: void setDevicePixelRatio(qreal ratio) Q_DECL_OVERRIDE { m_device_pixel_ratio = ratio; } + bool mirrorHorizontal() const { return bool(m_mirrorHorizontal); } + void setMirrorHorizontal(bool mirror) Q_DECL_OVERRIDE; + + bool mirrorVertical() const { return bool(m_mirrorVertical); } + void setMirrorVertical(bool mirror) Q_DECL_OVERRIDE; + void scheduleUpdate() Q_DECL_OVERRIDE; QImage toImage() const Q_DECL_OVERRIDE; + QRectF normalizedTextureSubRect() const Q_DECL_OVERRIDE; + public Q_SLOTS: void markDirtyTexture() Q_DECL_OVERRIDE; void invalidated() Q_DECL_OVERRIDE; @@ -115,6 +134,8 @@ private: uint m_multisamplingChecked : 1; uint m_multisampling : 1; uint m_grab : 1; + uint m_mirrorHorizontal : 1; + uint m_mirrorVertical : 1; }; #endif // QSGDEFAULTLAYER_P_H diff --git a/src/quick/scenegraph/qsgdefaultrectanglenode_p.h b/src/quick/scenegraph/qsgdefaultrectanglenode_p.h index 18e679d8b4..0987b1f9b4 100644 --- a/src/quick/scenegraph/qsgdefaultrectanglenode_p.h +++ b/src/quick/scenegraph/qsgdefaultrectanglenode_p.h @@ -35,6 +35,17 @@ #ifndef QSGDEFAULTRECTANGLENODE_P_H #define QSGDEFAULTRECTANGLENODE_P_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include <private/qsgadaptationlayer_p.h> #include <QtQuick/qsgvertexcolormaterial.h> 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/qsgdistancefieldglyphnode_p.h b/src/quick/scenegraph/qsgdistancefieldglyphnode_p.h index bce9379bee..ab171c4fb8 100644 --- a/src/quick/scenegraph/qsgdistancefieldglyphnode_p.h +++ b/src/quick/scenegraph/qsgdistancefieldglyphnode_p.h @@ -34,6 +34,17 @@ #ifndef QSGDISTANCEFIELDGLYPHNODE_P_H #define QSGDISTANCEFIELDGLYPHNODE_P_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include <private/qsgadaptationlayer_p.h> #include <QtQuick/qsgtexture.h> diff --git a/src/quick/scenegraph/qsgdistancefieldglyphnode_p_p.h b/src/quick/scenegraph/qsgdistancefieldglyphnode_p_p.h index 9aba26e5f0..d6538a39ed 100644 --- a/src/quick/scenegraph/qsgdistancefieldglyphnode_p_p.h +++ b/src/quick/scenegraph/qsgdistancefieldglyphnode_p_p.h @@ -34,6 +34,17 @@ #ifndef QSGDISTANCEFIELDGLYPHNODE_P_P_H #define QSGDISTANCEFIELDGLYPHNODE_P_P_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include <QtQuick/qsgmaterial.h> #include "qsgdistancefieldglyphnode_p.h" #include "qsgadaptationlayer_p.h" diff --git a/src/quick/scenegraph/qsgrenderloop.cpp b/src/quick/scenegraph/qsgrenderloop.cpp index 4d3f34c71c..68947d3a3c 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 @@ -183,13 +199,15 @@ QSGRenderLoop *QSGRenderLoop::instance() else if (qmlForceThreadedRenderer()) loopType = ThreadedRenderLoop; - const QByteArray loopName = qgetenv("QSG_RENDER_LOOP"); - if (loopName == QByteArrayLiteral("windows")) - loopType = WindowsRenderLoop; - else if (loopName == QByteArrayLiteral("basic")) - loopType = BasicRenderLoop; - else if (loopName == QByteArrayLiteral("threaded")) - loopType = ThreadedRenderLoop; + if (Q_UNLIKELY(qEnvironmentVariableIsSet("QSG_RENDER_LOOP"))) { + const QByteArray loopName = qgetenv("QSG_RENDER_LOOP"); + if (loopName == QByteArrayLiteral("windows")) + loopType = WindowsRenderLoop; + else if (loopName == QByteArrayLiteral("basic")) + loopType = BasicRenderLoop; + else if (loopName == QByteArrayLiteral("threaded")) + loopType = ThreadedRenderLoop; + } switch (loopType) { case ThreadedRenderLoop: @@ -382,7 +400,8 @@ void QSGGuiThreadRenderLoop::renderWindow(QQuickWindow *window) Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRenderLoopFrame); if (data.grabOnly) { - grabContent = qt_gl_read_framebuffer(window->size() * window->effectiveDevicePixelRatio(), false, false); + bool alpha = window->format().alphaBufferSize() > 0 && window->color().alpha() != 255; + grabContent = qt_gl_read_framebuffer(window->size() * window->effectiveDevicePixelRatio(), alpha, alpha); data.grabOnly = false; } diff --git a/src/quick/scenegraph/qsgrenderloop_p.h b/src/quick/scenegraph/qsgrenderloop_p.h index 4293015b96..1292e7ad9b 100644 --- a/src/quick/scenegraph/qsgrenderloop_p.h +++ b/src/quick/scenegraph/qsgrenderloop_p.h @@ -34,6 +34,17 @@ #ifndef QSGRenderLoop_P_H #define QSGRenderLoop_P_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include <QtGui/QImage> #include <QtGui/QSurface> #include <private/qtquickglobal_p.h> @@ -45,6 +56,7 @@ class QQuickWindow; class QSGContext; class QSGRenderContext; class QAnimationDriver; +class QRunnable; class Q_QUICK_PRIVATE_EXPORT QSGRenderLoop : public QObject { @@ -72,6 +84,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..8d6bea9e67 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,22 @@ 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); + bool alpha = ce->window->format().alphaBufferSize() > 0 && ce->window->color().alpha() != 255; + *ce->image = qt_gl_read_framebuffer(windowSize * ce->window->effectiveDevicePixelRatio(), alpha, alpha); } qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- waking gui to handle result"; waitCondition.wakeOne(); @@ -417,6 +430,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 +693,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 +1020,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 +1269,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..3fef6a0a88 100644 --- a/src/quick/scenegraph/qsgthreadedrenderloop_p.h +++ b/src/quick/scenegraph/qsgthreadedrenderloop_p.h @@ -34,6 +34,17 @@ #ifndef QSGTHREADEDRENDERLOOP_P_H #define QSGTHREADEDRENDERLOOP_P_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include <QtCore/QThread> #include <QtGui/QOpenGLContext> #include <private/qsgcontext_p.h> @@ -71,6 +82,7 @@ public: void releaseResources(QQuickWindow *window); bool event(QEvent *); + void postJob(QQuickWindow *window, QRunnable *job); bool interleaveIncubation() const; diff --git a/src/quick/scenegraph/qsgwindowsrenderloop.cpp b/src/quick/scenegraph/qsgwindowsrenderloop.cpp index 7fd9651618..04a46bf929 100644 --- a/src/quick/scenegraph/qsgwindowsrenderloop.cpp +++ b/src/quick/scenegraph/qsgwindowsrenderloop.cpp @@ -312,7 +312,8 @@ QImage QSGWindowsRenderLoop::grab(QQuickWindow *window) d->syncSceneGraph(); d->renderSceneGraph(window->size()); - QImage image = qt_gl_read_framebuffer(window->size() * window->effectiveDevicePixelRatio(), false, false); + bool alpha = window->format().alphaBufferSize() > 0 && window->color().alpha() != 255; + QImage image = qt_gl_read_framebuffer(window->size() * window->effectiveDevicePixelRatio(), alpha, alpha); return image; } diff --git a/src/quick/scenegraph/qsgwindowsrenderloop_p.h b/src/quick/scenegraph/qsgwindowsrenderloop_p.h index fd2dde6f2f..654a0ebbfd 100644 --- a/src/quick/scenegraph/qsgwindowsrenderloop_p.h +++ b/src/quick/scenegraph/qsgwindowsrenderloop_p.h @@ -34,6 +34,17 @@ #ifndef QSGWINDOWSRENDERLOOP_P_H #define QSGWINDOWSRENDERLOOP_P_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include <QtCore/QObject> #include <QtCore/QElapsedTimer> 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/qsgareaallocator_p.h b/src/quick/scenegraph/util/qsgareaallocator_p.h index d2823ce3ac..f7f753bb9c 100644 --- a/src/quick/scenegraph/util/qsgareaallocator_p.h +++ b/src/quick/scenegraph/util/qsgareaallocator_p.h @@ -34,6 +34,17 @@ #ifndef QSGAREAALLOCATOR_P_H #define QSGAREAALLOCATOR_P_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include <private/qtquickglobal_p.h> #include <QtCore/qsize.h> diff --git a/src/quick/scenegraph/util/qsgatlastexture.cpp b/src/quick/scenegraph/util/qsgatlastexture.cpp index b862fa6a2b..8e8e870505 100644 --- a/src/quick/scenegraph/util/qsgatlastexture.cpp +++ b/src/quick/scenegraph/util/qsgatlastexture.cpp @@ -54,21 +54,13 @@ QT_BEGIN_NAMESPACE #define GL_BGRA 0x80E1 #endif +int qt_sg_envInt(const char *name, int defaultValue); static QElapsedTimer qsg_renderer_timer; namespace QSGAtlasTexture { -static int qsg_envInt(const char *name, int defaultValue) -{ - QByteArray content = qgetenv(name); - - bool ok = false; - int value = content.toInt(&ok); - return ok ? value : defaultValue; -} - Manager::Manager() : m_atlas(0) { @@ -79,8 +71,8 @@ Manager::Manager() int max; gl->functions()->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max); - int w = qMin(max, qsg_envInt("QSG_ATLAS_WIDTH", qMax(512U, qNextPowerOfTwo(surfaceSize.width() - 1)))); - int h = qMin(max, qsg_envInt("QSG_ATLAS_HEIGHT", qMax(512U, qNextPowerOfTwo(surfaceSize.height() - 1)))); + int w = qMin(max, qt_sg_envInt("QSG_ATLAS_WIDTH", qMax(512U, qNextPowerOfTwo(surfaceSize.width() - 1)))); + int h = qMin(max, qt_sg_envInt("QSG_ATLAS_HEIGHT", qMax(512U, qNextPowerOfTwo(surfaceSize.height() - 1)))); if (surface->surfaceClass() == QSurface::Window) { QWindow *window = static_cast<QWindow *>(surface); @@ -91,7 +83,7 @@ Manager::Manager() } } - m_atlas_size_limit = qsg_envInt("QSG_ATLAS_SIZE_LIMIT", qMax(w, h) / 2); + m_atlas_size_limit = qt_sg_envInt("QSG_ATLAS_SIZE_LIMIT", qMax(w, h) / 2); m_atlas_size = QSize(w, h); qCDebug(QSG_LOG_INFO, "texture atlas dimensions: %dx%d", w, h); @@ -112,13 +104,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..e77e0fa104 100644 --- a/src/quick/scenegraph/util/qsgatlastexture_p.h +++ b/src/quick/scenegraph/util/qsgatlastexture_p.h @@ -34,6 +34,17 @@ #ifndef QSGATLASTEXTURE_P_H #define QSGATLASTEXTURE_P_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include <QtCore/QSize> #include <QtGui/qopengl.h> @@ -58,7 +69,7 @@ public: Manager(); ~Manager(); - QSGTexture *create(const QImage &image); + QSGTexture *create(const QImage &image, bool hasAlphaChannel); void invalidate(); private: @@ -114,6 +125,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/qsgdefaultpainternode.cpp b/src/quick/scenegraph/util/qsgdefaultpainternode.cpp index be8deb2aa3..38bcc7a3f3 100644 --- a/src/quick/scenegraph/util/qsgdefaultpainternode.cpp +++ b/src/quick/scenegraph/util/qsgdefaultpainternode.cpp @@ -76,6 +76,8 @@ QSGDefaultPainterNode::QSGDefaultPainterNode(QQuickPaintedItem *item) , m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4) , m_texture(0) , m_gl_device(0) + , m_fillColor(Qt::transparent) + , m_contentsScale(1.0) , m_dirtyContents(false) , m_opaquePainting(false) , m_linear_filtering(false) @@ -84,8 +86,6 @@ QSGDefaultPainterNode::QSGDefaultPainterNode(QQuickPaintedItem *item) , m_extensionsChecked(false) , m_multisamplingSupported(false) , m_fastFBOResizing(false) - , m_fillColor(Qt::transparent) - , m_contentsScale(1.0) , m_dirtyGeometry(false) , m_dirtyRenderTarget(false) , m_dirtyTexture(false) @@ -136,18 +136,35 @@ void QSGDefaultPainterNode::paint() painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform); } - painter.scale(m_contentsScale, m_contentsScale); - - QRect sclip(qFloor(dirtyRect.x()/m_contentsScale), - qFloor(dirtyRect.y()/m_contentsScale), - qCeil(dirtyRect.width()/m_contentsScale+dirtyRect.x()/m_contentsScale-qFloor(dirtyRect.x()/m_contentsScale)), - qCeil(dirtyRect.height()/m_contentsScale+dirtyRect.y()/m_contentsScale-qFloor(dirtyRect.y()/m_contentsScale))); + QRect clipRect; + QRect dirtyTextureRect; + + if (m_contentsScale == 1) { + qreal scaleX = m_textureSize.width() / (qreal) m_size.width(); + qreal scaleY = m_textureSize.height() / (qreal) m_size.height(); + painter.scale(scaleX, scaleY); + clipRect = dirtyRect; + dirtyTextureRect = QRectF(dirtyRect.x() * scaleX, + dirtyRect.y() * scaleY, + dirtyRect.width() * scaleX, + dirtyRect.height() * scaleY).toAlignedRect(); + } else { + painter.scale(m_contentsScale, m_contentsScale); + QRect sclip(qFloor(dirtyRect.x()/m_contentsScale), + qFloor(dirtyRect.y()/m_contentsScale), + qCeil(dirtyRect.width()/m_contentsScale+dirtyRect.x()/m_contentsScale-qFloor(dirtyRect.x()/m_contentsScale)), + qCeil(dirtyRect.height()/m_contentsScale+dirtyRect.y()/m_contentsScale-qFloor(dirtyRect.y()/m_contentsScale))); + clipRect = sclip; + dirtyTextureRect = dirtyRect; + } - if (!m_dirtyRect.isNull()) - painter.setClipRect(sclip); + // only clip if we were originally updating only a subrect + if (!m_dirtyRect.isNull()) { + painter.setClipRect(clipRect); + } painter.setCompositionMode(QPainter::CompositionMode_Source); - painter.fillRect(sclip, m_fillColor); + painter.fillRect(clipRect, m_fillColor); painter.setCompositionMode(QPainter::CompositionMode_SourceOver); m_item->paint(&painter); @@ -155,9 +172,9 @@ void QSGDefaultPainterNode::paint() if (m_actualRenderTarget == QQuickPaintedItem::Image) { m_texture->setImage(m_image); - m_texture->setDirtyRect(dirtyRect); + m_texture->setDirtyRect(dirtyTextureRect); } else if (m_multisampledFbo) { - QOpenGLFramebufferObject::blitFramebuffer(m_fbo, dirtyRect, m_multisampledFbo, dirtyRect); + QOpenGLFramebufferObject::blitFramebuffer(m_fbo, dirtyTextureRect, m_multisampledFbo, dirtyTextureRect); } if (m_multisampledFbo) @@ -276,7 +293,7 @@ void QSGDefaultPainterNode::updateRenderTarget() if (!m_image.isNull() && !m_dirtyGeometry) return; - m_image = QImage(m_size, QImage::Format_ARGB32_Premultiplied); + m_image = QImage(m_textureSize, QImage::Format_ARGB32_Premultiplied); m_image.fill(Qt::transparent); } @@ -302,12 +319,12 @@ void QSGDefaultPainterNode::updateFBOSize() int fboWidth; int fboHeight; if (m_fastFBOResizing) { - fboWidth = qMax(QT_MINIMUM_DYNAMIC_FBO_SIZE, qNextPowerOfTwo(m_size.width() - 1)); - fboHeight = qMax(QT_MINIMUM_DYNAMIC_FBO_SIZE, qNextPowerOfTwo(m_size.height() - 1)); + fboWidth = qMax(QT_MINIMUM_DYNAMIC_FBO_SIZE, qNextPowerOfTwo(m_textureSize.width() - 1)); + fboHeight = qMax(QT_MINIMUM_DYNAMIC_FBO_SIZE, qNextPowerOfTwo(m_textureSize.height() - 1)); } else { QSize minimumFBOSize = m_context->sceneGraphContext()->minimumFBOSize(); - fboWidth = qMax(minimumFBOSize.width(), m_size.width()); - fboHeight = qMax(minimumFBOSize.height(), m_size.height()); + fboWidth = qMax(minimumFBOSize.width(), m_textureSize.width()); + fboHeight = qMax(minimumFBOSize.height(), m_textureSize.height()); } m_fboSize = QSize(fboWidth, fboHeight); @@ -331,6 +348,15 @@ void QSGDefaultPainterNode::setSize(const QSize &size) return; m_size = size; + m_dirtyGeometry = true; +} + +void QSGDefaultPainterNode::setTextureSize(const QSize &size) +{ + if (size == m_textureSize) + return; + + m_textureSize = size; updateFBOSize(); if (m_fbo) diff --git a/src/quick/scenegraph/util/qsgdefaultpainternode_p.h b/src/quick/scenegraph/util/qsgdefaultpainternode_p.h index 62daa54432..6b6f485915 100644 --- a/src/quick/scenegraph/util/qsgdefaultpainternode_p.h +++ b/src/quick/scenegraph/util/qsgdefaultpainternode_p.h @@ -34,6 +34,17 @@ #ifndef QSGDEFAULTPAINTERNODE_P_H #define QSGDEFAULTPAINTERNODE_P_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include <private/qsgadaptationlayer_p.h> #include "qsgtexturematerial.h" #include "qsgtexture_p.h" @@ -94,6 +105,9 @@ public: void setFastFBOResizing(bool dynamic); bool fastFBOResizing() const { return m_fastFBOResizing; } + void setTextureSize(const QSize &textureSize); + QSize textureSize() const { return m_textureSize; } + QImage toImage() const; void update(); @@ -126,21 +140,25 @@ private: QSize m_size; QSize m_fboSize; - bool m_dirtyContents; + QSize m_textureSize; QRect m_dirtyRect; - bool m_opaquePainting; - bool m_linear_filtering; - bool m_mipmapping; - bool m_smoothPainting; - bool m_extensionsChecked; - bool m_multisamplingSupported; - bool m_fastFBOResizing; QColor m_fillColor; +#if QT_VERSION >= 0x060000 +#warning "Remove m_contentsScale and assume 1 everywhere" +#endif qreal m_contentsScale; - bool m_dirtyGeometry; - bool m_dirtyRenderTarget; - bool m_dirtyTexture; + bool m_dirtyContents : 1; + bool m_opaquePainting : 1; + bool m_linear_filtering : 1; + bool m_mipmapping : 1; + bool m_smoothPainting : 1; + bool m_extensionsChecked : 1; + bool m_multisamplingSupported : 1; + bool m_fastFBOResizing : 1; + bool m_dirtyGeometry : 1; + bool m_dirtyRenderTarget : 1; + bool m_dirtyTexture : 1; }; QT_END_NAMESPACE diff --git a/src/quick/scenegraph/util/qsgdepthstencilbuffer_p.h b/src/quick/scenegraph/util/qsgdepthstencilbuffer_p.h index e9d07ae605..c6d0de4435 100644 --- a/src/quick/scenegraph/util/qsgdepthstencilbuffer_p.h +++ b/src/quick/scenegraph/util/qsgdepthstencilbuffer_p.h @@ -34,6 +34,17 @@ #ifndef QSGDEPTHSTENCILBUFFER_P_H #define QSGDEPTHSTENCILBUFFER_P_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include <QtCore/qsize.h> #include <QtGui/private/qopenglcontext_p.h> #include <QtGui/private/qopenglextensions_p.h> diff --git a/src/quick/scenegraph/util/qsgdistancefieldutil.cpp b/src/quick/scenegraph/util/qsgdistancefieldutil.cpp index 8e02681703..96b606aa3c 100644 --- a/src/quick/scenegraph/util/qsgdistancefieldutil.cpp +++ b/src/quick/scenegraph/util/qsgdistancefieldutil.cpp @@ -39,18 +39,27 @@ QT_BEGIN_NAMESPACE +static float qt_sg_envFloat(const char *name, float defaultValue) +{ + if (Q_LIKELY(!qEnvironmentVariableIsSet(name))) + return defaultValue; + bool ok = false; + const float value = qgetenv(name).toFloat(&ok); + return ok ? value : defaultValue; +} + static float defaultThresholdFunc(float glyphScale) { - static float base = qgetenv("QT_DF_BASE").isEmpty() ? 0.5f : qgetenv("QT_DF_BASE").toFloat(); - static float baseDev = qgetenv("QT_DF_BASEDEVIATION").isEmpty() ? 0.065f : qgetenv("QT_DF_BASEDEVIATION").toFloat(); - static float devScaleMin = qgetenv("QT_DF_SCALEFORMAXDEV").isEmpty() ? 0.15f : qgetenv("QT_DF_SCALEFORMAXDEV").toFloat(); - static float devScaleMax = qgetenv("QT_DF_SCALEFORNODEV").isEmpty() ? 0.3f : qgetenv("QT_DF_SCALEFORNODEV").toFloat(); + static const float base = qt_sg_envFloat("QT_DF_BASE", 0.5f); + static const float baseDev = qt_sg_envFloat("QT_DF_BASEDEVIATION", 0.065f); + static const float devScaleMin = qt_sg_envFloat("QT_DF_SCALEFORMAXDEV", 0.15f); + static const float devScaleMax = qt_sg_envFloat("QT_DF_SCALEFORNODEV", 0.3f); return base - ((qBound(devScaleMin, glyphScale, devScaleMax) - devScaleMin) / (devScaleMax - devScaleMin) * -baseDev + baseDev); } static float defaultAntialiasingSpreadFunc(float glyphScale) { - static float range = qgetenv("QT_DF_RANGE").isEmpty() ? 0.06f : qgetenv("QT_DF_RANGE").toFloat(); + static const float range = qt_sg_envFloat("QT_DF_RANGE", 0.06f); return range / glyphScale; } diff --git a/src/quick/scenegraph/util/qsgdistancefieldutil_p.h b/src/quick/scenegraph/util/qsgdistancefieldutil_p.h index 7ed4b44a6d..3ee29230d5 100644 --- a/src/quick/scenegraph/util/qsgdistancefieldutil_p.h +++ b/src/quick/scenegraph/util/qsgdistancefieldutil_p.h @@ -34,6 +34,17 @@ #ifndef QSGDISTANCEFIELDUTIL_H #define QSGDISTANCEFIELDUTIL_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include <qrawfont.h> #include <private/qfontengine_p.h> #include <private/qsgadaptationlayer_p.h> 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) diff --git a/src/quick/scenegraph/util/qsgengine_p.h b/src/quick/scenegraph/util/qsgengine_p.h index 770c4a536c..9bae09ea71 100644 --- a/src/quick/scenegraph/util/qsgengine_p.h +++ b/src/quick/scenegraph/util/qsgengine_p.h @@ -34,6 +34,17 @@ #ifndef QSGENGINE_P_H #define QSGENGINE_P_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include "qsgengine.h" #include <private/qobject_p.h> diff --git a/src/quick/scenegraph/util/qsgshadersourcebuilder.cpp b/src/quick/scenegraph/util/qsgshadersourcebuilder.cpp index 93a9c98ffb..0d6375de1e 100644 --- a/src/quick/scenegraph/util/qsgshadersourcebuilder.cpp +++ b/src/quick/scenegraph/util/qsgshadersourcebuilder.cpp @@ -373,7 +373,7 @@ QString QSGShaderSourceBuilder::resolveShaderPath(const QString &path) const if (contextProfile() != QSurfaceFormat::CoreProfile) { return path; } else { - int idx = path.lastIndexOf(QStringLiteral(".")); + int idx = path.lastIndexOf(QLatin1Char('.')); QString resolvedPath; if (idx != -1) resolvedPath = path.left(idx) diff --git a/src/quick/scenegraph/util/qsgshadersourcebuilder_p.h b/src/quick/scenegraph/util/qsgshadersourcebuilder_p.h index a270acb6ab..180ced7990 100644 --- a/src/quick/scenegraph/util/qsgshadersourcebuilder_p.h +++ b/src/quick/scenegraph/util/qsgshadersourcebuilder_p.h @@ -34,6 +34,17 @@ #ifndef QSGSHADERSOURCEBUILDER_P_H #define QSGSHADERSOURCEBUILDER_P_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include <private/qtquickglobal_p.h> #include <QtGui/qsurfaceformat.h> diff --git a/src/quick/scenegraph/util/qsgtexture.cpp b/src/quick/scenegraph/util/qsgtexture.cpp index c89ad7a608..df9e569ca3 100644 --- a/src/quick/scenegraph/util/qsgtexture.cpp +++ b/src/quick/scenegraph/util/qsgtexture.cpp @@ -65,7 +65,7 @@ static QElapsedTimer qsg_renderer_timer; #ifndef QT_NO_DEBUG -static bool qsg_leak_check = !qgetenv("QML_LEAK_CHECK").isEmpty(); +static const bool qsg_leak_check = !qEnvironmentVariableIsEmpty("QML_LEAK_CHECK"); #endif diff --git a/src/quick/scenegraph/util/qsgtexture_p.h b/src/quick/scenegraph/util/qsgtexture_p.h index c4edee6d29..221b85c2f7 100644 --- a/src/quick/scenegraph/util/qsgtexture_p.h +++ b/src/quick/scenegraph/util/qsgtexture_p.h @@ -34,6 +34,17 @@ #ifndef QSGTEXTURE_P_H #define QSGTEXTURE_P_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include <QtQuick/qtquickglobal.h> #include <private/qobject_p.h> diff --git a/src/quick/scenegraph/util/qsgtexturematerial_p.h b/src/quick/scenegraph/util/qsgtexturematerial_p.h index 7146ea95ec..5abd25977c 100644 --- a/src/quick/scenegraph/util/qsgtexturematerial_p.h +++ b/src/quick/scenegraph/util/qsgtexturematerial_p.h @@ -34,6 +34,17 @@ #ifndef TEXTUREMATERIAL_P_H #define TEXTUREMATERIAL_P_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include "qsgtexturematerial.h" #include <private/qtquickglobal_p.h> |