aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/scenegraph
diff options
context:
space:
mode:
authorFrederik Gladhorn <frederik.gladhorn@digia.com>2014-10-09 18:13:54 +0200
committerFrederik Gladhorn <frederik.gladhorn@digia.com>2014-10-09 18:14:56 +0200
commite1dfb78667bd7e8dc418e12a9669404adea7e2cb (patch)
tree16f40a9852281a63c1f98af21c680bddedaa5258 /src/quick/scenegraph
parent28949c9699014b4f7abba396c28dea207b29821e (diff)
parent26bbd784d67d151eee531e5ff57977a5353549f5 (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')
-rw-r--r--src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp83
-rw-r--r--src/quick/scenegraph/qsgadaptationlayer.cpp21
-rw-r--r--src/quick/scenegraph/qsgadaptationlayer_p.h9
-rw-r--r--src/quick/scenegraph/qsgcontext.cpp135
-rw-r--r--src/quick/scenegraph/qsgdefaultglyphnode_p.cpp24
-rw-r--r--src/quick/scenegraph/qsgdefaultlayer.cpp13
-rw-r--r--src/quick/scenegraph/qsgdefaultlayer_p.h3
-rw-r--r--src/quick/scenegraph/qsgrenderloop.cpp43
-rw-r--r--src/quick/scenegraph/qsgrenderloop_p.h2
-rw-r--r--src/quick/scenegraph/qsgthreadedrenderloop.cpp21
-rw-r--r--src/quick/scenegraph/qsgthreadedrenderloop_p.h1
-rw-r--r--src/quick/scenegraph/qsgwindowsrenderloop.cpp48
-rw-r--r--src/quick/scenegraph/shaders/styledtext.vert4
-rw-r--r--src/quick/scenegraph/shaders/styledtext_core.vert4
-rw-r--r--src/quick/scenegraph/shaders/textmask.vert2
-rw-r--r--src/quick/scenegraph/shaders/textmask_core.vert2
-rw-r--r--src/quick/scenegraph/util/qsgatlastexture.cpp11
-rw-r--r--src/quick/scenegraph/util/qsgtexture.cpp2
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);
}