aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick
diff options
context:
space:
mode:
authorGunnar Sletta <gunnar.sletta@digia.com>2013-09-24 12:51:36 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-09-26 20:08:19 +0200
commit0150202cc710e580695656fee049bf25091c0ded (patch)
tree217f5fbf792b5d40baeea0916064bb0ac2050b84 /src/quick
parentc40d9f64a6bd9671edc807bc74cf5b73c7465250 (diff)
Allow animators to work properly with multiple windows
Change-Id: I5ba663ba0fa089ea786cf43cb4dfa40cbc955342 Reviewed-by: Alan Alpert (Personal) <416365416c@gmail.com>
Diffstat (limited to 'src/quick')
-rw-r--r--src/quick/scenegraph/qsgthreadedrenderloop.cpp15
-rw-r--r--src/quick/util/qquickanimatorcontroller.cpp40
-rw-r--r--src/quick/util/qquickanimatorcontroller_p.h6
-rw-r--r--src/quick/util/qquickanimatorjob.cpp67
-rw-r--r--src/quick/util/qquickanimatorjob_p.h6
5 files changed, 83 insertions, 51 deletions
diff --git a/src/quick/scenegraph/qsgthreadedrenderloop.cpp b/src/quick/scenegraph/qsgthreadedrenderloop.cpp
index 88bc013306..a2c16fa4dd 100644
--- a/src/quick/scenegraph/qsgthreadedrenderloop.cpp
+++ b/src/quick/scenegraph/qsgthreadedrenderloop.cpp
@@ -281,6 +281,7 @@ public:
: wm(w)
, gl(0)
, sg(QSGContext::createDefaultContext())
+ , animatorDriver(0)
, pendingUpdate(0)
, sleeping(false)
, syncResultedInChanges(false)
@@ -330,6 +331,8 @@ public:
QOpenGLContext *gl;
QSGContext *sg;
+ QAnimationDriver *animatorDriver;
+
uint pendingUpdate;
uint sleeping;
uint syncResultedInChanges;
@@ -375,6 +378,7 @@ bool QSGRenderThread::event(QEvent *e)
window.window = se->window;
window.size = se->size;
m_windows << window;
+ connect(animatorDriver, SIGNAL(started()), QQuickWindowPrivate::get(se->window)->animationController, SLOT(animationsStarted()));
return true; }
case WM_Obscure: {
@@ -384,6 +388,7 @@ bool QSGRenderThread::event(QEvent *e)
if (m_windows.at(i).window == ce->window) {
RLDEBUG1(" Render: - removed one...");
m_windows.removeAt(i);
+ disconnect(animatorDriver, SIGNAL(started()), QQuickWindowPrivate::get(ce->window)->animationController, SLOT(animationsStarted()));
break;
}
}
@@ -584,6 +589,9 @@ void QSGRenderThread::syncAndRender()
#endif
RLDEBUG(" Render: - rendering starting");
+ if (animatorDriver->isRunning())
+ animatorDriver->advance();
+
for (int i=0; i<m_windows.size(); ++i) {
Window &w = const_cast<Window &>(m_windows.at(i));
QQuickWindowPrivate *d = QQuickWindowPrivate::get(w.window);
@@ -656,6 +664,10 @@ void QSGRenderThread::processEventsAndWaitForMore()
void QSGRenderThread::run()
{
RLDEBUG1(" Render: run()");
+ animatorDriver = sg->createAnimationDriver(0);
+ animatorDriver->install();
+ QUnifiedTimer::instance(true)->setConsistentTiming(QSGRenderLoop::useConsistentTiming());
+
while (!shouldExit) {
if (m_windows.size() > 0) {
@@ -682,6 +694,9 @@ void QSGRenderThread::run()
Q_ASSERT_X(!gl, "QSGRenderThread::run()", "The OpenGL context should be cleaned up before exiting the render thread...");
RLDEBUG1(" Render: run() completed...");
+
+ delete animatorDriver;
+ animatorDriver = 0;
}
QSGThreadedRenderLoop::QSGThreadedRenderLoop()
diff --git a/src/quick/util/qquickanimatorcontroller.cpp b/src/quick/util/qquickanimatorcontroller.cpp
index 73d2882c05..344c64d091 100644
--- a/src/quick/util/qquickanimatorcontroller.cpp
+++ b/src/quick/util/qquickanimatorcontroller.cpp
@@ -52,7 +52,6 @@ QT_BEGIN_NAMESPACE
QQuickAnimatorController::QQuickAnimatorController()
: window(0)
- , driver(0)
{
}
@@ -61,20 +60,14 @@ QQuickAnimatorController::~QQuickAnimatorController()
qDeleteAll(activeRootAnimations);
}
-void QQuickAnimatorController::advance()
+void QQuickAnimatorController::itemDestroyed(QObject *o)
{
- if (driver && driver->isRunning()) {
- // This lock is to prevent conflicts with syncBackCurrentValues
- mutex.lock();
- driver->advance();
- mutex.unlock();
- }
+ deletedSinceLastFrame << (QQuickItem *) o;
+}
- // The animation system uses a chain of queued connections to
- // start the animation driver and these won't get delievered until,
- // at best, after this frame. We need to track if animations
- // are running here so we can keep on rendering in that case.
- bool running = driver && driver->isRunning();
+void QQuickAnimatorController::advance()
+{
+ bool running = false;
for (QSet<QAbstractAnimationJob *>::const_iterator it = activeRootAnimations.constBegin();
!running && it != activeRootAnimations.constEnd(); ++it) {
if ((*it)->isRunning())
@@ -97,7 +90,10 @@ static void qquick_initialize_helper(QAbstractAnimationJob *job, QQuickAnimatorC
{
if (job->isRenderThreadJob()) {
QQuickAnimatorJob *j = static_cast<QQuickAnimatorJob *>(job);
- j->initialize(c);
+ if (j->target() && c->deletedSinceLastFrame.contains(j->target()))
+ j->targetWasDeleted();
+ else
+ j->initialize(c);
} else if (job->isGroup()) {
QAnimationGroupJob *g = static_cast<QAnimationGroupJob *>(job);
for (QAbstractAnimationJob *a = g->firstChild(); a; a = a->nextSibling())
@@ -107,15 +103,6 @@ static void qquick_initialize_helper(QAbstractAnimationJob *job, QQuickAnimatorC
void QQuickAnimatorController::beforeNodeSync()
{
- if (!driver && window->thread() != window->openglContext()->thread()) {
- driver = QQuickWindowPrivate::get(window)->context->createAnimationDriver(this);
- connect(driver, SIGNAL(started()), this, SLOT(animationsStarted()), Qt::DirectConnection);
- connect(driver, SIGNAL(stopped()), this, SLOT(animationsStopped()), Qt::DirectConnection);
- driver->install();
-
- QUnifiedTimer::instance(true)->setConsistentTiming(QSGRenderLoop::useConsistentTiming());
- }
-
// Force a render pass if we are adding new animations
// so that advance will be called..
if (starting.size())
@@ -123,11 +110,12 @@ void QQuickAnimatorController::beforeNodeSync()
for (int i=0; i<starting.size(); ++i) {
QAbstractAnimationJob *job = starting.at(i);
- qquick_initialize_helper(job, this);
job->addAnimationChangeListener(this, QAbstractAnimationJob::StateChange);
+ qquick_initialize_helper(job, this);
job->start();
}
starting.clear();
+ deletedSinceLastFrame.clear();
for (QSet<QQuickAnimatorJob *>::const_iterator it = activeLeafAnimations.constBegin();
it != activeLeafAnimations.constEnd(); ++it) {
@@ -157,10 +145,6 @@ void QQuickAnimatorController::startAnimation(QAbstractAnimationJob *job)
mutex.unlock();
}
-void QQuickAnimatorController::animationsStopped()
-{
-}
-
void QQuickAnimatorController::animationsStarted()
{
window->update();
diff --git a/src/quick/util/qquickanimatorcontroller_p.h b/src/quick/util/qquickanimatorcontroller_p.h
index 1c79e3c493..ab08bf05db 100644
--- a/src/quick/util/qquickanimatorcontroller_p.h
+++ b/src/quick/util/qquickanimatorcontroller_p.h
@@ -93,7 +93,7 @@ public:
public Q_SLOTS:
void animationsStarted();
- void animationsStopped();
+ void itemDestroyed(QObject *);
public:
QList<QAbstractAnimationJob *> starting;
@@ -104,9 +104,9 @@ public:
QHash<QQuickItem *, QQuickTransformAnimatorJob::Helper *> transforms;
- QQuickWindow *window;
+ QSet<QQuickItem *> deletedSinceLastFrame;
- QAnimationDriver *driver;
+ QQuickWindow *window;
QMutex mutex;
};
diff --git a/src/quick/util/qquickanimatorjob.cpp b/src/quick/util/qquickanimatorjob.cpp
index ea8da018b0..5ab54ab733 100644
--- a/src/quick/util/qquickanimatorjob.cpp
+++ b/src/quick/util/qquickanimatorjob.cpp
@@ -87,8 +87,7 @@ QQuickAnimatorProxyJob::QQuickAnimatorProxyJob(QAbstractAnimationJob *job, QObje
QQuickItem *item = qobject_cast<QQuickItem *>(ctx);
if (item->window())
setWindow(item->window());
- else
- connect(item, SIGNAL(windowChanged(QQuickWindow*)), this, SLOT(windowChanged(QQuickWindow*)));
+ connect(item, SIGNAL(windowChanged(QQuickWindow*)), this, SLOT(windowChanged(QQuickWindow*)));
}
}
@@ -102,7 +101,7 @@ void QQuickAnimatorProxyJob::deleteJob()
if (m_job) {
if (m_controller && m_internalState != State_Starting)
QCoreApplication::postEvent(m_controller, new QQuickAnimatorController::Event(m_job, QQuickAnimatorController::DeleteAnimation));
- else
+ else if (m_internalState == State_Starting)
delete m_job;
m_job = 0;
}
@@ -133,7 +132,7 @@ void QQuickAnimatorProxyJob::updateState(QAbstractAnimationJob::State newState,
syncBackCurrentValues();
if (m_internalState == State_Starting)
m_internalState = State_Stopped;
- else {
+ else if (m_controller) {
QCoreApplication::postEvent(m_controller, new QQuickAnimatorController::Event(m_job, QQuickAnimatorController::StopAnimation));
}
}
@@ -146,13 +145,14 @@ void QQuickAnimatorProxyJob::windowChanged(QQuickWindow *window)
void QQuickAnimatorProxyJob::setWindow(QQuickWindow *window)
{
- if (m_controller) {
+ if (!window) {
+ m_controller = 0;
+ // Stop will trigger syncBackCurrentValues so best to do it before
+ // we delete m_job.
stop();
deleteJob();
- m_controller = 0;
- }
- if (!window)
return;
+ }
m_controller = QQuickWindowPrivate::get(window)->animationController;
@@ -250,8 +250,19 @@ void QQuickAnimatorJob::initialize(QQuickAnimatorController *controller)
m_controller = controller;
}
+void QQuickAnimatorJob::targetWasDeleted()
+{
+ m_target = 0;
+ m_controller = 0;
+}
+
void QQuickAnimatorJob::updateState(State newState, State oldState)
{
+ if (!m_controller) {
+ stop();
+ return;
+ }
+
if (newState == Running) {
m_controller->activeLeafAnimations << this;
} else if (oldState == Running) {
@@ -277,15 +288,22 @@ void QQuickTransformAnimatorJob::initialize(QQuickAnimatorController *controller
{
QQuickAnimatorJob::initialize(controller);
- m_helper = m_controller->transforms.value(m_target);
- if (!m_helper) {
- m_helper = new Helper();
- m_helper->item = m_target;
- m_controller->transforms.insert(m_target, m_helper);
- } else {
- ++m_helper->ref;
+ if (m_controller) {
+ m_helper = m_controller->transforms.value(m_target);
+ if (!m_helper) {
+ m_helper = new Helper();
+ m_helper->item = m_target;
+ m_controller->transforms.insert(m_target, m_helper);
+ QObject::connect(m_target, SIGNAL(destroyed(QObject *)), m_controller, SLOT(itemDestroyed(QObject*)), Qt::DirectConnection);
+ } else {
+ ++m_helper->ref;
+ }
+ m_helper->sync();
}
- m_helper->sync();
+}
+
+QQuickTransformAnimatorJob::Helper::~Helper()
+{
}
@@ -295,7 +313,8 @@ void QQuickTransformAnimatorJob::Helper::sync()
| QQuickItemPrivate::BasicTransform
| QQuickItemPrivate::TransformOrigin;
- quint32 dirty = mask & QQuickItemPrivate::get(item)->dirtyAttributes;
+ QQuickItemPrivate *d = QQuickItemPrivate::get(item);
+ quint32 dirty = mask & d->dirtyAttributes;
if (!wasSynced) {
dirty = 0xffffffffu;
@@ -305,7 +324,7 @@ void QQuickTransformAnimatorJob::Helper::sync()
if (dirty == 0)
return;
- node = QQuickItemPrivate::get(item)->itemNode();
+ node = d->itemNode();
if (dirty & QQuickItemPrivate::Position) {
dx = item->x();
@@ -350,6 +369,8 @@ void QQuickXAnimatorJob::writeBack()
void QQuickXAnimatorJob::updateCurrentTime(int time)
{
+ if (!m_controller)
+ return;
Q_ASSERT(m_controller->window->openglContext()->thread() == QThread::currentThread());
m_value = m_from + (m_to - m_from) * m_easing.valueForProgress(time / (qreal) m_duration);
@@ -365,6 +386,8 @@ void QQuickYAnimatorJob::writeBack()
void QQuickYAnimatorJob::updateCurrentTime(int time)
{
+ if (!m_controller)
+ return;
Q_ASSERT(m_controller->window->openglContext()->thread() == QThread::currentThread());
m_value = m_from + (m_to - m_from) * m_easing.valueForProgress(time / (qreal) m_duration);
@@ -410,6 +433,8 @@ void QQuickOpacityAnimatorJob::writeBack()
void QQuickOpacityAnimatorJob::updateCurrentTime(int time)
{
+ if (!m_controller)
+ return;
Q_ASSERT(m_controller->window->openglContext()->thread() == QThread::currentThread());
m_value = m_from + (m_to - m_from) * m_easing.valueForProgress(time / (qreal) m_duration);
@@ -424,6 +449,8 @@ void QQuickScaleAnimatorJob::writeBack()
void QQuickScaleAnimatorJob::updateCurrentTime(int time)
{
+ if (!m_controller)
+ return;
Q_ASSERT(m_controller->window->openglContext()->thread() == QThread::currentThread());
m_value = m_from + (m_to - m_from) * m_easing.valueForProgress(time / (qreal) m_duration);
@@ -442,6 +469,8 @@ extern QVariant _q_interpolateCounterclockwiseRotation(qreal &f, qreal &t, qreal
void QQuickRotationAnimatorJob::updateCurrentTime(int time)
{
+ if (!m_controller)
+ return;
Q_ASSERT(m_controller->window->openglContext()->thread() == QThread::currentThread());
float t = m_easing.valueForProgress(time / (qreal) m_duration);
@@ -510,6 +539,8 @@ void QQuickUniformAnimatorJob::afterNodeSync()
void QQuickUniformAnimatorJob::updateCurrentTime(int time)
{
+ if (!m_controller)
+ return;
Q_ASSERT(m_controller->window->openglContext()->thread() == QThread::currentThread());
if (!m_node || m_uniformIndex == -1 || m_uniformType == -1)
diff --git a/src/quick/util/qquickanimatorjob_p.h b/src/quick/util/qquickanimatorjob_p.h
index c6814523c6..44155c1f93 100644
--- a/src/quick/util/qquickanimatorjob_p.h
+++ b/src/quick/util/qquickanimatorjob_p.h
@@ -126,6 +126,7 @@ public:
QEasingCurve easingCurve() const { return m_easing; }
void setEasingCurve(const QEasingCurve &curve) { m_easing = curve; }
+ void targetWasDeleted();
virtual void initialize(QQuickAnimatorController *controller);
virtual void writeBack() = 0;
@@ -140,7 +141,7 @@ protected:
QQuickAnimatorJob();
void updateState(State newState, State oldState);
- QPointer<QQuickItem> m_target;
+ QQuickItem *m_target;
QQuickAnimatorController *m_controller;
qreal m_from;
@@ -164,7 +165,6 @@ public:
{
Helper()
: ref(1)
- , item(0)
, node(0)
, ox(0)
, oy(0)
@@ -177,6 +177,8 @@ public:
{
}
+ ~Helper();
+
void sync();
void apply();