aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJ-P Nurmi <jpnurmi@qt.io>2017-12-11 21:49:53 +0100
committerJ-P Nurmi <jpnurmi@qt.io>2017-12-12 14:39:48 +0000
commitd9e740d2ccf8c1d3caacfcd95537718048e3a7ba (patch)
treed6a5cd642183974e1947275dee199270d3141310 /src
parent64a01ff5b5d1eaadb1e60013673ac25459b79e14 (diff)
Migitate the performance regression caused by deferred execution
458eb65f7 introduced a performance regression. Before 458eb65f7, qmlbench delegates_button.qml results were around 40 frames on a TX1. After 458eb65f, it dropped to 32. This patch is unfortunately not able to bring it on the original level, but at least improves the results to 37. For QQuickText, it is extremely important that implicitWidth() gets called before the component is completed, to avoid doing implicit size calculation multiple times. Deferred execution caused a performance regression by creating contentItem in "one go". We need to split the deferred execution to two parts so that bindings get first setup, and later enabled upon completion. This way, we utilize QQuickText's performance optimization for implicit size calculation. Task-number: QTBUG-50992 Change-Id: I4bf00af71b6d7dbf1d4b58b00fe547c6c321f8ed Reviewed-by: Mitch Curtis <mitch.curtis@qt.io>
Diffstat (limited to 'src')
-rw-r--r--src/quicktemplates2/qquickabstractbutton.cpp28
-rw-r--r--src/quicktemplates2/qquickabstractbutton_p_p.h2
-rw-r--r--src/quicktemplates2/qquickcontrol.cpp27
-rw-r--r--src/quicktemplates2/qquickcontrol_p_p.h4
-rw-r--r--src/quicktemplates2/qquickdeferredexecute.cpp29
-rw-r--r--src/quicktemplates2/qquickdeferredexecute_p_p.h22
6 files changed, 83 insertions, 29 deletions
diff --git a/src/quicktemplates2/qquickabstractbutton.cpp b/src/quicktemplates2/qquickabstractbutton.cpp
index f87ee0ef..48d5fceb 100644
--- a/src/quicktemplates2/qquickabstractbutton.cpp
+++ b/src/quicktemplates2/qquickabstractbutton.cpp
@@ -133,8 +133,9 @@ QQuickAbstractButtonPrivate::QQuickAbstractButtonPrivate()
QQuickItem *QQuickAbstractButtonPrivate::getContentItem()
{
- executeContentItem();
- return QQuickControlPrivate::getContentItem();
+ if (!contentItem)
+ executeContentItem();
+ return contentItem;
}
void QQuickAbstractButtonPrivate::handlePress(const QPointF &point)
@@ -265,10 +266,18 @@ void QQuickAbstractButtonPrivate::toggle(bool value)
emit q->toggled();
}
-void QQuickAbstractButtonPrivate::executeIndicator()
+static inline QString indicatorName() { return QStringLiteral("indicator"); }
+
+void QQuickAbstractButtonPrivate::executeIndicator(bool complete)
{
- Q_Q(QQuickAbstractButton);
- quickExecuteDeferred(q, QStringLiteral("indicator"), indicator);
+ Q_Q(QQuickControl);
+ if (indicator.wasExecuted())
+ return;
+
+ if (!indicator)
+ quickBeginDeferred(q, indicatorName(), indicator);
+ if (complete)
+ quickCompleteDeferred(q, indicatorName(), indicator);
}
QQuickAbstractButton *QQuickAbstractButtonPrivate::findCheckedButton() const
@@ -559,7 +568,8 @@ void QQuickAbstractButton::setAutoRepeat(bool repeat)
QQuickItem *QQuickAbstractButton::indicator() const
{
QQuickAbstractButtonPrivate *d = const_cast<QQuickAbstractButtonPrivate *>(d_func());
- d->executeIndicator();
+ if (!d->indicator)
+ d->executeIndicator();
return d->indicator;
}
@@ -594,9 +604,9 @@ void QQuickAbstractButton::toggle()
void QQuickAbstractButton::componentComplete()
{
Q_D(QQuickAbstractButton);
- d->executeIndicator();
- d->executeBackground();
- d->executeContentItem();
+ d->executeIndicator(true);
+ d->executeBackground(true);
+ d->executeContentItem(true);
QQuickControl::componentComplete();
}
diff --git a/src/quicktemplates2/qquickabstractbutton_p_p.h b/src/quicktemplates2/qquickabstractbutton_p_p.h
index 5a2a52c7..0d8eab81 100644
--- a/src/quicktemplates2/qquickabstractbutton_p_p.h
+++ b/src/quicktemplates2/qquickabstractbutton_p_p.h
@@ -87,7 +87,7 @@ public:
void toggle(bool value);
- void executeIndicator();
+ void executeIndicator(bool complete = false);
QString text;
bool down;
diff --git a/src/quicktemplates2/qquickcontrol.cpp b/src/quicktemplates2/qquickcontrol.cpp
index 51248745..2f3791d5 100644
--- a/src/quicktemplates2/qquickcontrol.cpp
+++ b/src/quicktemplates2/qquickcontrol.cpp
@@ -934,16 +934,32 @@ QLocale QQuickControlPrivate::calcLocale(const QQuickItem *item)
return QLocale();
}
-void QQuickControlPrivate::executeContentItem()
+static inline QString contentItemName() { return QStringLiteral("contentItem"); }
+
+void QQuickControlPrivate::executeContentItem(bool complete)
{
Q_Q(QQuickControl);
- quickExecuteDeferred(q, QStringLiteral("contentItem"), contentItem);
+ if (contentItem.wasExecuted())
+ return;
+
+ if (!contentItem)
+ quickBeginDeferred(q, contentItemName(), contentItem);
+ if (complete)
+ quickCompleteDeferred(q, contentItemName(), contentItem);
}
-void QQuickControlPrivate::executeBackground()
+static inline QString backgroundName() { return QStringLiteral("background"); }
+
+void QQuickControlPrivate::executeBackground(bool complete)
{
Q_Q(QQuickControl);
- quickExecuteDeferred(q, QStringLiteral("background"), background);
+ if (background.wasExecuted())
+ return;
+
+ if (!background)
+ quickBeginDeferred(q, backgroundName(), background);
+ if (complete)
+ quickCompleteDeferred(q, backgroundName(), background);
}
/*
@@ -1228,7 +1244,8 @@ void QQuickControl::setWheelEnabled(bool enabled)
QQuickItem *QQuickControl::background() const
{
QQuickControlPrivate *d = const_cast<QQuickControlPrivate *>(d_func());
- d->executeBackground();
+ if (!d->background)
+ d->executeBackground();
return d->background;
}
diff --git a/src/quicktemplates2/qquickcontrol_p_p.h b/src/quicktemplates2/qquickcontrol_p_p.h
index 84a42fa5..d8b1dd40 100644
--- a/src/quicktemplates2/qquickcontrol_p_p.h
+++ b/src/quicktemplates2/qquickcontrol_p_p.h
@@ -127,8 +127,8 @@ public:
static bool calcHoverEnabled(const QQuickItem *item);
#endif
- void executeContentItem();
- void executeBackground();
+ void executeContentItem(bool complete = false);
+ void executeBackground(bool complete = false);
static void destroyDelegate(QObject *object, QObject *parent);
diff --git a/src/quicktemplates2/qquickdeferredexecute.cpp b/src/quicktemplates2/qquickdeferredexecute.cpp
index 7ec4e8e8..802ed3d0 100644
--- a/src/quicktemplates2/qquickdeferredexecute.cpp
+++ b/src/quicktemplates2/qquickdeferredexecute.cpp
@@ -36,6 +36,7 @@
#include "qquickdeferredexecute_p_p.h"
+#include <QtCore/qhash.h>
#include <QtQml/qqmlengine.h>
#include <QtQml/private/qqmldata_p.h>
#include <QtQml/private/qqmlcomponent_p.h>
@@ -45,6 +46,15 @@ QT_BEGIN_NAMESPACE
namespace QtQuickPrivate {
+typedef QHash<uint, QQmlComponentPrivate::DeferredState *> DeferredStates;
+
+static inline uint qHash(QObject *object, const QString &propertyName)
+{
+ return ::qHash(object) + ::qHash(propertyName);
+}
+
+Q_GLOBAL_STATIC(DeferredStates, deferredStates)
+
static void beginDeferred(QQmlEnginePrivate *enginePriv, const QQmlProperty &property, QQmlComponentPrivate::DeferredState *deferredState)
{
QObject *object = property.object();
@@ -89,20 +99,31 @@ static void beginDeferred(QQmlEnginePrivate *enginePriv, const QQmlProperty &pro
}
}
-void executeDeferred(QObject *object, const QString &property)
+void beginDeferred(QObject *object, const QString &property)
{
QQmlData *data = QQmlData::get(object);
if (data && !data->deferredData.isEmpty() && !data->wasDeleted(object)) {
QQmlEnginePrivate *ep = QQmlEnginePrivate::get(data->context->engine);
- QQmlComponentPrivate::DeferredState state;
- beginDeferred(ep, QQmlProperty(object, property), &state);
+ QQmlComponentPrivate::DeferredState *state = new QQmlComponentPrivate::DeferredState;
+ beginDeferred(ep, QQmlProperty(object, property), state);
// Release deferred data for those compilation units that no longer have deferred bindings
data->releaseDeferredData();
- QQmlComponentPrivate::completeDeferred(ep, &state);
+ deferredStates()->insert(qHash(object, property), state);
+ }
+}
+
+void completeDeferred(QObject *object, const QString &property)
+{
+ QQmlData *data = QQmlData::get(object);
+ QQmlComponentPrivate::DeferredState *state = deferredStates()->take(qHash(object, property));
+ if (data && state && !data->wasDeleted(object)) {
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(data->context->engine);
+ QQmlComponentPrivate::completeDeferred(ep, state);
}
+ delete state;
}
} // QtQuickPrivate
diff --git a/src/quicktemplates2/qquickdeferredexecute_p_p.h b/src/quicktemplates2/qquickdeferredexecute_p_p.h
index 2157d7ef..87124e48 100644
--- a/src/quicktemplates2/qquickdeferredexecute_p_p.h
+++ b/src/quicktemplates2/qquickdeferredexecute_p_p.h
@@ -57,21 +57,27 @@ class QString;
class QObject;
namespace QtQuickPrivate {
- void executeDeferred(QObject *object, const QString &property);
+ void beginDeferred(QObject *object, const QString &property);
+ void completeDeferred(QObject *object, const QString &property);
}
template<typename T>
-void quickExecuteDeferred(QObject *object, const QString &property, QQuickDeferredPointer<T> &delegate)
+void quickBeginDeferred(QObject *object, const QString &property, QQuickDeferredPointer<T> &delegate)
{
- if (!delegate.isNull() || delegate.wasExecuted())
- return;
-
+ Q_ASSERT(delegate.isNull());
delegate.setExecuting(true);
- QtQuickPrivate::executeDeferred(object, property);
+ QtQuickPrivate::beginDeferred(object, property);
delegate.setExecuting(false);
+}
- if (!delegate.isNull())
- delegate.setExecuted();
+template<typename T>
+void quickCompleteDeferred(QObject *object, const QString &property, QQuickDeferredPointer<T> &delegate)
+{
+ Q_ASSERT(!delegate.wasExecuted());
+ delegate.setExecuting(true);
+ QtQuickPrivate::completeDeferred(object, property);
+ delegate.setExecuting(false);
+ delegate.setExecuted();
}
QT_END_NAMESPACE