aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/scenegraph
diff options
context:
space:
mode:
Diffstat (limited to 'src/quick/scenegraph')
-rw-r--r--src/quick/scenegraph/coreapi/qsggeometry.cpp18
-rw-r--r--src/quick/scenegraph/coreapi/qsgmaterial.cpp1
-rw-r--r--src/quick/scenegraph/coreapi/qsgmaterial.h1
-rw-r--r--src/quick/scenegraph/coreapi/qsgnode.cpp52
-rw-r--r--src/quick/scenegraph/coreapi/qsgnode.h11
-rw-r--r--src/quick/scenegraph/coreapi/qsgnode_p.h76
-rw-r--r--src/quick/scenegraph/coreapi/qsgrenderer.cpp52
-rw-r--r--src/quick/scenegraph/qsgadaptationlayer.cpp21
-rw-r--r--src/quick/scenegraph/qsgcontext.cpp66
-rw-r--r--src/quick/scenegraph/qsgcontext_p.h1
-rw-r--r--src/quick/scenegraph/qsgdefaultglyphnode_p.cpp7
-rw-r--r--src/quick/scenegraph/qsgdefaultimagenode.cpp8
-rw-r--r--src/quick/scenegraph/qsgdefaultimagenode_p.h8
-rw-r--r--src/quick/scenegraph/qsgdefaultrectanglenode.cpp8
-rw-r--r--src/quick/scenegraph/qsgdefaultrectanglenode_p.h8
-rw-r--r--src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp39
-rw-r--r--src/quick/scenegraph/qsgdistancefieldglyphnode_p_p.h12
-rw-r--r--src/quick/scenegraph/qsgrenderloop.cpp122
-rw-r--r--src/quick/scenegraph/qsgrenderloop_p.h9
-rw-r--r--src/quick/scenegraph/qsgthreadedrenderloop.cpp98
-rw-r--r--src/quick/scenegraph/qsgthreadedrenderloop_p.h6
-rw-r--r--src/quick/scenegraph/qsgwindowsrenderloop.cpp469
-rw-r--r--src/quick/scenegraph/qsgwindowsrenderloop_p.h116
-rw-r--r--src/quick/scenegraph/scenegraph.pri17
-rw-r--r--src/quick/scenegraph/util/qsgflatcolormaterial.cpp10
-rw-r--r--src/quick/scenegraph/util/qsgpainternode.cpp31
-rw-r--r--src/quick/scenegraph/util/qsgsimpletexturenode.cpp81
-rw-r--r--src/quick/scenegraph/util/qsgsimpletexturenode.h16
-rw-r--r--src/quick/scenegraph/util/qsgtexture.cpp60
-rw-r--r--src/quick/scenegraph/util/qsgtexture_p.h2
-rw-r--r--src/quick/scenegraph/util/qsgtexturematerial.cpp6
31 files changed, 1175 insertions, 257 deletions
diff --git a/src/quick/scenegraph/coreapi/qsggeometry.cpp b/src/quick/scenegraph/coreapi/qsggeometry.cpp
index 818b9b26aa..7f09af4da3 100644
--- a/src/quick/scenegraph/coreapi/qsggeometry.cpp
+++ b/src/quick/scenegraph/coreapi/qsggeometry.cpp
@@ -332,42 +332,42 @@ const QSGGeometry::AttributeSet &QSGGeometry::defaultAttributes_ColoredPoint2D()
/*!
\fn const QSGGeometry::ColoredPoint2D *QSGGeometry::vertexDataAsColoredPoint2D() const
- Convenience function to access the vertex data as an immuatble
+ Convenience function to access the vertex data as an immutable
array of QSGGeometry::ColoredPoint2D.
*/
/*!
\fn QSGGeometry::ColoredPoint2D *QSGGeometry::vertexDataAsColoredPoint2D()
- Convenience function to access the vertex data as a muatble
+ Convenience function to access the vertex data as a mutable
array of QSGGeometry::ColoredPoint2D.
*/
/*!
\fn const QSGGeometry::TexturedPoint2D *QSGGeometry::vertexDataAsTexturedPoint2D() const
- Convenience function to access the vertex data as an immuatble
+ Convenience function to access the vertex data as an immutable
array of QSGGeometry::TexturedPoint2D.
*/
/*!
\fn QSGGeometry::TexturedPoint2D *QSGGeometry::vertexDataAsTexturedPoint2D()
- Convenience function to access the vertex data as a muatble
+ Convenience function to access the vertex data as a mutable
array of QSGGeometry::TexturedPoint2D.
*/
/*!
\fn const QSGGeometry::Point2D *QSGGeometry::vertexDataAsPoint2D() const
- Convenience function to access the vertex data as an immuatble
+ Convenience function to access the vertex data as an immutable
array of QSGGeometry::Point2D.
*/
/*!
\fn QSGGeometry::Point2D *QSGGeometry::vertexDataAsPoint2D()
- Convenience function to access the vertex data as a muatble
+ Convenience function to access the vertex data as a mutable
array of QSGGeometry::Point2D.
*/
@@ -705,7 +705,8 @@ void QSGGeometry::updateTexturedRectGeometry(QSGGeometry *g, const QRectF &rect,
The default is AlwaysUploadPattern. When set to anything other than
the default, the user must call markIndexDataDirty() after changing
- the index data.
+ the index data, in addition to calling QSGNode::markDirty() with
+ QSGNode::DirtyGeometry.
*/
void QSGGeometry::setIndexDataPattern(DataPattern p)
@@ -728,7 +729,8 @@ void QSGGeometry::setIndexDataPattern(DataPattern p)
The default is AlwaysUploadPattern. When set to anything other than
the default, the user must call markVertexDataDirty() after changing
- the vertex data.
+ the vertex data, in addition to calling QSGNode::markDirty() with
+ QSGNode::DirtyGeometry.
*/
void QSGGeometry::setVertexDataPattern(DataPattern p)
diff --git a/src/quick/scenegraph/coreapi/qsgmaterial.cpp b/src/quick/scenegraph/coreapi/qsgmaterial.cpp
index c0794d0d69..9346236db9 100644
--- a/src/quick/scenegraph/coreapi/qsgmaterial.cpp
+++ b/src/quick/scenegraph/coreapi/qsgmaterial.cpp
@@ -556,6 +556,7 @@ static void qt_print_material_count()
QSGMaterial::QSGMaterial()
: m_flags(0)
+ , m_reserved(0)
{
#ifndef QT_NO_DEBUG
if (qsg_leak_check) {
diff --git a/src/quick/scenegraph/coreapi/qsgmaterial.h b/src/quick/scenegraph/coreapi/qsgmaterial.h
index ee8889deac..20ab21ad28 100644
--- a/src/quick/scenegraph/coreapi/qsgmaterial.h
+++ b/src/quick/scenegraph/coreapi/qsgmaterial.h
@@ -133,6 +133,7 @@ public:
void setFlag(Flags flags, bool on = true);
private:
+ friend class QSGContext;
Flags m_flags;
void *m_reserved;
Q_DISABLE_COPY(QSGMaterial)
diff --git a/src/quick/scenegraph/coreapi/qsgnode.cpp b/src/quick/scenegraph/coreapi/qsgnode.cpp
index 6a22e0e7f9..25f8f342c9 100644
--- a/src/quick/scenegraph/coreapi/qsgnode.cpp
+++ b/src/quick/scenegraph/coreapi/qsgnode.cpp
@@ -40,6 +40,7 @@
****************************************************************************/
#include "qsgnode.h"
+#include "qsgnode_p.h"
#include "qsgrenderer_p.h"
#include "qsgnodeupdater_p.h"
#include "qsgmaterial.h"
@@ -128,12 +129,12 @@ static void qt_print_node_count()
before rendering starts.
\value OwnsGeometry Only valid for QSGGeometryNode and QSGClipNode.
The node has ownership over the QSGGeometry instance and will
- delete it when the node is destroyed.
+ delete it when the node is destroyed or a geometry is assigned.
\value OwnsMaterial Only valid for QSGGeometryNode. The node has ownership
- over the material and will delete it when the node is destroyed.
+ over the material and will delete it when the node is destroyed or a material is assigned.
\value OwnsOpaqueMaterial Only valid for QSGGeometryNode. The node has
ownership over the opaque material and will delete it when the node is
- destroyed.
+ destroyed or a material is assigned.
*/
/*!
@@ -267,6 +268,26 @@ QSGNode::QSGNode(NodeType type)
}
/*!
+ * Constructs a new node with the given node type.
+ *
+ * \internal
+ */
+QSGNode::QSGNode(QSGNodePrivate &dd, NodeType type)
+ : m_parent(0)
+ , m_type(type)
+ , m_firstChild(0)
+ , m_lastChild(0)
+ , m_nextSibling(0)
+ , m_previousSibling(0)
+ , m_subtreeRenderableCount(type == GeometryNodeType || type == RenderNodeType ? 1 : 0)
+ , m_nodeFlags(OwnedByParent)
+ , m_dirtyState(0)
+ , d_ptr(&dd)
+{
+ init();
+}
+
+/*!
* \internal
*/
void QSGNode::init()
@@ -678,6 +699,18 @@ QSGBasicGeometryNode::QSGBasicGeometryNode(NodeType type)
/*!
+ \internal
+ */
+QSGBasicGeometryNode::QSGBasicGeometryNode(QSGBasicGeometryNodePrivate &dd, NodeType type)
+ : QSGNode(dd, type)
+ , m_geometry(0)
+ , m_matrix(0)
+ , m_clip_list(0)
+{
+}
+
+
+/*!
Deletes this QSGBasicGeometryNode.
If the node has the flag QSGNode::OwnsGeometry set, it will also delete the
@@ -808,6 +841,19 @@ QSGGeometryNode::QSGGeometryNode()
/*!
+ \internal
+ */
+QSGGeometryNode::QSGGeometryNode(QSGGeometryNodePrivate &dd)
+ : QSGBasicGeometryNode(dd, GeometryNodeType)
+ , m_render_order(0)
+ , m_material(0)
+ , m_opaque_material(0)
+ , m_opacity(1)
+{
+}
+
+
+/*!
Deletes this geometry node.
The flags QSGNode::OwnsMaterial, QSGNode::OwnsOpaqueMaterial and
diff --git a/src/quick/scenegraph/coreapi/qsgnode.h b/src/quick/scenegraph/coreapi/qsgnode.h
index 3fa2f7fc04..d83e6bcc81 100644
--- a/src/quick/scenegraph/coreapi/qsgnode.h
+++ b/src/quick/scenegraph/coreapi/qsgnode.h
@@ -58,6 +58,9 @@ class QSGRootNode;
class QSGGeometryNode;
class QSGTransformNode;
class QSGClipNode;
+class QSGNodePrivate;
+class QSGBasicGeometryNodePrivate;
+class QSGGeometryNodePrivate;
class Q_QUICK_EXPORT QSGNode
{
@@ -149,6 +152,7 @@ public:
protected:
QSGNode(NodeType type);
+ QSGNode(QSGNodePrivate &dd, NodeType type);
private:
friend class QSGRootNode;
@@ -167,7 +171,8 @@ private:
Flags m_nodeFlags;
DirtyState m_dirtyState;
- void *m_reserved;
+protected:
+ QScopedPointer<QSGNodePrivate> d_ptr;
};
class Q_QUICK_EXPORT QSGBasicGeometryNode : public QSGNode
@@ -184,6 +189,7 @@ public:
protected:
QSGBasicGeometryNode(NodeType type);
+ QSGBasicGeometryNode(QSGBasicGeometryNodePrivate &dd, NodeType type);
private:
friend class QSGNodeUpdater;
@@ -218,6 +224,9 @@ public:
void setInheritedOpacity(qreal opacity);
qreal inheritedOpacity() const { return m_opacity; }
+protected:
+ QSGGeometryNode(QSGGeometryNodePrivate &dd);
+
private:
friend class QSGNodeUpdater;
diff --git a/src/quick/scenegraph/coreapi/qsgnode_p.h b/src/quick/scenegraph/coreapi/qsgnode_p.h
new file mode 100644
index 0000000000..b0d8088af2
--- /dev/null
+++ b/src/quick/scenegraph/coreapi/qsgnode_p.h
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB)
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGNODE_P_H
+#define QSGNODE_P_H
+
+#include <qglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+class QSGNodePrivate
+{
+public:
+ QSGNodePrivate() {}
+ virtual ~QSGNodePrivate() {}
+};
+
+
+class QSGBasicGeometryNodePrivate : public QSGNodePrivate
+{
+public:
+ QSGBasicGeometryNodePrivate()
+ : QSGNodePrivate()
+ {}
+};
+
+
+class QSGGeometryNodePrivate: public QSGBasicGeometryNodePrivate
+{
+public:
+ QSGGeometryNodePrivate()
+ : QSGBasicGeometryNodePrivate()
+ {}
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGNODE_P_H
diff --git a/src/quick/scenegraph/coreapi/qsgrenderer.cpp b/src/quick/scenegraph/coreapi/qsgrenderer.cpp
index b46d45be57..805cfaad0d 100644
--- a/src/quick/scenegraph/coreapi/qsgrenderer.cpp
+++ b/src/quick/scenegraph/coreapi/qsgrenderer.cpp
@@ -53,6 +53,8 @@
#include <qdatetime.h>
+#include <private/qqmlprofilerservice_p.h>
+
QT_BEGIN_NAMESPACE
//#define RENDERER_DEBUG
@@ -62,9 +64,9 @@ QT_BEGIN_NAMESPACE
#ifndef QSG_NO_RENDER_TIMING
static bool qsg_render_timing = !qgetenv("QSG_RENDER_TIMING").isEmpty();
-static QTime frameTimer;
-static int preprocessTime;
-static int updatePassTime;
+static QElapsedTimer frameTimer;
+static qint64 preprocessTime;
+static qint64 updatePassTime;
#endif
void QSGBindable::clear(QSGRenderer::ClearMode mode) const
@@ -238,10 +240,11 @@ void QSGRenderer::renderScene(const QSGBindable &bindable)
#ifndef QSG_NO_RENDER_TIMING
- if (qsg_render_timing)
+ bool profileFrames = qsg_render_timing || QQmlProfilerService::enabled;
+ if (profileFrames)
frameTimer.start();
- int bindTime = 0;
- int renderTime = 0;
+ qint64 bindTime = 0;
+ qint64 renderTime = 0;
#endif
m_bindable = &bindable;
@@ -249,8 +252,8 @@ void QSGRenderer::renderScene(const QSGBindable &bindable)
bindable.bind();
#ifndef QSG_NO_RENDER_TIMING
- if (qsg_render_timing)
- bindTime = frameTimer.elapsed();
+ if (profileFrames)
+ bindTime = frameTimer.nsecsElapsed();
#endif
#ifndef QT_NO_DEBUG
@@ -270,8 +273,8 @@ void QSGRenderer::renderScene(const QSGBindable &bindable)
render();
#ifndef QSG_NO_RENDER_TIMING
- if (qsg_render_timing)
- renderTime = frameTimer.elapsed();
+ if (profileFrames)
+ renderTime = frameTimer.nsecsElapsed();
#endif
glDisable(GL_SCISSOR_TEST);
@@ -292,12 +295,22 @@ void QSGRenderer::renderScene(const QSGBindable &bindable)
#ifndef QSG_NO_RENDER_TIMING
if (qsg_render_timing) {
printf(" - Breakdown of render time: preprocess=%d, updates=%d, binding=%d, render=%d, total=%d\n",
- preprocessTime,
- updatePassTime - preprocessTime,
- bindTime - updatePassTime,
- renderTime - bindTime,
- renderTime);
+ int(preprocessTime / 1000000),
+ int((updatePassTime - preprocessTime) / 1000000),
+ int((bindTime - updatePassTime) / 1000000),
+ int((renderTime - bindTime) / 1000000),
+ int(renderTime / 1000000));
+ }
+
+ if (QQmlProfilerService::enabled) {
+ QQmlProfilerService::sceneGraphFrame(
+ QQmlProfilerService::SceneGraphRendererFrame,
+ preprocessTime,
+ updatePassTime - preprocessTime,
+ bindTime - updatePassTime,
+ renderTime - bindTime);
}
+
#endif
}
@@ -380,16 +393,17 @@ void QSGRenderer::preprocess()
}
#ifndef QSG_NO_RENDER_TIMING
- if (qsg_render_timing)
- preprocessTime = frameTimer.elapsed();
+ bool profileFrames = qsg_render_timing || QQmlProfilerService::enabled;
+ if (profileFrames)
+ preprocessTime = frameTimer.nsecsElapsed();
#endif
nodeUpdater()->setToplevelOpacity(context()->renderAlpha());
nodeUpdater()->updateStates(m_root_node);
#ifndef QSG_NO_RENDER_TIMING
- if (qsg_render_timing)
- updatePassTime = frameTimer.elapsed();
+ if (profileFrames)
+ updatePassTime = frameTimer.nsecsElapsed();
#endif
}
diff --git a/src/quick/scenegraph/qsgadaptationlayer.cpp b/src/quick/scenegraph/qsgadaptationlayer.cpp
index 1d534e3563..3536975e94 100644
--- a/src/quick/scenegraph/qsgadaptationlayer.cpp
+++ b/src/quick/scenegraph/qsgadaptationlayer.cpp
@@ -48,6 +48,7 @@
#include <QtGui/qguiapplication.h>
#include <qdir.h>
+#include <private/qqmlprofilerservice_p.h>
#include <QElapsedTimer>
QT_BEGIN_NAMESPACE
@@ -162,7 +163,8 @@ void QSGDistanceFieldGlyphCache::update()
return;
#ifndef QSG_NO_RENDER_TIMING
- if (qsg_render_timing)
+ bool profileFrames = qsg_render_timing || QQmlProfilerService::enabled;
+ if (profileFrames)
qsg_render_timer.start();
#endif
@@ -176,10 +178,10 @@ void QSGDistanceFieldGlyphCache::update()
}
#ifndef QSG_NO_RENDER_TIMING
- int renderTime = 0;
+ qint64 renderTime = 0;
int count = m_pendingGlyphs.size();
- if (qsg_render_timing)
- renderTime = qsg_render_timer.elapsed();
+ if (profileFrames)
+ renderTime = qsg_render_timer.nsecsElapsed();
#endif
m_pendingGlyphs.reset();
@@ -190,11 +192,18 @@ void QSGDistanceFieldGlyphCache::update()
if (qsg_render_timing) {
printf(" - glyphs: count=%d, render=%d, store=%d, total=%d\n",
count,
- renderTime,
- (int) qsg_render_timer.elapsed() - renderTime,
+ int(renderTime/1000000),
+ (int) qsg_render_timer.elapsed() - int(renderTime/1000000),
(int) qsg_render_timer.elapsed());
}
+ if (QQmlProfilerService::enabled) {
+ QQmlProfilerService::sceneGraphFrame(
+ QQmlProfilerService::SceneGraphAdaptationLayerFrame,
+ count,
+ renderTime,
+ qsg_render_timer.nsecsElapsed() - renderTime);
+ }
#endif
}
diff --git a/src/quick/scenegraph/qsgcontext.cpp b/src/quick/scenegraph/qsgcontext.cpp
index 8d36fce481..866d678412 100644
--- a/src/quick/scenegraph/qsgcontext.cpp
+++ b/src/quick/scenegraph/qsgcontext.cpp
@@ -47,13 +47,16 @@
#include <QtQuick/private/qsgdefaultimagenode_p.h>
#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/QSGFlatColorMaterial>
#include <QtQuick/private/qsgtexture_p.h>
#include <QtQuick/private/qquickpixmapcache_p.h>
#include <QGuiApplication>
#include <QOpenGLContext>
+#include <QQuickWindow>
#include <QtGui/qopenglframebufferobject.h>
#include <private/qqmlglobal_p.h>
@@ -67,6 +70,8 @@
#include <private/qobject_p.h>
#include <qmutex.h>
+#include <private/qqmlprofilerservice_p.h>
+
DEFINE_BOOL_CONFIG_OPTION(qmlFlashMode, QML_FLASH_MODE)
DEFINE_BOOL_CONFIG_OPTION(qmlTranslucentMode, QML_TRANSLUCENT_MODE)
DEFINE_BOOL_CONFIG_OPTION(qmlDisableDistanceField, QML_DISABLE_DISTANCEFIELD)
@@ -157,15 +162,13 @@ QSGContext::QSGContext(QObject *parent) :
QObject(*(new QSGContextPrivate), parent)
{
Q_D(QSGContext);
- static bool doSubpixel = qApp->arguments().contains(QLatin1String("--text-subpixel-antialiasing"));
- static bool doLowQualSubpixel = qApp->arguments().contains(QLatin1String("--text-subpixel-antialiasing-lowq"));
- static bool doGray = qApp->arguments().contains(QLatin1String("--text-gray-antialiasing"));
- if (doSubpixel)
+ QByteArray mode = qgetenv("QSG_DISTANCEFIELD_ANTIALIASING");
+ if (mode == "subpixel")
d->distanceFieldAntialiasing = QSGGlyphNode::HighQualitySubPixelAntialiasing;
- else if (doLowQualSubpixel)
+ else if (mode == "subpixel-lowq")
d->distanceFieldAntialiasing = QSGGlyphNode::LowQualitySubPixelAntialiasing;
- else if (doGray)
- d->distanceFieldAntialiasing = QSGGlyphNode::GrayAntialiasing;
+ else if (mode == "gray")
+ d->distanceFieldAntialiasing = QSGGlyphNode::GrayAntialiasing;
}
@@ -260,9 +263,35 @@ void QSGContext::initialize(QOpenGLContext *context)
Q_ASSERT(!d->gl);
d->gl = context;
+ precompileMaterials();
+
emit initialized();
}
+#define QSG_PRECOMPILE_MATERIAL(name) { name m; prepareMaterial(&m); }
+
+/*
+ * Some glsl compilers take their time compiling materials, and
+ * the way the scene graph is being processed, these materials
+ * get compiled when they are first taken into use. This can
+ * easily lead to skipped frames. By precompiling the most
+ * common materials, we potentially add a few milliseconds to the
+ * start up, and reduce the chance of avoiding skipped frames
+ * later on.
+ */
+void QSGContext::precompileMaterials()
+{
+ if (qEnvironmentVariableIsEmpty("QSG_NO_MATERIAL_PRELOADING")) {
+ QSG_PRECOMPILE_MATERIAL(QSGVertexColorMaterial);
+ QSG_PRECOMPILE_MATERIAL(QSGFlatColorMaterial);
+ QSG_PRECOMPILE_MATERIAL(QSGOpaqueTextureMaterial);
+ QSG_PRECOMPILE_MATERIAL(QSGTextureMaterial);
+ QSG_PRECOMPILE_MATERIAL(QSGSmoothTextureMaterial);
+ QSG_PRECOMPILE_MATERIAL(QSGSmoothColorMaterial);
+ QSG_PRECOMPILE_MATERIAL(QSGDistanceFieldTextMaterial);
+ }
+}
+
/*!
Returns if the scene graph context is ready or not, meaning that it has a valid
@@ -354,7 +383,11 @@ QSGDistanceFieldGlyphCache *QSGContext::distanceFieldGlyphCache(const QRawFont &
*/
QSGGlyphNode *QSGContext::createNativeGlyphNode()
{
+#if defined(QT_OPENGL_ES) && !defined(QT_OPENGL_ES_2_ANGLE)
+ return createGlyphNode();
+#else
return new QSGDefaultGlyphNode;
+#endif
}
/*!
@@ -392,6 +425,8 @@ QSurfaceFormat QSGContext::defaultSurfaceFormat() const
QSurfaceFormat format;
format.setDepthBufferSize(24);
format.setStencilBufferSize(8);
+ if (QQuickWindow::hasDefaultAlphaBuffer())
+ format.setAlphaBufferSize(8);
format.setSwapBehavior(QSurfaceFormat::DoubleBuffer);
return format;
}
@@ -472,17 +507,24 @@ QSGDepthStencilBufferManager *QSGContext::depthStencilBufferManager()
QSGMaterialShader *QSGContext::prepareMaterial(QSGMaterial *material)
{
Q_D(QSGContext);
+
+ if (material->m_reserved)
+ return reinterpret_cast<QSGMaterialShader *>(material->m_reserved);
+
QSGMaterialType *type = material->type();
QSGMaterialShader *shader = d->materials.value(type);
- if (shader)
+ if (shader) {
+ material->m_reserved = shader;
return shader;
+ }
#ifndef QSG_NO_RENDER_TIMING
- if (qsg_render_timing)
+ if (qsg_render_timing || QQmlProfilerService::enabled)
qsg_renderer_timer.start();
#endif
shader = material->createShader();
+ material->m_reserved = shader;
shader->compile();
shader->initialize();
d->materials[type] = shader;
@@ -490,6 +532,12 @@ QSGMaterialShader *QSGContext::prepareMaterial(QSGMaterial *material)
#ifndef QSG_NO_RENDER_TIMING
if (qsg_render_timing)
printf(" - compiling material: %dms\n", (int) qsg_renderer_timer.elapsed());
+
+ if (QQmlProfilerService::enabled) {
+ QQmlProfilerService::sceneGraphFrame(
+ QQmlProfilerService::SceneGraphContextFrame,
+ qsg_renderer_timer.nsecsElapsed());
+ }
#endif
return shader;
diff --git a/src/quick/scenegraph/qsgcontext_p.h b/src/quick/scenegraph/qsgcontext_p.h
index b069c53dd3..bbc42674c6 100644
--- a/src/quick/scenegraph/qsgcontext_p.h
+++ b/src/quick/scenegraph/qsgcontext_p.h
@@ -90,6 +90,7 @@ public:
bool isReady() const;
+ virtual void precompileMaterials();
QSGMaterialShader *prepareMaterial(QSGMaterial *material);
virtual void renderNextFrame(QSGRenderer *renderer, GLuint fboId);
diff --git a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp
index 419062d025..f5a461f19e 100644
--- a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp
+++ b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp
@@ -95,7 +95,8 @@ const char *QSGTextMaskMaterialData::fragmentShader() const {
"uniform sampler2D texture; \n"
"uniform lowp vec4 color; \n"
"void main() { \n"
- " gl_FragColor = vec4(texture2D(texture, sampleCoord).rgb * color.a, 1.0); \n"
+ " lowp vec4 glyph = texture2D(texture, sampleCoord); \n"
+ " gl_FragColor = vec4(glyph.rgb * color.a, glyph.a); \n"
"}";
}
@@ -162,7 +163,7 @@ void QSGTextMaskMaterialData::updateState(const RenderState &state, QSGMaterial
state.context()->functions()->glBlendColor(c.redF(),
c.greenF(),
c.blueF(),
- 1.0f);
+ c.alphaF());
}
}
@@ -520,7 +521,7 @@ int QSGTextMaskMaterial::compare(const QSGMaterial *o) const
Q_ASSERT(o && type() == o->type());
const QSGTextMaskMaterial *other = static_cast<const QSGTextMaskMaterial *>(o);
if (m_glyphCache != other->m_glyphCache)
- return m_glyphCache - other->m_glyphCache;
+ return m_glyphCache.data() < other->m_glyphCache.data() ? -1 : 1;
QRgb c1 = m_color.rgba();
QRgb c2 = other->m_color.rgba();
return int(c2 < c1) - int(c1 < c2);
diff --git a/src/quick/scenegraph/qsgdefaultimagenode.cpp b/src/quick/scenegraph/qsgdefaultimagenode.cpp
index cadd18e833..aed69913fa 100644
--- a/src/quick/scenegraph/qsgdefaultimagenode.cpp
+++ b/src/quick/scenegraph/qsgdefaultimagenode.cpp
@@ -87,24 +87,24 @@ protected:
};
-SmoothTextureMaterial::SmoothTextureMaterial()
+QSGSmoothTextureMaterial::QSGSmoothTextureMaterial()
{
setFlag(RequiresFullMatrixExceptTranslate, true);
setFlag(Blending, true);
}
-void SmoothTextureMaterial::setTexture(QSGTexture *texture)
+void QSGSmoothTextureMaterial::setTexture(QSGTexture *texture)
{
m_texture = texture;
}
-QSGMaterialType *SmoothTextureMaterial::type() const
+QSGMaterialType *QSGSmoothTextureMaterial::type() const
{
static QSGMaterialType type;
return &type;
}
-QSGMaterialShader *SmoothTextureMaterial::createShader() const
+QSGMaterialShader *QSGSmoothTextureMaterial::createShader() const
{
return new SmoothTextureMaterialShader;
}
diff --git a/src/quick/scenegraph/qsgdefaultimagenode_p.h b/src/quick/scenegraph/qsgdefaultimagenode_p.h
index 7d299faee3..723943fd71 100644
--- a/src/quick/scenegraph/qsgdefaultimagenode_p.h
+++ b/src/quick/scenegraph/qsgdefaultimagenode_p.h
@@ -48,10 +48,10 @@
QT_BEGIN_NAMESPACE
-class SmoothTextureMaterial : public QSGTextureMaterial
+class Q_QUICK_PRIVATE_EXPORT QSGSmoothTextureMaterial : public QSGTextureMaterial
{
public:
- SmoothTextureMaterial();
+ QSGSmoothTextureMaterial();
void setTexture(QSGTexture *texture);
@@ -60,7 +60,7 @@ protected:
virtual QSGMaterialShader *createShader() const;
};
-class QSGDefaultImageNode : public QSGImageNode
+class Q_QUICK_PRIVATE_EXPORT QSGDefaultImageNode : public QSGImageNode
{
public:
QSGDefaultImageNode();
@@ -90,7 +90,7 @@ private:
QSGOpaqueTextureMaterial m_material;
QSGTextureMaterial m_materialO;
- SmoothTextureMaterial m_smoothMaterial;
+ QSGSmoothTextureMaterial m_smoothMaterial;
uint m_antialiasing : 1;
uint m_mirror : 1;
diff --git a/src/quick/scenegraph/qsgdefaultrectanglenode.cpp b/src/quick/scenegraph/qsgdefaultrectanglenode.cpp
index f642ca8d16..76fbbb4209 100644
--- a/src/quick/scenegraph/qsgdefaultrectanglenode.cpp
+++ b/src/quick/scenegraph/qsgdefaultrectanglenode.cpp
@@ -211,24 +211,24 @@ const char *SmoothColorMaterialShader::fragmentShader() const
"}";
}
-SmoothColorMaterial::SmoothColorMaterial()
+QSGSmoothColorMaterial::QSGSmoothColorMaterial()
{
setFlag(RequiresFullMatrixExceptTranslate, true);
setFlag(Blending, true);
}
-int SmoothColorMaterial::compare(const QSGMaterial *) const
+int QSGSmoothColorMaterial::compare(const QSGMaterial *) const
{
return 0;
}
-QSGMaterialType *SmoothColorMaterial::type() const
+QSGMaterialType *QSGSmoothColorMaterial::type() const
{
static QSGMaterialType type;
return &type;
}
-QSGMaterialShader *SmoothColorMaterial::createShader() const
+QSGMaterialShader *QSGSmoothColorMaterial::createShader() const
{
return new SmoothColorMaterialShader;
}
diff --git a/src/quick/scenegraph/qsgdefaultrectanglenode_p.h b/src/quick/scenegraph/qsgdefaultrectanglenode_p.h
index 24bdbb3d34..1994e015e9 100644
--- a/src/quick/scenegraph/qsgdefaultrectanglenode_p.h
+++ b/src/quick/scenegraph/qsgdefaultrectanglenode_p.h
@@ -51,10 +51,10 @@ QT_BEGIN_NAMESPACE
class QSGContext;
-class SmoothColorMaterial : public QSGMaterial
+class Q_QUICK_PRIVATE_EXPORT QSGSmoothColorMaterial : public QSGMaterial
{
public:
- SmoothColorMaterial();
+ QSGSmoothColorMaterial();
int compare(const QSGMaterial *other) const;
@@ -63,7 +63,7 @@ protected:
virtual QSGMaterialShader *createShader() const;
};
-class QSGDefaultRectangleNode : public QSGRectangleNode
+class Q_QUICK_PRIVATE_EXPORT QSGDefaultRectangleNode : public QSGRectangleNode
{
public:
QSGDefaultRectangleNode();
@@ -83,7 +83,7 @@ private:
void updateGradientTexture();
QSGVertexColorMaterial m_material;
- SmoothColorMaterial m_smoothMaterial;
+ QSGSmoothColorMaterial m_smoothMaterial;
QRectF m_rect;
QGradientStops m_gradient_stops;
diff --git a/src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp b/src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp
index 86c3356d58..bdbce6165b 100644
--- a/src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp
+++ b/src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp
@@ -144,8 +144,7 @@ void QSGDistanceFieldTextMaterialShader::updateState(const RenderState &state, Q
if (oldMaterial == 0
|| material->color() != oldMaterial->color()
|| state.isOpacityDirty()) {
- QColor c = material->color();
- QVector4D color(c.redF(), c.greenF(), c.blueF(), c.alphaF());
+ QVector4D color = material->color();
color *= state.opacity();
program()->setUniformValue(m_color_id, color);
}
@@ -206,10 +205,10 @@ QSGMaterialType *QSGDistanceFieldTextMaterial::type() const
void QSGDistanceFieldTextMaterial::setColor(const QColor &color)
{
- m_color = QColor::fromRgbF(color.redF() * color.alphaF(),
- color.greenF() * color.alphaF(),
- color.blueF() * color.alphaF(),
- color.alphaF());
+ m_color = QVector4D(color.redF() * color.alphaF(),
+ color.greenF() * color.alphaF(),
+ color.blueF() * color.alphaF(),
+ color.alphaF());
}
QSGMaterialShader *QSGDistanceFieldTextMaterial::createShader() const
@@ -239,10 +238,8 @@ int QSGDistanceFieldTextMaterial::compare(const QSGMaterial *o) const
if (m_fontScale != other->m_fontScale) {
return int(other->m_fontScale < m_fontScale) - int(m_fontScale < other->m_fontScale);
}
- QRgb c1 = m_color.rgba();
- QRgb c2 = other->m_color.rgba();
- if (c1 != c2)
- return int(c2 < c1) - int(c1 < c2);
+ if (m_color != other->m_color)
+ return &m_color < &other->m_color ? -1 : 1;
int t0 = m_texture ? m_texture->textureId : -1;
int t1 = other->m_texture ? other->m_texture->textureId : -1;
return t0 - t1;
@@ -284,8 +281,7 @@ void DistanceFieldStyledTextMaterialShader::updateState(const RenderState &state
if (oldMaterial == 0
|| material->styleColor() != oldMaterial->styleColor()
|| (state.isOpacityDirty())) {
- QColor c = material->styleColor();
- QVector4D color(c.redF(), c.greenF(), c.blueF(), c.alphaF());
+ QVector4D color = material->styleColor();
color *= state.opacity();
program()->setUniformValue(m_styleColor_id, color);
}
@@ -302,21 +298,18 @@ QSGDistanceFieldStyledTextMaterial::~QSGDistanceFieldStyledTextMaterial()
void QSGDistanceFieldStyledTextMaterial::setStyleColor(const QColor &color)
{
- m_styleColor = QColor::fromRgbF(color.redF() * color.alphaF(),
- color.greenF() * color.alphaF(),
- color.blueF() * color.alphaF(),
- color.alphaF());
+ m_styleColor = QVector4D(color.redF() * color.alphaF(),
+ color.greenF() * color.alphaF(),
+ color.blueF() * color.alphaF(),
+ color.alphaF());
}
int QSGDistanceFieldStyledTextMaterial::compare(const QSGMaterial *o) const
{
Q_ASSERT(o && type() == o->type());
const QSGDistanceFieldStyledTextMaterial *other = static_cast<const QSGDistanceFieldStyledTextMaterial *>(o);
- if (m_styleColor != other->m_styleColor) {
- QRgb c1 = m_styleColor.rgba();
- QRgb c2 = other->m_styleColor.rgba();
- return int(c2 < c1) - int(c1 < c2);
- }
+ if (m_styleColor != other->m_color)
+ return &m_styleColor < &other->m_styleColor ? -1 : 1;
return QSGDistanceFieldTextMaterial::compare(o);
}
@@ -657,8 +650,8 @@ void QSGHiQSubPixelDistanceFieldTextMaterialShader::updateState(const RenderStat
QSGDistanceFieldTextMaterial *oldMaterial = static_cast<QSGDistanceFieldTextMaterial *>(oldEffect);
if (oldMaterial == 0 || material->color() != oldMaterial->color()) {
- QColor c = material->color();
- state.context()->functions()->glBlendColor(c.redF(), c.greenF(), c.blueF(), 1.0f);
+ QVector4D c = material->color();
+ state.context()->functions()->glBlendColor(c.x(), c.y(), c.z(), 1.0f);
}
if (oldMaterial == 0 || material->fontScale() != oldMaterial->fontScale())
diff --git a/src/quick/scenegraph/qsgdistancefieldglyphnode_p_p.h b/src/quick/scenegraph/qsgdistancefieldglyphnode_p_p.h
index 7fea8f65dc..54d4146ddb 100644
--- a/src/quick/scenegraph/qsgdistancefieldglyphnode_p_p.h
+++ b/src/quick/scenegraph/qsgdistancefieldglyphnode_p_p.h
@@ -59,7 +59,7 @@ public:
virtual int compare(const QSGMaterial *other) const;
virtual void setColor(const QColor &color);
- const QColor &color() const { return m_color; }
+ const QVector4D &color() const { return m_color; }
void setGlyphCache(QSGDistanceFieldGlyphCache *a) { m_glyph_cache = a; }
QSGDistanceFieldGlyphCache *glyphCache() const { return m_glyph_cache; }
@@ -76,7 +76,7 @@ public:
protected:
QSize m_size;
- QColor m_color;
+ QVector4D m_color;
QSGDistanceFieldGlyphCache *m_glyph_cache;
const QSGDistanceFieldGlyphCache::Texture *m_texture;
qreal m_fontScale;
@@ -93,10 +93,10 @@ public:
virtual int compare(const QSGMaterial *other) const;
void setStyleColor(const QColor &color);
- const QColor &styleColor() const { return m_styleColor; }
+ const QVector4D &styleColor() const { return m_styleColor; }
protected:
- QColor m_styleColor;
+ QVector4D m_styleColor;
};
class Q_QUICK_PRIVATE_EXPORT QSGDistanceFieldOutlineTextMaterial : public QSGDistanceFieldStyledTextMaterial
@@ -130,7 +130,7 @@ class Q_QUICK_PRIVATE_EXPORT QSGHiQSubPixelDistanceFieldTextMaterial : public QS
public:
virtual QSGMaterialType *type() const;
virtual QSGMaterialShader *createShader() const;
- void setColor(const QColor &color) { m_color = color; }
+ void setColor(const QColor &color) { m_color = QVector4D(color.redF(), color.greenF(), color.blueF(), color.alphaF()); }
};
class Q_QUICK_PRIVATE_EXPORT QSGLoQSubPixelDistanceFieldTextMaterial : public QSGDistanceFieldTextMaterial
@@ -138,7 +138,7 @@ class Q_QUICK_PRIVATE_EXPORT QSGLoQSubPixelDistanceFieldTextMaterial : public QS
public:
virtual QSGMaterialType *type() const;
virtual QSGMaterialShader *createShader() const;
- void setColor(const QColor &color) { m_color = color; }
+ void setColor(const QColor &color) { m_color = QVector4D(color.redF(), color.greenF(), color.blueF(), color.alphaF()); }
};
QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/qsgrenderloop.cpp b/src/quick/scenegraph/qsgrenderloop.cpp
index 33a99d1506..e099d94a53 100644
--- a/src/quick/scenegraph/qsgrenderloop.cpp
+++ b/src/quick/scenegraph/qsgrenderloop.cpp
@@ -41,6 +41,7 @@
#include "qsgrenderloop_p.h"
#include "qsgthreadedrenderloop_p.h"
+#include "qsgwindowsrenderloop_p.h"
#include <QtCore/QCoreApplication>
#include <QtCore/QTime>
@@ -55,6 +56,7 @@
#include <QtQuick/QQuickWindow>
#include <QtQuick/private/qquickwindow_p.h>
#include <QtQuick/private/qsgcontext_p.h>
+#include <private/qqmlprofilerservice_p.h>
QT_BEGIN_NAMESPACE
@@ -80,7 +82,7 @@ QSGRenderLoop::~QSGRenderLoop()
{
}
-class QSGGuiThreadRenderLoop : public QObject, public QSGRenderLoop
+class QSGGuiThreadRenderLoop : public QSGRenderLoop
{
Q_OBJECT
public:
@@ -130,15 +132,6 @@ QSGRenderLoop *QSGRenderLoop::instance()
s_instance = QSGContext::createWindowManager();
bool bufferQueuing = QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::BufferQueueingOpenGL);
-#ifdef Q_OS_WIN
- bool fancy = false; // QTBUG-28037
-#else
- bool fancy = QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::ThreadedOpenGL);
-#endif
- if (qmlNoThreadedRenderer())
- fancy = false;
- else if (qmlForceThreadedRenderer())
- fancy = true;
// Enable fixed animation steps...
QByteArray fixed = qgetenv("QML_FIXED_ANIMATION_STEP");
@@ -151,9 +144,45 @@ QSGRenderLoop *QSGRenderLoop::instance()
QUnifiedTimer::instance(true)->setConsistentTiming(true);
if (!s_instance) {
- s_instance = fancy
- ? (QSGRenderLoop*) new QSGThreadedRenderLoop
- : (QSGRenderLoop*) new QSGGuiThreadRenderLoop;
+
+ enum RenderLoopType {
+ BasicRenderLoop,
+ ThreadedRenderLoop,
+ WindowsRenderLoop
+ };
+
+ RenderLoopType loopType = BasicRenderLoop;
+
+#ifdef Q_OS_WIN
+ loopType = WindowsRenderLoop;
+#else
+ if (QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::ThreadedOpenGL))
+ loopType = ThreadedRenderLoop;
+#endif
+ if (qmlNoThreadedRenderer())
+ loopType = BasicRenderLoop;
+ 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;
+
+ switch (loopType) {
+ case ThreadedRenderLoop:
+ s_instance = new QSGThreadedRenderLoop();
+ break;
+ case WindowsRenderLoop:
+ s_instance = new QSGWindowsRenderLoop();
+ break;
+ default:
+ s_instance = new QSGGuiThreadRenderLoop();
+ break;
+ }
}
}
return s_instance;
@@ -215,49 +244,25 @@ void QSGGuiThreadRenderLoop::windowDestroyed(QQuickWindow *window)
void QSGGuiThreadRenderLoop::renderWindow(QQuickWindow *window)
{
- bool renderWithoutShowing = QQuickWindowPrivate::get(window)->renderWithoutShowing;
- if ((!window->isExposed() && !renderWithoutShowing) || !m_windows.contains(window))
+ if (!QQuickWindowPrivate::get(window)->isRenderable() || !m_windows.contains(window))
return;
WindowData &data = const_cast<WindowData &>(m_windows[window]);
- QQuickWindow *masterWindow = 0;
- if (!window->isVisible() && !renderWithoutShowing) {
- // Find a "proper surface" to bind...
- for (QHash<QQuickWindow *, WindowData>::const_iterator it = m_windows.constBegin();
- it != m_windows.constEnd() && !masterWindow; ++it) {
- if (it.key()->isVisible())
- masterWindow = it.key();
- }
- } else {
- masterWindow = window;
- }
-
- if (!masterWindow)
- return;
-
- if (!QQuickWindowPrivate::get(masterWindow)->isRenderable()) {
- qWarning().nospace()
- << "Unable to find a renderable master window "
- << masterWindow << "when trying to render"
- << window << " (" << window->geometry() << ").";
- return;
- }
-
bool current = false;
if (!gl) {
gl = new QOpenGLContext();
- gl->setFormat(masterWindow->requestedFormat());
+ gl->setFormat(window->requestedFormat());
if (!gl->create()) {
delete gl;
gl = 0;
}
- current = gl->makeCurrent(masterWindow);
+ current = gl->makeCurrent(window);
if (current)
sg->initialize(gl);
} else {
- current = gl->makeCurrent(masterWindow);
+ current = gl->makeCurrent(window);
}
bool alsoSwap = data.updatePending;
@@ -269,20 +274,21 @@ void QSGGuiThreadRenderLoop::renderWindow(QQuickWindow *window)
QQuickWindowPrivate *cd = QQuickWindowPrivate::get(window);
cd->polishItems();
- int renderTime = 0, syncTime = 0;
- QTime renderTimer;
- if (qsg_render_timing())
+ qint64 renderTime = 0, syncTime = 0;
+ QElapsedTimer renderTimer;
+ bool profileFrames = qsg_render_timing() || QQmlProfilerService::enabled;
+ if (profileFrames)
renderTimer.start();
cd->syncSceneGraph();
- if (qsg_render_timing())
- syncTime = renderTimer.elapsed();
+ if (profileFrames)
+ syncTime = renderTimer.nsecsElapsed();
cd->renderSceneGraph(window->size());
- if (qsg_render_timing())
- renderTime = renderTimer.elapsed() - syncTime;
+ if (profileFrames)
+ renderTime = renderTimer.nsecsElapsed() - syncTime;
if (data.grabOnly) {
grabContent = qt_gl_read_framebuffer(window->size(), false, false);
@@ -294,17 +300,29 @@ void QSGGuiThreadRenderLoop::renderWindow(QQuickWindow *window)
cd->fireFrameSwapped();
}
+ qint64 swapTime = 0;
+ if (profileFrames) {
+ swapTime = renderTimer.nsecsElapsed() - renderTime - syncTime;
+ }
+
if (qsg_render_timing()) {
static QTime lastFrameTime = QTime::currentTime();
- const int swapTime = renderTimer.elapsed() - renderTime - syncTime;
- qDebug() << "- Breakdown of frame time; sync:" << syncTime
- << "ms render:" << renderTime << "ms swap:" << swapTime
- << "ms total:" << swapTime + renderTime + syncTime
+ qDebug() << "- Breakdown of frame time; sync:" << syncTime/1000000
+ << "ms render:" << renderTime/1000000 << "ms swap:" << swapTime/1000000
+ << "ms total:" << (swapTime + renderTime + syncTime)/1000000
<< "ms time since last frame:" << (lastFrameTime.msecsTo(QTime::currentTime()))
<< "ms";
lastFrameTime = QTime::currentTime();
}
+ if (QQmlProfilerService::enabled) {
+ QQmlProfilerService::sceneGraphFrame(
+ QQmlProfilerService::SceneGraphRenderLoopFrame,
+ syncTime,
+ renderTime,
+ swapTime);
+ }
+
// Might have been set during syncSceneGraph()
if (data.updatePending)
maybeUpdate(window);
diff --git a/src/quick/scenegraph/qsgrenderloop_p.h b/src/quick/scenegraph/qsgrenderloop_p.h
index b18e6f00ad..6ff9c4c5f9 100644
--- a/src/quick/scenegraph/qsgrenderloop_p.h
+++ b/src/quick/scenegraph/qsgrenderloop_p.h
@@ -51,8 +51,10 @@ class QQuickWindow;
class QSGContext;
class QAnimationDriver;
-class Q_QUICK_PRIVATE_EXPORT QSGRenderLoop
+class Q_QUICK_PRIVATE_EXPORT QSGRenderLoop : public QObject
{
+ Q_OBJECT
+
public:
virtual ~QSGRenderLoop();
@@ -77,6 +79,11 @@ public:
static QSGRenderLoop *instance();
static void setInstance(QSGRenderLoop *instance);
+ virtual bool interleaveIncubation() const { return false; }
+
+signals:
+ void timeToIncubate();
+
private:
static QSGRenderLoop *s_instance;
};
diff --git a/src/quick/scenegraph/qsgthreadedrenderloop.cpp b/src/quick/scenegraph/qsgthreadedrenderloop.cpp
index b01d816661..3ab7d2fb30 100644
--- a/src/quick/scenegraph/qsgthreadedrenderloop.cpp
+++ b/src/quick/scenegraph/qsgthreadedrenderloop.cpp
@@ -56,6 +56,8 @@
#include "qsgthreadedrenderloop_p.h"
+#include <private/qqmlprofilerservice_p.h>
+
/*
Overall design:
@@ -139,10 +141,10 @@ static inline int qsgrl_animation_interval() {
#ifndef QSG_NO_RENDER_TIMING
static bool qsg_render_timing = !qgetenv("QSG_RENDER_TIMING").isEmpty();
-static QTime threadTimer;
-static int syncTime;
-static int renderTime;
-static int sinceLastTime;
+static QElapsedTimer threadTimer;
+static qint64 syncTime;
+static qint64 renderTime;
+static qint64 sinceLastTime;
#endif
extern Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha);
@@ -329,9 +331,9 @@ public:
QEventLoop eventLoop;
- uint pendingUpdate : 2;
- uint sleeping : 1;
- uint syncResultedInChanges : 1;
+ uint pendingUpdate;
+ uint sleeping;
+ uint syncResultedInChanges;
volatile bool guiIsLocked;
volatile bool shouldExit;
@@ -516,7 +518,6 @@ void QSGRenderThread::sync()
mutex.lock();
Q_ASSERT_X(guiIsLocked, "QSGRenderThread::sync()", "sync triggered on bad terms as gui is not already locked...");
- pendingUpdate = 0;
for (int i=0; i<m_windows.size(); ++i) {
Window &w = const_cast<Window &>(m_windows.at(i));
@@ -547,8 +548,11 @@ void QSGRenderThread::sync()
void QSGRenderThread::syncAndRender()
{
#ifndef QSG_NO_RENDER_TIMING
- if (qsg_render_timing)
- sinceLastTime = threadTimer.restart();
+ bool profileFrames = qsg_render_timing || QQmlProfilerService::enabled;
+ if (profileFrames) {
+ sinceLastTime = threadTimer.nsecsElapsed();
+ threadTimer.start();
+ }
#endif
QElapsedTimer waitTimer;
waitTimer.start();
@@ -558,8 +562,10 @@ void QSGRenderThread::syncAndRender()
syncResultedInChanges = false;
bool repaintRequested = pendingUpdate & RepaintRequest;
+ bool syncRequested = pendingUpdate & SyncRequest;
+ pendingUpdate = 0;
- if (pendingUpdate & SyncRequest) {
+ if (syncRequested) {
RLDEBUG(" Render: - update pending, doing sync");
sync();
}
@@ -569,12 +575,13 @@ void QSGRenderThread::syncAndRender()
int waitTime = vsyncDelta - (int) waitTimer.elapsed();
if (waitTime > 0)
msleep(waitTime);
+ emit wm->timeToIncubate();
return;
}
#ifndef QSG_NO_RENDER_TIMING
- if (qsg_render_timing)
- syncTime = threadTimer.elapsed();
+ if (profileFrames)
+ syncTime = threadTimer.nsecsElapsed();
#endif
RLDEBUG(" Render: - rendering starting");
@@ -588,21 +595,30 @@ void QSGRenderThread::syncAndRender()
gl->makeCurrent(w.window);
d->renderSceneGraph(w.size);
#ifndef QSG_NO_RENDER_TIMING
- if (qsg_render_timing && i == 0)
- renderTime = threadTimer.elapsed();
+ if (profileFrames && i == 0)
+ renderTime = threadTimer.nsecsElapsed();
#endif
gl->swapBuffers(w.window);
d->fireFrameSwapped();
}
RLDEBUG(" Render: - rendering done");
+ emit wm->timeToIncubate();
#ifndef QSG_NO_RENDER_TIMING
if (qsg_render_timing)
qDebug("window Time: sinceLast=%d, sync=%d, first render=%d, after final swap=%d",
- sinceLastTime,
- syncTime,
- renderTime - syncTime,
- threadTimer.elapsed() - renderTime);
+ int(sinceLastTime/1000000),
+ int(syncTime/1000000),
+ int((renderTime - syncTime)/1000000),
+ int(threadTimer.elapsed() - renderTime/1000000));
+
+ if (QQmlProfilerService::enabled) {
+ QQmlProfilerService::sceneGraphFrame(
+ QQmlProfilerService::SceneGraphRenderLoopFrame,
+ syncTime,
+ renderTime - syncTime,
+ threadTimer.nsecsElapsed() - renderTime);
+ }
#endif
}
@@ -710,7 +726,7 @@ QSGContext *QSGThreadedRenderLoop::sceneGraphContext() const
return m_thread->sg;
}
-bool QSGThreadedRenderLoop::anyoneShowing()
+bool QSGThreadedRenderLoop::anyoneShowing() const
{
for (int i=0; i<m_windows.size(); ++i) {
QQuickWindow *c = m_windows.at(i).window;
@@ -720,6 +736,11 @@ bool QSGThreadedRenderLoop::anyoneShowing()
return false;
}
+bool QSGThreadedRenderLoop::interleaveIncubation() const
+{
+ return m_animation_driver->isRunning() && anyoneShowing();
+}
+
void QSGThreadedRenderLoop::animationStarted()
{
RLDEBUG("GUI: animationStarted()");
@@ -950,10 +971,11 @@ void QSGThreadedRenderLoop::polishAndSync()
#ifndef QSG_NO_RENDER_TIMING
QElapsedTimer timer;
- int polishTime = 0;
- int waitTime = 0;
- int syncTime;
- if (qsg_render_timing)
+ qint64 polishTime = 0;
+ qint64 waitTime = 0;
+ qint64 syncTime = 0;
+ bool profileFrames = qsg_render_timing || QQmlProfilerService::enabled;
+ if (profileFrames)
timer.start();
#endif
@@ -964,8 +986,8 @@ void QSGThreadedRenderLoop::polishAndSync()
d->polishItems();
}
#ifndef QSG_NO_RENDER_TIMING
- if (qsg_render_timing)
- polishTime = timer.elapsed();
+ if (profileFrames)
+ polishTime = timer.nsecsElapsed();
#endif
m_sync_triggered_update = false;
@@ -977,8 +999,8 @@ void QSGThreadedRenderLoop::polishAndSync()
RLDEBUG("GUI: - wait for sync...");
#ifndef QSG_NO_RENDER_TIMING
- if (qsg_render_timing)
- waitTime = timer.elapsed();
+ if (profileFrames)
+ waitTime = timer.nsecsElapsed();
#endif
m_thread->waitCondition.wait(&m_thread->mutex);
m_thread->guiIsLocked = false;
@@ -986,8 +1008,8 @@ void QSGThreadedRenderLoop::polishAndSync()
RLDEBUG("GUI: - unlocked after sync...");
#ifndef QSG_NO_RENDER_TIMING
- if (qsg_render_timing)
- syncTime = timer.elapsed();
+ if (profileFrames)
+ syncTime = timer.nsecsElapsed();
#endif
killTimer(m_update_timer);
@@ -997,7 +1019,6 @@ void QSGThreadedRenderLoop::polishAndSync()
RLDEBUG("GUI: - animations advancing");
m_animation_driver->advance();
RLDEBUG("GUI: - animations done");
-
// We need to trigger another sync to keep animations running...
maybePostPolishRequest();
} else if (m_sync_triggered_update) {
@@ -1006,7 +1027,20 @@ void QSGThreadedRenderLoop::polishAndSync()
#ifndef QSG_NO_RENDER_TIMING
if (qsg_render_timing)
- qDebug(" - polish=%d, wait=%d, sync=%d -- animations=%d", polishTime, waitTime - polishTime, syncTime - waitTime, int(timer.elapsed() - syncTime));
+ qDebug(" - polish=%d, wait=%d, sync=%d -- animations=%d",
+ int(polishTime/1000000),
+ int((waitTime - polishTime)/1000000),
+ int((syncTime - waitTime)/1000000),
+ int((timer.nsecsElapsed() - syncTime)/1000000));
+
+ if (QQmlProfilerService::enabled) {
+ QQmlProfilerService::sceneGraphFrame(
+ QQmlProfilerService::SceneGraphPolishAndSync,
+ polishTime,
+ waitTime - polishTime,
+ syncTime - waitTime,
+ timer.nsecsElapsed() - syncTime);
+ }
#endif
}
diff --git a/src/quick/scenegraph/qsgthreadedrenderloop_p.h b/src/quick/scenegraph/qsgthreadedrenderloop_p.h
index aab0e8726f..6ff5cabf43 100644
--- a/src/quick/scenegraph/qsgthreadedrenderloop_p.h
+++ b/src/quick/scenegraph/qsgthreadedrenderloop_p.h
@@ -52,7 +52,7 @@ QT_BEGIN_NAMESPACE
class QSGRenderThread;
-class QSGThreadedRenderLoop : public QObject, public QSGRenderLoop
+class QSGThreadedRenderLoop : public QSGRenderLoop
{
Q_OBJECT
public:
@@ -79,7 +79,7 @@ public:
bool event(QEvent *);
- void wakeup();
+ bool interleaveIncubation() const;
public slots:
void animationStarted();
@@ -91,7 +91,7 @@ private:
void releaseResources(QQuickWindow *window, bool inDestructor);
bool checkAndResetForceUpdate(QQuickWindow *window);
- bool anyoneShowing();
+ bool anyoneShowing() const;
void initialize();
void maybePostPolishRequest();
diff --git a/src/quick/scenegraph/qsgwindowsrenderloop.cpp b/src/quick/scenegraph/qsgwindowsrenderloop.cpp
new file mode 100644
index 0000000000..8e97f65ea5
--- /dev/null
+++ b/src/quick/scenegraph/qsgwindowsrenderloop.cpp
@@ -0,0 +1,469 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgwindowsrenderloop_p.h"
+
+#include <QtCore/QCoreApplication>
+
+#include <QtGui/QScreen>
+#include <QtGui/QGuiApplication>
+
+#include <QtQuick/private/qsgcontext_p.h>
+#include <QtQuick/private/qquickwindow_p.h>
+
+#include <QtQuick/QQuickWindow>
+
+#include <private/qqmlprofilerservice_p.h>
+
+QT_BEGIN_NAMESPACE
+
+extern Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha);
+
+// #define QSG_RENDER_LOOP_DEBUG
+
+#ifdef QSG_RENDER_LOOP_DEBUG
+static QElapsedTimer qsg_debug_timer;
+# define RLDEBUG(x) printf("(%6d) %s : %4d - %s\n", (int) qsg_debug_timer.elapsed(), __FILE__, __LINE__, x)
+#else
+# define RLDEBUG(x)
+#endif
+
+#ifndef QSG_NO_RENDER_TIMING
+static bool qsg_render_timing = !qgetenv("QSG_RENDER_TIMING").isEmpty();
+static QElapsedTimer qsg_render_timer;
+#define QSG_RENDER_TIMING_SAMPLE(sampleName) qint64 sampleName = 0; if (qsg_render_timing || QQmlProfilerService::enabled) sampleName = qsg_render_timer.nsecsElapsed()
+#else
+#define QSG_RENDER_TIMING_SAMPLE(sampleName)
+#endif
+
+
+QSGWindowsRenderLoop::QSGWindowsRenderLoop()
+ : m_gl(0)
+ , m_sg(QSGContext::createDefaultContext())
+ , m_updateTimer(0)
+ , m_animationTimer(0)
+{
+#ifdef QSG_RENDER_LOOP_DEBUG
+ qsg_debug_timer.start();
+#endif
+
+ m_animationDriver = m_sg->createAnimationDriver(m_sg);
+ m_animationDriver->install();
+
+ connect(m_animationDriver, SIGNAL(started()), this, SLOT(started()));
+ connect(m_animationDriver, SIGNAL(stopped()), this, SLOT(stopped()));
+
+ m_vsyncDelta = 1000 / QGuiApplication::primaryScreen()->refreshRate();
+ if (m_vsyncDelta <= 0)
+ m_vsyncDelta = 16;
+
+ RLDEBUG("Windows Render Loop created");
+
+#ifndef QSG_NO_RENDER_TIMIMG
+ qsg_render_timer.start();
+#endif
+}
+
+bool QSGWindowsRenderLoop::interleaveIncubation() const
+{
+ return m_animationDriver->isRunning() && anyoneShowing();
+}
+
+QSGWindowsRenderLoop::WindowData *QSGWindowsRenderLoop::windowData(QQuickWindow *window)
+{
+ for (int i=0; i<m_windows.size(); ++i) {
+ WindowData &wd = m_windows[i];
+ if (wd.window == window)
+ return &wd;
+ }
+ return 0;
+}
+
+void QSGWindowsRenderLoop::maybePostUpdateTimer()
+{
+ if (!m_updateTimer) {
+ RLDEBUG(" - posting event");
+ m_updateTimer = startTimer(m_vsyncDelta / 3);
+ }
+}
+
+/*
+ * If no windows are showing, start ticking animations using a timer,
+ * otherwise, start rendering
+ */
+void QSGWindowsRenderLoop::started()
+{
+ RLDEBUG("Animations started...");
+ if (!anyoneShowing()) {
+ if (m_animationTimer == 0) {
+ RLDEBUG(" - starting non-visual animation timer");
+ m_animationTimer = startTimer(m_vsyncDelta);
+ }
+ } else {
+ maybePostUpdateTimer();
+ }
+}
+
+void QSGWindowsRenderLoop::stopped()
+{
+ RLDEBUG("Animations stopped...");
+ if (m_animationTimer) {
+ RLDEBUG(" - stopping non-visual animation timer");
+ killTimer(m_animationTimer);
+ m_animationTimer = 0;
+ }
+}
+
+void QSGWindowsRenderLoop::show(QQuickWindow *window)
+{
+ RLDEBUG("show");
+ if (windowData(window) != 0)
+ return;
+
+ // This happens before the platform window is shown, but after
+ // it is created. Creating the GL context takes a lot of time
+ // (hundreds of milliseconds) and will prevent us from rendering
+ // the first frame in time for the initial show on screen.
+ // By preparing the GL context here, it is feasible (if the app
+ // is quick enough) to have a perfect first frame.
+ if (!m_gl) {
+ QSG_RENDER_TIMING_SAMPLE(time_start);
+
+ RLDEBUG(" - creating GL context");
+ m_gl = new QOpenGLContext();
+ m_gl->setFormat(window->requestedFormat());
+ m_gl->create();
+ QSG_RENDER_TIMING_SAMPLE(time_created);
+ RLDEBUG(" - making current");
+ m_gl->makeCurrent(window);
+ RLDEBUG(" - initializing SG");
+ QSG_RENDER_TIMING_SAMPLE(time_current);
+ m_sg->initialize(m_gl);
+
+#ifndef QSG_NO_RENDER_TIMING
+ if (qsg_render_timing) {
+ qDebug("WindowsRenderLoop: GL=%d ms, makeCurrent=%d ms, SG=%d ms",
+ int((time_created - time_start)/1000000),
+ int((time_current - time_created)/1000000),
+ int((qsg_render_timer.nsecsElapsed() - time_current)/1000000));
+ }
+ if (QQmlProfilerService::enabled) {
+ QQmlProfilerService::sceneGraphFrame(
+ QQmlProfilerService::SceneGraphWindowsRenderShow,
+ time_created - time_start,
+ time_current - time_created,
+ qsg_render_timer.nsecsElapsed() - time_current);
+ }
+#endif
+
+ }
+
+ WindowData data;
+ data.window = window;
+ data.pendingUpdate = false;
+ m_windows << data;
+
+ RLDEBUG(" - done with show");
+}
+
+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)
+ // The check is made here, after the removal from m_windows, so
+ // anyoneShowing will report the right value.
+ if (window->isExposed())
+ handleObscurity();
+
+ QQuickWindowPrivate *cd = QQuickWindowPrivate::get(window);
+ 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) {
+ m_sg->invalidate();
+ if (!cd->persistentGLContext) {
+ delete m_gl;
+ m_gl = 0;
+ }
+ }
+ }
+}
+
+void QSGWindowsRenderLoop::windowDestroyed(QQuickWindow *window)
+{
+ RLDEBUG("windowDestroyed");
+ hide(window);
+
+ // If this is the last tracked window, clean up SG and GL.
+ if (m_windows.size() == 0) {
+ m_sg->invalidate();
+ delete m_gl;
+ m_gl = 0;
+ }
+}
+
+bool QSGWindowsRenderLoop::anyoneShowing() const
+{
+ foreach (const WindowData &wd, m_windows)
+ if (wd.window->isExposed() && wd.window->size().isValid())
+ return true;
+ return false;
+}
+
+void QSGWindowsRenderLoop::exposureChanged(QQuickWindow *window)
+{
+
+ if (windowData(window) == 0)
+ return;
+
+ if (window->isExposed()) {
+
+ // Stop non-visual animation timer as we now have a window rendering
+ if (m_animationTimer && anyoneShowing()) {
+ RLDEBUG(" - stopping non-visual animation timer");
+ killTimer(m_animationTimer);
+ m_animationTimer = 0;
+ }
+
+ RLDEBUG("exposureChanged - exposed");
+ WindowData *wd = windowData(window);
+ wd->pendingUpdate = true;
+
+ // If we have a pending timer and we get an expose, we need to stop it.
+ // Otherwise we get two frames and two animation ticks in the same time-interval.
+ if (m_updateTimer) {
+ RLDEBUG(" - killing pending update timer");
+ killTimer(m_updateTimer);
+ m_updateTimer = 0;
+ }
+ render();
+ } else {
+ handleObscurity();
+ }
+}
+
+void QSGWindowsRenderLoop::handleObscurity()
+{
+ RLDEBUG("handleObscurity");
+ // Potentially start the non-visual animation timer if nobody is rendering
+ if (m_animationDriver->isRunning() && !anyoneShowing() && !m_animationTimer) {
+ RLDEBUG(" - starting non-visual animation timer");
+ m_animationTimer = startTimer(m_vsyncDelta);
+ }
+}
+
+QImage QSGWindowsRenderLoop::grab(QQuickWindow *window)
+{
+ RLDEBUG("grab");
+ if (!m_gl)
+ return QImage();
+
+ m_gl->makeCurrent(window);
+
+ QQuickWindowPrivate *d = QQuickWindowPrivate::get(window);
+ d->polishItems();
+ d->syncSceneGraph();
+ d->renderSceneGraph(window->size());
+
+ QImage image = qt_gl_read_framebuffer(window->size(), false, false);
+ return image;
+}
+
+void QSGWindowsRenderLoop::update(QQuickWindow *window)
+{
+ RLDEBUG("update");
+ maybeUpdate(window);
+}
+
+void QSGWindowsRenderLoop::maybeUpdate(QQuickWindow *window)
+{
+ RLDEBUG("maybeUpdate");
+
+ WindowData *wd = windowData(window);
+ if (!wd || !anyoneShowing())
+ return;
+
+ wd->pendingUpdate = true;
+ maybePostUpdateTimer();
+}
+
+bool QSGWindowsRenderLoop::event(QEvent *event)
+{
+ switch (event->type()) {
+ case QEvent::Timer: {
+ QTimerEvent *te = static_cast<QTimerEvent *>(event);
+ if (te->timerId() == m_animationTimer) {
+ RLDEBUG("event : animation tick while nothing is showing");
+ m_animationDriver->advance();
+ } else if (te->timerId() == m_updateTimer) {
+ RLDEBUG("event : update");
+ killTimer(m_updateTimer);
+ m_updateTimer = 0;
+ render();
+ }
+ return true; }
+ default:
+ break;
+ }
+
+ return QObject::event(event);
+}
+
+/*
+ * Go through all windows we control and render them in turn.
+ * Then tick animations if active.
+ */
+void QSGWindowsRenderLoop::render()
+{
+ RLDEBUG("render");
+ foreach (const WindowData &wd, m_windows) {
+ if (wd.pendingUpdate) {
+ const_cast<WindowData &>(wd).pendingUpdate = false;
+ renderWindow(wd.window);
+ }
+ }
+
+ if (m_animationDriver->isRunning()) {
+ RLDEBUG("advancing animations");
+ QSG_RENDER_TIMING_SAMPLE(time_start);
+ m_animationDriver->advance();
+ RLDEBUG("animations advanced");
+
+#ifndef QSG_NO_RENDER_TIMING
+ if (qsg_render_timing) {
+ qDebug("WindowsRenderLoop: animations=%d ms",
+ int((qsg_render_timer.nsecsElapsed() - time_start)/1000000));
+ }
+ if (QQmlProfilerService::Enabled) {
+ QQmlProfilerService::sceneGraphFrame(
+ QQmlProfilerService::SceneGraphWindowsAnimations,
+ qsg_render_timer.nsecsElapsed() - time_start);
+ }
+#endif
+
+ // It is not given that animations triggered another maybeUpdate()
+ // and thus another render pass, so to keep things running,
+ // make sure there is another frame pending.
+ maybePostUpdateTimer();
+
+ emit timeToIncubate();
+ }
+}
+
+/*
+ * Render the contents of this window. First polish, then sync, render
+ * then finally swap.
+ *
+ * Note: This render function does not implement aborting
+ * the render call when sync step results in no scene graph changes,
+ * like the threaded renderer does.
+ */
+void QSGWindowsRenderLoop::renderWindow(QQuickWindow *window)
+{
+ RLDEBUG("renderWindow");
+ QQuickWindowPrivate *d = QQuickWindowPrivate::get(window);
+
+ if (!d->isRenderable())
+ return;
+
+ if (!m_gl->makeCurrent(window))
+ return;
+
+ QSG_RENDER_TIMING_SAMPLE(time_start);
+
+ RLDEBUG(" - polishing");
+ d->polishItems();
+ QSG_RENDER_TIMING_SAMPLE(time_polished);
+
+ RLDEBUG(" - syncing");
+ d->syncSceneGraph();
+ QSG_RENDER_TIMING_SAMPLE(time_synced);
+
+ RLDEBUG(" - rendering");
+ d->renderSceneGraph(window->size());
+ QSG_RENDER_TIMING_SAMPLE(time_rendered);
+
+ RLDEBUG(" - swapping");
+ m_gl->swapBuffers(window);
+ QSG_RENDER_TIMING_SAMPLE(time_swapped);
+
+ RLDEBUG(" - frameDone");
+ d->fireFrameSwapped();
+
+#ifndef QSG_NO_RENDER_TIMING
+ if (qsg_render_timing) {
+ qDebug("WindowsRenderLoop(t=%d): window=%p, polish=%d ms, sync=%d ms, render=%d ms, swap=%d ms",
+ int(qsg_render_timer.elapsed()),
+ window,
+ int((time_polished - time_start)/1000000),
+ int((time_synced - time_polished)/1000000),
+ int((time_rendered - time_synced)/1000000),
+ int((time_swapped - time_rendered)/1000000));
+ }
+ if (QQmlProfilerService::enabled) {
+ QQmlProfilerService::sceneGraphFrame(
+ QQmlProfilerService::SceneGraphWindowsPolishFrame,
+ time_polished - time_start
+ );
+
+ QQmlProfilerService::sceneGraphFrame(
+ QQmlProfilerService::SceneGraphRenderLoopFrame,
+ time_synced - time_polished,
+ time_rendered - time_synced,
+ time_swapped - time_rendered
+ );
+ }
+#endif
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/qsgwindowsrenderloop_p.h b/src/quick/scenegraph/qsgwindowsrenderloop_p.h
new file mode 100644
index 0000000000..218e18c3e2
--- /dev/null
+++ b/src/quick/scenegraph/qsgwindowsrenderloop_p.h
@@ -0,0 +1,116 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGWINDOWSRENDERLOOP_P_H
+#define QSGWINDOWSRENDERLOOP_P_H
+
+#include <QtCore/QObject>
+#include <QtCore/QElapsedTimer>
+
+#include <QtGui/QOpenGLContext>
+
+#include "qsgrenderloop_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QSGWindowsRenderLoop : public QSGRenderLoop
+{
+ Q_OBJECT
+public:
+ explicit QSGWindowsRenderLoop();
+
+ void show(QQuickWindow *window);
+ void hide(QQuickWindow *window);
+
+ void windowDestroyed(QQuickWindow *window);
+
+ void exposureChanged(QQuickWindow *window);
+ QImage grab(QQuickWindow *window);
+
+ void update(QQuickWindow *window);
+ void maybeUpdate(QQuickWindow *window);
+
+ QAnimationDriver *animationDriver() const { return m_animationDriver; }
+
+ QSGContext *sceneGraphContext() const { return m_sg; }
+
+ void releaseResources(QQuickWindow *) { }
+
+ void render();
+ void renderWindow(QQuickWindow *window);
+
+ void resize(QQuickWindow *, const QSize &) { }
+
+ bool event(QEvent *event);
+ bool anyoneShowing() const;
+
+ bool interleaveIncubation() const;
+
+public slots:
+ void started();
+ void stopped();
+
+private:
+ struct WindowData {
+ QQuickWindow *window;
+ bool pendingUpdate;
+ };
+
+ void handleObscurity();
+ void maybePostUpdateTimer();
+ WindowData *windowData(QQuickWindow *window);
+
+ QList<WindowData> m_windows;
+
+ QOpenGLContext *m_gl;
+ QSGContext *m_sg;
+
+ QAnimationDriver *m_animationDriver;
+
+ int m_updateTimer;
+ int m_animationTimer;
+
+ int m_vsyncDelta;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGWINDOWSRENDERLOOP_P_H
diff --git a/src/quick/scenegraph/scenegraph.pri b/src/quick/scenegraph/scenegraph.pri
index 8c87e23ac9..34432ffd9c 100644
--- a/src/quick/scenegraph/scenegraph.pri
+++ b/src/quick/scenegraph/scenegraph.pri
@@ -6,6 +6,7 @@ HEADERS += \
$$PWD/coreapi/qsggeometry.h \
$$PWD/coreapi/qsgmaterial.h \
$$PWD/coreapi/qsgnode.h \
+ $$PWD/coreapi/qsgnode_p.h \
$$PWD/coreapi/qsgnodeupdater_p.h \
$$PWD/coreapi/qsgrenderer_p.h \
$$PWD/coreapi/qsgrendernode_p.h \
@@ -51,7 +52,6 @@ SOURCES += \
$$PWD/util/qsgpainternode.cpp \
$$PWD/util/qsgdistancefieldutil.cpp
-
# QML / Adaptations API
HEADERS += \
$$PWD/qsgadaptationlayer_p.h \
@@ -67,8 +67,8 @@ HEADERS += \
$$PWD/qsgflashnode_p.h \
$$PWD/qsgshareddistancefieldglyphcache_p.h \
$$PWD/qsgrenderloop_p.h \
- $$PWD/qsgthreadedrenderloop_p.h
-
+ $$PWD/qsgthreadedrenderloop_p.h \
+ $$PWD/qsgwindowsrenderloop_p.h
SOURCES += \
$$PWD/qsgadaptationlayer.cpp \
@@ -84,12 +84,5 @@ SOURCES += \
$$PWD/qsgflashnode.cpp \
$$PWD/qsgshareddistancefieldglyphcache.cpp \
$$PWD/qsgrenderloop.cpp \
- $$PWD/qsgthreadedrenderloop.cpp
-
-
-
-
-
-
-
-
+ $$PWD/qsgthreadedrenderloop.cpp \
+ $$PWD/qsgwindowsrenderloop.cpp
diff --git a/src/quick/scenegraph/util/qsgflatcolormaterial.cpp b/src/quick/scenegraph/util/qsgflatcolormaterial.cpp
index 307201277c..09e2a7da27 100644
--- a/src/quick/scenegraph/util/qsgflatcolormaterial.cpp
+++ b/src/quick/scenegraph/util/qsgflatcolormaterial.cpp
@@ -74,11 +74,11 @@ void FlatColorMaterialShader::updateState(const RenderState &state, QSGMaterial
const QColor &c = newMaterial->color();
if (oldMaterial == 0 || c != oldMaterial->color() || state.isOpacityDirty()) {
- float opacity = state.opacity();
- QVector4D v(c.redF() * c.alphaF() * opacity,
- c.greenF() * c.alphaF() * opacity,
- c.blueF() * c.alphaF() * opacity,
- c.alphaF() * opacity);
+ float opacity = state.opacity() * c.alphaF();
+ QVector4D v(c.redF() * opacity,
+ c.greenF() * opacity,
+ c.blueF() * opacity,
+ opacity);
program()->setUniformValue(m_color_id, v);
}
diff --git a/src/quick/scenegraph/util/qsgpainternode.cpp b/src/quick/scenegraph/util/qsgpainternode.cpp
index e5cf6b8295..97b3500ad0 100644
--- a/src/quick/scenegraph/util/qsgpainternode.cpp
+++ b/src/quick/scenegraph/util/qsgpainternode.cpp
@@ -73,10 +73,6 @@ QSGPainterTexture::QSGPainterTexture()
m_retain_image = true;
}
-#ifdef QT_OPENGL_ES
-extern void qsg_swizzleBGRAToRGBA(QImage *image);
-#endif
-
void QSGPainterTexture::bind()
{
if (m_dirty_rect.isNull()) {
@@ -84,33 +80,8 @@ void QSGPainterTexture::bind()
return;
}
- bool oldMipmapsGenerated = m_mipmaps_generated;
- m_mipmaps_generated = true;
+ setImage(m_image);
QSGPlainTexture::bind();
- m_mipmaps_generated = oldMipmapsGenerated;
-
- QImage subImage = m_image.copy(m_dirty_rect);
-
- int w = m_dirty_rect.width();
- int h = m_dirty_rect.height();
-
-#ifdef QT_OPENGL_ES
- qsg_swizzleBGRAToRGBA(&subImage);
- glTexSubImage2D(GL_TEXTURE_2D, 0, m_dirty_rect.x(), m_dirty_rect.y(), w, h,
- GL_RGBA, GL_UNSIGNED_BYTE, subImage.constBits());
-#else
- glTexSubImage2D(GL_TEXTURE_2D, 0, m_dirty_rect.x(), m_dirty_rect.y(), w, h,
- GL_BGRA, GL_UNSIGNED_BYTE, subImage.constBits());
-#endif
-
- if (m_has_mipmaps && !m_mipmaps_generated) {
- QOpenGLContext *ctx = QOpenGLContext::currentContext();
- ctx->functions()->glGenerateMipmap(GL_TEXTURE_2D);
- m_mipmaps_generated = true;
- }
-
- m_dirty_texture = false;
- m_dirty_bind_options = false;
m_dirty_rect = QRect();
}
diff --git a/src/quick/scenegraph/util/qsgsimpletexturenode.cpp b/src/quick/scenegraph/util/qsgsimpletexturenode.cpp
index 318120e4bf..86e0d36f6c 100644
--- a/src/quick/scenegraph/util/qsgsimpletexturenode.cpp
+++ b/src/quick/scenegraph/util/qsgsimpletexturenode.cpp
@@ -41,18 +41,44 @@
#include "qsgsimpletexturenode.h"
+#include <private/qsgnode_p.h>
QT_BEGIN_NAMESPACE
+class QSGSimpleTextureNodePrivate : public QSGGeometryNodePrivate
+{
+public:
+ QSGSimpleTextureNodePrivate()
+ : QSGGeometryNodePrivate()
+ , m_texCoordMode(QSGSimpleTextureNode::NoTransform)
+ {}
+
+ QSGSimpleTextureNode::TextureCoordinatesTransformMode m_texCoordMode;
+};
+
static void qsgsimpletexturenode_update(QSGGeometry *g,
QSGTexture *texture,
- const QRectF &rect)
+ const QRectF &rect,
+ QSGSimpleTextureNode::TextureCoordinatesTransformMode texCoordMode)
{
if (!texture)
return;
QSize ts = texture->textureSize();
QRectF sourceRect(0, 0, ts.width(), ts.height());
+
+ // Maybe transform the texture coordinates
+ if (texCoordMode.testFlag(QSGSimpleTextureNode::MirrorHorizontally)) {
+ float tmp = sourceRect.left();
+ sourceRect.setLeft(sourceRect.right());
+ sourceRect.setRight(tmp);
+ }
+ if (texCoordMode.testFlag(QSGSimpleTextureNode::MirrorVertically)) {
+ float tmp = sourceRect.top();
+ sourceRect.setTop(sourceRect.bottom());
+ sourceRect.setBottom(tmp);
+ }
+
QSGGeometry::updateTexturedRectGeometry(g, rect, texture->convertToNormalizedSourceRect(sourceRect));
}
@@ -71,7 +97,8 @@ static void qsgsimpletexturenode_update(QSGGeometry *g,
Constructs a new simple texture node
*/
QSGSimpleTextureNode::QSGSimpleTextureNode()
- : m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4)
+ : QSGGeometryNode(*new QSGSimpleTextureNodePrivate)
+ , m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4)
{
setGeometry(&m_geometry);
setMaterial(&m_material);
@@ -112,7 +139,8 @@ void QSGSimpleTextureNode::setRect(const QRectF &r)
if (m_rect == r)
return;
m_rect = r;
- qsgsimpletexturenode_update(&m_geometry, texture(), m_rect);
+ Q_D(QSGSimpleTextureNode);
+ qsgsimpletexturenode_update(&m_geometry, texture(), m_rect, d->m_texCoordMode);
markDirty(DirtyGeometry);
}
@@ -144,7 +172,8 @@ void QSGSimpleTextureNode::setTexture(QSGTexture *texture)
return;
m_material.setTexture(texture);
m_opaque_material.setTexture(texture);
- qsgsimpletexturenode_update(&m_geometry, texture, m_rect);
+ Q_D(QSGSimpleTextureNode);
+ qsgsimpletexturenode_update(&m_geometry, texture, m_rect, d->m_texCoordMode);
markDirty(DirtyMaterial);
}
@@ -158,4 +187,48 @@ QSGTexture *QSGSimpleTextureNode::texture() const
return m_material.texture();
}
+/*!
+ \enum QSGSimpleTextureNode::TextureCoordinatesTransformFlag
+
+ The TextureCoordinatesTransformFlag enum is used to specify the
+ mode used to generate texture coordinates for a textured quad.
+
+ \value NoTransform Texture coordinates are oriented with window coordinates
+ i.e. with origin at top-left.
+
+ \value MirrorHorizontally Texture coordinates are inverted in the horizontal axis with
+ respect to window coordinates
+
+ \value MirrorVertically Texture coordinates are inverted in the vertical axis with
+ respect to window coordinates
+ */
+
+/*!
+ Sets the method used to generate texture coordinates to \a mode. This can be used to obtain
+ correct orientation of the texture. This is commonly needed when using a third party OpenGL
+ library to render to texture as OpenGL has an inverted y-axis relative to Qt Quick.
+
+ \sa textureCoordinatesTransform()
+ */
+void QSGSimpleTextureNode::setTextureCoordinatesTransform(QSGSimpleTextureNode::TextureCoordinatesTransformMode mode)
+{
+ Q_D(QSGSimpleTextureNode);
+ if (d->m_texCoordMode == mode)
+ return;
+ d->m_texCoordMode = mode;
+ qsgsimpletexturenode_update(&m_geometry, texture(), m_rect, d->m_texCoordMode);
+ markDirty(DirtyMaterial);
+}
+
+/*!
+ Returns the mode used to generate texture coordinates for this node.
+
+ \sa setTextureCoordinatesTransform()
+ */
+QSGSimpleTextureNode::TextureCoordinatesTransformMode QSGSimpleTextureNode::textureCoordinatesTransform() const
+{
+ Q_D(const QSGSimpleTextureNode);
+ return d->m_texCoordMode;
+}
+
QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/util/qsgsimpletexturenode.h b/src/quick/scenegraph/util/qsgsimpletexturenode.h
index ffd10210ae..f5ab7fb3bb 100644
--- a/src/quick/scenegraph/util/qsgsimpletexturenode.h
+++ b/src/quick/scenegraph/util/qsgsimpletexturenode.h
@@ -48,6 +48,8 @@
QT_BEGIN_NAMESPACE
+class QSGSimpleTextureNodePrivate;
+
class Q_QUICK_EXPORT QSGSimpleTextureNode : public QSGGeometryNode
{
public:
@@ -63,14 +65,28 @@ public:
void setFiltering(QSGTexture::Filtering filtering);
QSGTexture::Filtering filtering() const;
+ enum TextureCoordinatesTransformFlag {
+ NoTransform = 0x00,
+ MirrorHorizontally = 0x01,
+ MirrorVertically = 0x02
+ };
+ Q_DECLARE_FLAGS(TextureCoordinatesTransformMode, TextureCoordinatesTransformFlag)
+
+ void setTextureCoordinatesTransform(TextureCoordinatesTransformMode mode);
+ TextureCoordinatesTransformMode textureCoordinatesTransform() const;
+
private:
QSGGeometry m_geometry;
QSGOpaqueTextureMaterial m_opaque_material;
QSGTextureMaterial m_material;
QRectF m_rect;
+
+ Q_DECLARE_PRIVATE(QSGSimpleTextureNode)
};
+Q_DECLARE_OPERATORS_FOR_FLAGS(QSGSimpleTextureNode::TextureCoordinatesTransformMode)
+
QT_END_NAMESPACE
#endif // QSGSIMPLETEXTURENODE_H
diff --git a/src/quick/scenegraph/util/qsgtexture.cpp b/src/quick/scenegraph/util/qsgtexture.cpp
index ad98fe9d47..a69f43f8d6 100644
--- a/src/quick/scenegraph/util/qsgtexture.cpp
+++ b/src/quick/scenegraph/util/qsgtexture.cpp
@@ -614,7 +614,8 @@ void QSGPlainTexture::bind()
m_dirty_texture = false;
#ifndef QSG_NO_RENDER_TIMING
- if (qsg_render_timing)
+ bool profileFrames = qsg_render_timing || QQmlProfilerService::enabled;
+ if (profileFrames)
qsg_renderer_timer.start();
#endif
@@ -628,6 +629,11 @@ void QSGPlainTexture::bind()
m_texture_size.width(),
m_texture_size.height());
}
+ if (QQmlProfilerService::enabled) {
+ QQmlProfilerService::sceneGraphFrame(
+ QQmlProfilerService::SceneGraphTextureDeletion,
+ qsg_renderer_timer.nsecsElapsed());
+ }
#endif
}
m_texture_id = 0;
@@ -645,9 +651,9 @@ void QSGPlainTexture::bind()
glBindTexture(GL_TEXTURE_2D, m_texture_id);
#ifndef QSG_NO_RENDER_TIMING
- int bindTime = 0;
- if (qsg_render_timing)
- bindTime = qsg_renderer_timer.elapsed();
+ qint64 bindTime = 0;
+ if (profileFrames)
+ bindTime = qsg_renderer_timer.nsecsElapsed();
#endif
// ### TODO: check for out-of-memory situations...
@@ -657,11 +663,13 @@ void QSGPlainTexture::bind()
QImage tmp = (m_image.format() == QImage::Format_RGB32 || m_image.format() == QImage::Format_ARGB32_Premultiplied)
? m_image
: m_image.convertToFormat(QImage::Format_ARGB32_Premultiplied);
+ if (tmp.width() * 4 != tmp.bytesPerLine())
+ tmp = tmp.copy();
#ifndef QSG_NO_RENDER_TIMING
- int convertTime = 0;
- if (qsg_render_timing)
- convertTime = qsg_renderer_timer.elapsed();
+ qint64 convertTime = 0;
+ if (profileFrames)
+ convertTime = qsg_renderer_timer.nsecsElapsed();
#endif
updateBindOptions(m_dirty_bind_options);
@@ -684,16 +692,16 @@ void QSGPlainTexture::bind()
}
#ifndef QSG_NO_RENDER_TIMING
- int swizzleTime = 0;
- if (qsg_render_timing)
- swizzleTime = qsg_renderer_timer.elapsed();
+ qint64 swizzleTime = 0;
+ if (profileFrames)
+ swizzleTime = qsg_renderer_timer.nsecsElapsed();
#endif
glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, w, h, 0, externalFormat, GL_UNSIGNED_BYTE, tmp.constBits());
#ifndef QSG_NO_RENDER_TIMING
- int uploadTime = 0;
- if (qsg_render_timing)
- uploadTime = qsg_renderer_timer.elapsed();
+ qint64 uploadTime = 0;
+ if (profileFrames)
+ uploadTime = qsg_renderer_timer.nsecsElapsed();
#endif
@@ -704,23 +712,35 @@ void QSGPlainTexture::bind()
}
#ifndef QSG_NO_RENDER_TIMING
- int mipmapTime = 0;
+ qint64 mipmapTime = 0;
if (qsg_render_timing) {
- mipmapTime = qsg_renderer_timer.elapsed();
+ mipmapTime = qsg_renderer_timer.nsecsElapsed();
printf(" - plaintexture(%dx%d) bind=%d, convert=%d, swizzle=%d (%s->%s), upload=%d, mipmap=%d, total=%d\n",
m_texture_size.width(), m_texture_size.height(),
- bindTime,
- convertTime - bindTime,
- swizzleTime - convertTime,
+ int(bindTime/1000000),
+ int((convertTime - bindTime)/1000000),
+ int((swizzleTime - convertTime)/1000000),
externalFormat == GL_BGRA ? "BGRA" : "RGBA",
internalFormat == GL_BGRA ? "BGRA" : "RGBA",
- uploadTime - swizzleTime,
- mipmapTime - uploadTime,
+ int((uploadTime - swizzleTime)/1000000),
+ int((mipmapTime - uploadTime)/1000000),
(int) qsg_renderer_timer.elapsed());
}
+ if (QQmlProfilerService::enabled) {
+ mipmapTime = qsg_renderer_timer.nsecsElapsed();
+
+ QQmlProfilerService::sceneGraphFrame(
+ QQmlProfilerService::SceneGraphTexturePrepare,
+ bindTime,
+ convertTime - bindTime,
+ swizzleTime - convertTime,
+ uploadTime - swizzleTime,
+ mipmapTime - uploadTime);
+ }
+
#endif
diff --git a/src/quick/scenegraph/util/qsgtexture_p.h b/src/quick/scenegraph/util/qsgtexture_p.h
index 6430a93ed8..7282d4051f 100644
--- a/src/quick/scenegraph/util/qsgtexture_p.h
+++ b/src/quick/scenegraph/util/qsgtexture_p.h
@@ -54,7 +54,7 @@ QT_BEGIN_NAMESPACE
class QSGTexturePrivate : public QObjectPrivate
{
- Q_DECLARE_PUBLIC(QSGTexture);
+ Q_DECLARE_PUBLIC(QSGTexture)
public:
QSGTexturePrivate();
diff --git a/src/quick/scenegraph/util/qsgtexturematerial.cpp b/src/quick/scenegraph/util/qsgtexturematerial.cpp
index ff91109a2a..87414766e3 100644
--- a/src/quick/scenegraph/util/qsgtexturematerial.cpp
+++ b/src/quick/scenegraph/util/qsgtexturematerial.cpp
@@ -145,7 +145,7 @@ void QSGOpaqueTextureMaterialShader::updateState(const RenderState &state, QSGMa
tuple. The QSGGeometry::defaultAttributes_TexturedPoint2D returns an
attribute set compatible with this material.
- The texture to be rendered is can be set using setTexture(). How the
+ The texture to be rendered can be set using setTexture(). How the
texture should be rendered can be specified using setMipmapFiltering(),
setFiltering(), setHorizontalWrapMode() and setVerticalWrapMode().
The rendering state is set on the texture instance just before it
@@ -208,7 +208,7 @@ QSGMaterialShader *QSGOpaqueTextureMaterial::createShader() const
/*!
Sets the texture of this material to \a texture.
- The material does not take ownership over the texture.
+ The material does not take ownership of the texture.
*/
void QSGOpaqueTextureMaterial::setTexture(QSGTexture *texture)
@@ -337,7 +337,7 @@ int QSGOpaqueTextureMaterial::compare(const QSGMaterial *o) const
tuple. The QSGGeometry::defaultAttributes_TexturedPoint2D returns an
attribute set compatible with this material.
- The texture to be rendered is set using setTexture(). How the
+ The texture to be rendered can be set using setTexture(). How the
texture should be rendered can be specified using setMipmapFiltering(),
setFiltering(), setHorizontalWrapMode() and setVerticalWrapMode().
The rendering state is set on the texture instance just before it