Render Thread Animations in Qt Quick 2.0

Published Monday August 20th, 2012 | by

One of the shortcomings of the Qt Quick API is that despite having a dedicated rendering thread, our animations are always running on the GUI thread.

Running animations outside the application’s main thread has the advantage that it greatly reduces jerkyness as operations that block the main thread will not hinder the animations from running.

There are three primary problems hindering us:

  • Animations update properties and these are tied to QObjects and the meta object system. To avoid threading insanity, we can only read and write these on the GUI thread.
  • Properties often have bindings in QML, which trigger JavaScript execution which must happen on the GUI thread.
  • The threaded render loop in the QtQuick library is driven by the GUI thread and does not redraw unless told, so if the GUI is blocked, nothing updates.

As I mentioned in my previous post, the render loop in the “customcontext” in ssh://codereview.qt-project.org:29418/playground/scenegraph.git fixes the third problem, but that leaves the issue of access to QObjects and JavaScript execution.

A colleague of mine, Marko Niemelä, has been working on an animation system that solves the QObject / QML binding part. His work is in the “animators” directory of the playground repository.

This is not Qt 5.0 material, but maybe we can get it in good shape for 5.1.

Enjoy!

Did you like this? Share it:

Posted in Performance, Qt Quick 2

12 comments to Render Thread Animations in Qt Quick 2.0

Benoit W says:

That’s good news! But what happens is the value is changed from the GUI thread during the animation? If I understand the behavior described in the video, it seems that the change will be overwritten at the end of the animation, which is probably not wanted.

Luiz says:

Feature request: Throw exception or simply crash the application, when ‘font.family’ is defined “Comic Sans”. :P

Blinded says:

The font blinded me, please help!

Kaitsu says:

Being able to run some animations in render thread would be very nice, well done Gunnar & Marko!

Gunnar Sletta says:

Benoit: The situation will be the same as it is today with the normal animation system. If you write to a property that is also written to by an animation, the value will be overwritten on the next “tick”. If you change the animation while it is running, it will update the animation accordingly. The same will happen for render thread animations, only that it gets overwritten only at the end. If you change the render thread animation, it will be changed on the render thread the next time the threads are synchronized. For a well performing scenario, that the sync happens once per frame.

We have considered sending a sync back for every frame, aka doing the meta call to set the property, but since the value is anyway a little bit out of sync it is less useful and if the metacalls were to add up (in the case of many parallel animations), then this might also have a negative performance impact, so for now, we decided on not sending “per frame” property values back to the GUI thread. If it comes in popular demand, we could make it an opt-in later.

Benoit W says:

@Gunnar: thanks for the clarification! I still have a doubt, though. When using “Behavior on”, animations are implicitly created on each property change. But currently, if the property value is changed again while the animation is still running (which should be allowed), the animation is stopped, the property gets the new value and a new animation is (implicitly) created. How can this scenario work if the animations are running in the render thread? Is it possible to stop the animation and make sure that the new value won’t be “posted back” to the GUI thread?

Scorp1us says:

Good idea! But everyone knows the GUI thread should not do any real work! This seems like a departure from existing Qt parlance. Could we also apply it to widgets as well, where we have a separate thread that does the same thing? While Widgets don’t generally animate properties, it would be cool to be able to execute functions in other threads and have them post back to the widget GUI thread as well. For instance, I could write a function checkBox01_enabled_calcuation() and assign it to the evaluation thread, and have it post back the result, setting the enabled property accordingly. We’d need some way to collect all these functions and run them in another thread context. But I see this approach being useful in widget UIs as well.

Benoit W says:

@Scorp1us: there are already many possibilities to do that, for example using QThread or QtConcurrent and by using signal/slots between the calculation and the GUI thread.

Here are a few examples but you can find much more interesting ones in the Qt documentation.

1. Using threads

// Class MyWidget, in GUI thread
QThread thread;
Worker worker;
connect( &worker, SIGNAL( valueCalculated( int ) ), this, SLOT ( setValue( int ) ) );
worker.moveToThread( &thread );
QMetaObject::invokeMethod( &worker, “calculateValue” ); // execute calculateValue() in the worker thread
// Note: Worker::valueCalculated( int ) is emitted from the worker thread and the slot MyWidget::setValue( int ) is executed in the GUI thread

2. Using QtConcurrent with signal/slots:

Worker worker;
QtConcurrent::run( &worker, Worker::calculateValue ); // execute Worker::calculateValue() in a thread of the thread-pool
connect( &worker, SIGNAL( valueCalculated( int ) ), this, SLOT ( setValue( int ) ) );

3. Using QtConcurrent and QFutureWatcher:

Worker worker;
QFutureWatcher watcher;
connect( &watcher, SIGNAL( finished() ), this, SLOT( valueCalculated() ) );
QFuture future = QtConcurrent::run( &worker, Worker::calculateValue ); // execute Worker::calculateValue() in a thread of the thread-pool
watcher.setFuture( future);

Alhaji says:

A Jane Austin fan friend of mind told me she hated this one, She remnocemds watching the starring Colin Firth as Fallatzwill Farcy, The guy who played Mark Darcy character in Bridget Jones’s Diary . Darcy’s character is insipired By Facry’s, it’s funny they brought him to do it, and I like how they changed the names :) .. that was trivial I know, But I just couldn’t help it :) Anstasia is beautiful, But to me Polar Express is what ugly computer animation is about, The characters look scary.. look at their eyes.. they look dead ! The whole movie was done in motion capture to copy the movements and facial expressions of real actors…which is a terrible thing !.. I mean.. it’s good for visual effects and realistic stuff, but why make a cartoon that looks and acts in a life-mimicking fashion with no exaggeration !.. Animation is about caricature and exaggeration, look at Pixar when they did humans in The Incredibles.. that’s the right way to do it.Btw, I really loved “In Mood for love”.. you might wanna give’em another chance and watch the sequel called some people would argue the fact if it’s a sequel or not.. but I believe it is.Hope I didn’t say too much.. hehe ! sorry for that :) Have a pleasant watching and 3eed sa3eedCheersP.S; Thanks for the homage in tagged-post about blogs, That “TADA” made me talk down to my friends for 2 days :)

Gunnar Sletta says:

Benoit: You raise a good point with Behaviors. They are currentøy not supported by this system. However, I think it will be fine. Just like we can cancel a GUI animation, we can cancel a render thread animation. The two threads synchronize once per frame, as long as the GUI thread is alive (which it is in your scenario).

Daniel says:

Hi,

thumbs up! I really think render thread animations are absoluetely vital.
While people might argue that the gui thread should never be blocked, they have to remember that just blocking the gui thread for 5ms might lead to jerky animation in the case of qml. Also threads have a cost, especicially on low hand hardware.
Each thread needs its own stack and context switches can become expensive if there are many of them.

I am really, really looking forward to see this implemented.

Stephan says:

Hi Gunnar,
does ssh://codereview.qt-project.org:29418/playground/scenegraph.git work with Qt5 beta out of the box? I tried to build it, but qmake + make stops immediately due to some unknown Qt modules in animators/src.

Commenting closed.