aboutsummaryrefslogtreecommitdiffstats
path: root/src/particles
diff options
context:
space:
mode:
authorGiuseppe D'Angelo <giuseppe.dangelo@kdab.com>2020-05-19 14:43:49 +0200
committerGiuseppe D'Angelo <giuseppe.dangelo@kdab.com>2020-05-27 16:25:56 +0200
commit27c0034d6bb0df50d4479e42fc82fcd74b03d810 (patch)
treefe5daa30e19287d79d5701fcdc90fe09fc1f786b /src/particles
parent5ce2d540be875041b38b481e3caef295071c79ee (diff)
Particles: reduce memory allocations by flattening a set
When an affector acts on a particle, it will add it to a set of "seen" particles. This means an allocation, per particle, per frame. In Qt 6 the problem is less dramatic due to the new QHash implementation, which uses "wider" buckets, but in Qt 5 this is hundreds of memory allocations (and deallocations) per frame. Just reimplement a minimal flat-set API for this use case, and replace the QSet usages with it. On a testcase with 200 active particles, this reduces memory allocations from ~20'000 per second to 0 when the scene is "stable". Pick-to: 5.15 Change-Id: I4be1e12a23b8dffca91955148532db243e383a4c Reviewed-by: Lars Knoll <lars.knoll@qt.io> Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
Diffstat (limited to 'src/particles')
-rw-r--r--src/particles/CMakeLists.txt1
-rw-r--r--src/particles/particles.pri1
-rw-r--r--src/particles/qquickparticleaffector_p.h3
-rw-r--r--src/particles/qquickparticleflatset_p.h145
-rw-r--r--src/particles/qquickparticlesystem.cpp2
-rw-r--r--src/particles/qquickparticlesystem_p.h3
6 files changed, 152 insertions, 3 deletions
diff --git a/src/particles/CMakeLists.txt b/src/particles/CMakeLists.txt
index f2da8b3e1c..9265da61ab 100644
--- a/src/particles/CMakeLists.txt
+++ b/src/particles/CMakeLists.txt
@@ -24,6 +24,7 @@ qt_add_module(QuickParticles
qquickparticleaffector.cpp qquickparticleaffector_p.h
qquickparticleemitter.cpp qquickparticleemitter_p.h
qquickparticleextruder.cpp qquickparticleextruder_p.h
+ qquickparticleflatset_p.h
qquickparticlegroup.cpp qquickparticlegroup_p.h
qquickparticlepainter.cpp qquickparticlepainter_p.h
qquickparticlesmodule.cpp qquickparticlesmodule_p.h
diff --git a/src/particles/particles.pri b/src/particles/particles.pri
index 576d826903..adb43b5e45 100644
--- a/src/particles/particles.pri
+++ b/src/particles/particles.pri
@@ -13,6 +13,7 @@ HEADERS += \
$$PWD/qquickparticleaffector_p.h \
$$PWD/qquickparticleemitter_p.h \
$$PWD/qquickparticleextruder_p.h \
+ $$PWD/qquickparticleflatset_p.h \
$$PWD/qquickparticlepainter_p.h \
$$PWD/qquickparticlesmodule_p.h \
$$PWD/qquickparticlesystem_p.h \
diff --git a/src/particles/qquickparticleaffector_p.h b/src/particles/qquickparticleaffector_p.h
index 22cebbead1..f5975708fa 100644
--- a/src/particles/qquickparticleaffector_p.h
+++ b/src/particles/qquickparticleaffector_p.h
@@ -55,6 +55,7 @@
#include "qquickparticlesystem_p.h"
#include "qquickparticleextruder_p.h"
#include "qtquickparticlesglobal_p.h"
+#include "qquickparticleflatset_p.h"
QT_BEGIN_NAMESPACE
@@ -195,7 +196,7 @@ protected:
static const qreal simulationCutoff;
QPointF m_offset;
- QSet<QPair<int, int> > m_onceOffed;
+ QtQuickParticlesPrivate::QFlatSet<QPair<int, int>> m_onceOffed;
private:
QSet<int> m_groupIds;
bool m_updateIntSet;
diff --git a/src/particles/qquickparticleflatset_p.h b/src/particles/qquickparticleflatset_p.h
new file mode 100644
index 0000000000..77946c8b87
--- /dev/null
+++ b/src/particles/qquickparticleflatset_p.h
@@ -0,0 +1,145 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKPARTICLEFLATSET_P_H
+#define QQUICKPARTICLEFLATSET_P_H
+
+#include <QtGlobal>
+
+#include <vector>
+#include <algorithm>
+#include <iterator>
+
+QT_BEGIN_NAMESPACE
+
+// Minimal API, just for the consumption of Qt Quick Particles.
+// For extra safety, it's in a private namespace
+
+namespace QtQuickParticlesPrivate {
+
+template <typename T>
+class QFlatSet
+{
+public:
+ using iterator = typename std::vector<T>::iterator;
+ using const_iterator = typename std::vector<T>::const_iterator;
+ using value_type = typename std::vector<T>::value_type;
+ using size_type = int;
+
+ iterator find(const T &t)
+ {
+ return std::find(begin(), end(), t);
+ }
+
+ const_iterator find(const T &t) const
+ {
+ return std::find(begin(), end(), t);
+ }
+
+ bool contains(const T &t) const
+ {
+ return find(t) != end();
+ }
+
+ void clear()
+ {
+ m_data.clear();
+ }
+
+ void reserve(int capacity)
+ {
+ m_data.reserve(capacity);
+ }
+
+ iterator insert(const T &t)
+ {
+ auto i = find(t);
+ if (i != end())
+ return i;
+ T copy = t;
+ m_data.push_back(std::move(copy));
+ return std::prev(m_data.end());
+ }
+
+ iterator insert(T &&t)
+ {
+ auto i = find(t);
+ if (i != end())
+ return i;
+ m_data.push_back(std::move(t));
+ return std::prev(m_data.end());
+ }
+
+ size_type remove(const T &t)
+ {
+ auto i = std::find(m_data.begin(), m_data.end(), t);
+ if (i != m_data.end()) {
+ m_data.erase(i);
+ return 1;
+ }
+ return 0;
+ }
+
+ iterator operator<<(const T &t)
+ {
+ return insert(t);
+ }
+
+ iterator operator<<(T &&t)
+ {
+ return insert(std::move(t));
+ }
+
+ iterator begin() { return m_data.begin(); }
+ const_iterator begin() const { return m_data.begin(); }
+ const_iterator cbegin() const { return m_data.cbegin(); }
+
+ iterator end() { return m_data.end(); }
+ const_iterator end() const { return m_data.end(); }
+ const_iterator cend() const { return m_data.cend(); }
+
+private:
+ std::vector<T> m_data;
+};
+
+} // namespace QtQuickParticlesPrivate
+
+QT_END_NAMESPACE
+
+#endif // QQUICKPARTICLEFLATSET_P_H
diff --git a/src/particles/qquickparticlesystem.cpp b/src/particles/qquickparticlesystem.cpp
index 158aede727..57812ba797 100644
--- a/src/particles/qquickparticlesystem.cpp
+++ b/src/particles/qquickparticlesystem.cpp
@@ -1077,7 +1077,7 @@ void QQuickParticleSystem::updateCurrentTime( int currentTime )
emitter->emitWindow(timeInt);
foreach (QQuickParticleAffector* a, m_affectors)
a->affectSystem(dt);
- foreach (QQuickParticleData* d, needsReset)
+ for (QQuickParticleData* d : needsReset)
foreach (QQuickParticlePainter* p, groupData[d->groupId]->painters)
p->reload(d);
diff --git a/src/particles/qquickparticlesystem_p.h b/src/particles/qquickparticlesystem_p.h
index b7812c6ea5..b1053d8ff8 100644
--- a/src/particles/qquickparticlesystem_p.h
+++ b/src/particles/qquickparticlesystem_p.h
@@ -63,6 +63,7 @@
#include <private/qv4global_p.h>
#include <private/qv4staticvalue_p.h>
#include "qtquickparticlesglobal_p.h"
+#include "qquickparticleflatset_p.h"
QT_BEGIN_NAMESPACE
@@ -410,7 +411,7 @@ public:
int systemSync(QQuickParticlePainter* p);
//Data members here for ease of related class and auto-test usage. Not "public" API. TODO: d_ptrize
- QSet<QQuickParticleData*> needsReset;
+ QtQuickParticlesPrivate::QFlatSet<QQuickParticleData*> needsReset;
QVector<QQuickParticleData*> bySysIdx; //Another reference to the data (data owned by group), but by sysIdx
QQuickStochasticEngine* stateEngine;