Bjørn Erik
Qt
KDE
Graphics View
Painting
Posted by Bjørn Erik
 in Qt, KDE, Graphics View, Painting
 on Monday, February 04, 2008 @ 15:19

Although the Nokia acquisition has sucked away some time from development and made it somewhat difficult to stay focused, it doesn’t mean we are halted. Our coffee machine is still up and running so there should be no need to worry.

I’ve been working on improving the painting performance lately, and I can tell you we’ve found nasty stuff. Resizing top-level windows has always been quite frankly horrible. With Qt3 it was snappy, but looking at it almost felt like staring at a strobe emitting a series of flashes. I’m pretty sure it was a useful feature at the discos back in the days. With Qt 4.1.4 and the backing store, we closed down that business and started focusing on usability and managed to get rid of most of the flicker at the cost of performance. We have continuously worked on improving the performance in the 4.2 and 4.3 series, but up until the alien technology, we struggled with flicker. With flicker-free child widgets in place, the only problem left was the sluggish top-level flicker, and that’s what I’ve been working on recently. Tests showed that in worst-case an application could easily repaint itself three times per resize. So, with 100 resize events you could actually get 300 repaint events, which is 200 more than needed! Now imagine how this appears with an application having lots of complex widgets with expensive paint events. It’s ridiculous!

This has now been fixed and reduced down to one repaint per resize, but the story doesn’t end here. Another nasty thing I found was useless QPainter redirection operating on a global list involving several mutex locks and for loop iterations. More precisely (per paint event); 2 + X mutex locks and 1 + X for-loops, where X is the number of painters created during the paint event.

In addition, Jens found out how we could easily get rid of the black background fill appearing on resize on Windows Vista, and it really makes things look much better!

Aah, yes, and there’s one more thing I’d like to mention. If we go few months back in time when the Widgets on The Canvas project was integrated, you can see how we were able to draw widgets directly onto the canvas with resolution independence. You might wonder how on earth we were able to do that. Well, there is an easy answer: The new QWidget::render overload taking an arbitrary QPainter :-) I really had to wrap my brain around lots of pain in order to achieve that. As you probably know, creating a QPainter on a widget boils down to initializing the paint engine using the backing store as the paint device. It just means we’re doing exactly the same over and over again, which in turn means it’s possible to use a shared painter! Yes! Easy, then we simply pass the shared painter in QPaintEvent and everything is fine. Or wait… Damn, then we would have to change every single paintEvent in Qt and customers code. Bad idea! So what we ended up doing instead was to hijack sub-sequent QPainter constructions/initializations and set the d-pointer of the newly created QPainter to the shared painter’s d-pointer and push/pop the state accordingly. Everything happens behind the scene without requiring changes to existing code. When it comes to performance it means we don’t have to initialize the paint engine (which is an expensive operation) each time we construct a QPainter. Great, isn’t it?

Unfortunately, I don’t have any demo to show you this time, but I hope it encourages you to download the latest snapshot and try it with your application. If you’re brave, you could also run it against 4.1, 4.2 and 4.3 and see how we gradually become better and better. It clearly shows we’re going in the right direction.

Performance is really important and needs serious attention, so you can expect to see more action on this topic in upcoming releases of Qt.

Happy hacking!

Bjørn Erik
Qt
KDE
News
Posted by Bjørn Erik
 in Qt, KDE, News
 on Thursday, August 30, 2007 @ 09:27

As a follow-up on Qt Invaded By Aliens — The End of All Flicker I’m pleased to inform that the alien branch was integrated into Qt main on Tuesday (2007/08/28).

To get use of aliens (a.k.a. windowless child widgets) simply go here and download the latest Qt 4.4 snapshot.

That’s it!

If you for some reason want to get back to the old behavior with native windows, here’s how you can do it:

1) Use ‘QT_USE_NATIVE_WINDOWS=1′ in your environment (PS! with today’s snapshot and earlier one must use ‘QT_NATIVE=1′ instead).
2) Set the Qt::AA_NativeWindows attribute on the application: All widgets are native.
3) Set the Qt::WA_NativeWindow attribute on widgets: The widget itself and all ancestors are native (unless Qt::WA_DontCreateNativeAncestors is set).
4) Calling QWidget::winId enforces a native window and implies 3).
5) Setting the Qt::WA_PaintOnScreen attribute enforces a native window and implies 3).

Enjoy!

Bjørn Erik
Qt
KDE
News
Posted by Bjørn Erik
 in Qt, KDE, News
 on Thursday, August 09, 2007 @ 12:33

No, this is not a wet dream — it’s all true; with Qt 4.4 you will be able to get rid of issues you have had with flickering. Just to make sure we are talking the same terminology, I’ve created a small movie demonstrating the problem:

Given the fact that we’ve passed the 90’s, this is not acceptable and up to Qt’s standard. As of today, every single widget in Qt has a native window that is managed by the window system — in this case the X server. The flicker you see on the movie is a result of multiple X windows trying to synchronize and play funny games with the X server.

But how can we improve? With Qt 4.1 we took a huge step towards resolving similar issues when introducing the backing store, but it can’t cover resize flicker as it’s fully caused by the X server. The only consequent and necessary next step is therefore to bypass the X server and let Qt do the job. In order to do that we must make our child widgets non-native — a.k.a. alien — such that X doesn’t know they exist. That sounds pretty easy, doesn’t it?

Moving away from native windows isn’t done over the night. Window handles have been in Qt from day one, and consequently our GUI kernel is heavily built around them. The main technical challenges in that respect have been core functionality such as mouse events, widget cursors, enter/leave events, drag’n'drop and so on. With native windows all widget events are related to a window handle and our job is simply to map system events into Qt events. Consequently, when we make our child widgets windowless, all events are related to the top-level window and we have to figure out ourselves which widget is the correct receiver for the given event. To make it even more interesting, all this depends on the platform your application is running on, so there’s no way it can be fixed properly in cross-platform code.

A somewhat funny scenario is drag’n'drop on Windows which is based on Object Linking and Embedding (OLE). Every drag’n'drop operation consists of at least two COM objects representing the source and the target. A widget acting as a drop target must register its window handle such that Windows can communicate between the source and the target. It’s not hard to imagine that some black magic is needed when the top-level window is the only native window we have, possibly acting as source and target at the same time.

And what happens if we suddenly create a widget that requires a window handle? Consider the scenario where a QGLWidget is the central widget of QMainWindow. Widgets with the Qt::WA_PaintOnScreen attribute set — in this case the QGLWidget — must have a native window to function properly. That’s OK, but the fun starts when we have to deal with clipping between native and non-native windows. Clipping between native windows is indeed handled by the window system, but it doesn’t help much when the only clipping we get for free is between the top-level and the GL widget.

Needless to say, but apart from reducing flickering, an application with windowless child widgets is much more light-weight and resource friendly as we don’t allocate native windows for every single widget.

I wish we could have taken this step a bit earlier, now that KDE 4 is around the corner, but there’s little point in adding hacks and workarounds now to avoid flicker with Qt 4.4 bringing the real solution soon.

I could probably tell you a lot more, but I’ll keep this blog short. Currently this work is going on in a separate research branch so it won’t show up in our snapshots, but within few weeks you should be able to try it out. I’ll blog with more details as soon as we have it integrated.

Last, but not least, here’s the obligatory movie showing how resizing with windowless child widgets looks like: