Around 20 o'clock on May 27, Owen Taylor wrote:
> I'm not particularly happy with the way the Xft backend for Pango > works at the moment ... it's complex, memory hungry, and relatively > slow. (Pango shaping with Xft is about twice as slow as Pango shaping > with the old X backend.) That's really sad -- let's make it faster than the old X stuff if at all possible. > The fundamental font operation in the Pango XFT backend (or any Pango > backend) is to map from a unicode codepoint and a PangoFontDescription > (family, style, weight, stretch, variant) to a particular PangoXftFont. Are you thinking of doing sequences of codepoints at some point to avoid ransom note results? > Operation A) is far too slow to implement into its entirety for each > small segment of text, so the bulk of the operation is cached - > a "infinite sized" map from PangoFontDescription to a list of patterns > is kept. (So, basically, everything but actually creating the PangoXftFont > objects and adding them to the fontset is cached.)) There's a new call you might like -- FcFontSetSort takes a pattern and returns the *whole* set of available fonts in sorted order, along with the union of all of their coverages. It's not significantly slower than matching a single font. Take all of the family names you want and stick them into the pattern, then hand the whole mess to FcFontSetSort and you'll get back the matches you're interested in. If you ask it to, it will only return the fonts which increase the global coverage of the list; that makes the list a *lot* shorter. When doing that, I can make it faster by stopping when the global list is full, but the implementation doesn't currently bother. Note that you needn't *open* fonts to determine their coverage; the result of any match contains the coverage for the target font. > A second cache is kept of PangoXftFont; when creating a PangoXftFont > for a pattern, instead of always creating it from scratch, we instead > check to see if there is already an outstanding font for the pattern, > and, if so, return it. We also keep a small number of fonts around > after the last refcount is dropped (MAX_FREED_FONTS, currently 16.) You don't have to do this; Xft caches at this level as well. It doesn't keep previously opened fonts around, but it could if you think that would be useful. > * The PangoFontDescription => [list of patterns] map really can > grow without bond, because each size is stored independently > (and Pango allows very fine-grained sizes.) So, an app that > allowed arbitrary zooming could easily end with a huge amount > of cached lists of patterns. If you use FcFontSetSort, you can keep only the pattern around and regenerate it as needed. That operation is (relatively) quick. > (So, first Pango does an hash lookup to make sure that > the no PangoXftFont is already open; if none is, then Xft will > do a linear lookup to the same effect.) If you find it necessary to avoid the linear search, it's obvious that Xft needs to use a hash as well. I avoided the complexity because I couldn't see it in my performance data (which is obviously limited at this point). Using Xft's cache instead of Pango's avoids the duplication of effort and allows faster operations as Xft can use the internal structures. I assume that the pattern equality tests have been of some use here already; I did convert the internal pattern representation to sort the pattern elements which avoided a quadratic comparison operation. > [ One problem with dropping the pattern => PangoXftFont cache, is > that you will end up creating many PangoXftFont objects for the > same font at the same size, even though Xft will only create > one XftFont object. ] We could allow you to store the PangoXftFont object from the XftFont; that way successive open operations could look for that and return it if it existed, saving the memory. > * Xft could export the idea of the "core" of a pattern ... an opaque > structure holding: > > file/minspace/char_width/size/spacing/rgba/antialias/load_flags/render/matrix > a) XftFont is fairly large. (It stores the complete pattern, for one thing) Note that the Unicode coverage is not duplicated; that structure is ref counted to avoid copying it. Your idea of further sub-caching leaves of that structure would serve to really reduce storage of these objects. I could attempt to reduce the pattern size further by sharing strings across different patterns and perhaps finding a small representation for the lists of values that are present today; embedding the initial value within the object header would save quite a bit of malloc overhead in this case. > b) When you open an XftFont, it immediately opens the FT_Face > for the font. We'd really like to avoid having to ever open the FT_Face > for fonts that are in our patterns but not used. I don't know why you're opening the font then; everything you need to know about the font is available from the pattern, including the Unicode coverage. The only thing not available are the glyph metrics; I assume you don't need those until you draw the glyphs. > * If the solution we take results in a large number of open XftFonts, it > might be necessary to replace the linear lookup in XftFontOpenPattern > with something smarter. Yes, that needs doing in any case; I left it linear just because it was easier. If there's a performance problem here, it's always easy to add a new hash table. I already have a hash function for patterns. Hmm. The return value from FcFontSetSort references the patterns of the original fonts; taking that value and opening a font requires a call to FcFontRenderPrepare; that makes the storage of this list *very* small, it's just an array of pointers, and a fairly short list at that. Let's see if we can't make this operation work for Pango, that seems like it will solve the pattern storage and matching performance problems. Fixing the XftFont opening to be sub-linear should solve the other end of the puzzle. -keith _______________________________________________ Fonts mailing list [EMAIL PROTECTED] http://XFree86.Org/mailman/listinfo/fonts
