Re: PangoOpenGLRenderer - a tale of code duplication



Hi Marc,

Enjoyed reading your tale.  First, I'm very interested in your workand
getting it integrated in Pango somewhere.  Next, the only thing you are
missing is that Pango doesn't expose internal/protected functions just
yet, because we (Owen actually) didn't want to freeze on an API that is
not mature enough, and we didn't envision anyone implementing an
external backend.

Also note that PangoFc is not only used by PangoFT2.  It's used by
PangoXft and PangoCairoFc too.  Also, PangoFT2 is not the best backend
to base your work on, but it works really good for the most part.

If you just send me the list of API you need public (as in
PANGO_ENABLE_BACKEND), I'll review and make them available.  If you
cleanup and submit your patch, I'll review and commit it to Pango.  In
both cases, helps if you open a bug at bugzilla.gnome.org.

Cheers and good job,
behdad

On Sat, 2006-07-15 at 16:48 -0400, gtk-i18n-list plan9 de wrote:
> [re-sent because the original mail is held for moderation for over a week,
> a courtesy cc of any replies would be great, thanks!]
> 
> Hi!
> 
> I recently decided to write an opengl game. A major problem with opengl
> is the lack of font/text suppport, and thus I had to decide wether I'd
> go with one of the many more-or-less primitive opengl text hacks or
> go for the right solution - leveraging pango.
> 
> Since I learned "interesting things" while implementing this, I thought
> I'd share this with you, maybe it is of some help to others (or even to me
> :).
> 
> Just a single warning: "long".
> 
> Preliminary thoughts
> 
>    Pango is slow, which was no news to me, but since the most practical
>    solution was to cache text strings fully in textures, I hoped rendering
>    speed was not a major problem, and indeed, it turned out that with
>    lots of caching, speed IS NOT a problem, at least compared to the high
>    quality of typesetting that I get with pango.
> 
> First tier of heaven (hell?) - pangoft2
> 
>    Now, my first implementation was using pangoft2, rendering strings into
>    graymaps and feeding those into an alpha tetxure. This worked fine,
>    although quite important features were missing, which soon became
>    quite painful. Most prominently, there was no way to get colour
>    out of pangoft2 - the only options you had are all ink, all transparent,
>    and text ink on transparent background.
> 
>    The problem with that is that you can't switch it off - inked text on
>    background is limited, but certainly readable. A "black" rectangle is
>    not, so I had to preparse markup to filter out colours.
> 
>    This worked relatively fine, but, due to my inefficient use of the
>    results (every pangoft2 rendered string became a texture, a real waste
>    of memory especially on opengl targets not supporting NPOT textures), I
>    looked for a better solution.
> 
>    Most pressing, though, was getting colour support.
> 
> Second tier of heaven (hell?) - pangocairo
> 
>    Looking at the existing options, I naturally found the cairo backend.
>    Apart from being much slower (>>50%) than pangoft2, and having lower
>    visual quality than pangoft2 on unix (I suspect a problem with
>    generating premulitplied alpha within cairo, which is unfortunately the
>    only available output format), the biggest problem was that the results
>    on win32 differed significantly from those of pangoft2, due to the use of
>    native win32 fonts (I assume).
>    
>    Worse, the resulting text was completely unreadable on win32 when
>    antialiasing was enabled, so I had to disable antialiasing on win32
>    compledtely to get at least readable text.
> 
>    For some time, I ran with both cairo and ft2 renderers, selecting the
>    most appropriate backend (pangoft2 for quality and speed, cairo for
>    features=color) per string based on wether it used any colour or not.
> 
>    Clearly, this was not the final solution.
> 
> Third tier of heaven (hell?) - pangoopengl
> 
>    I was looking at implementing my own opengl backend for pango for some
>    time, even before I started to use pangocairo, but everytime I tried, I
>    miserably failed. What kept me from trying was that I wasn't too keen
>    on managing texture catalogs for glyphs (== the opengl glyph cache),
>    especially not in C :), a 100% non-pango related problem, so I didn't
>    try very hard.
> 
>    Yesterday though I set out to solve it no matter what, and finally
>    succeeded, although the taste of victory is rather bitter, as I had
>    to throw some of my personal design standards overboard. A primitive
>    texture catalog infrastructure was finished after an hour hacking, so
>    what I feared most was not the problem I thought it would be.
> 
>    But pango was a different beast! Clearly not designed to be reused by
>    third party software! Or so!
> 
>    My first attempt was to subclass the PangoFT2Renderer. Unfortunately,
>    this quickly proved futile, as most of the required functionality
>    from PangoFT2Renderer, PangoFT2FontMap and PangoFT2Font is kept
>    private. One example is the glyph rendering and caching - all of that
>    is private, so subclassing PangoFT2Renderer is not possible (I learned
>    about PANGO_ENABLE_BACKEND early on, btw.)
> 
>    The second attempt was writing my own PangoOpenGLRenderer not derived
>    from PangoFT2Renderer. Most of that work was copying pangoft2-render.c
>    over to my own directory and starting a big rename party. The files are
>    still pretty similar - it was, after all, just simple code duplication
>    - but due to the important parts of the API being private, the only
>    solution available.
> 
>    It soon turned out that this wasn't enough, though - although the
>    FT2 fontmap and font classes provide some abstracted interface for
>    the benefit of PangoFT2Renderer /glyph info caching for example),
>    again a lot of other interfaces are private, so I had to clone
>    pangoft2-fontmap.c and pangoft2.c, and then some. Those files are even
>    more similar to the original files, as the only reason for cloning them
>    was to get at their private parts (uhum :), as the classes already
>    provide whats required, just not the everybody.
> 
>    After some more hacking (all this took about 8 hours - long for the
>    problem, at least by my standards), I was almost there.
> 
>    Of course, I forgot about PangoFCFontmap. Yes, you guess correctly,
>    it also doesn't expose vital parts of it's API (or better FT2-PI),
>    in this case pango_fc_font_get_raw_extents.
>    
>    While cloning, I naively assumed that identifiers starting with _ (a
>    despicable practise in itself, widely used within pango sources, given
>    that the C language reserves identifiers starting with an underscore at
>    file scope) are private, while those without are not - a mistake, as
>    pango_fc_font_get_raw_extents is indeed private to pango.
> 
>    I don't know wether there is a public API equivalent of that method,
>    but I suspect not, as there would be no reason to use the private one.
>    Again, just an assumption.
> 
>    At that point I was close to cloning pangofcfontmap, too - only the
>    massive amount of code duplicaiton that would result from that kept me
>    from doing it.
> 
>    Instead, I threw another of my precious design standards overboard and
>    just declared pango_fc_font_get_raw_extents in my implementation and
>    called it - that still sends shivers through my body, I feel really
>    awful. Drive with your eyes closed, so to speak. Just worse.
> 
>    But lets ignore those bleak seconds, and enjoy the result: I had
>    a working pango backend for opengl, with nice and fast glyph
>    caching, with all the features I needed, and it was actually quite
>    fast (ok, it slowed down the software rendering, as walking all
>    those pango structures using thousands of method calls that all
>    dynamically check pointer validity was quite slow - I immediately used
>    G_DISABLE_CAST_CHECKS in my copy, without giving it a second thought),
>    as glyph compositing by cpu dominated the rendering time with a hardware
>    opengl implementation.
> 
>    I saw heavenly light by then - till I switched into fullscreen and lost
>    my opengl context, and therefore my glyph cache.
>    
>    Well, of course, I thought "I just have to clear the glyph cache
>    info and be done with - EZEEEE". I already did that with my texture
>    catalog, and browsing through pango documentation and code I quickly
>    found pango_fc_font_map_cache_clear, which, well, obviously did what I
>    needed.
> 
>    Or maybe not.
> 
>    Turned out it didn't - it seems to do something with fontsets,
>    something I didn't really want to understand at that point (remember I
>    just wanted to implement a renderer).
> 
>    Hmm, ok, lets walk the fonts and...
> 
>    No, not either: that part of the implementation is hidden, too.
> 
>    Again, I was close to just cloning pangofcfontmap, but... No.
> 
>    The alternatives I saw would be some elaborate system to remember
>    every font used (which is actually the job of pangofcfontmap, or so
>    I figured), or associating a generation counter incremented on every
>    context change with every glyph cache entry, which was a true waste of
>    memory, but a stable and working way to solve the problem without more
>    code duplication.
> 
> [ The ugly, and far from production quality (or at least,
> library quality), is now part of the CFClient repository
> (http://software.schmorp.de) - please don't look for a finished product
> there, I just mention it because I think it would be inappropriate to talk
> a lot about code nobody can find :). ]
> 
>    I do feel quite uneasy - the generation counter is simply ugly,
>    declaring and using an internal function is outright evil, and copying
>    files and renaming things doesn't exactly feel like the right thing(tm)
>    either, but it works so far, and a better solution seems not to be
>    possible with pango.
> 
>    Gone are the days of pangocairo and pangoft2 - oh well, not the latter,
>    as pangofc is part of pangoft2, so I still have to link and ship it,
>    but at leats it's relatively small.
> 
> Morale of the story
> 
>    Well, maybe I am doing something very wrong, but it seems that pango
>    was not designed for code reuse at all. Which is puzzling, because it
>    uses all those OO techniques, such as multiple classes in a hierarchy
>    (pangofc => pangoft2), all of which seemingly just in support of each
>    other, as the interesting bits are not open and just provided for the
>    benefit of themselves. I think a much simpler design that obviously
>    made it impossible to subclass, combining pangofc into pangoft2 and not
>    exposing APIs that only the other class can make use of anyway, would
>    be smaller, faster, more maintainable.
> 
>    Or well, maybe I am missing something very crucial.
> 
> Final thoughts
> 
>    I hope that my adventures with pango + opengl were somewhat
>    entertaining, and maybe helpful to others who try to implement
>    something similar.
> 
> Thanks a lot for providing pango - a lot of people would (actually did)
> declare me a lost case for trying to combine pango with a realtime
> opengl application - but that part turned out very nicely, and with
> some optimisations pango is quite up to the task (well, at least on my
> machine, which is not the slowest one, but who cares).
> 
> A temporary screenshot of pango in action can be found here:
> URL<http://data.plan9.de/pango.png>.
> 
> It still used pangoft2 and pangocairo at that stage, but the current
> version very much looks the same. And no, the font is unnaturally large,
> and no, I have no idea wether the arabic script makes any sense (I would
> be glad for corrections).
> 
> Greetings,
> 
-- 
behdad
http://behdad.org/

"Commandment Three says Do Not Kill, Amendment Two says Blood Will Spill"
        -- Dan Bern, "New American Language"




[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]