Wednesday 23 November 2011

Avoiding graphics flicker in Qt / QML

It's very common when writing QML applications to write a small stub, something like the following:


int main(int argc, char **argv)
{
    QApplication application(argc, argv);
    QDeclarativeView view;
    view.setSource(QUrl("qrc:/qml/main.qml"));
    view.showFullScreen();
    return a.exec();
}

What's wrong with this? It's a very subtle problem. I'll give you a moment to think about it, and a video to see if you notice the problem. Make sure you don't cheat.

(demonstrating removal of flicker in QML)

Back already? Have you figured it out? That's right, it flickers. Horrifically.

So what causes this? By default, QWidgets are drawn parent first, with parents drawing children. When a widget is drawn, first, it draws its background, then it draws the actual content. That background proves to be a problem, in this case.

If we add the following lines to the above example, the flicker goes away, and my eyes no longer want to bleed:
    view.setAttribute(Qt::WA_OpaquePaintEvent);
    view.setAttribute(Qt::WA_NoSystemBackground);
    view.viewport()->setAttribute(Qt::WA_OpaquePaintEvent);
    view.viewport()->setAttribute(Qt::WA_NoSystemBackground);

NB: I'm not completely sure that adding it to both the view, and the viewport is completely necessary, but it can't harm at least. Make sure to re-set it if you change viewports.

For completeness, here's the full, fixed example:

int main(int argc, char **argv)
{
    QApplication application(argc, argv);
    QDeclarativeView view;
    view.setSource(QUrl("qrc:/qml/main.qml"));
    view.setAttribute(Qt::WA_OpaquePaintEvent);

    view.setAttribute(Qt::WA_NoSystemBackground);
    view.viewport()->setAttribute(Qt::WA_OpaquePaintEvent);
    view.viewport()->setAttribute(Qt::WA_NoSystemBackground);

    view.showFullScreen();
    return a.exec();
}

(If you're curious, Qt::WA_OpaquePaintEvent basically implies that you'll repaint everything as necessary yourself (which QML is well behaved with), and Qt::WA_NoSystemBackground tells Qt to nicely not paint the background.)

NB: on Harmattan (and Nemo Mobile) at least, make sure you always use QWidget::showFullScreen(). The compositor in use there unredirects fullscreen windows (meaning no compositor in the way), so you get faster drawing performance, and every frame counts.

(obligatory thanks to Daniel Stone of X and Collabora fame, for telling me to stop blaming X, and start blaming the crappy toolkits ☺)

Labels: , , , , , , , ,

Fast UI with Qt 4 on mobile

For device manufacturers, and those targeting device manufacturers like us in the Mer¹ and Nemo Mobile².communities, we need a performant base, and Qt's default configuration on Linux is ..not really that performant. It uses what is known as the 'native' graphics system, which uses X (and XRender) to do a lot of the grunt work. Unfortunately, XRender isn't exactly what you'd call speedy in many cases, and making loads of round trips to ask X to draw things probably doesn't help either.

There's another option in the 'raster' graphics system, which does all rendering client-side in your application using (as you'd expect) Qt's software rasterizer, which is adequate enough for performance on most desktops, but still not quite optimal on desktops: hardware acceleration is the missing goodie.

Qt as of 4.8 also includes what's known as the MeeGo graphics system - as the name implies, it's used on the Nokia N9. It uses hardware acceleration (plus some additional EGL extensions) to perform absolute magic and make your pixels (especially QML :)) fly, so if you're working on getting a device together using Qt 4, I'd highly recommend you look at it.

Because no blog post is complete without a video, here's one:
(comparing the performance of raster and MeeGo graphics systems on a Lenovo S10-3t)

This sounds great, but there's one caveat. If you're on certain types of graphics hardware (SGX in particular), then you'll probably not to just want to enable the MeeGo graphics system for everything, because you'll end up with a lot of GL contexts allocated, which is not good for two reasons; they're scarce resources, and they take up a large chunk of RAM (something in the order of 5-10mb, depending on your PVR configuration file. I never actually looked).

There is good news at hand, though! Qt has *another* graphics system, specifically designed to proxy everything through another system, and allow for runtime switching back to raster. In our case, obviously, we want it to use MeeGo's graphics system by default, but fall back to raster to avoid taking extra resources when not needed.

There's also some bad news: it didn't work out of the box with Qt 4.8 RC1.

But some more good news: I fixed it (and yes, I upstreamed the patches)!
http://qt.gitorious.org/qt/qt/commit/a7c77bd46ef85bae624e829cb2a02110ec60b318
and
http://qt.gitorious.org/qt/qt/commit/0ceab866c76e0d9eb17bc1f3d42af06c0033560b
are the two commits you'll want.

After that, configure Qt with -graphicssystem runtime, and -runtimegraphicssystem meego (or set QT_DEFAULT_RUNTIME_SYSTEM=meego), and it'll work beautifully, provided your system has the required GL extensions.

Alternatively, you can use Mer, which already includes these patches right now, and, as of this week, has this beautiful magic enabled by default on the Nokia N900/N950/N9 hardware ports, where this is really needed (and works well). I'm working on getting it enabled by default on other systems that can support it, too, like the Lenovo S10-3t, as time permits.

Labels: , , , , , , , , , ,

Thursday 10 November 2011

debugging connmand

just so it's out there on the intarwebs, since it cost me a few minutes of head scratching: when you're trying to debug connmand, -d isn't enough. You need to use -n (nofork) too, otherwise you'll be left with a console, wondering why you aren't seeing the magics happening.

Labels: ,