From 0150202cc710e580695656fee049bf25091c0ded Mon Sep 17 00:00:00 2001 From: Gunnar Sletta Date: Tue, 24 Sep 2013 12:51:36 +0200 Subject: Allow animators to work properly with multiple windows Change-Id: I5ba663ba0fa089ea786cf43cb4dfa40cbc955342 Reviewed-by: Alan Alpert (Personal) <416365416c@gmail.com> --- src/quick/scenegraph/qsgthreadedrenderloop.cpp | 15 ++++++ src/quick/util/qquickanimatorcontroller.cpp | 40 +++++---------- src/quick/util/qquickanimatorcontroller_p.h | 6 +-- src/quick/util/qquickanimatorjob.cpp | 67 +++++++++++++++++++------- src/quick/util/qquickanimatorjob_p.h | 6 ++- 5 files changed, 83 insertions(+), 51 deletions(-) (limited to 'src') 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.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::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(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(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; iaddAnimationChangeListener(this, QAbstractAnimationJob::StateChange); + qquick_initialize_helper(job, this); job->start(); } starting.clear(); + deletedSinceLastFrame.clear(); for (QSet::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 starting; @@ -104,9 +104,9 @@ public: QHash transforms; - QQuickWindow *window; + QSet 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(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 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(); -- cgit v1.2.3