Sunday, 25 April 2010

Every time you scale a pixmap, God kills a kitten.

I've had a fun weekend.

Carsten Munk, of Mer and other fame got me interested in insane schemes (once again): this time playing around with libdui (or libmeegotouch, as it is now apparently known), as we had repeatedly heard from many sources that it relied on GL, which meant that it couldn't be used with devices that require software rendering. Having found the -software flag to widgetsgallery, and poked around the source of DUI in the past, I thought this was a bit of a funny claim to make, until we actually used it and found out how horribly slow it was. Maybe they had a point?

Why was it slow? Well, it happened again. Not completely the same, of course, but this is a very similar issue to one I wrote about recently in Qt on Maemo. Something that a lot of developers, particularly ones working in higher level libraries or languages like C# or Qt forget from time to time is that image (or pixmap) scaling - in particular, smooth scaling - is generally not a fast operation.

DUI did a lot of scaling.

DUI has a class called MScalableImage, the purpose of which is to draw (and scale) a pixmap as needed, which is a good enough reason to have a class. MScalableImage is passed a pixmap, and stores it.

So far, so good.

Now, onto the details of scaling. When being asked to draw, QPainter pointer is passed, as well as an x, y, width and height. The width and height are checked against the stored pixmap's width and height, and if they match, it's drawn instantly, no questions asked.

So far, so good.

What happens, though, in the case where they don't match?

Oops.

DUI currently copies and rescales the stored pixmap to the target width/height, and then proceeds to draw as normal.

This behaviour is obviously wasteful. In the (frequent) case of GL acceleration, this doesn't really matter so much, because scaling on GL hardware - abstracted away by Qt - isn't all that slow, which is why this problem was probably not noticed previously. In the case of software rendering, though, that's a whole different story.

Patching this away to use the application-wide QPixmapCache drastically improves the performance of software rendering. My laptop isn't exactly slow, and I still ended up with a boost from an (unusable) 5-6 FPS to around 170-180 FPS.

Hopefully this post serves as an educational warning to help prevent future such mistakes.

(Oh, and the conclusion? No, DUI doesn't require GL. It helps, obviously, but it's not required.)

5 comments:

  1. Awesome work as usual, Robin!
    ReplyDelete
  2. i´m not a real programmer, just a caffeine adict graphic designer, but it really makes sense.
    Maybe some already compiled softwares can actually gain a boost in speed just because you noticed something they don´t.

    best regards, nice story
    ReplyDelete
  3. @Texrat: thanks!

    @Marcel: you'd be surprised how many different applications issues like this hit, yes. there's a lot of them. there's a few other common issues, but I'll write about them when I next encounter them. ;)
    ReplyDelete
  4. I agreed that the speed is so important, especially for end-user experiences. Maemo 5 did make a huge improvement from previous maemo releases, but it's still not smooth enough comparing to iPhone or WebOS. The screen resolution might be one of the causes, but even a high resolution Android phone looks better. I sometimes even think if we can just drop X and try directFB. Hope we can really make it better in the future.
    ReplyDelete
  5. Care to call on the GNOME Shell people one of these days?
    ReplyDelete