james_lohr's picture

TextPrinter - Performance for dynamically changing text

Hello,

I'm getting very poor performance out of the TextPrinter for text that is dynamically changing. For example: displaying a number that may change every frame.

Is there anything I can do to get around this?

I've just looked at the code for the TextPrinter, and it appears to cache at two levels:

1) At the glyph level (what I would expect)
2) At the text block level (this seems very odd to me!)

Clearly my text blocks are changing very rapidly, and so caching at this level does not make sense. Presumably there is some overhead to building a display list, so could this be what is causing the performance issue I'm seeing?

I've only glanced at the code, so I can't say I have much understanding of it, but if I were to fiddle with the rendering code so that it does not build a display list to be cached when rendering a block, do you think I might be able to improve the performance?

Many thanks,

James L.

[EDIT]

There is something that looks very suspicious to me: the delay I'm getting when new text blocks are added appears to always be the same, no matter how many new unique text blocks are added that frame. Also, it appears to always be ~16ms , which leads me to believe that something in the TextPrinter is causing a wait for the next Vsync. Is this possible?


Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
the Fiddler's picture
Quote:

2) At the text block level (this seems very odd to me!)
Clearly my text blocks are changing very rapidly, and so caching at this level does not make sense. Presumably there is some overhead to building a display list, so could this be what is causing the performance issue I'm seeing?

Yes. There is a flag to disable caching for dynamic text, check the last parameter of TextPrinter.Print().

The the two-level caching is a workaround for the workarounds around GDI+ bugs. The "don't cache" flag is a workaround for that workaround.

Which is why the TextPrinter is no longer supported.

james_lohr's picture

Great, that seems to have worked fine.

>>The the two-level caching is a workaround for the workarounds around GDI+ bugs. The "don't cache" flag is a workaround for that workaround.

Ouch, that does not sound pleasant.

Is there any major disadvantage to disabling block-level caching, apart from maybe large blocks of text being a bit slow to render?

Thanks again for the fast response.

the Fiddler's picture

There are two potential issues:

  • Performance will suffer (OpenTK has to measure and layout text from scratch each time).
  • Memory allocations may occur. This is more insidious, because the impact will vary depending on the allocation patterns of the rest of the application.
james_lohr's picture

Thank you Fiddler, I have a few more questions which concern the general approach used by the TextPrinter.

I do not understand the issues you have mentioned above, probably because I do not understand how the TextPrinter functions. So, let me first explain how I would expect (or at least, how I would like) the TextPrinter to function, and you can then correct me as to how it actually functions.

This is what I would like:

1) Specify a font and a font size (size could be called quality, since small fonts can be scaled up)
2) Load the font which involves:
- Rendering every glyph of the font at the specified size to bitmaps (presumably using some sort of open source ttf software renderer)
- Packing these glyphs into a single bitmap, recording size and offset of each glyph
- Loading this into an OpenGL texture
3) Write text with the font, which simply renders quads using the stored texture offsets per glyph

If I was writing a game, I might even want to skip 1), and have a pre-rendered glyph sheet so that the distributable doesn't need to depend on the font renderer.

Is this very different to how it functions at the moment? - Where does GDI+ fit in?

Many thanks,

James L.

the Fiddler's picture

GDI+ is used in all three parts:
1) fonts specification / loading
2) glyph rendering
3) text layout (measurement, justification, kerning)

However, GDI+ has been abandoned by Microsoft and has numerous bugs in parts 2 and 3. The Mono implementation is even worse. Additionally, neither one supports complex scripts.

Were I to implement a game-oriented text engine today, I would probably go for Valve's vector textures method for rendering and either Pango or platform-specific solutions for layout. (There are simpler solutions for latin scripts, though). This doesn't belong in the core library, however.