[cairo] [PATCHSET] Multithread-safe FreeType

Behdad Esfahbod behdad at behdad.org
Tue Dec 30 16:06:32 PST 2014


Hi,

Over the past couple of days I developed a tool for testing FreeType in
multi-threaded environments:

  https://github.com/behdad/ftthread

and a patchset to go with it:

  https://github.com/behdad/freetype/commits/ftthread

With the patchset the test has been running happily for hours, using tens of
threads...

The patchset mainly removes use of singleton buffers in favor of stack or
per-face allocated ones.  In all cases this has no down side.  The exception
is the patch that affects the autohinter, which results in significant (~20%)
slowdown.  I plan to track that down and fix, but believe that the patchset
should be integrated before that.

Some dead code is removed as well.

Here's what https://github.com/behdad/ftthread/blob/master/README currently says:


ftthread
========

This is a test tool to use FreeType2 in a multi-threaded environment.

FreeType2 is not thread-safe, and the original author(s) of FreeType
suggest that one FT_Library per thread should be used.  Unfortunately
this is too inflexible to be really useful.

However, there are ways to use it safely in a multi-threaded environment
with simple modifications to FreeType.  I have now produced a complete
patchset to that effect and tested it using this utility.  The patchset
is available here:

  https://github.com/behdad/freetype/commits/ftthread

and I hope it to be integrated into upstream FreeType very soon.  In
the mean time, here's the new threadsafety model, which needs to be
integrated into FreeType documentation.  Note that cairo graphics
library already uses FreeType in this way and as such the entire GNOME
desktop has been relying on this model, to huge disappointment as seen
in the following bug reports, each of which have many duplicates:

  https://bugzilla.redhat.com/show_bug.cgi?id=678397
  https://bugzilla.redhat.com/show_bug.cgi?id=1004315
  https://bugzilla.redhat.com/show_bug.cgi?id=1164941
  https://bugzilla.redhat.com/show_bug.cgi?id=1165471
  https://bugs.freedesktop.org/show_bug.cgi?id=69034


Threadsafety model
==================

  - A FT_Face object can only be safely used from one thread at a time.

  - A FT_Library object can be used without modification from multiple
    threads at the same time.

  - FT_Face creation / destruction with the same FT_Library object can
    only be done from one thread at a time.


Discussion
==========

In this model, one can use a single FT_Library object across threads as
long as a mutex lock is used around FT_New_Face / FT_Done_Face.  Any calls
to FT_Load_Glyph and similar API are safe and do not need the lock to be
held as long as the same FT_Face is not used from multiple threads at the
same time.

Note that this goes almost all the way to making FreeType API useful from
multiple threads.  The only remaining bit is the unfortunately API that is
FT_Library_SetLcdFilter (and to less extent FT_Library_SetLcdFilterWeights).

I will try to work out a solution for replacing FT_Library_SetLcdFilter
using new FT_LOAD_* values.  There seem to be quite a few bits available in
that space, so that work should happen soon.


Running
=======

To run this test, give it a font file, and optionally:

  - Number of threads
  - Number of iterations per thread
  - Pixels per EM
  - Load flags in hexadecimal

The tool then will create one FT_Library, spawn many threads, and within
each thread create an FT_Face (after proper locking) and load glyphs from
the font for specified number of iterations and then destruct the face and
return.  The test also destructs and reconstructs the face every 1000
iterations.

Run with no arguments to get usage info.  Quoting here:

usage: ftthread fontfile.ttf [numthreads] [numiters] [ppem] [loadflags-hex]

numthreads, numiters, and ppem default to 100.

loadflags defaults to 0.  Values are in hex.
Useful flags to logically or:
NO_HINTING=2
RENDER=4
FORCE_AUTOHINT=20
MONOCHROME=1000
NO_AUTOHINT=8000
COLOR=100000


In particular, I've found the following load_flags values to be useful:

  0	Use native hinting (bytecode / CFF), no rasterization
  2	No hinting whatsoever
  20	Use autohinter
  4	Rasterize using smooth rasterizer
  1004	Rasterize using monochrome rasterizer

Remember to test with both TrueType and CFF fonts.  I have done both.
I have not tested bitmap (color or not) fonts, but don't know of any
outstanding issues there.

For example, here's how I test rasterizing glyphs in Roboto-Regular.ttf
using 40 threads, 10000 iterations per thread, at 150ppm, and repeat
that until it fails:

$ time while ./ftthread Roboto-Regular.ttf 40 10000 150 4; do echo -n '.'; done

Make sure you run "ulimit -c unlimited" in your shell first such that
you get a core dump when the test fails.

Please report any failures you discover if it happens with a FreeType
including the patchset.


Thanks!

Behdad Esfahbod
30 December 2014


More information about the cairo mailing list