aboutsummaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorJan Arve Sæther <jan-arve.saether@qt.io>2020-04-15 16:18:03 +0200
committerJan Arve Sæther <jan-arve.saether@qt.io>2020-05-04 15:11:12 +0200
commitcc77a0bc549ce8f0b218661e7ae0e82e5b89e0da (patch)
treed78d8902579be745ea823b10e56dcc2c4b06b89f /tests
parent788a3a183f8c49c1a88270c1456c3d47423df240 (diff)
Improve performance when dynamically adding items to a layout
This was especially noticeable when a Repeater was populating the children of a layout, and its model was dynamically changed: When the model was changed, the repeater removed one item at a time until all items were removed, then applied the new model and then added all the new items for the new model. The layout reacted to that by doing a full sync of the QML layout into the internal gridlayout engine each time an item got removed or added. For very large layouts (or layouts that have complex size hints to calculate), this caused a major slowdown. This patch fixes that by postponing the sync until we get a updatePolish(), basically replacing most calls to updateLayoutItems() (which does the sync) with a call to invalidate() (which schedules a polish). It will also get rid of some binding loop warnings due to this change. This means that there is a small change in behavior: impicitWidth, implicitHeight and Layout.{min,max}imum{Width,Height} might in some cases be incorrect until the updatePolish() have been done. (This is however consistent with how Row/Column/Grid behaves) The creation test in qmlbench was quite simple, so it did not suffer from the most severe performance issues, but we did not regress: > compareresults: auto/creation/layouts/delegates_rowlayout.qml: improvement by 3.91% auto/creation/layouts/delegates_columnlayout.qml: improvement by 6.59% auto/creation/layouts/delegates_gridlayout.qml: improvement by 1.83% Overall average of differences: 4.11% And for the gridlayout_large.qml (Repeater with 1000 dynamically changing items): > compareresults: auto/layouts/gridlayout_large.qml: improvement by 66477.78% Overall average of differences: 66477.78% [ChangeLog][Qt Quick Layouts] Performance improvements to Qt Quick Layouts. This has the small side-effect that size hints (implicitWidth/implicithHeight etc) changes are not immediately emitted after a layout has been modified (e.g item added) Pick-to: 5.15 Fixes: QTBUG-71839 Fixes: QTBUG-65121 Fixes: QTBUG-66017 Change-Id: I6922efe449134246df66b177992e4442747bc8fb Reviewed-by: Mitch Curtis <mitch.curtis@qt.io>
Diffstat (limited to 'tests')
-rw-r--r--tests/auto/quick/qquicklayouts/data/tst_gridlayout.qml60
-rw-r--r--tests/auto/quick/qquicklayouts/data/tst_rowlayout.qml89
-rw-r--r--tests/auto/quick/qquicklayouts/data/tst_stacklayout.qml2
3 files changed, 126 insertions, 25 deletions
diff --git a/tests/auto/quick/qquicklayouts/data/tst_gridlayout.qml b/tests/auto/quick/qquicklayouts/data/tst_gridlayout.qml
index be94fca8d4..0fa84a1617 100644
--- a/tests/auto/quick/qquicklayouts/data/tst_gridlayout.qml
+++ b/tests/auto/quick/qquicklayouts/data/tst_gridlayout.qml
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the test suite of the Qt Toolkit.
@@ -48,7 +48,7 @@
**
****************************************************************************/
-import QtQuick 2.2
+import QtQuick 2.6
import QtTest 1.0
import QtQuick.Layouts 1.1
@@ -1106,5 +1106,61 @@ Item {
layout.destroy()
}
+ // ------------------
+ Component {
+ id: replaceCell_QTBUG_65121
+ GridLayout {
+ id: gridLayout
+ anchors.fill: parent
+ columns: 2
+ property var categories: ['one', 'two', 'three']
+ property var values: [1, 2, 3]
+ Repeater {
+ model: gridLayout.categories
+ Item {
+ Layout.row: index
+ Layout.column: 0
+ Layout.preferredWidth: label.width
+ Layout.fillHeight: true
+ Text {
+ id: label
+ height: parent.height
+ anchors.right: parent.right
+ text: modelData
+ verticalAlignment: Text.AlignVCenter
+ font.pointSize: 27
+ leftPadding: 10
+ }
+ }
+ }
+ Repeater {
+ model: gridLayout.values
+ Item {
+ Layout.row: index
+ Layout.column: 1
+ Layout.preferredWidth: label.width
+ Layout.fillHeight: true
+ Text {
+ id: label
+ height: parent.height
+ anchors.right: parent.right
+ text: modelData
+ verticalAlignment: Text.AlignVCenter
+ font.pointSize: 27
+ leftPadding: 10
+ }
+ }
+ }
+ }
+ }
+ function test_replaceCell_QTBUG_65121() {
+ var layout = createTemporaryObject(replaceCell_QTBUG_65121, container)
+ verify(layout)
+ layout.categories = ["eleven", "twelve"]
+ layout.values = [11, 12]
+ verify(isPolishScheduled(layout))
+ verify(waitForItemPolished(layout))
+ // Shouldn't be any warnings, but no way to verify this currently: QTBUG-70029
+ }
}
}
diff --git a/tests/auto/quick/qquicklayouts/data/tst_rowlayout.qml b/tests/auto/quick/qquicklayouts/data/tst_rowlayout.qml
index 590249cf91..85fe54eca6 100644
--- a/tests/auto/quick/qquicklayouts/data/tst_rowlayout.qml
+++ b/tests/auto/quick/qquicklayouts/data/tst_rowlayout.qml
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the test suite of the Qt Toolkit.
@@ -69,6 +69,14 @@ Item {
}
Component {
+ id: rectangle_Component
+ Rectangle {
+ width: 100
+ height: 50
+ }
+ }
+
+ Component {
id: itemsWithAnchorsLayout_Component
RowLayout {
spacing: 2
@@ -193,8 +201,8 @@ Item {
} '
var tmp = Qt.createQmlObject(test_layoutStr, container, '');
- tryCompare(tmp, 'implicitWidth', 15);
- compare(tmp.implicitHeight, 20);
+ waitForRendering(tmp)
+ compare(tmp.implicitWidth, 15);
compare(tmp.height, 20);
tmp.width = 30
compare(tmp.r1.width, 10);
@@ -242,6 +250,46 @@ Item {
col.destroy()
}
+ Component {
+ id: propagateImplicitWidthToParent_Component
+ Item {
+ width: 200
+ height: 20
+
+ // These might trigger a updateLayoutItems() before its component is completed...
+ implicitWidth: row.implicitWidth
+ implicitHeight: row.implicitHeight
+ RowLayout {
+ id : row
+ anchors.fill: parent
+ property alias r1: _r1
+ property alias r2: _r2
+ spacing: 0
+ Rectangle {
+ id: _r1
+ color: "red"
+ implicitWidth: 50
+ implicitHeight: 20
+ }
+ Rectangle {
+ id: _r2
+ color: "green"
+ implicitWidth: 50
+ implicitHeight: 20
+ Layout.fillWidth: true
+ }
+ }
+ }
+ }
+
+ function test_propagateImplicitWidthToParent() {
+ var item = createTemporaryObject(propagateImplicitWidthToParent_Component, container)
+ var row = item.children[0]
+ compare(row.width, 200)
+ compare(itemRect(row.r1), [0, 0, 50, 20])
+ compare(itemRect(row.r2), [50, 0, 150, 20])
+ }
+
function test_implicitSize() {
var test_layoutStr =
'import QtQuick 2.2; \
@@ -272,6 +320,14 @@ Item {
var row = Qt.createQmlObject(test_layoutStr, container, '');
compare(row.implicitWidth, 50 + 10 + 40);
compare(row.implicitHeight, 6);
+ var r2 = row.children[2]
+ r2.implicitWidth = 20
+ verify(waitForRendering(row))
+ compare(row.implicitWidth, 50 + 10 + 20)
+ var r3 = rectangle_Component.createObject(container)
+ r3.implicitWidth = 30
+ r3.parent = row
+ compare(row.implicitWidth, 50 + 10 + 20 + 30)
row.destroy()
}
@@ -382,7 +438,7 @@ Item {
function test_addAndRemoveItems()
{
- var layout = layout_addAndRemoveItems_Component.createObject(container)
+ var layout = createTemporaryObject(layout_addAndRemoveItems_Component, container)
compare(layout.implicitWidth, 0)
compare(layout.implicitHeight, 0)
@@ -423,8 +479,6 @@ Item {
wait(0)
compare(layout.implicitWidth, 0)
compare(layout.implicitHeight, 0)
-
- layout.destroy()
}
Component {
@@ -543,6 +597,9 @@ Item {
Rectangle {
id: r1
color: "red"
+ implicitWidth: 1
+ implicitHeight: 1
+
Layout.minimumWidth: 1
Layout.preferredWidth: 2
Layout.maximumWidth: 3
@@ -622,13 +679,13 @@ Item {
child.Layout.minimumWidth = -1
compare(itemSizeHints(layout), [0, 2, 3])
child.Layout.preferredWidth = -1
- compare(itemSizeHints(layout), [0, 0, 3])
+ compare(itemSizeHints(layout), [0, 1, 3])
child.Layout.maximumWidth = -1
- compare(itemSizeHints(layout), [0, 0, Number.POSITIVE_INFINITY])
+ compare(itemSizeHints(layout), [0, 1, Number.POSITIVE_INFINITY])
layout.Layout.maximumWidth = 1000
- compare(itemSizeHints(layout), [0, 0, 1000])
+ compare(itemSizeHints(layout), [0, 1, 1000])
layout.Layout.maximumWidth = -1
- compare(itemSizeHints(layout), [0, 0, Number.POSITIVE_INFINITY])
+ compare(itemSizeHints(layout), [0, 1, Number.POSITIVE_INFINITY])
layout.implicitWidthChangedCount = 0
child.Layout.minimumWidth = 10
@@ -914,14 +971,6 @@ Item {
layout.destroy() // Do not crash
}
- Component {
- id: rectangle_Component
- Rectangle {
- width: 100
- height: 50
- }
- }
-
function test_destroyImplicitInvisibleLayout()
{
var root = rectangle_Component.createObject(container)
@@ -1179,10 +1228,6 @@ Item {
function test_rowlayoutWithTextItems() {
var layout = createTemporaryObject(rowlayoutWithTextItems_Component, container)
waitForRendering(layout)
- for (var i = 0; i < 3; i++) {
- ignoreWarning(/Qt Quick Layouts: Detected recursive rearrange. Aborting after two iterations./)
- }
- ignoreWarning(/Qt Quick Layouts: Polish loop detected. Aborting after two iterations./)
layout.width = layout.width - 2 // set the size to be smaller than its "minimum size"
waitForRendering(layout) // do not exit before all warnings have been received
diff --git a/tests/auto/quick/qquicklayouts/data/tst_stacklayout.qml b/tests/auto/quick/qquicklayouts/data/tst_stacklayout.qml
index 9c0b3f8635..c567b31db3 100644
--- a/tests/auto/quick/qquicklayouts/data/tst_stacklayout.qml
+++ b/tests/auto/quick/qquicklayouts/data/tst_stacklayout.qml
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the test suite of the Qt Toolkit.