diff options
author | Frederik Gladhorn <frederik.gladhorn@digia.com> | 2014-10-09 18:13:54 +0200 |
---|---|---|
committer | Frederik Gladhorn <frederik.gladhorn@digia.com> | 2014-10-09 18:14:56 +0200 |
commit | e1dfb78667bd7e8dc418e12a9669404adea7e2cb (patch) | |
tree | 16f40a9852281a63c1f98af21c680bddedaa5258 /src/quick/scenegraph | |
parent | 28949c9699014b4f7abba396c28dea207b29821e (diff) | |
parent | 26bbd784d67d151eee531e5ff57977a5353549f5 (diff) |
Merge remote-tracking branch 'origin/5.4' into dev
Conflicts:
src/quick/items/context2d/qquickcanvasitem.cpp
src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
src/quick/scenegraph/coreapi/qsgrenderer.cpp
src/quick/scenegraph/qsgadaptationlayer.cpp
src/quick/scenegraph/qsgrenderloop.cpp
src/quick/scenegraph/qsgthreadedrenderloop.cpp
src/quick/scenegraph/qsgwindowsrenderloop.cpp
src/quick/scenegraph/util/qsgatlastexture.cpp
src/quick/scenegraph/util/qsgtexture.cpp
src/quick/util/qquickprofiler_p.h
Change-Id: Ie274c3baf72a8a0711c87d67238d68e2b2887429
Diffstat (limited to 'src/quick/scenegraph')
18 files changed, 242 insertions, 186 deletions
diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp index 173858b21d..ac45cf70db 100644 --- a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp +++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp @@ -63,15 +63,19 @@ extern QByteArray qsgShaderRewriter_insertZAttributes(const char *input, QSurfac namespace QSGBatchRenderer { -const bool debug_render = qgetenv("QSG_RENDERER_DEBUG").contains("render"); -const bool debug_build = qgetenv("QSG_RENDERER_DEBUG").contains("build"); -const bool debug_change = qgetenv("QSG_RENDERER_DEBUG").contains("change"); -const bool debug_upload = qgetenv("QSG_RENDERER_DEBUG").contains("upload"); -const bool debug_roots = qgetenv("QSG_RENDERER_DEBUG").contains("roots"); -const bool debug_dump = qgetenv("QSG_RENDERER_DEBUG").contains("dump"); -const bool debug_noalpha = qgetenv("QSG_RENDERER_DEBUG").contains("noalpha"); -const bool debug_noopaque = qgetenv("QSG_RENDERER_DEBUG").contains("noopaque"); -const bool debug_noclip = qgetenv("QSG_RENDERER_DEBUG").contains("noclip"); +#define DECLARE_DEBUG_VAR(variable) \ + static bool debug_ ## variable() \ + { static bool value = qgetenv("QSG_RENDERER_DEBUG").contains(QT_STRINGIFY(variable)); return value; } +DECLARE_DEBUG_VAR(render) +DECLARE_DEBUG_VAR(build) +DECLARE_DEBUG_VAR(change) +DECLARE_DEBUG_VAR(upload) +DECLARE_DEBUG_VAR(roots) +DECLARE_DEBUG_VAR(dump) +DECLARE_DEBUG_VAR(noalpha) +DECLARE_DEBUG_VAR(noopaque) +DECLARE_DEBUG_VAR(noclip) +#undef DECLARE_DEBUG_VAR static QElapsedTimer qsg_renderer_timer; @@ -268,10 +272,10 @@ void Updater::updateStates(QSGNode *n) Node *sn = renderer->m_nodes.value(n, 0); Q_ASSERT(sn); - if (Q_UNLIKELY(debug_roots)) + if (Q_UNLIKELY(debug_roots())) qsg_dumpShadowRoots(sn); - if (Q_UNLIKELY(debug_build)) { + if (Q_UNLIKELY(debug_build())) { qDebug() << "Updater::updateStates()"; if (sn->dirtyState & (QSGNode::DirtyNodeAdded << 16)) qDebug() << " - nodes have been added"; @@ -785,7 +789,7 @@ Renderer::Renderer(QSGRenderContext *ctx) if (ok) m_batchVertexThreshold = threshold; } - if (Q_UNLIKELY(debug_build || debug_render)) { + 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")); } @@ -1048,7 +1052,7 @@ void Renderer::nodeWasRemoved(Node *node) void Renderer::turnNodeIntoBatchRoot(Node *node) { - if (Q_UNLIKELY(debug_change)) qDebug() << " - new batch root"; + if (Q_UNLIKELY(debug_change())) qDebug() << " - new batch root"; m_rebuild |= FullRebuild; node->isBatchRoot = true; node->becameBatchRoot = true; @@ -1069,7 +1073,7 @@ void Renderer::turnNodeIntoBatchRoot(Node *node) void Renderer::nodeChanged(QSGNode *node, QSGNode::DirtyState state) { - if (Q_UNLIKELY(debug_change)) { + if (Q_UNLIKELY(debug_change())) { QDebug debug = qDebug(); debug << "dirty:"; if (state & QSGNode::DirtyGeometry) @@ -1616,7 +1620,7 @@ void Renderer::prepareAlphaBatches() void Renderer::uploadMergedElement(Element *e, int vaOffset, char **vertexData, char **zData, char **indexData, quint16 *iBase, int *indexCount) { - if (Q_UNLIKELY(debug_upload)) qDebug() << " - uploading element:" << e << e->node << (void *) *vertexData << (qintptr) (*zData - *vertexData) << (qintptr) (*indexData - *vertexData); + if (Q_UNLIKELY(debug_upload())) qDebug() << " - uploading element:" << e << e->node << (void *) *vertexData << (qintptr) (*zData - *vertexData) << (qintptr) (*indexData - *vertexData); QSGGeometry *g = e->node->geometry(); const QMatrix4x4 &localx = *e->node->matrix(); @@ -1689,17 +1693,17 @@ void Renderer::uploadBatch(Batch *b) { // Early out if nothing has changed in this batch.. if (!b->needsUpload) { - if (Q_UNLIKELY(debug_upload)) qDebug() << " Batch:" << b << "already uploaded..."; + if (Q_UNLIKELY(debug_upload())) qDebug() << " Batch:" << b << "already uploaded..."; return; } if (!b->first) { - if (Q_UNLIKELY(debug_upload)) qDebug() << " Batch:" << b << "is invalid..."; + if (Q_UNLIKELY(debug_upload())) qDebug() << " Batch:" << b << "is invalid..."; return; } if (b->isRenderNode) { - if (Q_UNLIKELY(debug_upload)) qDebug() << " Batch: " << b << "is a render node..."; + if (Q_UNLIKELY(debug_upload())) qDebug() << " Batch: " << b << "is a render node..."; return; } @@ -1778,7 +1782,7 @@ void Renderer::uploadBatch(Batch *b) #endif map(&b->vbo, bufferSize); - if (Q_UNLIKELY(debug_upload)) qDebug() << " - batch" << b << " first:" << b->first << " root:" + if (Q_UNLIKELY(debug_upload())) qDebug() << " - batch" << b << " first:" << b->first << " root:" << b->root << " merged:" << b->merged << " positionAttribute" << b->positionAttribute << " vbo:" << b->vbo.id << ":" << b->vbo.size; @@ -1844,7 +1848,7 @@ void Renderer::uploadBatch(Batch *b) } } - if (Q_UNLIKELY(debug_upload)) { + if (Q_UNLIKELY(debug_upload())) { const char *vd = b->vbo.data; qDebug() << " -- Vertex Data, count:" << b->vertexCount << " - " << g->sizeOfVertex() << "bytes/vertex"; for (int i=0; i<b->vertexCount; ++i) { @@ -1875,9 +1879,12 @@ void Renderer::uploadBatch(Batch *b) vd += g->sizeOfVertex(); } - const quint16 *id = (const quint16 *) (b->vbo.data - + b->vertexCount * g->sizeOfVertex() - + (b->merged ? b->vertexCount * sizeof(float) : 0)); + const quint16 *id = +#ifdef QSG_SEPARATE_INDEX_BUFFER + (const quint16 *) (b->ibo.data); +#else + (const quint16 *) (b->vbo.data + b->drawSets.at(0).indices); +#endif { QDebug iDump = qDebug(); iDump << " -- Index Data, count:" << b->indexCount; @@ -1899,11 +1906,11 @@ void Renderer::uploadBatch(Batch *b) unmap(&b->ibo, true); #endif - if (Q_UNLIKELY(debug_upload)) qDebug() << " --- vertex/index buffers unmapped, batch upload completed..."; + if (Q_UNLIKELY(debug_upload())) qDebug() << " --- vertex/index buffers unmapped, batch upload completed..."; b->needsUpload = false; - if (Q_UNLIKELY(debug_render)) + if (Q_UNLIKELY(debug_render())) b->uploadedThisFrame = true; } @@ -2035,7 +2042,7 @@ Renderer::ClipType Renderer::updateStencilClip(const QSGClipNode *clip) void Renderer::updateClip(const QSGClipNode *clipList, const Batch *batch) { - if (clipList != m_currentClip && Q_LIKELY(!debug_noclip)) { + if (clipList != m_currentClip && Q_LIKELY(!debug_noclip())) { m_currentClip = clipList; // updateClip sets another program, so force-reactivate our own if (m_currentShader) @@ -2114,7 +2121,7 @@ void Renderer::renderMergedBatch(const Batch *batch) Element *e = batch->first; Q_ASSERT(e); - if (Q_UNLIKELY(debug_render)) { + if (Q_UNLIKELY(debug_render())) { QDebug debug = qDebug(); debug << " -" << batch @@ -2223,7 +2230,7 @@ void Renderer::renderUnmergedBatch(const Batch *batch) Element *e = batch->first; Q_ASSERT(e); - if (Q_UNLIKELY(debug_render)) { + if (Q_UNLIKELY(debug_render())) { qDebug() << " -" << batch << (batch->uploadedThisFrame ? "[ upload]" : "[retained]") @@ -2353,7 +2360,7 @@ void Renderer::renderUnmergedBatch(const Batch *batch) void Renderer::renderBatches() { - if (Q_UNLIKELY(debug_render)) { + if (Q_UNLIKELY(debug_render())) { qDebug().nospace() << "Rendering:" << endl << " -> Opaque: " << qsg_countNodesInBatches(m_opaqueBatches) << " nodes in " << m_opaqueBatches.size() << " batches..." << endl << " -> Alpha: " << qsg_countNodesInBatches(m_alphaBatches) << " nodes in " << m_alphaBatches.size() << " batches..."; @@ -2386,8 +2393,8 @@ void Renderer::renderBatches() m_currentProgram = 0; m_currentClip = 0; - bool renderOpaque = !debug_noopaque; - bool renderAlpha = !debug_noalpha; + bool renderOpaque = !debug_noopaque(); + bool renderAlpha = !debug_noalpha(); if (Q_LIKELY(renderOpaque)) { for (int i=0; i<m_opaqueBatches.size(); ++i) { @@ -2463,12 +2470,12 @@ void Renderer::preprocess() void Renderer::render() { - if (Q_UNLIKELY(debug_dump)) { + if (Q_UNLIKELY(debug_dump())) { qDebug("\n"); QSGNodeDumper::dump(rootNode()); } - if (Q_UNLIKELY(debug_render || debug_build)) { + if (Q_UNLIKELY(debug_render() || debug_build())) { QByteArray type("rebuild:"); if (m_rebuild == 0) @@ -2495,7 +2502,7 @@ void Renderer::render() buildRenderListsForTaggedRoots(); m_rebuild |= BuildBatches; - if (Q_UNLIKELY(debug_build)) { + if (Q_UNLIKELY(debug_build())) { qDebug() << "Opaque render lists" << (complete ? "(complete)" : "(partial)") << ":"; for (int i=0; i<m_opaqueRenderList.size(); ++i) { Element *e = m_opaqueRenderList.at(i); @@ -2522,7 +2529,7 @@ void Renderer::render() prepareOpaqueBatches(); prepareAlphaBatches(); - if (Q_UNLIKELY(debug_build)) { + if (Q_UNLIKELY(debug_build())) { qDebug() << "Opaque Batches:"; for (int i=0; i<m_opaqueBatches.size(); ++i) { Batch *b = m_opaqueBatches.at(i); @@ -2558,11 +2565,11 @@ void Renderer::render() } - if (Q_UNLIKELY(debug_upload)) qDebug() << "Uploading Opaque Batches:"; + if (Q_UNLIKELY(debug_upload())) qDebug() << "Uploading Opaque Batches:"; for (int i=0; i<m_opaqueBatches.size(); ++i) uploadBatch(m_opaqueBatches.at(i)); - if (Q_UNLIKELY(debug_upload)) qDebug() << "Uploading Alpha Batches:"; + if (Q_UNLIKELY(debug_upload())) qDebug() << "Uploading Alpha Batches:"; for (int i=0; i<m_alphaBatches.size(); ++i) uploadBatch(m_alphaBatches.at(i)); @@ -2581,7 +2588,7 @@ void Renderer::render() void Renderer::renderRenderNode(Batch *batch) { - if (Q_UNLIKELY(debug_render)) + if (Q_UNLIKELY(debug_render())) qDebug() << " -" << batch << "rendernode"; Q_ASSERT(batch->first->isRenderNode); diff --git a/src/quick/scenegraph/qsgadaptationlayer.cpp b/src/quick/scenegraph/qsgadaptationlayer.cpp index db32f656e1..e0b96a45b6 100644 --- a/src/quick/scenegraph/qsgadaptationlayer.cpp +++ b/src/quick/scenegraph/qsgadaptationlayer.cpp @@ -338,25 +338,4 @@ void QSGNodeVisitorEx::visitChildren(QSGNode *node) } } -void QSGLayer::markDirtyTextureLater() -{ - QCoreApplication::postEvent(this, new QEvent(static_cast<QEvent::Type>(markDirtyEventType()))); -} - -void QSGLayer::customEvent(QEvent *event) -{ - if (event->type() == markDirtyEventType()) - markDirtyTexture(); - else - QObject::customEvent(event); -} - -int QSGLayer::markDirtyEventType() -{ - static int type = QEvent::None; - if (type == QEvent::None) - type = QEvent::registerEventType(); - return type; -} - QT_END_NAMESPACE diff --git a/src/quick/scenegraph/qsgadaptationlayer_p.h b/src/quick/scenegraph/qsgadaptationlayer_p.h index 71033bd6d0..a63299fcde 100644 --- a/src/quick/scenegraph/qsgadaptationlayer_p.h +++ b/src/quick/scenegraph/qsgadaptationlayer_p.h @@ -198,7 +198,6 @@ class Q_QUICK_EXPORT QSGLayer : public QSGDynamicTexture Q_OBJECT public: virtual void setItem(QSGNode *item) = 0; - virtual void setShaderSourceNode(QSGNode *node) = 0; virtual void setRect(const QRectF &rect) = 0; virtual void setSize(const QSize &size) = 0; virtual void scheduleUpdate() = 0; @@ -211,17 +210,9 @@ public: Q_SLOT virtual void markDirtyTexture() = 0; Q_SLOT virtual void invalidated() = 0; - Q_SLOT void markDirtyTextureLater(); - Q_SIGNALS: void updateRequested(); void scheduledUpdateCompleted(); - -protected: - virtual void customEvent(QEvent *); - -private: - int markDirtyEventType(); }; class Q_QUICK_PRIVATE_EXPORT QSGGlyphNode : public QSGVisitableNode diff --git a/src/quick/scenegraph/qsgcontext.cpp b/src/quick/scenegraph/qsgcontext.cpp index e7b37e50d2..b87ab3686f 100644 --- a/src/quick/scenegraph/qsgcontext.cpp +++ b/src/quick/scenegraph/qsgcontext.cpp @@ -50,6 +50,7 @@ #include <QtQuick/private/qquickpixmapcache_p.h> #include <QGuiApplication> +#include <QScreen> #include <QOpenGLContext> #include <QQuickWindow> #include <QtGui/qopenglframebufferobject.h> @@ -58,6 +59,7 @@ #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> @@ -134,6 +136,135 @@ public: bool distanceFieldAntialiasingDecided; }; +static bool qsg_useConsistentTiming() +{ + static int use = -1; + if (use < 0) { + QByteArray fixed = qgetenv("QSG_FIXED_ANIMATION_STEP"); + use = !(fixed.isEmpty() || fixed == "no"); + qCDebug(QSG_LOG_INFO, "Using %s", bool(use) ? "fixed animation steps" : "sg animation driver"); + } + return bool(use); +} + +class QSGAnimationDriver : public QAnimationDriver +{ + Q_OBJECT +public: + enum Mode { + VSyncMode, + TimerMode + }; + + QSGAnimationDriver(QObject *parent) + : QAnimationDriver(parent) + , m_time(0) + , m_vsync(0) + , m_mode(VSyncMode) + , m_bad(0) + , m_reallyBad(0) + , m_good(0) + { + QScreen *screen = QGuiApplication::primaryScreen(); + if (screen && !qsg_useConsistentTiming()) { + m_vsync = 1000.0 / screen->refreshRate(); + if (m_vsync <= 0) + m_mode = TimerMode; + } else { + m_mode = TimerMode; + if (qsg_useConsistentTiming()) + QUnifiedTimer::instance(true)->setConsistentTiming(true); + } + if (m_mode == VSyncMode) + qCDebug(QSG_LOG_INFO, "Animation Driver: using vsync: %.2f ms", m_vsync); + else + qCDebug(QSG_LOG_INFO, "Animation Driver: using walltime"); + } + + void start() Q_DECL_OVERRIDE + { + m_time = 0; + m_timer.start(); + QAnimationDriver::start(); + } + + qint64 elapsed() const Q_DECL_OVERRIDE + { + return m_mode == VSyncMode + ? qint64(m_time) + : QAnimationDriver::elapsed(); + } + + void advance() Q_DECL_OVERRIDE + { + qint64 delta = m_timer.restart(); + + if (m_mode == VSyncMode) { + // If a frame is skipped, either because rendering was slow or because + // the QML was slow, we accept it and continue advancing with a single + // vsync tick. The reason for this is that by the time we notice this + // on the GUI thread, the temporal distortion has already gone to screen + // and by catching up, we will introduce a second distortion which will + // worse. We accept that the animation time falls behind wall time because + // it comes out looking better. + // Only when multiple bad frames are hit in a row, do we consider + // switching. A few really bad frames and we switch right away. For frames + // just above the vsync delta, we tolerate a bit more since a buffered + // driver can have vsync deltas on the form: 4, 21, 21, 2, 23, 16, and + // still manage to put the frames to screen at 16 ms intervals. In addition + // to that, we tolerate a 25% margin of error on the value of m_vsync + // reported from the system as this value is often not precise. + + m_time += m_vsync; + + if (delta > m_vsync * 5) { + ++m_reallyBad; + ++m_bad; + } else if (delta > m_vsync * 1.25) { + ++m_bad; + } else { + // reset counters on a good frame. + m_reallyBad = 0; + m_bad = 0; + } + + // rational for the 3 and 50. If we have several really bad frames + // in a row, that would indicate a huge performance problem and we should + // switch right away. For the case of m_bad, we're a bit more tolerant. + if (m_reallyBad > 3 || m_bad > 50) { + m_mode = TimerMode; + qCDebug(QSG_LOG_INFO, "animation driver switched to timer mode"); + } + + } else { + if (delta < 1.25 * m_vsync) { + ++m_good; + } else { + m_good = 0; + } + + // We've been solid for a while, switch back to vsync mode. Tolerance + // for switching back is lower than switching to timer mode, as we + // want to stay in vsync mode as much as possible. + if (m_good > 10 && !qsg_useConsistentTiming()) { + m_time = elapsed(); + m_mode = VSyncMode; + qCDebug(QSG_LOG_INFO, "animation driver switched to vsync mode"); + } + } + + advanceAnimation(); + } + + float m_time; + float m_vsync; + Mode m_mode; + QElapsedTimer m_timer; + int m_bad; + int m_reallyBad; + int m_good; +}; + class QSGTextureCleanupEvent : public QEvent { public: @@ -389,7 +520,7 @@ bool QSGContext::isDistanceFieldEnabled() const QAnimationDriver *QSGContext::createAnimationDriver(QObject *parent) { - return new QAnimationDriver(parent); + return new QSGAnimationDriver(parent); } QSGRenderContext::QSGRenderContext(QSGContext *context) @@ -730,4 +861,6 @@ void QSGRenderContext::initialize(QSGMaterialShader *shader) shader->initialize(); } +#include "qsgcontext.moc" + QT_END_NAMESPACE diff --git a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp index 16feafe02f..802c92be9f 100644 --- a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp +++ b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp @@ -128,28 +128,8 @@ void QSGTextMaskShader::updateState(const RenderState &state, QSGMaterial *newEf } } - if (state.isMatrixDirty()) { - QMatrix4x4 transform = state.modelViewMatrix(); - qreal xTranslation = transform(0, 3); - qreal yTranslation = transform(1, 3); - - // Remove translation and check identity to see if matrix is only translating. - // If it is, we can round the translation to make sure the text is pixel aligned, - // which is the only thing that works with GL_NEAREST filtering. Adding rotations - // and scales to native rendered text is not a prioritized use case, since the - // default rendering type is designed for that. - transform(0, 3) = 0.0; - transform(1, 3) = 0.0; - if (transform.isIdentity()) { - transform(0, 3) = qRound(xTranslation); - transform(1, 3) = qRound(yTranslation); - - transform = state.projectionMatrix() * transform; - program()->setUniformValue(m_matrix_id, transform); - } else { - program()->setUniformValue(m_matrix_id, state.combinedMatrix()); - } - } + if (state.isMatrixDirty()) + program()->setUniformValue(m_matrix_id, state.combinedMatrix()); } class QSG8BitTextMaskShader : public QSGTextMaskShader diff --git a/src/quick/scenegraph/qsgdefaultlayer.cpp b/src/quick/scenegraph/qsgdefaultlayer.cpp index 29f125e0be..2d114aebd5 100644 --- a/src/quick/scenegraph/qsgdefaultlayer.cpp +++ b/src/quick/scenegraph/qsgdefaultlayer.cpp @@ -88,7 +88,6 @@ namespace QSGDefaultLayer::QSGDefaultLayer(QSGRenderContext *context) : QSGLayer() , m_item(0) - , m_shaderSourceNode(0) , m_device_pixel_ratio(1) , m_format(GL_RGBA) , m_renderer(0) @@ -259,11 +258,8 @@ void QSGDefaultLayer::scheduleUpdate() if (m_grab) return; m_grab = true; - if (m_dirtyTexture) { + if (m_dirtyTexture) emit updateRequested(); - if (m_shaderSourceNode) - m_shaderSourceNode->markDirty(QSGNode::DirtyMaterial); - } } void QSGDefaultLayer::setRecursive(bool recursive) @@ -274,11 +270,8 @@ void QSGDefaultLayer::setRecursive(bool recursive) void QSGDefaultLayer::markDirtyTexture() { m_dirtyTexture = true; - if (m_live || m_grab) { + if (m_live || m_grab) emit updateRequested(); - if (m_shaderSourceNode) - m_shaderSourceNode->markDirty(QSGNode::DirtyMaterial); - } } void QSGDefaultLayer::grab() @@ -299,7 +292,7 @@ void QSGDefaultLayer::grab() if (!m_renderer) { m_renderer = m_context->createRenderer(); - connect(m_renderer, SIGNAL(sceneGraphChanged()), this, SLOT(markDirtyTextureLater())); + connect(m_renderer, SIGNAL(sceneGraphChanged()), this, SLOT(markDirtyTexture())); } m_renderer->setDevicePixelRatio(m_device_pixel_ratio); m_renderer->setRootNode(static_cast<QSGRootNode *>(root)); diff --git a/src/quick/scenegraph/qsgdefaultlayer_p.h b/src/quick/scenegraph/qsgdefaultlayer_p.h index b4a5adab5a..0615045d60 100644 --- a/src/quick/scenegraph/qsgdefaultlayer_p.h +++ b/src/quick/scenegraph/qsgdefaultlayer_p.h @@ -60,8 +60,6 @@ public: QSGNode *item() const { return m_item; } void setItem(QSGNode *item); - void setShaderSourceNode(QSGNode *node) { m_shaderSourceNode = node; } - QRectF rect() const { return m_rect; } void setRect(const QRectF &rect); @@ -100,7 +98,6 @@ private: void grab(); QSGNode *m_item; - QSGNode *m_shaderSourceNode; QRectF m_rect; QSize m_size; qreal m_device_pixel_ratio; diff --git a/src/quick/scenegraph/qsgrenderloop.cpp b/src/quick/scenegraph/qsgrenderloop.cpp index 0de3c84491..6381c3160f 100644 --- a/src/quick/scenegraph/qsgrenderloop.cpp +++ b/src/quick/scenegraph/qsgrenderloop.cpp @@ -147,19 +147,6 @@ public: bool eventPending; }; -bool QSGRenderLoop::useConsistentTiming() -{ - bool bufferQueuing = QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::BufferQueueingOpenGL); - // Enable fixed animation steps... - QByteArray fixed = qgetenv("QSG_FIXED_ANIMATION_STEP"); - bool fixedAnimationSteps = bufferQueuing; - if (fixed == "no") - fixedAnimationSteps = false; - else if (fixed.length()) - fixedAnimationSteps = true; - return fixedAnimationSteps; -} - QSGRenderLoop *QSGRenderLoop::instance() { if (!s_instance) { @@ -170,11 +157,6 @@ QSGRenderLoop *QSGRenderLoop::instance() s_instance = QSGContext::createWindowManager(); - if (useConsistentTiming()) { - QUnifiedTimer::instance(true)->setConsistentTiming(true); - qCDebug(QSG_LOG_INFO, "using fixed animation steps"); - } - if (!s_instance) { enum RenderLoopType { @@ -283,37 +265,24 @@ void QSGGuiThreadRenderLoop::show(QQuickWindow *window) void QSGGuiThreadRenderLoop::hide(QQuickWindow *window) { - if (!m_windows.contains(window)) - return; - - m_windows.remove(window); QQuickWindowPrivate *cd = QQuickWindowPrivate::get(window); - if (gl) - gl->makeCurrent(window); cd->fireAboutToStop(); - cd->cleanupNodesOnShutdown(); - - if (m_windows.size() == 0) { - if (!cd->persistentSceneGraph) { - rc->invalidate(); - QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); - if (!cd->persistentGLContext) { - delete gl; - gl = 0; - } - } - } } void QSGGuiThreadRenderLoop::windowDestroyed(QQuickWindow *window) { + m_windows.remove(window); hide(window); + QQuickWindowPrivate *d = QQuickWindowPrivate::get(window); + if (gl) + gl->makeCurrent(window); + d->cleanupNodesOnShutdown(); if (m_windows.size() == 0) { rc->invalidate(); QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); delete gl; gl = 0; - } else if (window == gl->surface()) { + } else if (gl && window == gl->surface()) { gl->doneCurrent(); } } diff --git a/src/quick/scenegraph/qsgrenderloop_p.h b/src/quick/scenegraph/qsgrenderloop_p.h index daba3bc69d..e9b58c60ba 100644 --- a/src/quick/scenegraph/qsgrenderloop_p.h +++ b/src/quick/scenegraph/qsgrenderloop_p.h @@ -82,8 +82,6 @@ public: static QSGRenderLoop *instance(); static void setInstance(QSGRenderLoop *instance); - static bool useConsistentTiming(); - virtual bool interleaveIncubation() const { return false; } static void cleanup(); diff --git a/src/quick/scenegraph/qsgthreadedrenderloop.cpp b/src/quick/scenegraph/qsgthreadedrenderloop.cpp index 92c478b54f..29bee67f69 100644 --- a/src/quick/scenegraph/qsgthreadedrenderloop.cpp +++ b/src/quick/scenegraph/qsgthreadedrenderloop.cpp @@ -189,9 +189,15 @@ public: class WMSyncEvent : public WMWindowEvent { public: - WMSyncEvent(QQuickWindow *c, bool inExpose) : WMWindowEvent(c, WM_RequestSync), size(c->size()), syncInExpose(inExpose) { } + WMSyncEvent(QQuickWindow *c, bool inExpose, bool force) + : WMWindowEvent(c, WM_RequestSync) + , size(c->size()) + , syncInExpose(inExpose) + , forceRenderPass(force) + {} QSize size; bool syncInExpose; + bool forceRenderPass; }; @@ -368,6 +374,10 @@ bool QSGRenderThread::event(QEvent *e) qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- triggered from expose"; pendingUpdate |= ExposeRequest; } + if (se->forceRenderPass) { + qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "- repaint regardless"; + pendingUpdate |= RepaintRequest; + } return true; } case WM_TryRelease: { @@ -641,7 +651,6 @@ void QSGRenderThread::run() qCDebug(QSG_LOG_RENDERLOOP) << QSG_RT_PAD << "run()"; animatorDriver = sgrc->sceneGraphContext()->createAnimationDriver(0); animatorDriver->install(); - QUnifiedTimer::instance(true)->setConsistentTiming(QSGRenderLoop::useConsistentTiming()); if (QQmlDebugService::isDebuggingEnabled()) QQuickProfiler::registerAnimationCallback(); @@ -855,6 +864,7 @@ void QSGThreadedRenderLoop::handleExposure(QQuickWindow *window) win.thread = new QSGRenderThread(this, QQuickWindowPrivate::get(window)->context); win.timerId = 0; win.updateDuringSync = false; + win.forceRenderPass = true; // also covered by polishAndSync(inExpose=true), but doesn't hurt m_windows << win; w = &m_windows.last(); } @@ -998,7 +1008,9 @@ void QSGThreadedRenderLoop::update(QQuickWindow *window) } qCDebug(QSG_LOG_RENDERLOOP) << "update on window" << w->window; - w->thread->postEvent(new QEvent(WM_RequestRepaint)); + // We set forceRenderPass because we want to make sure the QQuickWindow + // actually does a full render pass after the next sync. + w->forceRenderPass = true; maybeUpdate(w); } @@ -1107,7 +1119,8 @@ void QSGThreadedRenderLoop::polishAndSync(Window *w, bool inExpose) qCDebug(QSG_LOG_RENDERLOOP) << "- lock for sync"; w->thread->mutex.lock(); m_lockedForSync = true; - w->thread->postEvent(new WMSyncEvent(window, inExpose)); + w->thread->postEvent(new WMSyncEvent(window, inExpose, w->forceRenderPass)); + w->forceRenderPass = false; qCDebug(QSG_LOG_RENDERLOOP) << "- wait for sync"; if (profileFrames) diff --git a/src/quick/scenegraph/qsgthreadedrenderloop_p.h b/src/quick/scenegraph/qsgthreadedrenderloop_p.h index 0e4da27fc6..82f314a6af 100644 --- a/src/quick/scenegraph/qsgthreadedrenderloop_p.h +++ b/src/quick/scenegraph/qsgthreadedrenderloop_p.h @@ -82,6 +82,7 @@ private: QSurfaceFormat actualWindowFormat; int timerId; uint updateDuringSync : 1; + uint forceRenderPass : 1; }; friend class QSGRenderThread; diff --git a/src/quick/scenegraph/qsgwindowsrenderloop.cpp b/src/quick/scenegraph/qsgwindowsrenderloop.cpp index b55977296c..11e3376af5 100644 --- a/src/quick/scenegraph/qsgwindowsrenderloop.cpp +++ b/src/quick/scenegraph/qsgwindowsrenderloop.cpp @@ -189,14 +189,6 @@ void QSGWindowsRenderLoop::show(QQuickWindow *window) void QSGWindowsRenderLoop::hide(QQuickWindow *window) { RLDEBUG("hide"); - - for (int i=0; i<m_windows.size(); ++i) { - if (m_windows.at(i).window == window) { - m_windows.removeAt(i); - break; - } - } - // The expose event is queued while hide is sent synchronously, so // the value might not be updated yet. (plus that the windows plugin // sends exposed=true when it goes to hidden, so it is doubly broken) @@ -204,47 +196,41 @@ void QSGWindowsRenderLoop::hide(QQuickWindow *window) // anyoneShowing will report the right value. if (window->isExposed()) handleObscurity(); - if (!m_gl) return; - - QQuickWindowPrivate *cd = QQuickWindowPrivate::get(window); - m_gl->makeCurrent(window); - cd->fireAboutToStop(); - cd->cleanupNodesOnShutdown(); - - // If this is the last tracked window, check for persistent SG and GL and - // potentially clean up. - if (m_windows.size() == 0) { - if (!cd->persistentSceneGraph) { - QQuickWindowPrivate::get(window)->context->invalidate(); - QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); - if (!cd->persistentGLContext) { - delete m_gl; - m_gl = 0; - } - } - } + QQuickWindowPrivate::get(window)->fireAboutToStop(); } void QSGWindowsRenderLoop::windowDestroyed(QQuickWindow *window) { RLDEBUG("windowDestroyed"); + for (int i=0; i<m_windows.size(); ++i) { + if (m_windows.at(i).window == window) { + m_windows.removeAt(i); + break; + } + } + hide(window); - // If this is the last tracked window, clean up SG and GL. + QQuickWindowPrivate *d = QQuickWindowPrivate::get(window); + if (m_gl) + m_gl->makeCurrent(window); + d->cleanupNodesOnShutdown(); if (m_windows.size() == 0) { - QQuickWindowPrivate::get(window)->context->invalidate(); + d->context->invalidate(); QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); delete m_gl; m_gl = 0; + } else if (m_gl) { + m_gl->doneCurrent(); } } bool QSGWindowsRenderLoop::anyoneShowing() const { foreach (const WindowData &wd, m_windows) - if (wd.window->isExposed() && wd.window->size().isValid()) + if (wd.window->isVisible() && wd.window->isExposed() && wd.window->size().isValid()) return true; return false; } @@ -255,7 +241,7 @@ void QSGWindowsRenderLoop::exposureChanged(QQuickWindow *window) if (windowData(window) == 0) return; - if (window->isExposed()) { + if (window->isExposed() && window->isVisible()) { // Stop non-visual animation timer as we now have a window rendering if (m_animationTimer && anyoneShowing()) { diff --git a/src/quick/scenegraph/shaders/styledtext.vert b/src/quick/scenegraph/shaders/styledtext.vert index 3ad9497b65..14fefc2564 100644 --- a/src/quick/scenegraph/shaders/styledtext.vert +++ b/src/quick/scenegraph/shaders/styledtext.vert @@ -12,5 +12,5 @@ void main() { sampleCoord = tCoord * textureScale; shiftedSampleCoord = (tCoord - shift) * textureScale; - gl_Position = matrix * vCoord; -}
\ No newline at end of file + gl_Position = matrix * floor(vCoord + 0.5); +} diff --git a/src/quick/scenegraph/shaders/styledtext_core.vert b/src/quick/scenegraph/shaders/styledtext_core.vert index b7a3ecc667..65bdb66814 100644 --- a/src/quick/scenegraph/shaders/styledtext_core.vert +++ b/src/quick/scenegraph/shaders/styledtext_core.vert @@ -14,5 +14,5 @@ void main() { sampleCoord = tCoord * textureScale; shiftedSampleCoord = (tCoord - shift) * textureScale; - gl_Position = matrix * vCoord; -}
\ No newline at end of file + gl_Position = matrix * round(vCoord); +} diff --git a/src/quick/scenegraph/shaders/textmask.vert b/src/quick/scenegraph/shaders/textmask.vert index 1f45e9cf71..dd8918839e 100644 --- a/src/quick/scenegraph/shaders/textmask.vert +++ b/src/quick/scenegraph/shaders/textmask.vert @@ -9,5 +9,5 @@ varying highp vec2 sampleCoord; void main() { sampleCoord = tCoord * textureScale; - gl_Position = matrix * vCoord; + gl_Position = matrix * floor(vCoord + 0.5); } diff --git a/src/quick/scenegraph/shaders/textmask_core.vert b/src/quick/scenegraph/shaders/textmask_core.vert index 619248dccb..d145d33195 100644 --- a/src/quick/scenegraph/shaders/textmask_core.vert +++ b/src/quick/scenegraph/shaders/textmask_core.vert @@ -11,5 +11,5 @@ uniform vec2 textureScale; void main() { sampleCoord = tCoord * textureScale; - gl_Position = matrix * vCoord; + gl_Position = matrix * round(vCoord); } diff --git a/src/quick/scenegraph/util/qsgatlastexture.cpp b/src/quick/scenegraph/util/qsgatlastexture.cpp index bc091edffe..cb82d721ca 100644 --- a/src/quick/scenegraph/util/qsgatlastexture.cpp +++ b/src/quick/scenegraph/util/qsgatlastexture.cpp @@ -307,7 +307,16 @@ void Atlas::uploadBgra(Texture *texture) funcs->glTexSubImage2D(GL_TEXTURE_2D, 0, r.x() + iw + 1, r.y() + 1, 1, ih, m_externalFormat, GL_UNSIGNED_BYTE, dst); // Inner part of the image.... - funcs->glTexSubImage2D(GL_TEXTURE_2D, 0, r.x() + 1, r.y() + 1, r.width() - 2, r.height() - 2, m_externalFormat, GL_UNSIGNED_BYTE, src); + if (bpl != iw) { + int sy = r.y() + 1; + int ey = sy + r.height() - 2; + for (int y = sy; y < ey; ++y) { + funcs->glTexSubImage2D(GL_TEXTURE_2D, 0, r.x() + 1, y, r.width() - 2, 1, m_externalFormat, GL_UNSIGNED_BYTE, src); + src += bpl; + } + } else { + funcs->glTexSubImage2D(GL_TEXTURE_2D, 0, r.x() + 1, r.y() + 1, r.width() - 2, r.height() - 2, m_externalFormat, GL_UNSIGNED_BYTE, src); + } } void Atlas::bind(QSGTexture::Filtering filtering) diff --git a/src/quick/scenegraph/util/qsgtexture.cpp b/src/quick/scenegraph/util/qsgtexture.cpp index 3bb0cb0074..673323baa2 100644 --- a/src/quick/scenegraph/util/qsgtexture.cpp +++ b/src/quick/scenegraph/util/qsgtexture.cpp @@ -563,7 +563,7 @@ QSGPlainTexture::QSGPlainTexture() QSGPlainTexture::~QSGPlainTexture() { - if (m_texture_id && m_owns_texture) + if (m_texture_id && m_owns_texture && QOpenGLContext::currentContext()) QOpenGLContext::currentContext()->functions()->glDeleteTextures(1, &m_texture_id); } |