From 99a83c8bad03a071f867bab41ffb149b38238ed6 Mon Sep 17 00:00:00 2001 From: Tim Blechmann Date: Mon, 29 Feb 2016 19:44:51 +0800 Subject: QQuickRenderControl: cleanup material cache on invalidate invalidate() releases resources, but doesn't clean up the materialCache, resulting in a memory leak Change-Id: I3cf7b7a3b977bb9aa295ef1824c384bcdf9494f2 Reviewed-by: Laszlo Agocs --- src/quick/items/qquickrendercontrol.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src') diff --git a/src/quick/items/qquickrendercontrol.cpp b/src/quick/items/qquickrendercontrol.cpp index d00b02c005..fd8d354594 100644 --- a/src/quick/items/qquickrendercontrol.cpp +++ b/src/quick/items/qquickrendercontrol.cpp @@ -48,6 +48,8 @@ #include #include +#include + QT_BEGIN_NAMESPACE extern Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha); @@ -175,6 +177,8 @@ void QQuickRenderControlPrivate::windowDestroyed() delete QQuickWindowPrivate::get(window)->animationController; QQuickWindowPrivate::get(window)->animationController = 0; + QQuickShaderEffectMaterial::cleanupMaterialCache(); + window = 0; } } -- cgit v1.2.3 From ac64e7b14d347aa021dde3b2ef5cfce2d5750dbe Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Sun, 21 Feb 2016 22:12:29 -0600 Subject: Ensure ShaderEffect correctly updates with supportsAtlasTexture. Given a simple ShaderEffect with supportsAtlasTexture: ShaderEffect { property variant source: myImage supportsAtlasTextures: true } ensure the atlas subrect used by the ShaderEffect is updated if myImage.source changes. Change-Id: I4560b80ba38c3487b16f53411451fb9891920738 Reviewed-by: Gunnar Sletta --- src/quick/items/qquickshadereffect.cpp | 8 ++++++++ src/quick/items/qquickshadereffect_p.h | 1 + src/quick/items/qquickshadereffectnode.cpp | 1 + src/quick/items/qquickshadereffectnode_p.h | 1 + 4 files changed, 11 insertions(+) (limited to 'src') diff --git a/src/quick/items/qquickshadereffect.cpp b/src/quick/items/qquickshadereffect.cpp index 349207f145..6cb9216955 100644 --- a/src/quick/items/qquickshadereffect.cpp +++ b/src/quick/items/qquickshadereffect.cpp @@ -952,6 +952,12 @@ void QQuickShaderEffect::updateGeometry() update(); } +void QQuickShaderEffect::updateGeometryIfAtlased() +{ + if (m_supportsAtlasTextures) + updateGeometry(); +} + void QQuickShaderEffect::updateLogAndStatus(const QString &log, int status) { m_log = parseLog() + log; @@ -1000,6 +1006,8 @@ QSGNode *QQuickShaderEffect::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDa m_dirtyUniforms = true; m_dirtyGeometry = true; connect(node, SIGNAL(logAndStatusChanged(QString,int)), this, SLOT(updateLogAndStatus(QString,int))); + connect(node, &QQuickShaderEffectNode::dirtyTexture, + this, &QQuickShaderEffect::updateGeometryIfAtlased); } QQuickShaderEffectMaterial *material = static_cast(node->material()); diff --git a/src/quick/items/qquickshadereffect_p.h b/src/quick/items/qquickshadereffect_p.h index a5e993ee0c..4ed87e88ac 100644 --- a/src/quick/items/qquickshadereffect_p.h +++ b/src/quick/items/qquickshadereffect_p.h @@ -167,6 +167,7 @@ protected: private Q_SLOTS: void updateGeometry(); + void updateGeometryIfAtlased(); void updateLogAndStatus(const QString &log, int status); void sourceDestroyed(QObject *object); void propertyChanged(int mappedId); diff --git a/src/quick/items/qquickshadereffectnode.cpp b/src/quick/items/qquickshadereffectnode.cpp index 081e572e3b..954aa6c67b 100644 --- a/src/quick/items/qquickshadereffectnode.cpp +++ b/src/quick/items/qquickshadereffectnode.cpp @@ -491,6 +491,7 @@ QQuickShaderEffectNode::~QQuickShaderEffectNode() void QQuickShaderEffectNode::markDirtyTexture() { markDirty(DirtyMaterial); + Q_EMIT dirtyTexture(); } void QQuickShaderEffectNode::textureProviderDestroyed(QObject *object) diff --git a/src/quick/items/qquickshadereffectnode_p.h b/src/quick/items/qquickshadereffectnode_p.h index 76aecd1b04..8a7fd6c3a5 100644 --- a/src/quick/items/qquickshadereffectnode_p.h +++ b/src/quick/items/qquickshadereffectnode_p.h @@ -142,6 +142,7 @@ public: Q_SIGNALS: void logAndStatusChanged(const QString &, int status); + void dirtyTexture(); private Q_SLOTS: void markDirtyTexture(); -- cgit v1.2.3 From 83cb2069ead120e7777a13ef6b7c0a0b14052685 Mon Sep 17 00:00:00 2001 From: Robin Burchell Date: Sun, 28 Feb 2016 22:43:42 +0100 Subject: QQuickText{Edit,Input}: Reset selection when becoming readOnly. When read only, controls may not be edited or altered, and indeed, a read-only control cannot acquire a selection (as it cannot be interacted with). Leaving an existing selection breaks that implication, so clear it when becoming read-only. [ChangeLog][QtQuick][TextEdit/TextInput] If a control has a selection, it is now cleared when becoming read-only. Task-number: QTBUG-51115 Change-Id: Ife43b97ee3d6b780f09a938868c3ccb2f1b6e6e7 Reviewed-by: Simon Hausmann --- src/quick/items/qquicktextedit.cpp | 3 +-- src/quick/items/qquicktextinput.cpp | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/quick/items/qquicktextedit.cpp b/src/quick/items/qquicktextedit.cpp index f6c3d2f09f..f2e9f63fa9 100644 --- a/src/quick/items/qquicktextedit.cpp +++ b/src/quick/items/qquicktextedit.cpp @@ -1534,8 +1534,7 @@ void QQuickTextEdit::setReadOnly(bool r) if (!r) flags = flags | Qt::TextEditable; d->control->setTextInteractionFlags(flags); - if (!r) - d->control->moveCursor(QTextCursor::End); + d->control->moveCursor(QTextCursor::End); #ifndef QT_NO_IM updateInputMethod(Qt::ImEnabled); diff --git a/src/quick/items/qquicktextinput.cpp b/src/quick/items/qquicktextinput.cpp index 7a86e1a323..4b816c41c3 100644 --- a/src/quick/items/qquicktextinput.cpp +++ b/src/quick/items/qquicktextinput.cpp @@ -679,8 +679,7 @@ void QQuickTextInput::setReadOnly(bool ro) setFlag(QQuickItem::ItemAcceptsInputMethod, !ro); #endif d->m_readOnly = ro; - if (!ro) - d->setCursorPosition(d->end()); + d->setCursorPosition(d->end()); #ifndef QT_NO_IM updateInputMethod(Qt::ImEnabled); #endif -- cgit v1.2.3 From df16c819cb4ee096a38c8c013cbb26a0ca561432 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Thu, 18 Feb 2016 11:39:07 +0100 Subject: Clear profiling data from QQuickProfiler after reporting This is what 5.6 does. It's debatable if this is actually correct, as logically we should report the same global profiling data multiple times, when data for different engines is reported. However, there is no practical benefit for such a "feature". It just wastes CPU time and memory and it makes the client implementation more complicated. Change-Id: I6d2a253d906d3d74c9d9b1f8fc952673c9da3e2a Reviewed-by: Kai Koehne --- src/quick/util/qquickprofiler.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/quick/util/qquickprofiler.cpp b/src/quick/util/qquickprofiler.cpp index dc72b5f287..f8d090cc2c 100644 --- a/src/quick/util/qquickprofiler.cpp +++ b/src/quick/util/qquickprofiler.cpp @@ -99,22 +99,22 @@ QQuickProfiler::~QQuickProfiler() void QQuickProfiler::startProfilingImpl(quint64 features) { QMutexLocker lock(&m_dataMutex); - m_data.clear(); featuresEnabled = features; } void QQuickProfiler::stopProfilingImpl() { - { - QMutexLocker lock(&m_dataMutex); - featuresEnabled = 0; - } + QMutexLocker lock(&m_dataMutex); + featuresEnabled = 0; emit dataReady(m_data); + m_data.clear(); } void QQuickProfiler::reportDataImpl() { + QMutexLocker lock(&m_dataMutex); emit dataReady(m_data); + m_data.clear(); } void QQuickProfiler::setTimer(const QElapsedTimer &t) -- cgit v1.2.3 From b9dd708bde39fb7eb01a5a212ea554fc0cc88923 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Tue, 1 Mar 2016 15:08:39 +0100 Subject: V4: fix bootstrapped builds on Ubuntu 32bit. We use 64bit value encoding there, so gcc complained that memcpy would write 8 bytes to a 4 byte pointer value. Change-Id: Ib44372fb0e4bbacf0279930f7f5fcf4bbb5d48bf Reviewed-by: Nikolai Kosjar --- src/qml/jsruntime/qv4value_p.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h index 089b2bbd34..723afcab54 100644 --- a/src/qml/jsruntime/qv4value_p.h +++ b/src/qml/jsruntime/qv4value_p.h @@ -113,11 +113,14 @@ struct Q_QML_PRIVATE_EXPORT Value Q_ALWAYS_INLINE quint32 value() const { return _val >> 32; } #endif -#ifdef QV4_USE_64_BIT_VALUE_ENCODING +#if defined(V4_BOOTSTRAP) + Q_ALWAYS_INLINE Heap::Base *m() const { Q_UNREACHABLE(); return Q_NULLPTR; } + Q_ALWAYS_INLINE void setM(Heap::Base *b) { Q_UNUSED(b); Q_UNREACHABLE(); } +#elif defined(QV4_USE_64_BIT_VALUE_ENCODING) Q_ALWAYS_INLINE Heap::Base *m() const { Heap::Base *b; memcpy(&b, &_val, 8); return b; } Q_ALWAYS_INLINE void setM(Heap::Base *b) { memcpy(&_val, &b, 8); } #else // !QV4_USE_64_BIT_VALUE_ENCODING - Q_ALWAYS_INLINE Heap::Base *m() const { Heap::Base *b; quint32 v = value(); memcpy(&b, &v, 4); return b; } + Q_ALWAYS_INLINE Heap::Base *m() const { Q_STATIC_ASSERT(sizeof(Heap::Base*) == sizeof(quint32)); Heap::Base *b; quint32 v = value(); memcpy(&b, &v, 4); return b; } Q_ALWAYS_INLINE void setM(Heap::Base *b) { quint32 v; memcpy(&v, &b, 4); setValue(v); } #endif -- cgit v1.2.3 From 8a99d2e11b1d4971faa489cef626b70a7d828d17 Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Thu, 3 Mar 2016 08:25:32 +0100 Subject: Fix typo in QQmlContext documentation Change-Id: Iea662214988c35473a8526c546f01ac5629308dc Reviewed-by: Venugopal Shivashankar --- src/qml/qml/qqmlcontext.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/qml/qml/qqmlcontext.cpp b/src/qml/qml/qqmlcontext.cpp index b056731e96..1d1134bb74 100644 --- a/src/qml/qml/qqmlcontext.cpp +++ b/src/qml/qml/qqmlcontext.cpp @@ -89,7 +89,7 @@ QQmlContextPrivate::QQmlContextPrivate() by name in the context, as though they were all individually added through calls to QQmlContext::setContextProperty(). Changes to the property's values are detected through the property's notify signal. Setting a context object is both - faster and easier than manually adding and maintaing context property values. + faster and easier than manually adding and maintaining context property values. The following example has the same effect as the previous one, but it uses a context object. -- cgit v1.2.3 From 0e0c351fff752ceadc99eef5fbcf5a180f453efc Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Thu, 3 Mar 2016 10:45:35 +0100 Subject: Make public headers compile with -Wzero-as-null-pointer-constant ... or equivalent. QtBase 5.6 headers already compile that way, so let the other modules follow suit. Task-number: QTBUG-45291 Change-Id: Ied526fb2d7adc3a68946d6843a6bd6f475ebf864 Reviewed-by: Lars Knoll --- src/qml/jsapi/qjsengine.h | 2 +- src/qml/qml/qqml.h | 55 ++++++++++++---------- src/qml/qml/qqmlapplicationengine.h | 6 +-- src/qml/qml/qqmlcomponent.h | 18 +++---- src/qml/qml/qqmlcontext.h | 4 +- src/qml/qml/qqmlengine.h | 2 +- src/qml/qml/qqmlexpression.h | 6 +-- src/qml/qml/qqmlextensionplugin.h | 2 +- src/qml/qml/qqmlfileselector.h | 2 +- src/qml/qml/qqmllist.h | 36 ++++++++++++-- src/qml/util/qqmlpropertymap.h | 2 +- src/quick/items/qquickframebufferobject.h | 2 +- src/quick/items/qquickitem.h | 6 +-- src/quick/items/qquickitemgrabresult.h | 2 +- src/quick/items/qquickpainteditem.h | 4 +- src/quick/items/qquickrendercontrol.h | 6 +-- src/quick/items/qquickview.h | 4 +- src/quick/items/qquickwindow.h | 6 +-- src/quick/scenegraph/coreapi/qsgabstractrenderer.h | 2 +- src/quick/scenegraph/coreapi/qsgnode.h | 2 +- src/quick/scenegraph/util/qsgengine.h | 6 +-- src/quick/util/qquickimageprovider.h | 2 +- src/quickwidgets/qquickwidget.h | 4 +- 23 files changed, 106 insertions(+), 75 deletions(-) (limited to 'src') diff --git a/src/qml/jsapi/qjsengine.h b/src/qml/jsapi/qjsengine.h index 40b0a60369..c3f3ace1dd 100644 --- a/src/qml/jsapi/qjsengine.h +++ b/src/qml/jsapi/qjsengine.h @@ -105,7 +105,7 @@ private: friend inline bool qjsvalue_cast_helper(const QJSValue &, int, void *); protected: - QJSEngine(QJSEnginePrivate &dd, QObject *parent = 0); + QJSEngine(QJSEnginePrivate &dd, QObject *parent = Q_NULLPTR); private: QV8Engine *d; diff --git a/src/qml/qml/qqml.h b/src/qml/qml/qqml.h index 23cb69e2f1..02618f77f5 100644 --- a/src/qml/qml/qqml.h +++ b/src/qml/qml/qqml.h @@ -105,10 +105,11 @@ int qmlRegisterType() qRegisterNormalizedMetaType(pointerName.constData()), qRegisterNormalizedMetaType >(listName.constData()), - 0, 0, + 0, + Q_NULLPTR, QString(), - 0, 0, 0, 0, &T::staticMetaObject, + Q_NULLPTR, 0, 0, Q_NULLPTR, &T::staticMetaObject, QQmlPrivate::attachedPropertiesFunc(), QQmlPrivate::attachedPropertiesMetaObject(), @@ -117,9 +118,9 @@ int qmlRegisterType() QQmlPrivate::StaticCastSelector::cast(), QQmlPrivate::StaticCastSelector::cast(), - 0, 0, + Q_NULLPTR, Q_NULLPTR, - 0, + Q_NULLPTR, 0 }; @@ -138,7 +139,8 @@ int qmlRegisterUncreatableType(const char *uri, int versionMajor, int versionMin qRegisterNormalizedMetaType(pointerName.constData()), qRegisterNormalizedMetaType >(listName.constData()), - 0, 0, + 0, + Q_NULLPTR, reason, uri, versionMajor, versionMinor, qmlName, &T::staticMetaObject, @@ -150,9 +152,9 @@ int qmlRegisterUncreatableType(const char *uri, int versionMajor, int versionMin QQmlPrivate::StaticCastSelector::cast(), QQmlPrivate::StaticCastSelector::cast(), - 0, 0, + Q_NULLPTR, Q_NULLPTR, - 0, + Q_NULLPTR, 0 }; @@ -169,7 +171,8 @@ int qmlRegisterUncreatableType(const char *uri, int versionMajor, int versionMin qRegisterNormalizedMetaType(pointerName.constData()), qRegisterNormalizedMetaType >(listName.constData()), - 0, 0, + 0, + Q_NULLPTR, reason, uri, versionMajor, versionMinor, qmlName, &T::staticMetaObject, @@ -181,9 +184,9 @@ int qmlRegisterUncreatableType(const char *uri, int versionMajor, int versionMin QQmlPrivate::StaticCastSelector::cast(), QQmlPrivate::StaticCastSelector::cast(), - 0, 0, + Q_NULLPTR, Q_NULLPTR, - 0, + Q_NULLPTR, metaObjectRevision }; @@ -207,7 +210,8 @@ int qmlRegisterExtendedUncreatableType(const char *uri, int versionMajor, int ve qRegisterNormalizedMetaType(pointerName.constData()), qRegisterNormalizedMetaType >(listName.constData()), - 0, 0, + 0, + Q_NULLPTR, reason, uri, versionMajor, versionMinor, qmlName, &T::staticMetaObject, @@ -221,7 +225,7 @@ int qmlRegisterExtendedUncreatableType(const char *uri, int versionMajor, int ve QQmlPrivate::createParent, &E::staticMetaObject, - 0, + Q_NULLPTR, 0 }; @@ -250,9 +254,9 @@ int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const c QQmlPrivate::StaticCastSelector::cast(), QQmlPrivate::StaticCastSelector::cast(), - 0, 0, + Q_NULLPTR, Q_NULLPTR, - 0, + Q_NULLPTR, 0 }; @@ -281,9 +285,9 @@ int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const c QQmlPrivate::StaticCastSelector::cast(), QQmlPrivate::StaticCastSelector::cast(), - 0, 0, + Q_NULLPTR, Q_NULLPTR, - 0, + Q_NULLPTR, metaObjectRevision }; @@ -312,9 +316,9 @@ int qmlRegisterRevision(const char *uri, int versionMajor, int versionMinor) QQmlPrivate::StaticCastSelector::cast(), QQmlPrivate::StaticCastSelector::cast(), - 0, 0, + Q_NULLPTR, Q_NULLPTR, - 0, + Q_NULLPTR, metaObjectRevision }; @@ -332,10 +336,11 @@ int qmlRegisterExtendedType() qRegisterNormalizedMetaType(pointerName.constData()), qRegisterNormalizedMetaType >(listName.constData()), - 0, 0, + 0, + Q_NULLPTR, QString(), - 0, 0, 0, 0, &T::staticMetaObject, + Q_NULLPTR, 0, 0, Q_NULLPTR, &T::staticMetaObject, QQmlPrivate::attachedPropertiesFunc(), QQmlPrivate::attachedPropertiesMetaObject(), @@ -346,7 +351,7 @@ int qmlRegisterExtendedType() QQmlPrivate::createParent, &E::staticMetaObject, - 0, + Q_NULLPTR, 0 }; @@ -385,7 +390,7 @@ int qmlRegisterExtendedType(const char *uri, int versionMajor, int versionMinor, QQmlPrivate::createParent, &E::staticMetaObject, - 0, + Q_NULLPTR, 0 }; @@ -435,7 +440,7 @@ int qmlRegisterCustomType(const char *uri, int versionMajor, int versionMinor, QQmlPrivate::StaticCastSelector::cast(), QQmlPrivate::StaticCastSelector::cast(), - 0, 0, + Q_NULLPTR, Q_NULLPTR, parser, 0 @@ -530,7 +535,7 @@ inline int qmlRegisterSingletonType(const char *uri, int versionMajor, int versi uri, versionMajor, versionMinor, typeName, - callback, 0, 0, 0, 0 + callback, Q_NULLPTR, Q_NULLPTR, 0, 0 }; return QQmlPrivate::qmlregister(QQmlPrivate::SingletonRegistration, &api); @@ -548,7 +553,7 @@ inline int qmlRegisterSingletonType(const char *uri, int versionMajor, int versi uri, versionMajor, versionMinor, typeName, - 0, callback, &T::staticMetaObject, qRegisterNormalizedMetaType(pointerName.constData()), 0 + Q_NULLPTR, callback, &T::staticMetaObject, qRegisterNormalizedMetaType(pointerName.constData()), 0 }; return QQmlPrivate::qmlregister(QQmlPrivate::SingletonRegistration, &api); diff --git a/src/qml/qml/qqmlapplicationengine.h b/src/qml/qml/qqmlapplicationengine.h index 84cb2625dc..3b91d6adfc 100644 --- a/src/qml/qml/qqmlapplicationengine.h +++ b/src/qml/qml/qqmlapplicationengine.h @@ -47,9 +47,9 @@ class Q_QML_EXPORT QQmlApplicationEngine : public QQmlEngine { Q_OBJECT public: - QQmlApplicationEngine(QObject *parent=0); - QQmlApplicationEngine(const QUrl &url, QObject *parent=0); - QQmlApplicationEngine(const QString &filePath, QObject *parent=0); + QQmlApplicationEngine(QObject *parent = Q_NULLPTR); + QQmlApplicationEngine(const QUrl &url, QObject *parent = Q_NULLPTR); + QQmlApplicationEngine(const QString &filePath, QObject *parent = Q_NULLPTR); ~QQmlApplicationEngine(); QList rootObjects(); diff --git a/src/qml/qml/qqmlcomponent.h b/src/qml/qml/qqmlcomponent.h index 121c83db5c..58cbadff00 100644 --- a/src/qml/qml/qqmlcomponent.h +++ b/src/qml/qml/qqmlcomponent.h @@ -66,12 +66,12 @@ public: enum CompilationMode { PreferSynchronous, Asynchronous }; Q_ENUM(CompilationMode) - QQmlComponent(QObject *parent = 0); - QQmlComponent(QQmlEngine *, QObject *parent=0); - QQmlComponent(QQmlEngine *, const QString &fileName, QObject *parent = 0); - QQmlComponent(QQmlEngine *, const QString &fileName, CompilationMode mode, QObject *parent = 0); - QQmlComponent(QQmlEngine *, const QUrl &url, QObject *parent = 0); - QQmlComponent(QQmlEngine *, const QUrl &url, CompilationMode mode, QObject *parent = 0); + QQmlComponent(QObject *parent = Q_NULLPTR); + QQmlComponent(QQmlEngine *, QObject *parent = Q_NULLPTR); + QQmlComponent(QQmlEngine *, const QString &fileName, QObject *parent = Q_NULLPTR); + QQmlComponent(QQmlEngine *, const QString &fileName, CompilationMode mode, QObject *parent = Q_NULLPTR); + QQmlComponent(QQmlEngine *, const QUrl &url, QObject *parent = Q_NULLPTR); + QQmlComponent(QQmlEngine *, const QUrl &url, CompilationMode mode, QObject *parent = Q_NULLPTR); virtual ~QQmlComponent(); enum Status { Null, Ready, Loading, Error }; @@ -90,12 +90,12 @@ public: QUrl url() const; - virtual QObject *create(QQmlContext *context = 0); + virtual QObject *create(QQmlContext *context = Q_NULLPTR); virtual QObject *beginCreate(QQmlContext *); virtual void completeCreate(); - void create(QQmlIncubator &, QQmlContext *context = 0, - QQmlContext *forContext = 0); + void create(QQmlIncubator &, QQmlContext *context = Q_NULLPTR, + QQmlContext *forContext = Q_NULLPTR); QQmlContext *creationContext() const; diff --git a/src/qml/qml/qqmlcontext.h b/src/qml/qml/qqmlcontext.h index e69a2f8f69..3049ec7f71 100644 --- a/src/qml/qml/qqmlcontext.h +++ b/src/qml/qml/qqmlcontext.h @@ -56,8 +56,8 @@ class Q_QML_EXPORT QQmlContext : public QObject Q_DECLARE_PRIVATE(QQmlContext) public: - QQmlContext(QQmlEngine *parent, QObject *objParent=0); - QQmlContext(QQmlContext *parent, QObject *objParent=0); + QQmlContext(QQmlEngine *parent, QObject *objParent = Q_NULLPTR); + QQmlContext(QQmlContext *parent, QObject *objParent = Q_NULLPTR); virtual ~QQmlContext(); bool isValid() const; diff --git a/src/qml/qml/qqmlengine.h b/src/qml/qml/qqmlengine.h index 61a884279d..a0d47c33a6 100644 --- a/src/qml/qml/qqmlengine.h +++ b/src/qml/qml/qqmlengine.h @@ -88,7 +88,7 @@ class Q_QML_EXPORT QQmlEngine : public QJSEngine Q_PROPERTY(QString offlineStoragePath READ offlineStoragePath WRITE setOfflineStoragePath) Q_OBJECT public: - QQmlEngine(QObject *p = 0); + QQmlEngine(QObject *p = Q_NULLPTR); virtual ~QQmlEngine(); QQmlContext *rootContext() const; diff --git a/src/qml/qml/qqmlexpression.h b/src/qml/qml/qqmlexpression.h index 408871cfc5..e3e96f8030 100644 --- a/src/qml/qml/qqmlexpression.h +++ b/src/qml/qml/qqmlexpression.h @@ -54,8 +54,8 @@ class Q_QML_EXPORT QQmlExpression : public QObject Q_OBJECT public: QQmlExpression(); - QQmlExpression(QQmlContext *, QObject *, const QString &, QObject * = 0); - explicit QQmlExpression(const QQmlScriptString &, QQmlContext * = 0, QObject * = 0, QObject * = 0); + QQmlExpression(QQmlContext *, QObject *, const QString &, QObject * = Q_NULLPTR); + explicit QQmlExpression(const QQmlScriptString &, QQmlContext * = Q_NULLPTR, QObject * = Q_NULLPTR, QObject * = Q_NULLPTR); virtual ~QQmlExpression(); QQmlEngine *engine() const; @@ -78,7 +78,7 @@ public: void clearError(); QQmlError error() const; - QVariant evaluate(bool *valueIsUndefined = 0); + QVariant evaluate(bool *valueIsUndefined = Q_NULLPTR); Q_SIGNALS: void valueChanged(); diff --git a/src/qml/qml/qqmlextensionplugin.h b/src/qml/qml/qqmlextensionplugin.h index 879cc91abe..074b5e2531 100644 --- a/src/qml/qml/qqmlextensionplugin.h +++ b/src/qml/qml/qqmlextensionplugin.h @@ -52,7 +52,7 @@ class Q_QML_EXPORT QQmlExtensionPlugin Q_INTERFACES(QQmlExtensionInterface) Q_INTERFACES(QQmlTypesExtensionInterface) public: - explicit QQmlExtensionPlugin(QObject *parent = 0); + explicit QQmlExtensionPlugin(QObject *parent = Q_NULLPTR); ~QQmlExtensionPlugin(); QUrl baseUrl() const; diff --git a/src/qml/qml/qqmlfileselector.h b/src/qml/qml/qqmlfileselector.h index d86908e9cb..3af63a8293 100644 --- a/src/qml/qml/qqmlfileselector.h +++ b/src/qml/qml/qqmlfileselector.h @@ -48,7 +48,7 @@ class Q_QML_EXPORT QQmlFileSelector : public QObject Q_OBJECT Q_DECLARE_PRIVATE(QQmlFileSelector) public: - QQmlFileSelector(QQmlEngine* engine, QObject* parent=0); + QQmlFileSelector(QQmlEngine *engine, QObject *parent = Q_NULLPTR); ~QQmlFileSelector(); void setSelector(QFileSelector *selector); void setExtraSelectors(QStringList &strings); // TODO Qt6: remove diff --git a/src/qml/qml/qqmllist.h b/src/qml/qml/qqmllist.h index edd61b26c9..5a06299f3b 100644 --- a/src/qml/qml/qqmllist.h +++ b/src/qml/qml/qqmllist.h @@ -55,15 +55,41 @@ public: typedef void (*ClearFunction)(QQmlListProperty *); QQmlListProperty() - : object(0), data(0), append(0), count(0), at(0), clear(0), dummy1(0), dummy2(0) {} + : object(Q_NULLPTR), + data(Q_NULLPTR), + append(Q_NULLPTR), + count(Q_NULLPTR), + at(Q_NULLPTR), + clear(Q_NULLPTR), + dummy1(Q_NULLPTR), + dummy2(Q_NULLPTR) + {} QQmlListProperty(QObject *o, QList &list) : object(o), data(&list), append(qlist_append), count(qlist_count), at(qlist_at), - clear(qlist_clear), dummy1(0), dummy2(0) {} + clear(qlist_clear), + dummy1(Q_NULLPTR), + dummy2(Q_NULLPTR) + {} QQmlListProperty(QObject *o, void *d, AppendFunction a, CountFunction c, AtFunction t, ClearFunction r ) - : object(o), data(d), append(a), count(c), at(t), clear(r), dummy1(0), dummy2(0) {} + : object(o), + data(d), + append(a), + count(c), + at(t), + clear(r), + dummy1(Q_NULLPTR), + dummy2(Q_NULLPTR) + {} QQmlListProperty(QObject *o, void *d, CountFunction c, AtFunction t) - : object(o), data(d), append(0), count(c), at(t), clear(0), dummy1(0), dummy2(0) {} + : object(o), + data(d), + append(Q_NULLPTR), + count(c), at(t), + clear(Q_NULLPTR), + dummy1(Q_NULLPTR), + dummy2(Q_NULLPTR) + {} bool operator==(const QQmlListProperty &o) const { return object == o.object && data == o.data && @@ -108,7 +134,7 @@ class Q_QML_EXPORT QQmlListReference { public: QQmlListReference(); - QQmlListReference(QObject *, const char *property, QQmlEngine * = 0); + QQmlListReference(QObject *, const char *property, QQmlEngine * = Q_NULLPTR); QQmlListReference(const QQmlListReference &); QQmlListReference &operator=(const QQmlListReference &); ~QQmlListReference(); diff --git a/src/qml/util/qqmlpropertymap.h b/src/qml/util/qqmlpropertymap.h index 685f771452..028a299eec 100644 --- a/src/qml/util/qqmlpropertymap.h +++ b/src/qml/util/qqmlpropertymap.h @@ -49,7 +49,7 @@ class Q_QML_EXPORT QQmlPropertyMap : public QObject { Q_OBJECT public: - explicit QQmlPropertyMap(QObject *parent = 0); + explicit QQmlPropertyMap(QObject *parent = Q_NULLPTR); virtual ~QQmlPropertyMap(); QVariant value(const QString &key) const; diff --git a/src/quick/items/qquickframebufferobject.h b/src/quick/items/qquickframebufferobject.h index 7fb7262222..ec40e7e97e 100644 --- a/src/quick/items/qquickframebufferobject.h +++ b/src/quick/items/qquickframebufferobject.h @@ -69,7 +69,7 @@ public: void *data; }; - QQuickFramebufferObject(QQuickItem *parent = 0); + QQuickFramebufferObject(QQuickItem *parent = Q_NULLPTR); bool textureFollowsItemSize() const; void setTextureFollowsItemSize(bool follows); diff --git a/src/quick/items/qquickitem.h b/src/quick/items/qquickitem.h index bda6dd4da5..bf208e1f3e 100644 --- a/src/quick/items/qquickitem.h +++ b/src/quick/items/qquickitem.h @@ -53,7 +53,7 @@ class Q_QUICK_EXPORT QQuickTransform : public QObject { Q_OBJECT public: - QQuickTransform(QObject *parent = 0); + explicit QQuickTransform(QObject *parent = Q_NULLPTR); ~QQuickTransform(); void appendToItem(QQuickItem *); @@ -189,7 +189,7 @@ public: }; Q_ENUM(TransformOrigin) - QQuickItem(QQuickItem *parent = 0); + explicit QQuickItem(QQuickItem *parent = Q_NULLPTR); virtual ~QQuickItem(); QQuickWindow *window() const; @@ -430,7 +430,7 @@ protected: virtual void updatePolish(); protected: - QQuickItem(QQuickItemPrivate &dd, QQuickItem *parent = 0); + QQuickItem(QQuickItemPrivate &dd, QQuickItem *parent = Q_NULLPTR); private: Q_PRIVATE_SLOT(d_func(), void _q_resourceObjectDeleted(QObject *)) diff --git a/src/quick/items/qquickitemgrabresult.h b/src/quick/items/qquickitemgrabresult.h index 055cd09095..027ed19d9e 100644 --- a/src/quick/items/qquickitemgrabresult.h +++ b/src/quick/items/qquickitemgrabresult.h @@ -73,7 +73,7 @@ private Q_SLOTS: private: friend class QQuickItem; - QQuickItemGrabResult(QObject *parent = 0); + QQuickItemGrabResult(QObject *parent = Q_NULLPTR); }; QT_END_NAMESPACE diff --git a/src/quick/items/qquickpainteditem.h b/src/quick/items/qquickpainteditem.h index 8c9ae2eebb..85e90e7263 100644 --- a/src/quick/items/qquickpainteditem.h +++ b/src/quick/items/qquickpainteditem.h @@ -51,7 +51,7 @@ class Q_QUICK_EXPORT QQuickPaintedItem : public QQuickItem Q_PROPERTY(QSize textureSize READ textureSize WRITE setTextureSize NOTIFY textureSizeChanged) public: - QQuickPaintedItem(QQuickItem *parent = 0); + QQuickPaintedItem(QQuickItem *parent = Q_NULLPTR); virtual ~QQuickPaintedItem(); enum RenderTarget { @@ -112,7 +112,7 @@ Q_SIGNALS: void textureSizeChanged(); protected: - QQuickPaintedItem(QQuickPaintedItemPrivate &dd, QQuickItem *parent = 0); + QQuickPaintedItem(QQuickPaintedItemPrivate &dd, QQuickItem *parent = Q_NULLPTR); QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) Q_DECL_OVERRIDE; void releaseResources() Q_DECL_OVERRIDE; diff --git a/src/quick/items/qquickrendercontrol.h b/src/quick/items/qquickrendercontrol.h index ff80acf766..1132585a66 100644 --- a/src/quick/items/qquickrendercontrol.h +++ b/src/quick/items/qquickrendercontrol.h @@ -49,7 +49,7 @@ class Q_QUICK_EXPORT QQuickRenderControl : public QObject Q_OBJECT public: - QQuickRenderControl(QObject *parent = 0); + QQuickRenderControl(QObject *parent = Q_NULLPTR); ~QQuickRenderControl(); void prepareThread(QThread *targetThread); @@ -62,8 +62,8 @@ public: QImage grab(); - static QWindow *renderWindowFor(QQuickWindow *win, QPoint *offset = 0); - virtual QWindow *renderWindow(QPoint *offset) { Q_UNUSED(offset); return 0; } + static QWindow *renderWindowFor(QQuickWindow *win, QPoint *offset = Q_NULLPTR); + virtual QWindow *renderWindow(QPoint *offset) { Q_UNUSED(offset); return Q_NULLPTR; } Q_SIGNALS: void renderRequested(); diff --git a/src/quick/items/qquickview.h b/src/quick/items/qquickview.h index 80da0ba4f1..28be948ff4 100644 --- a/src/quick/items/qquickview.h +++ b/src/quick/items/qquickview.h @@ -54,9 +54,9 @@ class Q_QUICK_EXPORT QQuickView : public QQuickWindow Q_PROPERTY(Status status READ status NOTIFY statusChanged) Q_PROPERTY(QUrl source READ source WRITE setSource DESIGNABLE true) public: - explicit QQuickView(QWindow *parent = 0); + explicit QQuickView(QWindow *parent = Q_NULLPTR); QQuickView(QQmlEngine* engine, QWindow *parent); - QQuickView(const QUrl &source, QWindow *parent = 0); + QQuickView(const QUrl &source, QWindow *parent = Q_NULLPTR); virtual ~QQuickView(); QUrl source() const; diff --git a/src/quick/items/qquickwindow.h b/src/quick/items/qquickwindow.h index d4ffb100de..92c560644e 100644 --- a/src/quick/items/qquickwindow.h +++ b/src/quick/items/qquickwindow.h @@ -89,7 +89,7 @@ public: }; Q_ENUM(SceneGraphError) - QQuickWindow(QWindow *parent = 0); + QQuickWindow(QWindow *parent = Q_NULLPTR); explicit QQuickWindow(QQuickRenderControl *renderControl); virtual ~QQuickWindow(); @@ -123,7 +123,7 @@ public: // Scene graph specific functions QSGTexture *createTextureFromImage(const QImage &image) const; QSGTexture *createTextureFromImage(const QImage &image, CreateTextureOptions options) const; - QSGTexture *createTextureFromId(uint id, const QSize &size, CreateTextureOptions options = CreateTextureOption(0)) const; + QSGTexture *createTextureFromId(uint id, const QSize &size, CreateTextureOptions options = CreateTextureOption()) const; void setClearBeforeRendering(bool enabled); bool clearBeforeRendering() const; @@ -170,7 +170,7 @@ public Q_SLOTS: void releaseResources(); protected: - QQuickWindow(QQuickWindowPrivate &dd, QWindow *parent = 0); + QQuickWindow(QQuickWindowPrivate &dd, QWindow *parent = Q_NULLPTR); void exposeEvent(QExposeEvent *) Q_DECL_OVERRIDE; void resizeEvent(QResizeEvent *) Q_DECL_OVERRIDE; diff --git a/src/quick/scenegraph/coreapi/qsgabstractrenderer.h b/src/quick/scenegraph/coreapi/qsgabstractrenderer.h index 2f7da6f610..2b13f94bc8 100644 --- a/src/quick/scenegraph/coreapi/qsgabstractrenderer.h +++ b/src/quick/scenegraph/coreapi/qsgabstractrenderer.h @@ -80,7 +80,7 @@ Q_SIGNALS: void sceneGraphChanged(); protected: - QSGAbstractRenderer(QObject *parent = 0); + QSGAbstractRenderer(QObject *parent = Q_NULLPTR); virtual void nodeChanged(QSGNode *node, QSGNode::DirtyState state) = 0; private: diff --git a/src/quick/scenegraph/coreapi/qsgnode.h b/src/quick/scenegraph/coreapi/qsgnode.h index 4c9ae7251e..f73fcdacf2 100644 --- a/src/quick/scenegraph/coreapi/qsgnode.h +++ b/src/quick/scenegraph/coreapi/qsgnode.h @@ -145,7 +145,7 @@ public: QT_DEPRECATED void clearDirty() { } void markDirty(DirtyState bits); - QT_DEPRECATED DirtyState dirtyState() const { return 0; } + QT_DEPRECATED DirtyState dirtyState() const { return Q_NULLPTR; } virtual bool isSubtreeBlocked() const; diff --git a/src/quick/scenegraph/util/qsgengine.h b/src/quick/scenegraph/util/qsgengine.h index 325d3a9ca2..f49561d4b0 100644 --- a/src/quick/scenegraph/util/qsgengine.h +++ b/src/quick/scenegraph/util/qsgengine.h @@ -57,15 +57,15 @@ public: }; Q_DECLARE_FLAGS(CreateTextureOptions, CreateTextureOption) - QSGEngine(QObject *parent = 0); + QSGEngine(QObject *parent = Q_NULLPTR); ~QSGEngine(); void initialize(QOpenGLContext *context); void invalidate(); QSGAbstractRenderer *createRenderer() const; - QSGTexture *createTextureFromImage(const QImage &image, CreateTextureOptions options = CreateTextureOption(0)) const; - QSGTexture *createTextureFromId(uint id, const QSize &size, CreateTextureOptions options = CreateTextureOption(0)) const; + QSGTexture *createTextureFromImage(const QImage &image, CreateTextureOptions options = CreateTextureOption()) const; + QSGTexture *createTextureFromId(uint id, const QSize &size, CreateTextureOptions options = CreateTextureOption()) const; }; QT_END_NAMESPACE diff --git a/src/quick/util/qquickimageprovider.h b/src/quick/util/qquickimageprovider.h index cc03eb0fa0..9ecedf60ad 100644 --- a/src/quick/util/qquickimageprovider.h +++ b/src/quick/util/qquickimageprovider.h @@ -81,7 +81,7 @@ Q_SIGNALS: class Q_QUICK_EXPORT QQuickImageProvider : public QQmlImageProviderBase { public: - QQuickImageProvider(ImageType type, Flags flags = 0); + QQuickImageProvider(ImageType type, Flags flags = Flags()); virtual ~QQuickImageProvider(); ImageType imageType() const; diff --git a/src/quickwidgets/qquickwidget.h b/src/quickwidgets/qquickwidget.h index 5bb6b49a49..236a4a9c27 100644 --- a/src/quickwidgets/qquickwidget.h +++ b/src/quickwidgets/qquickwidget.h @@ -58,9 +58,9 @@ class Q_QUICKWIDGETS_EXPORT QQuickWidget : public QWidget Q_PROPERTY(QUrl source READ source WRITE setSource DESIGNABLE true) public: - explicit QQuickWidget(QWidget *parent = 0); + explicit QQuickWidget(QWidget *parent = Q_NULLPTR); QQuickWidget(QQmlEngine* engine, QWidget *parent); - QQuickWidget(const QUrl &source, QWidget *parent = 0); + QQuickWidget(const QUrl &source, QWidget *parent = Q_NULLPTR); virtual ~QQuickWidget(); QUrl source() const; -- cgit v1.2.3 From c1c9beadde2b017c37751bb94d9e679f38fd0d25 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Tue, 23 Feb 2016 13:42:47 +0100 Subject: V4: Replace foreach loops with range-based for loops. Also replaced some QVectors with std::vectors so calls to clear() will re-use the storage instead of re-allocating it. Change-Id: Ibe7d8509af8d264ea93376288cec15fec7c38f70 Reviewed-by: Lars Knoll --- src/qml/jit/qv4regalloc.cpp | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/src/qml/jit/qv4regalloc.cpp b/src/qml/jit/qv4regalloc.cpp index a6e085a913..6741529245 100644 --- a/src/qml/jit/qv4regalloc.cpp +++ b/src/qml/jit/qv4regalloc.cpp @@ -180,9 +180,9 @@ public: _calls.reserve(function->statementCount() / 3); _hints.resize(function->tempCount); - foreach (BasicBlock *bb, function->basicBlocks()) { + for (BasicBlock *bb : function->basicBlocks()) { _currentBB = bb; - foreach (Stmt *s, bb->statements()) { + for (Stmt *s : bb->statements()) { _currentStmt = s; s->accept(this); } @@ -821,8 +821,8 @@ class ResolutionPhase: protected StmtVisitor, protected ExprVisitor { const QVector &_fpRegs; Stmt *_currentStmt; - QVector _loads; - QVector _stores; + std::vector _loads; + std::vector _stores; QHash > _liveAtStart; QHash > _liveAtEnd; @@ -872,7 +872,7 @@ private: { QVector newStatements; - foreach (BasicBlock *bb, _function->basicBlocks()) { + for (BasicBlock *bb : _function->basicBlocks()) { _currentStmt = 0; QVector statements = bb->statements(); @@ -892,13 +892,13 @@ private: else addNewIntervals(defPosition(_currentStmt)); _currentStmt->accept(this); - foreach (Move *load, _loads) + for (Move *load : _loads) newStatements.append(load); if (_currentStmt->asPhi()) newStatements.prepend(_currentStmt); else newStatements.append(_currentStmt); - foreach (Move *store, _stores) + for (Move *store : _stores) newStatements.append(store); } @@ -912,7 +912,7 @@ private: os << "Intervals live at the start of L" << bb->index() << ":" << endl; if (_liveAtStart[bb].isEmpty()) os << "\t(none)" << endl; - foreach (const LifeTimeInterval *i, _liveAtStart[bb]) { + for (const LifeTimeInterval *i : _liveAtStart.value(bb)) { os << "\t"; i->dump(os); os << endl; @@ -920,7 +920,7 @@ private: os << "Intervals live at the end of L" << bb->index() << ":" << endl; if (_liveAtEnd[bb].isEmpty()) os << "\t(none)" << endl; - foreach (const LifeTimeInterval *i, _liveAtEnd[bb]) { + for (const LifeTimeInterval *i : _liveAtEnd.value(bb)) { os << "\t"; i->dump(os); os << endl; @@ -943,7 +943,7 @@ private: Q_ASSERT(pReg); int spillSlot = _assignedSpillSlots[i->temp().index]; if (spillSlot != RegisterAllocator::InvalidSpillSlot) - _stores.append(generateSpill(spillSlot, i->temp().type, pReg->reg())); + _stores.push_back(generateSpill(spillSlot, i->temp().type, pReg->reg())); } void addNewIntervals(int position) @@ -976,15 +976,15 @@ private: void resolve() { - foreach (BasicBlock *bb, _function->basicBlocks()) { - foreach (BasicBlock *bbOut, bb->out) + for (BasicBlock *bb : _function->basicBlocks()) { + for (BasicBlock *bbOut : bb->out) resolveEdge(bb, bbOut); } } Phi *findDefPhi(const Temp &t, BasicBlock *bb) const { - foreach (Stmt *s, bb->statements()) { + for (Stmt *s : bb->statements()) { Phi *phi = s->asPhi(); if (!phi) return 0; @@ -1017,7 +1017,7 @@ private: int successorStart = _intervals->startPosition(successor); Q_ASSERT(successorStart > 0); - foreach (const LifeTimeInterval *it, _liveAtStart[successor]) { + for (const LifeTimeInterval *it : _liveAtStart.value(successor)) { bool isPhiTarget = false; Expr *moveFrom = 0; @@ -1031,7 +1031,7 @@ private: Temp *t = opd->asTemp(); Q_ASSERT(t); - foreach (const LifeTimeInterval *it2, _liveAtEnd[predecessor]) { + for (const LifeTimeInterval *it2 : _liveAtEnd.value(predecessor)) { if (it2->temp() == *t && it2->reg() != LifeTimeInterval::InvalidRegister && it2->covers(predecessorEnd)) { @@ -1046,7 +1046,7 @@ private: } } } else { - foreach (const LifeTimeInterval *predIt, _liveAtEnd[predecessor]) { + for (const LifeTimeInterval *predIt : _liveAtEnd.value(predecessor)) { if (predIt->temp() == it->temp()) { if (predIt->reg() != LifeTimeInterval::InvalidRegister && predIt->covers(predecessorEnd)) { @@ -1191,7 +1191,7 @@ protected: Q_ASSERT(i->isSplitFromInterval()); const RegisterInfo *pReg = platformRegister(*i); Q_ASSERT(pReg); - _loads.append(generateUnspill(i->temp(), pReg->reg())); + _loads.push_back(generateUnspill(i->temp(), pReg->reg())); } if (i->reg() != LifeTimeInterval::InvalidRegister && @@ -1303,7 +1303,7 @@ void RegisterAllocator::run(IR::Function *function, const Optimizer &opt) qout << "Ranges:" << endl; QVector intervals = _unhandled; std::reverse(intervals.begin(), intervals.end()); - foreach (const LifeTimeInterval *r, intervals) { + for (const LifeTimeInterval *r : qAsConst(intervals)) { r->dump(qout); qout << endl; } @@ -1490,11 +1490,11 @@ void RegisterAllocator::linearScan() } } - foreach (LifeTimeInterval *r, _active) + for (LifeTimeInterval *r : qAsConst(_active)) if (!r->isFixedInterval()) _handled.append(r); _active.clear(); - foreach (LifeTimeInterval *r, _inactive) + for (LifeTimeInterval *r : qAsConst(_inactive)) if (!r->isFixedInterval()) _handled.append(r); _inactive.clear(); @@ -1922,7 +1922,7 @@ void RegisterAllocator::dump(IR::Function *function) const qout << "Ranges:" << endl; QVector handled = _handled; std::sort(handled.begin(), handled.end(), LifeTimeInterval::lessThanForTemp); - foreach (const LifeTimeInterval *r, handled) { + for (const LifeTimeInterval *r : qAsConst(handled)) { r->dump(qout); qout << endl; } -- cgit v1.2.3 From 0e30dc40df70cef2cd3f31b913bf867a620327cb Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Tue, 16 Feb 2016 11:32:33 +0100 Subject: AnimatedSprite: don't access deleted scene graph nodes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It’s a bad idea to store a scene graph paint node as a member variable. First of all, it should not access the node outside updatePaintNode(), that is, outside the render thread. Secondly, the node is owned by the scene graph and may be nuked whenever the scene graph feels so. Some creative re-parenting easily triggers a case where AnimatedSprite ends up accessing a node that was already deleted by the scene graph. Change-Id: I89205ac36333a2fcb094121afa61b6409fda5883 Task-number: QTBUG-51162 Reviewed-by: Gunnar Sletta --- src/quick/items/qquickanimatedsprite.cpp | 92 +++++++++++++++----------------- src/quick/items/qquickanimatedsprite_p.h | 10 ++-- 2 files changed, 49 insertions(+), 53 deletions(-) (limited to 'src') diff --git a/src/quick/items/qquickanimatedsprite.cpp b/src/quick/items/qquickanimatedsprite.cpp index 5f77c6461f..d7f3f4f83b 100644 --- a/src/quick/items/qquickanimatedsprite.cpp +++ b/src/quick/items/qquickanimatedsprite.cpp @@ -310,8 +310,6 @@ struct AnimatedSpriteVertices { //TODO: Implicitly size element to size of sprite QQuickAnimatedSprite::QQuickAnimatedSprite(QQuickItem *parent) : QQuickItem(parent) - , m_node(0) - , m_material(0) , m_sprite(new QQuickSprite(this)) , m_spriteEngine(0) , m_curFrame(0) @@ -325,9 +323,9 @@ QQuickAnimatedSprite::QQuickAnimatedSprite(QQuickItem *parent) : { setFlag(ItemHasContents); connect(this, SIGNAL(widthChanged()), - this, SLOT(sizeVertices())); + this, SLOT(reset())); connect(this, SIGNAL(heightChanged()), - this, SLOT(sizeVertices())); + this, SLOT(reset())); } bool QQuickAnimatedSprite::isCurrentFrameChangedConnected() @@ -455,12 +453,9 @@ static QSGGeometry::AttributeSet AnimatedSprite_AttributeSet = AnimatedSprite_Attributes }; -void QQuickAnimatedSprite::sizeVertices() +void QQuickAnimatedSprite::sizeVertices(QSGGeometryNode *node) { - if (!m_node) - return; - - AnimatedSpriteVertices *p = (AnimatedSpriteVertices *) m_node->geometry()->vertexData(); + AnimatedSpriteVertices *p = (AnimatedSpriteVertices *) node->geometry()->vertexData(); p->v1.x = 0; p->v1.y = 0; @@ -488,21 +483,21 @@ QSGGeometryNode* QQuickAnimatedSprite::buildNode() return 0; } - m_material = new QQuickAnimatedSpriteMaterial(); + QQuickAnimatedSpriteMaterial *material = new QQuickAnimatedSpriteMaterial(); QImage image = m_spriteEngine->assembledImage(); //Engine prints errors if there are any if (image.isNull()) return 0; m_sheetSize = QSizeF(image.size()); - m_material->texture = window()->createTextureFromImage(image); + material->texture = window()->createTextureFromImage(image); m_spriteEngine->start(0); - m_material->animT = 0; - m_material->animX1 = m_spriteEngine->spriteX() / m_sheetSize.width(); - m_material->animY1 = m_spriteEngine->spriteY() / m_sheetSize.height(); - m_material->animX2 = m_material->animX1; - m_material->animY2 = m_material->animY1; - m_material->animW = m_spriteEngine->spriteWidth() / m_sheetSize.width(); - m_material->animH = m_spriteEngine->spriteHeight() / m_sheetSize.height(); + material->animT = 0; + material->animX1 = m_spriteEngine->spriteX() / m_sheetSize.width(); + material->animY1 = m_spriteEngine->spriteY() / m_sheetSize.height(); + material->animX2 = material->animX1; + material->animY2 = material->animY1; + material->animW = m_spriteEngine->spriteWidth() / m_sheetSize.width(); + material->animH = m_spriteEngine->spriteHeight() / m_sheetSize.height(); int vCount = 4; int iCount = 6; @@ -511,7 +506,7 @@ QSGGeometryNode* QQuickAnimatedSprite::buildNode() AnimatedSpriteVertices *p = (AnimatedSpriteVertices *) g->vertexData(); - QRectF texRect = m_material->texture->normalizedTextureSubRect(); + QRectF texRect = material->texture->normalizedTextureSubRect(); p->v1.tx = texRect.topLeft().x(); p->v1.ty = texRect.topLeft().y(); @@ -534,51 +529,51 @@ QSGGeometryNode* QQuickAnimatedSprite::buildNode() indices[5] = 2; - m_node = new QSGGeometryNode(); - m_node->setGeometry(g); - m_node->setMaterial(m_material); - m_node->setFlag(QSGGeometryNode::OwnsMaterial); - m_node->setFlag(QSGGeometryNode::OwnsGeometry); - sizeVertices(); - return m_node; + QSGGeometryNode *node = new QSGGeometryNode(); + node->setGeometry(g); + node->setMaterial(material); + node->setFlag(QSGGeometryNode::OwnsMaterial); + node->setFlag(QSGGeometryNode::OwnsGeometry); + sizeVertices(node); + return node; } void QQuickAnimatedSprite::reset() { m_pleaseReset = true; + update(); } -QSGNode *QQuickAnimatedSprite::updatePaintNode(QSGNode *, UpdatePaintNodeData *) +QSGNode *QQuickAnimatedSprite::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) { if (m_pleaseReset) { - delete m_node; + delete oldNode; - m_node = 0; - m_material = 0; + oldNode = 0; m_pleaseReset = false; } - prepareNextFrame(); + QSGGeometryNode *node = static_cast(oldNode); + if (!node) + node = buildNode(); + + if (node) + prepareNextFrame(node); if (m_running) { if (!m_paused) update(); - if (m_node) { - m_node->markDirty(QSGNode::DirtyMaterial); + if (node) { + node->markDirty(QSGNode::DirtyMaterial); } } - return m_node; + return node; } -void QQuickAnimatedSprite::prepareNextFrame() +void QQuickAnimatedSprite::prepareNextFrame(QSGGeometryNode *node) { - if (m_node == 0) - m_node = buildNode(); - if (m_node == 0) //error creating node - return; - int timeInt = m_timestamp.elapsed() + m_pauseOffset; qreal time = timeInt / 1000.; @@ -694,14 +689,15 @@ void QQuickAnimatedSprite::prepareNextFrame() } } - m_material->animX1 = x1; - m_material->animY1 = y1; - m_material->animX2 = x2; - m_material->animY2 = y2; - m_material->animW = w; - m_material->animH = h; - m_material->animT = m_interpolate ? progress : 0.0; - m_material->texture->setFiltering(smooth() ? QSGTexture::Linear : QSGTexture::Nearest); + QQuickAnimatedSpriteMaterial *material = static_cast(node->material()); + material->animX1 = x1; + material->animY1 = y1; + material->animX2 = x2; + material->animY2 = y2; + material->animW = w; + material->animH = h; + material->animT = m_interpolate ? progress : 0.0; + material->texture->setFiltering(smooth() ? QSGTexture::Linear : QSGTexture::Nearest); } QT_END_NAMESPACE diff --git a/src/quick/items/qquickanimatedsprite_p.h b/src/quick/items/qquickanimatedsprite_p.h index ffaddefb47..5b181640f9 100644 --- a/src/quick/items/qquickanimatedsprite_p.h +++ b/src/quick/items/qquickanimatedsprite_p.h @@ -351,19 +351,19 @@ public Q_SLOTS: private Q_SLOTS: void createEngine(); - void sizeVertices(); + void sizeVertices(QSGGeometryNode *node); -protected: +protected Q_SLOTS: void reset(); + +protected: void componentComplete() Q_DECL_OVERRIDE; QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) Q_DECL_OVERRIDE; private: bool isCurrentFrameChangedConnected(); - void prepareNextFrame(); + void prepareNextFrame(QSGGeometryNode *node); void reloadImage(); QSGGeometryNode* buildNode(); - QSGGeometryNode *m_node; - QQuickAnimatedSpriteMaterial *m_material; QQuickSprite* m_sprite; QQuickSpriteEngine* m_spriteEngine; QElapsedTimer m_timestamp; -- cgit v1.2.3 From 998036e9de667ae7b456c96855af4e542738e33c Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Thu, 3 Mar 2016 10:49:02 +0100 Subject: Make more ctors explicit Added explicit where it was missing. This is not a source- incompatible change, because code that breaks by this is a bug. Let's not have this sitting around in an LTS. Change-Id: Ic198750717799126b4e37817845a8ee4684d631f Reviewed-by: Lars Knoll --- src/qml/qml/qqmlengine.h | 2 +- src/qml/qml/qqmlfileselector.h | 2 +- src/quick/items/qquickpainteditem.h | 2 +- src/quick/items/qquickrendercontrol.h | 2 +- src/quick/items/qquickview.h | 2 +- src/quick/items/qquickwindow.h | 2 +- src/quick/scenegraph/coreapi/qsgabstractrenderer.h | 2 +- src/quick/scenegraph/util/qsgengine.h | 2 +- src/quickwidgets/qquickwidget.h | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/qml/qml/qqmlengine.h b/src/qml/qml/qqmlengine.h index a0d47c33a6..bf878bd994 100644 --- a/src/qml/qml/qqmlengine.h +++ b/src/qml/qml/qqmlengine.h @@ -88,7 +88,7 @@ class Q_QML_EXPORT QQmlEngine : public QJSEngine Q_PROPERTY(QString offlineStoragePath READ offlineStoragePath WRITE setOfflineStoragePath) Q_OBJECT public: - QQmlEngine(QObject *p = Q_NULLPTR); + explicit QQmlEngine(QObject *p = Q_NULLPTR); virtual ~QQmlEngine(); QQmlContext *rootContext() const; diff --git a/src/qml/qml/qqmlfileselector.h b/src/qml/qml/qqmlfileselector.h index 3af63a8293..afc819e214 100644 --- a/src/qml/qml/qqmlfileselector.h +++ b/src/qml/qml/qqmlfileselector.h @@ -48,7 +48,7 @@ class Q_QML_EXPORT QQmlFileSelector : public QObject Q_OBJECT Q_DECLARE_PRIVATE(QQmlFileSelector) public: - QQmlFileSelector(QQmlEngine *engine, QObject *parent = Q_NULLPTR); + explicit QQmlFileSelector(QQmlEngine *engine, QObject *parent = Q_NULLPTR); ~QQmlFileSelector(); void setSelector(QFileSelector *selector); void setExtraSelectors(QStringList &strings); // TODO Qt6: remove diff --git a/src/quick/items/qquickpainteditem.h b/src/quick/items/qquickpainteditem.h index 85e90e7263..bb4e7f1f85 100644 --- a/src/quick/items/qquickpainteditem.h +++ b/src/quick/items/qquickpainteditem.h @@ -51,7 +51,7 @@ class Q_QUICK_EXPORT QQuickPaintedItem : public QQuickItem Q_PROPERTY(QSize textureSize READ textureSize WRITE setTextureSize NOTIFY textureSizeChanged) public: - QQuickPaintedItem(QQuickItem *parent = Q_NULLPTR); + explicit QQuickPaintedItem(QQuickItem *parent = Q_NULLPTR); virtual ~QQuickPaintedItem(); enum RenderTarget { diff --git a/src/quick/items/qquickrendercontrol.h b/src/quick/items/qquickrendercontrol.h index 1132585a66..74419ecc9c 100644 --- a/src/quick/items/qquickrendercontrol.h +++ b/src/quick/items/qquickrendercontrol.h @@ -49,7 +49,7 @@ class Q_QUICK_EXPORT QQuickRenderControl : public QObject Q_OBJECT public: - QQuickRenderControl(QObject *parent = Q_NULLPTR); + explicit QQuickRenderControl(QObject *parent = Q_NULLPTR); ~QQuickRenderControl(); void prepareThread(QThread *targetThread); diff --git a/src/quick/items/qquickview.h b/src/quick/items/qquickview.h index 28be948ff4..46dfe96506 100644 --- a/src/quick/items/qquickview.h +++ b/src/quick/items/qquickview.h @@ -56,7 +56,7 @@ class Q_QUICK_EXPORT QQuickView : public QQuickWindow public: explicit QQuickView(QWindow *parent = Q_NULLPTR); QQuickView(QQmlEngine* engine, QWindow *parent); - QQuickView(const QUrl &source, QWindow *parent = Q_NULLPTR); + explicit QQuickView(const QUrl &source, QWindow *parent = Q_NULLPTR); virtual ~QQuickView(); QUrl source() const; diff --git a/src/quick/items/qquickwindow.h b/src/quick/items/qquickwindow.h index 92c560644e..522101c7e4 100644 --- a/src/quick/items/qquickwindow.h +++ b/src/quick/items/qquickwindow.h @@ -89,7 +89,7 @@ public: }; Q_ENUM(SceneGraphError) - QQuickWindow(QWindow *parent = Q_NULLPTR); + explicit QQuickWindow(QWindow *parent = Q_NULLPTR); explicit QQuickWindow(QQuickRenderControl *renderControl); virtual ~QQuickWindow(); diff --git a/src/quick/scenegraph/coreapi/qsgabstractrenderer.h b/src/quick/scenegraph/coreapi/qsgabstractrenderer.h index 2b13f94bc8..8eb16ed129 100644 --- a/src/quick/scenegraph/coreapi/qsgabstractrenderer.h +++ b/src/quick/scenegraph/coreapi/qsgabstractrenderer.h @@ -80,7 +80,7 @@ Q_SIGNALS: void sceneGraphChanged(); protected: - QSGAbstractRenderer(QObject *parent = Q_NULLPTR); + explicit QSGAbstractRenderer(QObject *parent = Q_NULLPTR); virtual void nodeChanged(QSGNode *node, QSGNode::DirtyState state) = 0; private: diff --git a/src/quick/scenegraph/util/qsgengine.h b/src/quick/scenegraph/util/qsgengine.h index f49561d4b0..438c6d789b 100644 --- a/src/quick/scenegraph/util/qsgengine.h +++ b/src/quick/scenegraph/util/qsgengine.h @@ -57,7 +57,7 @@ public: }; Q_DECLARE_FLAGS(CreateTextureOptions, CreateTextureOption) - QSGEngine(QObject *parent = Q_NULLPTR); + explicit QSGEngine(QObject *parent = Q_NULLPTR); ~QSGEngine(); void initialize(QOpenGLContext *context); diff --git a/src/quickwidgets/qquickwidget.h b/src/quickwidgets/qquickwidget.h index 236a4a9c27..53d3c16533 100644 --- a/src/quickwidgets/qquickwidget.h +++ b/src/quickwidgets/qquickwidget.h @@ -60,7 +60,7 @@ class Q_QUICKWIDGETS_EXPORT QQuickWidget : public QWidget public: explicit QQuickWidget(QWidget *parent = Q_NULLPTR); QQuickWidget(QQmlEngine* engine, QWidget *parent); - QQuickWidget(const QUrl &source, QWidget *parent = Q_NULLPTR); + explicit QQuickWidget(const QUrl &source, QWidget *parent = Q_NULLPTR); virtual ~QQuickWidget(); QUrl source() const; -- cgit v1.2.3 From 13c8aecdfccc9d15c367a9d45ec575f1542a90fd Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Thu, 3 Mar 2016 11:49:55 +0100 Subject: Document default value of wrapMode Change-Id: Ie08653c2c89e48349cbc41e8bec5714574302963 Reviewed-by: Miikka Heikkinen Reviewed-by: Laszlo Agocs --- src/quick/items/qquickshadereffectsource.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/quick/items/qquickshadereffectsource.cpp b/src/quick/items/qquickshadereffectsource.cpp index cd2e2c1cb6..a8cf6155a0 100644 --- a/src/quick/items/qquickshadereffectsource.cpp +++ b/src/quick/items/qquickshadereffectsource.cpp @@ -269,6 +269,8 @@ QSGTextureProvider *QQuickShaderEffectSource::textureProvider() const Modifying this property makes most sense when the item is used as a source texture of a \l ShaderEffect. + The default value is \c{ShaderEffectSource.ClampToEdge}. + \list \li ShaderEffectSource.ClampToEdge - GL_CLAMP_TO_EDGE both horizontally and vertically \li ShaderEffectSource.RepeatHorizontally - GL_REPEAT horizontally, GL_CLAMP_TO_EDGE vertically -- cgit v1.2.3 From 62ecfe55f414d0d04a4344bc6934b4b01408190f Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Thu, 3 Mar 2016 14:18:52 +0100 Subject: Particles: code clean-up. Replace QHash groupData with a QVarLengthArray, and make sure that those integers (== indices) are continuous, re-used, and start at zero. That way a whole bunch of qhash calls, hash node creatrion/deletion, and other overhead is removed. Change-Id: Ie74fab8a3e3c7b6efa15b7b9ceff1d1a3e9820e9 Reviewed-by: Lars Knoll Reviewed-by: Robin Burchell --- src/particles/qquickcustomaffector.cpp | 12 ++++-- src/particles/qquickitemparticle.cpp | 2 +- src/particles/qquickparticleaffector.cpp | 2 +- src/particles/qquickparticlesystem.cpp | 72 +++++++++++++++++++++----------- src/particles/qquickparticlesystem_p.h | 15 ++++--- src/particles/qquickturbulence.cpp | 2 +- 6 files changed, 69 insertions(+), 36 deletions(-) (limited to 'src') diff --git a/src/particles/qquickcustomaffector.cpp b/src/particles/qquickcustomaffector.cpp index 55310f92d5..6f50c17287 100644 --- a/src/particles/qquickcustomaffector.cpp +++ b/src/particles/qquickcustomaffector.cpp @@ -122,11 +122,15 @@ void QQuickCustomAffector::affectSystem(qreal dt) updateOffsets(); QList toAffect; - foreach (QQuickParticleGroupData* gd, m_system->groupData) - if (activeGroup(m_system->groupData.key(gd))) - foreach (QQuickParticleData* d, gd->data) - if (shouldAffect(d)) + foreach (QQuickParticleGroupData* gd, m_system->groupData) { + if (activeGroup(gd->index)) { + foreach (QQuickParticleData* d, gd->data) { + if (shouldAffect(d)) { toAffect << d; + } + } + } + } if (toAffect.isEmpty()) return; diff --git a/src/particles/qquickitemparticle.cpp b/src/particles/qquickitemparticle.cpp index 86dc04ea5a..4cd8ee9db8 100644 --- a/src/particles/qquickitemparticle.cpp +++ b/src/particles/qquickitemparticle.cpp @@ -278,7 +278,7 @@ void QQuickItemParticle::prepareNextFrame() //TODO: Size, better fade? foreach (const QString &str, m_groups){ const int gIdx = m_system->groupIds[str]; - const QVector dataVector = m_system->groupData.value(gIdx)->data; + const QVector dataVector = m_system->groupData[gIdx]->data; const int count = dataVector.size(); for (int i=0; igroupData) { - if (activeGroup(m_system->groupData.key(gd))) { + if (activeGroup(gd->index)) { foreach (QQuickParticleData* d, gd->data) { if (shouldAffect(d)) { bool affected = false; diff --git a/src/particles/qquickparticlesystem.cpp b/src/particles/qquickparticlesystem.cpp index 603515dc66..c0306e9025 100644 --- a/src/particles/qquickparticlesystem.cpp +++ b/src/particles/qquickparticlesystem.cpp @@ -330,7 +330,10 @@ void QQuickParticleDataHeap::bubbleDown(int idx)//tends to be called log n times } } -QQuickParticleGroupData::QQuickParticleGroupData(int id, QQuickParticleSystem* sys):index(id),m_size(0),m_system(sys) +QQuickParticleGroupData::QQuickParticleGroupData(const QString &name, QQuickParticleSystem* sys) + : index(sys->registerParticleGroupData(name, this)) + , m_size(0) + , m_system(sys) { initList(); } @@ -703,6 +706,7 @@ void QQuickParticleData::extendLife(float time) QQuickParticleSystem::QQuickParticleSystem(QQuickItem *parent) : QQuickItem(parent), stateEngine(0), + nextFreeGroupId(0), m_animation(0), m_running(true), initialized(0), @@ -732,11 +736,11 @@ void QQuickParticleSystem::initGroups() qDeleteAll(groupData); groupData.clear(); groupIds.clear(); + nextFreeGroupId = 0; - QQuickParticleGroupData* gd = new QQuickParticleGroupData(0, this);//Default group - groupData.insert(0,gd); - groupIds.insert(QString(), 0); - m_nextGroupId = 1; + QQuickParticleGroupData *pd = new QQuickParticleGroupData(QString(), this); // Default group + Q_ASSERT(pd->index == 0); + Q_UNUSED(pd); } void QQuickParticleSystem::registerParticlePainter(QQuickParticlePainter* p) @@ -848,6 +852,34 @@ void QQuickParticleSystem::stateRedirect(QQuickParticleGroup* group, QQuickParti qWarning() << value << " was placed inside a particle system state but cannot be taken into the particle system. It will be lost."; } + +int QQuickParticleSystem::registerParticleGroupData(const QString &name, QQuickParticleGroupData *pgd) +{ + Q_ASSERT(!groupIds.contains(name)); + int id; + if (nextFreeGroupId >= groupData.size()) { + groupData.push_back(pgd); + nextFreeGroupId = groupData.size(); + id = nextFreeGroupId - 1; + } else { + id = nextFreeGroupId; + groupData[id] = pgd; + searchNextFreeGroupId(); + } + groupIds.insert(name, id); + return id; +} + +void QQuickParticleSystem::searchNextFreeGroupId() +{ + ++nextFreeGroupId; + for (int ei = groupData.size(); nextFreeGroupId != ei; ++nextFreeGroupId) { + if (groupData[nextFreeGroupId] == nullptr) { + return; + } + } +} + void QQuickParticleSystem::componentComplete() { @@ -917,11 +949,8 @@ void QQuickParticleSystem::loadPainter(QObject *p) groupData[0]->painters << painter; } else { foreach (const QString &group, painter->groups()) { - if (group != QLatin1String("") && !groupIds[group]) {//new group - int id = m_nextGroupId++; - QQuickParticleGroupData* gd = new QQuickParticleGroupData(id, this); - groupIds.insert(group, id); - groupData.insert(id, gd); + if (!group.isEmpty() && !groupIds.contains(group)) {//new group + new QQuickParticleGroupData(group, this); } particleCount += groupData[groupIds[group]]->size(); groupData[groupIds[group]]->painters << painter; @@ -939,9 +968,9 @@ void QQuickParticleSystem::emittersChanged() QVector previousSizes; QVector newSizes; - previousSizes.reserve(m_nextGroupId); - newSizes.reserve(m_nextGroupId); - for (int i=0; isize(); newSizes << 0; } @@ -957,10 +986,7 @@ void QQuickParticleSystem::emittersChanged() if (!e->group().isEmpty() && !groupIds.contains(e->group())) { - int id = m_nextGroupId++; - QQuickParticleGroupData* gd = new QQuickParticleGroupData(id, this); - groupIds.insert(e->group(), id); - groupData.insert(id, gd); + new QQuickParticleGroupData(e->group(), this); previousSizes << 0; newSizes << 0; } @@ -970,13 +996,13 @@ void QQuickParticleSystem::emittersChanged() //TODO: Garbage collection? particleCount = 0; - for (int i=0; isetSize(qMax(newSizes[i], previousSizes[i])); particleCount += groupData[i]->size(); } if (m_debugMode) - qDebug() << "Particle system emitters changed. New particle count: " << particleCount; + qDebug() << "Particle system emitters changed. New particle count: " << particleCount << "in" << groupData.size() << "groups."; if (particleCount > bySysIdx.size())//New datum requests haven't updated it bySysIdx.resize(particleCount); @@ -1008,17 +1034,15 @@ void QQuickParticleSystem::createEngine() } } if (!exists) { - int id = m_nextGroupId++; - QQuickParticleGroupData* gd = new QQuickParticleGroupData(id, this); - groupIds.insert(group->name(), id); - groupData.insert(id, gd); + new QQuickParticleGroupData(group->name(), this); } } if (m_groups.count()) { //Reorder groups List so as to have the same order as groupData + // TODO: can't we just merge the two lists? QList newList; - for (int i=0; iname(); foreach (QQuickParticleGroup* existing, m_groups) { diff --git a/src/particles/qquickparticlesystem_p.h b/src/particles/qquickparticlesystem_p.h index 5a1ab5022d..7805f87094 100644 --- a/src/particles/qquickparticlesystem_p.h +++ b/src/particles/qquickparticlesystem_p.h @@ -111,7 +111,7 @@ private: class Q_QUICKPARTICLES_PRIVATE_EXPORT QQuickParticleGroupData { public: - QQuickParticleGroupData(int id, QQuickParticleSystem* sys); + QQuickParticleGroupData(const QString &name, QQuickParticleSystem* sys); ~QQuickParticleGroupData(); int size(); @@ -119,7 +119,7 @@ public: void setSize(int newSize); - int index; + const int index; QSet painters;//TODO: What if they are dynamically removed? //TODO: Refactor particle data list out into a separate class @@ -317,10 +317,13 @@ public: //Data members here for ease of related class and auto-test usage. Not "public" API. TODO: d_ptrize QSet needsReset; QVector bySysIdx; //Another reference to the data (data owned by group), but by sysIdx - QHash groupIds; - QHash groupData; QQuickStochasticEngine* stateEngine; + QHash groupIds; + QVarLengthArray groupData; + int nextFreeGroupId; + int registerParticleGroupData(const QString &name, QQuickParticleGroupData *pgd); + //Also only here for auto-test usage void updateCurrentTime( int currentTime ); QQuickParticleSystemAnimation* m_animation; @@ -348,6 +351,9 @@ public: return m_empty; } +private: + void searchNextFreeGroupId(); + private: void initializeSystem(); void initGroups(); @@ -356,7 +362,6 @@ private: QList > m_painters; QList > m_syncList; QList m_groups; - int m_nextGroupId; int m_nextIndex; QSet m_reusableIndexes; bool m_componentComplete; diff --git a/src/particles/qquickturbulence.cpp b/src/particles/qquickturbulence.cpp index 154235441b..eed8604438 100644 --- a/src/particles/qquickturbulence.cpp +++ b/src/particles/qquickturbulence.cpp @@ -181,7 +181,7 @@ void QQuickTurbulenceAffector::affectSystem(qreal dt) QRect boundsRect(0,0,m_gridSize,m_gridSize); foreach (QQuickParticleGroupData *gd, m_system->groupData){ - if (!activeGroup(m_system->groupData.key(gd))) + if (!activeGroup(gd->index)) continue; foreach (QQuickParticleData *d, gd->data){ if (!shouldAffect(d)) -- cgit v1.2.3 From 554566788f585caaef14d929cee6557ad929e06e Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Tue, 1 Mar 2016 12:39:09 +0100 Subject: Particles: inline 4 methods. And when in the area, remove 3 unused functions. Benchmark: start samegame, click '1 player', quit. Valgrind result: removes/inlines ~90,000 calls. Change-Id: If911b19b46bf163f7fe678623c068f960296f17e Reviewed-by: Lars Knoll Reviewed-by: Robin Burchell --- src/particles/qquickparticleemitter.cpp | 7 ------ src/particles/qquickparticleemitter_p.h | 7 +++++- src/particles/qquickparticlesystem.cpp | 38 +-------------------------------- src/particles/qquickparticlesystem_p.h | 21 +++++++++++++++++- 4 files changed, 27 insertions(+), 46 deletions(-) (limited to 'src') diff --git a/src/particles/qquickparticleemitter.cpp b/src/particles/qquickparticleemitter.cpp index 4d9f834492..5e5c750e0e 100644 --- a/src/particles/qquickparticleemitter.cpp +++ b/src/particles/qquickparticleemitter.cpp @@ -319,13 +319,6 @@ void QQuickParticleEmitter::setMaxParticleCount(int arg) } } -int QQuickParticleEmitter::particleCount() const -{ - if (m_maxParticleCount >= 0) - return m_maxParticleCount; - return m_particlesPerSecond*((m_particleDuration+m_particleDurationVariation)/1000.0); -} - void QQuickParticleEmitter::setVelocityFromMovement(qreal t) { if (t == m_velocity_from_movement) diff --git a/src/particles/qquickparticleemitter_p.h b/src/particles/qquickparticleemitter_p.h index e0036c4007..bb77d132cc 100644 --- a/src/particles/qquickparticleemitter_p.h +++ b/src/particles/qquickparticleemitter_p.h @@ -266,7 +266,12 @@ public Q_SLOTS: virtual void reset(); public: - int particleCount() const; + int particleCount() const + { + if (m_maxParticleCount >= 0) + return m_maxParticleCount; + return m_particlesPerSecond*((m_particleDuration+m_particleDurationVariation)/1000.0); + } QQuickParticleExtruder* extruder() const { diff --git a/src/particles/qquickparticlesystem.cpp b/src/particles/qquickparticlesystem.cpp index c0306e9025..e91ab40ffa 100644 --- a/src/particles/qquickparticlesystem.cpp +++ b/src/particles/qquickparticlesystem.cpp @@ -199,24 +199,8 @@ DEFINE_BOOL_CONFIG_OPTION(qmlParticlesDebug, QML_PARTICLES_DEBUG) Discards all currently existing particles. */ -const qreal EPSILON = 0.001; -//Utility functions for when within 1ms is close enough -bool timeEqualOrGreater(qreal a, qreal b) -{ - return (a+EPSILON >= b); -} - -bool timeLess(qreal a, qreal b) -{ - return (a-EPSILON < b); -} -bool timeEqual(qreal a, qreal b) -{ - return (a+EPSILON > b) && (a-EPSILON < b); -} - -int roundedTime(qreal a) +static inline int roundedTime(qreal a) {// in ms return (int)qRound(a*1000.0); } @@ -344,11 +328,6 @@ QQuickParticleGroupData::~QQuickParticleGroupData() delete d; } -int QQuickParticleGroupData::size() -{ - return m_size; -} - QString QQuickParticleGroupData::name()//### Worth caching as well? { return m_system->groupIds.key(index); @@ -652,21 +631,6 @@ void QQuickParticleData::debugDump() << "Time: " << t << "," <timeInt / 1000.0) ; } -bool QQuickParticleData::stillAlive() -{ - if (!system) - return false; - return (t + lifeSpan - EPSILON) > ((qreal)system->timeInt/1000.0); -} - -bool QQuickParticleData::alive() -{ - if (!system) - return false; - qreal st = ((qreal)system->timeInt/1000.0); - return (t + EPSILON) < st && (t + lifeSpan - EPSILON) > st; -} - float QQuickParticleData::curSize() { if (!system || !lifeSpan) diff --git a/src/particles/qquickparticlesystem_p.h b/src/particles/qquickparticlesystem_p.h index 7805f87094..9ddbb2ff38 100644 --- a/src/particles/qquickparticlesystem_p.h +++ b/src/particles/qquickparticlesystem_p.h @@ -114,7 +114,9 @@ public: QQuickParticleGroupData(const QString &name, QQuickParticleSystem* sys); ~QQuickParticleGroupData(); - int size(); + int size() + { return m_size; } + QString name(); void setSize(int newSize); @@ -248,6 +250,9 @@ public: void clone(const QQuickParticleData& other);//Not =, leaves meta-data like index QQmlV4Handle v4Value(); void extendLife(float time); + + static inline Q_DECL_CONSTEXPR qreal EPSILON() Q_DECL_NOTHROW { return 0.001; } + private: QQuickV4ParticleData* v8Datum; }; @@ -396,6 +401,20 @@ private: QQuickParticleSystem* m_system; }; +inline bool QQuickParticleData::stillAlive() +{ + if (!system) + return false; + return (t + lifeSpan - EPSILON()) > ((qreal)system->timeInt/1000.0); +} + +inline bool QQuickParticleData::alive() +{ + if (!system) + return false; + qreal st = ((qreal)system->timeInt/1000.0); + return (t + EPSILON()) < st && (t + lifeSpan - EPSILON()) > st; +} QT_END_NAMESPACE -- cgit v1.2.3 From 5a9734c0d071b7490b3ef7edf5f080786dc89f79 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Thu, 3 Mar 2016 14:54:31 +0100 Subject: Particles: reduce excessive hash accesses to a more passable level. By caching the group id in the particle emitter, and groups in the painter. Test case: samegame, 1 player, click 1 set of 3 stones, quit. QQuickParticleSystem::emittersChanged(), before patch: - 64M instr. inclusive - 145,880 calls to findNode (29M instr.) after: - 21M instr. inclusive - 0 calls to findNode - 25 calls to QQuickParticlePainter::recalculateGroupIds (9800 instr. inclusive). Change-Id: I4aba9d50100513c6b7cdd230e30b3aecaf84485a Reviewed-by: Lars Knoll --- src/particles/qquickcustomparticle.cpp | 11 +++---- src/particles/qquickimageparticle.cpp | 55 +++++++++++++++++++-------------- src/particles/qquickitemparticle.cpp | 38 ++++++++++------------- src/particles/qquickparticleemitter.cpp | 12 +++++++ src/particles/qquickparticleemitter_p.h | 19 ++++++++++-- src/particles/qquickparticlepainter.cpp | 46 ++++++++++++++++++++++----- src/particles/qquickparticlepainter_p.h | 37 +++++++++++++++------- src/particles/qquickparticlesystem.cpp | 32 +++++++++---------- src/particles/qquickparticlesystem_p.h | 32 +++++++++++++++++-- src/particles/qquicktrailemitter.cpp | 2 +- 10 files changed, 192 insertions(+), 92 deletions(-) (limited to 'src') diff --git a/src/particles/qquickcustomparticle.cpp b/src/particles/qquickcustomparticle.cpp index 97cfdc7bf9..32b2fd847e 100644 --- a/src/particles/qquickcustomparticle.cpp +++ b/src/particles/qquickcustomparticle.cpp @@ -324,19 +324,18 @@ QQuickShaderEffectNode* QQuickCustomParticle::buildCustomNodes() return 0; } - if (m_groups.isEmpty()) + if (groups().isEmpty()) return 0; QQuickShaderEffectNode *rootNode = 0; QQuickShaderEffectMaterial *material = new QQuickShaderEffectMaterial; m_dirtyProgram = true; - foreach (const QString &str, m_groups){ - int gIdx = m_system->groupIds[str]; - int count = m_system->groupData[gIdx]->size(); + for (auto groupId : groupIds()) { + int count = m_system->groupData[groupId]->size(); QQuickShaderEffectNode* node = new QQuickShaderEffectNode(); - m_nodes.insert(gIdx, node); + m_nodes.insert(groupId, node); node->setMaterial(material); @@ -349,7 +348,7 @@ QQuickShaderEffectNode* QQuickCustomParticle::buildCustomNodes() node->setFlag(QSGNode::OwnsGeometry, true); PlainVertex *vertices = (PlainVertex *) g->vertexData(); for (int p=0; p < count; ++p) { - commit(gIdx, p); + commit(groupId, p); vertices[0].tx = 0; vertices[0].ty = 0; diff --git a/src/particles/qquickimageparticle.cpp b/src/particles/qquickimageparticle.cpp index c88a0b002b..5f2d1db663 100644 --- a/src/particles/qquickimageparticle.cpp +++ b/src/particles/qquickimageparticle.cpp @@ -1020,10 +1020,13 @@ void QQuickImageParticle::setEntryEffect(EntryEffect arg) void QQuickImageParticle::resetColor() { m_explicitColor = false; - foreach (const QString &str, m_groups) - foreach (QQuickParticleData* d, m_system->groupData[m_system->groupIds[str]]->data) - if (d->colorOwner == this) + for (auto groupId : groupIds()) { + for (QQuickParticleData* d : qAsConst(m_system->groupData[groupId]->data)) { + if (d->colorOwner == this) { d->colorOwner = 0; + } + } + } m_color = QColor(); m_color_variation = 0.0f; m_redVariation = 0.0f; @@ -1036,10 +1039,13 @@ void QQuickImageParticle::resetColor() void QQuickImageParticle::resetRotation() { m_explicitRotation = false; - foreach (const QString &str, m_groups) - foreach (QQuickParticleData* d, m_system->groupData[m_system->groupIds[str]]->data) - if (d->rotationOwner == this) + for (auto groupId : groupIds()) { + for (QQuickParticleData* d : qAsConst(m_system->groupData[groupId]->data)) { + if (d->rotationOwner == this) { d->rotationOwner = 0; + } + } + } m_rotation = 0; m_rotationVariation = 0; m_rotationVelocity = 0; @@ -1050,10 +1056,13 @@ void QQuickImageParticle::resetRotation() void QQuickImageParticle::resetDeformation() { m_explicitDeformation = false; - foreach (const QString &str, m_groups) - foreach (QQuickParticleData* d, m_system->groupData[m_system->groupIds[str]]->data) - if (d->deformationOwner == this) + for (auto groupId : groupIds()) { + for (QQuickParticleData* d : qAsConst(m_system->groupData[groupId]->data)) { + if (d->deformationOwner == this) { d->deformationOwner = 0; + } + } + } if (m_xVector) delete m_xVector; if (m_yVector) @@ -1255,9 +1264,9 @@ void QQuickImageParticle::finishBuildParticleNodes(QSGNode** node) perfLevel = Simple; } - foreach (const QString &str, m_groups){//For sharing higher levels, need to have highest used so it renders - int gIdx = m_system->groupIds[str]; - foreach (QQuickParticlePainter* p, m_system->groupData[gIdx]->painters){ + for (auto groupId : groupIds()) { + //For sharing higher levels, need to have highest used so it renders + for (QQuickParticlePainter* p : qAsConst(m_system->groupData[groupId]->painters)) { QQuickImageParticle* other = qobject_cast(p); if (other){ if (other->perfLevel > perfLevel) { @@ -1382,16 +1391,15 @@ void QQuickImageParticle::finishBuildParticleNodes(QSGNode** node) } m_nodes.clear(); - foreach (const QString &str, m_groups){ - int gIdx = m_system->groupIds[str]; - int count = m_system->groupData[gIdx]->size(); + for (auto groupId : groupIds()) { + int count = m_system->groupData[groupId]->size(); QSGGeometryNode* node = new QSGGeometryNode(); node->setMaterial(m_material); node->markDirty(QSGNode::DirtyMaterial); - m_nodes.insert(gIdx, node); - m_idxStarts.insert(gIdx, m_lastIdxStart); - m_startsIdx.append(qMakePair(m_lastIdxStart, gIdx)); + m_nodes.insert(groupId, node); + m_idxStarts.insert(groupId, m_lastIdxStart); + m_startsIdx.append(qMakePair(m_lastIdxStart, groupId)); m_lastIdxStart += count; //Create Particle Geometry @@ -1423,7 +1431,7 @@ void QQuickImageParticle::finishBuildParticleNodes(QSGNode** node) g->setDrawingMode(GL_TRIANGLES); for (int p=0; p < count; ++p) - commit(gIdx, p);//commit sets geometry for the node, has its own perfLevel switch + commit(groupId, p);//commit sets geometry for the node, has its own perfLevel switch if (perfLevel == Sprites) initTexCoords((SpriteVertex*)g->vertexData(), vCount); @@ -1538,10 +1546,9 @@ void QQuickImageParticle::prepareNextFrame(QSGNode **node) void QQuickImageParticle::spritesUpdate(qreal time) { // Sprite progression handled CPU side, so as to have per-frame control. - foreach (const QString &str, m_groups) { - int gIdx = m_system->groupIds[str]; - foreach (QQuickParticleData* mainDatum, m_system->groupData[gIdx]->data) { - QSGGeometryNode *node = m_nodes[gIdx]; + for (auto groupId : groupIds()) { + for (QQuickParticleData* mainDatum : qAsConst(m_system->groupData[groupId]->data)) { + QSGGeometryNode *node = m_nodes[groupId]; if (!node) continue; //TODO: Interpolate between two different animations if it's going to transition next frame @@ -1549,7 +1556,7 @@ void QQuickImageParticle::spritesUpdate(qreal time) QQuickParticleData* datum = (mainDatum->animationOwner == this ? mainDatum : getShadowDatum(mainDatum)); int spriteIdx = 0; for (int i = 0; iindex; break; } diff --git a/src/particles/qquickitemparticle.cpp b/src/particles/qquickitemparticle.cpp index 4cd8ee9db8..ba6c6f915d 100644 --- a/src/particles/qquickitemparticle.cpp +++ b/src/particles/qquickitemparticle.cpp @@ -231,10 +231,10 @@ void QQuickItemParticle::reset() // delete all managed items which had their logical particles cleared // but leave it alone if the logical particle is maintained QSet lost = QSet::fromList(m_managed); - foreach (const QString group, m_groups){ - int gIdx = m_system->groupIds[group]; - foreach (QQuickParticleData* d, m_system->groupData[gIdx]->data) - lost.remove(d->delegate); + for (auto groupId : groupIds()) { + for (QQuickParticleData* d : qAsConst(m_system->groupData[groupId]->data)) { + lost.remove(d->delegate); + } } m_deletables.append(lost.toList()); //TODO: This doesn't yet handle calling detach on taken particles in the system reset case @@ -249,11 +249,12 @@ QSGNode* QQuickItemParticle::updatePaintNode(QSGNode* n, UpdatePaintNodeData* d) m_pleaseReset = false; //Refill loadables, delayed here so as to only happen once per frame max //### Constant resetting might lead to m_loadables never being populated when tick() occurs - foreach (const QString group, m_groups){ - int gIdx = m_system->groupIds[group]; - foreach (QQuickParticleData* d, m_system->groupData[gIdx]->data) - if (!d->delegate && d->t != -1 && d->stillAlive()) + for (auto groupId : groupIds()) { + for (QQuickParticleData* d : qAsConst(m_system->groupData[groupId]->data)) { + if (!d->delegate && d->t != -1 && d->stillAlive()) { m_loadables << d; + } + } } } prepareNextFrame(); @@ -276,31 +277,26 @@ void QQuickItemParticle::prepareNextFrame() return; //TODO: Size, better fade? - foreach (const QString &str, m_groups){ - const int gIdx = m_system->groupIds[str]; - const QVector dataVector = m_system->groupData[gIdx]->data; - const int count = dataVector.size(); - - for (int i=0; igroupData[groupId]->data)) { QQuickItem* item = data->delegate; if (!item) continue; - qreal t = ((timeStamp/1000.0) - data->t) / data->lifeSpan; + float t = ((timeStamp / 1000.0f) - data->t) / data->lifeSpan; if (m_stasis.contains(item)) { data->t += dt;//Stasis effect continue; } - if (t >= 1.0){//Usually happens from load + if (t >= 1.0f){//Usually happens from load m_deletables << item; data->delegate = 0; }else{//Fade data->delegate->setVisible(true); if (m_fade){ - qreal o = 1.; - if (t<0.2) - o = t*5; - if (t>0.8) + float o = 1.f; + if (t <0.2f) + o = t * 5; + if (t > 0.8f) o = (1-t)*5; item->setOpacity(o); } diff --git a/src/particles/qquickparticleemitter.cpp b/src/particles/qquickparticleemitter.cpp index 5e5c750e0e..7cce4d481a 100644 --- a/src/particles/qquickparticleemitter.cpp +++ b/src/particles/qquickparticleemitter.cpp @@ -237,6 +237,8 @@ QQuickParticleEmitter::QQuickParticleEmitter(QQuickItem *parent) : , m_reset_last(true) , m_last_timestamp(-1) , m_last_emission(0) + , m_groupIdNeedRecalculation(false) + , m_groupId(QQuickParticleGroupData::DefaultGroupID) { //TODO: Reset velocity/acc back to null vector? Or allow null pointer? @@ -257,6 +259,16 @@ bool QQuickParticleEmitter::isEmitConnected() IS_SIGNAL_CONNECTED(this, QQuickParticleEmitter, emitParticles, (QQmlV4Handle)); } +void QQuickParticleEmitter::reclaculateGroupId() const +{ + if (!m_system) { + m_groupId = QQuickParticleGroupData::InvalidID; + return; + } + m_groupId = m_system->groupIds.value(group(), QQuickParticleGroupData::InvalidID); + m_groupIdNeedRecalculation = m_groupId == QQuickParticleGroupData::InvalidID; +} + void QQuickParticleEmitter::componentComplete() { if (!m_system && qobject_cast(parentItem())) diff --git a/src/particles/qquickparticleemitter_p.h b/src/particles/qquickparticleemitter_p.h index bb77d132cc..9b114ad46b 100644 --- a/src/particles/qquickparticleemitter_p.h +++ b/src/particles/qquickparticleemitter_p.h @@ -119,6 +119,13 @@ public: return m_group; } + QQuickParticleGroupData::ID groupId() const + { + if (m_groupIdNeedRecalculation) + reclaculateGroupId(); + return m_groupId; + } + int particleDurationVariation() const { return m_particleDurationVariation; @@ -185,6 +192,7 @@ public Q_SLOTS: { if (m_system != arg) { m_system = arg; + m_groupIdNeedRecalculation = true; if (m_system) m_system->registerParticleEmitter(this); Q_EMIT systemChanged(arg); @@ -195,6 +203,7 @@ public Q_SLOTS: { if (m_group != arg) { m_group = arg; + m_groupIdNeedRecalculation = true; Q_EMIT groupChanged(arg); } } @@ -319,7 +328,6 @@ protected: int m_particleDurationVariation; bool m_enabled; QQuickParticleSystem* m_system; - QString m_group; QQuickParticleExtruder* m_extruder; QQuickParticleExtruder* m_defaultExtruder; QQuickParticleExtruder* effectiveExtruder(); @@ -350,7 +358,14 @@ protected: QPointF m_last_last_last_emitter; bool isEmitConnected(); -private: + +private: // methods + void reclaculateGroupId() const; + +private: // data + QString m_group; + mutable bool m_groupIdNeedRecalculation; + mutable QQuickParticleGroupData::ID m_groupId; QQuickDirection m_nullVector; }; diff --git a/src/particles/qquickparticlepainter.cpp b/src/particles/qquickparticlepainter.cpp index 134689713d..556d137fd4 100644 --- a/src/particles/qquickparticlepainter.cpp +++ b/src/particles/qquickparticlepainter.cpp @@ -64,9 +64,13 @@ QT_BEGIN_NAMESPACE If empty, it will paint the default particle group (""). */ -QQuickParticlePainter::QQuickParticlePainter(QQuickItem *parent) : - QQuickItem(parent), - m_system(0), m_count(0), m_pleaseReset(true), m_window(0) +QQuickParticlePainter::QQuickParticlePainter(QQuickItem *parent) + : QQuickItem(parent) + , m_system(0) + , m_count(0) + , m_pleaseReset(true) + , m_window(0) + , m_groupIdsNeedRecalculation(false) { } @@ -89,11 +93,32 @@ void QQuickParticlePainter::componentComplete() QQuickItem::componentComplete(); } +void QQuickParticlePainter::recalculateGroupIds() const +{ + if (!m_system) { + m_groupIds.clear(); + return; + } + + m_groupIdsNeedRecalculation = false; + m_groupIds.clear(); + + for (const QString &str : groups()) { + QQuickParticleGroupData::ID groupId = m_system->groupIds.value(str, QQuickParticleGroupData::InvalidID); + if (groupId == QQuickParticleGroupData::InvalidID) { + // invalid data, not finished setting up, or whatever. Fallback: do not cache. + m_groupIdsNeedRecalculation = true; + } else { + m_groupIds.append(groupId); + } + } +} void QQuickParticlePainter::setSystem(QQuickParticleSystem *arg) { if (m_system != arg) { m_system = arg; + m_groupIdsNeedRecalculation = true; if (m_system){ m_system->registerParticlePainter(this); reset(); @@ -102,6 +127,16 @@ void QQuickParticlePainter::setSystem(QQuickParticleSystem *arg) } } +void QQuickParticlePainter::setGroups(const QStringList &arg) +{ + if (m_groups != arg) { + m_groups = arg; + m_groupIdsNeedRecalculation = true; + //Note: The system watches this as it has to recalc things when groups change. It will request a reset if necessary + Q_EMIT groupsChanged(arg); + } +} + void QQuickParticlePainter::load(QQuickParticleData* d) { initialize(d->group, d->index); @@ -133,11 +168,6 @@ void QQuickParticlePainter::setCount(int c)//### TODO: some resizeing so that pa reset(); } -int QQuickParticlePainter::count() -{ - return m_count; -} - void QQuickParticlePainter::calcSystemOffset(bool resetPending) { if (!m_system || !parentItem()) diff --git a/src/particles/qquickparticlepainter_p.h b/src/particles/qquickparticlepainter_p.h index 719dfdb3d8..064ce27fe8 100644 --- a/src/particles/qquickparticlepainter_p.h +++ b/src/particles/qquickparticlepainter_p.h @@ -64,25 +64,40 @@ class QQuickParticlePainter : public QQuickItem Q_PROPERTY(QQuickParticleSystem* system READ system WRITE setSystem NOTIFY systemChanged) Q_PROPERTY(QStringList groups READ groups WRITE setGroups NOTIFY groupsChanged) +public: // data + typedef QQuickParticleVarLengthArray GroupIDs; + public: explicit QQuickParticlePainter(QQuickItem *parent = 0); //Data Interface to system void load(QQuickParticleData*); void reload(QQuickParticleData*); void setCount(int c); - int count(); + + int count() const + { + return m_count; + } + void performPendingCommits();//Called from updatePaintNode QQuickParticleSystem* system() const { return m_system; } - QStringList groups() const { return m_groups; } + const GroupIDs &groupIds() const + { + if (m_groupIdsNeedRecalculation) { + recalculateGroupIds(); + } + return m_groupIds; + } + void itemChange(ItemChange, const ItemChangeData &); Q_SIGNALS: @@ -94,14 +109,7 @@ Q_SIGNALS: public Q_SLOTS: void setSystem(QQuickParticleSystem* arg); - void setGroups(const QStringList &arg) - { - if (m_groups != arg) { - m_groups = arg; - //Note: The system watches this as it has to recalc things when groups change. It will request a reset if necessary - Q_EMIT groupsChanged(arg); - } - } + void setGroups(const QStringList &arg); void calcSystemOffset(bool resetPending = false); @@ -130,13 +138,18 @@ protected: friend class QQuickParticleSystem; int m_count; bool m_pleaseReset;//Used by subclasses, but it's a nice optimization to know when stuff isn't going to matter. - QStringList m_groups; QPointF m_systemOffset; QQuickWindow *m_window; -private: +private: // methods + void recalculateGroupIds() const; + +private: // data + QStringList m_groups; QSet > m_pendingCommits; + mutable GroupIDs m_groupIds; + mutable bool m_groupIdsNeedRecalculation; }; QT_END_NAMESPACE diff --git a/src/particles/qquickparticlesystem.cpp b/src/particles/qquickparticlesystem.cpp index e91ab40ffa..8ccdec4792 100644 --- a/src/particles/qquickparticlesystem.cpp +++ b/src/particles/qquickparticlesystem.cpp @@ -902,22 +902,21 @@ void QQuickParticleSystem::loadPainter(QObject *p) QQuickParticlePainter* painter = qobject_cast(p); Q_ASSERT(painter);//XXX - foreach (QQuickParticleGroupData* sg, groupData) - sg->painters.remove(painter); + for (QQuickParticleGroupData* sg : groupData) { + sg->painters.removeOne(painter); + } + int particleCount = 0; if (painter->groups().isEmpty()) {//Uses default particle - QStringList def; - def << QString(); + static QStringList def = QStringList() << QString(); painter->setGroups(def); particleCount += groupData[0]->size(); groupData[0]->painters << painter; } else { - foreach (const QString &group, painter->groups()) { - if (!group.isEmpty() && !groupIds.contains(group)) {//new group - new QQuickParticleGroupData(group, this); - } - particleCount += groupData[groupIds[group]]->size(); - groupData[groupIds[group]]->painters << painter; + for (auto groupId : painter->groupIds()) { + QQuickParticleGroupData *gd = groupData[groupId]; + particleCount += gd->size(); + gd->painters << painter; } } painter->setCount(particleCount); @@ -940,22 +939,23 @@ void QQuickParticleSystem::emittersChanged() } // Populate groups and set sizes. - for (int i = 0; i < m_emitters.count(); ++i) { + for (int i = 0; i < m_emitters.count(); ) { QQuickParticleEmitter *e = m_emitters.at(i); if (!e) { m_emitters.removeAt(i); - i--; continue; } - if (!e->group().isEmpty() && - !groupIds.contains(e->group())) { - new QQuickParticleGroupData(e->group(), this); + int groupId = e->groupId(); + if (groupId == QQuickParticleGroupData::InvalidID) { + groupId = (new QQuickParticleGroupData(e->group(), this))->index; previousSizes << 0; newSizes << 0; } - newSizes[groupIds[e->group()]] += e->particleCount(); + newSizes[groupId] += e->particleCount(); //###: Cull emptied groups? + + ++i; } //TODO: Garbage collection? diff --git a/src/particles/qquickparticlesystem_p.h b/src/particles/qquickparticlesystem_p.h index 9ddbb2ff38..2745e73053 100644 --- a/src/particles/qquickparticlesystem_p.h +++ b/src/particles/qquickparticlesystem_p.h @@ -65,6 +65,30 @@ QT_BEGIN_NAMESPACE +template +class QQuickParticleVarLengthArray: public QVarLengthArray +{ +public: + void insert(const T &element) + { + if (!this->contains(element)) { + this->append(element); + } + } + + bool removeOne(const T &element) + { + for (int i = 0; i < this->size(); ++i) { + if (this->at(i) == element) { + this->remove(i); + return true; + } + } + + return false; + } +}; + class QQuickParticleSystem; class QQuickParticleAffector; class QQuickParticleEmitter; @@ -110,6 +134,10 @@ private: }; class Q_QUICKPARTICLES_PRIVATE_EXPORT QQuickParticleGroupData { +public: // types + typedef int ID; + enum { InvalidID = -1, DefaultGroupID = 0 }; + public: QQuickParticleGroupData(const QString &name, QQuickParticleSystem* sys); ~QQuickParticleGroupData(); @@ -121,8 +149,8 @@ public: void setSize(int newSize); - const int index; - QSet painters;//TODO: What if they are dynamically removed? + const ID index; + QQuickParticleVarLengthArray painters;//TODO: What if they are dynamically removed? //TODO: Refactor particle data list out into a separate class QVector data; diff --git a/src/particles/qquicktrailemitter.cpp b/src/particles/qquicktrailemitter.cpp index 89a68a0356..904421c296 100644 --- a/src/particles/qquicktrailemitter.cpp +++ b/src/particles/qquicktrailemitter.cpp @@ -179,7 +179,7 @@ void QQuickTrailEmitter::emitWindow(int timeStamp) qreal sizeAtEnd = m_particleEndSize >= 0 ? m_particleEndSize : m_particleSize; int gId = m_system->groupIds[m_follow]; - int gId2 = m_system->groupIds[m_group]; + int gId2 = groupId(); for (int i=0; igroupData[gId]->data.count(); i++) { QQuickParticleData *d = m_system->groupData[gId]->data[i]; if (!d->stillAlive()){ -- cgit v1.2.3 From 7179050ecf53634befba08cacee5f260ab373f0b Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Tue, 23 Feb 2016 15:09:53 +0100 Subject: V4: Replace foreach with range-based for loops on QVarLengthArrays. QVarLengthArray is not shared, so it will not detach and make a copy of the data when begin() is called. Change-Id: I9114d99fc0cabb17d68993408bea01695754437a Reviewed-by: Lars Knoll --- src/qml/compiler/qv4ssa.cpp | 46 ++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/qml/compiler/qv4ssa.cpp b/src/qml/compiler/qv4ssa.cpp index 7881ab951a..924fb36794 100644 --- a/src/qml/compiler/qv4ssa.cpp +++ b/src/qml/compiler/qv4ssa.cpp @@ -557,7 +557,7 @@ class DominatorTree BasicBlockIndex p = d->parent[n]; BasicBlockIndex s = p; - foreach (BasicBlock *v, function->basicBlock(n)->in) { + for (BasicBlock *v : function->basicBlock(n)->in) { BasicBlockIndex ss = InvalidBasicBlockIndex; if (d->dfnum[v->index()] <= d->dfnum[n]) ss = v->index(); @@ -667,7 +667,7 @@ public: if (np.todo.empty()) { BasicBlockSet &S = DF[node]; S.init(function); - foreach (BasicBlock *y, function->basicBlock(node)->out) + for (BasicBlock *y : function->basicBlock(node)->out) if (idom[y->index()] != node) S.insert(y); for (BasicBlockIndex child : np.children) { @@ -714,7 +714,7 @@ public: BasicBlock *fBlock = *it; Q_ASSERT(!dominates(n, fBlock) || fBlock == n); bool hasDominatedSucc = false; - foreach (BasicBlock *succ, fBlock->in) { + for (BasicBlock *succ : fBlock->in) { if (dominates(n, succ)) { hasDominatedSucc = true; break; @@ -945,8 +945,7 @@ private: std::vector prefix; prefix.reserve(32); - for (int i = 0, ei = node->in.size(); i != ei; ++i) { - BasicBlock *in = node->in.at(i); + for (BasicBlock *in : node->in) { if (node == in) // back-edge to self continue; if (dominates(node->index(), in->index())) // a known back-edge @@ -1565,7 +1564,7 @@ private: processed.markAsProcessed(bb); BasicBlock *next = 0; - foreach (BasicBlock *out, bb->out) { + for (BasicBlock *out : bb->out) { if (processed.alreadyProcessed(out)) continue; if (!next) @@ -1586,7 +1585,7 @@ private: s->accept(this); } - foreach (BasicBlock *Y, bb->out) { + for (BasicBlock *Y : bb->out) { const int j = Y->in.indexOf(bb); Q_ASSERT(j >= 0 && j < Y->in.size()); foreach (Stmt *s, Y->statements()) { @@ -3117,7 +3116,7 @@ void splitCriticalEdges(IR::Function *f, DominatorTree &df, StatementWorklist &w df.setImmediateDominator(newBB, fromBB); bool toNeedsNewIdom = true; - foreach (BasicBlock *bb, toBB->in) { + for (BasicBlock *bb : toBB->in) { if (bb != newBB && !df.dominates(toBB, bb)) { toNeedsNewIdom = false; break; @@ -3227,7 +3226,7 @@ public: backedges.clear(); - foreach (BasicBlock *in, bb->in) + for (BasicBlock *in : bb->in) if (dt.dominates(bb, in)) backedges.push_back(in); @@ -3304,7 +3303,7 @@ private: // those predecessors are not in the current subloop. It might be the case // that they are in other loops, which we will then add as a subloop to the // current loop. - foreach (BasicBlock *predIn, predIt->in) + for (BasicBlock *predIn : predIt->in) if (predIn->containingGroup() != subloop) worklist.push_back(predIn); } else { @@ -3315,7 +3314,7 @@ private: predIt->setContainingGroup(loopHead); // Add all incoming edges to the worklist. - foreach (BasicBlock *bb, predIt->in) + for (BasicBlock *bb : predIt->in) worklist.push_back(bb); } } @@ -3400,7 +3399,7 @@ class BlockScheduler { Q_ASSERT(candidate->containingGroup() == currentGroup.group); - foreach (BasicBlock *in, candidate->in) { + for (BasicBlock *in : candidate->in) { if (emitted.alreadyProcessed(in)) continue; @@ -3510,7 +3509,7 @@ public: void checkCriticalEdges(QVector basicBlocks) { foreach (BasicBlock *bb, basicBlocks) { if (bb && bb->out.size() > 1) { - foreach (BasicBlock *bb2, bb->out) { + for (BasicBlock *bb2 : bb->out) { if (bb2 && bb2->in.size() > 1) { qDebug() << "found critical edge between block" << bb->index() << "and block" << bb2->index(); @@ -3545,7 +3544,7 @@ static void cleanupBasicBlocks(IR::Function *function) reachableBlocks.setBit(bb->index()); - foreach (BasicBlock *outBB, bb->out) { + for (BasicBlock *outBB : bb->out) { if (!reachableBlocks.at(outBB->index())) postponed.append(outBB); } @@ -3557,7 +3556,7 @@ static void cleanupBasicBlocks(IR::Function *function) if (reachableBlocks.at(bb->index())) // the block is reachable, so ignore it continue; - foreach (BasicBlock *outBB, bb->out) { + for (BasicBlock *outBB : bb->out) { if (outBB->isRemoved() || !reachableBlocks.at(outBB->index())) continue; // We do not need to unlink from blocks that are scheduled to be removed. @@ -3800,14 +3799,14 @@ void unlink(BasicBlock *from, BasicBlock *to, IR::Function *func, DefUses &defUs continue; // unlink all incoming edges - foreach (BasicBlock *in, bb->in) { + for (BasicBlock *in : bb->in) { int idx = in->out.indexOf(bb); if (idx != -1) in->out.remove(idx); } // unlink all outgoing edges, including "arguments" to phi statements - foreach (BasicBlock *out, bb->out) { + for (BasicBlock *out : bb->out) { if (out->isRemoved()) continue; @@ -3949,7 +3948,7 @@ void cfg2dot(IR::Function *f, const QVector &loops = else qout << ", shape=circle"; qout << "];\n"; - foreach (BasicBlock *out, bb->out) + for (BasicBlock *out : bb->out) qout << " L" << idx << " -> L" << out->index() << "\n"; } @@ -4420,7 +4419,7 @@ private: void buildIntervals(BasicBlock *bb, BasicBlock *loopEnd) { LiveRegs live; - foreach (BasicBlock *successor, bb->out) { + for (BasicBlock *successor : bb->out) { live.unite(_liveIn[successor->index()]); const int bbIndex = successor->in.indexOf(bb); Q_ASSERT(bbIndex >= 0); @@ -4731,7 +4730,8 @@ private: // the terminators will automatically insert that edge). The blocks where the originals // pointed to will have an extra incoming edge from the copied blocks. - foreach (BasicBlock *in, loop->loopHeader->in) { + BasicBlock::IncomingEdges inCopy = loop->loopHeader->in; + for (BasicBlock *in : inCopy) { if (unpeeled.loopHeader != in // this can happen for really tight loops (where there are no body blocks). This is a back-edge in that case. && !unpeeled.loopBody.contains(in) // if the edge is not coming from within the copied set, leave it alone && !dt.dominates(loop->loopHeader, in)) // an edge coming from within the loop (so a back-edge): this is handled when rewiring all outgoing edges @@ -4837,14 +4837,14 @@ static void verifyCFG(IR::Function *function) } // Check the outgoing edges: - foreach (BasicBlock *out, bb->out) { + for (BasicBlock *out : bb->out) { Q_UNUSED(out); Q_ASSERT(!out->isRemoved()); Q_ASSERT(out->in.contains(bb)); } // Check the incoming edges: - foreach (BasicBlock *in, bb->in) { + for (BasicBlock *in : bb->in) { Q_UNUSED(in); Q_ASSERT(!in->isRemoved()); Q_ASSERT(in->out.contains(bb)); @@ -5335,7 +5335,7 @@ void Optimizer::convertOutOfSSA() { foreach (BasicBlock *bb, function->basicBlocks()) { MoveMapping moves; - foreach (BasicBlock *successor, bb->out) { + for (BasicBlock *successor : bb->out) { const int inIdx = successor->in.indexOf(bb); Q_ASSERT(inIdx >= 0); foreach (Stmt *s, successor->statements()) { -- cgit v1.2.3 From 601e28b6289a7965c79e0e014d710913c20a91d7 Mon Sep 17 00:00:00 2001 From: Frederik Gladhorn Date: Mon, 29 Feb 2016 15:00:09 +0100 Subject: Let QQmlObjectCreator::setPropertyBinding return false for invalid types This in theory happen for attached property types. Fixes Coverity CID 154272. Change-Id: I113797dea8949877cbeac82bae57655170878d4c Reviewed-by: Lars Knoll --- src/qml/qml/qqmlobjectcreator.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index 21e6d5f6de..15c38c1d5b 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -710,6 +710,8 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con QQmlTypeNameCache::Result res = context->imports->query(stringAt(binding->propertyNameIndex)); if (res.isValid()) attachedType = res.type; + else + return false; } const int id = attachedType->attachedPropertiesId(QQmlEnginePrivate::get(engine)); QObject *qmlObject = qmlAttachedPropertiesObjectById(id, _qobject); -- cgit v1.2.3 From 06d82fdbce5f647ac2651cc28eede456c681953c Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Tue, 23 Feb 2016 15:18:26 +0100 Subject: V4: Replace foreach with range based for loops for statements. BasicBlock::statements() returns a const reference to a QVector, so it can safely be iterated over without qAsConst. Change-Id: If4e47e0e113adbc87253bb3478208a3a38fed9e2 Reviewed-by: Simon Hausmann --- src/qml/compiler/qqmltypecompiler.cpp | 4 ++-- src/qml/compiler/qv4isel_moth.cpp | 4 ++-- src/qml/compiler/qv4isel_util_p.h | 2 +- src/qml/compiler/qv4ssa.cpp | 30 +++++++++++++++--------------- 4 files changed, 20 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp index 33716d57b8..57192a9221 100644 --- a/src/qml/compiler/qqmltypecompiler.cpp +++ b/src/qml/compiler/qqmltypecompiler.cpp @@ -2732,7 +2732,7 @@ bool QQmlJavaScriptBindingExpressionSimplificationPass::simplifyBinding(QV4::IR: return false; foreach (QV4::IR::BasicBlock *bb, function->basicBlocks()) { - foreach (QV4::IR::Stmt *s, bb->statements()) { + for (QV4::IR::Stmt *s : bb->statements()) { s->accept(this); if (!_canSimplify) return false; @@ -2902,7 +2902,7 @@ void QQmlIRFunctionCleanser::clean() foreach (QV4::IR::Function *function, module->functions) { foreach (QV4::IR::BasicBlock *block, function->basicBlocks()) { - foreach (QV4::IR::Stmt *s, block->statements()) { + for (QV4::IR::Stmt *s : block->statements()) { s->accept(this); } } diff --git a/src/qml/compiler/qv4isel_moth.cpp b/src/qml/compiler/qv4isel_moth.cpp index b3468848ca..dcedc54b6e 100644 --- a/src/qml/compiler/qv4isel_moth.cpp +++ b/src/qml/compiler/qv4isel_moth.cpp @@ -255,7 +255,7 @@ protected: if (IR::Jump *jump = s->asJump()) { IR::MoveMapping moves; - foreach (IR::Stmt *succStmt, jump->target->statements()) { + for (IR::Stmt *succStmt : jump->target->statements()) { if (IR::Phi *phi = succStmt->asPhi()) { forceActivation(*phi->targetTemp); for (int i = 0, ei = phi->d->incoming.size(); i != ei; ++i) { @@ -404,7 +404,7 @@ void InstructionSelection::run(int functionIndex) exceptionHandler = _block->catchBlock; } - foreach (IR::Stmt *s, _block->statements()) { + for (IR::Stmt *s : _block->statements()) { _currentStatement = s; if (s->location.isValid()) { diff --git a/src/qml/compiler/qv4isel_util_p.h b/src/qml/compiler/qv4isel_util_p.h index 9ef3ef6721..0f207f8368 100644 --- a/src/qml/compiler/qv4isel_util_p.h +++ b/src/qml/compiler/qv4isel_util_p.h @@ -149,7 +149,7 @@ public: if (bb->isRemoved()) continue; _currentBasicBlock = bb; - foreach (IR::Stmt *s, bb->statements()) + for (IR::Stmt *s : bb->statements()) process(s); } diff --git a/src/qml/compiler/qv4ssa.cpp b/src/qml/compiler/qv4ssa.cpp index 924fb36794..77b1aef1e8 100644 --- a/src/qml/compiler/qv4ssa.cpp +++ b/src/qml/compiler/qv4ssa.cpp @@ -1060,7 +1060,7 @@ public: currentBB = bb; killed.assign(function->tempCount, false); - foreach (Stmt *s, bb->statements()) + for (Stmt *s : bb->statements()) s->accept(this); } } @@ -1580,7 +1580,7 @@ private: { currentBB = bb; - foreach (Stmt *s, bb->statements()) { + for (Stmt *s : bb->statements()) { currentStmt = s; s->accept(this); } @@ -1588,7 +1588,7 @@ private: for (BasicBlock *Y : bb->out) { const int j = Y->in.indexOf(bb); Q_ASSERT(j >= 0 && j < Y->in.size()); - foreach (Stmt *s, Y->statements()) { + for (Stmt *s : Y->statements()) { if (Phi *phi = s->asPhi()) { Temp *t = phi->d->incoming[j]->asTemp(); unsigned newTmp = currentNumber(*t); @@ -1848,7 +1848,7 @@ public: if (bb->isRemoved()) continue; - foreach (Stmt *s, bb->statements()) { + for (Stmt *s : bb->statements()) { if (!s) continue; @@ -2838,7 +2838,7 @@ public: continue; _conversions.clear(); - foreach (Stmt *s, bb->statements()) { + for (Stmt *s : bb->statements()) { _currStmt = s; s->accept(this); } @@ -3563,7 +3563,7 @@ static void cleanupBasicBlocks(IR::Function *function) int idx = outBB->in.indexOf(bb); if (idx != -1) { outBB->in.remove(idx); - foreach (Stmt *s, outBB->statements()) { + for (Stmt *s : outBB->statements()) { if (Phi *phi = s->asPhi()) phi->d->incoming.remove(idx); else @@ -3822,7 +3822,7 @@ void unlink(BasicBlock *from, BasicBlock *to, IR::Function *func, DefUses &defUs } // unlink all defs/uses from the statements in the basic block - foreach (Stmt *s, bb->statements()) { + for (Stmt *s : bb->statements()) { if (!s) continue; @@ -4424,7 +4424,7 @@ private: const int bbIndex = successor->in.indexOf(bb); Q_ASSERT(bbIndex >= 0); - foreach (Stmt *s, successor->statements()) { + for (Stmt *s : successor->statements()) { if (Phi *phi = s->asPhi()) { if (Temp *t = phi->d->incoming.at(bbIndex)->asTemp()) live.insert(*t); @@ -4434,7 +4434,7 @@ private: } } - QVector statements = bb->statements(); + const QVector &statements = bb->statements(); foreach (const Temp &opd, live) interval(&opd).addRange(start(bb), end(bb)); @@ -4529,7 +4529,7 @@ public: foreach (BasicBlock *bb, function->basicBlocks()) if (!bb->isRemoved()) - foreach (Stmt *s, bb->statements()) + for (Stmt *s : bb->statements()) s->accept(this); if (convertArgs && function->formals.size() > 0) @@ -4613,7 +4613,7 @@ public: { block = new BasicBlock(originalBlock->function, 0); - foreach (Stmt *s, originalBlock->statements()) { + for (Stmt *s : originalBlock->statements()) { s->accept(this); clonedStmt->location = s->location; } @@ -4886,7 +4886,7 @@ static void verifyNoPointerSharing(IR::Function *function) if (bb->isRemoved()) continue; - foreach (Stmt *s, bb->statements()) + for (Stmt *s : bb->statements()) s->accept(this); } } @@ -4954,7 +4954,7 @@ public: if (bb->isRemoved()) continue; - foreach (Stmt *s, bb->statements()) { + for (Stmt *s : bb->statements()) { if (!hasSideEffects(s)) { s->location = QQmlJS::AST::SourceLocation(); } @@ -5172,7 +5172,7 @@ void LifeTimeIntervals::renumber(IR::Function *function) _basicBlockPosition[bb->index()].start = _lastPosition + 1; - foreach (Stmt *s, bb->statements()) { + for (Stmt *s : bb->statements()) { if (s->asPhi()) continue; @@ -5338,7 +5338,7 @@ void Optimizer::convertOutOfSSA() { for (BasicBlock *successor : bb->out) { const int inIdx = successor->in.indexOf(bb); Q_ASSERT(inIdx >= 0); - foreach (Stmt *s, successor->statements()) { + for (Stmt *s : successor->statements()) { if (Phi *phi = s->asPhi()) { moves.add(clone(phi->d->incoming[inIdx], function), clone(phi->targetTemp, function)->asTemp()); -- cgit v1.2.3 From 3cc5c3b845b6c26d2e6c35de4672bd55b7e192b0 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Tue, 23 Feb 2016 15:27:25 +0100 Subject: V4: Replace foreach with range based for loops for statements. Function::basicBlocks() returns a const reference to a QVector, so it can safely be iterated over without qAsConst. Change-Id: Ie9a17edfff7c1fbdc3601121935aef4b41338a35 Reviewed-by: Simon Hausmann --- src/qml/compiler/qqmltypecompiler.cpp | 4 +-- src/qml/compiler/qv4isel_moth.cpp | 2 +- src/qml/compiler/qv4isel_util_p.h | 2 +- src/qml/compiler/qv4ssa.cpp | 49 ++++++++++++++++++----------------- 4 files changed, 29 insertions(+), 28 deletions(-) (limited to 'src') diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp index 57192a9221..a71793f2b6 100644 --- a/src/qml/compiler/qqmltypecompiler.cpp +++ b/src/qml/compiler/qqmltypecompiler.cpp @@ -2731,7 +2731,7 @@ bool QQmlJavaScriptBindingExpressionSimplificationPass::simplifyBinding(QV4::IR: if (function->basicBlockCount() > 10) return false; - foreach (QV4::IR::BasicBlock *bb, function->basicBlocks()) { + for (QV4::IR::BasicBlock *bb : function->basicBlocks()) { for (QV4::IR::Stmt *s : bb->statements()) { s->accept(this); if (!_canSimplify) @@ -2901,7 +2901,7 @@ void QQmlIRFunctionCleanser::clean() module->functions = newFunctions; foreach (QV4::IR::Function *function, module->functions) { - foreach (QV4::IR::BasicBlock *block, function->basicBlocks()) { + for (QV4::IR::BasicBlock *block : function->basicBlocks()) { for (QV4::IR::Stmt *s : block->statements()) { s->accept(this); } diff --git a/src/qml/compiler/qv4isel_moth.cpp b/src/qml/compiler/qv4isel_moth.cpp index dcedc54b6e..7d6d7e65bc 100644 --- a/src/qml/compiler/qv4isel_moth.cpp +++ b/src/qml/compiler/qv4isel_moth.cpp @@ -385,7 +385,7 @@ void InstructionSelection::run(int functionIndex) addInstruction(push); currentLine = 0; - QVector basicBlocks = _function->basicBlocks(); + const QVector &basicBlocks = _function->basicBlocks(); for (int i = 0, ei = basicBlocks.size(); i != ei; ++i) { blockNeedsDebugInstruction = irModule->debugMode; _block = basicBlocks[i]; diff --git a/src/qml/compiler/qv4isel_util_p.h b/src/qml/compiler/qv4isel_util_p.h index 0f207f8368..674fc01623 100644 --- a/src/qml/compiler/qv4isel_util_p.h +++ b/src/qml/compiler/qv4isel_util_p.h @@ -145,7 +145,7 @@ public: { _stackSlotForTemp.reserve(function->tempCount); - foreach (IR::BasicBlock *bb, function->basicBlocks()) { + for (IR::BasicBlock *bb : function->basicBlocks()) { if (bb->isRemoved()) continue; _currentBasicBlock = bb; diff --git a/src/qml/compiler/qv4ssa.cpp b/src/qml/compiler/qv4ssa.cpp index 77b1aef1e8..704524ce19 100644 --- a/src/qml/compiler/qv4ssa.cpp +++ b/src/qml/compiler/qv4ssa.cpp @@ -617,7 +617,7 @@ public: // compute children of each node in the dominator tree std::vector > children; // BasicBlock index -> children children.resize(function->basicBlockCount()); - foreach (BasicBlock *n, function->basicBlocks()) { + for (BasicBlock *n : function->basicBlocks()) { if (n->isRemoved()) continue; const BasicBlockIndex nodeIndex = n->index(); @@ -633,7 +633,7 @@ public: nodeStatus.resize(function->basicBlockCount()); std::vector worklist; worklist.reserve(function->basicBlockCount()); - foreach (BasicBlock *bb, function->basicBlocks()) { + for (BasicBlock *bb : function->basicBlocks()) { if (bb->isRemoved()) continue; BasicBlockIndex nodeIndex = bb->index(); @@ -689,7 +689,7 @@ public: buf.open(QIODevice::WriteOnly); QTextStream qout(&buf); qout << "Dominator Frontiers:" << endl; - foreach (BasicBlock *n, function->basicBlocks()) { + for (BasicBlock *n : function->basicBlocks()) { if (n->isRemoved()) continue; @@ -706,7 +706,7 @@ public: } if (DebugDominatorFrontiers && DebugCodeCanUseLotsOfCpu) { - foreach (BasicBlock *n, function->basicBlocks()) { + for (BasicBlock *n : function->basicBlocks()) { if (n->isRemoved()) continue; const BasicBlockSet &fBlocks = DF[n->index()]; @@ -747,7 +747,7 @@ public: buf.open(QIODevice::WriteOnly); QTextStream qout(&buf); qout << "Immediate dominators:" << endl; - foreach (BasicBlock *to, function->basicBlocks()) { + for (BasicBlock *to : function->basicBlocks()) { if (to->isRemoved()) continue; @@ -881,7 +881,7 @@ private: { std::vector nodeDepths(size_t(function->basicBlockCount()), -1); nodeDepths[0] = 0; - foreach (BasicBlock *bb, function->basicBlocks()) { + for (BasicBlock *bb : function->basicBlocks()) { if (bb->isRemoved()) continue; @@ -1054,7 +1054,7 @@ public: for (size_t i = 0; i != ei; ++i) A_orig[i].reserve(8); - foreach (BasicBlock *bb, function->basicBlocks()) { + for (BasicBlock *bb : function->basicBlocks()) { if (bb->isRemoved()) continue; @@ -1844,7 +1844,7 @@ public: { grow(); - foreach (BasicBlock *bb, function->basicBlocks()) { + for (BasicBlock *bb : function->basicBlocks()) { if (bb->isRemoved()) continue; @@ -1904,7 +1904,7 @@ public: void applyToFunction() { - foreach (BasicBlock *bb, theFunction->basicBlocks()) { + for (BasicBlock *bb : theFunction->basicBlocks()) { if (bb->isRemoved()) continue; @@ -2833,7 +2833,7 @@ public: void run(IR::Function *f, StatementWorklist &worklist) { _f = f; - foreach (BasicBlock *bb, f->basicBlocks()) { + for (BasicBlock *bb : f->basicBlocks()) { if (bb->isRemoved()) continue; _conversions.clear(); @@ -3048,7 +3048,8 @@ protected: void splitCriticalEdges(IR::Function *f, DominatorTree &df, StatementWorklist &worklist, DefUses &defUses) { - foreach (BasicBlock *toBB, f->basicBlocks()) { + const QVector copy = f->basicBlocks(); + for (BasicBlock *toBB : copy) { if (toBB->isRemoved()) continue; if (toBB->in.size() < 2) @@ -3326,7 +3327,7 @@ private: void createLoopInfos(IR::Function *function) { - foreach (BasicBlock *bb, function->basicBlocks()) { + for (BasicBlock *bb : function->basicBlocks()) { if (bb->isRemoved()) continue; if (BasicBlock *loopHeader = bb->containingGroup()) @@ -3550,7 +3551,7 @@ static void cleanupBasicBlocks(IR::Function *function) } } - foreach (BasicBlock *bb, function->basicBlocks()) { + for (BasicBlock *bb : function->basicBlocks()) { if (bb->isRemoved()) // the block has already been removed, so ignore it continue; if (reachableBlocks.at(bb->index())) // the block is reachable, so ignore it @@ -3937,7 +3938,7 @@ void cfg2dot(IR::Function *f, const QVector &loops = Util(qout).genLoop(l); } - foreach (BasicBlock *bb, f->basicBlocks()) { + for (BasicBlock *bb : f->basicBlocks()) { if (bb->isRemoved()) continue; @@ -4482,7 +4483,7 @@ void removeUnreachleBlocks(IR::Function *function) { QVector newSchedule; newSchedule.reserve(function->basicBlockCount()); - foreach (BasicBlock *bb, function->basicBlocks()) + for (BasicBlock *bb : function->basicBlocks()) if (!bb->isRemoved()) newSchedule.append(bb); function->setScheduledBlocks(newSchedule); @@ -4527,7 +4528,7 @@ public: } } - foreach (BasicBlock *bb, function->basicBlocks()) + for (BasicBlock *bb : function->basicBlocks()) if (!bb->isRemoved()) for (Stmt *s : bb->statements()) s->accept(this); @@ -4805,7 +4806,7 @@ static void verifyCFG(IR::Function *function) if (!DoVerification) return; - foreach (BasicBlock *bb, function->basicBlocks()) { + for (BasicBlock *bb : function->basicBlocks()) { if (bb->isRemoved()) { Q_ASSERT(bb->in.isEmpty()); Q_ASSERT(bb->out.isEmpty()); @@ -4861,7 +4862,7 @@ static void verifyImmediateDominators(const DominatorTree &dt, IR::Function *fun dt.dumpImmediateDominators(); DominatorTree referenceTree(function); - foreach (BasicBlock *bb, function->basicBlocks()) { + for (BasicBlock *bb : function->basicBlocks()) { if (bb->isRemoved()) continue; @@ -4882,7 +4883,7 @@ static void verifyNoPointerSharing(IR::Function *function) public: void operator()(IR::Function *f) { - foreach (BasicBlock *bb, f->basicBlocks()) { + for (BasicBlock *bb : f->basicBlocks()) { if (bb->isRemoved()) continue; @@ -4950,7 +4951,7 @@ class RemoveLineNumbers: public SideEffectsChecker, public StmtVisitor public: static void run(IR::Function *function) { - foreach (BasicBlock *bb, function->basicBlocks()) { + for (BasicBlock *bb : function->basicBlocks()) { if (bb->isRemoved()) continue; @@ -5166,7 +5167,7 @@ LifeTimeIntervals::LifeTimeIntervals(IR::Function *function) // basic-block. void LifeTimeIntervals::renumber(IR::Function *function) { - foreach (BasicBlock *bb, function->basicBlocks()) { + for (BasicBlock *bb : function->basicBlocks()) { if (bb->isRemoved()) continue; @@ -5202,7 +5203,7 @@ void Optimizer::run(QQmlEnginePrivate *qmlEngine, bool doTypeInference, bool pee function->removeSharedExpressions(); int statementCount = 0; - foreach (BasicBlock *bb, function->basicBlocks()) + for (BasicBlock *bb : function->basicBlocks()) if (!bb->isRemoved()) statementCount += bb->statementCount(); // showMeTheCode(function); @@ -5332,7 +5333,7 @@ void Optimizer::convertOutOfSSA() { // There should be no critical edges at this point. - foreach (BasicBlock *bb, function->basicBlocks()) { + for (BasicBlock *bb : function->basicBlocks()) { MoveMapping moves; for (BasicBlock *successor : bb->out) { @@ -5368,7 +5369,7 @@ void Optimizer::convertOutOfSSA() { moves.insertMoves(bb, function, true); } - foreach (BasicBlock *bb, function->basicBlocks()) { + for (BasicBlock *bb : function->basicBlocks()) { while (!bb->isEmpty()) { if (bb->statements().first()->asPhi()) { bb->removeStatement(0); -- cgit v1.2.3 From bd380e7ff3717895b47b7a7996ebb57e0cefe2b8 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Sat, 5 Mar 2016 14:28:21 +0100 Subject: QQmlListModelWorkerAgent: fix -Wmisleading-indentation warning (GCC 6, genuine) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Says GCC 6: qtdeclarative/src/qml/types/qqmllistmodelworkeragent_p.h: In member function ‘QQmlListModelWorkerAgent::VariantRef& QQmlListModelWorkerAgent::VariantRef::operator=(const QQmlListModelWorkerAgent::VariantRef&)’: qtdeclarative/src/qml/types/qqmllistmodelworkeragent_p.h:94:34: error: statement is indented as if it were guarded by... [-Werror=misleading-indentation] if (a) a->release(); a = o.a; ^ qtdeclarative/src/qml/types/qqmllistmodelworkeragent_p.h:94:13: note: ...this ‘if’ clause, but it is not if (a) a->release(); a = o.a; ^~ This one is correct. Change-Id: I6315e4afa6a0cf8bb4dd3a599bd7ffe7b6a5c1e4 Reviewed-by: Simon Hausmann --- src/qml/types/qqmllistmodelworkeragent_p.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/qml/types/qqmllistmodelworkeragent_p.h b/src/qml/types/qqmllistmodelworkeragent_p.h index be5217eaa4..9a39ecaa38 100644 --- a/src/qml/types/qqmllistmodelworkeragent_p.h +++ b/src/qml/types/qqmllistmodelworkeragent_p.h @@ -91,7 +91,8 @@ public: VariantRef &operator=(const VariantRef &o) { if (o.a) o.a->addref(); - if (a) a->release(); a = o.a; + if (a) a->release(); + a = o.a; return *this; } -- cgit v1.2.3 From f8a6b3b9ab967c65708e9b72a2557f564d22a8ea Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Sat, 5 Mar 2016 14:40:27 +0100 Subject: Export some more classes. QQuickSprite is used in QtQuickParticles. Export unconditionally. QQuickScaleGrid is used in auto-tests. AUTOTEST_EXPORT it. Unbreaks UBSan build, which requires access to the classes' type_info. Change-Id: I65b538fe0a4255d1b5c4e2e1212001d356382cb4 Reviewed-by: Lars Knoll --- src/quick/items/qquickscalegrid_p_p.h | 2 +- src/quick/items/qquicksprite.cpp | 5 +++++ src/quick/items/qquicksprite_p.h | 4 +++- 3 files changed, 9 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/quick/items/qquickscalegrid_p_p.h b/src/quick/items/qquickscalegrid_p_p.h index 1d067f1a94..de8a5b66fb 100644 --- a/src/quick/items/qquickscalegrid_p_p.h +++ b/src/quick/items/qquickscalegrid_p_p.h @@ -55,7 +55,7 @@ QT_BEGIN_NAMESPACE -class QQuickScaleGrid : public QObject +class Q_AUTOTEST_EXPORT QQuickScaleGrid : public QObject { Q_OBJECT diff --git a/src/quick/items/qquicksprite.cpp b/src/quick/items/qquicksprite.cpp index e69e12d967..0538707a5d 100644 --- a/src/quick/items/qquicksprite.cpp +++ b/src/quick/items/qquicksprite.cpp @@ -218,6 +218,11 @@ QQuickSprite::QQuickSprite(QObject *parent) { } +/*! \internal */ +QQuickSprite::~QQuickSprite() +{ +} + int QQuickSprite::variedDuration() const //Deals with precedence when multiple durations are set { if (m_frameSync) diff --git a/src/quick/items/qquicksprite_p.h b/src/quick/items/qquicksprite_p.h index 43c5e44be3..555ba0f8d9 100644 --- a/src/quick/items/qquicksprite_p.h +++ b/src/quick/items/qquicksprite_p.h @@ -55,7 +55,8 @@ QT_BEGIN_NAMESPACE -class QQuickSprite : public QQuickStochasticState +// exported, since it's used in QtQuickParticles +class Q_QUICK_EXPORT QQuickSprite : public QQuickStochasticState { Q_OBJECT Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged) @@ -78,6 +79,7 @@ class QQuickSprite : public QQuickStochasticState public: explicit QQuickSprite(QObject *parent = 0); + ~QQuickSprite(); QUrl source() const { -- cgit v1.2.3 From c020bc671b30ea90f6bacd8bf6cd26ce5e808a6b Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Thu, 25 Feb 2016 10:58:58 +0100 Subject: V4 IR: Store the phi-node parameters directly in the class. Every time one of the paramets was accessed, the chain of loads was: phi->d->incoming->heapdata[i] Now it is: phi[i + offsetof(incoming)] This also removes at least one malloc (for the Data), and usually two (when the number of parameters is <= 4, which is most of the cases). Change-Id: I953e784647148266ae5a49a93a203d0d22cdcb63 Reviewed-by: Lars Knoll --- src/qml/compiler/qv4isel_moth.cpp | 8 +++--- src/qml/compiler/qv4jsir.cpp | 6 ++--- src/qml/compiler/qv4jsir_p.h | 14 +++-------- src/qml/compiler/qv4ssa.cpp | 52 +++++++++++++++++++-------------------- src/qml/jit/qv4regalloc.cpp | 6 ++--- 5 files changed, 39 insertions(+), 47 deletions(-) (limited to 'src') diff --git a/src/qml/compiler/qv4isel_moth.cpp b/src/qml/compiler/qv4isel_moth.cpp index 7d6d7e65bc..be10d50e9b 100644 --- a/src/qml/compiler/qv4isel_moth.cpp +++ b/src/qml/compiler/qv4isel_moth.cpp @@ -258,13 +258,13 @@ protected: for (IR::Stmt *succStmt : jump->target->statements()) { if (IR::Phi *phi = succStmt->asPhi()) { forceActivation(*phi->targetTemp); - for (int i = 0, ei = phi->d->incoming.size(); i != ei; ++i) { - IR::Expr *e = phi->d->incoming[i]; + for (int i = 0, ei = phi->incoming.size(); i != ei; ++i) { + IR::Expr *e = phi->incoming[i]; if (IR::Temp *t = e->asTemp()) { forceActivation(*t); } if (jump->target->in[i] == _currentBasicBlock) - moves.add(phi->d->incoming[i], phi->targetTemp); + moves.add(phi->incoming[i], phi->targetTemp); } } else { break; @@ -303,7 +303,7 @@ protected: #if !defined(QT_NO_DEBUG) Q_ASSERT(_stackSlotForTemp.contains(phi->targetTemp->index)); Q_ASSERT(_slotIsInUse[_stackSlotForTemp[phi->targetTemp->index]]); - foreach (IR::Expr *e, phi->d->incoming) { + foreach (IR::Expr *e, phi->incoming) { if (IR::Temp *t = e->asTemp()) Q_ASSERT(_stackSlotForTemp.contains(t->index)); } diff --git a/src/qml/compiler/qv4jsir.cpp b/src/qml/compiler/qv4jsir.cpp index 4c87b7557e..e383d1432b 100644 --- a/src/qml/compiler/qv4jsir.cpp +++ b/src/qml/compiler/qv4jsir.cpp @@ -1084,13 +1084,13 @@ void IRPrinter::visitPhi(Phi *s) s->targetTemp->accept(this); *out << " = phi "; - for (int i = 0, ei = s->d->incoming.size(); i < ei; ++i) { + for (int i = 0, ei = s->incoming.size(); i < ei; ++i) { if (i > 0) *out << ", "; if (currentBB) *out << 'L' << currentBB->in.at(i)->index() << ": "; - if (s->d->incoming[i]) - s->d->incoming[i]->accept(this); + if (s->incoming[i]) + s->incoming[i]->accept(this); } } diff --git a/src/qml/compiler/qv4jsir_p.h b/src/qml/compiler/qv4jsir_p.h index 974e8dfe0d..0189ff4a23 100644 --- a/src/qml/compiler/qv4jsir_p.h +++ b/src/qml/compiler/qv4jsir_p.h @@ -753,21 +753,15 @@ struct Ret: Stmt { struct Phi: Stmt { Temp *targetTemp; - struct Data { - QVector incoming; // used by Phi nodes - }; - - Data *d; + VarLengthArray incoming; - Phi(int id): Stmt(id), d(0) {} + Phi(int id): Stmt(id) {} virtual void accept(StmtVisitor *v) { v->visitPhi(this); } virtual Phi *asPhi() { return this; } - void destroyData() { - delete d; - d = 0; - } + void destroyData() + { incoming.~VarLengthArray(); } }; struct Q_QML_PRIVATE_EXPORT Module { diff --git a/src/qml/compiler/qv4ssa.cpp b/src/qml/compiler/qv4ssa.cpp index 704524ce19..1e55f6b1c7 100644 --- a/src/qml/compiler/qv4ssa.cpp +++ b/src/qml/compiler/qv4ssa.cpp @@ -1380,16 +1380,15 @@ public: void insertPhiNode(const Temp &a, BasicBlock *y, IR::Function *f) { Phi *phiNode = f->NewStmt(); - phiNode->d = new Phi::Data; phiNode->targetTemp = f->New(); phiNode->targetTemp->init(a.kind, a.index); y->prependStatement(phiNode); - phiNode->d->incoming.resize(y->in.size()); + phiNode->incoming.resize(y->in.size()); for (int i = 0, ei = y->in.size(); i < ei; ++i) { Temp *t = f->New(); t->init(a.kind, a.index); - phiNode->d->incoming[i] = t; + phiNode->incoming[i] = t; } } @@ -1590,7 +1589,7 @@ private: Q_ASSERT(j >= 0 && j < Y->in.size()); for (Stmt *s : Y->statements()) { if (Phi *phi = s->asPhi()) { - Temp *t = phi->d->incoming[j]->asTemp(); + Temp *t = phi->incoming[j]->asTemp(); unsigned newTmp = currentNumber(*t); // qDebug()<<"I: replacing phi use"<index; t->index = newTmp; @@ -2273,7 +2272,7 @@ protected: virtual void visitRet(Ret *s) { s->expr->accept(this); } virtual void visitPhi(Phi *s) { s->targetTemp->accept(this); - foreach (Expr *e, s->d->incoming) + foreach (Expr *e, s->incoming) e->accept(this); } }; @@ -2568,9 +2567,9 @@ protected: virtual void visitCJump(CJump *s) { _ty = run(s->cond); } virtual void visitRet(Ret *s) { _ty = run(s->expr); } virtual void visitPhi(Phi *s) { - _ty = run(s->d->incoming[0]); - for (int i = 1, ei = s->d->incoming.size(); i != ei; ++i) { - TypingResult ty = run(s->d->incoming[i]); + _ty = run(s->incoming[0]); + for (int i = 1, ei = s->incoming.size(); i != ei; ++i) { + TypingResult ty = run(s->incoming[i]); if (!ty.fullyTyped && _ty.fullyTyped) { // When one of the temps not fully typed, we already know that we cannot completely type this node. // So, pick the type we calculated upto this point, and wait until the unknown one will be typed. @@ -2889,7 +2888,7 @@ public: _defUses.addUse(*source, conversion.stmt); if (Phi *phi = conversion.stmt->asPhi()) { - int idx = phi->d->incoming.indexOf(t); + int idx = phi->incoming.indexOf(t); Q_ASSERT(idx != -1); bb->in[idx]->insertStatementBeforeTerminator(convCall); } else { @@ -3041,8 +3040,8 @@ protected: virtual void visitRet(Ret *s) { run(s->expr); } virtual void visitPhi(Phi *s) { Type ty = s->targetTemp->type; - for (int i = 0, ei = s->d->incoming.size(); i != ei; ++i) - run(s->d->incoming[i], ty); + for (int i = 0, ei = s->incoming.size(); i != ei; ++i) + run(s->incoming[i], ty); } }; @@ -3566,7 +3565,7 @@ static void cleanupBasicBlocks(IR::Function *function) outBB->in.remove(idx); for (Stmt *s : outBB->statements()) { if (Phi *phi = s->asPhi()) - phi->d->incoming.remove(idx); + phi->incoming.remove(idx); else break; } @@ -3581,9 +3580,9 @@ static void cleanupBasicBlocks(IR::Function *function) inline Const *isConstPhi(Phi *phi) { - if (Const *c = phi->d->incoming[0]->asConst()) { - for (int i = 1, ei = phi->d->incoming.size(); i != ei; ++i) { - if (Const *cc = phi->d->incoming[i]->asConst()) { + if (Const *c = phi->incoming[0]->asConst()) { + for (int i = 1, ei = phi->incoming.size(); i != ei; ++i) { + if (Const *cc = phi->incoming[i]->asConst()) { if (c->value != cc->value) return 0; if (!(c->type == cc->type || (c->type & NumberType && cc->type & NumberType))) @@ -3684,8 +3683,8 @@ protected: virtual void visitCJump(CJump *s) { check(s->cond); } virtual void visitRet(Ret *s) { check(s->expr); } virtual void visitPhi(Phi *s) { - for (int i = 0, ei = s->d->incoming.size(); i != ei; ++i) - check(s->d->incoming[i]); + for (int i = 0, ei = s->incoming.size(); i != ei; ++i) + check(s->incoming[i]); } private: @@ -3746,11 +3745,11 @@ void unlink(BasicBlock *from, BasicBlock *to, IR::Function *func, DefUses &defUs if (!outStmt) continue; if (Phi *phi = outStmt->asPhi()) { - if (Temp *t = phi->d->incoming[idx]->asTemp()) { + if (Temp *t = phi->incoming[idx]->asTemp()) { defUses.removeUse(phi, *t); W += defUses.defStmt(*t); } - phi->d->incoming.remove(idx); + phi->incoming.remove(idx); W += phi; } else { break; @@ -3987,9 +3986,9 @@ void optimizeSSA(StatementWorklist &W, DefUses &defUses, DominatorTree &df) } // copy propagation: - if (phi->d->incoming.size() == 1) { + if (phi->incoming.size() == 1) { Temp *t = phi->targetTemp; - Expr *e = phi->d->incoming.first(); + Expr *e = phi->incoming.first(); QVector newT2Uses; replaceUses(t, e, W, &newT2Uses); @@ -4427,7 +4426,7 @@ private: for (Stmt *s : successor->statements()) { if (Phi *phi = s->asPhi()) { - if (Temp *t = phi->d->incoming.at(bbIndex)->asTemp()) + if (Temp *t = phi->incoming.at(bbIndex)->asTemp()) live.insert(*t); } else { break; @@ -4644,9 +4643,8 @@ protected: clonedStmt = phi; phi->targetTemp = clone(stmt->targetTemp); - phi->d = new Phi::Data; - foreach (Expr *in, stmt->d->incoming) - phi->d->incoming.append(clone(in)); + foreach (Expr *in, stmt->incoming) + phi->incoming.append(clone(in)); block->appendStatement(phi); } @@ -4902,7 +4900,7 @@ static void verifyNoPointerSharing(IR::Function *function) { check(s); s->targetTemp->accept(this); - foreach (Expr *e, s->d->incoming) + foreach (Expr *e, s->incoming) e->accept(this); } @@ -5341,7 +5339,7 @@ void Optimizer::convertOutOfSSA() { Q_ASSERT(inIdx >= 0); for (Stmt *s : successor->statements()) { if (Phi *phi = s->asPhi()) { - moves.add(clone(phi->d->incoming[inIdx], function), + moves.add(clone(phi->incoming[inIdx], function), clone(phi->targetTemp, function)->asTemp()); } else { break; diff --git a/src/qml/jit/qv4regalloc.cpp b/src/qml/jit/qv4regalloc.cpp index 6741529245..131e0a5b0a 100644 --- a/src/qml/jit/qv4regalloc.cpp +++ b/src/qml/jit/qv4regalloc.cpp @@ -702,8 +702,8 @@ protected: // IRDecoder virtual void visitPhi(IR::Phi *s) { addDef(s->targetTemp, true); - for (int i = 0, ei = s->d->incoming.size(); i < ei; ++i) { - Expr *e = s->d->incoming.at(i); + for (int i = 0, ei = s->incoming.size(); i < ei; ++i) { + Expr *e = s->incoming.at(i); if (Temp *t = e->asTemp()) { // The actual use of an incoming value in a phi node is right before the terminator // of the other side of the incoming edge. @@ -1024,7 +1024,7 @@ private: if (it->start() == successorStart) { if (Phi *phi = findDefPhi(it->temp(), successor)) { isPhiTarget = true; - Expr *opd = phi->d->incoming[successor->in.indexOf(predecessor)]; + Expr *opd = phi->incoming[successor->in.indexOf(predecessor)]; if (opd->asConst()) { moveFrom = opd; } else { -- cgit v1.2.3 From 30ab43463c4b70f0ca9643d163e4e46c62133415 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Thu, 25 Feb 2016 11:15:17 +0100 Subject: V4: tweak Phi node data destruction. Phi nodes can only occur at the start of a basic block. If there are any, they need to be subsequent to eachother, and the first phi node should be the first statement in the basic-block. A number of loops rely on this behavior, so they don't need to walk through the whole list of instructions in a basic-block (e.g. the calls to destroyData in BasicBlock::~BasicBlock). Change-Id: I57763bc6abae271337b0b169cccd26e10ecd9b2d Reviewed-by: Lars Knoll --- src/qml/compiler/qv4jsir.cpp | 33 ++++++++++++++++++--------------- src/qml/compiler/qv4jsir_p.h | 4 ++++ 2 files changed, 22 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/qml/compiler/qv4jsir.cpp b/src/qml/compiler/qv4jsir.cpp index e383d1432b..a9f8df7748 100644 --- a/src/qml/compiler/qv4jsir.cpp +++ b/src/qml/compiler/qv4jsir.cpp @@ -514,9 +514,11 @@ void Function::setStatementCount(int cnt) BasicBlock::~BasicBlock() { for (Stmt *s : qAsConst(_statements)) { - Phi *p = s->asPhi(); - if (p) + if (Phi *p = s->asPhi()) { p->destroyData(); + } else { + break; + } } } @@ -769,14 +771,15 @@ void BasicBlock::setStatements(const QVector &newStatements) { Q_ASSERT(!isRemoved()); Q_ASSERT(newStatements.size() >= _statements.size()); - // FIXME: this gets quite inefficient for large basic-blocks, so this function/case should be re-worked. for (Stmt *s : qAsConst(_statements)) { - Phi *p = s->asPhi(); - if (!p) - continue; - - if (!newStatements.contains(p)) - p->destroyData(); + if (Phi *p = s->asPhi()) { + if (!newStatements.contains(p)) { + // phi-node was not copied over, so: + p->destroyData(); + } + } else { + break; + } } _statements = newStatements; } @@ -825,27 +828,27 @@ void BasicBlock::insertStatementBeforeTerminator(Stmt *stmt) void BasicBlock::replaceStatement(int index, Stmt *newStmt) { Q_ASSERT(!isRemoved()); - Phi *p = _statements[index]->asPhi(); - if (p) + if (Phi *p = _statements[index]->asPhi()) { p->destroyData(); + } _statements[index] = newStmt; } void BasicBlock::removeStatement(Stmt *stmt) { Q_ASSERT(!isRemoved()); - Phi *p = stmt->asPhi(); - if (p) + if (Phi *p = stmt->asPhi()) { p->destroyData(); + } _statements.remove(_statements.indexOf(stmt)); } void BasicBlock::removeStatement(int idx) { Q_ASSERT(!isRemoved()); - Phi *p = _statements[idx]->asPhi(); - if (p) + if (Phi *p = _statements[idx]->asPhi()) { p->destroyData(); + } _statements.remove(idx); } diff --git a/src/qml/compiler/qv4jsir_p.h b/src/qml/compiler/qv4jsir_p.h index 0189ff4a23..baa338ed52 100644 --- a/src/qml/compiler/qv4jsir_p.h +++ b/src/qml/compiler/qv4jsir_p.h @@ -751,6 +751,10 @@ struct Ret: Stmt { virtual Ret *asRet() { return this; } }; +// Phi nodes can only occur at the start of a basic block. If there are any, they need to be +// subsequent to eachother, and the first phi node should be the first statement in the basic-block. +// A number of loops rely on this behavior, so they don't need to walk through the whole list +// of instructions in a basic-block (e.g. the calls to destroyData in BasicBlock::~BasicBlock). struct Phi: Stmt { Temp *targetTemp; VarLengthArray incoming; -- cgit v1.2.3 From 443ba99b1ef825e198fe1999c34ee44547135797 Mon Sep 17 00:00:00 2001 From: Joni Poikelin Date: Thu, 18 Feb 2016 13:18:33 +0200 Subject: Prevent cutting in non-Normal echoMode of TextInput Cutting the text in Password mode led to the text being deleted. Cut and copy operations should not be allowed when echoMode is set to a mode other than Normal. Task-number: QTBUG-51231 Change-Id: If75cdaedac7478ecc1a5126ad4a5ecbf32acd1ab Reviewed-by: Robin Burchell --- src/quick/items/qquicktextinput.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/quick/items/qquicktextinput.cpp b/src/quick/items/qquicktextinput.cpp index ba7142856b..ffc94dfd46 100644 --- a/src/quick/items/qquicktextinput.cpp +++ b/src/quick/items/qquicktextinput.cpp @@ -1886,11 +1886,15 @@ bool QQuickTextInput::isRightToLeft(int start, int end) \qmlmethod QtQuick::TextInput::cut() Moves the currently selected text to the system clipboard. + + \note If the echo mode is set to a mode other than Normal then cut + will not work. This is to prevent using cut as a method of bypassing + password features of the line control. */ void QQuickTextInput::cut() { Q_D(QQuickTextInput); - if (!d->m_readOnly) { + if (!d->m_readOnly && d->m_echoMode == QQuickTextInput::Normal) { d->copy(); d->del(); } @@ -1900,6 +1904,10 @@ void QQuickTextInput::cut() \qmlmethod QtQuick::TextInput::copy() Copies the currently selected text to the system clipboard. + + \note If the echo mode is set to a mode other than Normal then copy + will not work. This is to prevent using copy as a method of bypassing + password features of the line control. */ void QQuickTextInput::copy() { @@ -4251,10 +4259,7 @@ void QQuickTextInputPrivate::processKeyEvent(QKeyEvent* event) } } else if (event == QKeySequence::Cut) { - if (!m_readOnly) { - copy(); - del(); - } + q->cut(); } else if (event == QKeySequence::DeleteEndOfLine) { if (!m_readOnly) -- cgit v1.2.3 From 669c554516736a6735b7286039c56cc0e8d56e05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Arve=20S=C3=A6ther?= Date: Fri, 26 Feb 2016 11:13:36 +0100 Subject: Copy the inverted property when the QWheelEvent is cloned Task-number: QTBUG-35972 Change-Id: I51efc0a390053f1da41352e4242cc4339c15a372 Reviewed-by: Robin Burchell Reviewed-by: Shawn Rutledge --- src/quick/items/qquickwindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index 44ff9aef81..bb3f5138ad 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -1816,7 +1816,7 @@ bool QQuickWindowPrivate::deliverWheelEvent(QQuickItem *item, QWheelEvent *event if (item->contains(p)) { QWheelEvent wheel(p, p, event->pixelDelta(), event->angleDelta(), event->delta(), - event->orientation(), event->buttons(), event->modifiers(), event->phase(), event->source()); + event->orientation(), event->buttons(), event->modifiers(), event->phase(), event->source(), event->inverted()); wheel.accept(); q->sendEvent(item, &wheel); if (wheel.isAccepted()) { -- cgit v1.2.3 From 922e9d6b0c7ae1acdae4986e8000ad9a693b7469 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Thu, 3 Mar 2016 10:23:02 +0100 Subject: V4: Move BitVector to the util header, so it can be re-used. Change-Id: I994ff9277fbbcebf2e45b3146859eb75264b83f4 Reviewed-by: Lars Knoll --- src/qml/compiler/qv4ssa.cpp | 115 ----------------------------------------- src/qml/jsruntime/qv4util_p.h | 117 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 117 insertions(+), 115 deletions(-) (limited to 'src') diff --git a/src/qml/compiler/qv4ssa.cpp b/src/qml/compiler/qv4ssa.cpp index 1e55f6b1c7..6c51044b1e 100644 --- a/src/qml/compiler/qv4ssa.cpp +++ b/src/qml/compiler/qv4ssa.cpp @@ -56,7 +56,6 @@ #include #include #include -#include QT_USE_NAMESPACE @@ -87,120 +86,6 @@ static void showMeTheCode(IR::Function *function, const char *marker) } } -#if !defined(BROKEN_STD_VECTOR_BOOL_OR_BROKEN_STD_FIND) -// Sanity: -class BitVector -{ - std::vector bits; - -public: - BitVector(int size = 0, bool value = false) - : bits(size, value) - {} - - void reserve(int size) - { bits.reserve(size); } - - int size() const - { - Q_ASSERT(bits.size() < INT_MAX); - return static_cast(bits.size()); - } - - void resize(int newSize) - { bits.resize(newSize); } - - void assign(int newSize, bool value) - { bits.assign(newSize, value); } - - int findNext(int start, bool value, bool wrapAround) const - { - // The ++operator of std::vector::iterator in libc++ has a bug when using it on an - // iterator pointing to the last element. It will not be set to ::end(), but beyond - // that. (It will be set to the first multiple of the native word size that is bigger - // than size().) - // - // See http://llvm.org/bugs/show_bug.cgi?id=19663 - // - // The work-around is to calculate the distance, and compare it to the size() to see if it's - // beyond the end, or take the minimum of the distance and the size. - - size_t pos = std::distance(bits.begin(), - std::find(bits.begin() + start, bits.end(), value)); - if (wrapAround && pos >= static_cast(size())) - pos = std::distance(bits.begin(), - std::find(bits.begin(), bits.begin() + start, value)); - - pos = qMin(pos, static_cast(size())); - - Q_ASSERT(pos <= static_cast(size())); - Q_ASSERT(pos < INT_MAX); - - return static_cast(pos); - } - - bool at(int idx) const - { return bits.at(idx); } - - void setBit(int idx) - { bits[idx] = true; } - - void clearBit(int idx) - { bits[idx] = false; } -}; -#else // Insanity: -class BitVector -{ - QBitArray bits; - -public: - BitVector(int size = 0, bool value = false) - : bits(size, value) - {} - - void reserve(int size) - { Q_UNUSED(size); } - - int size() const - { return bits.size(); } - - void resize(int newSize) - { bits.resize(newSize); } - - void assign(int newSize, bool value) - { - bits.resize(newSize); - bits.fill(value); - } - - int findNext(int start, bool value, bool wrapAround) const - { - for (int i = start, ei = size(); i < ei; ++i) { - if (at(i) == value) - return i; - } - - if (wrapAround) { - for (int i = 0, ei = start; i < ei; ++i) { - if (at(i) == value) - return i; - } - } - - return size(); - } - - bool at(int idx) const - { return bits.at(idx); } - - void setBit(int idx) - { bits[idx] = true; } - - void clearBit(int idx) - { bits[idx] = false; } -}; -#endif - class ProcessedBlocks { BitVector processed; diff --git a/src/qml/jsruntime/qv4util_p.h b/src/qml/jsruntime/qv4util_p.h index 3ffcc8a846..132abd211e 100644 --- a/src/qml/jsruntime/qv4util_p.h +++ b/src/qml/jsruntime/qv4util_p.h @@ -51,6 +51,9 @@ // #include "qv4global_p.h" +#include +#include +#include QT_BEGIN_NAMESPACE @@ -76,6 +79,120 @@ private: TemporaryAssignment operator=(const TemporaryAssignment&); }; +#if !defined(BROKEN_STD_VECTOR_BOOL_OR_BROKEN_STD_FIND) +// Sanity: +class BitVector +{ + std::vector bits; + +public: + BitVector(int size = 0, bool value = false) + : bits(size, value) + {} + + void reserve(int size) + { bits.reserve(size); } + + int size() const + { + Q_ASSERT(bits.size() < INT_MAX); + return static_cast(bits.size()); + } + + void resize(int newSize) + { bits.resize(newSize); } + + void assign(int newSize, bool value) + { bits.assign(newSize, value); } + + int findNext(int start, bool value, bool wrapAround) const + { + // The ++operator of std::vector::iterator in libc++ has a bug when using it on an + // iterator pointing to the last element. It will not be set to ::end(), but beyond + // that. (It will be set to the first multiple of the native word size that is bigger + // than size().) + // + // See http://llvm.org/bugs/show_bug.cgi?id=19663 + // + // The work-around is to calculate the distance, and compare it to the size() to see if it's + // beyond the end, or take the minimum of the distance and the size. + + size_t pos = std::distance(bits.begin(), + std::find(bits.begin() + start, bits.end(), value)); + if (wrapAround && pos >= static_cast(size())) + pos = std::distance(bits.begin(), + std::find(bits.begin(), bits.begin() + start, value)); + + pos = qMin(pos, static_cast(size())); + + Q_ASSERT(pos <= static_cast(size())); + Q_ASSERT(pos < INT_MAX); + + return static_cast(pos); + } + + bool at(int idx) const + { return bits.at(idx); } + + void setBit(int idx) + { bits[idx] = true; } + + void clearBit(int idx) + { bits[idx] = false; } +}; +#else // Insanity: +class BitVector +{ + QBitArray bits; + +public: + BitVector(int size = 0, bool value = false) + : bits(size, value) + {} + + void reserve(int size) + { Q_UNUSED(size); } + + int size() const + { return bits.size(); } + + void resize(int newSize) + { bits.resize(newSize); } + + void assign(int newSize, bool value) + { + bits.resize(newSize); + bits.fill(value); + } + + int findNext(int start, bool value, bool wrapAround) const + { + for (int i = start, ei = size(); i < ei; ++i) { + if (at(i) == value) + return i; + } + + if (wrapAround) { + for (int i = 0, ei = start; i < ei; ++i) { + if (at(i) == value) + return i; + } + } + + return size(); + } + + bool at(int idx) const + { return bits.at(idx); } + + void setBit(int idx) + { bits[idx] = true; } + + void clearBit(int idx) + { bits[idx] = false; } +}; +#endif + } QT_END_NAMESPACE -- cgit v1.2.3 From 350a74ec69b535df07ad7ca45415090749c75293 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Tue, 8 Mar 2016 10:13:15 +0100 Subject: Particles: Shrink QQuickParticleData by 2 pointers. Samegame creates about 23,000 particles, so this reduces the memory by ~180kb on 32bit, so ~360kb on 64bit. Change-Id: I0581524ab232b474c5d43abeabd7ebf6174e740f Reviewed-by: Lars Knoll --- src/particles/qquickage.cpp | 22 +++--- src/particles/qquickcustomaffector.cpp | 22 +++--- src/particles/qquickfriction.cpp | 8 +-- src/particles/qquickgravity.cpp | 4 +- src/particles/qquickimageparticle.cpp | 10 +-- src/particles/qquickitemparticle.cpp | 10 +-- src/particles/qquickparticleaffector.cpp | 32 ++++----- src/particles/qquickparticleemitter.cpp | 5 +- src/particles/qquickparticlepainter.cpp | 6 +- src/particles/qquickparticlesystem.cpp | 114 +++++++++++++++---------------- src/particles/qquickparticlesystem_p.h | 50 +++++++------- src/particles/qquickpointattractor.cpp | 16 ++--- src/particles/qquickspritegoal.cpp | 2 +- src/particles/qquicktrailemitter.cpp | 19 +++--- src/particles/qquickturbulence.cpp | 6 +- src/particles/qquickv4particledata.cpp | 16 +++-- src/particles/qquickv4particledata_p.h | 3 +- src/particles/qquickwander.cpp | 24 +++---- 18 files changed, 183 insertions(+), 186 deletions(-) (limited to 'src') diff --git a/src/particles/qquickage.cpp b/src/particles/qquickage.cpp index 9867e7e0ed..e1eb714623 100644 --- a/src/particles/qquickage.cpp +++ b/src/particles/qquickage.cpp @@ -88,23 +88,23 @@ QQuickAgeAffector::QQuickAgeAffector(QQuickItem *parent) : bool QQuickAgeAffector::affectParticle(QQuickParticleData *d, qreal dt) { Q_UNUSED(dt); - if (d->stillAlive()){ + if (d->stillAlive(m_system)){ qreal curT = (qreal)m_system->timeInt/1000.0; qreal ttl = (qreal)m_lifeLeft/1000.0; if (!m_advancePosition && ttl > 0){ - qreal x = d->curX(); - qreal vx = d->curVX(); + qreal x = d->curX(m_system); + qreal vx = d->curVX(m_system); qreal ax = d->curAX(); - qreal y = d->curY(); - qreal vy = d->curVY(); + qreal y = d->curY(m_system); + qreal vy = d->curVY(m_system); qreal ay = d->curAY(); d->t = curT - (d->lifeSpan - ttl); - d->setInstantaneousX(x); - d->setInstantaneousVX(vx); - d->setInstantaneousAX(ax); - d->setInstantaneousY(y); - d->setInstantaneousVY(vy); - d->setInstantaneousAY(ay); + d->setInstantaneousX(x, m_system); + d->setInstantaneousVX(vx, m_system); + d->setInstantaneousAX(ax, m_system); + d->setInstantaneousY(y, m_system); + d->setInstantaneousVY(vy, m_system); + d->setInstantaneousAY(ay, m_system); } else { d->t = curT - (d->lifeSpan - ttl); } diff --git a/src/particles/qquickcustomaffector.cpp b/src/particles/qquickcustomaffector.cpp index 6f50c17287..b95810bb62 100644 --- a/src/particles/qquickcustomaffector.cpp +++ b/src/particles/qquickcustomaffector.cpp @@ -138,8 +138,8 @@ void QQuickCustomAffector::affectSystem(qreal dt) if (justAffected) { foreach (QQuickParticleData* d, toAffect) {//Not postAffect to avoid saying the particle changed if (m_onceOff) - m_onceOffed << qMakePair(d->group, d->index); - emit affected(d->curX(), d->curY()); + m_onceOffed << qMakePair(d->groupId, d->index); + emit affected(d->curX(m_system), d->curY(m_system)); } return; } @@ -154,7 +154,7 @@ void QQuickCustomAffector::affectSystem(qreal dt) QV4::ScopedArrayObject array(scope, v4->newArrayObject(toAffect.size())); QV4::ScopedValue v(scope); for (int i=0; iputIndexed(i, (v = toAffect[i]->v4Value())); + array->putIndexed(i, (v = toAffect[i]->v4Value(m_system))); if (dt >= simulationCutoff || dt <= simulationDelta) { affectProperties(toAffect, dt); @@ -184,7 +184,7 @@ bool QQuickCustomAffector::affectParticle(QQuickParticleData *d, qreal dt) { //This does the property based affecting, called by superclass if signal isn't hooked up. bool changed = false; - QPointF curPos(d->curX(), d->curY()); + QPointF curPos(d->curX(m_system), d->curY(m_system)); if (m_acceleration != &m_nullVector){ QPointF pos = m_acceleration->sample(curPos); @@ -194,22 +194,22 @@ bool QQuickCustomAffector::affectParticle(QQuickParticleData *d, qreal dt) pos += curAcc; } if (pos != curAcc) { - d->setInstantaneousAX(pos.x()); - d->setInstantaneousAY(pos.y()); + d->setInstantaneousAX(pos.x(), m_system); + d->setInstantaneousAY(pos.y(), m_system); changed = true; } } if (m_velocity != &m_nullVector){ QPointF pos = m_velocity->sample(curPos); - QPointF curVel = QPointF(d->curVX(), d->curVY()); + QPointF curVel = QPointF(d->curVX(m_system), d->curVY(m_system)); if (m_relative) { pos *= dt; pos += curVel; } if (pos != curVel) { - d->setInstantaneousVX(pos.x()); - d->setInstantaneousVY(pos.y()); + d->setInstantaneousVX(pos.x(), m_system); + d->setInstantaneousVY(pos.y(), m_system); changed = true; } } @@ -221,8 +221,8 @@ bool QQuickCustomAffector::affectParticle(QQuickParticleData *d, qreal dt) pos += curPos; } if (pos != curPos) { - d->setInstantaneousX(pos.x()); - d->setInstantaneousY(pos.y()); + d->setInstantaneousX(pos.x(), m_system); + d->setInstantaneousY(pos.y(), m_system); changed = true; } } diff --git a/src/particles/qquickfriction.cpp b/src/particles/qquickfriction.cpp index f234bc27ad..401f4cd8c9 100644 --- a/src/particles/qquickfriction.cpp +++ b/src/particles/qquickfriction.cpp @@ -80,8 +80,8 @@ bool QQuickFrictionAffector::affectParticle(QQuickParticleData *d, qreal dt) { if (!m_factor) return false; - qreal curVX = d->curVX(); - qreal curVY = d->curVY(); + qreal curVX = d->curVX(m_system); + qreal curVY = d->curVY(m_system); if (!curVX && !curVY) return false; qreal newVX = curVX + (curVX * m_factor * -1 * dt); @@ -106,8 +106,8 @@ bool QQuickFrictionAffector::affectParticle(QQuickParticleData *d, qreal dt) } } - d->setInstantaneousVX(newVX); - d->setInstantaneousVY(newVY); + d->setInstantaneousVX(newVX, m_system); + d->setInstantaneousVY(newVY, m_system); return true; } QT_END_NAMESPACE diff --git a/src/particles/qquickgravity.cpp b/src/particles/qquickgravity.cpp index 54a03ac4bd..90f305f336 100644 --- a/src/particles/qquickgravity.cpp +++ b/src/particles/qquickgravity.cpp @@ -90,8 +90,8 @@ bool QQuickGravityAffector::affectParticle(QQuickParticleData *d, qreal dt) m_dy = m_magnitude * std::sin(m_angle * CONV); } - d->setInstantaneousVX(d->curVX() + m_dx*dt); - d->setInstantaneousVY(d->curVY() + m_dy*dt); + d->setInstantaneousVX(d->curVX(m_system) + m_dx*dt, m_system); + d->setInstantaneousVY(d->curVY(m_system) + m_dy*dt, m_system); return true; } QT_END_NAMESPACE diff --git a/src/particles/qquickimageparticle.cpp b/src/particles/qquickimageparticle.cpp index 5f2d1db663..07cbee1383 100644 --- a/src/particles/qquickimageparticle.cpp +++ b/src/particles/qquickimageparticle.cpp @@ -1168,21 +1168,21 @@ QQuickParticleData* QQuickImageParticle::getShadowDatum(QQuickParticleData* datu //Will return datum if the datum is a sentinel or uninitialized, to centralize that one check if (datum->systemIndex == -1) return datum; - QQuickParticleGroupData* gd = m_system->groupData[datum->group]; - if (!m_shadowData.contains(datum->group)) { + QQuickParticleGroupData* gd = m_system->groupData[datum->groupId]; + if (!m_shadowData.contains(datum->groupId)) { QVector data; const int gdSize = gd->size(); data.reserve(gdSize); for (int i = 0; i < gdSize; i++) { - QQuickParticleData* datum = new QQuickParticleData(m_system); + QQuickParticleData* datum = new QQuickParticleData; *datum = *(gd->data[i]); data << datum; } - m_shadowData.insert(datum->group, data); + m_shadowData.insert(datum->groupId, data); } //### If dynamic resize is added, remember to potentially resize the shadow data on out-of-bounds access request - return m_shadowData[datum->group][datum->index]; + return m_shadowData[datum->groupId][datum->index]; } bool QQuickImageParticle::loadingSomething() diff --git a/src/particles/qquickitemparticle.cpp b/src/particles/qquickitemparticle.cpp index ba6c6f915d..15cf19181e 100644 --- a/src/particles/qquickitemparticle.cpp +++ b/src/particles/qquickitemparticle.cpp @@ -206,8 +206,8 @@ void QQuickItemParticle::tick(int time) m_managed << d->delegate; } if (d && d->delegate){//###Data can be zero if creating an item leads to a reset - this screws things up. - d->delegate->setX(d->curX() - d->delegate->width()/2);//TODO: adjust for system? - d->delegate->setY(d->curY() - d->delegate->height()/2); + d->delegate->setX(d->curX(m_system) - d->delegate->width() / 2); //TODO: adjust for system? + d->delegate->setY(d->curY(m_system) - d->delegate->height() / 2); QQuickItemParticleAttached* mpa = qobject_cast(qmlAttachedPropertiesObject(d->delegate)); if (mpa){ mpa->m_mp = this; @@ -251,7 +251,7 @@ QSGNode* QQuickItemParticle::updatePaintNode(QSGNode* n, UpdatePaintNodeData* d) //### Constant resetting might lead to m_loadables never being populated when tick() occurs for (auto groupId : groupIds()) { for (QQuickParticleData* d : qAsConst(m_system->groupData[groupId]->data)) { - if (!d->delegate && d->t != -1 && d->stillAlive()) { + if (!d->delegate && d->t != -1 && d->stillAlive(m_system)) { m_loadables << d; } } @@ -301,8 +301,8 @@ void QQuickItemParticle::prepareNextFrame() item->setOpacity(o); } } - item->setX(data->curX() - item->width()/2 - m_systemOffset.x()); - item->setY(data->curY() - item->height()/2 - m_systemOffset.y()); + item->setX(data->curX(m_system) - item->width() / 2 - m_systemOffset.x()); + item->setY(data->curY(m_system) - item->height() / 2 - m_systemOffset.y()); } } } diff --git a/src/particles/qquickparticleaffector.cpp b/src/particles/qquickparticleaffector.cpp index 1878908a5d..6ed0d9e14a 100644 --- a/src/particles/qquickparticleaffector.cpp +++ b/src/particles/qquickparticleaffector.cpp @@ -162,13 +162,13 @@ bool QQuickParticleAffector::shouldAffect(QQuickParticleData* d) { if (!d) return false; - if (activeGroup(d->group)){ - if ((m_onceOff && m_onceOffed.contains(qMakePair(d->group, d->index))) - || !d->stillAlive()) + if (activeGroup(d->groupId)){ + if ((m_onceOff && m_onceOffed.contains(qMakePair(d->groupId, d->index))) + || !d->stillAlive(m_system)) return false; //Need to have previous location for affected anyways if (width() == 0 || height() == 0 - || m_shape->contains(QRectF(m_offset.x(), m_offset.y(), width(), height()), QPointF(d->curX(), d->curY()))){ + || m_shape->contains(QRectF(m_offset.x(), m_offset.y(), width(), height()), QPointF(d->curX(m_system), d->curY(m_system)))){ if (m_whenCollidingWith.isEmpty() || isColliding(d)){ return true; } @@ -182,9 +182,9 @@ void QQuickParticleAffector::postAffect(QQuickParticleData* d) { m_system->needsReset << d; if (m_onceOff) - m_onceOffed << qMakePair(d->group, d->index); + m_onceOffed << qMakePair(d->groupId, d->index); if (isAffectedConnected()) - emit affected(d->curX(), d->curY()); + emit affected(d->curX(m_system), d->curY(m_system)); } const qreal QQuickParticleAffector::simulationDelta = 0.020; @@ -210,7 +210,7 @@ void QQuickParticleAffector::affectSystem(qreal dt) m_system->timeInt -= myDt * 1000.0; while (myDt > simulationDelta) { m_system->timeInt += simulationDelta * 1000.0; - if (d->alive())//Only affect during the parts it was alive for + if (d->alive(m_system))//Only affect during the parts it was alive for affected = affectParticle(d, simulationDelta) || affected; myDt -= simulationDelta; } @@ -234,8 +234,8 @@ bool QQuickParticleAffector::affectParticle(QQuickParticleData *, qreal ) void QQuickParticleAffector::reset(QQuickParticleData* pd) {//TODO: This, among other ones, should be restructured so they don't all need to remember to call the superclass if (m_onceOff) - if (activeGroup(pd->group)) - m_onceOffed.remove(qMakePair(pd->group, pd->index)); + if (activeGroup(pd->groupId)) + m_onceOffed.remove(qMakePair(pd->groupId, pd->index)); } void QQuickParticleAffector::updateOffsets() @@ -246,16 +246,16 @@ void QQuickParticleAffector::updateOffsets() bool QQuickParticleAffector::isColliding(QQuickParticleData *d) { - qreal myCurX = d->curX(); - qreal myCurY = d->curY(); - qreal myCurSize = d->curSize()/2; + qreal myCurX = d->curX(m_system); + qreal myCurY = d->curY(m_system); + qreal myCurSize = d->curSize(m_system) / 2; foreach (const QString &group, m_whenCollidingWith){ foreach (QQuickParticleData* other, m_system->groupData[m_system->groupIds[group]]->data){ - if (!other->stillAlive()) + if (!other->stillAlive(m_system)) continue; - qreal otherCurX = other->curX(); - qreal otherCurY = other->curY(); - qreal otherCurSize = other->curSize()/2; + qreal otherCurX = other->curX(m_system); + qreal otherCurY = other->curY(m_system); + qreal otherCurSize = other->curSize(m_system) / 2; if ((myCurX + myCurSize > otherCurX - otherCurSize && myCurX - myCurSize < otherCurX + otherCurSize) && (myCurY + myCurSize > otherCurY - otherCurSize diff --git a/src/particles/qquickparticleemitter.cpp b/src/particles/qquickparticleemitter.cpp index 7cce4d481a..c72cbc01e0 100644 --- a/src/particles/qquickparticleemitter.cpp +++ b/src/particles/qquickparticleemitter.cpp @@ -407,7 +407,6 @@ void QQuickParticleEmitter::emitWindow(int timeStamp) //int pos = m_last_particle % m_particle_count; QQuickParticleData* datum = m_system->newDatum(m_system->groupIds[m_group], !m_overwrite); if (datum){//actually emit(otherwise we've been asked to skip this one) - datum->e = this;//###useful? qreal t = 1 - (pt - opt) / dt; qreal vx = - 2 * ax * (1 - t) @@ -480,7 +479,7 @@ void QQuickParticleEmitter::emitWindow(int timeStamp) } foreach (QQuickParticleData* d, toEmit) - m_system->emitParticle(d); + m_system->emitParticle(d, this); if (isEmitConnected()) { QQmlEngine *qmlEngine = ::qmlEngine(this); @@ -492,7 +491,7 @@ void QQuickParticleEmitter::emitWindow(int timeStamp) QV4::ScopedArrayObject array(scope, v4->newArrayObject(toEmit.size())); QV4::ScopedValue v(scope); for (int i=0; iputIndexed(i, (v = toEmit[i]->v4Value())); + array->putIndexed(i, (v = toEmit[i]->v4Value(m_system))); emitParticles(QQmlV4Handle(array));//A chance for arbitrary JS changes } diff --git a/src/particles/qquickparticlepainter.cpp b/src/particles/qquickparticlepainter.cpp index 556d137fd4..d6303eb219 100644 --- a/src/particles/qquickparticlepainter.cpp +++ b/src/particles/qquickparticlepainter.cpp @@ -139,17 +139,17 @@ void QQuickParticlePainter::setGroups(const QStringList &arg) void QQuickParticlePainter::load(QQuickParticleData* d) { - initialize(d->group, d->index); + initialize(d->groupId, d->index); if (m_pleaseReset) return; - m_pendingCommits << qMakePair(d->group, d->index); + m_pendingCommits << qMakePair(d->groupId, d->index); } void QQuickParticlePainter::reload(QQuickParticleData* d) { if (m_pleaseReset) return; - m_pendingCommits << qMakePair(d->group, d->index); + m_pendingCommits << qMakePair(d->groupId, d->index); } void QQuickParticlePainter::reset() diff --git a/src/particles/qquickparticlesystem.cpp b/src/particles/qquickparticlesystem.cpp index 8ccdec4792..e9bd073133 100644 --- a/src/particles/qquickparticlesystem.cpp +++ b/src/particles/qquickparticlesystem.cpp @@ -340,8 +340,8 @@ void QQuickParticleGroupData::setSize(int newSize) Q_ASSERT(newSize > m_size);//XXX allow shrinking data.resize(newSize); for (int i=m_size; igroup = index; + data[i] = new QQuickParticleData; + data[i]->groupId = index; data[i]->index = i; reusableIndexes << i; } @@ -358,7 +358,7 @@ void QQuickParticleGroupData::initList() void QQuickParticleGroupData::kill(QQuickParticleData* d) { - Q_ASSERT(d->group == index); + Q_ASSERT(d->groupId == index); d->lifeSpan = 0;//Kill off foreach (QQuickParticlePainter* p, painters) p->reload(d); @@ -372,7 +372,7 @@ QQuickParticleData* QQuickParticleGroupData::newDatum(bool respectsLimits) while (!reusableIndexes.empty()) { int idx = *(reusableIndexes.begin()); reusableIndexes.remove(idx); - if (data[idx]->stillAlive()) {// ### This means resurrection of 'dead' particles. Is that allowed? + if (data[idx]->stillAlive(m_system)) {// ### This means resurrection of 'dead' particles. Is that allowed? prepareRecycler(data[idx]); continue; } @@ -391,7 +391,7 @@ bool QQuickParticleGroupData::recycle() { while (dataHeap.top() <= m_system->timeInt) { foreach (QQuickParticleData* datum, dataHeap.pop()) { - if (!datum->stillAlive()) { + if (!datum->stillAlive(m_system)) { reusableIndexes << datum->index; } else { prepareRecycler(datum); //ttl has been altered mid-way, put it back @@ -409,17 +409,15 @@ void QQuickParticleGroupData::prepareRecycler(QQuickParticleData* d) dataHeap.insert(d); } else { while ((roundedTime(d->t) + 2*m_system->maxLife/3) <= m_system->timeInt) - d->extendLife(m_system->maxLife/3000.0); + d->extendLife(m_system->maxLife / 3000.0, m_system); dataHeap.insertTimed(d, roundedTime(d->t) + 2*m_system->maxLife/3); } } -QQuickParticleData::QQuickParticleData(QQuickParticleSystem* sys) - : e(0) - , system(sys) - , index(0) +QQuickParticleData::QQuickParticleData() + : index(0) , systemIndex(-1) - , group(0) + , groupId(0) , colorOwner(0) , rotationOwner(0) , deformationOwner(0) @@ -475,9 +473,7 @@ QQuickParticleData &QQuickParticleData::operator=(const QQuickParticleData &othe { clone(other); - group = other.group; - e = other.e; - system = other.system; + groupId = other.groupId; index = other.index; systemIndex = other.systemIndex; // Lazily initialized @@ -527,16 +523,16 @@ void QQuickParticleData::clone(const QQuickParticleData& other) animationOwner = other.animationOwner; } -QQmlV4Handle QQuickParticleData::v4Value() +QQmlV4Handle QQuickParticleData::v4Value(QQuickParticleSystem* particleSystem) { if (!v8Datum) - v8Datum = new QQuickV4ParticleData(QQmlEnginePrivate::getV8Engine(qmlEngine(system)), this); + v8Datum = new QQuickV4ParticleData(QQmlEnginePrivate::getV8Engine(qmlEngine(particleSystem)), this, particleSystem); return v8Datum->v4Value(); } //sets the x accleration without affecting the instantaneous x velocity or position -void QQuickParticleData::setInstantaneousAX(qreal ax) +void QQuickParticleData::setInstantaneousAX(qreal ax, QQuickParticleSystem* particleSystem) { - qreal t = (system->timeInt / 1000.0) - this->t; + qreal t = (particleSystem->timeInt / 1000.0) - this->t; qreal vx = (this->vx + t*this->ax) - t*ax; qreal ex = this->x + this->vx * t + 0.5 * this->ax * t * t; qreal x = ex - t*vx - 0.5 * t*t*ax; @@ -547,9 +543,9 @@ void QQuickParticleData::setInstantaneousAX(qreal ax) } //sets the x velocity without affecting the instantaneous x postion -void QQuickParticleData::setInstantaneousVX(qreal vx) +void QQuickParticleData::setInstantaneousVX(qreal vx, QQuickParticleSystem* particleSystem) { - qreal t = (system->timeInt / 1000.0) - this->t; + qreal t = (particleSystem->timeInt / 1000.0) - this->t; qreal evx = vx - t*this->ax; qreal ex = this->x + this->vx * t + 0.5 * this->ax * t * t; qreal x = ex - t*evx - 0.5 * t*t*this->ax; @@ -559,16 +555,16 @@ void QQuickParticleData::setInstantaneousVX(qreal vx) } //sets the instantaneous x postion -void QQuickParticleData::setInstantaneousX(qreal x) +void QQuickParticleData::setInstantaneousX(qreal x, QQuickParticleSystem* particleSystem) { - qreal t = (system->timeInt / 1000.0) - this->t; + qreal t = (particleSystem->timeInt / 1000.0) - this->t; this->x = x - t*this->vx - 0.5 * t*t*this->ax; } //sets the y accleration without affecting the instantaneous y velocity or position -void QQuickParticleData::setInstantaneousAY(qreal ay) +void QQuickParticleData::setInstantaneousAY(qreal ay, QQuickParticleSystem* particleSystem) { - qreal t = (system->timeInt / 1000.0) - this->t; + qreal t = (particleSystem->timeInt / 1000.0) - this->t; qreal vy = (this->vy + t*this->ay) - t*ay; qreal ey = this->y + this->vy * t + 0.5 * this->ay * t * t; qreal y = ey - t*vy - 0.5 * t*t*ay; @@ -579,9 +575,9 @@ void QQuickParticleData::setInstantaneousAY(qreal ay) } //sets the y velocity without affecting the instantaneous y position -void QQuickParticleData::setInstantaneousVY(qreal vy) +void QQuickParticleData::setInstantaneousVY(qreal vy, QQuickParticleSystem* particleSystem) { - qreal t = (system->timeInt / 1000.0) - this->t; + qreal t = (particleSystem->timeInt / 1000.0) - this->t; qreal evy = vy - t*this->ay; qreal ey = this->y + this->vy * t + 0.5 * this->ay * t * t; qreal y = ey - t*evy - 0.5 * t*t*this->ay; @@ -591,71 +587,71 @@ void QQuickParticleData::setInstantaneousVY(qreal vy) } //sets the instantaneous Y position -void QQuickParticleData::setInstantaneousY(qreal y) +void QQuickParticleData::setInstantaneousY(qreal y, QQuickParticleSystem* particleSystem) { - qreal t = (system->timeInt / 1000.0) - this->t; + qreal t = (particleSystem->timeInt / 1000.0) - this->t; this->y = y - t*this->vy - 0.5 * t*t*this->ay; } -qreal QQuickParticleData::curX() const +qreal QQuickParticleData::curX(QQuickParticleSystem* particleSystem) const { - qreal t = (system->timeInt / 1000.0) - this->t; + qreal t = (particleSystem->timeInt / 1000.0) - this->t; return this->x + this->vx * t + 0.5 * this->ax * t * t; } -qreal QQuickParticleData::curVX() const +qreal QQuickParticleData::curVX(QQuickParticleSystem* particleSystem) const { - qreal t = (system->timeInt / 1000.0) - this->t; + qreal t = (particleSystem->timeInt / 1000.0) - this->t; return this->vx + t*this->ax; } -qreal QQuickParticleData::curY() const +qreal QQuickParticleData::curY(QQuickParticleSystem* particleSystem) const { - qreal t = (system->timeInt / 1000.0) - this->t; + qreal t = (particleSystem->timeInt / 1000.0) - this->t; return y + vy * t + 0.5 * ay * t * t; } -qreal QQuickParticleData::curVY() const +qreal QQuickParticleData::curVY(QQuickParticleSystem* particleSystem) const { - qreal t = (system->timeInt / 1000.0) - this->t; + qreal t = (particleSystem->timeInt / 1000.0) - this->t; return vy + t*ay; } -void QQuickParticleData::debugDump() +void QQuickParticleData::debugDump(QQuickParticleSystem* particleSystem) { - qDebug() << "Particle" << systemIndex << group << "/" << index << stillAlive() + qDebug() << "Particle" << systemIndex << groupId << "/" << index << stillAlive(particleSystem) << "Pos: " << x << "," << y << "Vel: " << vx << "," << vy << "Acc: " << ax << "," << ay << "Size: " << size << "," << endSize - << "Time: " << t << "," <timeInt / 1000.0) ; + << "Time: " << t << "," <timeInt / 1000.0) ; } -float QQuickParticleData::curSize() +float QQuickParticleData::curSize(QQuickParticleSystem* particleSystem) { - if (!system || !lifeSpan) + if (!particleSystem || !lifeSpan) return 0.0f; - return size + (endSize - size) * (1 - (lifeLeft() / lifeSpan)); + return size + (endSize - size) * (1 - (lifeLeft(particleSystem) / lifeSpan)); } -float QQuickParticleData::lifeLeft() +float QQuickParticleData::lifeLeft(QQuickParticleSystem* particleSystem) { - if (!system) + if (!particleSystem) return 0.0f; - return (t + lifeSpan) - (system->timeInt/1000.0); + return (t + lifeSpan) - (particleSystem->timeInt/1000.0); } -void QQuickParticleData::extendLife(float time) +void QQuickParticleData::extendLife(float time, QQuickParticleSystem* particleSystem) { - qreal newX = curX(); - qreal newY = curY(); - qreal newVX = curVX(); - qreal newVY = curVY(); + qreal newX = curX(particleSystem); + qreal newY = curY(particleSystem); + qreal newVX = curVX(particleSystem); + qreal newVY = curVY(particleSystem); t += time; animT += time; - qreal elapsed = (system->timeInt / 1000.0) - t; + qreal elapsed = (particleSystem->timeInt / 1000.0) - t; qreal evy = newVY - elapsed*ay; qreal ey = newY - elapsed*evy - 0.5 * elapsed*elapsed*ay; qreal evx = newVX - elapsed*ax; @@ -1049,7 +1045,7 @@ void QQuickParticleSystem::particleStateChange(int idx) void QQuickParticleSystem::moveGroups(QQuickParticleData *d, int newGIdx) { - if (!d || newGIdx == d->group) + if (!d || newGIdx == d->groupId) return; QQuickParticleData* pd = newDatum(newGIdx, false, d->systemIndex); @@ -1060,7 +1056,7 @@ void QQuickParticleSystem::moveGroups(QQuickParticleData *d, int newGIdx) finishNewDatum(pd); d->systemIndex = -1; - groupData[d->group]->kill(d); + groupData[d->groupId]->kill(d); } int QQuickParticleSystem::nextSystemIndex() @@ -1102,17 +1098,17 @@ QQuickParticleData* QQuickParticleSystem::newDatum(int groupId, bool respectLimi bySysIdx[ret->systemIndex] = ret; if (stateEngine) - stateEngine->start(ret->systemIndex, ret->group); + stateEngine->start(ret->systemIndex, ret->groupId); m_empty = false; return ret; } -void QQuickParticleSystem::emitParticle(QQuickParticleData* pd) +void QQuickParticleSystem::emitParticle(QQuickParticleData* pd, QQuickParticleEmitter* particleEmitter) {// called from prepareNextFrame()->emitWindow - enforce? //Account for relative emitter position bool okay = false; - QTransform t = pd->e->itemTransform(this, &okay); + QTransform t = particleEmitter->itemTransform(this, &okay); if (okay) { qreal tx,ty; t.map(pd->x, pd->y, &tx, &ty); @@ -1126,12 +1122,12 @@ void QQuickParticleSystem::emitParticle(QQuickParticleData* pd) void QQuickParticleSystem::finishNewDatum(QQuickParticleData *pd) { Q_ASSERT(pd); - groupData[pd->group]->prepareRecycler(pd); + groupData[pd->groupId]->prepareRecycler(pd); foreach (QQuickParticleAffector *a, m_affectors) if (a && a->m_needsReset) a->reset(pd); - foreach (QQuickParticlePainter* p, groupData[pd->group]->painters) + foreach (QQuickParticlePainter* p, groupData[pd->groupId]->painters) if (p) p->load(pd); } @@ -1165,7 +1161,7 @@ void QQuickParticleSystem::updateCurrentTime( int currentTime ) foreach (QQuickParticleAffector* a, m_affectors) a->affectSystem(dt); foreach (QQuickParticleData* d, needsReset) - foreach (QQuickParticlePainter* p, groupData[d->group]->painters) + foreach (QQuickParticlePainter* p, groupData[d->groupId]->painters) p->reload(d); if (oldClear != m_empty) diff --git a/src/particles/qquickparticlesystem_p.h b/src/particles/qquickparticlesystem_p.h index 2745e73053..fcdd027a54 100644 --- a/src/particles/qquickparticlesystem_p.h +++ b/src/particles/qquickparticlesystem_p.h @@ -154,8 +154,8 @@ public: //TODO: Refactor particle data list out into a separate class QVector data; - QQuickParticleDataHeap dataHeap; QSet reusableIndexes; + QQuickParticleDataHeap dataHeap; bool recycle(); //Force recycling round, returns true if all indexes are now reusable void initList(); @@ -182,7 +182,7 @@ struct Color4ub { class Q_QUICKPARTICLES_PRIVATE_EXPORT QQuickParticleData { public: //TODO: QObject like memory management (without the cost, just attached to system) - QQuickParticleData(QQuickParticleSystem* sys); + QQuickParticleData(); ~QQuickParticleData(); QQuickParticleData(const QQuickParticleData &other); @@ -192,28 +192,28 @@ public: //If setting multiple parameters at once, doing the conversion yourself will be faster. //sets the x accleration without affecting the instantaneous x velocity or position - void setInstantaneousAX(qreal ax); + void setInstantaneousAX(qreal ax, QQuickParticleSystem *particleSystem); //sets the x velocity without affecting the instantaneous x postion - void setInstantaneousVX(qreal vx); + void setInstantaneousVX(qreal vx, QQuickParticleSystem *particleSystem); //sets the instantaneous x postion - void setInstantaneousX(qreal x); + void setInstantaneousX(qreal x, QQuickParticleSystem *particleSystem); //sets the y accleration without affecting the instantaneous y velocity or position - void setInstantaneousAY(qreal ay); + void setInstantaneousAY(qreal ay, QQuickParticleSystem *particleSystem); //sets the y velocity without affecting the instantaneous y postion - void setInstantaneousVY(qreal vy); + void setInstantaneousVY(qreal vy, QQuickParticleSystem *particleSystem); //sets the instantaneous Y postion - void setInstantaneousY(qreal y); + void setInstantaneousY(qreal y, QQuickParticleSystem *particleSystem); //TODO: Slight caching? - qreal curX() const; - qreal curVX() const; + qreal curX(QQuickParticleSystem *particleSystem) const; + qreal curVX(QQuickParticleSystem *particleSystem) const; qreal curAX() const { return ax; } - qreal curY() const; - qreal curVY() const; + qreal curAX(QQuickParticleSystem *) const { return ax; } // used by the macros in qquickv4particledata.cpp + qreal curY(QQuickParticleSystem *particleSystem) const; + qreal curVY(QQuickParticleSystem *particleSystem) const; qreal curAY() const { return ay; } + qreal curAY(QQuickParticleSystem *) const { return ay; } // used by the macros in qquickv4particledata.cpp - QQuickParticleEmitter* e;//### Needed? - QQuickParticleSystem* system; int index; int systemIndex; @@ -251,7 +251,7 @@ public: float animWidth; float animHeight; - int group; + QQuickParticleGroupData::ID groupId; //Used by ImageParticle data shadowing QQuickImageParticle* colorOwner; @@ -270,14 +270,14 @@ public: // 4 bytes wasted - void debugDump(); - bool stillAlive();//Only checks end, because usually that's all you need and it's a little faster. - bool alive(); - float lifeLeft(); - float curSize(); + void debugDump(QQuickParticleSystem *particleSystem); + bool stillAlive(QQuickParticleSystem *particleSystem);//Only checks end, because usually that's all you need and it's a little faster. + bool alive(QQuickParticleSystem *particleSystem); + float lifeLeft(QQuickParticleSystem *particleSystem); + float curSize(QQuickParticleSystem *particleSystem); void clone(const QQuickParticleData& other);//Not =, leaves meta-data like index - QQmlV4Handle v4Value(); - void extendLife(float time); + QQmlV4Handle v4Value(QQuickParticleSystem *particleSystem); + void extendLife(float time, QQuickParticleSystem *particleSystem); static inline Q_DECL_CONSTEXPR qreal EPSILON() Q_DECL_NOTHROW { return 0.001; } @@ -338,7 +338,7 @@ private Q_SLOTS: public: //These can be called multiple times per frame, performance critical - void emitParticle(QQuickParticleData* p); + void emitParticle(QQuickParticleData* p, QQuickParticleEmitter *particleEmitter); QQuickParticleData* newDatum(int groupId, bool respectLimits = true, int sysIdx = -1); void finishNewDatum(QQuickParticleData*); void moveGroups(QQuickParticleData *d, int newGIdx); @@ -429,14 +429,14 @@ private: QQuickParticleSystem* m_system; }; -inline bool QQuickParticleData::stillAlive() +inline bool QQuickParticleData::stillAlive(QQuickParticleSystem* system) { if (!system) return false; return (t + lifeSpan - EPSILON()) > ((qreal)system->timeInt/1000.0); } -inline bool QQuickParticleData::alive() +inline bool QQuickParticleData::alive(QQuickParticleSystem* system) { if (!system) return false; diff --git a/src/particles/qquickpointattractor.cpp b/src/particles/qquickpointattractor.cpp index 8b3cfbd1ff..779b2915f0 100644 --- a/src/particles/qquickpointattractor.cpp +++ b/src/particles/qquickpointattractor.cpp @@ -115,8 +115,8 @@ bool QQuickAttractorAffector::affectParticle(QQuickParticleData *d, qreal dt) { if (m_strength == 0.0) return false; - qreal dx = m_x+m_offset.x() - d->curX(); - qreal dy = m_y+m_offset.y() - d->curY(); + qreal dx = m_x+m_offset.x() - d->curX(m_system); + qreal dy = m_y+m_offset.y() - d->curY(m_system); qreal r = std::sqrt((dx*dx) + (dy*dy)); qreal theta = std::atan2(dy,dx); qreal ds = 0; @@ -146,15 +146,15 @@ bool QQuickAttractorAffector::affectParticle(QQuickParticleData *d, qreal dt) d->y = (d->y + dy); break; case Acceleration: - d->setInstantaneousAX(d->ax + dx); - d->setInstantaneousAY(d->ay + dy); + d->setInstantaneousAX(d->ax + dx, m_system); + d->setInstantaneousAY(d->ay + dy, m_system); break; case Velocity: //also default default: - vx = d->curVX(); - vy = d->curVY(); - d->setInstantaneousVX(vx + dx); - d->setInstantaneousVY(vy + dy); + vx = d->curVX(m_system); + vy = d->curVY(m_system); + d->setInstantaneousVX(vx + dx, m_system); + d->setInstantaneousVY(vy + dy, m_system); } return true; diff --git a/src/particles/qquickspritegoal.cpp b/src/particles/qquickspritegoal.cpp index 7afb787530..5784f1402d 100644 --- a/src/particles/qquickspritegoal.cpp +++ b/src/particles/qquickspritegoal.cpp @@ -124,7 +124,7 @@ bool QQuickSpriteGoalAffector::affectParticle(QQuickParticleData *d, qreal dt) QQuickStochasticEngine *engine = 0; if (!m_systemStates){ //TODO: Affect all engines - foreach (QQuickParticlePainter *p, m_system->groupData[d->group]->painters) + foreach (QQuickParticlePainter *p, m_system->groupData[d->groupId]->painters) if (qobject_cast(p)) engine = qobject_cast(p)->spriteEngine(); }else{ diff --git a/src/particles/qquicktrailemitter.cpp b/src/particles/qquicktrailemitter.cpp index 904421c296..d4d2adcfb2 100644 --- a/src/particles/qquicktrailemitter.cpp +++ b/src/particles/qquicktrailemitter.cpp @@ -182,7 +182,7 @@ void QQuickTrailEmitter::emitWindow(int timeStamp) int gId2 = groupId(); for (int i=0; igroupData[gId]->data.count(); i++) { QQuickParticleData *d = m_system->groupData[gId]->data[i]; - if (!d->stillAlive()){ + if (!d->stillAlive(m_system)){ m_lastEmission[i] = time; //Should only start emitting when it returns to life continue; } @@ -192,7 +192,8 @@ void QQuickTrailEmitter::emitWindow(int timeStamp) if (pt + maxLife < time)//We missed so much, that we should skip emiting particles that are dead by now pt = time - maxLife; - if ((width() || height()) && !effectiveExtruder()->contains(QRectF(offset.x(), offset.y(), width(), height()),QPointF(d->curX(), d->curY()))){ + if ((width() || height()) && !effectiveExtruder()->contains(QRectF(offset.x(), offset.y(), width(), height()), + QPointF(d->curX(m_system), d->curY(m_system)))) { m_lastEmission[d->index] = time;//jump over this time period without emitting, because it's outside continue; } @@ -202,8 +203,6 @@ void QQuickTrailEmitter::emitWindow(int timeStamp) while (pt < time || !m_burstQueue.isEmpty()){ QQuickParticleData* datum = m_system->newDatum(gId2, !m_overwrite); if (datum){//else, skip this emission - datum->e = this;//###useful? - // Particle timestamp datum->t = pt; datum->lifeSpan = @@ -215,8 +214,8 @@ void QQuickTrailEmitter::emitWindow(int timeStamp) // Note that burst location doesn't get used for follow emitter qreal followT = pt - d->t; qreal followT2 = followT * followT * 0.5; - qreal eW = m_emitterXVariation < 0 ? d->curSize() : m_emitterXVariation; - qreal eH = m_emitterYVariation < 0 ? d->curSize() : m_emitterYVariation; + qreal eW = m_emitterXVariation < 0 ? d->curSize(m_system) : m_emitterXVariation; + qreal eH = m_emitterYVariation < 0 ? d->curSize(m_system) : m_emitterYVariation; //Subtract offset, because PS expects this in emitter coordinates QRectF boundsRect(d->x - offset.x() + d->vx * followT + d->ax * followT2 - eW/2, d->y - offset.y() + d->vy * followT + d->ay * followT2 - eH/2, @@ -251,7 +250,7 @@ void QQuickTrailEmitter::emitWindow(int timeStamp) toEmit << datum; - m_system->emitParticle(datum); + m_system->emitParticle(datum, this); } if (!m_burstQueue.isEmpty()){ m_burstQueue.first().first--; @@ -263,7 +262,7 @@ void QQuickTrailEmitter::emitWindow(int timeStamp) } foreach (QQuickParticleData* d, toEmit) - m_system->emitParticle(d); + m_system->emitParticle(d, this); if (isEmitConnected() || isEmitFollowConnected()) { QQmlEngine *qmlEngine = ::qmlEngine(this); @@ -273,10 +272,10 @@ void QQuickTrailEmitter::emitWindow(int timeStamp) QV4::ScopedArrayObject array(scope, v4->newArrayObject(toEmit.size())); QV4::ScopedValue v(scope); for (int i=0; iputIndexed(i, (v = toEmit[i]->v4Value())); + array->putIndexed(i, (v = toEmit[i]->v4Value(m_system))); if (isEmitFollowConnected()) - emitFollowParticles(QQmlV4Handle(array), d->v4Value());//A chance for many arbitrary JS changes + emitFollowParticles(QQmlV4Handle(array), d->v4Value(m_system));//A chance for many arbitrary JS changes else if (isEmitConnected()) emitParticles(QQmlV4Handle(array));//A chance for arbitrary JS changes } diff --git a/src/particles/qquickturbulence.cpp b/src/particles/qquickturbulence.cpp index eed8604438..74558413a6 100644 --- a/src/particles/qquickturbulence.cpp +++ b/src/particles/qquickturbulence.cpp @@ -186,7 +186,7 @@ void QQuickTurbulenceAffector::affectSystem(qreal dt) foreach (QQuickParticleData *d, gd->data){ if (!shouldAffect(d)) continue; - QPoint pos = (QPointF(d->curX(), d->curY()) - m_offset).toPoint(); + QPoint pos = (QPointF(d->curX(m_system), d->curY(m_system)) - m_offset).toPoint(); if (!boundsRect.contains(pos,true))//Need to redo bounds checking due to quantization. continue; qreal fx = 0.0; @@ -194,8 +194,8 @@ void QQuickTurbulenceAffector::affectSystem(qreal dt) fx += m_vectorField[pos.x()][pos.y()].x() * m_strength; fy += m_vectorField[pos.x()][pos.y()].y() * m_strength; if (fx || fy){ - d->setInstantaneousVX(d->curVX()+ fx * dt); - d->setInstantaneousVY(d->curVY()+ fy * dt); + d->setInstantaneousVX(d->curVX(m_system)+ fx * dt, m_system); + d->setInstantaneousVY(d->curVY(m_system)+ fy * dt, m_system); postAffect(d); } } diff --git a/src/particles/qquickv4particledata.cpp b/src/particles/qquickv4particledata.cpp index 86e3c91ba8..3d7f4ce5b8 100644 --- a/src/particles/qquickv4particledata.cpp +++ b/src/particles/qquickv4particledata.cpp @@ -272,11 +272,13 @@ QT_BEGIN_NAMESPACE struct QV4ParticleData : public QV4::Object { struct Data : QV4::Object::Data { - Data(QQuickParticleData *datum) + Data(QQuickParticleData *datum, QQuickParticleSystem* particleSystem) : datum(datum) + , particleSystem(particleSystem) { } QQuickParticleData* datum;//TODO: Guard needed? + QQuickParticleSystem* particleSystem; }; V4_OBJECT(QV4::Object) }; @@ -312,7 +314,7 @@ static QV4::ReturnedValue particleData_lifeLeft(QV4::CallContext *ctx) if (!r || !r->d()->datum) return ctx->engine()->throwError(QStringLiteral("Not a valid ParticleData object")); - return QV4::Encode(r->d()->datum->lifeLeft()); + return QV4::Encode(r->d()->datum->lifeLeft(r->d()->particleSystem)); } static QV4::ReturnedValue particleData_curSize(QV4::CallContext *ctx) @@ -323,7 +325,7 @@ static QV4::ReturnedValue particleData_curSize(QV4::CallContext *ctx) if (!r || !r->d()->datum) return ctx->engine()->throwError(QStringLiteral("Not a valid ParticleData object")); - return QV4::Encode(r->d()->datum->curSize()); + return QV4::Encode(r->d()->datum->curSize(r->d()->particleSystem)); } #define COLOR_GETTER_AND_SETTER(VAR, NAME) static QV4::ReturnedValue particleData_get_ ## NAME (QV4::CallContext *ctx) \ { \ @@ -397,7 +399,7 @@ static QV4::ReturnedValue particleData_set_ ## VARIABLE (QV4::CallContext *ctx)\ if (!r || !r->d()->datum) \ ctx->engine()->throwError(QStringLiteral("Not a valid ParticleData object")); \ \ - return QV4::Encode(r->d()->datum-> GETTER ());\ + return QV4::Encode(r->d()->datum-> GETTER (r->d()->particleSystem));\ }\ \ static QV4::ReturnedValue particleData_set_ ## VARIABLE (QV4::CallContext *ctx)\ @@ -407,7 +409,7 @@ static QV4::ReturnedValue particleData_set_ ## VARIABLE (QV4::CallContext *ctx)\ if (!r || !r->d()->datum)\ ctx->engine()->throwError(QStringLiteral("Not a valid ParticleData object"));\ \ - r->d()->datum-> SETTER (ctx->argc() ? ctx->args()[0].toNumber() : qQNaN());\ + r->d()->datum-> SETTER (ctx->argc() ? ctx->args()[0].toNumber() : qQNaN(), r->d()->particleSystem);\ return QV4::Encode::undefined(); \ } @@ -503,7 +505,7 @@ QV4ParticleDataDeletable::~QV4ParticleDataDeletable() V4_DEFINE_EXTENSION(QV4ParticleDataDeletable, particleV4Data); -QQuickV4ParticleData::QQuickV4ParticleData(QV8Engine* engine, QQuickParticleData* datum) +QQuickV4ParticleData::QQuickV4ParticleData(QV8Engine* engine, QQuickParticleData* datum, QQuickParticleSystem *system) { if (!engine || !datum) return; @@ -511,7 +513,7 @@ QQuickV4ParticleData::QQuickV4ParticleData(QV8Engine* engine, QQuickParticleData QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine); QV4::Scope scope(v4); QV4ParticleDataDeletable *d = particleV4Data(scope.engine); - QV4::ScopedObject o(scope, v4->memoryManager->allocObject(datum)); + QV4::ScopedObject o(scope, v4->memoryManager->allocObject(datum, system)); QV4::ScopedObject p(scope, d->proto.value()); o->setPrototype(p); m_v4Value = o; diff --git a/src/particles/qquickv4particledata_p.h b/src/particles/qquickv4particledata_p.h index b93c0333d7..0d88f0f9cc 100644 --- a/src/particles/qquickv4particledata_p.h +++ b/src/particles/qquickv4particledata_p.h @@ -58,9 +58,10 @@ QT_BEGIN_NAMESPACE class QQuickParticleData; +class QQuickParticleSystem; class QQuickV4ParticleData { public: - QQuickV4ParticleData(QV8Engine*,QQuickParticleData*); + QQuickV4ParticleData(QV8Engine*, QQuickParticleData*, QQuickParticleSystem *system); ~QQuickV4ParticleData(); QQmlV4Handle v4Value(); private: diff --git a/src/particles/qquickwander.cpp b/src/particles/qquickwander.cpp index 862c796dac..09d36ab2e8 100644 --- a/src/particles/qquickwander.cpp +++ b/src/particles/qquickwander.cpp @@ -151,29 +151,29 @@ bool QQuickWanderAffector::affectParticle(QQuickParticleData* data, qreal dt) qreal newX, newY; switch (m_affectedParameter){ case Position: - newX = data->curX() + dx; + newX = data->curX(m_system) + dx; if (m_xVariance > qAbs(newX) ) data->x += dx; - newY = data->curY() + dy; + newY = data->curY(m_system) + dy; if (m_yVariance > qAbs(newY) ) data->y += dy; break; default: case Velocity: - newX = data->curVX() + dx; - if (m_xVariance > qAbs(newX) ) - data->setInstantaneousVX(newX); - newY = data->curVY() + dy; - if (m_yVariance > qAbs(newY) ) - data->setInstantaneousVY(newY); + newX = data->curVX(m_system) + dx; + if (m_xVariance > qAbs(newX)) + data->setInstantaneousVX(newX, m_system); + newY = data->curVY(m_system) + dy; + if (m_yVariance > qAbs(newY)) + data->setInstantaneousVY(newY, m_system); break; case Acceleration: newX = data->ax + dx; - if (m_xVariance > qAbs(newX) ) - data->setInstantaneousAX(newX); + if (m_xVariance > qAbs(newX)) + data->setInstantaneousAX(newX, m_system); newY = data->ay + dy; - if (m_yVariance > qAbs(newY) ) - data->setInstantaneousAY(newY); + if (m_yVariance > qAbs(newY)) + data->setInstantaneousAY(newY, m_system); break; } return true; -- cgit v1.2.3 From ec3b4cf7a5de9a4ead73f09c3d7a02421b29f805 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Thu, 3 Mar 2016 15:06:25 +0100 Subject: Particles: replace a QSet with a bit vector for group data. The reusableIndexes represented a "free-list". Now the allocation behavior in QQuickParticleGroupData::setSize was to grow by (large) chunks. That means that as soon setSize was called, a (big) number of hash entries was created, which are drained over time. This memory would stay around (and probably unused) as long as the group was alive. By using a bit vector, the amount of memory is much more compressed, and finding an entry takes less time. The FreeList "caches" the next free entry, because allocation and de-allocation behavior is that they occur bunches: allocate a number of particles, use them, allocate the same number. Test case: samegame, 1 player, click 1 set of 3 stones, quit. QQuickParticleSystem::emittersChanged(), before patch: - 21 instr. inclusive, 15M in QQuickParticleGroupData::setSize - 23,000 calls to QHashData::allocateNode after: - 13M instr. inclusive, 7M in QQuickParticleGroupData::setSize - 0 calls to QHashData::allocateNode Change-Id: If35ea5ed9b29129f210638f6f59275a24eb6afdc Reviewed-by: Lars Knoll --- src/particles/qquickparticlesystem.cpp | 18 +++++----- src/particles/qquickparticlesystem_p.h | 62 +++++++++++++++++++++++++++++++++- src/qml/jsruntime/qv4util_p.h | 10 ++++++ 3 files changed, 80 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/particles/qquickparticlesystem.cpp b/src/particles/qquickparticlesystem.cpp index e9bd073133..f4c9121007 100644 --- a/src/particles/qquickparticlesystem.cpp +++ b/src/particles/qquickparticlesystem.cpp @@ -339,11 +339,11 @@ void QQuickParticleGroupData::setSize(int newSize) return; Q_ASSERT(newSize > m_size);//XXX allow shrinking data.resize(newSize); + freeList.resize(newSize); for (int i=m_size; igroupId = index; data[i]->index = i; - reusableIndexes << i; } int delta = newSize - m_size; m_size = newSize; @@ -362,16 +362,15 @@ void QQuickParticleGroupData::kill(QQuickParticleData* d) d->lifeSpan = 0;//Kill off foreach (QQuickParticlePainter* p, painters) p->reload(d); - reusableIndexes << d->index; + freeList.free(d->index); } QQuickParticleData* QQuickParticleGroupData::newDatum(bool respectsLimits) { //recycle();//Extra recycler round to be sure? - while (!reusableIndexes.empty()) { - int idx = *(reusableIndexes.begin()); - reusableIndexes.remove(idx); + while (freeList.hasUnusedEntries()) { + int idx = freeList.alloc(); if (data[idx]->stillAlive(m_system)) {// ### This means resurrection of 'dead' particles. Is that allowed? prepareRecycler(data[idx]); continue; @@ -383,8 +382,9 @@ QQuickParticleData* QQuickParticleGroupData::newDatum(bool respectsLimits) int oldSize = m_size; setSize(oldSize + 10);//###+1,10%,+10? Choose something non-arbitrarily - reusableIndexes.remove(oldSize); - return data[oldSize]; + int idx = freeList.alloc(); + Q_ASSERT(idx == oldSize); + return data[idx]; } bool QQuickParticleGroupData::recycle() @@ -392,7 +392,7 @@ bool QQuickParticleGroupData::recycle() while (dataHeap.top() <= m_system->timeInt) { foreach (QQuickParticleData* datum, dataHeap.pop()) { if (!datum->stillAlive(m_system)) { - reusableIndexes << datum->index; + freeList.free(datum->index); } else { prepareRecycler(datum); //ttl has been altered mid-way, put it back } @@ -400,7 +400,7 @@ bool QQuickParticleGroupData::recycle() } //TODO: If the data is clear, gc (consider shrinking stack size)? - return reusableIndexes.count() == m_size; + return freeList.count() == 0; } void QQuickParticleGroupData::prepareRecycler(QQuickParticleData* d) diff --git a/src/particles/qquickparticlesystem_p.h b/src/particles/qquickparticlesystem_p.h index fcdd027a54..182fc6aed6 100644 --- a/src/particles/qquickparticlesystem_p.h +++ b/src/particles/qquickparticlesystem_p.h @@ -61,6 +61,7 @@ #include #include #include //For QQmlV4Handle +#include #include "qtquickparticlesglobal_p.h" QT_BEGIN_NAMESPACE @@ -134,6 +135,65 @@ private: }; class Q_QUICKPARTICLES_PRIVATE_EXPORT QQuickParticleGroupData { + class FreeList + { + public: + FreeList() + : firstUnused(UINT_MAX) + , allocated(0) + {} + + void resize(int newSize) + { + Q_ASSERT(newSize >= 0); + int oldSize = isUnused.size(); + isUnused.resize(newSize, true); + if (newSize > oldSize) { + if (firstUnused == UINT_MAX) { + firstUnused = oldSize; + } else { + firstUnused = std::min(firstUnused, unsigned(oldSize)); + } + } else if (firstUnused >= unsigned(newSize)) { + firstUnused = UINT_MAX; + } + } + + void free(int index) + { + isUnused.setBit(index); + firstUnused = std::min(firstUnused, unsigned(index)); + --allocated; + } + + int count() const + { return allocated; } + + bool hasUnusedEntries() const + { return firstUnused != UINT_MAX; } + + int alloc() + { + if (hasUnusedEntries()) { + int nextFree = firstUnused; + isUnused.clearBit(firstUnused); + firstUnused = isUnused.findNext(firstUnused, true, false); + if (firstUnused >= unsigned(isUnused.size())) { + firstUnused = UINT_MAX; + } + ++allocated; + return nextFree; + } else { + return -1; + } + } + + private: + QV4::BitVector isUnused; + unsigned firstUnused; + int allocated; + }; + public: // types typedef int ID; enum { InvalidID = -1, DefaultGroupID = 0 }; @@ -154,7 +214,7 @@ public: //TODO: Refactor particle data list out into a separate class QVector data; - QSet reusableIndexes; + FreeList freeList; QQuickParticleDataHeap dataHeap; bool recycle(); //Force recycling round, returns true if all indexes are now reusable diff --git a/src/qml/jsruntime/qv4util_p.h b/src/qml/jsruntime/qv4util_p.h index 132abd211e..59c12c5e46 100644 --- a/src/qml/jsruntime/qv4util_p.h +++ b/src/qml/jsruntime/qv4util_p.h @@ -102,6 +102,9 @@ public: void resize(int newSize) { bits.resize(newSize); } + void resize(int newSize, bool newValue) + { bits.resize(newSize, newValue); } + void assign(int newSize, bool value) { bits.assign(newSize, value); } @@ -159,6 +162,13 @@ public: void resize(int newSize) { bits.resize(newSize); } + void resize(int newSize, bool newValue) + { + int oldSize = bits.size(); + bits.resize(newSize); + bits.fill(newValue, oldSize, bits.size()); + } + void assign(int newSize, bool value) { bits.resize(newSize); -- cgit v1.2.3 From 46204fd5d1362811ae040a4a9cb6cf01c37e77c1 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Thu, 3 Mar 2016 13:00:28 +0100 Subject: Particles: make many QQuickParticleData members inlinable. Calls to these functions often occur in sets of two (x, y) or even more (x, y, vx, vy, etc). By allowing the compiler to inline, it allows for many CSE opportunities. Also, if your compiler is reasonably good, it will also auto-vectorize the operations. Change-Id: I4bffe4826671dd60683b941a569fc6a7b4b34da7 Reviewed-by: Lars Knoll --- src/particles/qquickparticlesystem.cpp | 103 +----------------------------- src/particles/qquickparticlesystem_p.h | 111 ++++++++++++++++++++++++++++++--- 2 files changed, 105 insertions(+), 109 deletions(-) (limited to 'src') diff --git a/src/particles/qquickparticlesystem.cpp b/src/particles/qquickparticlesystem.cpp index f4c9121007..5109375f43 100644 --- a/src/particles/qquickparticlesystem.cpp +++ b/src/particles/qquickparticlesystem.cpp @@ -529,95 +529,8 @@ QQmlV4Handle QQuickParticleData::v4Value(QQuickParticleSystem* particleSystem) v8Datum = new QQuickV4ParticleData(QQmlEnginePrivate::getV8Engine(qmlEngine(particleSystem)), this, particleSystem); return v8Datum->v4Value(); } -//sets the x accleration without affecting the instantaneous x velocity or position -void QQuickParticleData::setInstantaneousAX(qreal ax, QQuickParticleSystem* particleSystem) -{ - qreal t = (particleSystem->timeInt / 1000.0) - this->t; - qreal vx = (this->vx + t*this->ax) - t*ax; - qreal ex = this->x + this->vx * t + 0.5 * this->ax * t * t; - qreal x = ex - t*vx - 0.5 * t*t*ax; - - this->ax = ax; - this->vx = vx; - this->x = x; -} - -//sets the x velocity without affecting the instantaneous x postion -void QQuickParticleData::setInstantaneousVX(qreal vx, QQuickParticleSystem* particleSystem) -{ - qreal t = (particleSystem->timeInt / 1000.0) - this->t; - qreal evx = vx - t*this->ax; - qreal ex = this->x + this->vx * t + 0.5 * this->ax * t * t; - qreal x = ex - t*evx - 0.5 * t*t*this->ax; - - this->vx = evx; - this->x = x; -} - -//sets the instantaneous x postion -void QQuickParticleData::setInstantaneousX(qreal x, QQuickParticleSystem* particleSystem) -{ - qreal t = (particleSystem->timeInt / 1000.0) - this->t; - this->x = x - t*this->vx - 0.5 * t*t*this->ax; -} - -//sets the y accleration without affecting the instantaneous y velocity or position -void QQuickParticleData::setInstantaneousAY(qreal ay, QQuickParticleSystem* particleSystem) -{ - qreal t = (particleSystem->timeInt / 1000.0) - this->t; - qreal vy = (this->vy + t*this->ay) - t*ay; - qreal ey = this->y + this->vy * t + 0.5 * this->ay * t * t; - qreal y = ey - t*vy - 0.5 * t*t*ay; - - this->ay = ay; - this->vy = vy; - this->y = y; -} - -//sets the y velocity without affecting the instantaneous y position -void QQuickParticleData::setInstantaneousVY(qreal vy, QQuickParticleSystem* particleSystem) -{ - qreal t = (particleSystem->timeInt / 1000.0) - this->t; - qreal evy = vy - t*this->ay; - qreal ey = this->y + this->vy * t + 0.5 * this->ay * t * t; - qreal y = ey - t*evy - 0.5 * t*t*this->ay; - - this->vy = evy; - this->y = y; -} - -//sets the instantaneous Y position -void QQuickParticleData::setInstantaneousY(qreal y, QQuickParticleSystem* particleSystem) -{ - qreal t = (particleSystem->timeInt / 1000.0) - this->t; - this->y = y - t*this->vy - 0.5 * t*t*this->ay; -} -qreal QQuickParticleData::curX(QQuickParticleSystem* particleSystem) const -{ - qreal t = (particleSystem->timeInt / 1000.0) - this->t; - return this->x + this->vx * t + 0.5 * this->ax * t * t; -} - -qreal QQuickParticleData::curVX(QQuickParticleSystem* particleSystem) const -{ - qreal t = (particleSystem->timeInt / 1000.0) - this->t; - return this->vx + t*this->ax; -} - -qreal QQuickParticleData::curY(QQuickParticleSystem* particleSystem) const -{ - qreal t = (particleSystem->timeInt / 1000.0) - this->t; - return y + vy * t + 0.5 * ay * t * t; -} - -qreal QQuickParticleData::curVY(QQuickParticleSystem* particleSystem) const -{ - qreal t = (particleSystem->timeInt / 1000.0) - this->t; - return vy + t*ay; -} - -void QQuickParticleData::debugDump(QQuickParticleSystem* particleSystem) +void QQuickParticleData::debugDump(QQuickParticleSystem* particleSystem) const { qDebug() << "Particle" << systemIndex << groupId << "/" << index << stillAlive(particleSystem) << "Pos: " << x << "," << y @@ -627,20 +540,6 @@ void QQuickParticleData::debugDump(QQuickParticleSystem* particleSystem) << "Time: " << t << "," <timeInt / 1000.0) ; } -float QQuickParticleData::curSize(QQuickParticleSystem* particleSystem) -{ - if (!particleSystem || !lifeSpan) - return 0.0f; - return size + (endSize - size) * (1 - (lifeLeft(particleSystem) / lifeSpan)); -} - -float QQuickParticleData::lifeLeft(QQuickParticleSystem* particleSystem) -{ - if (!particleSystem) - return 0.0f; - return (t + lifeSpan) - (particleSystem->timeInt/1000.0); -} - void QQuickParticleData::extendLife(float time, QQuickParticleSystem* particleSystem) { qreal newX = curX(particleSystem); diff --git a/src/particles/qquickparticlesystem_p.h b/src/particles/qquickparticlesystem_p.h index 182fc6aed6..3ab5300a80 100644 --- a/src/particles/qquickparticlesystem_p.h +++ b/src/particles/qquickparticlesystem_p.h @@ -330,11 +330,12 @@ public: // 4 bytes wasted - void debugDump(QQuickParticleSystem *particleSystem); - bool stillAlive(QQuickParticleSystem *particleSystem);//Only checks end, because usually that's all you need and it's a little faster. - bool alive(QQuickParticleSystem *particleSystem); - float lifeLeft(QQuickParticleSystem *particleSystem); - float curSize(QQuickParticleSystem *particleSystem); + void debugDump(QQuickParticleSystem *particleSystem) const; + bool stillAlive(QQuickParticleSystem *particleSystem) const; //Only checks end, because usually that's all you need and it's a little faster. + bool alive(QQuickParticleSystem *particleSystem) const; + float lifeLeft(QQuickParticleSystem *particleSystem) const; + + float curSize(QQuickParticleSystem *particleSystem) const; void clone(const QQuickParticleData& other);//Not =, leaves meta-data like index QQmlV4Handle v4Value(QQuickParticleSystem *particleSystem); void extendLife(float time, QQuickParticleSystem *particleSystem); @@ -489,14 +490,96 @@ private: QQuickParticleSystem* m_system; }; -inline bool QQuickParticleData::stillAlive(QQuickParticleSystem* system) +inline void QQuickParticleData::setInstantaneousAX(qreal ax, QQuickParticleSystem* particleSystem) +{ + qreal t = (particleSystem->timeInt / 1000.0) - this->t; + qreal vx = (this->vx + t*this->ax) - t*ax; + qreal ex = this->x + this->vx * t + 0.5 * this->ax * t * t; + qreal x = ex - t*vx - 0.5 * t*t*ax; + + this->ax = ax; + this->vx = vx; + this->x = x; +} + +inline void QQuickParticleData::setInstantaneousVX(qreal vx, QQuickParticleSystem* particleSystem) +{ + qreal t = (particleSystem->timeInt / 1000.0) - this->t; + qreal evx = vx - t*this->ax; + qreal ex = this->x + this->vx * t + 0.5 * this->ax * t * t; + qreal x = ex - t*evx - 0.5 * t*t*this->ax; + + this->vx = evx; + this->x = x; +} + +inline void QQuickParticleData::setInstantaneousX(qreal x, QQuickParticleSystem* particleSystem) +{ + qreal t = (particleSystem->timeInt / 1000.0) - this->t; + this->x = x - t*this->vx - 0.5 * t*t*this->ax; +} + +inline void QQuickParticleData::setInstantaneousAY(qreal ay, QQuickParticleSystem* particleSystem) +{ + qreal t = (particleSystem->timeInt / 1000.0) - this->t; + qreal vy = (this->vy + t*this->ay) - t*ay; + qreal ey = this->y + this->vy * t + 0.5 * this->ay * t * t; + qreal y = ey - t*vy - 0.5 * t*t*ay; + + this->ay = ay; + this->vy = vy; + this->y = y; +} + +inline void QQuickParticleData::setInstantaneousVY(qreal vy, QQuickParticleSystem* particleSystem) +{ + qreal t = (particleSystem->timeInt / 1000.0) - this->t; + qreal evy = vy - t*this->ay; + qreal ey = this->y + this->vy * t + 0.5 * this->ay * t * t; + qreal y = ey - t*evy - 0.5 * t*t*this->ay; + + this->vy = evy; + this->y = y; +} + +inline void QQuickParticleData::setInstantaneousY(qreal y, QQuickParticleSystem *particleSystem) +{ + qreal t = (particleSystem->timeInt / 1000.0) - this->t; + this->y = y - t * this->vy - 0.5 * t*t*this->ay; +} + +inline qreal QQuickParticleData::curX(QQuickParticleSystem *particleSystem) const +{ + qreal t = (particleSystem->timeInt / 1000.0) - this->t; + return this->x + this->vx * t + 0.5 * this->ax * t * t; +} + +inline qreal QQuickParticleData::curVX(QQuickParticleSystem *particleSystem) const +{ + qreal t = (particleSystem->timeInt / 1000.0) - this->t; + return this->vx + t*this->ax; +} + +inline qreal QQuickParticleData::curY(QQuickParticleSystem *particleSystem) const +{ + qreal t = (particleSystem->timeInt / 1000.0) - this->t; + return y + vy * t + 0.5 * ay * t * t; +} + +inline qreal QQuickParticleData::curVY(QQuickParticleSystem *particleSystem) const +{ + qreal t = (particleSystem->timeInt / 1000.0) - this->t; + return vy + t*ay; +} + +inline bool QQuickParticleData::stillAlive(QQuickParticleSystem* system) const { if (!system) return false; return (t + lifeSpan - EPSILON()) > ((qreal)system->timeInt/1000.0); } -inline bool QQuickParticleData::alive(QQuickParticleSystem* system) +inline bool QQuickParticleData::alive(QQuickParticleSystem* system) const { if (!system) return false; @@ -504,6 +587,20 @@ inline bool QQuickParticleData::alive(QQuickParticleSystem* system) return (t + EPSILON()) < st && (t + lifeSpan - EPSILON()) > st; } +inline float QQuickParticleData::lifeLeft(QQuickParticleSystem *particleSystem) const +{ + if (!particleSystem) + return 0.0f; + return (t + lifeSpan) - (particleSystem->timeInt/1000.0); +} + +inline float QQuickParticleData::curSize(QQuickParticleSystem *particleSystem) const +{ + if (!particleSystem || !lifeSpan) + return 0.0f; + return size + (endSize - size) * (1 - (lifeLeft(particleSystem) / lifeSpan)); +} + QT_END_NAMESPACE #endif // PARTICLESYSTEM_H -- cgit v1.2.3 From 9ecf2d33501dcd74a510adf6501c636c414ef543 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Tue, 8 Mar 2016 10:18:05 +0100 Subject: Particles: consistently use floats for particle data calculations. This removes float<->double conversions, which makes the auto-vectorized code even smaller. Change-Id: Ic4319b11a3248e3034b65e7be047d99cba84716b Reviewed-by: Lars Knoll --- src/particles/qquickage.cpp | 16 ++--- src/particles/qquickparticlesystem_p.h | 112 ++++++++++++++++----------------- 2 files changed, 64 insertions(+), 64 deletions(-) (limited to 'src') diff --git a/src/particles/qquickage.cpp b/src/particles/qquickage.cpp index e1eb714623..578207531d 100644 --- a/src/particles/qquickage.cpp +++ b/src/particles/qquickage.cpp @@ -89,15 +89,15 @@ bool QQuickAgeAffector::affectParticle(QQuickParticleData *d, qreal dt) { Q_UNUSED(dt); if (d->stillAlive(m_system)){ - qreal curT = (qreal)m_system->timeInt/1000.0; - qreal ttl = (qreal)m_lifeLeft/1000.0; + float curT = m_system->timeInt / 1000.0f; + float ttl = m_lifeLeft / 1000.0f; if (!m_advancePosition && ttl > 0){ - qreal x = d->curX(m_system); - qreal vx = d->curVX(m_system); - qreal ax = d->curAX(); - qreal y = d->curY(m_system); - qreal vy = d->curVY(m_system); - qreal ay = d->curAY(); + float x = d->curX(m_system); + float vx = d->curVX(m_system); + float ax = d->curAX(); + float y = d->curY(m_system); + float vy = d->curVY(m_system); + float ay = d->curAY(); d->t = curT - (d->lifeSpan - ttl); d->setInstantaneousX(x, m_system); d->setInstantaneousVX(vx, m_system); diff --git a/src/particles/qquickparticlesystem_p.h b/src/particles/qquickparticlesystem_p.h index 3ab5300a80..2a64735541 100644 --- a/src/particles/qquickparticlesystem_p.h +++ b/src/particles/qquickparticlesystem_p.h @@ -252,27 +252,27 @@ public: //If setting multiple parameters at once, doing the conversion yourself will be faster. //sets the x accleration without affecting the instantaneous x velocity or position - void setInstantaneousAX(qreal ax, QQuickParticleSystem *particleSystem); + void setInstantaneousAX(float ax, QQuickParticleSystem *particleSystem); //sets the x velocity without affecting the instantaneous x postion - void setInstantaneousVX(qreal vx, QQuickParticleSystem *particleSystem); + void setInstantaneousVX(float vx, QQuickParticleSystem *particleSystem); //sets the instantaneous x postion - void setInstantaneousX(qreal x, QQuickParticleSystem *particleSystem); + void setInstantaneousX(float x, QQuickParticleSystem *particleSystem); //sets the y accleration without affecting the instantaneous y velocity or position - void setInstantaneousAY(qreal ay, QQuickParticleSystem *particleSystem); + void setInstantaneousAY(float ay, QQuickParticleSystem *particleSystem); //sets the y velocity without affecting the instantaneous y postion - void setInstantaneousVY(qreal vy, QQuickParticleSystem *particleSystem); + void setInstantaneousVY(float vy, QQuickParticleSystem *particleSystem); //sets the instantaneous Y postion - void setInstantaneousY(qreal y, QQuickParticleSystem *particleSystem); + void setInstantaneousY(float y, QQuickParticleSystem *particleSystem); //TODO: Slight caching? - qreal curX(QQuickParticleSystem *particleSystem) const; - qreal curVX(QQuickParticleSystem *particleSystem) const; - qreal curAX() const { return ax; } - qreal curAX(QQuickParticleSystem *) const { return ax; } // used by the macros in qquickv4particledata.cpp - qreal curY(QQuickParticleSystem *particleSystem) const; - qreal curVY(QQuickParticleSystem *particleSystem) const; - qreal curAY() const { return ay; } - qreal curAY(QQuickParticleSystem *) const { return ay; } // used by the macros in qquickv4particledata.cpp + float curX(QQuickParticleSystem *particleSystem) const; + float curVX(QQuickParticleSystem *particleSystem) const; + float curAX() const { return ax; } + float curAX(QQuickParticleSystem *) const { return ax; } // used by the macros in qquickv4particledata.cpp + float curY(QQuickParticleSystem *particleSystem) const; + float curVY(QQuickParticleSystem *particleSystem) const; + float curAY() const { return ay; } + float curAY(QQuickParticleSystem *) const { return ay; } // used by the macros in qquickv4particledata.cpp int index; int systemIndex; @@ -340,7 +340,7 @@ public: QQmlV4Handle v4Value(QQuickParticleSystem *particleSystem); void extendLife(float time, QQuickParticleSystem *particleSystem); - static inline Q_DECL_CONSTEXPR qreal EPSILON() Q_DECL_NOTHROW { return 0.001; } + static inline Q_DECL_CONSTEXPR float EPSILON() Q_DECL_NOTHROW { return 0.001f; } private: QQuickV4ParticleData* v8Datum; @@ -490,85 +490,85 @@ private: QQuickParticleSystem* m_system; }; -inline void QQuickParticleData::setInstantaneousAX(qreal ax, QQuickParticleSystem* particleSystem) +inline void QQuickParticleData::setInstantaneousAX(float ax, QQuickParticleSystem* particleSystem) { - qreal t = (particleSystem->timeInt / 1000.0) - this->t; - qreal vx = (this->vx + t*this->ax) - t*ax; - qreal ex = this->x + this->vx * t + 0.5 * this->ax * t * t; - qreal x = ex - t*vx - 0.5 * t*t*ax; + float t = (particleSystem->timeInt / 1000.0f) - this->t; + float vx = (this->vx + t * this->ax) - t * ax; + float ex = this->x + this->vx * t + 0.5f * this->ax * t * t; + float x = ex - t * vx - 0.5f * t * t * ax; this->ax = ax; this->vx = vx; this->x = x; } -inline void QQuickParticleData::setInstantaneousVX(qreal vx, QQuickParticleSystem* particleSystem) +inline void QQuickParticleData::setInstantaneousVX(float vx, QQuickParticleSystem* particleSystem) { - qreal t = (particleSystem->timeInt / 1000.0) - this->t; - qreal evx = vx - t*this->ax; - qreal ex = this->x + this->vx * t + 0.5 * this->ax * t * t; - qreal x = ex - t*evx - 0.5 * t*t*this->ax; + float t = (particleSystem->timeInt / 1000.0f) - this->t; + float evx = vx - t * this->ax; + float ex = this->x + this->vx * t + 0.5f * this->ax * t * t; + float x = ex - t * evx - 0.5f * t * t * this->ax; this->vx = evx; this->x = x; } -inline void QQuickParticleData::setInstantaneousX(qreal x, QQuickParticleSystem* particleSystem) +inline void QQuickParticleData::setInstantaneousX(float x, QQuickParticleSystem* particleSystem) { - qreal t = (particleSystem->timeInt / 1000.0) - this->t; - this->x = x - t*this->vx - 0.5 * t*t*this->ax; + float t = (particleSystem->timeInt / 1000.0f) - this->t; + this->x = x - t * this->vx - 0.5f * t * t * this->ax; } -inline void QQuickParticleData::setInstantaneousAY(qreal ay, QQuickParticleSystem* particleSystem) +inline void QQuickParticleData::setInstantaneousAY(float ay, QQuickParticleSystem* particleSystem) { - qreal t = (particleSystem->timeInt / 1000.0) - this->t; - qreal vy = (this->vy + t*this->ay) - t*ay; - qreal ey = this->y + this->vy * t + 0.5 * this->ay * t * t; - qreal y = ey - t*vy - 0.5 * t*t*ay; + float t = (particleSystem->timeInt / 1000.0f) - this->t; + float vy = (this->vy + t * this->ay) - t * ay; + float ey = this->y + this->vy * t + 0.5f * this->ay * t * t; + float y = ey - t * vy - 0.5f * t * t * ay; this->ay = ay; this->vy = vy; this->y = y; } -inline void QQuickParticleData::setInstantaneousVY(qreal vy, QQuickParticleSystem* particleSystem) +inline void QQuickParticleData::setInstantaneousVY(float vy, QQuickParticleSystem* particleSystem) { - qreal t = (particleSystem->timeInt / 1000.0) - this->t; - qreal evy = vy - t*this->ay; - qreal ey = this->y + this->vy * t + 0.5 * this->ay * t * t; - qreal y = ey - t*evy - 0.5 * t*t*this->ay; + float t = (particleSystem->timeInt / 1000.0f) - this->t; + float evy = vy - t * this->ay; + float ey = this->y + this->vy * t + 0.5f * this->ay * t * t; + float y = ey - t*evy - 0.5f * t * t * this->ay; this->vy = evy; this->y = y; } -inline void QQuickParticleData::setInstantaneousY(qreal y, QQuickParticleSystem *particleSystem) +inline void QQuickParticleData::setInstantaneousY(float y, QQuickParticleSystem *particleSystem) { - qreal t = (particleSystem->timeInt / 1000.0) - this->t; - this->y = y - t * this->vy - 0.5 * t*t*this->ay; + float t = (particleSystem->timeInt / 1000.0f) - this->t; + this->y = y - t * this->vy - 0.5f * t * t * this->ay; } -inline qreal QQuickParticleData::curX(QQuickParticleSystem *particleSystem) const +inline float QQuickParticleData::curX(QQuickParticleSystem *particleSystem) const { - qreal t = (particleSystem->timeInt / 1000.0) - this->t; - return this->x + this->vx * t + 0.5 * this->ax * t * t; + float t = (particleSystem->timeInt / 1000.0f) - this->t; + return this->x + this->vx * t + 0.5f * this->ax * t * t; } -inline qreal QQuickParticleData::curVX(QQuickParticleSystem *particleSystem) const +inline float QQuickParticleData::curVX(QQuickParticleSystem *particleSystem) const { - qreal t = (particleSystem->timeInt / 1000.0) - this->t; - return this->vx + t*this->ax; + float t = (particleSystem->timeInt / 1000.0f) - this->t; + return this->vx + t * this->ax; } -inline qreal QQuickParticleData::curY(QQuickParticleSystem *particleSystem) const +inline float QQuickParticleData::curY(QQuickParticleSystem *particleSystem) const { - qreal t = (particleSystem->timeInt / 1000.0) - this->t; - return y + vy * t + 0.5 * ay * t * t; + float t = (particleSystem->timeInt / 1000.0f) - this->t; + return y + vy * t + 0.5f * ay * t * t; } -inline qreal QQuickParticleData::curVY(QQuickParticleSystem *particleSystem) const +inline float QQuickParticleData::curVY(QQuickParticleSystem *particleSystem) const { - qreal t = (particleSystem->timeInt / 1000.0) - this->t; + float t = (particleSystem->timeInt / 1000.0f) - this->t; return vy + t*ay; } @@ -576,14 +576,14 @@ inline bool QQuickParticleData::stillAlive(QQuickParticleSystem* system) const { if (!system) return false; - return (t + lifeSpan - EPSILON()) > ((qreal)system->timeInt/1000.0); + return (t + lifeSpan - EPSILON()) > (system->timeInt / 1000.0f); } inline bool QQuickParticleData::alive(QQuickParticleSystem* system) const { if (!system) return false; - qreal st = ((qreal)system->timeInt/1000.0); + float st = (system->timeInt / 1000.0f); return (t + EPSILON()) < st && (t + lifeSpan - EPSILON()) > st; } @@ -591,12 +591,12 @@ inline float QQuickParticleData::lifeLeft(QQuickParticleSystem *particleSystem) { if (!particleSystem) return 0.0f; - return (t + lifeSpan) - (particleSystem->timeInt/1000.0); + return (t + lifeSpan) - (particleSystem->timeInt / 1000.0f); } inline float QQuickParticleData::curSize(QQuickParticleSystem *particleSystem) const { - if (!particleSystem || !lifeSpan) + if (!particleSystem || lifeSpan == 0.0f) return 0.0f; return size + (endSize - size) * (1 - (lifeLeft(particleSystem) / lifeSpan)); } -- cgit v1.2.3 From 562fc162014f78146bd407438512501419ac089b Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Thu, 3 Mar 2016 13:50:50 +0100 Subject: Particles: factor out t^2. According to IEEE754 a * t * t is not the same as a * (t * t), hence the compiler won't lift t^2 out as common expression when in another place 'a' is replaced with 'b'. Now for the particles this doesn't matter as it doesn't need super high precision, nor should any of the calculations come in overflow territory. So by manually introducing t_sq(uare), the compiler can remove duplicate t^2 calculations after inlining. Change-Id: Ibfdb054e34945d7e78eb993fdcedfae886472e83 Reviewed-by: Lars Knoll --- src/particles/qquickparticlesystem_p.h | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/particles/qquickparticlesystem_p.h b/src/particles/qquickparticlesystem_p.h index 2a64735541..3a119f99fe 100644 --- a/src/particles/qquickparticlesystem_p.h +++ b/src/particles/qquickparticlesystem_p.h @@ -493,9 +493,10 @@ private: inline void QQuickParticleData::setInstantaneousAX(float ax, QQuickParticleSystem* particleSystem) { float t = (particleSystem->timeInt / 1000.0f) - this->t; + float t_sq = t * t; float vx = (this->vx + t * this->ax) - t * ax; - float ex = this->x + this->vx * t + 0.5f * this->ax * t * t; - float x = ex - t * vx - 0.5f * t * t * ax; + float ex = this->x + this->vx * t + 0.5f * this->ax * t_sq; + float x = ex - t * vx - 0.5f * t_sq * ax; this->ax = ax; this->vx = vx; @@ -505,9 +506,10 @@ inline void QQuickParticleData::setInstantaneousAX(float ax, QQuickParticleSyste inline void QQuickParticleData::setInstantaneousVX(float vx, QQuickParticleSystem* particleSystem) { float t = (particleSystem->timeInt / 1000.0f) - this->t; + float t_sq = t * t; float evx = vx - t * this->ax; - float ex = this->x + this->vx * t + 0.5f * this->ax * t * t; - float x = ex - t * evx - 0.5f * t * t * this->ax; + float ex = this->x + this->vx * t + 0.5f * this->ax * t_sq; + float x = ex - t * evx - 0.5f * t_sq * this->ax; this->vx = evx; this->x = x; @@ -516,15 +518,17 @@ inline void QQuickParticleData::setInstantaneousVX(float vx, QQuickParticleSyste inline void QQuickParticleData::setInstantaneousX(float x, QQuickParticleSystem* particleSystem) { float t = (particleSystem->timeInt / 1000.0f) - this->t; - this->x = x - t * this->vx - 0.5f * t * t * this->ax; + float t_sq = t * t; + this->x = x - t * this->vx - 0.5f * t_sq * this->ax; } inline void QQuickParticleData::setInstantaneousAY(float ay, QQuickParticleSystem* particleSystem) { float t = (particleSystem->timeInt / 1000.0f) - this->t; + float t_sq = t * t; float vy = (this->vy + t * this->ay) - t * ay; - float ey = this->y + this->vy * t + 0.5f * this->ay * t * t; - float y = ey - t * vy - 0.5f * t * t * ay; + float ey = this->y + this->vy * t + 0.5f * this->ay * t_sq; + float y = ey - t * vy - 0.5f * t_sq * ay; this->ay = ay; this->vy = vy; @@ -534,9 +538,10 @@ inline void QQuickParticleData::setInstantaneousAY(float ay, QQuickParticleSyste inline void QQuickParticleData::setInstantaneousVY(float vy, QQuickParticleSystem* particleSystem) { float t = (particleSystem->timeInt / 1000.0f) - this->t; + float t_sq = t * t; float evy = vy - t * this->ay; - float ey = this->y + this->vy * t + 0.5f * this->ay * t * t; - float y = ey - t*evy - 0.5f * t * t * this->ay; + float ey = this->y + this->vy * t + 0.5f * this->ay * t_sq; + float y = ey - t*evy - 0.5f * t_sq * this->ay; this->vy = evy; this->y = y; @@ -545,13 +550,15 @@ inline void QQuickParticleData::setInstantaneousVY(float vy, QQuickParticleSyste inline void QQuickParticleData::setInstantaneousY(float y, QQuickParticleSystem *particleSystem) { float t = (particleSystem->timeInt / 1000.0f) - this->t; - this->y = y - t * this->vy - 0.5f * t * t * this->ay; + float t_sq = t * t; + this->y = y - t * this->vy - 0.5f * t_sq * this->ay; } inline float QQuickParticleData::curX(QQuickParticleSystem *particleSystem) const { float t = (particleSystem->timeInt / 1000.0f) - this->t; - return this->x + this->vx * t + 0.5f * this->ax * t * t; + float t_sq = t * t; + return this->x + this->vx * t + 0.5f * this->ax * t_sq; } inline float QQuickParticleData::curVX(QQuickParticleSystem *particleSystem) const @@ -563,7 +570,8 @@ inline float QQuickParticleData::curVX(QQuickParticleSystem *particleSystem) con inline float QQuickParticleData::curY(QQuickParticleSystem *particleSystem) const { float t = (particleSystem->timeInt / 1000.0f) - this->t; - return y + vy * t + 0.5f * ay * t * t; + float t_sq = t * t; + return y + vy * t + 0.5f * ay * t_sq; } inline float QQuickParticleData::curVY(QQuickParticleSystem *particleSystem) const -- cgit v1.2.3 From 6c923498cd89e3fb1b4d92f27a9d7c840cee5971 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Fri, 4 Mar 2016 13:36:45 +0100 Subject: Particles: half the number of calls to emittersChanged. When a particle emitter is not yet complete, calling emittersChanged through both groupChanged and systemChanged is unnecessary. Only connect to those signals once after the component is complete, and then call emittersChanged. Also do not call emittersChanged when the particle system component is not complete yet. Change-Id: I67543ce80c9235bd5f72d95352ec96e97a1cf66b Reviewed-by: Lars Knoll --- src/particles/qquickparticleemitter.cpp | 2 ++ src/particles/qquickparticlesystem.cpp | 7 ++++++- src/particles/qquickparticlesystem_p.h | 1 + 3 files changed, 9 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/particles/qquickparticleemitter.cpp b/src/particles/qquickparticleemitter.cpp index c72cbc01e0..6e116d450c 100644 --- a/src/particles/qquickparticleemitter.cpp +++ b/src/particles/qquickparticleemitter.cpp @@ -273,6 +273,8 @@ void QQuickParticleEmitter::componentComplete() { if (!m_system && qobject_cast(parentItem())) setSystem(qobject_cast(parentItem())); + if (m_system) + m_system->finishRegisteringParticleEmitter(this); QQuickItem::componentComplete(); } diff --git a/src/particles/qquickparticlesystem.cpp b/src/particles/qquickparticlesystem.cpp index 5109375f43..17d9e49d63 100644 --- a/src/particles/qquickparticlesystem.cpp +++ b/src/particles/qquickparticlesystem.cpp @@ -618,11 +618,16 @@ void QQuickParticleSystem::registerParticleEmitter(QQuickParticleEmitter* e) if (m_debugMode) qDebug() << "Registering Emitter" << e << "to" << this; m_emitters << QPointer(e);//###How to get them out? +} + +void QQuickParticleSystem::finishRegisteringParticleEmitter(QQuickParticleEmitter* e) +{ connect(e, SIGNAL(particleCountChanged()), this, SLOT(emittersChanged())); connect(e, SIGNAL(groupChanged(QString)), this, SLOT(emittersChanged())); - emittersChanged(); + if (m_componentComplete) + emittersChanged(); e->reset();//Start, so that starttime factors appropriately } diff --git a/src/particles/qquickparticlesystem_p.h b/src/particles/qquickparticlesystem_p.h index 3a119f99fe..b57d55bd98 100644 --- a/src/particles/qquickparticlesystem_p.h +++ b/src/particles/qquickparticlesystem_p.h @@ -430,6 +430,7 @@ public: void registerParticlePainter(QQuickParticlePainter* p); void registerParticleEmitter(QQuickParticleEmitter* e); + void finishRegisteringParticleEmitter(QQuickParticleEmitter *e); void registerParticleAffector(QQuickParticleAffector* a); void registerParticleGroup(QQuickParticleGroup* g); -- cgit v1.2.3 From c44413067da24f5d768f3fde25248cdba5a566bd Mon Sep 17 00:00:00 2001 From: Rafael Roquetto Date: Wed, 9 Mar 2016 09:44:51 -0300 Subject: QNX: Fix compilation QNX only export library functions into the std namespace. Change-Id: Id5c479bb8b4540e26edabd6f50bc0f3f32e72432 Reviewed-by: Simon Hausmann --- src/3rdparty/masm/stubs/ExecutableAllocator.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src') diff --git a/src/3rdparty/masm/stubs/ExecutableAllocator.h b/src/3rdparty/masm/stubs/ExecutableAllocator.h index fe8fc66b03..5a3939b7b2 100644 --- a/src/3rdparty/masm/stubs/ExecutableAllocator.h +++ b/src/3rdparty/masm/stubs/ExecutableAllocator.h @@ -57,6 +57,10 @@ #include #endif +#ifdef __QNXNTO__ +using std::perror; +#endif + namespace JSC { class JSGlobalData; -- cgit v1.2.3 From d87572053a15474a577dcf5714187fbdb4cfec0d Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Wed, 2 Mar 2016 16:26:36 +0100 Subject: QmlProfiler: Send events in smaller batches This enables more parallel data processing and limits the memory usage. Benchmarks with the "planets" example from canvas3d show that this change reduces the time between the profiling being stopped and the last events arriving in the profiling client by about 50%. Change-Id: Iea16f9e2ae3adf584ec4a3c7fc766eaa21740f98 Reviewed-by: Simon Hausmann --- .../qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp | 2 +- .../qmltooling/qmldbg_profiler/qqmlprofilerservice.cpp | 15 +++++++++------ .../qmltooling/qmldbg_profiler/qv4profileradapter.cpp | 4 ++-- .../qmldbg_quickprofiler/qquickprofileradapter.cpp | 2 +- src/qml/debugger/qqmlabstractprofileradapter_p.h | 2 ++ 5 files changed, 15 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp index e89d87e76b..872dcbe718 100644 --- a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp +++ b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp @@ -107,7 +107,7 @@ static void qQmlProfilerDataToByteArrays(const QQmlProfilerData *d, QList &messages) { while (next != data.length()) { - if (data[next].time > until) + if (data[next].time > until || messages.length() > s_numMessagesPerBatch) return data[next].time; qQmlProfilerDataToByteArrays(&(data[next++]), messages); } diff --git a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservice.cpp b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservice.cpp index fc2ba1e094..9e1c8af3e6 100644 --- a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservice.cpp +++ b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservice.cpp @@ -342,12 +342,15 @@ void QQmlProfilerServiceImpl::sendMessages() while (!m_startTimes.empty()) { QQmlAbstractProfilerAdapter *first = m_startTimes.begin().value(); m_startTimes.erase(m_startTimes.begin()); - if (!m_startTimes.empty()) { - qint64 next = first->sendMessages(m_startTimes.begin().key(), messages); - if (next != -1) - m_startTimes.insert(next, first); - } else { - first->sendMessages(std::numeric_limits::max(), messages); + qint64 next = first->sendMessages(m_startTimes.isEmpty() ? + std::numeric_limits::max() : + m_startTimes.begin().key(), messages); + if (next != -1) + m_startTimes.insert(next, first); + + if (messages.length() >= QQmlAbstractProfilerAdapter::s_numMessagesPerBatch) { + emit messagesToClient(name(), messages); + messages.clear(); } } diff --git a/src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.cpp b/src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.cpp index ffacc58817..e91f7fbf51 100644 --- a/src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.cpp +++ b/src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.cpp @@ -105,7 +105,7 @@ qint64 QV4ProfilerAdapter::sendMessages(qint64 until, QList &message while (!m_stack.isEmpty() && (m_functionCallPos == m_functionCallData.length() || m_stack.top() <= m_functionCallData[m_functionCallPos].start)) { - if (m_stack.top() > until) + if (m_stack.top() > until || messages.length() > s_numMessagesPerBatch) return finalizeMessages(until, messages, m_stack.top()); appendMemoryEvents(m_stack.top(), messages); @@ -117,7 +117,7 @@ qint64 QV4ProfilerAdapter::sendMessages(qint64 until, QList &message (m_stack.empty() || m_functionCallData[m_functionCallPos].start < m_stack.top())) { const QV4::Profiling::FunctionCallProperties &props = m_functionCallData[m_functionCallPos]; - if (props.start > until) + if (props.start > until || messages.length() > s_numMessagesPerBatch) return finalizeMessages(until, messages, props.start); appendMemoryEvents(props.start, messages); diff --git a/src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapter.cpp b/src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapter.cpp index 5ca64fda15..0f44ba3dc2 100644 --- a/src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapter.cpp +++ b/src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapter.cpp @@ -153,7 +153,7 @@ static void qQuickProfilerDataToByteArrays(const QQuickProfilerData &data, qint64 QQuickProfilerAdapter::sendMessages(qint64 until, QList &messages) { while (next < m_data.size()) { - if (m_data[next].time <= until) + if (m_data[next].time <= until && messages.length() <= s_numMessagesPerBatch) qQuickProfilerDataToByteArrays(m_data[next++], messages); else return m_data[next].time; diff --git a/src/qml/debugger/qqmlabstractprofileradapter_p.h b/src/qml/debugger/qqmlabstractprofileradapter_p.h index bd93da324d..1104608055 100644 --- a/src/qml/debugger/qqmlabstractprofileradapter_p.h +++ b/src/qml/debugger/qqmlabstractprofileradapter_p.h @@ -64,6 +64,8 @@ class Q_QML_PRIVATE_EXPORT QQmlAbstractProfilerAdapter : public QObject, public Q_OBJECT public: + static const int s_numMessagesPerBatch = 1000; + QQmlAbstractProfilerAdapter(QObject *parent = 0) : QObject(parent), service(0), waiting(true), featuresEnabled(0) {} virtual ~QQmlAbstractProfilerAdapter() {} -- cgit v1.2.3 From 9ca9de7cbc8b045c19899987d6666576399af33d Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Thu, 3 Mar 2016 11:25:27 +0100 Subject: QmlDebug: Support sending multiple messages per packet This reduces the overhead caused by the prepending of service names to packets. When running the planets example from qtcanvas3d through qmlprofiler the average message length, without service name, is 26 bytes. The average full packet, with name and length, is 64 bytes long. In fact, the time between stopping the application and the last message arriving in the profiling client is reduced by 30-50% with this change. Change-Id: I0ffdd0483d45bbe8b092c59a9dcd63c6dc59119c Reviewed-by: Simon Hausmann --- .../qmltooling/qmldbg_server/qqmldebugserver.cpp | 31 +++++++++++++++++----- src/qmldebug/qqmldebugconnection.cpp | 13 +++++---- 2 files changed, 32 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp b/src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp index a5f9ed9a1a..7c18f0c38a 100644 --- a/src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp +++ b/src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp @@ -186,6 +186,7 @@ private: QStringList m_clientPlugins; bool m_gotHello; bool m_blockingMode; + bool m_clientSupportsMultiPackets; QHash m_engineConditions; @@ -274,7 +275,8 @@ static void cleanupOnShutdown() QQmlDebugServerImpl::QQmlDebugServerImpl() : m_connection(0), m_gotHello(false), - m_blockingMode(false) + m_blockingMode(false), + m_clientSupportsMultiPackets(false) { static bool postRoutineAdded = false; if (!postRoutineAdded) { @@ -456,6 +458,11 @@ void QQmlDebugServerImpl::receiveMessage() s_dataStreamVersion = QDataStream::Qt_DefaultCompiledVersion; } + if (!in.atEnd()) + in >> m_clientSupportsMultiPackets; + else + m_clientSupportsMultiPackets = false; + // Send the hello answer immediately, since it needs to arrive before // the plugins below start sending messages. @@ -516,14 +523,16 @@ void QQmlDebugServerImpl::receiveMessage() } else { if (m_gotHello) { - QByteArray message; - in >> message; - QHash::Iterator iter = m_plugins.find(name); if (iter == m_plugins.end()) { qWarning() << "QML Debugger: Message received for missing plugin" << name << '.'; } else { - (*iter)->messageReceived(message); + QQmlDebugService *service = *iter; + QByteArray message; + while (!in.atEnd()) { + in >> message; + service->messageReceived(message); + } } } else { qWarning("QML Debugger: Invalid hello message."); @@ -686,8 +695,16 @@ void QQmlDebugServerImpl::sendMessage(const QString &name, const QByteArray &mes void QQmlDebugServerImpl::sendMessages(const QString &name, const QList &messages) { if (canSendMessage(name)) { - foreach (const QByteArray &message, messages) - doSendMessage(name, message); + if (m_clientSupportsMultiPackets) { + QQmlDebugPacket out; + out << name; + foreach (const QByteArray &message, messages) + out << message; + m_protocol->send(out.data()); + } else { + foreach (const QByteArray &message, messages) + doSendMessage(name, message); + } m_connection->flush(); } } diff --git a/src/qmldebug/qqmldebugconnection.cpp b/src/qmldebug/qqmldebugconnection.cpp index 37b66889cd..35a540bff8 100644 --- a/src/qmldebug/qqmldebugconnection.cpp +++ b/src/qmldebug/qqmldebugconnection.cpp @@ -106,7 +106,8 @@ void QQmlDebugConnection::socketConnected() { Q_D(QQmlDebugConnection); QPacket pack(d->currentDataStreamVersion); - pack << serverId << 0 << protocolVersion << d->plugins.keys() << d->maximumDataStreamVersion; + pack << serverId << 0 << protocolVersion << d->plugins.keys() << d->maximumDataStreamVersion + << true; // We accept multiple messages per packet d->protocol->send(pack.data()); d->flush(); } @@ -221,9 +222,6 @@ void QQmlDebugConnection::protocolReadyRead() qWarning() << "QQmlDebugConnection: Unknown control message id" << op; } } else { - QByteArray message; - pack >> message; - QHash::Iterator iter = d->plugins.find(name); if (iter == d->plugins.end()) { // We can get more messages for plugins we have removed because it takes time to @@ -232,7 +230,12 @@ void QQmlDebugConnection::protocolReadyRead() qWarning() << "QQmlDebugConnection: Message received for missing plugin" << name; } else { - (*iter)->messageReceived(message); + QQmlDebugClient *client = *iter; + QByteArray message; + while (!pack.atEnd()) { + pack >> message; + client->messageReceived(message); + } } } } -- cgit v1.2.3 From 6300f4dde0ab3279b18a0fb29f94cfe142557cba Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Thu, 3 Mar 2016 13:38:27 +0100 Subject: QmlDebug: Reuse packets instead of deleting and recreating them This reduces memory churn as we don't have to reallocate the various QPacket, QBuffer, QByteArray objects and their private classes all the time. Also, subsequent packets often have similar sizes, which makes it beneficial to preallocate the underlying byte array to the size of the previous packet on clear(). In order not to carry the extra reserved space in the lists passed to the debug server, we squeeze the byte arrays before inserting them into the lists. That detaches and copies them, which would have been done anyway when reusing the same packet for the next message. The result is a reduction in the number of temporary memory allocations from QQmlProfilerServiceImpl::sendMessages() by about 75%. Change-Id: Ief98cd7a93a2e8e840e111dee6b346cae00e06bf Reviewed-by: Simon Hausmann --- src/plugins/qmltooling/packetprotocol/qpacket.cpp | 27 +++++++++++- src/plugins/qmltooling/packetprotocol/qpacket_p.h | 4 +- .../qmldbg_profiler/qqmlprofileradapter.cpp | 6 +-- .../qmldbg_profiler/qv4profileradapter.cpp | 51 +++++++++++----------- .../qmldbg_profiler/qv4profileradapter.h | 6 ++- .../qmldbg_quickprofiler/qquickprofileradapter.cpp | 6 +-- 6 files changed, 64 insertions(+), 36 deletions(-) (limited to 'src') diff --git a/src/plugins/qmltooling/packetprotocol/qpacket.cpp b/src/plugins/qmltooling/packetprotocol/qpacket.cpp index c42288e920..fab0a5b189 100644 --- a/src/plugins/qmltooling/packetprotocol/qpacket.cpp +++ b/src/plugins/qmltooling/packetprotocol/qpacket.cpp @@ -108,11 +108,34 @@ QPacket::QPacket(int version, const QByteArray &data) } /*! - Returns raw packet data. + Returns a reference to the raw packet data. */ -QByteArray QPacket::data() const +const QByteArray &QPacket::data() const { return buf.data(); } +/*! + Returns a copy of the raw packet data, with extra reserved space removed. + Mind that this triggers a deep copy. Use it if you anticipate the data to be detached soon anyway. + */ +QByteArray QPacket::squeezedData() const +{ + QByteArray ret = buf.data(); + ret.squeeze(); + return ret; +} + +/*! + Clears the packet, discarding any data. + */ +void QPacket::clear() +{ + buf.reset(); + QByteArray &buffer = buf.buffer(); + // Keep the old size to prevent unnecessary allocations + buffer.reserve(buffer.capacity()); + buffer.truncate(0); +} + QT_END_NAMESPACE diff --git a/src/plugins/qmltooling/packetprotocol/qpacket_p.h b/src/plugins/qmltooling/packetprotocol/qpacket_p.h index a079b244e8..b6fda2411d 100644 --- a/src/plugins/qmltooling/packetprotocol/qpacket_p.h +++ b/src/plugins/qmltooling/packetprotocol/qpacket_p.h @@ -61,7 +61,9 @@ class QPacket : public QDataStream public: QPacket(int version); explicit QPacket(int version, const QByteArray &ba); - QByteArray data() const; + const QByteArray &data() const; + QByteArray squeezedData() const; + void clear(); private: void init(QIODevice::OpenMode mode); diff --git a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp index 872dcbe718..688ced26ec 100644 --- a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp +++ b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp @@ -67,7 +67,7 @@ QQmlProfilerAdapter::QQmlProfilerAdapter(QQmlProfilerService *service, QQmlEngin // (see tst_qqmldebugtrace::trace() benchmark) static void qQmlProfilerDataToByteArrays(const QQmlProfilerData *d, QList &messages) { - QByteArray data; + QQmlDebugPacket ds; Q_ASSERT_X(((d->messageType | d->detailType) & (1 << 31)) == 0, Q_FUNC_INFO, "You can use at most 31 message types and 31 detail types."); for (uint decodedMessageType = 0; (d->messageType >> decodedMessageType) != 0; @@ -81,7 +81,6 @@ static void qQmlProfilerDataToByteArrays(const QQmlProfilerData *d, QListtime << decodedMessageType << decodedDetailType; switch (decodedMessageType) { @@ -99,7 +98,8 @@ static void qQmlProfilerDataToByteArrays(const QQmlProfilerData *d, QList))); } -qint64 QV4ProfilerAdapter::appendMemoryEvents(qint64 until, QList &messages) +qint64 QV4ProfilerAdapter::appendMemoryEvents(qint64 until, QList &messages, + QQmlDebugPacket &d) { while (m_memoryData.length() > m_memoryPos && m_memoryData[m_memoryPos].timestamp <= until) { - QQmlDebugPacket d; QV4::Profiling::MemoryAllocationProperties &props = m_memoryData[m_memoryPos]; d << props.timestamp << MemoryAllocation << props.type << props.size; ++m_memoryPos; - messages.append(d.data()); + messages.append(d.squeezedData()); + d.clear(); } return m_memoryData.length() == m_memoryPos ? -1 : m_memoryData[m_memoryPos].timestamp; } qint64 QV4ProfilerAdapter::finalizeMessages(qint64 until, QList &messages, - qint64 callNext) + qint64 callNext, QQmlDebugPacket &d) { if (callNext == -1) { m_functionCallData.clear(); m_functionCallPos = 0; } - qint64 memoryNext = appendMemoryEvents(until, messages); + qint64 memoryNext = appendMemoryEvents(until, messages, d); if (memoryNext == -1) { m_memoryData.clear(); @@ -101,42 +101,43 @@ qint64 QV4ProfilerAdapter::finalizeMessages(qint64 until, QList &mes qint64 QV4ProfilerAdapter::sendMessages(qint64 until, QList &messages) { + QQmlDebugPacket d; while (true) { while (!m_stack.isEmpty() && (m_functionCallPos == m_functionCallData.length() || m_stack.top() <= m_functionCallData[m_functionCallPos].start)) { if (m_stack.top() > until || messages.length() > s_numMessagesPerBatch) - return finalizeMessages(until, messages, m_stack.top()); + return finalizeMessages(until, messages, m_stack.top(), d); - appendMemoryEvents(m_stack.top(), messages); - QQmlDebugPacket d; + appendMemoryEvents(m_stack.top(), messages, d); d << m_stack.pop() << RangeEnd << Javascript; - messages.append(d.data()); + messages.append(d.squeezedData()); + d.clear(); } while (m_functionCallPos != m_functionCallData.length() && (m_stack.empty() || m_functionCallData[m_functionCallPos].start < m_stack.top())) { const QV4::Profiling::FunctionCallProperties &props = m_functionCallData[m_functionCallPos]; if (props.start > until || messages.length() > s_numMessagesPerBatch) - return finalizeMessages(until, messages, props.start); - - appendMemoryEvents(props.start, messages); - - QQmlDebugPacket d_start; - d_start << props.start << RangeStart << Javascript; - messages.push_back(d_start.data()); - QQmlDebugPacket d_location; - d_location << props.start << RangeLocation << Javascript << props.file << props.line - << props.column; - messages.push_back(d_location.data()); - QQmlDebugPacket d_data; - d_data << props.start << RangeData << Javascript << props.name; - messages.push_back(d_data.data()); + return finalizeMessages(until, messages, props.start, d); + + appendMemoryEvents(props.start, messages, d); + + d << props.start << RangeStart << Javascript; + messages.push_back(d.squeezedData()); + d.clear(); + d << props.start << RangeLocation << Javascript << props.file << props.line + << props.column; + messages.push_back(d.squeezedData()); + d.clear(); + d << props.start << RangeData << Javascript << props.name; + messages.push_back(d.squeezedData()); + d.clear(); m_stack.push(props.end); ++m_functionCallPos; } if (m_stack.empty() && m_functionCallPos == m_functionCallData.length()) - return finalizeMessages(until, messages, -1); + return finalizeMessages(until, messages, -1, d); } } diff --git a/src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.h b/src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.h index 303ccab72c..f2985af98b 100644 --- a/src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.h +++ b/src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.h @@ -53,6 +53,7 @@ #include #include +#include "qqmldebugpacket.h" #include #include @@ -86,8 +87,9 @@ private: int m_functionCallPos; int m_memoryPos; QStack m_stack; - qint64 appendMemoryEvents(qint64 until, QList &messages); - qint64 finalizeMessages(qint64 until, QList &messages, qint64 callNext); + qint64 appendMemoryEvents(qint64 until, QList &messages, QQmlDebugPacket &d); + qint64 finalizeMessages(qint64 until, QList &messages, qint64 callNext, + QQmlDebugPacket &d); static quint64 translateFeatures(quint64 qmlFeatures); }; diff --git a/src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapter.cpp b/src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapter.cpp index 0f44ba3dc2..9a2afd367d 100644 --- a/src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapter.cpp +++ b/src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapter.cpp @@ -79,6 +79,7 @@ QQuickProfilerAdapter::~QQuickProfilerAdapter() static void qQuickProfilerDataToByteArrays(const QQuickProfilerData &data, QList &messages) { + QQmlDebugPacket ds; Q_ASSERT_X(((data.messageType | data.detailType) & (1 << 31)) == 0, Q_FUNC_INFO, "You can use at most 31 message types and 31 detail types."); for (uint decodedMessageType = 0; (data.messageType >> decodedMessageType) != 0; @@ -91,8 +92,6 @@ static void qQuickProfilerDataToByteArrays(const QQuickProfilerData &data, if ((data.detailType & (1 << decodedDetailType)) == 0) continue; - //### using QDataStream is relatively expensive - QQmlDebugPacket ds; ds << data.time << decodedMessageType << decodedDetailType; switch (decodedMessageType) { @@ -145,7 +144,8 @@ static void qQuickProfilerDataToByteArrays(const QQuickProfilerData &data, Q_ASSERT_X(false, Q_FUNC_INFO, "Invalid message type."); break; } - messages << ds.data(); + messages.append(ds.squeezedData()); + ds.clear(); } } } -- cgit v1.2.3 From 644a6a42a45ceb9790df6d6ee1c3ba43c7b9ab10 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Fri, 4 Mar 2016 11:02:54 +0100 Subject: MouseArea: add source property to mouse event It comes from the source() of the QMouseEvent which triggered it. This makes it possible to distinguish real mouse events from those that are synthesized from touch or tablet. And for this we need to import QtQuick 2.7 [ChangeLog][QtQuick][MouseArea] Added mouse.source property to enable distinguishing genuine mouse events from those that are synthesized from touch or tablet events. Change-Id: I568964f63981703bd23e05daac5288518f09d837 Reviewed-by: Robin Burchell --- src/qml/doc/src/qmltypereference.qdoc | 2 +- src/quick/doc/src/qmltypereference.qdoc | 6 ++-- src/quick/items/qquickevents.cpp | 50 +++++++++++++++++++++++++++++++++ src/quick/items/qquickevents_p_p.h | 6 +++- src/quick/items/qquickitemsmodule.cpp | 2 ++ src/quick/items/qquickmousearea.cpp | 10 +++++-- src/quick/items/qquickmousearea_p.h | 2 +- 7 files changed, 69 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/qml/doc/src/qmltypereference.qdoc b/src/qml/doc/src/qmltypereference.qdoc index 31133c862f..f32574fcc1 100644 --- a/src/qml/doc/src/qmltypereference.qdoc +++ b/src/qml/doc/src/qmltypereference.qdoc @@ -55,7 +55,7 @@ are also provided by the \c QtQuick namespace which may be imported as follows: \qml -import QtQuick 2.5 +import QtQuick 2.7 \endqml See the \l{Qt Quick} module documentation for more information about the \c diff --git a/src/quick/doc/src/qmltypereference.qdoc b/src/quick/doc/src/qmltypereference.qdoc index 630e0f58bc..6e6e66e026 100644 --- a/src/quick/doc/src/qmltypereference.qdoc +++ b/src/quick/doc/src/qmltypereference.qdoc @@ -26,7 +26,7 @@ ****************************************************************************/ /*! -\qmlmodule QtQuick 2.5 +\qmlmodule QtQuick 2.7 \title Qt Quick QML Types \ingroup qmlmodules \brief Provides graphical QML types. @@ -34,11 +34,11 @@ The \l{Qt Quick} module provides graphical primitive types. These types are only available in a QML document if that document imports the \c QtQuick namespace. -The current version of the \c QtQuick module is version 2.5, and thus it may be +The current version of the \c QtQuick module is version 2.7, and thus it may be imported via the following statement: \qml -import QtQuick 2.5 +import QtQuick 2.7 \endqml Visit the \l {Qt Quick} module documentation for more diff --git a/src/quick/items/qquickevents.cpp b/src/quick/items/qquickevents.cpp index 7706412a5f..5061c19f1e 100644 --- a/src/quick/items/qquickevents.cpp +++ b/src/quick/items/qquickevents.cpp @@ -263,6 +263,56 @@ Item { \endqml */ +/*! + \qmlproperty int QtQuick::MouseEvent::source + \since 5.7 + + This property holds the source of the mouse event. + + The mouse event source can be used to distinguish between genuine and + artificial mouse events. When using other pointing devices such as + touchscreens and graphics tablets, if the application does not make use of + the actual touch or tablet events, mouse events may be synthesized by the + operating system or by Qt itself. + + The value can be one of: + + \value Qt.MouseEventNotSynthesized The most common value. On platforms where + such information is available, this value indicates that the event + represents a genuine mouse event from the system. + + \value Qt.MouseEventSynthesizedBySystem Indicates that the mouse event was + synthesized from a touch or tablet event by the platform. + + \value Qt.MouseEventSynthesizedByQt Indicates that the mouse event was + synthesized from an unhandled touch or tablet event by Qt. + + \value Qt.MouseEventSynthesizedByApplication Indicates that the mouse event + was synthesized by the application. This allows distinguishing + application-generated mouse events from the ones that are coming from the + system or are synthesized by Qt. + + For example, to react only to events which come from an actual mouse: + \qml + MouseArea { + onPressed: if (mouse.source !== Qt.MouseEventNotSynthesized) { + mouse.accepted = false + } + + onClicked: doSomething() + } + \endqml + + If the handler for the press event rejects the event, it will be propagated + further, and then another Item underneath can handle synthesized events + from touchscreens. For example, if a Flickable is used underneath (and the + MouseArea is not a child of the Flickable), it can be useful for the + MouseArea to handle genuine mouse events in one way, while allowing touch + events to fall through to the Flickable underneath, so that the ability to + flick on a touchscreen is retained. In that case the ability to drag the + Flickable via mouse would be lost, but it does not prevent Flickable from + receiving mouse wheel events. +*/ /*! \qmltype WheelEvent diff --git a/src/quick/items/qquickevents_p_p.h b/src/quick/items/qquickevents_p_p.h index f0d7769705..b28ab555b0 100644 --- a/src/quick/items/qquickevents_p_p.h +++ b/src/quick/items/qquickevents_p_p.h @@ -103,6 +103,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickMouseEvent : public QObject Q_PROPERTY(int button READ button) Q_PROPERTY(int buttons READ buttons) Q_PROPERTY(int modifiers READ modifiers) + Q_PROPERTY(int source READ source REVISION 7) Q_PROPERTY(bool wasHeld READ wasHeld) Q_PROPERTY(bool isClick READ isClick) Q_PROPERTY(bool accepted READ isAccepted WRITE setAccepted) @@ -111,13 +112,14 @@ public: QQuickMouseEvent(qreal x, qreal y, Qt::MouseButton button, Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers , bool isClick=false, bool wasHeld=false) : _x(x), _y(y), _button(button), _buttons(buttons), _modifiers(modifiers) - , _wasHeld(wasHeld), _isClick(isClick), _accepted(true) {} + , _source(Qt::MouseEventNotSynthesized), _wasHeld(wasHeld), _isClick(isClick), _accepted(true) {} qreal x() const { return _x; } qreal y() const { return _y; } int button() const { return _button; } int buttons() const { return _buttons; } int modifiers() const { return _modifiers; } + int source() const { return _source; } bool wasHeld() const { return _wasHeld; } bool isClick() const { return _isClick; } @@ -125,6 +127,7 @@ public: void setX(qreal x) { _x = x; } void setY(qreal y) { _y = y; } void setPosition(const QPointF &point) { _x = point.x(); _y = point.y(); } + void setSource(Qt::MouseEventSource s) { _source = s; } bool isAccepted() { return _accepted; } void setAccepted(bool accepted) { _accepted = accepted; } @@ -135,6 +138,7 @@ private: Qt::MouseButton _button; Qt::MouseButtons _buttons; Qt::KeyboardModifiers _modifiers; + Qt::MouseEventSource _source; bool _wasHeld; bool _isClick; bool _accepted; diff --git a/src/quick/items/qquickitemsmodule.cpp b/src/quick/items/qquickitemsmodule.cpp index ce4f81e1dd..23245e4a7b 100644 --- a/src/quick/items/qquickitemsmodule.cpp +++ b/src/quick/items/qquickitemsmodule.cpp @@ -285,6 +285,8 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor) qmlRegisterType(uri, 2, 7, "GridView"); qmlRegisterType(uri, 2, 7, "TextInput"); qmlRegisterType(uri, 2, 7, "TextEdit"); + + qmlRegisterUncreatableType(uri, 2, 7, nullptr, QQuickMouseEvent::tr("MouseEvent is only available within handlers in MouseArea")); } static void initResources() diff --git a/src/quick/items/qquickmousearea.cpp b/src/quick/items/qquickmousearea.cpp index 42de98eff7..920a86881b 100644 --- a/src/quick/items/qquickmousearea.cpp +++ b/src/quick/items/qquickmousearea.cpp @@ -685,7 +685,7 @@ void QQuickMouseArea::mousePressEvent(QMouseEvent *event) d->startScene = event->windowPos(); d->pressAndHoldTimer.start(QGuiApplication::styleHints()->mousePressAndHoldInterval(), this); setKeepMouseGrab(d->stealMouse); - event->setAccepted(setPressed(event->button(), true)); + event->setAccepted(setPressed(event->button(), true, event->source())); } } @@ -762,6 +762,7 @@ void QQuickMouseArea::mouseMoveEvent(QMouseEvent *event) #endif QQuickMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, false, d->longPress); + me.setSource(event->source()); emit mouseXChanged(&me); me.setPosition(d->lastPos); emit mouseYChanged(&me); @@ -777,7 +778,7 @@ void QQuickMouseArea::mouseReleaseEvent(QMouseEvent *event) QQuickItem::mouseReleaseEvent(event); } else { d->saveEvent(event); - setPressed(event->button(), false); + setPressed(event->button(), false, event->source()); if (!d->pressed) { // no other buttons are pressed #ifndef QT_NO_DRAGANDDROP @@ -802,6 +803,7 @@ void QQuickMouseArea::mouseDoubleClickEvent(QMouseEvent *event) if (d->enabled) { d->saveEvent(event); QQuickMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, true, false); + me.setSource(event->source()); me.setAccepted(d->isDoubleClickConnected()); emit this->doubleClicked(&me); if (!me.isAccepted()) @@ -996,6 +998,7 @@ void QQuickMouseArea::timerEvent(QTimerEvent *event) if (d->pressed && dragged == false && d->hovered == true) { d->longPress = true; QQuickMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, false, d->longPress); + me.setSource(Qt::MouseEventSynthesizedByQt); me.setAccepted(d->isPressAndHoldConnected()); emit pressAndHold(&me); if (!me.isAccepted()) @@ -1158,7 +1161,7 @@ void QQuickMouseArea::setAcceptedButtons(Qt::MouseButtons buttons) } } -bool QQuickMouseArea::setPressed(Qt::MouseButton button, bool p) +bool QQuickMouseArea::setPressed(Qt::MouseButton button, bool p, Qt::MouseEventSource source) { Q_D(QQuickMouseArea); @@ -1173,6 +1176,7 @@ bool QQuickMouseArea::setPressed(Qt::MouseButton button, bool p) if (wasPressed != p) { QQuickMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, isclick, d->longPress); + me.setSource(source); if (p) { d->pressed |= button; if (!d->doubleClick) diff --git a/src/quick/items/qquickmousearea_p.h b/src/quick/items/qquickmousearea_p.h index ae3e3b1e5a..5cd86541d4 100644 --- a/src/quick/items/qquickmousearea_p.h +++ b/src/quick/items/qquickmousearea_p.h @@ -155,7 +155,7 @@ Q_SIGNALS: protected: void setHovered(bool); - bool setPressed(Qt::MouseButton button, bool); + bool setPressed(Qt::MouseButton button, bool p, Qt::MouseEventSource source); bool sendMouseEvent(QMouseEvent *event); void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE; -- cgit v1.2.3 From 201dec50b6f08b740aab9947725f8f5ec36349bb Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Mon, 7 Mar 2016 13:18:56 +0100 Subject: QQuickItemView::forceLayout: Also call layout when d->forceLayout This way callers of forceLayout get a relayout if the dimension of a delegate that affects the itemview content size has just changed but the itemview content size has not been updated yet. This is useful because sometimes in the QML side you want to do things when the item view delegate size has changed but need the item view content size to be already updated. Change-Id: I846984a841e8e14c84d7a700a7ff736196b60afb Reviewed-by: Michael Brasser Reviewed-by: Shawn Rutledge --- src/quick/items/qquickitemview.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/quick/items/qquickitemview.cpp b/src/quick/items/qquickitemview.cpp index 188b347a20..aff03b7539 100644 --- a/src/quick/items/qquickitemview.cpp +++ b/src/quick/items/qquickitemview.cpp @@ -1052,7 +1052,8 @@ QQuickItem *QQuickItemView::itemAt(qreal x, qreal y) const void QQuickItemView::forceLayout() { Q_D(QQuickItemView); - d->applyPendingChanges(); + if (isComponentComplete() && (d->currentChanges.hasPendingChanges() || d->forceLayout)) + d->layout(); } void QQuickItemViewPrivate::applyPendingChanges() -- cgit v1.2.3 From 2e7d4ecdc59942b484159ca827f5d5dbc8787a1b Mon Sep 17 00:00:00 2001 From: Gabriel de Dietrich Date: Mon, 4 May 2015 13:15:37 +0200 Subject: SignalSpy: Support "pressed" signal use-case In some types, e.g. MouseArea, the "pressed" symbol refers both to a signal and to a property. When trying to connect to the signal, we get an error since the engine will resolve to the property instead. We circumvent that by connecting to the signal handler instead, i.e. "onPressed" for the "pressed" signal. Change-Id: I4212b752be4da4ec2209a3447ac41326f1e0bb5d Reviewed-by: J-P Nurmi --- src/imports/testlib/SignalSpy.qml | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/imports/testlib/SignalSpy.qml b/src/imports/testlib/SignalSpy.qml index 7288c57ea0..882e3d3578 100644 --- a/src/imports/testlib/SignalSpy.qml +++ b/src/imports/testlib/SignalSpy.qml @@ -222,14 +222,16 @@ Item { /*! \internal */ function qtest_update() { if (qtest_prevTarget != null) { - var prevFunc = qtest_prevTarget[qtest_prevSignalName] + var prevHandlerName = qtest_signalHandlerName(qtest_prevSignalName) + var prevFunc = qtest_prevTarget[prevHandlerName] if (prevFunc) prevFunc.disconnect(spy.qtest_activated) qtest_prevTarget = null qtest_prevSignalName = "" } if (target != null && signalName != "") { - var func = target[signalName] + var handlerName = qtest_signalHandlerName(signalName) + var func = target[handlerName] if (func === undefined) { spy.qtest_valid = false console.log("Signal '" + signalName + "' not found") @@ -250,4 +252,9 @@ Item { ++qtest_count spy.qtest_signalArguments[spy.qtest_signalArguments.length] = arguments } + + /*! \internal */ + function qtest_signalHandlerName(sn) { + return "on" + sn.substr(0, 1).toUpperCase() + sn.substr(1) + } } -- cgit v1.2.3 From 2a37b8f2b1522558a6144b09db6f9487652a788c Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Fri, 11 Mar 2016 12:27:48 +0100 Subject: V4: Allow the compiler to inline more small methods. Change-Id: Ib2dc03a2535fcbdb10be2dab39593e8dc224fd93 Reviewed-by: Simon Hausmann --- src/qml/compiler/qv4jsir.cpp | 324 ----------------------------------- src/qml/compiler/qv4jsir_p.h | 333 ++++++++++++++++++++++++++++++++++-- src/qml/parser/qqmljsmemorypool_p.h | 4 +- 3 files changed, 325 insertions(+), 336 deletions(-) (limited to 'src') diff --git a/src/qml/compiler/qv4jsir.cpp b/src/qml/compiler/qv4jsir.cpp index a9f8df7748..b28db59190 100644 --- a/src/qml/compiler/qv4jsir.cpp +++ b/src/qml/compiler/qv4jsir.cpp @@ -511,262 +511,6 @@ void Function::setStatementCount(int cnt) _statementCount = cnt; } -BasicBlock::~BasicBlock() -{ - for (Stmt *s : qAsConst(_statements)) { - if (Phi *p = s->asPhi()) { - p->destroyData(); - } else { - break; - } - } -} - -unsigned BasicBlock::newTemp() -{ - Q_ASSERT(!isRemoved()); - return function->tempCount++; -} - -Temp *BasicBlock::TEMP(unsigned index) -{ - Q_ASSERT(!isRemoved()); - Temp *e = function->New(); - e->init(Temp::VirtualRegister, index); - return e; -} - -ArgLocal *BasicBlock::ARG(unsigned index, unsigned scope) -{ - Q_ASSERT(!isRemoved()); - ArgLocal *e = function->New(); - e->init(scope ? ArgLocal::ScopedFormal : ArgLocal::Formal, index, scope); - return e; -} - -ArgLocal *BasicBlock::LOCAL(unsigned index, unsigned scope) -{ - Q_ASSERT(!isRemoved()); - ArgLocal *e = function->New(); - e->init(scope ? ArgLocal::ScopedLocal : ArgLocal::Local, index, scope); - return e; -} - -Expr *BasicBlock::CONST(Type type, double value) -{ - Q_ASSERT(!isRemoved()); - Const *e = function->New(); - if (type == NumberType) { - int ival = (int)value; - // +0 != -0, so we need to convert to double when negating 0 - if (ival == value && !(value == 0 && isNegative(value))) - type = SInt32Type; - else - type = DoubleType; - } else if (type == NullType) { - value = 0; - } else if (type == UndefinedType) { - value = qQNaN(); - } - - e->init(type, value); - return e; -} - -Expr *BasicBlock::STRING(const QString *value) -{ - Q_ASSERT(!isRemoved()); - String *e = function->New(); - e->init(value); - return e; -} - -Expr *BasicBlock::REGEXP(const QString *value, int flags) -{ - Q_ASSERT(!isRemoved()); - RegExp *e = function->New(); - e->init(value, flags); - return e; -} - -Name *BasicBlock::NAME(const QString &id, quint32 line, quint32 column) -{ - Q_ASSERT(!isRemoved()); - Name *e = function->New(); - e->init(function->newString(id), line, column); - return e; -} - -Name *BasicBlock::GLOBALNAME(const QString &id, quint32 line, quint32 column) -{ - Q_ASSERT(!isRemoved()); - Name *e = function->New(); - e->initGlobal(function->newString(id), line, column); - return e; -} - - -Name *BasicBlock::NAME(Name::Builtin builtin, quint32 line, quint32 column) -{ - Q_ASSERT(!isRemoved()); - Name *e = function->New(); - e->init(builtin, line, column); - return e; -} - -Closure *BasicBlock::CLOSURE(int functionInModule) -{ - Q_ASSERT(!isRemoved()); - Closure *clos = function->New(); - clos->init(functionInModule, function->module->functions.at(functionInModule)->name); - return clos; -} - -Expr *BasicBlock::CONVERT(Expr *expr, Type type) -{ - Q_ASSERT(!isRemoved()); - Convert *e = function->New(); - e->init(expr, type); - return e; -} - -Expr *BasicBlock::UNOP(AluOp op, Expr *expr) -{ - Q_ASSERT(!isRemoved()); - Unop *e = function->New(); - e->init(op, expr); - return e; -} - -Expr *BasicBlock::BINOP(AluOp op, Expr *left, Expr *right) -{ - Q_ASSERT(!isRemoved()); - Binop *e = function->New(); - e->init(op, left, right); - return e; -} - -Expr *BasicBlock::CALL(Expr *base, ExprList *args) -{ - Q_ASSERT(!isRemoved()); - Call *e = function->New(); - e->init(base, args); - int argc = 0; - for (ExprList *it = args; it; it = it->next) - ++argc; - function->maxNumberOfArguments = qMax(function->maxNumberOfArguments, argc); - return e; -} - -Expr *BasicBlock::NEW(Expr *base, ExprList *args) -{ - Q_ASSERT(!isRemoved()); - New *e = function->New(); - e->init(base, args); - return e; -} - -Expr *BasicBlock::SUBSCRIPT(Expr *base, Expr *index) -{ - Q_ASSERT(!isRemoved()); - Subscript *e = function->New(); - e->init(base, index); - return e; -} - -Expr *BasicBlock::MEMBER(Expr *base, const QString *name, QQmlPropertyData *property, uchar kind, int attachedPropertiesIdOrEnumValue) -{ - Q_ASSERT(!isRemoved()); - Member*e = function->New(); - e->init(base, name, property, kind, attachedPropertiesIdOrEnumValue); - return e; -} - -Stmt *BasicBlock::EXP(Expr *expr) -{ - Q_ASSERT(!isRemoved()); - if (isTerminated()) - return 0; - - Exp *s = function->NewStmt(); - s->init(expr); - appendStatement(s); - return s; -} - -Stmt *BasicBlock::MOVE(Expr *target, Expr *source) -{ - Q_ASSERT(!isRemoved()); - if (isTerminated()) - return 0; - - Move *s = function->NewStmt(); - s->init(target, source); - appendStatement(s); - return s; -} - -Stmt *BasicBlock::JUMP(BasicBlock *target) -{ - Q_ASSERT(!isRemoved()); - if (isTerminated()) - return 0; - - Jump *s = function->NewStmt(); - s->init(target); - appendStatement(s); - - Q_ASSERT(! out.contains(target)); - out.append(target); - - Q_ASSERT(! target->in.contains(this)); - target->in.append(this); - - return s; -} - -Stmt *BasicBlock::CJUMP(Expr *cond, BasicBlock *iftrue, BasicBlock *iffalse) -{ - Q_ASSERT(!isRemoved()); - if (isTerminated()) - return 0; - - if (iftrue == iffalse) { - MOVE(TEMP(newTemp()), cond); - return JUMP(iftrue); - } - - CJump *s = function->NewStmt(); - s->init(cond, iftrue, iffalse, this); - appendStatement(s); - - Q_ASSERT(! out.contains(iftrue)); - out.append(iftrue); - - Q_ASSERT(! iftrue->in.contains(this)); - iftrue->in.append(this); - - Q_ASSERT(! out.contains(iffalse)); - out.append(iffalse); - - Q_ASSERT(! iffalse->in.contains(this)); - iffalse->in.append(this); - - return s; -} - -Stmt *BasicBlock::RET(Expr *expr) -{ - Q_ASSERT(!isRemoved()); - if (isTerminated()) - return 0; - - Ret *s = function->NewStmt(); - s->init(expr); - appendStatement(s); - return s; -} - void BasicBlock::setStatements(const QVector &newStatements) { Q_ASSERT(!isRemoved()); @@ -784,74 +528,6 @@ void BasicBlock::setStatements(const QVector &newStatements) _statements = newStatements; } -void BasicBlock::appendStatement(Stmt *statement) -{ - Q_ASSERT(!isRemoved()); - if (nextLocation.startLine) - statement->location = nextLocation; - _statements.append(statement); -} - -void BasicBlock::prependStatement(Stmt *stmt) -{ - Q_ASSERT(!isRemoved()); - _statements.prepend(stmt); -} - -void BasicBlock::prependStatements(const QVector &stmts) -{ - Q_ASSERT(!isRemoved()); - QVector newStmts = stmts; - newStmts += _statements; - _statements = newStmts; -} - -void BasicBlock::insertStatementBefore(Stmt *before, Stmt *newStmt) -{ - int idx = _statements.indexOf(before); - Q_ASSERT(idx >= 0); - _statements.insert(idx, newStmt); -} - -void BasicBlock::insertStatementBefore(int index, Stmt *newStmt) -{ - Q_ASSERT(index >= 0); - _statements.insert(index, newStmt); -} - -void BasicBlock::insertStatementBeforeTerminator(Stmt *stmt) -{ - Q_ASSERT(!isRemoved()); - _statements.insert(_statements.size() - 1, stmt); -} - -void BasicBlock::replaceStatement(int index, Stmt *newStmt) -{ - Q_ASSERT(!isRemoved()); - if (Phi *p = _statements[index]->asPhi()) { - p->destroyData(); - } - _statements[index] = newStmt; -} - -void BasicBlock::removeStatement(Stmt *stmt) -{ - Q_ASSERT(!isRemoved()); - if (Phi *p = stmt->asPhi()) { - p->destroyData(); - } - _statements.remove(_statements.indexOf(stmt)); -} - -void BasicBlock::removeStatement(int idx) -{ - Q_ASSERT(!isRemoved()); - if (Phi *p = _statements[idx]->asPhi()) { - p->destroyData(); - } - _statements.remove(idx); -} - CloneExpr::CloneExpr(BasicBlock *block) : block(block), cloned(0) { diff --git a/src/qml/compiler/qv4jsir_p.h b/src/qml/compiler/qv4jsir_p.h index baa338ed52..4dfd63705b 100644 --- a/src/qml/compiler/qv4jsir_p.h +++ b/src/qml/compiler/qv4jsir_p.h @@ -811,7 +811,17 @@ public: , _groupStart(false) , _isRemoved(false) {} - ~BasicBlock(); + + ~BasicBlock() + { + for (Stmt *s : qAsConst(_statements)) { + if (Phi *p = s->asPhi()) { + p->destroyData(); + } else { + break; + } + } + } const QVector &statements() const { @@ -834,15 +844,73 @@ public: return i; } - void appendStatement(Stmt *statement); - void prependStatement(Stmt *stmt); - void prependStatements(const QVector &stmts); - void insertStatementBefore(Stmt *before, Stmt *newStmt); - void insertStatementBefore(int index, Stmt *newStmt); - void insertStatementBeforeTerminator(Stmt *stmt); - void replaceStatement(int index, Stmt *newStmt); - void removeStatement(Stmt *stmt); - void removeStatement(int idx); + void appendStatement(Stmt *statement) + { + Q_ASSERT(!isRemoved()); + if (nextLocation.startLine) + statement->location = nextLocation; + _statements.append(statement); + } + + void prependStatement(Stmt *stmt) + { + Q_ASSERT(!isRemoved()); + _statements.prepend(stmt); + } + + void prependStatements(const QVector &stmts) + { + Q_ASSERT(!isRemoved()); + QVector newStmts = stmts; + newStmts += _statements; + _statements = newStmts; + } + + void insertStatementBefore(Stmt *before, Stmt *newStmt) + { + int idx = _statements.indexOf(before); + Q_ASSERT(idx >= 0); + _statements.insert(idx, newStmt); + } + + void insertStatementBefore(int index, Stmt *newStmt) + { + Q_ASSERT(index >= 0); + _statements.insert(index, newStmt); + } + + void insertStatementBeforeTerminator(Stmt *stmt) + { + Q_ASSERT(!isRemoved()); + _statements.insert(_statements.size() - 1, stmt); + } + + void replaceStatement(int index, Stmt *newStmt) + { + Q_ASSERT(!isRemoved()); + if (Phi *p = _statements[index]->asPhi()) { + p->destroyData(); + } + _statements[index] = newStmt; + } + + void removeStatement(Stmt *stmt) + { + Q_ASSERT(!isRemoved()); + if (Phi *p = stmt->asPhi()) { + p->destroyData(); + } + _statements.remove(_statements.indexOf(stmt)); + } + + void removeStatement(int idx) + { + Q_ASSERT(!isRemoved()); + if (Phi *p = _statements[idx]->asPhi()) { + p->destroyData(); + } + _statements.remove(idx); + } inline bool isEmpty() const { Q_ASSERT(!isRemoved()); @@ -1207,6 +1275,251 @@ protected: BasicBlock *currentBB; }; +inline unsigned BasicBlock::newTemp() +{ + Q_ASSERT(!isRemoved()); + return function->tempCount++; +} + +inline Temp *BasicBlock::TEMP(unsigned index) +{ + Q_ASSERT(!isRemoved()); + Temp *e = function->New(); + e->init(Temp::VirtualRegister, index); + return e; +} + +inline ArgLocal *BasicBlock::ARG(unsigned index, unsigned scope) +{ + Q_ASSERT(!isRemoved()); + ArgLocal *e = function->New(); + e->init(scope ? ArgLocal::ScopedFormal : ArgLocal::Formal, index, scope); + return e; +} + +inline ArgLocal *BasicBlock::LOCAL(unsigned index, unsigned scope) +{ + Q_ASSERT(!isRemoved()); + ArgLocal *e = function->New(); + e->init(scope ? ArgLocal::ScopedLocal : ArgLocal::Local, index, scope); + return e; +} + +inline Expr *BasicBlock::CONST(Type type, double value) +{ + Q_ASSERT(!isRemoved()); + Const *e = function->New(); + if (type == NumberType) { + int ival = (int)value; + // +0 != -0, so we need to convert to double when negating 0 + if (ival == value && !(value == 0 && isNegative(value))) + type = SInt32Type; + else + type = DoubleType; + } else if (type == NullType) { + value = 0; + } else if (type == UndefinedType) { + value = qQNaN(); + } + + e->init(type, value); + return e; +} + +inline Expr *BasicBlock::STRING(const QString *value) +{ + Q_ASSERT(!isRemoved()); + String *e = function->New(); + e->init(value); + return e; +} + +inline Expr *BasicBlock::REGEXP(const QString *value, int flags) +{ + Q_ASSERT(!isRemoved()); + RegExp *e = function->New(); + e->init(value, flags); + return e; +} + +inline Name *BasicBlock::NAME(const QString &id, quint32 line, quint32 column) +{ + Q_ASSERT(!isRemoved()); + Name *e = function->New(); + e->init(function->newString(id), line, column); + return e; +} + +inline Name *BasicBlock::GLOBALNAME(const QString &id, quint32 line, quint32 column) +{ + Q_ASSERT(!isRemoved()); + Name *e = function->New(); + e->initGlobal(function->newString(id), line, column); + return e; +} + + +inline Name *BasicBlock::NAME(Name::Builtin builtin, quint32 line, quint32 column) +{ + Q_ASSERT(!isRemoved()); + Name *e = function->New(); + e->init(builtin, line, column); + return e; +} + +inline Closure *BasicBlock::CLOSURE(int functionInModule) +{ + Q_ASSERT(!isRemoved()); + Closure *clos = function->New(); + clos->init(functionInModule, function->module->functions.at(functionInModule)->name); + return clos; +} + +inline Expr *BasicBlock::CONVERT(Expr *expr, Type type) +{ + Q_ASSERT(!isRemoved()); + Convert *e = function->New(); + e->init(expr, type); + return e; +} + +inline Expr *BasicBlock::UNOP(AluOp op, Expr *expr) +{ + Q_ASSERT(!isRemoved()); + Unop *e = function->New(); + e->init(op, expr); + return e; +} + +inline Expr *BasicBlock::BINOP(AluOp op, Expr *left, Expr *right) +{ + Q_ASSERT(!isRemoved()); + Binop *e = function->New(); + e->init(op, left, right); + return e; +} + +inline Expr *BasicBlock::CALL(Expr *base, ExprList *args) +{ + Q_ASSERT(!isRemoved()); + Call *e = function->New(); + e->init(base, args); + int argc = 0; + for (ExprList *it = args; it; it = it->next) + ++argc; + function->maxNumberOfArguments = qMax(function->maxNumberOfArguments, argc); + return e; +} + +inline Expr *BasicBlock::NEW(Expr *base, ExprList *args) +{ + Q_ASSERT(!isRemoved()); + New *e = function->New(); + e->init(base, args); + return e; +} + +inline Expr *BasicBlock::SUBSCRIPT(Expr *base, Expr *index) +{ + Q_ASSERT(!isRemoved()); + Subscript *e = function->New(); + e->init(base, index); + return e; +} + +inline Expr *BasicBlock::MEMBER(Expr *base, const QString *name, QQmlPropertyData *property, uchar kind, int attachedPropertiesIdOrEnumValue) +{ + Q_ASSERT(!isRemoved()); + Member*e = function->New(); + e->init(base, name, property, kind, attachedPropertiesIdOrEnumValue); + return e; +} + +inline Stmt *BasicBlock::EXP(Expr *expr) +{ + Q_ASSERT(!isRemoved()); + if (isTerminated()) + return 0; + + Exp *s = function->NewStmt(); + s->init(expr); + appendStatement(s); + return s; +} + +inline Stmt *BasicBlock::MOVE(Expr *target, Expr *source) +{ + Q_ASSERT(!isRemoved()); + if (isTerminated()) + return 0; + + Move *s = function->NewStmt(); + s->init(target, source); + appendStatement(s); + return s; +} + +inline Stmt *BasicBlock::JUMP(BasicBlock *target) +{ + Q_ASSERT(!isRemoved()); + if (isTerminated()) + return 0; + + Jump *s = function->NewStmt(); + s->init(target); + appendStatement(s); + + Q_ASSERT(! out.contains(target)); + out.append(target); + + Q_ASSERT(! target->in.contains(this)); + target->in.append(this); + + return s; +} + +inline Stmt *BasicBlock::CJUMP(Expr *cond, BasicBlock *iftrue, BasicBlock *iffalse) +{ + Q_ASSERT(!isRemoved()); + if (isTerminated()) + return 0; + + if (iftrue == iffalse) { + MOVE(TEMP(newTemp()), cond); + return JUMP(iftrue); + } + + CJump *s = function->NewStmt(); + s->init(cond, iftrue, iffalse, this); + appendStatement(s); + + Q_ASSERT(! out.contains(iftrue)); + out.append(iftrue); + + Q_ASSERT(! iftrue->in.contains(this)); + iftrue->in.append(this); + + Q_ASSERT(! out.contains(iffalse)); + out.append(iffalse); + + Q_ASSERT(! iffalse->in.contains(this)); + iffalse->in.append(this); + + return s; +} + +inline Stmt *BasicBlock::RET(Expr *expr) +{ + Q_ASSERT(!isRemoved()); + if (isTerminated()) + return 0; + + Ret *s = function->NewStmt(); + s->init(expr); + appendStatement(s); + return s; +} + } // end of namespace IR } // end of namespace QV4 diff --git a/src/qml/parser/qqmljsmemorypool_p.h b/src/qml/parser/qqmljsmemorypool_p.h index 3659271bc6..08609e2961 100644 --- a/src/qml/parser/qqmljsmemorypool_p.h +++ b/src/qml/parser/qqmljsmemorypool_p.h @@ -94,7 +94,7 @@ public: inline void *allocate(size_t size) { size = (size + 7) & ~7; - if (_ptr && (_ptr + size < _end)) { + if (Q_LIKELY(_ptr && (_ptr + size < _end))) { void *addr = _ptr; _ptr += size; return addr; @@ -111,7 +111,7 @@ public: template Tp *New() { return new (this->allocate(sizeof(Tp))) Tp(); } private: - void *allocate_helper(size_t size) + Q_NEVER_INLINE void *allocate_helper(size_t size) { Q_ASSERT(size < BLOCK_SIZE); -- cgit v1.2.3 From 37547a91b10da7559ee03f9fe2c23f8f22cc1c27 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Mon, 21 Mar 2016 14:32:19 +0100 Subject: SignalSpy: fix qtest_signalHandlerName() Don't add second 'on' prefix if the user passed a signal handler name. Change-Id: I9ba3e61503ca3f9f0ac880dbbb83ca790b98eb47 Reviewed-by: Simon Hausmann Reviewed-by: Mitch Curtis --- src/imports/testlib/SignalSpy.qml | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/imports/testlib/SignalSpy.qml b/src/imports/testlib/SignalSpy.qml index 882e3d3578..200fc725f7 100644 --- a/src/imports/testlib/SignalSpy.qml +++ b/src/imports/testlib/SignalSpy.qml @@ -255,6 +255,8 @@ Item { /*! \internal */ function qtest_signalHandlerName(sn) { + if (sn.substr(0, 2) === "on" && sn[2] === sn[2].toUpperCase()) + return sn return "on" + sn.substr(0, 1).toUpperCase() + sn.substr(1) } } -- cgit v1.2.3 From a34db672a6dd30587b55a27927bdd85c3c4a89a7 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Tue, 22 Mar 2016 14:10:18 +0100 Subject: QQmlEngineDebugService: Make translating the usage simpler. Remove whitespace and formatting from the messages where possible to reduce the chances of them being overlooked by the translators. Change-Id: Ie0d0b29e03b13ae4f46dce1b57dd2a85d427c8c6 Reviewed-by: Ulf Hermann --- .../qmltooling/qmldbg_server/qqmldebugserver.cpp | 80 ++++++++++++---------- 1 file changed, 42 insertions(+), 38 deletions(-) (limited to 'src') diff --git a/src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp b/src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp index 7c18f0c38a..bc259afaa4 100644 --- a/src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp +++ b/src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp @@ -329,7 +329,6 @@ bool QQmlDebugServerImpl::open(const QVariantHash &configuration = QVariantHash( return true; } -#define qUsage qWarning().noquote().nospace void QQmlDebugServerImpl::parseArguments() { // format: qmljsdebugger=port:[,port_to],host:][,block] @@ -378,8 +377,9 @@ void QQmlDebugServerImpl::parseArguments() } else if (!services.isEmpty()) { services.append(strArgument); } else { - qUsage() << tr("QML Debugger: Invalid argument \"%1\" detected. Ignoring the same.") - .arg(strArgument); + const QString message = tr("QML Debugger: Invalid argument \"%1\" detected." + " Ignoring the same.").arg(strArgument); + qWarning("%s", qPrintable(message)); } } @@ -391,43 +391,47 @@ void QQmlDebugServerImpl::parseArguments() else m_thread.setPortRange(portFrom, portTo, hostAddress); } else { - qUsage() << tr("QML Debugger: Ignoring \"-qmljsdebugger=%1\".").arg(args); - qUsage() << tr("The format is \"-qmljsdebugger=[file:|port:][,]" - "[,host:][,block][,services:][,]*\"\n"); - qUsage() << tr("\"file:\" can be used to specify the name of a file the debugger will try " - "to connect to using a QLocalSocket. If \"file:\" is given any \"host:\" and" - "\"port:\" arguments will be ignored.\n"); - qUsage() << tr("\"host:\" and \"port:\" can be used to specify an address and a single " - "port or a range of ports the debugger will try to bind to with a " - "QTcpServer.\n"); - qUsage() << tr("\"block\" makes the debugger and some services wait for clients to be " - "connected and ready before the first QML engine starts.\n"); - qUsage() << tr("\"services:\" can be used to specify which debug services the debugger " - "should load. Some debug services interact badly with others. The V4 " - "debugger should not be loaded when using the QML profiler as it will force " - "any V4 engines to use the JavaScript interpreter rather than the JIT. The " - "following debug services are available by default:"); - qUsage() << QQmlEngineDebugService::s_key << tr("\t- The QML debugger"); - qUsage() << QV4DebugService::s_key << tr("\t- The V4 debugger"); - qUsage() << QQmlInspectorService::s_key << tr("\t- The QML inspector"); - qUsage() << QQmlProfilerService::s_key << tr("\t- The QML profiler"); - qUsage() << QQmlEngineControlService::s_key - << tr("\t- Allows the client to delay the starting and stopping of\n" - "\t\t QML engines until other services are ready. QtCreator\n" - "\t\t uses this service with the QML profiler in order to\n" - "\t\t profile multiple QML engines at the same time."); - qUsage() << QDebugMessageService::s_key - << tr("\t- Sends qDebug() and similar messages over the QML debug\n" - "\t\t connection. QtCreator uses this for showing debug\n" - "\t\t messages in the JavaScript console."); - qUsage() << tr("Other services offered by qmltooling plugins that implement " - "QQmlDebugServiceFactory and which can be found in the standard plugin " - "paths will also be available and can be specified. If no \"services\" " - "argument is given, all services found this way, including the default " - "ones, are loaded."); + QString usage; + QTextStream str(&usage); + str << tr("QML Debugger: Ignoring \"-qmljsdebugger=%1\".").arg(args) << '\n' + << tr("The format is \"-qmljsdebugger=[file:|port:][,]" + "[,host:][,block][,services:][,]*\"") << '\n' + << tr("\"file:\" can be used to specify the name of a file the debugger will try " + "to connect to using a QLocalSocket. If \"file:\" is given any \"host:\" and" + "\"port:\" arguments will be ignored.") << '\n' + << tr("\"host:\" and \"port:\" can be used to specify an address and a single " + "port or a range of ports the debugger will try to bind to with a " + "QTcpServer.") << '\n' + << tr("\"block\" makes the debugger and some services wait for clients to be " + "connected and ready before the first QML engine starts.") << '\n' + << tr("\"services:\" can be used to specify which debug services the debugger " + "should load. Some debug services interact badly with others. The V4 " + "debugger should not be loaded when using the QML profiler as it will force " + "any V4 engines to use the JavaScript interpreter rather than the JIT. The " + "following debug services are available by default:") << '\n' + << QQmlEngineDebugService::s_key << "\t- " << tr("The QML debugger") << '\n' + << QV4DebugService::s_key << "\t- " << tr("The V4 debugger") << '\n' + << QQmlInspectorService::s_key << "\t- " << tr("The QML inspector") << '\n' + << QQmlProfilerService::s_key << "\t- " << tr("The QML profiler") << '\n' + << QQmlEngineControlService::s_key << "\t- " + //: Please preserve the line breaks and formatting + << tr("Allows the client to delay the starting and stopping of\n" + "\t\t QML engines until other services are ready. QtCreator\n" + "\t\t uses this service with the QML profiler in order to\n" + "\t\t profile multiple QML engines at the same time.") + << '\n' << QDebugMessageService::s_key << "\t- " + //: Please preserve the line breaks and formatting + << tr("Sends qDebug() and similar messages over the QML debug\n" + "\t\t connection. QtCreator uses this for showing debug\n" + "\t\t messages in the JavaScript console.") << '\n' + << tr("Other services offered by qmltooling plugins that implement " + "QQmlDebugServiceFactory and which can be found in the standard plugin " + "paths will also be available and can be specified. If no \"services\" " + "argument is given, all services found this way, including the default " + "ones, are loaded."); + qWarning("%s", qPrintable(usage)); } } -#undef qUsage void QQmlDebugServerImpl::receiveMessage() { -- cgit v1.2.3 From 5ce1b892a14a9940e4c8abbbed69bc011394c617 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Tue, 22 Mar 2016 12:57:19 +0100 Subject: QQmlImportDatabase: Introduce utility message function. Reduces the number of messages that need to be translated. Change-Id: I986d3202ac2dcc6c8e197e19c735dd66dad37f39 Reviewed-by: Shawn Rutledge --- src/qml/qml/qqmlimport.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp index 0014ccd3ba..d6c81bcc49 100644 --- a/src/qml/qml/qqmlimport.cpp +++ b/src/qml/qml/qqmlimport.cpp @@ -888,6 +888,11 @@ bool QQmlImportsPrivate::populatePluginPairVector(QVector &res } #endif +static inline QString msgCannotLoadPlugin(const QString &uri, const QString &why) +{ + return QQmlImportDatabase::tr("plugin cannot be loaded for module \"%1\": %2").arg(uri, why); +} + /*! Import an extension defined by a qmldir file. @@ -949,7 +954,7 @@ bool QQmlImportsPrivate::importExtension(const QString &qmldirFilePath, // The reason is that the lower level may add url and line/column numbering information. QQmlError poppedError = errors->takeFirst(); QQmlError error; - error.setDescription(QQmlImportDatabase::tr("plugin cannot be loaded for module \"%1\": %2").arg(uri).arg(poppedError.description())); + error.setDescription(msgCannotLoadPlugin(uri, poppedError.description())); error.setUrl(QUrl::fromLocalFile(qmldirFilePath)); errors->prepend(error); } @@ -1020,10 +1025,7 @@ bool QQmlImportsPrivate::importExtension(const QString &qmldirFilePath, if (errors) { QQmlError error; - error.setDescription( - QQmlImportDatabase::tr( - "plugin cannot be loaded for module \"%1\": library loading is disabled") - .arg(uri)); + error.setDescription(msgCannotLoadPlugin(uri, QQmlImportDatabase::tr("library loading is disabled"))); error.setUrl(QUrl::fromLocalFile(qmldirFilePath)); errors->prepend(error); } -- cgit v1.2.3 From 19d16b33ad2bf7312e2470f31f43fa1acf92f088 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Thu, 17 Mar 2016 16:17:15 +0100 Subject: Allow custom debug connectors Expose a generic method for loading connector plugins in QQmlDebuggingEnabler and don't insist on the two known ones when actually loading them. This allows third-party connector plugins to be loaded, for example to pass QML trace events to a generic tracing library. Change-Id: I4f66dfabdbd0c3aff3676f7e2591e0a6c42f8f7f Reviewed-by: hjk Reviewed-by: Simon Hausmann --- src/qml/debugger/qqmldebug.cpp | 52 ++++++++++++++++++--------------- src/qml/debugger/qqmldebug.h | 3 ++ src/qml/debugger/qqmldebugconnector.cpp | 13 ++++----- 3 files changed, 36 insertions(+), 32 deletions(-) (limited to 'src') diff --git a/src/qml/debugger/qqmldebug.cpp b/src/qml/debugger/qqmldebug.cpp index 64a951d53b..9276bd0544 100644 --- a/src/qml/debugger/qqmldebug.cpp +++ b/src/qml/debugger/qqmldebug.cpp @@ -134,22 +134,11 @@ void QQmlDebuggingEnabler::setServices(const QStringList &services) */ bool QQmlDebuggingEnabler::startTcpDebugServer(int port, StartMode mode, const QString &hostName) { -#ifndef QQML_NO_DEBUG_PROTOCOL - QQmlDebugConnector::setPluginKey(QLatin1String("QQmlDebugServer")); - QQmlDebugConnector *connector = QQmlDebugConnector::instance(); - if (connector) { - QVariantHash configuration; - configuration[QLatin1String("portFrom")] = configuration[QLatin1String("portTo")] = port; - configuration[QLatin1String("block")] = (mode == WaitForClient); - configuration[QLatin1String("hostAddress")] = hostName; - return connector->open(configuration); - } -#else - Q_UNUSED(port); - Q_UNUSED(mode); - Q_UNUSED(hostName); -#endif - return false; + QVariantHash configuration; + configuration[QLatin1String("portFrom")] = configuration[QLatin1String("portTo")] = port; + configuration[QLatin1String("block")] = (mode == WaitForClient); + configuration[QLatin1String("hostAddress")] = hostName; + return startDebugConnector(QLatin1String("QQmlDebugServer"), configuration); } /*! @@ -163,19 +152,34 @@ bool QQmlDebuggingEnabler::startTcpDebugServer(int port, StartMode mode, const Q * returns \c true if a new debug connector was successfully started, or \c false otherwise. */ bool QQmlDebuggingEnabler::connectToLocalDebugger(const QString &socketFileName, StartMode mode) +{ + QVariantHash configuration; + configuration[QLatin1String("fileName")] = socketFileName; + configuration[QLatin1String("block")] = (mode == WaitForClient); + return startDebugConnector(QLatin1String("QQmlDebugServer"), configuration); +} + +/*! + * \since 5.7 + * + * Enables debugging for QML engines created after calling this function. A debug connector plugin + * specified by \a pluginName will be loaded and started using the given \a configuration. Supported + * configuration entries and their semantics depend on the plugin being loaded. You can only start + * one debug connector at a time. A debug connector may have already been started if the + * -qmljsdebugger= command line argument was given. This method returns \c true if a new debug + * connector was successfully started, or \c false otherwise. + */ +bool QQmlDebuggingEnabler::startDebugConnector(const QString &pluginName, + const QVariantHash &configuration) { #ifndef QQML_NO_DEBUG_PROTOCOL - QQmlDebugConnector::setPluginKey(QLatin1String("QQmlDebugServer")); + QQmlDebugConnector::setPluginKey(pluginName); QQmlDebugConnector *connector = QQmlDebugConnector::instance(); - if (connector) { - QVariantHash configuration; - configuration[QLatin1String("fileName")] = socketFileName; - configuration[QLatin1String("block")] = (mode == WaitForClient); + if (connector) return connector->open(configuration); - } #else - Q_UNUSED(fileName); - Q_UNUSED(mode); + Q_UNUSED(pluginName); + Q_UNUSED(configuration); #endif return false; } diff --git a/src/qml/debugger/qqmldebug.h b/src/qml/debugger/qqmldebug.h index eebebefe62..660b9e4d46 100644 --- a/src/qml/debugger/qqmldebug.h +++ b/src/qml/debugger/qqmldebug.h @@ -42,6 +42,7 @@ #include #include +#include QT_BEGIN_NAMESPACE @@ -65,6 +66,8 @@ struct Q_QML_EXPORT QQmlDebuggingEnabler const QString &hostName = QString()); static bool connectToLocalDebugger(const QString &socketFileName, StartMode mode = DoNotWaitForClient); + static bool startDebugConnector(const QString &pluginName, + const QVariantHash &configuration = QVariantHash()); }; // Execute code in constructor before first QQmlEngine is instantiated diff --git a/src/qml/debugger/qqmldebugconnector.cpp b/src/qml/debugger/qqmldebugconnector.cpp index 6edd28ea01..e6d1a218ad 100644 --- a/src/qml/debugger/qqmldebugconnector.cpp +++ b/src/qml/debugger/qqmldebugconnector.cpp @@ -127,18 +127,15 @@ QQmlDebugConnector *QQmlDebugConnector::instance() } if (!params->instance) { - const QString serverConnector = QStringLiteral("QQmlDebugServer"); - const QString nativeConnector = QStringLiteral("QQmlNativeDebugConnector"); - const bool isNative = params->arguments.startsWith(QLatin1String("native")); if (!params->pluginKey.isEmpty()) { - if (params->pluginKey == serverConnector || params->pluginKey == nativeConnector) - params->instance = loadQQmlDebugConnector(params->pluginKey); - else - return 0; // We cannot load anything else, yet + params->instance = loadQQmlDebugConnector(params->pluginKey); } else if (params->arguments.isEmpty()) { return 0; // no explicit class name given and no command line arguments } else { - params->instance = loadQQmlDebugConnector(isNative ? nativeConnector : serverConnector); + params->instance = loadQQmlDebugConnector( + params->arguments.startsWith(QLatin1String("native")) ? + QStringLiteral("QQmlNativeDebugConnector") : + QStringLiteral("QQmlDebugServer")); } if (params->instance) { -- cgit v1.2.3 From c0c369efb3e5ecd9d4b6224267fa213de523ea17 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Tue, 22 Mar 2016 14:00:03 +0100 Subject: V4: Fix debug output for the type inference pass. Change-Id: Ia09b9ed4689b850a5575c72d63ca9677baf631e1 Reviewed-by: Simon Hausmann --- src/qml/compiler/qv4ssa.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'src') diff --git a/src/qml/compiler/qv4ssa.cpp b/src/qml/compiler/qv4ssa.cpp index 6c51044b1e..45ab6be84e 100644 --- a/src/qml/compiler/qv4ssa.cpp +++ b/src/qml/compiler/qv4ssa.cpp @@ -1862,6 +1862,11 @@ public: return worklistSize == 0; } + unsigned size() const + { + return worklistSize; + } + Stmt *takeNext(Stmt *last) { if (isEmpty()) @@ -2213,7 +2218,10 @@ public: QTextStream qout(&buf); qout<<"Typing stmt "; IRPrinter(&qout).print(s); + qout.flush(); qDebug("%s", buf.data().constData()); + + qDebug("%u left in the worklist", _worklist->size()); } if (!run(s)) { @@ -2224,6 +2232,7 @@ public: QTextStream qout(&buf); qout<<"Pushing back stmt: "; IRPrinter(&qout).print(s); + qout.flush(); qDebug("%s", buf.data().constData()); } } else { @@ -2233,6 +2242,7 @@ public: QTextStream qout(&buf); qout<<"Finished: "; IRPrinter(&qout).print(s); + qout.flush(); qDebug("%s", buf.data().constData()); } } @@ -2290,6 +2300,7 @@ private: QTextStream qout(&buf); qout << "Pushing back dependent stmt: "; IRPrinter(&qout).print(s); + qout.flush(); qDebug("%s", buf.data().constData()); } } -- cgit v1.2.3 From 84b72c51382ae861b5815f174cb482d0461c7955 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Tue, 22 Mar 2016 14:45:37 +0100 Subject: V4: prevent re-adding currentStmt to the worklist in type inference. Adding the statement that is currently inferred to the worklist can happen when it's a member access where the base is discovered due to static QML lookup. Change-Id: I0e1b7011c4cfd691320d9b8dbcc660a65a558853 Reviewed-by: Simon Hausmann --- src/qml/compiler/qv4ssa.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/qml/compiler/qv4ssa.cpp b/src/qml/compiler/qv4ssa.cpp index 45ab6be84e..39f23ffc71 100644 --- a/src/qml/compiler/qv4ssa.cpp +++ b/src/qml/compiler/qv4ssa.cpp @@ -2194,6 +2194,7 @@ class TypeInference: public StmtVisitor, public ExprVisitor {} }; TypingResult _ty; + Stmt *_currentStmt; public: TypeInference(QQmlEnginePrivate *qmlEngine, const DefUses &defUses) @@ -2202,6 +2203,7 @@ public: , _tempTypes(_defUses.tempCount()) , _worklist(0) , _ty(UnknownType) + , _currentStmt(nullptr) {} void run(StatementWorklist &w) { @@ -2266,7 +2268,9 @@ private: bool run(Stmt *s) { TypingResult ty; std::swap(_ty, ty); - s->accept(this); + std::swap(_currentStmt, s); + _currentStmt->accept(this); + std::swap(_currentStmt, s); std::swap(_ty, ty); return ty.fullyTyped; } @@ -2305,7 +2309,11 @@ private: } } - *_worklist += _defUses.uses(*t); + for (Stmt *s : qAsConst(_defUses.uses(*t))) { + if (s != _currentStmt) { + *_worklist += s; + } + } } } else { e->type = (Type) ty.type; -- cgit v1.2.3 From bac1268ab00011f901602072277f1a02ebf5b35b Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Tue, 22 Mar 2016 15:08:07 +0100 Subject: QQuick: remove property index from the accessor functions. This parameter was not used. Change-Id: I1e8c0994cad37fc24105e354a80a4fb0131d58ee Reviewed-by: Simon Hausmann --- src/qml/jsruntime/qv4qobjectwrapper.cpp | 4 ++-- src/qml/qml/qqmlaccessors_p.h | 6 +++--- src/qml/qml/qqmlpropertycache.cpp | 1 - src/qml/qml/qqmlpropertycache_p.h | 1 - src/quick/items/qquickitem.cpp | 2 +- 5 files changed, 6 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index f529b4bc7d..5fb44307a9 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -140,8 +140,8 @@ struct ReadAccessor { { Q_ASSERT(property.accessors); - property.accessors->read(object, property.accessorData, output); - if (n) property.accessors->notifier(object, property.accessorData, n); + property.accessors->read(object, output); + if (n) property.accessors->notifier(object, n); } }; diff --git a/src/qml/qml/qqmlaccessors_p.h b/src/qml/qml/qqmlaccessors_p.h index cae4e2c2ff..55562a5307 100644 --- a/src/qml/qml/qqmlaccessors_p.h +++ b/src/qml/qml/qqmlaccessors_p.h @@ -103,7 +103,7 @@ class QQmlNotifier; } while (false); #define QML_PRIVATE_ACCESSOR(clazz, cpptype, name, variable) \ - static void clazz ## _ ## name ## Read(QObject *o, qintptr, void *rv) \ + static void clazz ## _ ## name ## Read(QObject *o, void *rv) \ { \ clazz ## Private *d = clazz ## Private::get(static_cast(o)); \ *static_cast(rv) = d->variable; \ @@ -114,8 +114,8 @@ class QQmlNotifier; class QQmlAccessors { public: - void (*read)(QObject *object, qintptr property, void *output); - void (*notifier)(QObject *object, qintptr property, QQmlNotifier **notifier); + void (*read)(QObject *object, void *output); + void (*notifier)(QObject *object, QQmlNotifier **notifier); }; namespace QQmlAccessorProperties { diff --git a/src/qml/qml/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp index 357b5ae577..3be52cf461 100644 --- a/src/qml/qml/qqmlpropertycache.cpp +++ b/src/qml/qml/qqmlpropertycache.cpp @@ -698,7 +698,6 @@ void QQmlPropertyCache::append(const QMetaObject *metaObject, if (accessorProperty) { data->flags |= QQmlPropertyData::HasAccessors; data->accessors = accessorProperty->accessors; - data->accessorData = accessorProperty->data; } else if (old) { data->markAsOverrideOf(old); } diff --git a/src/qml/qml/qqmlpropertycache_p.h b/src/qml/qml/qqmlpropertycache_p.h index 0b3573c58c..4ff5ee89f9 100644 --- a/src/qml/qml/qqmlpropertycache_p.h +++ b/src/qml/qml/qqmlpropertycache_p.h @@ -209,7 +209,6 @@ public: }; struct { // When HasAccessors QQmlAccessors *accessors; - qintptr accessorData; }; }; int coreIndex; diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp index f2a6e570c0..0c5c6e6c30 100644 --- a/src/quick/items/qquickitem.cpp +++ b/src/quick/items/qquickitem.cpp @@ -107,7 +107,7 @@ void debugFocusTree(QQuickItem *item, QQuickItem *scope = 0, int depth = 1) } } -static void QQuickItem_parentNotifier(QObject *o, qintptr, QQmlNotifier **n) +static void QQuickItem_parentNotifier(QObject *o, QQmlNotifier **n) { QQuickItemPrivate *d = QQuickItemPrivate::get(static_cast(o)); *n = &d->parentNotifier; -- cgit v1.2.3 From 7d512482842b2570b345a32a725d0f28b4e74697 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Wed, 23 Mar 2016 13:23:21 +0100 Subject: V4: Allow some more functions to be inlined. Change-Id: If9d1f87fd7cf0b12d2827c4574109234be7e8ab8 Reviewed-by: Robin Burchell --- src/qml/jsruntime/qv4engine.cpp | 30 ------------------------------ src/qml/jsruntime/qv4engine_p.h | 29 +++++++++++++++++++++++++++++ src/qml/qml/ftw/qhashedstring_p.h | 1 - src/qml/qml/qqmlcontext_p.h | 1 + src/qml/qml/qqmlengine_p.h | 2 +- src/qml/qml/qqmljavascriptexpression.cpp | 2 +- src/quick/items/qquickdrag.cpp | 1 + src/quick/items/qquicktextinput.cpp | 2 +- 8 files changed, 34 insertions(+), 34 deletions(-) (limited to 'src') diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index c28df7d74a..bc64bbfe06 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -576,15 +576,6 @@ ExecutionContext *ExecutionEngine::pushGlobalContext() return currentContext; } -ExecutionContext *ExecutionEngine::parentContext(ExecutionContext *context) const -{ - Value *offset = static_cast(context) + 1; - Q_ASSERT(offset->isInteger()); - int o = offset->integerValue(); - return o ? context - o : 0; -} - - Heap::Object *ExecutionEngine::newObject() { return memoryManager->allocObject(); @@ -770,27 +761,6 @@ Heap::Object *ExecutionEngine::newForEachIteratorObject(Object *o) return obj->d(); } -Heap::QmlContext *ExecutionEngine::qmlContext() const -{ - Heap::ExecutionContext *ctx = current; - - // get the correct context when we're within a builtin function - if (ctx->type == Heap::ExecutionContext::Type_SimpleCallContext && !ctx->outer) - ctx = parentContext(currentContext)->d(); - - if (!ctx->outer) - return 0; - - while (ctx->outer && ctx->outer->type != Heap::ExecutionContext::Type_GlobalContext) - ctx = ctx->outer; - - Q_ASSERT(ctx); - if (ctx->type != Heap::ExecutionContext::Type_QmlContext) - return 0; - - return static_cast(ctx); -} - QObject *ExecutionEngine::qmlScopeObject() const { Heap::QmlContext *ctx = qmlContext(); diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h index 12ed98e6e7..7da4a1c3c1 100644 --- a/src/qml/jsruntime/qv4engine_p.h +++ b/src/qml/jsruntime/qv4engine_p.h @@ -500,6 +500,35 @@ inline void ExecutionEngine::popContext() current = currentContext->d(); } +inline ExecutionContext *ExecutionEngine::parentContext(ExecutionContext *context) const +{ + Value *offset = static_cast(context) + 1; + Q_ASSERT(offset->isInteger()); + int o = offset->integerValue(); + return o ? context - o : 0; +} + +inline Heap::QmlContext *ExecutionEngine::qmlContext() const +{ + Heap::ExecutionContext *ctx = current; + + // get the correct context when we're within a builtin function + if (ctx->type == Heap::ExecutionContext::Type_SimpleCallContext && !ctx->outer) + ctx = parentContext(currentContext)->d(); + + if (!ctx->outer) + return 0; + + while (ctx->outer && ctx->outer->type != Heap::ExecutionContext::Type_GlobalContext) + ctx = ctx->outer; + + Q_ASSERT(ctx); + if (ctx->type != Heap::ExecutionContext::Type_QmlContext) + return 0; + + return static_cast(ctx); +} + inline void Heap::Base::mark(QV4::ExecutionEngine *engine) { diff --git a/src/qml/qml/ftw/qhashedstring_p.h b/src/qml/qml/ftw/qhashedstring_p.h index 4ddac0c2c6..6ff3e4a11b 100644 --- a/src/qml/qml/ftw/qhashedstring_p.h +++ b/src/qml/qml/ftw/qhashedstring_p.h @@ -54,7 +54,6 @@ #include #include #include -#include #include diff --git a/src/qml/qml/qqmlcontext_p.h b/src/qml/qml/qqmlcontext_p.h index 057f4b54c0..48d596418d 100644 --- a/src/qml/qml/qqmlcontext_p.h +++ b/src/qml/qml/qqmlcontext_p.h @@ -66,6 +66,7 @@ #include #include +#include #include QT_BEGIN_NAMESPACE diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h index 88518ac749..4014d20a9e 100644 --- a/src/qml/qml/qqmlengine_p.h +++ b/src/qml/qml/qqmlengine_p.h @@ -375,7 +375,7 @@ const QQmlEnginePrivate *QQmlEnginePrivate::get(const QQmlEngine *e) { Q_ASSERT(e); - return e->d_func(); + return e ? e->d_func() : nullptr; } QQmlEnginePrivate *QQmlEnginePrivate::get(QQmlContext *c) diff --git a/src/qml/qml/qqmljavascriptexpression.cpp b/src/qml/qml/qqmljavascriptexpression.cpp index aef0916239..15d0a571a5 100644 --- a/src/qml/qml/qqmljavascriptexpression.cpp +++ b/src/qml/qml/qqmljavascriptexpression.cpp @@ -298,7 +298,7 @@ void QQmlPropertyCapture::registerQmlDependencies(QV4::ExecutionEngine *engine, // Let the caller check and avoid the function call :) Q_ASSERT(compiledFunction->hasQmlDependencies()); - QQmlEnginePrivate *ep = engine->qmlEngine() ? QQmlEnginePrivate::get(engine->qmlEngine()) : 0; + QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine->qmlEngine()); if (!ep) return; QQmlPropertyCapture *capture = ep->propertyCapture; diff --git a/src/quick/items/qquickdrag.cpp b/src/quick/items/qquickdrag.cpp index 5bfbaf74b2..4aa54b71df 100644 --- a/src/quick/items/qquickdrag.cpp +++ b/src/quick/items/qquickdrag.cpp @@ -46,6 +46,7 @@ #include #include #include +#include #include #include #include diff --git a/src/quick/items/qquicktextinput.cpp b/src/quick/items/qquicktextinput.cpp index 2b1141bea8..6551af4396 100644 --- a/src/quick/items/qquicktextinput.cpp +++ b/src/quick/items/qquicktextinput.cpp @@ -43,7 +43,7 @@ #include "qquicktextutil_p.h" #include - +#include #include #include -- cgit v1.2.3 From 0e010cd9d25c472eaad8f8352e8478597ba7569a Mon Sep 17 00:00:00 2001 From: Nico Vertriest Date: Wed, 30 Mar 2016 14:31:07 +0200 Subject: Minor link issue in qquickpropertychanges MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I88d588a73daa5465c687a18353b2fd5f82cc5aa1 Reviewed-by: Topi Reiniö --- src/quick/util/qquickpropertychanges.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src') diff --git a/src/quick/util/qquickpropertychanges.cpp b/src/quick/util/qquickpropertychanges.cpp index 2ee635d71a..0119aecb7e 100644 --- a/src/quick/util/qquickpropertychanges.cpp +++ b/src/quick/util/qquickpropertychanges.cpp @@ -61,10 +61,9 @@ QT_BEGIN_NAMESPACE /*! \qmltype PropertyChanges - \instantiates QQuickPropertyChanges \inqmlmodule QtQuick \ingroup qtquick-states - \brief Describes new property bindings or values for a state + \brief Describes new property bindings or values for a state. PropertyChanges is used to define the property values or bindings in a \l State. This enables an item's property values to be changed when it -- cgit v1.2.3 From f5afec250cc63ba3a7b1cc78f51d5eb0031dd478 Mon Sep 17 00:00:00 2001 From: Eirik Aavitsland Date: Fri, 18 Mar 2016 10:08:59 +0100 Subject: Remove traces of the discontinued android-no-sdk platform Change-Id: Ie734d6bfcb492c8aeeb18909650a27b1288f2b52 Reviewed-by: Robin Burchell Reviewed-by: Frank Meerkoetter --- src/quick/scenegraph/util/qsgatlastexture.cpp | 2 +- src/quick/scenegraph/util/qsgtexture.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/quick/scenegraph/util/qsgatlastexture.cpp b/src/quick/scenegraph/util/qsgatlastexture.cpp index 57468e5799..68dc813933 100644 --- a/src/quick/scenegraph/util/qsgatlastexture.cpp +++ b/src/quick/scenegraph/util/qsgatlastexture.cpp @@ -137,7 +137,7 @@ Atlas::Atlas(const QSize &size) if (QOpenGLContext::currentContext()->isOpenGLES()) { #endif -#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_NO_SDK) +#if defined(Q_OS_ANDROID) QString *deviceName = static_cast(QGuiApplication::platformNativeInterface()->nativeResourceForIntegration("AndroidDeviceName")); static bool wrongfullyReportsBgra8888Support = deviceName != 0 diff --git a/src/quick/scenegraph/util/qsgtexture.cpp b/src/quick/scenegraph/util/qsgtexture.cpp index 74390334c4..9b9c77dce4 100644 --- a/src/quick/scenegraph/util/qsgtexture.cpp +++ b/src/quick/scenegraph/util/qsgtexture.cpp @@ -716,7 +716,7 @@ void QSGPlainTexture::bind() GLenum externalFormat = GL_RGBA; GLenum internalFormat = GL_RGBA; -#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_NO_SDK) +#if defined(Q_OS_ANDROID) QString *deviceName = static_cast(QGuiApplication::platformNativeInterface()->nativeResourceForIntegration("AndroidDeviceName")); static bool wrongfullyReportsBgra8888Support = deviceName != 0 -- cgit v1.2.3 From 02ebc8ba89be301a8bb8761142ec629b27a1493f Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Tue, 29 Mar 2016 14:20:20 +0200 Subject: Add a note saying that QQuickWidget::rootObject can return null Change-Id: Ia5db63c39287d23c3ed279aa5671a9e7bc7b26c0 Reviewed-by: Gunnar Sletta --- src/quickwidgets/qquickwidget.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/quickwidgets/qquickwidget.cpp b/src/quickwidgets/qquickwidget.cpp index 83e617f8e4..f720513b85 100644 --- a/src/quickwidgets/qquickwidget.cpp +++ b/src/quickwidgets/qquickwidget.cpp @@ -986,7 +986,9 @@ QSize QQuickWidget::initialSize() const } /*! - Returns the view's root \l {QQuickItem} {item}. + Returns the view's root \l {QQuickItem} {item}. Can be null + when setContents/setSource has not been called, if they were called with + broken QtQuick code or while the QtQuick contents are being created. */ QQuickItem *QQuickWidget::rootObject() const { -- cgit v1.2.3 From ad1b0b6e7a6b5d266a36138295e6a58ad98fd1ef Mon Sep 17 00:00:00 2001 From: Rolland Dudemaine Date: Tue, 29 Mar 2016 06:55:56 +0200 Subject: Remove dummy implementation for Pass*Ptr operator=(). This resolves a lot of warnings when building with the GHS toolchain. Change-Id: I061dac0bf42f6a8158afe8eee9c898e8f7ee4dd7 Reviewed-by: Frank Meerkoetter Reviewed-by: Simon Hausmann --- src/3rdparty/masm/stubs/wtf/PassOwnPtr.h | 4 ++-- src/3rdparty/masm/stubs/wtf/PassRefPtr.h | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/3rdparty/masm/stubs/wtf/PassOwnPtr.h b/src/3rdparty/masm/stubs/wtf/PassOwnPtr.h index 21436b0bec..0e18132f77 100644 --- a/src/3rdparty/masm/stubs/wtf/PassOwnPtr.h +++ b/src/3rdparty/masm/stubs/wtf/PassOwnPtr.h @@ -101,8 +101,8 @@ public: private: template friend PassOwnPtr adoptPtr(PtrType*); - PassOwnPtr& operator=(const PassOwnPtr&) - {} + PassOwnPtr& operator=(const PassOwnPtr& t); + mutable QScopedPointer m_ptr; }; diff --git a/src/3rdparty/masm/stubs/wtf/PassRefPtr.h b/src/3rdparty/masm/stubs/wtf/PassRefPtr.h index 1a837464fa..f072e70dd7 100644 --- a/src/3rdparty/masm/stubs/wtf/PassRefPtr.h +++ b/src/3rdparty/masm/stubs/wtf/PassRefPtr.h @@ -81,8 +81,7 @@ public: } private: - PassRefPtr& operator=(const PassRefPtr&) - {} + PassRefPtr& operator=(const PassRefPtr& t); template friend PassRefPtr adoptRef(PtrType*); mutable T* m_ptr; -- cgit v1.2.3 From fcbbedc3c21ff69d9251264dd708d6ca66c09359 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Mon, 4 Apr 2016 15:58:45 +0200 Subject: QML: do not re-use the resolver data for members. On successful lookup, the resolver data was cleared and re-used for the resolved member. The effect is that a second time the resolver is used, it will not be able to do the same lookup, resulting in it returning an unknown type. Because the same expression might need to be resolved multiple times (e.g. when a dependency changes type), this results in the wrong type (var), and then more iterations to propagate this wrong type to all usages. Instead, return a new resolver with its own data for the resolved member. This way, a member access on this result can be resolved correctly by this new resolver. Change-Id: Ia930c08a2e4a2182d800192547fc03cba209c78c Reviewed-by: Simon Hausmann --- src/qml/compiler/qqmlirbuilder.cpp | 66 +++++++++++++++++++++++++------------- src/qml/compiler/qv4jsir_p.h | 29 +++++++++++++++-- src/qml/compiler/qv4ssa.cpp | 23 +------------ 3 files changed, 71 insertions(+), 47 deletions(-) (limited to 'src') diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp index a34c1cbf0e..1960f1d65b 100644 --- a/src/qml/compiler/qqmlirbuilder.cpp +++ b/src/qml/compiler/qqmlirbuilder.cpp @@ -1589,7 +1589,9 @@ enum MetaObjectResolverFlags { static void initMetaObjectResolver(QV4::IR::MemberExpressionResolver *resolver, QQmlPropertyCache *metaObject); -static QV4::IR::Type resolveQmlType(QQmlEnginePrivate *qmlEngine, QV4::IR::MemberExpressionResolver *resolver, QV4::IR::Member *member) +static QV4::IR::DiscoveredType resolveQmlType(QQmlEnginePrivate *qmlEngine, + const QV4::IR::MemberExpressionResolver *resolver, + QV4::IR::Member *member) { QV4::IR::Type result = QV4::IR::VarType; @@ -1600,7 +1602,6 @@ static QV4::IR::Type resolveQmlType(QQmlEnginePrivate *qmlEngine, QV4::IR::Membe int value = type->enumValue(qmlEngine, *member->name, &ok); if (ok) { member->setEnumValue(value); - resolver->clear(); return QV4::IR::SInt32Type; } } @@ -1611,25 +1612,30 @@ static QV4::IR::Type resolveQmlType(QQmlEnginePrivate *qmlEngine, QV4::IR::Membe tdata->release(); // Decrease the reference count added from QQmlTypeLoader::getType() // When a singleton tries to reference itself, it may not be complete yet. if (tdata->isComplete()) { - initMetaObjectResolver(resolver, qmlEngine->propertyCacheForType(tdata->compiledData()->metaTypeId)); - resolver->flags |= AllPropertiesAreFinal; - return resolver->resolveMember(qmlEngine, resolver, member); + auto newResolver = resolver->owner->New(); + newResolver->owner = resolver->owner; + initMetaObjectResolver(newResolver, qmlEngine->propertyCacheForType(tdata->compiledData()->metaTypeId)); + newResolver->flags |= AllPropertiesAreFinal; + return newResolver->resolveMember(qmlEngine, newResolver, member); } } else if (type->isSingleton()) { const QMetaObject *singletonMeta = type->singletonInstanceInfo()->instanceMetaObject; if (singletonMeta) { // QJSValue-based singletons cannot be accelerated - initMetaObjectResolver(resolver, qmlEngine->cache(singletonMeta)); + auto newResolver = resolver->owner->New(); + newResolver->owner = resolver->owner; + initMetaObjectResolver(newResolver, qmlEngine->cache(singletonMeta)); member->kind = QV4::IR::Member::MemberOfSingletonObject; - return resolver->resolveMember(qmlEngine, resolver, member); + return newResolver->resolveMember(qmlEngine, newResolver, member); } } else if (const QMetaObject *attachedMeta = type->attachedPropertiesType(qmlEngine)) { QQmlPropertyCache *cache = qmlEngine->cache(attachedMeta); - initMetaObjectResolver(resolver, cache); + auto newResolver = resolver->owner->New(); + newResolver->owner = resolver->owner; + initMetaObjectResolver(newResolver, cache); member->setAttachedPropertiesId(type->attachedPropertiesId(qmlEngine)); - return resolver->resolveMember(qmlEngine, resolver, member); + return newResolver->resolveMember(qmlEngine, newResolver, member); } - resolver->clear(); return result; } @@ -1643,7 +1649,9 @@ static void initQmlTypeResolver(QV4::IR::MemberExpressionResolver *resolver, QQm resolver->flags = 0; } -static QV4::IR::Type resolveImportNamespace(QQmlEnginePrivate *, QV4::IR::MemberExpressionResolver *resolver, QV4::IR::Member *member) +static QV4::IR::DiscoveredType resolveImportNamespace( + QQmlEnginePrivate *, const QV4::IR::MemberExpressionResolver *resolver, + QV4::IR::Member *member) { QV4::IR::Type result = QV4::IR::VarType; QQmlTypeNameCache *typeNamespace = static_cast(resolver->extraData); @@ -1660,19 +1668,21 @@ static QV4::IR::Type resolveImportNamespace(QQmlEnginePrivate *, QV4::IR::Member // through the singleton getter in the run-time. Until then we // can't accelerate access :( if (!r.type->isSingleton()) { - initQmlTypeResolver(resolver, r.type); - return QV4::IR::QObjectType; + auto newResolver = resolver->owner->New(); + newResolver->owner = resolver->owner; + initQmlTypeResolver(newResolver, r.type); + return QV4::IR::DiscoveredType(newResolver); } } else { Q_ASSERT(false); // How can this happen? } } - resolver->clear(); return result; } -static void initImportNamespaceResolver(QV4::IR::MemberExpressionResolver *resolver, QQmlTypeNameCache *imports, const void *importNamespace) +static void initImportNamespaceResolver(QV4::IR::MemberExpressionResolver *resolver, + QQmlTypeNameCache *imports, const void *importNamespace) { resolver->resolveMember = &resolveImportNamespace; resolver->data = const_cast(importNamespace); @@ -1680,7 +1690,9 @@ static void initImportNamespaceResolver(QV4::IR::MemberExpressionResolver *resol resolver->flags = 0; } -static QV4::IR::Type resolveMetaObjectProperty(QQmlEnginePrivate *qmlEngine, QV4::IR::MemberExpressionResolver *resolver, QV4::IR::Member *member) +static QV4::IR::DiscoveredType resolveMetaObjectProperty( + QQmlEnginePrivate *qmlEngine, const QV4::IR::MemberExpressionResolver *resolver, + QV4::IR::Member *member) { QV4::IR::Type result = QV4::IR::VarType; QQmlPropertyCache *metaObject = static_cast(resolver->data); @@ -1694,7 +1706,6 @@ static QV4::IR::Type resolveMetaObjectProperty(QQmlEnginePrivate *qmlEngine, QV4 int value = metaEnum.keyToValue(enumName.constData(), &ok); if (ok) { member->setEnumValue(value); - resolver->clear(); return QV4::IR::SInt32Type; } } @@ -1739,21 +1750,25 @@ static QV4::IR::Type resolveMetaObjectProperty(QQmlEnginePrivate *qmlEngine, QV4 default: if (property->isQObject()) { if (QQmlPropertyCache *cache = qmlEngine->propertyCacheForType(property->propType)) { - initMetaObjectResolver(resolver, cache); - return QV4::IR::QObjectType; + auto newResolver = resolver->owner->New(); + newResolver->owner = resolver->owner; + initMetaObjectResolver(newResolver, cache); + return QV4::IR::DiscoveredType(newResolver); } } else if (const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(property->propType)) { if (QQmlPropertyCache *cache = qmlEngine->cache(valueTypeMetaObject)) { - initMetaObjectResolver(resolver, cache); - resolver->flags |= ResolveTypeInformationOnly; - return QV4::IR::QObjectType; + auto newResolver = resolver->owner->New(); + newResolver->owner = resolver->owner; + initMetaObjectResolver(newResolver, cache); + newResolver->flags |= ResolveTypeInformationOnly; + return QV4::IR::DiscoveredType(newResolver); } } break; } } } - resolver->clear(); + return result; } @@ -1809,6 +1824,7 @@ QV4::IR::Expr *JSCodeGen::fallbackNameLookup(const QString &name, int line, int result = _block->TEMP(result->index); if (mapping.type) { result->memberResolver = _function->New(); + result->memberResolver->owner = _function; initMetaObjectResolver(result->memberResolver, mapping.type); result->memberResolver->flags |= AllPropertiesAreFinal; } @@ -1831,6 +1847,7 @@ QV4::IR::Expr *JSCodeGen::fallbackNameLookup(const QString &name, int line, int result = _block->TEMP(result->index); result->memberResolver = _function->New(); + result->memberResolver->owner = _function; initQmlTypeResolver(result->memberResolver, r.type); return result; } else { @@ -1839,6 +1856,7 @@ QV4::IR::Expr *JSCodeGen::fallbackNameLookup(const QString &name, int line, int namespaceName->freeOfSideEffects = true; QV4::IR::Temp *result = _block->TEMP(_block->newTemp()); result->memberResolver = _function->New(); + result->memberResolver->owner = _function; initImportNamespaceResolver(result->memberResolver, imports, r.importNamespace); _block->MOVE(result, namespaceName); @@ -1855,6 +1873,7 @@ QV4::IR::Expr *JSCodeGen::fallbackNameLookup(const QString &name, int line, int if (pd) { QV4::IR::Temp *base = _block->TEMP(_qmlContextTemp); base->memberResolver = _function->New(); + base->memberResolver->owner = _function; initMetaObjectResolver(base->memberResolver, _scopeObject); return _block->MEMBER(base, _function->newString(name), pd, QV4::IR::Member::MemberOfQmlScopeObject); } @@ -1868,6 +1887,7 @@ QV4::IR::Expr *JSCodeGen::fallbackNameLookup(const QString &name, int line, int if (pd) { QV4::IR::Temp *base = _block->TEMP(_qmlContextTemp); base->memberResolver = _function->New(); + base->memberResolver->owner = _function; initMetaObjectResolver(base->memberResolver, _contextObject); return _block->MEMBER(base, _function->newString(name), pd, QV4::IR::Member::MemberOfQmlContextObject); } diff --git a/src/qml/compiler/qv4jsir_p.h b/src/qml/compiler/qv4jsir_p.h index 4dfd63705b..eafecae494 100644 --- a/src/qml/compiler/qv4jsir_p.h +++ b/src/qml/compiler/qv4jsir_p.h @@ -244,13 +244,37 @@ struct StmtVisitor { virtual void visitPhi(Phi *) = 0; }; +struct MemberExpressionResolver; + +struct DiscoveredType { + int type; + MemberExpressionResolver *memberResolver; + + DiscoveredType() : type(UnknownType), memberResolver(0) {} + DiscoveredType(Type t) : type(t), memberResolver(0) { Q_ASSERT(type != QObjectType); } + explicit DiscoveredType(int t) : type(t), memberResolver(0) { Q_ASSERT(type != QObjectType); } + explicit DiscoveredType(MemberExpressionResolver *memberResolver) + : type(QObjectType) + , memberResolver(memberResolver) + { Q_ASSERT(memberResolver); } + + bool test(Type t) const { return type & t; } + bool isNumber() const { return (type & NumberType) && !(type & ~NumberType); } + + bool operator!=(Type other) const { return type != other; } + bool operator==(Type other) const { return type == other; } + bool operator==(const DiscoveredType &other) const { return type == other.type; } + bool operator!=(const DiscoveredType &other) const { return type != other.type; } +}; struct MemberExpressionResolver { - typedef Type (*ResolveFunction)(QQmlEnginePrivate *engine, MemberExpressionResolver *resolver, Member *member); + typedef DiscoveredType (*ResolveFunction)(QQmlEnginePrivate *engine, + const MemberExpressionResolver *resolver, + Member *member); MemberExpressionResolver() - : resolveMember(0), data(0), extraData(0), flags(0) {} + : resolveMember(0), data(0), extraData(0), owner(nullptr), flags(0) {} bool isValid() const { return !!resolveMember; } void clear() { *this = MemberExpressionResolver(); } @@ -258,6 +282,7 @@ struct MemberExpressionResolver ResolveFunction resolveMember; void *data; // Could be pointer to meta object, importNameSpace, etc. - depends on resolveMember implementation void *extraData; // Could be QQmlTypeNameCache + Function *owner; unsigned int flags; }; diff --git a/src/qml/compiler/qv4ssa.cpp b/src/qml/compiler/qv4ssa.cpp index 39f23ffc71..6a4c1c54d6 100644 --- a/src/qml/compiler/qv4ssa.cpp +++ b/src/qml/compiler/qv4ssa.cpp @@ -2073,27 +2073,6 @@ protected: } }; -struct DiscoveredType { - int type; - MemberExpressionResolver *memberResolver; - - DiscoveredType() : type(UnknownType), memberResolver(0) {} - DiscoveredType(Type t) : type(t), memberResolver(0) { Q_ASSERT(type != QObjectType); } - explicit DiscoveredType(int t) : type(t), memberResolver(0) { Q_ASSERT(type != QObjectType); } - explicit DiscoveredType(MemberExpressionResolver *memberResolver) - : type(QObjectType) - , memberResolver(memberResolver) - { Q_ASSERT(memberResolver); } - - bool test(Type t) const { return type & t; } - bool isNumber() const { return (type & NumberType) && !(type & ~NumberType); } - - bool operator!=(Type other) const { return type != other; } - bool operator==(Type other) const { return type == other; } - bool operator==(const DiscoveredType &other) const { return type == other.type; } - bool operator!=(const DiscoveredType &other) const { return type != other.type; } -}; - class PropagateTempTypes: public StmtVisitor, ExprVisitor { const DefUses &defUses; @@ -2449,7 +2428,7 @@ protected: if (_ty.fullyTyped && _ty.type.memberResolver && _ty.type.memberResolver->isValid()) { MemberExpressionResolver *resolver = _ty.type.memberResolver; - _ty.type.type = resolver->resolveMember(qmlEngine, resolver, e); + _ty.type = resolver->resolveMember(qmlEngine, resolver, e); } else _ty.type = VarType; } -- cgit v1.2.3