aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGunnar Sletta <gunnar@sletta.org>2014-10-07 12:22:26 +0200
committerGunnar Sletta <gunnar@sletta.org>2014-10-10 21:10:52 +0200
commit099ae0597df6f6bbd0b9e05d063a4a58c9cae2ff (patch)
treeccfaf743aa3a572d362927131311787dd98c599b
parent7f5a59c2025022f99dff9fa030c892adb4473d6a (diff)
Improve performance of animators.v5.4.0-beta1
The use of one QCoreApp::postEvent() per completed animation added up to a very large overhead when 1000+ animators were used at the same time. This is very relevant for sprite games and similar and deserves to work at least as good as normal animations. Instead, store the animations to stop and stop then on the gui thread later as a result of frameSwapped. For the benchmark in question this allows for roughly double the amount of animators being started and stopped. Change-Id: Iae3d1ec1502ee1908fdbba708fa9f976aa230064 Reviewed-by: Michael Brasser <michael.brasser@live.com>
-rw-r--r--src/quick/items/qquickwindow.cpp3
-rw-r--r--src/quick/util/qquickanimatorcontroller.cpp44
-rw-r--r--src/quick/util/qquickanimatorcontroller_p.h21
-rw-r--r--src/quick/util/qquickanimatorjob.cpp11
-rw-r--r--src/quick/util/qquickanimatorjob_p.h2
5 files changed, 63 insertions, 18 deletions
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
index 7b300c9ab6..4ec901ceb4 100644
--- a/src/quick/items/qquickwindow.cpp
+++ b/src/quick/items/qquickwindow.cpp
@@ -458,8 +458,7 @@ void QQuickWindowPrivate::init(QQuickWindow *c, QQuickRenderControl *control)
q->setSurfaceType(windowManager ? windowManager->windowSurfaceType() : QSurface::OpenGLSurface);
q->setFormat(sg->defaultSurfaceFormat());
- animationController = new QQuickAnimatorController();
- animationController->m_window = q;
+ animationController = new QQuickAnimatorController(q);
delayedTouch = 0;
diff --git a/src/quick/util/qquickanimatorcontroller.cpp b/src/quick/util/qquickanimatorcontroller.cpp
index e009de205c..cfaa439072 100644
--- a/src/quick/util/qquickanimatorcontroller.cpp
+++ b/src/quick/util/qquickanimatorcontroller.cpp
@@ -44,10 +44,19 @@
QT_BEGIN_NAMESPACE
-QQuickAnimatorController::QQuickAnimatorController()
- : m_window(0)
+QQuickAnimatorController::QQuickAnimatorController(QQuickWindow *window)
+ : m_window(window)
, m_nodesAreInvalid(false)
{
+ m_guiEntity = new QQuickAnimatorControllerGuiThreadEntity();
+ m_guiEntity->controller = this;
+ connect(window, SIGNAL(frameSwapped()), m_guiEntity, SLOT(frameSwapped()));
+}
+
+void QQuickAnimatorControllerGuiThreadEntity::frameSwapped()
+{
+ if (!controller.isNull())
+ controller->stopProxyJobs();
}
QQuickAnimatorController::~QQuickAnimatorController()
@@ -71,6 +80,8 @@ QQuickAnimatorController::~QQuickAnimatorController()
if (!m_animatorRoots.contains(job))
delete job;
}
+
+ delete m_guiEntity;
}
static void qquickanimator_invalidate_node(QAbstractAnimationJob *job)
@@ -211,6 +222,27 @@ void QQuickAnimatorController::afterNodeSync()
}
}
+void QQuickAnimatorController::proxyWasDestroyed(QQuickAnimatorProxyJob *proxy)
+{
+ lock();
+ m_proxiesToStop.remove(proxy);
+ unlock();
+}
+
+void QQuickAnimatorController::stopProxyJobs()
+{
+ // Need to make a copy under lock and then stop while unlocked.
+ // Stopping triggers writeBack which in turn may lock, so it needs
+ // to be outside the lock. It is also safe because deletion of
+ // proxies happens on the GUI thread, where this code is also executing.
+ lock();
+ QSet<QQuickAnimatorProxyJob *> jobs = m_proxiesToStop;
+ m_proxiesToStop.clear();
+ unlock();
+ foreach (QQuickAnimatorProxyJob *p, jobs)
+ p->stop();
+}
+
void QQuickAnimatorController::animationFinished(QAbstractAnimationJob *job)
{
/* We are currently on the render thread and m_deleting is primarily
@@ -221,8 +253,10 @@ void QQuickAnimatorController::animationFinished(QAbstractAnimationJob *job)
*/
if (!m_deleting.contains(job)) {
QQuickAnimatorProxyJob *proxy = m_animatorRoots[job];
- if (proxy)
- QCoreApplication::postEvent(proxy, new QEvent(QEvent::User));
+ if (proxy) {
+ m_window->update();
+ m_proxiesToStop << proxy;
+ }
// else already gone...
}
}
@@ -254,12 +288,14 @@ void QQuickAnimatorController::startJob(QQuickAnimatorProxyJob *proxy, QAbstract
{
proxy->markJobManagedByController();
m_starting[job] = proxy;
+ m_stopping.remove(job);
requestSync();
}
void QQuickAnimatorController::stopJob(QQuickAnimatorProxyJob *proxy, QAbstractAnimationJob *job)
{
m_stopping[job] = proxy;
+ m_starting.remove(job);
requestSync();
}
diff --git a/src/quick/util/qquickanimatorcontroller_p.h b/src/quick/util/qquickanimatorcontroller_p.h
index bd44adf928..b13c174606 100644
--- a/src/quick/util/qquickanimatorcontroller_p.h
+++ b/src/quick/util/qquickanimatorcontroller_p.h
@@ -43,12 +43,14 @@
QT_BEGIN_NAMESPACE
+class QQuickAnimatorControllerGuiThreadEntity;
+
class QQuickAnimatorController : public QObject, public QAnimationJobChangeListener
{
Q_OBJECT
public:
- QQuickAnimatorController();
+ QQuickAnimatorController(QQuickWindow *window);
~QQuickAnimatorController();
void advance();
@@ -68,6 +70,9 @@ public:
void lock() { m_mutex.lock(); }
void unlock() { m_mutex.unlock(); }
+
+ void proxyWasDestroyed(QQuickAnimatorProxyJob *proxy);
+ void stopProxyJobs();
void windowNodesDestroyed();
public Q_SLOTS:
@@ -85,11 +90,25 @@ public:
QHash<QQuickItem *, QQuickTransformAnimatorJob::Helper *> m_transforms;
QSet<QQuickItem *> m_deletedSinceLastFrame;
QQuickWindow *m_window;
+ QQuickAnimatorControllerGuiThreadEntity *m_guiEntity;
+ QSet<QQuickAnimatorProxyJob *> m_proxiesToStop;
QMutex m_mutex;
bool m_nodesAreInvalid;
};
+class QQuickAnimatorControllerGuiThreadEntity : public QObject
+{
+ Q_OBJECT
+public:
+ QPointer<QQuickAnimatorController> controller;
+
+public Q_SLOTS:
+ void frameSwapped();
+};
+
+
+
QT_END_NAMESPACE
#endif // QQUICKANIMATORCONTROLLER_P_H
diff --git a/src/quick/util/qquickanimatorjob.cpp b/src/quick/util/qquickanimatorjob.cpp
index fdbffd4709..f29ec49b9f 100644
--- a/src/quick/util/qquickanimatorjob.cpp
+++ b/src/quick/util/qquickanimatorjob.cpp
@@ -85,6 +85,8 @@ QQuickAnimatorProxyJob::QQuickAnimatorProxyJob(QAbstractAnimationJob *job, QObje
QQuickAnimatorProxyJob::~QQuickAnimatorProxyJob()
{
deleteJob();
+ if (m_controller)
+ m_controller->proxyWasDestroyed(this);
}
void QQuickAnimatorProxyJob::deleteJob()
@@ -179,15 +181,6 @@ void QQuickAnimatorProxyJob::startedByController()
m_internalState = State_Running;
}
-bool QQuickAnimatorProxyJob::event(QEvent *e)
-{
- if (e->type() == QEvent::User) {
- stop();
- return true;
- }
- return QObject::event(e);
-}
-
static void qquick_syncback_helper(QAbstractAnimationJob *job)
{
if (job->isRenderThreadJob()) {
diff --git a/src/quick/util/qquickanimatorjob_p.h b/src/quick/util/qquickanimatorjob_p.h
index 4bdcd6917d..d87c9072a2 100644
--- a/src/quick/util/qquickanimatorjob_p.h
+++ b/src/quick/util/qquickanimatorjob_p.h
@@ -72,8 +72,6 @@ public:
void markJobManagedByController() { m_jobManagedByController = true; }
protected:
- bool event(QEvent *);
-
void updateCurrentTime(int);
void updateState(QAbstractAnimationJob::State newState, QAbstractAnimationJob::State oldState);