Sunday, June 01, 2008

LCL, Gtk2, Pango and Cairo

Introduction

Lately, in the Lazarus mail list, has been a lot of discussion about the performance of LCL/TextOut under Gtk2 and many (erroneous) arguments used derives from the lack of proper knowledge, including from myself. So in this article, i'll try to clear the things a bit.

When Gtk2 was released back in 2002, Pango was one of the Gtk2 main new features. Pango provides support to render Unicode text (encoded in utf8) with advanced layouts. But i was also one of the reasons of the degraded performance of Gtk2 when compared with its predecessor.

Pango has a flexible design allowing to use different backends (Cairo, Xft, Win32, X) to render text. Until version 2.6 Gtk2 used the Xft backend that was replaced, starting from version 2.8, by cairo (a 2D vector drawing library) as the default renderer. At that time the performance dropped even more, but after some work in pango and in cairo, the things got better.

So, the first point to take in consideration when evaluating pango performance is the version of pango and cairo. More on this later.

Testing LCL

In order to get an accurate diagnostic, i wrote an test application that fills an entire window with text using TextOut and compared the results (output quality and time to draw) of the Linux widgetsets (Gtk1, Gtk2, Qt).

Here is the output:




The time to draw an entire screen (average times of 15 iterations):

gtk1: 24ms
gtk2: 150ms
qt: 92ms

The gtk1 widgetset is really fast but it has two drawbacks: the font quality is low and the screen flickers while updating.
The gtk2 widgetset is the slowest loosing to qt by 60%, but in other hand has the sharpest font draw. An important point is that when double buffer is disabled (LCL disables it by default), the screen flickers just like gtk1, but if double buffer is enabled there's no flicker and the screen is updated instantaneous.
The qt widgetset is in the midterm both in quality and in speed. Not sure why qt text looks blurred: if is a configuration or the default font is not so good. There's also no screen flicker since qt is all double buffered.

Gtk2 dissected (almost)

Pango allows more than one engine to be used and there's also the options to draw directly using cairo or the old gdk functions (that use the X11 bitmap fonts). So i wrote an application using direct calls to the gtk2 api. It draws text with default Gtk2 (Pango/Gdk), Pango/Xft, Xft, Cairo, Gdk/X11.

The output (Cairo is equal to Gtk2 and Gdk/X11 is equal to LCL/Gtk1):



The time results:

Gtk2 (Pango/Gdk): 130ms
Cairo: 90ms
Xft: 70ms
Gdk/X11: 12ms
Pango/Xft: 110ms

Gtk2: very close to LCL/Gtk2
Cairo: the same quality of Pango/Gdk (I would be very surprised if was different ;-)) but significantly faster
Xft: Almost two time faster then Pango/Gdk but with lower quality output (An configuration issue?)
Gdk/X11: basically the same output of gtk1. Again really faster but without the screen flicker of gtk1.
Pango/Xft: faster than Pango/Gdk, slower than Xft. Out of option since is not working at all: it draws always at 0,0 coordinates.

Alternatives to pango?

From this tests, using directly Cairo to draw text seems to be a good option to replace Pango: the same quality and faster. But is not that easy. With direct calls to Cairo is needed to do all sort of text position (bidi, alignment) and text styles (underline) manually. Also it would be necessary to do the font selection and loading logic manually in a system specific way,i.e., is necessary different code to Linux/Win32/MacOSX.

Another option is using Xft directly. Aside from the different/worse output, it would be necessary to change the widgetset to retrieve the XftDraw handle for each drawable which is a complex task principally for double buffered controls. All in a system specific way.

Gdk/X11: the quality of output and lack of Unicode support makes a no-no option. At least for me.

Conclusion

Is there a direct/easy/faster replacement for Pango under LCL/Gtk2? No.

Here is necessary to make another question: there's a real need to replace it? Like shown earlier, default Pango is really slow compared to other alternatives, but, principally when double buffer is enabled, there's no visible glitches or general system slowdown. Is also necessary to take in account the increase of code size and complexity in LCL/Gtk2 side to make such change.

Notes

  • The test applications can be found here and here. Is necessary the package chronolog;
  • The test were conducted in a Celeron 1.4, 512MB, with an intel integrated video running Ubuntu 8.04;
  • Upgrading from Ubuntu 7.10 to 8.04 leaded to an significant speed in all widgetsets (Gtk2 250 > 150 / Gtk1 50 > 24ms);
  • I also tested drawing with low level Pango api. I'll post the results later;
  • Win32 took impressive 5ms in the same test Not to be considered since the win32 test was done in another (more powerful) machine;
  • A point that is not directly related to text draw but affects performance of LCL/Gtk2 is the fact that the LCL/Gtk2 test application calls 4 times FcFontSort, while a Gtk2 pure application calls only once. This is an expensive call that takes almost 20% of the application time.

5 comments:

etrusco said...

Luiz, você já deu uma olhada no código do gEdit ou do LeafPad? Há muito pretendo fazer isso, mas nunca arrumo "tempo", fico só vendo esse tar no meu desktop hehe

The importent part in English: did you ever took a look on the source code of gedit or leafpad?

Anonymous said...

Hi.

I'm playing with Cairo in Lazarus. It works fine for creating png images, but I can't craw Cairo surface on my lazarus GTK2 window or paintbox or something like that. You seems to be more skilled in this area, can you please help me with that? Thanks.

Luiz Américo said...

I wrote a component to wrap integrate cairo with LCL.

You can find the packages and the examples at: http://code.google.com/p/luipack/source/browse/#svn/trunk/cairo

Anonymous said...

Thanks, it works very well. Good work, keep going :)

Unknown said...
This comment has been removed by a blog administrator.