aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick
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
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')
-rw-r--r--src/quick/doc/images/qml-blending-layered.pngbin0 -> 7582 bytes
-rw-r--r--src/quick/doc/images/qml-blending-nonlayered.pngbin0 -> 7707 bytes
-rw-r--r--src/quick/doc/images/qml-shadereffect-layereffect.pngbin0 -> 22264 bytes
-rw-r--r--src/quick/doc/images/qml-shadereffect-nolayereffect.pngbin0 -> 26718 bytes
-rw-r--r--src/quick/doc/images/qml-shadereffect-opacitymask.pngbin0 -> 15661 bytes
-rw-r--r--src/quick/doc/qtquick.qdocconf6
-rw-r--r--src/quick/doc/snippets/qml/layerblending.qml111
-rw-r--r--src/quick/doc/snippets/qml/layerwitheffect.qml111
-rw-r--r--src/quick/doc/snippets/qml/opacitymask.qml114
-rw-r--r--src/quick/doc/src/concepts/input/focus.qdoc2
-rw-r--r--src/quick/doc/src/concepts/modelviewsdata/cppmodels.qdoc8
-rw-r--r--src/quick/doc/src/concepts/positioning/righttoleft.qdoc8
-rw-r--r--src/quick/doc/src/dynamicview-tutorial.qdoc34
-rw-r--r--src/quick/items/context2d/qquickcanvasitem.cpp9
-rw-r--r--src/quick/items/context2d/qquickcontext2d.cpp6
-rw-r--r--src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp7
-rw-r--r--src/quick/items/context2d/qquickcontext2dcommandbuffer_p.h3
-rw-r--r--src/quick/items/context2d/qquickcontext2dtexture.cpp19
-rw-r--r--src/quick/items/context2d/qquickcontext2dtexture_p.h6
-rw-r--r--src/quick/items/qquickborderimage.cpp213
-rw-r--r--src/quick/items/qquickdrag.cpp13
-rw-r--r--src/quick/items/qquickframebufferobject.cpp1
-rw-r--r--src/quick/items/qquickgridview.cpp2
-rw-r--r--src/quick/items/qquickimagebase_p_p.h2
-rw-r--r--src/quick/items/qquickitem.cpp111
-rw-r--r--src/quick/items/qquicklistview.cpp2
-rw-r--r--src/quick/items/qquickscreen.cpp34
-rw-r--r--src/quick/items/qquickscreen_p.h10
-rw-r--r--src/quick/items/qquickshadereffect.cpp24
-rw-r--r--src/quick/items/qquickshadereffectsource.cpp60
-rw-r--r--src/quick/items/qquicktextcontrol.cpp6
-rw-r--r--src/quick/items/qquicktextcontrol_p.h2
-rw-r--r--src/quick/items/qquicktextcontrol_p_p.h2
-rw-r--r--src/quick/items/qquicktextnodeengine.cpp73
-rw-r--r--src/quick/items/qquicktextnodeengine_p.h14
-rw-r--r--src/quick/items/qquickview.cpp10
-rw-r--r--src/quick/items/qquickwindow.cpp13
-rw-r--r--src/quick/items/qquickwindow.h3
-rw-r--r--src/quick/items/qquickwindowmodule.cpp11
-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
-rw-r--r--src/quick/util/qquickanimatorcontroller.cpp9
-rw-r--r--src/quick/util/qquickanimatorjob.cpp28
-rw-r--r--src/quick/util/qquickanimatorjob_p.h7
-rw-r--r--src/quick/util/qquickpixmapcache.cpp53
-rw-r--r--src/quick/util/qquickprofiler.cpp18
-rw-r--r--src/quick/util/qquickprofiler_p.h42
63 files changed, 1172 insertions, 463 deletions
diff --git a/src/quick/doc/images/qml-blending-layered.png b/src/quick/doc/images/qml-blending-layered.png
new file mode 100644
index 0000000000..fa1c24a98e
--- /dev/null
+++ b/src/quick/doc/images/qml-blending-layered.png
Binary files differ
diff --git a/src/quick/doc/images/qml-blending-nonlayered.png b/src/quick/doc/images/qml-blending-nonlayered.png
new file mode 100644
index 0000000000..265abf6530
--- /dev/null
+++ b/src/quick/doc/images/qml-blending-nonlayered.png
Binary files differ
diff --git a/src/quick/doc/images/qml-shadereffect-layereffect.png b/src/quick/doc/images/qml-shadereffect-layereffect.png
new file mode 100644
index 0000000000..44b05a9949
--- /dev/null
+++ b/src/quick/doc/images/qml-shadereffect-layereffect.png
Binary files differ
diff --git a/src/quick/doc/images/qml-shadereffect-nolayereffect.png b/src/quick/doc/images/qml-shadereffect-nolayereffect.png
new file mode 100644
index 0000000000..f21e3f0c4e
--- /dev/null
+++ b/src/quick/doc/images/qml-shadereffect-nolayereffect.png
Binary files differ
diff --git a/src/quick/doc/images/qml-shadereffect-opacitymask.png b/src/quick/doc/images/qml-shadereffect-opacitymask.png
new file mode 100644
index 0000000000..e056aa763b
--- /dev/null
+++ b/src/quick/doc/images/qml-shadereffect-opacitymask.png
Binary files differ
diff --git a/src/quick/doc/qtquick.qdocconf b/src/quick/doc/qtquick.qdocconf
index 5b8388f977..d54e5feecb 100644
--- a/src/quick/doc/qtquick.qdocconf
+++ b/src/quick/doc/qtquick.qdocconf
@@ -62,9 +62,9 @@ headerdirs += ../../plugins
sourcedirs += ../../plugins
#exclude certain directories
-excludedirs += ../../imports/dialogs \
- ../../imports/models \
- ../../../examples/quick/dialogs
+excludedirs += ../../imports/models
+
+examples.fileextensions += "*.qm"
manifestmeta.thumbnail.names += "QtQuick/Threaded ListModel Example"
diff --git a/src/quick/doc/snippets/qml/layerblending.qml b/src/quick/doc/snippets/qml/layerblending.qml
new file mode 100644
index 0000000000..0ef23465a5
--- /dev/null
+++ b/src/quick/doc/snippets/qml/layerblending.qml
@@ -0,0 +1,111 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Gunnar Sletta <gunnar@sletta.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+
+Item {
+ width: 300
+ height: 200
+
+ // The checkers background
+ ShaderEffect {
+ id: tileBackground
+ anchors.fill: parent
+
+ property real tileSize: 10
+ property color color1: Qt.rgba(0.9, 0.9, 0.9, 1);
+ property color color2: Qt.rgba(0.85, 0.85, 0.85, 1);
+
+ property size pixelSize: Qt.size(width / tileSize, height / tileSize);
+
+ fragmentShader:
+ "
+ uniform lowp vec4 color1;
+ uniform lowp vec4 color2;
+ uniform highp vec2 pixelSize;
+ varying highp vec2 qt_TexCoord0;
+ void main() {
+ highp vec2 tc = sign(sin(3.14152 * qt_TexCoord0 * pixelSize));
+ if (tc.x != tc.y)
+ gl_FragColor = color1;
+ else
+ gl_FragColor = color2;
+ }
+ "
+ }
+
+
+ Row {
+ height: 100
+ anchors.centerIn: parent
+ spacing: 50
+
+//! [non-layered]
+Item {
+ id: nonLayered
+
+ opacity: 0.5
+
+ width: 100
+ height: 100
+
+ Rectangle { width: 80; height: 80; border.width: 1 }
+ Rectangle { x: 20; y: 20; width: 80; height: 80; border.width: 1 }
+}
+//! [non-layered]
+
+//! [layered]
+Item {
+ id: layered
+
+ opacity: 0.5
+
+ layer.enabled: true
+
+ width: 100
+ height: 100
+
+ Rectangle { width: 80; height: 80; border.width: 1 }
+ Rectangle { x: 20; y: 20; width: 80; height: 80; border.width: 1 }
+}
+//! [layered]
+
+ }
+}
diff --git a/src/quick/doc/snippets/qml/layerwitheffect.qml b/src/quick/doc/snippets/qml/layerwitheffect.qml
new file mode 100644
index 0000000000..8cfac0bb19
--- /dev/null
+++ b/src/quick/doc/snippets/qml/layerwitheffect.qml
@@ -0,0 +1,111 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Gunnar Sletta <gunnar@sletta.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.2
+
+Rectangle {
+ id: root
+ width: 320
+ height: 320
+
+ gradient: Gradient {
+ GradientStop { position: 0; color: "steelblue" }
+ GradientStop { position: 1; color: "black" }
+ }
+
+ property real cx: width / 2;
+ property real cy: height / 2;
+ property real boxSize: root.width * 0.2;
+ property real radius: width / 4;
+
+
+//! [1]
+Item {
+ id: layerRoot
+ layer.enabled: true
+ layer.effect: ShaderEffect {
+ fragmentShader: "
+ uniform lowp sampler2D source; // this item
+ uniform lowp float qt_Opacity; // inherited opacity of this item
+ varying highp vec2 qt_TexCoord0;
+ void main() {
+ lowp vec4 p = texture2D(source, qt_TexCoord0);
+ lowp float g = dot(p.xyz, vec3(0.344, 0.5, 0.156));
+ gl_FragColor = vec4(g, g, g, p.a) * qt_Opacity;
+ }"
+ }
+//! [1]
+
+ anchors.fill: parent
+
+
+ Repeater {
+ id: repeater
+ model: 200
+
+ Rectangle {
+ id: box
+
+ property real t: index / (repeater.model - 1);
+
+ width: 0
+ height: 0
+ x: root.cx - Math.sin(Math.PI * 2 * t) * root.radius;
+ y: root.cy - Math.cos(Math.PI * 2 * t) * root.radius;
+
+ Rectangle {
+ width: root.boxSize
+ height: root.boxSize
+ anchors.centerIn: parent
+ color: Qt.hsla(box.t, 0.5, 0.5);
+ border.color: "white"
+ antialiasing: true;
+ rotation: box.t * 360;
+// RotationAnimator on rotation {
+// from: box.t * 360;
+// to: box.t * 360 + 360;
+// duration: 7592;
+// loops: Animation.Infinite
+// }
+ }
+ }
+ }
+ }
+}
diff --git a/src/quick/doc/snippets/qml/opacitymask.qml b/src/quick/doc/snippets/qml/opacitymask.qml
new file mode 100644
index 0000000000..e458f810ea
--- /dev/null
+++ b/src/quick/doc/snippets/qml/opacitymask.qml
@@ -0,0 +1,114 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Gunnar Sletta <gunnar@sletta.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+
+Item {
+ id: root
+ width: 480
+ height: 320
+
+ // The checkers background
+ ShaderEffect {
+ id: tileBackground
+ anchors.fill: parent
+
+ property real tileSize: 20
+ property color color1: Qt.hsla(0, 0, 0.1);
+ property color color2: Qt.hsla(0, 0, 0.2);
+
+ property size pixelSize: Qt.size(width / tileSize, height / tileSize);
+
+ fragmentShader:
+ "
+ uniform lowp vec4 color1;
+ uniform lowp vec4 color2;
+ uniform highp vec2 pixelSize;
+ varying highp vec2 qt_TexCoord0;
+ void main() {
+ highp vec2 tc = sign(sin(3.14152 * qt_TexCoord0 * pixelSize));
+ if (tc.x != tc.y)
+ gl_FragColor = color1;
+ else
+ gl_FragColor = color2;
+ }
+ "
+ }
+
+//! [1]
+ Rectangle {
+ id: gradientRect;
+ width: 10
+ height: 10
+ gradient: Gradient {
+ GradientStop { position: 0; color: "white" }
+ GradientStop { position: 1; color: "steelblue" }
+ }
+ visible: false; // should not be visible on screen.
+ layer.enabled: true;
+ layer.smooth: true
+ }
+
+ Text {
+ id: textItem
+ font.pixelSize: 48
+ text: "Gradient Text"
+ anchors.centerIn: parent
+ layer.enabled: true
+ // This item should be used as the 'mask'
+ layer.samplerName: "maskSource"
+ layer.effect: ShaderEffect {
+ property var colorSource: gradientRect;
+ fragmentShader: "
+ uniform lowp sampler2D colorSource;
+ uniform lowp sampler2D maskSource;
+ uniform lowp float qt_Opacity;
+ varying highp vec2 qt_TexCoord0;
+ void main() {
+ gl_FragColor =
+ texture2D(colorSource, qt_TexCoord0)
+ * texture2D(maskSource, qt_TexCoord0).a
+ * qt_Opacity;
+ }
+ "
+ }
+ }
+//! [1]
+}
diff --git a/src/quick/doc/src/concepts/input/focus.qdoc b/src/quick/doc/src/concepts/input/focus.qdoc
index 065651c826..748c8eb53c 100644
--- a/src/quick/doc/src/concepts/input/focus.qdoc
+++ b/src/quick/doc/src/concepts/input/focus.qdoc
@@ -172,7 +172,7 @@ See \l{Qt Quick Examples - Key Interaction} for a
demonstration of moving keyboard focus between multiple areas using FocusScope
types.
-\section1 Advanced uses of Focus Scopes
+\section1 Advanced Uses of Focus Scopes
Focus scopes allow focus to allocation to be easily partitioned. Several
QML items use it to this effect.
diff --git a/src/quick/doc/src/concepts/modelviewsdata/cppmodels.qdoc b/src/quick/doc/src/concepts/modelviewsdata/cppmodels.qdoc
index 49e4998ee1..dcc7a592e6 100644
--- a/src/quick/doc/src/concepts/modelviewsdata/cppmodels.qdoc
+++ b/src/quick/doc/src/concepts/modelviewsdata/cppmodels.qdoc
@@ -146,14 +146,14 @@ within the Qt install directory.
QAbstractItemModel presents a hierarchy of tables, but the views currently provided by QML
can only display list data.
In order to display the child lists of a hierarchical model,
-use the VisualDataModel type, which provides the following properties and functions to be used
+use the DelegateModel QML type, which provides the following properties and functions to be used
with list models of QAbstractItemModel type:
\list
\li \e hasModelChildren role property to determine whether a node has child nodes.
-\li \l VisualDataModel::rootIndex allows the root node to be specified
-\li \l VisualDataModel::modelIndex() returns a QModelIndex which can be assigned to VisualDataModel::rootIndex
-\li \l VisualDataModel::parentModelIndex() returns a QModelIndex which can be assigned to VisualDataModel::rootIndex
+\li \l DelegateModel::rootIndex allows the root node to be specified
+\li \l DelegateModel::modelIndex() returns a QModelIndex which can be assigned to DelegateModel::rootIndex
+\li \l DelegateModel::parentModelIndex() returns a QModelIndex which can be assigned to DelegateModel::rootIndex
\endlist
\section2 Exposing C++ Data Models to QML
diff --git a/src/quick/doc/src/concepts/positioning/righttoleft.qdoc b/src/quick/doc/src/concepts/positioning/righttoleft.qdoc
index 8f55cc8dd7..d6b1753ee3 100644
--- a/src/quick/doc/src/concepts/positioning/righttoleft.qdoc
+++ b/src/quick/doc/src/concepts/positioning/righttoleft.qdoc
@@ -69,7 +69,7 @@ the effective alignment of the text element that takes the mirroring into accoun
\snippet qml/righttoleft.qml 0
-\section1 Layout direction of positioners and views
+\section1 Layout Direction of Positioners and Views
(This applies to the \l Row, \l Grid, \l Flow, \l ListView and \l GridView types.)
@@ -85,7 +85,7 @@ views that takes the mirroring into account can be read from the \c effectiveLay
\snippet qml/righttoleft.qml 1
-\section1 Layout mirroring
+\section1 Layout Mirroring
The attached property \l LayoutMirroring is provided as a convenience for easily implementing right-to-left
support for existing left-to-right Qt Quick applications. It mirrors the behavior of \l {anchor-layout}
@@ -127,7 +127,7 @@ the animations and transitions continue to work as expected. If you do not have
right-to-left support for your application, it may be better to just keep the application layouts left
aligned and just make sure that text is translated and aligned properly.
-\section1 Mirroring icons
+\section1 Mirroring Icons
(This applies to \l Image, \l BorderImage and \l AnimatedImage types.)
@@ -136,7 +136,7 @@ The painting of these icons can be mirrored with a dedicated \c mirror property
\snippet qml/righttoleft.qml 5
-\section1 Default layout direction
+\section1 Default Layout Direction
The \l {QtQml::Qt::application}{Qt.application.layoutDirection} property can be used to query the active layout direction of the
application. It is based on QGuiApplication::layoutDirection(), which most commonly determines the layout
diff --git a/src/quick/doc/src/dynamicview-tutorial.qdoc b/src/quick/doc/src/dynamicview-tutorial.qdoc
index cf1115cf4a..619f0abd4b 100644
--- a/src/quick/doc/src/dynamicview-tutorial.qdoc
+++ b/src/quick/doc/src/dynamicview-tutorial.qdoc
@@ -136,7 +136,7 @@ so that is above other items in the stacking order and isn't obscured as it is d
The next step in our application to move items within the list as they're dragged so that we
can re-order the list. To achieve this we introduce three new types to our application;
-VisualDataModel, \l Drag and DropArea.
+DelegateModel, \l Drag and DropArea.
\snippet tutorials/dynamicview/dynamicview3/dynamicview.qml 0
\snippet tutorials/dynamicview/dynamicview3/dynamicview.qml 1
@@ -162,17 +162,17 @@ to the index of the item it was dragged over.
\snippet tutorials/dynamicview/dynamicview3/dynamicview.qml 3
-To move the items within the view we use a VisualDataModel. The VisualDataModel type is used by
+To move the items within the view we use a DelegateModel. The DelegateModel type is used by
the view types to instantiate delegate items from model data and when constructed explicitly can
be used to filter and re-order the model items provided to ListView. The
-\l {QtQuick::VisualDataModel::items}{items} property of VisualDataModel provides access to the
+\l {QtQuick::DelegateModel::items}{items} property of DelegateModel provides access to the
view's items and allows us to change the visible order without modifying the source model. To
-determine the current visible index of the items we use \l {QtQuick::VisualDataModel::itemsIndex}
-{itemsIndex} property on the VisualDataModel attached property of the delegate item.
+determine the current visible index of the items we use \l {QtQuick::DelegateModel::itemsIndex}
+{itemsIndex} property on the DelegateModel attached property of the delegate item.
-To utilize a VisualDataModel with a ListView we bind it to the \l {QtQuick::ListView::model}{model}
-property of the view and bind the \l {QtQuick::VisualDataModel::model}{model} and
-\l {QtQuick::VisualDataModel::delegate}{delegate} to the VisualDataModel.
+To utilize a DelegateModel with a ListView we bind it to the \l {QtQuick::ListView::model}{model}
+property of the view and bind the \l {QtQuick::DelegateModel::model}{model} and
+\l {QtQuick::DelegateModel::delegate}{delegate} to the DelegateModel.
\snippet tutorials/dynamicview/dynamicview3/dynamicview.qml 4
@@ -185,16 +185,16 @@ property of the view and bind the \l {QtQuick::VisualDataModel::model}{model} an
\example tutorials/dynamicview/dynamicview4
-Drag and drop isn't the only way items in a view can be re-ordered, using a VisualDataModel it is
-also possible to sort items based on model data. To do that we extend our VisualDataModel instance
+Drag and drop isn't the only way items in a view can be re-ordered, using a DelegateModel it is
+also possible to sort items based on model data. To do that we extend our DelegateModel instance
like this:
\snippet tutorials/dynamicview/dynamicview4/dynamicview.qml 0
\section2 Walkthrough
-Items in a VisualDataModel are filtered into groups represented by the VisualDataGroup type,
-normally all items in the model belong to a default \l {QtQuick::VisualDataModel::items}{items}
+Items in a DelegateModel are filtered into groups represented by the DelegateModelGroup type,
+normally all items in the model belong to a default \l {QtQuick::DelegateModel::items}{items}
group but this default can be changed with the includeByDefault property. To implement our sorting
we want items to first be added to an unsorted group from where we can transfer them to a sorted
position in the items group. To do that we clear includeByDefault on the items group and set it on
@@ -208,7 +208,7 @@ item and then transfer the item to the items group before moving it to the pre-d
repeat until the unsorted group is empty.
To find the insert position for an item we request a handle for the item from the unsorted group
-with the \l {QtQuick::VisualDataModel::get} {get} function. Through the model property on this
+with the \l {QtQuick::DelegateModel::get} {get} function. Through the model property on this
handle we can access the same model data that is available in a delegate instance of that item and
compare against other items to determine relative position.
@@ -219,8 +219,8 @@ of the list. In this example it can be one of the following:
\snippet tutorials/dynamicview/dynamicview4/dynamicview.qml 4
-A sort is triggered whenever new items are added to the unsorted VisualDataGroup which we are
-notified of by the \l {QtQuick::VisualDataGroup::onChanged}{onChanged} handler. If no sort
+A sort is triggered whenever new items are added to the unsorted DelegateModel which we are
+notified of by the \l {QtQuick::DelegateModelGroup::onChanged}{onChanged} handler. If no sort
function is currently selected we simply transfer all items from the unsorted group to the items
group, otherwise we call sort with the selected sort function.
@@ -228,8 +228,8 @@ group, otherwise we call sort with the selected sort function.
Finally when the selected sort order changes we can trigger a full re-sort of the list by moving
all items from the items group to the unsorted group, which will trigger the
-\l {QtQuick::VisualDataGroup::onChanged}{onChanged} handler and transfer the items back to the
-items group in correct order. Note that the \l {QtQuick::VisualDataGroup::onChanged}{onChanged}
+\l {QtQuick::DelegateModelGroup::onChanged}{onChanged} handler and transfer the items back to the
+items group in correct order. Note that the \l {QtQuick::DelegateModelGroup::onChanged}{onChanged}
handler will not be invoked recursively so there's no issue with it being invoked during a sort.
\snippet tutorials/dynamicview/dynamicview4/dynamicview.qml 6
diff --git a/src/quick/items/context2d/qquickcanvasitem.cpp b/src/quick/items/context2d/qquickcanvasitem.cpp
index 8249e268e8..15eb28350e 100644
--- a/src/quick/items/context2d/qquickcanvasitem.cpp
+++ b/src/quick/items/context2d/qquickcanvasitem.cpp
@@ -275,7 +275,7 @@ QQuickCanvasItemPrivate::~QQuickCanvasItemPrivate()
\l{http://en.wikipedia.org/wiki/Screen_tearing}{screen tearing}) which will further
impact pixel operations with \c Canvas.FrambufferObject render target.
- \section1 Tips for Porting Existing HTML5 Canvas applications
+ \section1 Tips for Porting Existing HTML5 Canvas Applications
Although the Canvas item is provides a HTML5 like API, HTML5 canvas
applications need to be modified to run in the Canvas item:
@@ -667,7 +667,10 @@ void QQuickCanvasItem::itemChange(QQuickItem::ItemChange change, const QQuickIte
return;
d->window = value.window;
- if (d->window->isSceneGraphInitialized())
+ QSGRenderContext *context = QQuickWindowPrivate::get(d->window)->context;
+
+ // Rendering to FramebufferObject needs a valid OpenGL context.
+ if (context != 0 && (d->renderTarget != FramebufferObject || context->isValid()))
sceneGraphInitialized();
else
connect(d->window, SIGNAL(sceneGraphInitialized()), SLOT(sceneGraphInitialized()));
@@ -746,7 +749,7 @@ QSGNode *QQuickCanvasItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData
QQuickContext2D *ctx = qobject_cast<QQuickContext2D *>(d->context);
QQuickContext2DTexture *factory = ctx->texture();
- QSGTexture *texture = factory->textureForNextFrame(node->texture());
+ QSGTexture *texture = factory->textureForNextFrame(node->texture(), window());
if (!texture) {
delete node;
d->node = 0;
diff --git a/src/quick/items/context2d/qquickcontext2d.cpp b/src/quick/items/context2d/qquickcontext2d.cpp
index 28c84facb5..d9ac3abdc3 100644
--- a/src/quick/items/context2d/qquickcontext2d.cpp
+++ b/src/quick/items/context2d/qquickcontext2d.cpp
@@ -3548,7 +3548,7 @@ void QQuickContext2D::clip()
state.clip = true;
state.clipPath = clipPath;
}
- buffer()->clip(state.clipPath);
+ buffer()->clip(state.clip, state.clipPath);
}
void QQuickContext2D::stroke()
@@ -4283,8 +4283,8 @@ void QQuickContext2D::popState()
if (newState.miterLimit != state.miterLimit)
buffer()->setMiterLimit(newState.miterLimit);
- if (newState.clip && (!state.clip || newState.clipPath != state.clipPath))
- buffer()->clip(newState.clipPath);
+ if (newState.clip != state.clip || newState.clipPath != state.clipPath)
+ buffer()->clip(newState.clip, newState.clipPath);
if (newState.shadowBlur != state.shadowBlur)
buffer()->setShadowBlur(newState.shadowBlur);
diff --git a/src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp b/src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp
index 3fb230b928..eac5e2cef8 100644
--- a/src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp
+++ b/src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp
@@ -207,6 +207,7 @@ void QQuickContext2DCommandBuffer::setPainterState(QPainter* p, const QQuickCont
if (state.globalCompositeOperation != p->compositionMode())
p->setCompositionMode(state.globalCompositeOperation);
+ p->setClipping(state.clip);
if (state.clip)
p->setClipPath(state.clipPath);
}
@@ -383,9 +384,11 @@ void QQuickContext2DCommandBuffer::replay(QPainter* p, QQuickContext2D::State& s
}
case QQuickContext2D::Clip:
{
+ state.clip = takeBool();
state.clipPath = takePath();
- p->setClipping(true);
- p->setClipPath(state.clipPath);
+ p->setClipping(state.clip);
+ if (state.clip)
+ p->setClipPath(state.clipPath);
break;
}
case QQuickContext2D::GlobalAlpha:
diff --git a/src/quick/items/context2d/qquickcontext2dcommandbuffer_p.h b/src/quick/items/context2d/qquickcontext2dcommandbuffer_p.h
index 9b2fde33d8..4e6232ac7f 100644
--- a/src/quick/items/context2d/qquickcontext2dcommandbuffer_p.h
+++ b/src/quick/items/context2d/qquickcontext2dcommandbuffer_p.h
@@ -145,9 +145,10 @@ public:
pathes << path;
}
- inline void clip(const QPainterPath& path)
+ inline void clip(bool enabled, const QPainterPath& path)
{
commands << QQuickContext2D::Clip;
+ bools << enabled;
pathes << path;
}
diff --git a/src/quick/items/context2d/qquickcontext2dtexture.cpp b/src/quick/items/context2d/qquickcontext2dtexture.cpp
index a3b316a217..1dd8e50387 100644
--- a/src/quick/items/context2d/qquickcontext2dtexture.cpp
+++ b/src/quick/items/context2d/qquickcontext2dtexture.cpp
@@ -427,7 +427,7 @@ QVector2D QQuickContext2DFBOTexture::scaleFactor() const
m_fbo->height() / m_fboSize.height());
}
-QSGTexture *QQuickContext2DFBOTexture::textureForNextFrame(QSGTexture *lastTexture)
+QSGTexture *QQuickContext2DFBOTexture::textureForNextFrame(QSGTexture *lastTexture, QQuickWindow *)
{
QSGPlainTexture *texture = static_cast<QSGPlainTexture *>(lastTexture);
@@ -666,22 +666,15 @@ void QQuickContext2DImageTexture::grabImage(const QRectF& rf)
QQuickContext2D::mutex.unlock();
}
-QSGTexture *QQuickContext2DImageTexture::textureForNextFrame(QSGTexture *last)
+QSGTexture *QQuickContext2DImageTexture::textureForNextFrame(QSGTexture *last, QQuickWindow *window)
{
- QSGPlainTexture *texture = static_cast<QSGPlainTexture *>(last);
-
if (m_onCustomThread)
m_mutex.lock();
- if (!texture) {
- texture = new QSGPlainTexture();
- texture->setHasAlphaChannel(true);
- m_dirtyTexture = true;
- }
- if (m_dirtyTexture) {
- texture->setImage(m_displayImage);
- m_dirtyTexture = false;
- }
+ delete last;
+
+ QSGTexture *texture = window->createTextureFromImage(m_displayImage, QQuickWindow::TextureCanUseAtlas);
+ m_dirtyTexture = false;
if (m_onCustomThread)
m_mutex.unlock();
diff --git a/src/quick/items/context2d/qquickcontext2dtexture_p.h b/src/quick/items/context2d/qquickcontext2dtexture_p.h
index 10ac246d1b..3ff0cb12c1 100644
--- a/src/quick/items/context2d/qquickcontext2dtexture_p.h
+++ b/src/quick/items/context2d/qquickcontext2dtexture_p.h
@@ -102,7 +102,7 @@ public:
bool isOnCustomThread() const { return m_onCustomThread; }
// Called during sync() on the scene graph thread while GUI is blocked.
- virtual QSGTexture *textureForNextFrame(QSGTexture *lastFrame) = 0;
+ virtual QSGTexture *textureForNextFrame(QSGTexture *lastFrame, QQuickWindow *window) = 0;
bool event(QEvent *e);
void initializeOpenGL(QOpenGLContext *gl, QOffscreenSurface *s) {
@@ -173,7 +173,7 @@ public:
virtual void compositeTile(QQuickContext2DTile* tile);
QSize adjustedTileSize(const QSize &ts);
- QSGTexture *textureForNextFrame(QSGTexture *);
+ QSGTexture *textureForNextFrame(QSGTexture *, QQuickWindow *window);
protected:
QVector2D scaleFactor() const Q_DECL_OVERRIDE;
@@ -209,7 +209,7 @@ public:
virtual void endPainting();
virtual void compositeTile(QQuickContext2DTile* tile);
- virtual QSGTexture *textureForNextFrame(QSGTexture *lastFrame);
+ virtual QSGTexture *textureForNextFrame(QSGTexture *lastFrame, QQuickWindow *window);
public Q_SLOTS:
virtual void grabImage(const QRectF& region = QRectF());
diff --git a/src/quick/items/qquickborderimage.cpp b/src/quick/items/qquickborderimage.cpp
index 50a0a76267..8d8e4b6a02 100644
--- a/src/quick/items/qquickborderimage.cpp
+++ b/src/quick/items/qquickborderimage.cpp
@@ -562,7 +562,9 @@ QSGNode *QQuickBorderImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDat
// Don't implicitly create the scalegrid in the rendering thread...
QRectF innerSourceRect(0, 0, 1, 1);
QRectF innerTargetRect(0, 0, width(), height());
- int borderLeft, borderTop, borderRight, borderBottom;
+ int borderLeft = 0, borderTop = 0, borderRight = 0, borderBottom = 0;
+
+ bool updateNode = !oldNode;
if (d->border) {
const QQuickScaleGrid *border = d->getScaleGrid();
@@ -579,11 +581,17 @@ QSGNode *QQuickBorderImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDat
borderTop,
qMax<qreal>(0, width() - border->right() - border->left()),
qMax<qreal>(0, height() - border->bottom() - border->top()));
+
+ if (innerSourceRect != d->oldInnerSourceRect || innerTargetRect != d->oldInnerTargetRect)
+ updateNode = true;
+ d->oldInnerSourceRect = innerSourceRect;
+ d->oldInnerTargetRect = innerTargetRect;
}
bool updatePixmap = d->pixmapChanged;
d->pixmapChanged = false;
- if (!oldNode) {
+ if (updateNode) {
+ delete oldNode;
oldNode = new QSGNode;
updatePixmap = true;
@@ -591,33 +599,130 @@ QSGNode *QQuickBorderImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDat
d->regions[i].node = 0;
if (innerSourceRect.left() > 0) {
- if (innerSourceRect.top() > 0)
- d->regions[0].node = d->sceneGraphContext()->createImageNode();
- if (innerSourceRect.bottom() < 1)
- d->regions[6].node = d->sceneGraphContext()->createImageNode();
+ if (innerSourceRect.top() > 0) {
+ QRectF rect(0,
+ 0,
+ innerTargetRect.left(),
+ innerTargetRect.top());
+
+ if (!rect.isEmpty()) {
+ d->regions[0].node = d->sceneGraphContext()->createImageNode();
+ d->regions[0].node->setTargetRect(rect);
+ d->regions[0].node->setInnerTargetRect(rect);
+ d->regions[0].targetRect = rect;
+ }
+ }
+
+ if (innerSourceRect.bottom() < 1) {
+ QRectF rect(0,
+ innerTargetRect.bottom(),
+ innerTargetRect.left(),
+ height() - innerTargetRect.height() - innerTargetRect.top());
+
+ if (!rect.isEmpty()) {
+ d->regions[6].node = d->sceneGraphContext()->createImageNode();
+ d->regions[6].node->setTargetRect(rect);
+ d->regions[6].node->setInnerTargetRect(rect);
+ d->regions[6].targetRect = rect;
+ }
+ }
- if (innerSourceRect.top() < innerSourceRect.bottom())
- d->regions[3].node = d->sceneGraphContext()->createImageNode();
+ if (innerSourceRect.top() < innerSourceRect.bottom()) {
+ QRectF rect(0,
+ innerTargetRect.top(),
+ innerTargetRect.left(),
+ innerTargetRect.height());
+
+ if (!rect.isEmpty()) {
+ d->regions[3].node = d->sceneGraphContext()->createImageNode();
+ d->regions[3].node->setTargetRect(rect);
+ d->regions[3].node->setInnerTargetRect(rect);
+ d->regions[3].targetRect = rect;
+ }
+ }
}
if (innerSourceRect.right() < 1) {
- if (innerSourceRect.top() > 0)
- d->regions[2].node = d->sceneGraphContext()->createImageNode();
- if (innerSourceRect.bottom() < 1)
- d->regions[8].node = d->sceneGraphContext()->createImageNode();
+ if (innerSourceRect.top() > 0) {
+ QRectF rect(innerTargetRect.right(),
+ 0,
+ width() - innerTargetRect.width() - innerTargetRect.left(),
+ innerTargetRect.top());
+
+ if (!rect.isEmpty()) {
+ d->regions[2].node = d->sceneGraphContext()->createImageNode();
+ d->regions[2].node->setTargetRect(rect);
+ d->regions[2].node->setInnerTargetRect(rect);
+ d->regions[2].targetRect = rect;
+ }
+ }
- if (innerSourceRect.top() < innerSourceRect.bottom())
- d->regions[5].node = d->sceneGraphContext()->createImageNode();
+ if (innerSourceRect.bottom() < 1) {
+ QRectF rect(innerTargetRect.right(),
+ innerTargetRect.bottom(),
+ width() - innerTargetRect.width() - innerTargetRect.left(),
+ height() - innerTargetRect.height() - innerTargetRect.top());
+
+ if (!rect.isEmpty()) {
+ d->regions[8].node = d->sceneGraphContext()->createImageNode();
+ d->regions[8].node->setTargetRect(rect);
+ d->regions[8].node->setInnerTargetRect(rect);
+ d->regions[8].targetRect = rect;
+ }
+ }
+
+ if (innerSourceRect.top() < innerSourceRect.bottom()) {
+ QRectF rect(innerTargetRect.right(),
+ innerTargetRect.top(),
+ width() - innerTargetRect.width() - innerTargetRect.left(),
+ innerTargetRect.height());
+
+ if (!rect.isEmpty()) {
+ d->regions[5].node = d->sceneGraphContext()->createImageNode();
+ d->regions[5].node->setTargetRect(rect);
+ d->regions[5].node->setInnerTargetRect(rect);
+ d->regions[5].targetRect = rect;
+ }
+ }
}
- if (innerSourceRect.top() > 0 && innerSourceRect.left() < innerSourceRect.right())
- d->regions[1].node = d->sceneGraphContext()->createImageNode();
+ if (innerSourceRect.top() > 0 && innerSourceRect.left() < innerSourceRect.right()) {
+ QRectF rect(innerTargetRect.left(),
+ 0,
+ innerTargetRect.width(),
+ innerTargetRect.top());
+
+ if (!rect.isEmpty()) {
+ d->regions[1].node = d->sceneGraphContext()->createImageNode();
+ d->regions[1].node->setTargetRect(rect);
+ d->regions[1].node->setInnerTargetRect(rect);
+ d->regions[1].targetRect = rect;
+ }
+ }
- if (innerSourceRect.bottom() < 1 && innerSourceRect.left() < innerSourceRect.right())
- d->regions[7].node = d->sceneGraphContext()->createImageNode();
+ if (innerSourceRect.bottom() < 1 && innerSourceRect.left() < innerSourceRect.right()) {
+ QRectF rect(innerTargetRect.left(),
+ innerTargetRect.bottom(),
+ innerTargetRect.width(),
+ height() - innerTargetRect.height() - innerTargetRect.top());
+
+ if (!rect.isEmpty()) {
+ d->regions[7].node = d->sceneGraphContext()->createImageNode();
+ d->regions[7].node->setTargetRect(rect);
+ d->regions[7].node->setInnerTargetRect(rect);
+ d->regions[7].targetRect = rect;
+ }
+ }
- if (innerSourceRect.left() < innerSourceRect.right() && innerSourceRect.top() < innerSourceRect.bottom())
- d->regions[4].node = d->sceneGraphContext()->createImageNode();
+ if (innerSourceRect.left() < innerSourceRect.right()
+ && innerSourceRect.top() < innerSourceRect.bottom()) {
+ if (!innerTargetRect.isEmpty()) {
+ d->regions[4].node = d->sceneGraphContext()->createImageNode();
+ d->regions[4].node->setInnerTargetRect(innerTargetRect);
+ d->regions[4].node->setTargetRect(innerTargetRect);
+ d->regions[4].targetRect = innerTargetRect;
+ }
+ }
for (int i=0; i<9; ++i) {
if (d->regions[i].node != 0)
@@ -638,14 +743,6 @@ QSGNode *QQuickBorderImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDat
if (d->regions[3].node == 0 && d->regions[6].node == 0)
antialiasing |= QSGImageNode::AntialiasingBottom;
d->regions[0].node->setAntialiasing(antialiasing);
-
- QRectF rect(0,
- 0,
- innerTargetRect.left(),
- innerTargetRect.top());
- d->regions[0].node->setTargetRect(rect);
- d->regions[0].node->setInnerTargetRect(rect);
- d->regions[0].targetRect = rect;
}
if (d->regions[1].node != 0) {
@@ -660,14 +757,6 @@ QSGNode *QQuickBorderImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDat
if (d->regions[4].node == 0 && d->regions[7].node == 0)
antialiasing |= QSGImageNode::AntialiasingBottom;
d->regions[1].node->setAntialiasing(antialiasing);
-
- QRectF rect(innerTargetRect.left(),
- 0,
- innerTargetRect.width(),
- innerTargetRect.top());
- d->regions[1].node->setTargetRect(rect);
- d->regions[1].node->setInnerTargetRect(rect);
- d->regions[1].targetRect = rect;
}
if (d->regions[2].node != 0) {
@@ -680,14 +769,6 @@ QSGNode *QQuickBorderImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDat
if (d->regions[5].node == 0 && d->regions[8].node == 0)
antialiasing |= QSGImageNode::AntialiasingBottom;
d->regions[2].node->setAntialiasing(antialiasing);
-
- QRectF rect(innerTargetRect.right(),
- 0,
- width() - innerTargetRect.width() - innerTargetRect.left(),
- innerTargetRect.top());
- d->regions[2].node->setTargetRect(rect);
- d->regions[2].node->setInnerTargetRect(rect);
- d->regions[2].targetRect = rect;
}
if (d->regions[3].node != 0) {
@@ -702,14 +783,6 @@ QSGNode *QQuickBorderImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDat
if (d->regions[0].node == 0)
antialiasing |= QSGImageNode::AntialiasingTop;
d->regions[3].node->setAntialiasing(antialiasing);
-
- QRectF rect(0,
- innerTargetRect.top(),
- innerTargetRect.left(),
- innerTargetRect.height());
- d->regions[3].node->setTargetRect(rect);
- d->regions[3].node->setInnerTargetRect(rect);
- d->regions[3].targetRect = rect;
}
if (d->regions[4].node != 0) {
@@ -731,10 +804,6 @@ QSGNode *QQuickBorderImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDat
if (d->regions[7].node == 0)
antialiasing |= QSGImageNode::AntialiasingBottom;
d->regions[4].node->setAntialiasing(antialiasing);
-
- d->regions[4].node->setInnerTargetRect(innerTargetRect);
- d->regions[4].node->setTargetRect(innerTargetRect);
- d->regions[4].targetRect = innerTargetRect;
}
if (d->regions[5].node != 0) {
@@ -749,14 +818,6 @@ QSGNode *QQuickBorderImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDat
if (d->regions[8].node == 0)
antialiasing |= QSGImageNode::AntialiasingBottom;
d->regions[5].node->setAntialiasing(antialiasing);
-
- QRectF rect(innerTargetRect.right(),
- innerTargetRect.top(),
- width() - innerTargetRect.width() - innerTargetRect.left(),
- innerTargetRect.height());
- d->regions[5].node->setTargetRect(rect);
- d->regions[5].node->setInnerTargetRect(rect);
- d->regions[5].targetRect = rect;
}
if (d->regions[6].node != 0) {
@@ -769,14 +830,6 @@ QSGNode *QQuickBorderImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDat
if (d->regions[3].node == 0 && d->regions[0].node == 0)
antialiasing |= QSGImageNode::AntialiasingTop;
d->regions[6].node->setAntialiasing(antialiasing);
-
- QRectF rect(0,
- innerTargetRect.bottom(),
- innerTargetRect.left(),
- height() - innerTargetRect.height() - innerTargetRect.top());
- d->regions[6].node->setTargetRect(rect);
- d->regions[6].node->setInnerTargetRect(rect);
- d->regions[6].targetRect = rect;
}
if (d->regions[7].node != 0) {
@@ -791,14 +844,6 @@ QSGNode *QQuickBorderImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDat
if (d->regions[4].node == 0 && d->regions[1].node == 0)
antialiasing |= QSGImageNode::AntialiasingTop;
d->regions[7].node->setAntialiasing(antialiasing);
-
- QRectF rect(innerTargetRect.left(),
- innerTargetRect.bottom(),
- innerTargetRect.width(),
- height() - innerTargetRect.height() - innerTargetRect.top());
- d->regions[7].node->setTargetRect(rect);
- d->regions[7].node->setInnerTargetRect(rect);
- d->regions[7].targetRect = rect;
}
if (d->regions[8].node != 0) {
@@ -811,14 +856,6 @@ QSGNode *QQuickBorderImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDat
if (d->regions[5].node == 0 && d->regions[2].node == 0)
antialiasing |= QSGImageNode::AntialiasingTop;
d->regions[8].node->setAntialiasing(antialiasing);
-
- QRectF rect(innerTargetRect.right(),
- innerTargetRect.bottom(),
- width() - innerTargetRect.width() - innerTargetRect.left(),
- height() - innerTargetRect.height() - innerTargetRect.top());
- d->regions[8].node->setTargetRect(rect);
- d->regions[8].node->setInnerTargetRect(rect);
- d->regions[8].targetRect = rect;
}
for (int i=0; i<9; ++i) {
diff --git a/src/quick/items/qquickdrag.cpp b/src/quick/items/qquickdrag.cpp
index c85b1416f6..e49347351c 100644
--- a/src/quick/items/qquickdrag.cpp
+++ b/src/quick/items/qquickdrag.cpp
@@ -112,23 +112,23 @@ public:
\ingroup qtquick-input
\brief For specifying drag and drop events for moved Items
- Using the Drag attached property any Item can be made a source of drag and drop
+ Using the Drag attached property, any Item can be made a source of drag and drop
events within a scene.
- When a drag is \l active on an item any change in that item's position will
+ When a drag is \l active on an item, any change in that item's position will
generate a drag event that will be sent to any DropArea that intersects
with the new position of the item. Other items which implement drag and
drop event handlers can also receive these events.
The following snippet shows how an item can be dragged with a MouseArea.
- However, dragging is not limited to mouse drags, anything that can move an item
- can generate drag events, this can include touch events, animations and bindings.
+ However, dragging is not limited to mouse drags; anything that can move an item
+ can generate drag events, including touch events, animations and bindings.
\snippet qml/drag.qml 0
A drag can be terminated either by canceling it with Drag.cancel() or setting
Drag.active to false, or it can be terminated with a drop event by calling
- Drag.drop(). If the drop event is accepted Drag.drop() will return the
+ Drag.drop(). If the drop event is accepted, Drag.drop() will return the
\l {supportedActions}{drop action} chosen by the recipient of the event,
otherwise it will return Qt.IgnoreAction.
@@ -314,7 +314,8 @@ void QQuickDragAttached::setActive(bool active)
\qmlattachedproperty Object QtQuick::Drag::source
This property holds an object that is identified to recipients of drag events as
- the source of the events. By default this is the item Drag property is attached to.
+ the source of the events. By default this is the item that the Drag
+ property is attached to.
Changing the source while a drag is active will reset the sequence of drag events by
sending a drag leave event followed by a drag enter event with the new source.
diff --git a/src/quick/items/qquickframebufferobject.cpp b/src/quick/items/qquickframebufferobject.cpp
index da1709f055..dc4668be3f 100644
--- a/src/quick/items/qquickframebufferobject.cpp
+++ b/src/quick/items/qquickframebufferobject.cpp
@@ -254,6 +254,7 @@ QSGNode *QQuickFramebufferObject::updatePaintNode(QSGNode *node, UpdatePaintNode
n->fbo = 0;
delete n->msDisplayFbo;
n->msDisplayFbo = 0;
+ n->invalidatePending = false;
}
}
diff --git a/src/quick/items/qquickgridview.cpp b/src/quick/items/qquickgridview.cpp
index db8cc0532e..e3af926e22 100644
--- a/src/quick/items/qquickgridview.cpp
+++ b/src/quick/items/qquickgridview.cpp
@@ -1173,7 +1173,7 @@ bool QQuickGridViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExte
fully outside the view.
- \section1 GridView layouts
+ \section1 GridView Layouts
The layout of the items in a GridView can be controlled by these properties:
diff --git a/src/quick/items/qquickimagebase_p_p.h b/src/quick/items/qquickimagebase_p_p.h
index f30eacb4ac..ec2f0bb73e 100644
--- a/src/quick/items/qquickimagebase_p_p.h
+++ b/src/quick/items/qquickimagebase_p_p.h
@@ -75,6 +75,8 @@ public:
QSize sourcesize;
QSize oldSourceSize;
qreal devicePixelRatio;
+ QRectF oldInnerSourceRect;
+ QRectF oldInnerTargetRect;
bool async : 1;
bool cache : 1;
bool mirror: 1;
diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp
index d45fb31fd9..b8362c9dac 100644
--- a/src/quick/items/qquickitem.cpp
+++ b/src/quick/items/qquickitem.cpp
@@ -397,7 +397,7 @@ void QQuickItemKeyFilter::componentComplete()
\c KeyNavigation.BeforeItem allows the event to be used for key navigation
before the item, rather than after.
- If item to which the focus is switching is not enabled or visible, an attempt will
+ If the item to which the focus is switching is not enabled or visible, an attempt will
be made to skip this item and focus on the next. This is possible if there are
a chain of items with the same KeyNavigation handler. If multiple items in a row are not enabled
or visible, they will also be skipped.
@@ -405,7 +405,7 @@ void QQuickItemKeyFilter::componentComplete()
KeyNavigation will implicitly set the other direction to return focus to this item. So if you set
\l left to another item, \l right will be set on that item's KeyNavigation to set focus back to this
item. However, if that item's KeyNavigation has had right explicitly set then no change will occur.
- This means that the above example could have been written, with the same behaviour, without specifying
+ This means that the example above could achieve the same behavior without specifying
KeyNavigation.right or KeyNavigation.down for any of the items.
\sa {Keys}{Keys attached property}
@@ -887,6 +887,8 @@ bool QQuickKeysAttached::isConnected(const char *signalName)
handling. If the item accepts the key event it will not be
handled by the Keys attached property handler.
\endlist
+
+ \sa {Key Handling Priorities}
*/
/*!
@@ -914,6 +916,9 @@ bool QQuickKeysAttached::isConnected(const char *signalName)
focus: true
}
\endqml
+
+ To see the order in which events are received when using forwardTo, see
+ \l {Key Handling Priorities}.
*/
/*!
@@ -1833,6 +1838,101 @@ void QQuickItemPrivate::updateSubFocusItem(QQuickItem *scope, bool focus)
their layouts.
See LayoutMirroring for more details.
+
+ \section1 Item Layers
+
+ An Item will normally be rendered directly into the window it
+ belongs to. However, by setting \l layer.enabled, it is possible
+ to delegate the item and its entire subtree into an offscreen
+ surface. Only the offscreen surface, a texture, will be then drawn
+ into the window.
+
+ If it is desired to have a texture size different from that of the
+ item, this is possible using \l layer.textureSize. To render only
+ a section of the item into the texture, use \l
+ layer.sourceRect. It is also possible to specify \l
+ layer.sourceRect so it extends beyond the bounds of the item. In
+ this case, the exterior will be padded with transparent pixels.
+
+ The item will use linear interpolation for scaling if
+ \l layer.smooth is set to \c true and will use mipmap for
+ downsampling if \l layer.mipmap is set to \c true. Mipmapping may
+ improve visual quality of downscaled items. For mipmapping of
+ single Image items, prefer Image::mipmap.
+
+ \section2 Layer Opacity vs Item Opacity
+
+ When applying \l opacity to an item hierarchy the opacity is
+ applied to each item individually. This can lead to undesired
+ visual results when the opacity is applied to a subtree. Consider
+ the following example:
+
+ \table
+ \row
+ \li \inlineimage qml-blending-nonlayered.png
+ \li \b {Non-layered Opacity} \snippet qml/layerblending.qml non-layered
+ \endtable
+
+ A layer is rendered with the root item's opacity being 1, and then
+ the root item's opacity is applied to the texture when it is
+ drawn. This means that fading in a large item hierarchy from
+ transparent to opaque, or vice versa, can be done without the
+ overlap artifacts that the normal item by item alpha blending
+ has. Here is the same example with layer enabled:
+
+ \table
+ \row
+ \li \image qml-blending-layered.png
+ \li \b {Layered Opacity} \snippet qml/layerblending.qml layered
+ \endtable
+
+ \section2 Combined with ShaderEffects
+
+ Setting \l layer.enabled to true will turn the item into a \l
+ {QQuickItem::isTextureProvider}{texture provider}, making it
+ possible to use the item directly as a texture, for instance
+ in combination with the ShaderEffect type.
+
+ It is possible to apply an effect on a layer at runtime using
+ layer.effect:
+
+ \snippet qml/layerwitheffect.qml 1
+
+ In this example, we implement the shader effect manually. The \l
+ {Qt Graphical Effects} module contains a suite of ready-made
+ effects for use with Qt Quick.
+
+ See ShaderEffect for more information about using effects.
+
+ \note \l layer.enabled is actually just a more convenient way of using
+ ShaderEffectSource.
+
+
+ \section2 Memory and Performance
+
+ When an item's layer is enabled, the scene graph will allocate memory
+ in the GPU equal to \c {width x height x 4}. In memory constrained
+ configurations, large layers should be used with care.
+
+ In the QPainter / QWidget world, it is some times favorable to
+ cache complex content in a pixmap, image or texture. In Qt Quick,
+ because of the techniques already applied by the \l {Qt Quick
+ Scene Graph Renderer} {scene graph renderer}, this will in most
+ cases not be the case. Excessive draw calls are already reduced
+ because of batching and a cache will in most cases end up blending
+ more pixels than the original content. The overhead of rendering
+ to an offscreen and the blending involved with drawing the
+ resulting texture is therefore often more costly than simply
+ letting the item and its children be drawn normally.
+
+ Also, an item using a layer can not be \l {Batching} {batched} during
+ rendering. This means that a scene with many layered items may
+ have performance problems.
+
+ Layering can be convenient and useful for visual effects, but
+ should in most cases be enabled for the duration of the effect and
+ disabled afterwards.
+
*/
/*!
@@ -7481,12 +7581,15 @@ void QQuickItemLayer::setMipmap(bool mipmap)
allow you to save some texture memory.
\list
- \li ShaderEffectSource.Alpha - GL_ALPHA
+ \li ShaderEffectSource.Alpha - GL_ALPHA;
\li ShaderEffectSource.RGB - GL_RGB
\li ShaderEffectSource.RGBA - GL_RGBA
\endlist
- \note Some OpenGL implementations do not support the GL_ALPHA format.
+ \note ShaderEffectSource.RGB and ShaderEffectSource.Alpha should
+ be used with caution, as support for these formats in the underlying
+ hardare and driver is often not present.
+
*/
void QQuickItemLayer::setFormat(QQuickShaderEffectSource::Format f)
diff --git a/src/quick/items/qquicklistview.cpp b/src/quick/items/qquicklistview.cpp
index 0037879fb3..851204ccde 100644
--- a/src/quick/items/qquicklistview.cpp
+++ b/src/quick/items/qquicklistview.cpp
@@ -1742,7 +1742,7 @@ bool QQuickListViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExte
nicely.
- \section1 ListView layouts
+ \section1 ListView Layouts
The layout of the items in a ListView can be controlled by these properties:
diff --git a/src/quick/items/qquickscreen.cpp b/src/quick/items/qquickscreen.cpp
index 0d9226d77f..926ac7b4ee 100644
--- a/src/quick/items/qquickscreen.cpp
+++ b/src/quick/items/qquickscreen.cpp
@@ -171,6 +171,9 @@ QT_BEGIN_NAMESPACE
change, then probably you are using a device which does not rotate its own
display. In that case you may need to use \l {Item::rotation}{Item.rotation} or
\l {Item::transform}{Item.transform} to rotate your content.
+
+ \note This property does not update unless a Screen::orientationUpdateMask
+ is set to a value other than \c 0.
*/
/*!
\qmlattachedmethod int Screen::angleBetween(Qt::ScreenOrientation a, Qt::ScreenOrientation b)
@@ -178,10 +181,21 @@ QT_BEGIN_NAMESPACE
Returns the rotation angle, in degrees, between the two specified angles.
*/
+/*!
+ \qmlattachedproperty Qt::ScreenOrientations Screen::orientationUpdateMask
+ \since 5.4
+
+ This contains the update mask for the orientation. Screen::orientation
+ only emits changes for the screen orientations matching this mask.
+
+ The default, \c 0, means Screen::orientation never updates.
+*/
+
QQuickScreenAttached::QQuickScreenAttached(QObject* attachee)
: QObject(attachee)
, m_screen(NULL)
, m_window(NULL)
+ , m_updateMask(0)
{
m_attachee = qobject_cast<QQuickItem*>(attachee);
@@ -260,6 +274,24 @@ Qt::ScreenOrientation QQuickScreenAttached::orientation() const
return m_screen->orientation();
}
+Qt::ScreenOrientations QQuickScreenAttached::orientationUpdateMask() const
+{
+ return m_updateMask;
+}
+
+void QQuickScreenAttached::setOrientationUpdateMask(Qt::ScreenOrientations mask)
+{
+ if (m_updateMask == mask)
+ return;
+
+ m_updateMask = mask;
+
+ if (m_screen)
+ m_screen->setOrientationUpdateMask(m_updateMask);
+
+ emit orientationUpdateMaskChanged();
+}
+
int QQuickScreenAttached::angleBetween(int a, int b)
{
if (!m_screen)
@@ -290,6 +322,8 @@ void QQuickScreenAttached::screenChanged(QScreen *screen)
if (!screen)
return; //Don't bother emitting signals, because the new values are garbage anyways
+ screen->setOrientationUpdateMask(m_updateMask);
+
if (!oldScreen || screen->size() != oldScreen->size()) {
emit widthChanged();
emit heightChanged();
diff --git a/src/quick/items/qquickscreen_p.h b/src/quick/items/qquickscreen_p.h
index 884995a67e..d661cc6f56 100644
--- a/src/quick/items/qquickscreen_p.h
+++ b/src/quick/items/qquickscreen_p.h
@@ -50,15 +50,19 @@ class Q_AUTOTEST_EXPORT QQuickScreenAttached : public QObject
{
Q_OBJECT
- Q_PROPERTY(QString name READ name NOTIFY nameChanged);
+ Q_PROPERTY(QString name READ name NOTIFY nameChanged)
Q_PROPERTY(int width READ width NOTIFY widthChanged)
Q_PROPERTY(int height READ height NOTIFY heightChanged)
Q_PROPERTY(int desktopAvailableWidth READ desktopAvailableWidth NOTIFY desktopGeometryChanged)
Q_PROPERTY(int desktopAvailableHeight READ desktopAvailableHeight NOTIFY desktopGeometryChanged)
Q_PROPERTY(qreal logicalPixelDensity READ logicalPixelDensity NOTIFY logicalPixelDensityChanged)
Q_PROPERTY(qreal pixelDensity READ pixelDensity NOTIFY pixelDensityChanged)
+ // TODO Qt 6 Rename primaryOrientation to orientation
Q_PROPERTY(Qt::ScreenOrientation primaryOrientation READ primaryOrientation NOTIFY primaryOrientationChanged)
+ // TODO Qt 6 Remove this orientation -> incomplete device orientation -> better use OrientationSensor
Q_PROPERTY(Qt::ScreenOrientation orientation READ orientation NOTIFY orientationChanged)
+ Q_PROPERTY(Qt::ScreenOrientations orientationUpdateMask READ orientationUpdateMask
+ WRITE setOrientationUpdateMask NOTIFY orientationUpdateMaskChanged)
public:
QQuickScreenAttached(QObject* attachee);
@@ -72,6 +76,8 @@ public:
qreal pixelDensity() const;
Qt::ScreenOrientation primaryOrientation() const;
Qt::ScreenOrientation orientation() const;
+ Qt::ScreenOrientations orientationUpdateMask() const;
+ void setOrientationUpdateMask(Qt::ScreenOrientations mask);
//Treats int as Qt::ScreenOrientation, due to QTBUG-20639
Q_INVOKABLE int angleBetween(int a, int b);
@@ -87,6 +93,7 @@ Q_SIGNALS:
void pixelDensityChanged();
void primaryOrientationChanged();
void orientationChanged();
+ void orientationUpdateMaskChanged();
protected Q_SLOTS:
void screenChanged(QScreen*);
@@ -95,6 +102,7 @@ private:
QScreen* m_screen;
QQuickWindow* m_window;
QQuickItem* m_attachee;
+ Qt::ScreenOrientations m_updateMask;
};
class Q_AUTOTEST_EXPORT QQuickScreen : public QObject
diff --git a/src/quick/items/qquickshadereffect.cpp b/src/quick/items/qquickshadereffect.cpp
index fb5dac1080..0358495a3b 100644
--- a/src/quick/items/qquickshadereffect.cpp
+++ b/src/quick/items/qquickshadereffect.cpp
@@ -641,10 +641,34 @@ void QQuickShaderEffectCommon::propertyChanged(QQuickItem *item, int mappedId,
corner. For non-linear vertex transformations, like page curl, you can
specify a fine grid of vertices by specifying a \l mesh resolution.
+ \section1 ShaderEffect and Item Layers
+
+ The ShaderEffect type can be combined with \l {Item Layers} {layered items}.
+
+ \table
+ \row
+ \li \b {Layer with effect disabled} \inlineimage qml-shadereffect-nolayereffect.png
+ \li \b {Layer with effect enabled} \inlineimage qml-shadereffect-layereffect.png
+ \li \snippet qml/layerwitheffect.qml 1
+ \endtable
+
+ It is also possible to combine multiple layered items:
+
+ \table
+ \row
+ \li \inlineimage qml-shadereffect-opacitymask.png
+ \li \snippet qml/opacitymask.qml 1
+ \endtable
+
+ The \l {Qt Graphical Effects} module contains several ready-made effects
+ for using with Qt Quick applications.
+
\note Scene Graph textures have origin in the top-left corner rather than
bottom-left which is common in OpenGL.
For information about the GLSL version being used, see \l QtQuick::OpenGLInfo.
+
+ \sa {Item Layers}
*/
QQuickShaderEffect::QQuickShaderEffect(QQuickItem *parent)
diff --git a/src/quick/items/qquickshadereffectsource.cpp b/src/quick/items/qquickshadereffectsource.cpp
index 80be283443..52e5ba2464 100644
--- a/src/quick/items/qquickshadereffectsource.cpp
+++ b/src/quick/items/qquickshadereffectsource.cpp
@@ -74,7 +74,6 @@ public:
QSGTexture::WrapMode horizontalWrap;
QSGTexture::WrapMode verticalWrap;
};
-#include "qquickshadereffectsource.moc"
class QQuickShaderEffectSourceCleanup : public QRunnable
{
@@ -322,24 +321,28 @@ void QQuickShaderEffectSource::setSourceItem(QQuickItem *item)
d->derefWindow();
}
- if (window() == item->window()) {
- m_sourceItem = item;
- } else {
- qWarning("ShaderEffectSource: sourceItem and ShaderEffectSource must both be children of the same window.");
- m_sourceItem = 0;
- }
+ m_sourceItem = item;
if (m_sourceItem) {
- QQuickItemPrivate *d = QQuickItemPrivate::get(item);
- // 'item' needs a window to get a scene graph node. It usually gets one through its
- // parent, but if the source item is "inline" rather than a reference -- i.e.
- // "sourceItem: Item { }" instead of "sourceItem: foo" -- it will not get a parent.
- // In those cases, 'item' should get the window from 'this'.
- if (window())
- d->refWindow(window());
- d->refFromEffectItem(m_hideSource);
- d->addItemChangeListener(this, QQuickItemPrivate::Geometry);
- connect(m_sourceItem, SIGNAL(destroyed(QObject*)), this, SLOT(sourceItemDestroyed(QObject*)));
+ if (window() == m_sourceItem->window()
+ || (window() == 0 && m_sourceItem->window())
+ || (m_sourceItem->window() == 0 && window())) {
+ QQuickItemPrivate *d = QQuickItemPrivate::get(item);
+ // 'item' needs a window to get a scene graph node. It usually gets one through its
+ // parent, but if the source item is "inline" rather than a reference -- i.e.
+ // "sourceItem: Item { }" instead of "sourceItem: foo" -- it will not get a parent.
+ // In those cases, 'item' should get the window from 'this'.
+ if (window())
+ d->refWindow(window());
+ else if (m_sourceItem->window())
+ d->refWindow(m_sourceItem->window());
+ d->refFromEffectItem(m_hideSource);
+ d->addItemChangeListener(this, QQuickItemPrivate::Geometry);
+ connect(m_sourceItem, SIGNAL(destroyed(QObject*)), this, SLOT(sourceItemDestroyed(QObject*)));
+ } else {
+ qWarning("ShaderEffectSource: sourceItem and ShaderEffectSource must both be children of the same window.");
+ m_sourceItem = 0;
+ }
}
update();
emit sourceItemChanged();
@@ -586,13 +589,24 @@ void QQuickShaderEffectSource::releaseResources()
}
}
+class QQuickShaderSourceAttachedNode : public QObject, public QSGNode
+{
+ Q_OBJECT
+public:
+ Q_SLOT void markTextureDirty() {
+ QSGNode *pn = QSGNode::parent();
+ if (pn) {
+ Q_ASSERT(pn->type() == QSGNode::GeometryNodeType);
+ pn->markDirty(DirtyMaterial);
+ }
+ }
+};
+
QSGNode *QQuickShaderEffectSource::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
{
if (!m_sourceItem || m_sourceItem->width() <= 0 || m_sourceItem->height() <= 0) {
- if (m_texture) {
+ if (m_texture)
m_texture->setItem(0);
- m_texture->setShaderSourceNode(0);
- }
delete oldNode;
return 0;
}
@@ -658,7 +672,9 @@ QSGNode *QQuickShaderEffectSource::updatePaintNode(QSGNode *oldNode, UpdatePaint
node = d->sceneGraphContext()->createImageNode();
node->setFlag(QSGNode::UsePreprocess);
node->setTexture(m_texture);
- m_texture->setShaderSourceNode(node);
+ QQuickShaderSourceAttachedNode *attached = new QQuickShaderSourceAttachedNode;
+ node->appendChildNode(attached);
+ connect(m_texture, SIGNAL(updateRequested()), attached, SLOT(markTextureDirty()));
}
// If live and recursive, update continuously.
@@ -698,4 +714,6 @@ void QQuickShaderEffectSource::itemChange(ItemChange change, const ItemChangeDat
QQuickItem::itemChange(change, value);
}
+#include "qquickshadereffectsource.moc"
+
QT_END_NAMESPACE
diff --git a/src/quick/items/qquicktextcontrol.cpp b/src/quick/items/qquicktextcontrol.cpp
index a263a890b5..2585caefb5 100644
--- a/src/quick/items/qquicktextcontrol.cpp
+++ b/src/quick/items/qquicktextcontrol.cpp
@@ -435,12 +435,12 @@ void QQuickTextControlPrivate::setClipboardSelection()
}
#endif
-void QQuickTextControlPrivate::_q_emitCursorPosChanged(const QTextCursor &someCursor)
+void QQuickTextControlPrivate::_q_updateCursorPosChanged(const QTextCursor &someCursor)
{
Q_Q(QQuickTextControl);
if (someCursor.isCopyOf(cursor)) {
emit q->cursorPositionChanged();
- cursorRectangleChanged = true;
+ q->updateCursorRectangle(true);
}
}
@@ -578,7 +578,7 @@ QQuickTextControl::QQuickTextControl(QTextDocument *doc, QObject *parent)
qmlobject_connect(layout, QAbstractTextDocumentLayout, SIGNAL(updateBlock(QTextBlock)), this, QQuickTextControl, SIGNAL(updateRequest()));
qmlobject_connect(doc, QTextDocument, SIGNAL(contentsChanged()), this, QQuickTextControl, SIGNAL(textChanged()));
qmlobject_connect(doc, QTextDocument, SIGNAL(contentsChanged()), this, QQuickTextControl, SLOT(_q_updateCurrentCharFormatAndSelection()));
- qmlobject_connect(doc, QTextDocument, SIGNAL(cursorPositionChanged(QTextCursor)), this, QQuickTextControl, SLOT(_q_emitCursorPosChanged(QTextCursor)));
+ qmlobject_connect(doc, QTextDocument, SIGNAL(cursorPositionChanged(QTextCursor)), this, QQuickTextControl, SLOT(_q_updateCursorPosChanged(QTextCursor)));
connect(doc, &QTextDocument::contentsChange, this, &QQuickTextControl::contentsChange);
layout->setProperty("cursorWidth", textCursorWidth);
diff --git a/src/quick/items/qquicktextcontrol_p.h b/src/quick/items/qquicktextcontrol_p.h
index 3cb1590be8..2fe083f1d2 100644
--- a/src/quick/items/qquicktextcontrol_p.h
+++ b/src/quick/items/qquicktextcontrol_p.h
@@ -169,7 +169,7 @@ protected:
private:
Q_DISABLE_COPY(QQuickTextControl)
Q_PRIVATE_SLOT(d_func(), void _q_updateCurrentCharFormatAndSelection())
- Q_PRIVATE_SLOT(d_func(), void _q_emitCursorPosChanged(const QTextCursor &))
+ Q_PRIVATE_SLOT(d_func(), void _q_updateCursorPosChanged(const QTextCursor &))
};
diff --git a/src/quick/items/qquicktextcontrol_p_p.h b/src/quick/items/qquicktextcontrol_p_p.h
index a3b7c7be99..bd07d86f9c 100644
--- a/src/quick/items/qquicktextcontrol_p_p.h
+++ b/src/quick/items/qquicktextcontrol_p_p.h
@@ -88,7 +88,7 @@ public:
void setClipboardSelection();
#endif
- void _q_emitCursorPosChanged(const QTextCursor &someCursor);
+ void _q_updateCursorPosChanged(const QTextCursor &someCursor);
void setBlinkingCursorEnabled(bool enable);
diff --git a/src/quick/items/qquicktextnodeengine.cpp b/src/quick/items/qquicktextnodeengine.cpp
index f746fe8b1b..67ff79d20f 100644
--- a/src/quick/items/qquicktextnodeengine.cpp
+++ b/src/quick/items/qquicktextnodeengine.cpp
@@ -46,12 +46,37 @@
#include <private/qtextdocumentlayout_p.h>
#include <private/qtextimagehandler_p.h>
#include <private/qrawfont_p.h>
+#include <private/qglyphrun_p.h>
QT_BEGIN_NAMESPACE
+QQuickTextNodeEngine::BinaryTreeNode::BinaryTreeNode(const QGlyphRun &g,
+ SelectionState selState,
+ const QRectF &brect,
+ const QQuickTextNode::Decorations &decs,
+ const QColor &c,
+ const QColor &bc,
+ const QPointF &pos, qreal a)
+ : glyphRun(g)
+ , boundingRect(brect)
+ , selectionState(selState)
+ , clipNode(0)
+ , decorations(decs)
+ , color(c)
+ , backgroundColor(bc)
+ , position(pos)
+ , ascent(a)
+ , leftChildIndex(-1)
+ , rightChildIndex(-1)
+{
+ QGlyphRunPrivate *d = QGlyphRunPrivate::get(g);
+ ranges.append(qMakePair(d->textRangeStart, d->textRangeEnd));
+}
+
+
void QQuickTextNodeEngine::BinaryTreeNode::insert(QVarLengthArray<BinaryTreeNode, 16> *binaryTree, const QGlyphRun &glyphRun, SelectionState selectionState,
QQuickTextNode::Decorations decorations, const QColor &textColor,
- const QColor &backgroundColor, const QPointF &position, int rangeStart, int rangeEnd)
+ const QColor &backgroundColor, const QPointF &position)
{
QRectF searchRect = glyphRun.boundingRect();
searchRect.translate(position);
@@ -65,8 +90,14 @@ void QQuickTextNodeEngine::BinaryTreeNode::insert(QVarLengthArray<BinaryTreeNode
decorations |= (backgroundColor.isValid() ? QQuickTextNode::Background : QQuickTextNode::NoDecoration);
qreal ascent = glyphRun.rawFont().ascent();
- insert(binaryTree, BinaryTreeNode(glyphRun, selectionState, searchRect, decorations,
- textColor, backgroundColor, position, ascent, rangeStart, rangeEnd));
+ insert(binaryTree, BinaryTreeNode(glyphRun,
+ selectionState,
+ searchRect,
+ decorations,
+ textColor,
+ backgroundColor,
+ position,
+ ascent));
}
void QQuickTextNodeEngine::BinaryTreeNode::insert(QVarLengthArray<BinaryTreeNode, 16> *binaryTree, const BinaryTreeNode &binaryTreeNode)
@@ -441,19 +472,27 @@ void QQuickTextNodeEngine::addTextObject(const QPointF &position, const QTextCha
}
}
-void QQuickTextNodeEngine::addUnselectedGlyphs(const QGlyphRun &glyphRun, int rangeStart, int rangeEnd)
+void QQuickTextNodeEngine::addUnselectedGlyphs(const QGlyphRun &glyphRun)
{
- BinaryTreeNode::insert(&m_currentLineTree, glyphRun, Unselected,
- QQuickTextNode::NoDecoration, m_textColor, m_backgroundColor, m_position,
- rangeStart, rangeEnd);
+ BinaryTreeNode::insert(&m_currentLineTree,
+ glyphRun,
+ Unselected,
+ QQuickTextNode::NoDecoration,
+ m_textColor,
+ m_backgroundColor,
+ m_position);
}
-void QQuickTextNodeEngine::addSelectedGlyphs(const QGlyphRun &glyphRun, int rangeStart, int rangeEnd)
+void QQuickTextNodeEngine::addSelectedGlyphs(const QGlyphRun &glyphRun)
{
int currentSize = m_currentLineTree.size();
- BinaryTreeNode::insert(&m_currentLineTree, glyphRun, Selected,
- QQuickTextNode::NoDecoration, m_textColor, m_backgroundColor, m_position,
- rangeStart, rangeEnd);
+ BinaryTreeNode::insert(&m_currentLineTree,
+ glyphRun,
+ Selected,
+ QQuickTextNode::NoDecoration,
+ m_textColor,
+ m_backgroundColor,
+ m_position);
m_hasSelection = m_hasSelection || m_currentLineTree.size() > currentSize;
}
@@ -526,7 +565,7 @@ void QQuickTextNodeEngine::addGlyphsInRange(int rangeStart, int rangeLength,
QList<QGlyphRun> glyphRuns = line.glyphRuns(rangeStart, rangeLength);
for (int j=0; j<glyphRuns.size(); ++j) {
const QGlyphRun &glyphRun = glyphRuns.at(j);
- addUnselectedGlyphs(glyphRun, rangeStart, rangeEnd - 1);
+ addUnselectedGlyphs(glyphRun);
}
} else {
if (rangeStart < selectionStart) {
@@ -534,7 +573,7 @@ void QQuickTextNodeEngine::addGlyphsInRange(int rangeStart, int rangeLength,
QList<QGlyphRun> glyphRuns = line.glyphRuns(rangeStart, length);
for (int j=0; j<glyphRuns.size(); ++j) {
const QGlyphRun &glyphRun = glyphRuns.at(j);
- addUnselectedGlyphs(glyphRun, rangeStart, rangeStart + length - 1);
+ addUnselectedGlyphs(glyphRun);
}
}
@@ -545,8 +584,8 @@ void QQuickTextNodeEngine::addGlyphsInRange(int rangeStart, int rangeLength,
for (int j=0; j<glyphRuns.size(); ++j) {
const QGlyphRun &glyphRun = glyphRuns.at(j);
- addSelectedGlyphs(glyphRun, start, start + length - 1);
- addUnselectedGlyphs(glyphRun, start, start + length - 1);
+ addSelectedGlyphs(glyphRun);
+ addUnselectedGlyphs(glyphRun);
}
}
@@ -556,7 +595,7 @@ void QQuickTextNodeEngine::addGlyphsInRange(int rangeStart, int rangeLength,
QList<QGlyphRun> glyphRuns = line.glyphRuns(start, length);
for (int j=0; j<glyphRuns.size(); ++j) {
const QGlyphRun &glyphRun = glyphRuns.at(j);
- addUnselectedGlyphs(glyphRun, start, start + length - 1);
+ addUnselectedGlyphs(glyphRun);
}
}
}
@@ -927,7 +966,7 @@ void QQuickTextNodeEngine::addTextBlock(QTextDocument *textDocument, const QText
QList<QGlyphRun> glyphRuns = layout.glyphRuns();
for (int i=0; i<glyphRuns.size(); ++i)
- addUnselectedGlyphs(glyphRuns.at(i), 0, layout.text().length() - 1);
+ addUnselectedGlyphs(glyphRuns.at(i));
}
}
diff --git a/src/quick/items/qquicktextnodeengine_p.h b/src/quick/items/qquicktextnodeengine_p.h
index 142375b5a3..f0d52683c6 100644
--- a/src/quick/items/qquicktextnodeengine_p.h
+++ b/src/quick/items/qquicktextnodeengine_p.h
@@ -75,12 +75,7 @@ public:
BinaryTreeNode(const QGlyphRun &g, SelectionState selState, const QRectF &brect,
const QQuickTextNode::Decorations &decs, const QColor &c, const QColor &bc,
- const QPointF &pos, qreal a, int rangeStart, int rangeEnd)
- : glyphRun(g), boundingRect(brect), selectionState(selState), clipNode(0), decorations(decs)
- , color(c), backgroundColor(bc), position(pos), ascent(a), leftChildIndex(-1), rightChildIndex(-1)
- {
- ranges.append(qMakePair(rangeStart, rangeEnd));
- }
+ const QPointF &pos, qreal a);
QGlyphRun glyphRun;
QRectF boundingRect;
@@ -102,8 +97,7 @@ public:
{ insert(binaryTree, BinaryTreeNode(rect, image, selectionState, ascent)); }
static void insert(QVarLengthArray<BinaryTreeNode, 16> *binaryTree, const QGlyphRun &glyphRun, SelectionState selectionState,
- QQuickTextNode::Decorations decorations, const QColor &textColor, const QColor &backgroundColor, const QPointF &position,
- int rangeStart, int rangeEnd);
+ QQuickTextNode::Decorations decorations, const QColor &textColor, const QColor &backgroundColor, const QPointF &position);
static void insert(QVarLengthArray<BinaryTreeNode, 16> *binaryTree, const BinaryTreeNode &binaryTreeNode);
static void inOrder(const QVarLengthArray<BinaryTreeNode, 16> &binaryTree, QVarLengthArray<int> *sortedIndexes, int currentIndex = 0);
};
@@ -138,8 +132,8 @@ public:
SelectionState selectionState,
QTextDocument *textDocument, int pos,
QTextFrameFormat::Position layoutPosition = QTextFrameFormat::InFlow);
- void addSelectedGlyphs(const QGlyphRun &glyphRun, int rangeStart, int rangeEnd);
- void addUnselectedGlyphs(const QGlyphRun &glyphRun, int rangeStart, int rangeEnd);
+ void addSelectedGlyphs(const QGlyphRun &glyphRun);
+ void addUnselectedGlyphs(const QGlyphRun &glyphRun);
void addGlyphsInRange(int rangeStart, int rangeEnd,
const QColor &color, const QColor &backgroundColor,
int selectionStart, int selectionEnd);
diff --git a/src/quick/items/qquickview.cpp b/src/quick/items/qquickview.cpp
index 91a6468593..a55d056c75 100644
--- a/src/quick/items/qquickview.cpp
+++ b/src/quick/items/qquickview.cpp
@@ -594,7 +594,7 @@ void QQuickView::resizeEvent(QResizeEvent *e)
/*! \reimp */
void QQuickView::keyPressEvent(QKeyEvent *e)
{
- Q_QUICK_PROFILE(addEvent<QQuickProfiler::Key>());
+ Q_QUICK_INPUT_PROFILE(addEvent<QQuickProfiler::Key>());
QQuickWindow::keyPressEvent(e);
}
@@ -602,7 +602,7 @@ void QQuickView::keyPressEvent(QKeyEvent *e)
/*! \reimp */
void QQuickView::keyReleaseEvent(QKeyEvent *e)
{
- Q_QUICK_PROFILE(addEvent<QQuickProfiler::Key>());
+ Q_QUICK_INPUT_PROFILE(addEvent<QQuickProfiler::Key>());
QQuickWindow::keyReleaseEvent(e);
}
@@ -610,7 +610,7 @@ void QQuickView::keyReleaseEvent(QKeyEvent *e)
/*! \reimp */
void QQuickView::mouseMoveEvent(QMouseEvent *e)
{
- Q_QUICK_PROFILE(addEvent<QQuickProfiler::Mouse>());
+ Q_QUICK_INPUT_PROFILE(addEvent<QQuickProfiler::Mouse>());
QQuickWindow::mouseMoveEvent(e);
}
@@ -618,7 +618,7 @@ void QQuickView::mouseMoveEvent(QMouseEvent *e)
/*! \reimp */
void QQuickView::mousePressEvent(QMouseEvent *e)
{
- Q_QUICK_PROFILE(addEvent<QQuickProfiler::Mouse>());
+ Q_QUICK_INPUT_PROFILE(addEvent<QQuickProfiler::Mouse>());
QQuickWindow::mousePressEvent(e);
}
@@ -626,7 +626,7 @@ void QQuickView::mousePressEvent(QMouseEvent *e)
/*! \reimp */
void QQuickView::mouseReleaseEvent(QMouseEvent *e)
{
- Q_QUICK_PROFILE(addEvent<QQuickProfiler::Mouse>());
+ Q_QUICK_INPUT_PROFILE(addEvent<QQuickProfiler::Mouse>());
QQuickWindow::mouseReleaseEvent(e);
}
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
index ca0a81f2f4..5548017ddc 100644
--- a/src/quick/items/qquickwindow.cpp
+++ b/src/quick/items/qquickwindow.cpp
@@ -1654,8 +1654,8 @@ bool QQuickWindowPrivate::deliverHoverEvent(QQuickItem *item, const QPointF &sce
// Leaving from previous hovered items until we reach the item or one of its ancestors.
while (!hoverItems.isEmpty() && !itemsToHover.contains(hoverItems[0])) {
- sendHoverEvent(QEvent::HoverLeave, hoverItems[0], scenePos, lastScenePos, modifiers, accepted);
- hoverItems.removeFirst();
+ QQuickItem *hoverLeaveItem = hoverItems.takeFirst();
+ sendHoverEvent(QEvent::HoverLeave, hoverLeaveItem, scenePos, lastScenePos, modifiers, accepted);
}
if (!hoverItems.isEmpty() && hoverItems[0] == item){//Not entering a new Item
@@ -2922,7 +2922,7 @@ void QQuickWindow::setTransientParent_helper(QQuickWindow *window)
QOpenGLContext *QQuickWindow::openglContext() const
{
Q_D(const QQuickWindow);
- return d->context->openglContext();
+ return d->context ? d->context->openglContext() : 0;
}
/*!
@@ -3530,7 +3530,7 @@ void QQuickWindow::setColor(const QColor &color)
}
d->clearColor = color;
emit colorChanged(color);
- d->dirtyItem(contentItem());
+ update();
}
QColor QQuickWindow::color() const
@@ -3914,11 +3914,6 @@ void QQuickWindow::scheduleRenderJob(QRunnable *job, RenderStage stage)
d->renderJobMutex.unlock();
}
-QQuickWindowAttached *QQuickWindow::qmlAttachedProperties(QObject *object)
-{
- return new QQuickWindowAttached(object);
-}
-
void QQuickWindowPrivate::runAndClearJobs(QList<QRunnable *> *jobs)
{
renderJobMutex.lock();
diff --git a/src/quick/items/qquickwindow.h b/src/quick/items/qquickwindow.h
index 82f2e29d9d..8d75a4767c 100644
--- a/src/quick/items/qquickwindow.h
+++ b/src/quick/items/qquickwindow.h
@@ -143,8 +143,6 @@ public:
void scheduleRenderJob(QRunnable *job, RenderStage schedule);
- static QQuickWindowAttached *qmlAttachedProperties(QObject *object);
-
Q_SIGNALS:
void frameSwapped();
Q_REVISION(2) void openglContextCreated(QOpenGLContext *context);
@@ -209,7 +207,6 @@ private:
QT_END_NAMESPACE
Q_DECLARE_METATYPE(QQuickWindow *)
-QML_DECLARE_TYPEINFO(QQuickWindow, QML_HAS_ATTACHED_PROPERTIES)
#endif // QQUICKWINDOW_H
diff --git a/src/quick/items/qquickwindowmodule.cpp b/src/quick/items/qquickwindowmodule.cpp
index dbd0628db2..bf41bc136f 100644
--- a/src/quick/items/qquickwindowmodule.cpp
+++ b/src/quick/items/qquickwindowmodule.cpp
@@ -79,6 +79,11 @@ public:
QQuickWindow::setVisibility(visibility);
}
+ static QQuickWindowAttached *qmlAttachedProperties(QObject *object)
+ {
+ return new QQuickWindowAttached(object);
+ }
+
Q_SIGNALS:
void visibleChanged(bool arg);
void visibilityChanged(QWindow::Visibility visibility);
@@ -166,16 +171,13 @@ void QQuickWindowModule::defineModule()
{
const char uri[] = "QtQuick.Window";
- // Since Window is both an attached property and a createable type,
- // the attached property declaration must come first so that it can
- // be overridden below.
- qmlRegisterUncreatableType<QQuickWindow>(uri, 2, 2, "Window", QQuickWindow::tr("Window is available via attached properties"));
qmlRegisterType<QQuickWindow>(uri, 2, 0, "Window");
qmlRegisterRevision<QWindow,1>(uri, 2, 1);
qmlRegisterRevision<QWindow,2>(uri, 2, 2);
qmlRegisterRevision<QQuickWindow,1>(uri, 2, 1);//Type moved to a subclass, but also has new members
qmlRegisterRevision<QQuickWindow,2>(uri, 2, 2);
qmlRegisterType<QQuickWindowQmlImpl>(uri, 2, 1, "Window");
+ qmlRegisterType<QQuickWindowQmlImpl,1>(uri, 2, 2, "Window");
qmlRegisterUncreatableType<QQuickScreen>(uri, 2, 0, "Screen", QStringLiteral("Screen can only be used via the attached property."));
}
@@ -183,3 +185,4 @@ void QQuickWindowModule::defineModule()
QT_END_NAMESPACE
+QML_DECLARE_TYPEINFO(QQuickWindowQmlImpl, QML_HAS_ATTACHED_PROPERTIES)
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);
}
diff --git a/src/quick/util/qquickanimatorcontroller.cpp b/src/quick/util/qquickanimatorcontroller.cpp
index 01f182c35d..e009de205c 100644
--- a/src/quick/util/qquickanimatorcontroller.cpp
+++ b/src/quick/util/qquickanimatorcontroller.cpp
@@ -184,8 +184,6 @@ void QQuickAnimatorController::beforeNodeSync()
m_nodesAreInvalid = false;
}
-
-
foreach (QQuickAnimatorJob *job, m_activeLeafAnimations) {
if (!job->target())
continue;
@@ -197,9 +195,9 @@ void QQuickAnimatorController::beforeNodeSync()
}
}
foreach (QQuickItem *wiped, m_deletedSinceLastFrame) {
- QQuickTransformAnimatorJob::Helper *helper = m_transforms.value(wiped);
- if (helper)
- helper->item = 0;
+ QQuickTransformAnimatorJob::Helper *helper = m_transforms.take(wiped);
+ // Helper will now already have been reset in all animators referencing it.
+ delete helper;
}
m_deletedSinceLastFrame.clear();
@@ -254,6 +252,7 @@ void QQuickAnimatorController::requestSync()
// These functions are called on the GUI thread.
void QQuickAnimatorController::startJob(QQuickAnimatorProxyJob *proxy, QAbstractAnimationJob *job)
{
+ proxy->markJobManagedByController();
m_starting[job] = proxy;
requestSync();
}
diff --git a/src/quick/util/qquickanimatorjob.cpp b/src/quick/util/qquickanimatorjob.cpp
index 741fa9bb7f..fdbffd4709 100644
--- a/src/quick/util/qquickanimatorjob.cpp
+++ b/src/quick/util/qquickanimatorjob.cpp
@@ -49,6 +49,7 @@ QQuickAnimatorProxyJob::QQuickAnimatorProxyJob(QAbstractAnimationJob *job, QObje
: m_controller(0)
, m_job(job)
, m_internalState(State_Stopped)
+ , m_jobManagedByController(false)
{
m_isRenderThreadProxy = true;
m_animation = qobject_cast<QQuickAbstractAnimation *>(item);
@@ -93,7 +94,10 @@ void QQuickAnimatorProxyJob::deleteJob()
// so delete it through the controller to clean up properly.
if (m_controller)
m_controller->deleteJob(m_job);
- else
+
+ // We explicitly delete the job if the animator controller has never touched
+ // it. If it has, it will have ownership as well.
+ else if (!m_jobManagedByController)
delete m_job;
m_job = 0;
}
@@ -141,11 +145,13 @@ void QQuickAnimatorProxyJob::controllerWasDeleted()
void QQuickAnimatorProxyJob::setWindow(QQuickWindow *window)
{
if (!window) {
- // Stop will trigger syncBackCurrentValues so best to do it before
- // we delete m_job.
stop();
deleteJob();
- return;
+
+ // Upon leaving a window, we reset the controller. This means that
+ // animators will only enter the Starting phase and won't be making
+ // calls to QQuickAnimatorController::startjob().
+ m_controller = 0;
} else if (!m_controller && m_job) {
m_controller = QQuickWindowPrivate::get(window)->animationController;
@@ -250,6 +256,10 @@ QQuickTransformAnimatorJob::QQuickTransformAnimatorJob()
QQuickTransformAnimatorJob::~QQuickTransformAnimatorJob()
{
if (m_helper && --m_helper->ref == 0) {
+ // The only condition for not having a controller is when target was
+ // destroyed, in which case we have neither m_helper nor m_contorller.
+ Q_ASSERT(m_controller);
+ Q_ASSERT(m_helper->item);
m_controller->m_transforms.remove(m_helper->item);
delete m_helper;
}
@@ -260,6 +270,7 @@ void QQuickTransformAnimatorJob::initialize(QQuickAnimatorController *controller
QQuickAnimatorJob::initialize(controller);
if (m_controller) {
+ bool newHelper = m_helper == 0;
m_helper = m_controller->m_transforms.value(m_target);
if (!m_helper) {
m_helper = new Helper();
@@ -267,7 +278,8 @@ void QQuickTransformAnimatorJob::initialize(QQuickAnimatorController *controller
m_controller->m_transforms.insert(m_target, m_helper);
QObject::connect(m_target, SIGNAL(destroyed(QObject*)), m_controller, SLOT(itemDestroyed(QObject*)), Qt::DirectConnection);
} else {
- ++m_helper->ref;
+ if (newHelper) // only add reference the first time around..
+ ++m_helper->ref;
// Make sure leftovers from previous runs are being used...
m_helper->wasSynced = false;
}
@@ -281,6 +293,12 @@ void QQuickTransformAnimatorJob::nodeWasDestroyed()
m_helper->node = 0;
}
+void QQuickTransformAnimatorJob::targetWasDeleted()
+{
+ m_helper = 0;
+ QQuickAnimatorJob::targetWasDeleted();
+}
+
void QQuickTransformAnimatorJob::Helper::sync()
{
const quint32 mask = QQuickItemPrivate::Position
diff --git a/src/quick/util/qquickanimatorjob_p.h b/src/quick/util/qquickanimatorjob_p.h
index 7c6ad823b3..4bdcd6917d 100644
--- a/src/quick/util/qquickanimatorjob_p.h
+++ b/src/quick/util/qquickanimatorjob_p.h
@@ -69,6 +69,7 @@ public:
void startedByController();
void controllerWasDeleted();
+ void markJobManagedByController() { m_jobManagedByController = true; }
protected:
bool event(QEvent *);
@@ -87,7 +88,7 @@ private:
void setWindow(QQuickWindow *window);
static QObject *findAnimationContext(QQuickAbstractAnimation *);
- QQuickAnimatorController *m_controller;
+ QPointer<QQuickAnimatorController> m_controller;
QQuickAbstractAnimation *m_animation;
QAbstractAnimationJob *m_job;
int m_duration;
@@ -100,6 +101,7 @@ private:
};
InternalState m_internalState;
+ bool m_jobManagedByController;
};
class Q_QUICK_PRIVATE_EXPORT QQuickAnimatorJob : public QAbstractAnimationJob
@@ -120,7 +122,7 @@ public:
QEasingCurve easingCurve() const { return m_easing; }
void setEasingCurve(const QEasingCurve &curve) { m_easing = curve; }
- void targetWasDeleted();
+ virtual void targetWasDeleted();
virtual void initialize(QQuickAnimatorController *controller);
virtual void writeBack() = 0;
virtual void nodeWasDestroyed() = 0;
@@ -202,6 +204,7 @@ protected:
QQuickTransformAnimatorJob();
void initialize(QQuickAnimatorController *controller);
void nodeWasDestroyed();
+ void targetWasDeleted() Q_DECL_OVERRIDE;
Helper *m_helper;
};
diff --git a/src/quick/util/qquickpixmapcache.cpp b/src/quick/util/qquickpixmapcache.cpp
index 3e94d0cea6..a2a8ef03c7 100644
--- a/src/quick/util/qquickpixmapcache.cpp
+++ b/src/quick/util/qquickpixmapcache.cpp
@@ -40,6 +40,7 @@
#include <private/qqmlengine_p.h>
#include <QtGui/private/qguiapplication_p.h>
+#include <QtGui/private/qimage_p.h>
#include <qpa/qplatformintegration.h>
#include <QtQuick/private/qsgtexture_p.h>
@@ -70,6 +71,8 @@
#define CACHE_EXPIRE_TIME 30
#define CACHE_REMOVAL_FRACTION 4
+#define PIXMAP_PROFILE(Code) Q_QUICK_PROFILE(QQuickProfiler::ProfilePixmapCache, Code)
+
QT_BEGIN_NAMESPACE
@@ -329,6 +332,29 @@ QNetworkAccessManager *QQuickPixmapReader::networkAccessManager()
return accessManager;
}
+static void maybeRemoveAlpha(QImage *image)
+{
+ // If the image
+ if (image->hasAlphaChannel() && image->data_ptr()
+ && !image->data_ptr()->checkForAlphaPixels()) {
+ switch (image->format()) {
+ case QImage::Format_RGBA8888:
+ case QImage::Format_RGBA8888_Premultiplied:
+ *image = image->convertToFormat(QImage::Format_RGBX8888);
+ break;
+ case QImage::Format_A2BGR30_Premultiplied:
+ *image = image->convertToFormat(QImage::Format_BGR30);
+ break;
+ case QImage::Format_A2RGB30_Premultiplied:
+ *image = image->convertToFormat(QImage::Format_RGB30);
+ break;
+ default:
+ *image = image->convertToFormat(QImage::Format_RGB32);
+ break;
+ }
+ }
+}
+
static bool readImage(const QUrl& url, QIODevice *dev, QImage *image, QString *errorString, QSize *impsize,
const QSize &requestSize)
{
@@ -358,6 +384,7 @@ static bool readImage(const QUrl& url, QIODevice *dev, QImage *image, QString *e
*impsize = imgio.size();
if (imgio.read(image)) {
+ maybeRemoveAlpha(image);
if (impsize && impsize->width() < 0)
*impsize = image->size();
return true;
@@ -500,7 +527,7 @@ void QQuickPixmapReader::processJobs()
replies.remove(reply);
reply->close();
}
- Q_QUICK_PROFILE(pixmapStateChanged<QQuickProfiler::PixmapLoadingError>(job->url));
+ PIXMAP_PROFILE(pixmapStateChanged<QQuickProfiler::PixmapLoadingError>(job->url));
// deleteLater, since not owned by this thread
job->deleteLater();
}
@@ -512,7 +539,7 @@ void QQuickPixmapReader::processJobs()
runningJob->loading = true;
QUrl url = runningJob->url;
- Q_QUICK_PROFILE(pixmapStateChanged<QQuickProfiler::PixmapLoadingStarted>(url));
+ PIXMAP_PROFILE(pixmapStateChanged<QQuickProfiler::PixmapLoadingStarted>(url));
QSize requestSize = runningJob->requestSize;
locker.unlock();
@@ -660,7 +687,7 @@ void QQuickPixmapReader::cancel(QQuickPixmapReply *reply)
// If loading was started (reply removed from jobs) but the reply was never processed
// (otherwise it would have deleted itself) we need to profile an error.
if (jobs.removeAll(reply) == 0) {
- Q_QUICK_PROFILE(pixmapStateChanged<QQuickProfiler::PixmapLoadingError>(reply->url));
+ PIXMAP_PROFILE(pixmapStateChanged<QQuickProfiler::PixmapLoadingError>(reply->url));
}
delete reply;
}
@@ -896,12 +923,12 @@ bool QQuickPixmapReply::event(QEvent *event)
if (data->pixmapStatus == QQuickPixmap::Ready) {
data->textureFactory = de->textureFactory;
data->implicitSize = de->implicitSize;
- Q_QUICK_PROFILE(pixmapLoadingFinished(data->url,
+ PIXMAP_PROFILE(pixmapLoadingFinished(data->url,
data->textureFactory != 0 && data->textureFactory->textureSize().isValid() ?
data->textureFactory->textureSize() :
(data->requestSize.isValid() ? data->requestSize : data->implicitSize)));
} else {
- Q_QUICK_PROFILE(pixmapStateChanged<QQuickProfiler::PixmapLoadingError>(data->url));
+ PIXMAP_PROFILE(pixmapStateChanged<QQuickProfiler::PixmapLoadingError>(data->url));
data->errorString = de->errorString;
data->removeFromCache(); // We don't continue to cache error'd pixmaps
}
@@ -909,7 +936,7 @@ bool QQuickPixmapReply::event(QEvent *event)
data->reply = 0;
emit finished();
} else {
- Q_QUICK_PROFILE(pixmapStateChanged<QQuickProfiler::PixmapLoadingError>(url));
+ PIXMAP_PROFILE(pixmapStateChanged<QQuickProfiler::PixmapLoadingError>(url));
}
delete this;
@@ -929,7 +956,7 @@ int QQuickPixmapData::cost() const
void QQuickPixmapData::addref()
{
++refCount;
- Q_QUICK_PROFILE(pixmapCountChanged<QQuickProfiler::PixmapReferenceCountChanged>(url, refCount));
+ PIXMAP_PROFILE(pixmapCountChanged<QQuickProfiler::PixmapReferenceCountChanged>(url, refCount));
if (prevUnreferencedPtr)
pixmapStore()->referencePixmap(this);
}
@@ -938,7 +965,7 @@ void QQuickPixmapData::release()
{
Q_ASSERT(refCount > 0);
--refCount;
- Q_QUICK_PROFILE(pixmapCountChanged<QQuickProfiler::PixmapReferenceCountChanged>(url, refCount));
+ PIXMAP_PROFILE(pixmapCountChanged<QQuickProfiler::PixmapReferenceCountChanged>(url, refCount));
if (refCount == 0) {
if (reply) {
QQuickPixmapReply *cancelReply = reply;
@@ -969,7 +996,7 @@ void QQuickPixmapData::addToCache()
QQuickPixmapKey key = { &url, &requestSize };
pixmapStore()->m_cache.insert(key, this);
inCache = true;
- Q_QUICK_PROFILE(pixmapCountChanged<QQuickProfiler::PixmapCacheCountChanged>(
+ PIXMAP_PROFILE(pixmapCountChanged<QQuickProfiler::PixmapCacheCountChanged>(
url, pixmapStore()->m_cache.count()));
}
}
@@ -980,7 +1007,7 @@ void QQuickPixmapData::removeFromCache()
QQuickPixmapKey key = { &url, &requestSize };
pixmapStore()->m_cache.remove(key);
inCache = false;
- Q_QUICK_PROFILE(pixmapCountChanged<QQuickProfiler::PixmapCacheCountChanged>(
+ PIXMAP_PROFILE(pixmapCountChanged<QQuickProfiler::PixmapCacheCountChanged>(
url, pixmapStore()->m_cache.count()));
}
}
@@ -1259,16 +1286,16 @@ void QQuickPixmap::load(QQmlEngine *engine, const QUrl &url, const QSize &reques
if (!(options & QQuickPixmap::Asynchronous)) {
bool ok = false;
- Q_QUICK_PROFILE(pixmapStateChanged<QQuickProfiler::PixmapLoadingStarted>(url));
+ PIXMAP_PROFILE(pixmapStateChanged<QQuickProfiler::PixmapLoadingStarted>(url));
d = createPixmapDataSync(this, engine, url, requestSize, &ok);
if (ok) {
- Q_QUICK_PROFILE(pixmapLoadingFinished(url, QSize(width(), height())));
+ PIXMAP_PROFILE(pixmapLoadingFinished(url, QSize(width(), height())));
if (options & QQuickPixmap::Cache)
d->addToCache();
return;
}
if (d) { // loadable, but encountered error while loading
- Q_QUICK_PROFILE(pixmapStateChanged<QQuickProfiler::PixmapLoadingError>(url));
+ PIXMAP_PROFILE(pixmapStateChanged<QQuickProfiler::PixmapLoadingError>(url));
return;
}
}
diff --git a/src/quick/util/qquickprofiler.cpp b/src/quick/util/qquickprofiler.cpp
index 7cb64bbeeb..c4441ed5dd 100644
--- a/src/quick/util/qquickprofiler.cpp
+++ b/src/quick/util/qquickprofiler.cpp
@@ -40,7 +40,7 @@ QT_BEGIN_NAMESPACE
// instance will be set, unset in constructor. Allows static methods to be inlined.
QQuickProfiler *QQuickProfiler::s_instance = 0;
-bool QQuickProfiler::enabled = false;
+quint64 QQuickProfiler::featuresEnabled = 0;
// convert to QByteArrays that can be sent to the debug client
// use of QDataStream can skew results
@@ -129,7 +129,7 @@ void QQuickProfiler::initialize()
void animationTimerCallback(qint64 delta)
{
- Q_QUICK_PROFILE(animationFrame(delta,
+ Q_QUICK_PROFILE(QQuickProfiler::ProfileAnimations, animationFrame(delta,
QThread::currentThread() == QCoreApplication::instance()->thread() ?
QQuickProfiler::GuiThread : QQuickProfiler::RenderThread));
}
@@ -158,10 +158,10 @@ QQuickProfiler::QQuickProfiler(QQmlProfilerService *service) :
m_timer.start();
// We can always do DirectConnection here as all methods are protected by mutexes
- connect(this, SIGNAL(profilingEnabled()), this, SLOT(startProfilingImpl()),
- Qt::DirectConnection);
- connect(this, SIGNAL(profilingEnabledWhileWaiting()), this, SLOT(startProfilingImpl()),
+ connect(this, SIGNAL(profilingEnabled(quint64)), this, SLOT(startProfilingImpl(quint64)),
Qt::DirectConnection);
+ connect(this, SIGNAL(profilingEnabledWhileWaiting(quint64)),
+ this, SLOT(startProfilingImpl(quint64)), Qt::DirectConnection);
connect(this, SIGNAL(referenceTimeKnown(QElapsedTimer)), this, SLOT(setTimer(QElapsedTimer)),
Qt::DirectConnection);
connect(this, SIGNAL(profilingDisabled()), this, SLOT(stopProfilingImpl()),
@@ -179,23 +179,23 @@ QQuickProfiler::QQuickProfiler(QQmlProfilerService *service) :
QQuickProfiler::~QQuickProfiler()
{
QMutexLocker lock(&m_dataMutex);
- enabled = false;
+ featuresEnabled = 0;
s_instance = 0;
}
-void QQuickProfiler::startProfilingImpl()
+void QQuickProfiler::startProfilingImpl(quint64 features)
{
QMutexLocker lock(&m_dataMutex);
next = 0;
m_data.clear();
- enabled = true;
+ featuresEnabled = features;
}
void QQuickProfiler::stopProfilingImpl()
{
{
QMutexLocker lock(&m_dataMutex);
- enabled = false;
+ featuresEnabled = 0;
next = 0;
}
service->dataReady(this);
diff --git a/src/quick/util/qquickprofiler_p.h b/src/quick/util/qquickprofiler_p.h
index 6796fab912..ea37558741 100644
--- a/src/quick/util/qquickprofiler_p.h
+++ b/src/quick/util/qquickprofiler_p.h
@@ -55,40 +55,50 @@
QT_BEGIN_NAMESPACE
-#define Q_QUICK_PROFILE_IF_ENABLED(Code)\
- if (QQuickProfiler::enabled) {\
+#define Q_QUICK_PROFILE_IF_ENABLED(feature, Code)\
+ if (QQuickProfiler::featuresEnabled & (1 << feature)) {\
Code;\
} else\
(void)0
-#define Q_QUICK_PROFILE(Method)\
- Q_QUICK_PROFILE_IF_ENABLED(QQuickProfiler::Method)
+#define Q_QUICK_PROFILE(feature, Method)\
+ Q_QUICK_PROFILE_IF_ENABLED(feature, QQuickProfiler::Method)
#define Q_QUICK_SG_PROFILE_START(Type)\
- Q_QUICK_PROFILE_IF_ENABLED((QQuickProfiler::startSceneGraphFrame<Type>()))
+ Q_QUICK_PROFILE_IF_ENABLED(QQuickProfiler::ProfileSceneGraph,\
+ (QQuickProfiler::startSceneGraphFrame<Type>()))
#define Q_QUICK_SG_PROFILE_RECORD(Type)\
- Q_QUICK_PROFILE_IF_ENABLED((QQuickProfiler::recordSceneGraphTimestamp<Type>()))
+ Q_QUICK_PROFILE_IF_ENABLED(QQuickProfiler::ProfileSceneGraph,\
+ (QQuickProfiler::recordSceneGraphTimestamp<Type>()))
#define Q_QUICK_SG_PROFILE_SKIP(Type, Skip)\
- Q_QUICK_PROFILE_IF_ENABLED((QQuickProfiler::skipSceneGraphTimestamps<Type, Skip>()))
+ Q_QUICK_PROFILE_IF_ENABLED(QQuickProfiler::ProfileSceneGraph,\
+ (QQuickProfiler::skipSceneGraphTimestamps<Type, Skip>()))
#define Q_QUICK_SG_PROFILE_START_SYNCHRONIZED(Type1, Type2)\
- Q_QUICK_PROFILE_IF_ENABLED((QQuickProfiler::startSceneGraphFrame<Type1, Type2>()))
+ Q_QUICK_PROFILE_IF_ENABLED(QQuickProfiler::ProfileSceneGraph,\
+ (QQuickProfiler::startSceneGraphFrame<Type1, Type2>()))
#define Q_QUICK_SG_PROFILE_SWITCH(Type1, Type2) \
- Q_QUICK_PROFILE_IF_ENABLED((QQuickProfiler::reportSceneGraphFrame<Type1, true, Type2>()))
+ Q_QUICK_PROFILE_IF_ENABLED(QQuickProfiler::ProfileSceneGraph,\
+ (QQuickProfiler::reportSceneGraphFrame<Type1, true, Type2>()))
#define Q_QUICK_SG_PROFILE_REPORT(Type)\
- Q_QUICK_PROFILE_IF_ENABLED((QQuickProfiler::reportSceneGraphFrame<Type, false>()))
+ Q_QUICK_PROFILE_IF_ENABLED(QQuickProfiler::ProfileSceneGraph,\
+ (QQuickProfiler::reportSceneGraphFrame<Type, false>()))
#define Q_QUICK_SG_PROFILE_END(Type)\
- Q_QUICK_PROFILE_IF_ENABLED((QQuickProfiler::reportSceneGraphFrame<Type, true>()))
+ Q_QUICK_PROFILE_IF_ENABLED(QQuickProfiler::ProfileSceneGraph,\
+ (QQuickProfiler::reportSceneGraphFrame<Type, true>()))
#define Q_QUICK_SG_PROFILE_END_WITH_PAYLOAD(Type, Payload)\
- Q_QUICK_PROFILE_IF_ENABLED((QQuickProfiler::reportSceneGraphFrame<Type, true>(Payload)))
+ Q_QUICK_PROFILE_IF_ENABLED(QQuickProfiler::ProfileSceneGraph,\
+ (QQuickProfiler::reportSceneGraphFrame<Type, true>(Payload)))
+#define Q_QUICK_INPUT_PROFILE(Method)\
+ Q_QUICK_PROFILE(QQuickProfiler::ProfileInputEvents, Method)
// This struct is somewhat dangerous to use:
// You can save values either with 32 or 64 bit precision. toByteArrays will
@@ -302,7 +312,11 @@ public:
qint64 sendMessages(qint64 until, QList<QByteArray> &messages);
- static bool enabled;
+ static quint64 featuresEnabled;
+ static bool profilingSceneGraph()
+ {
+ return featuresEnabled & (1 << QQuickProfiler::ProfileSceneGraph);
+ }
static void initialize();
@@ -325,7 +339,7 @@ protected:
}
protected slots:
- void startProfilingImpl();
+ void startProfilingImpl(quint64 features);
void stopProfilingImpl();
void reportDataImpl();
void setTimer(const QElapsedTimer &t);