Soundbomber's picture

Is TextPrinter inherently slow?

A couple of questions:
1 - I recently added some text to my 3D views resulting in slower rendering. I only added a couple of words, but at high magnifications, the render speed was noticably slower. Is TextPrinter inherently slow?
2 - Can antilaliasing be used with TextPrinter?

[Edit] Is TextPrinter the only way to go for 2D text in a 3D environment?


Comments

Comment viewing options

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

Which OpenTK version, video card and drivers? How many characters are we talking about?

Starting from OpenTK 0.9.8, the TextPrinter is a couple orders of magnitude faster for cached text and about 2x as fast for TextPrinterOptions.NoCache text. My 8400M peaks at about 1.6M 16pt-size glyphs with TextQuality.High at 800x600 - an order of magnitude faster than System.Drawing.Graphics.DrawString.

There are a few things to consider here:

  • Text layout and measurement is inherently slow. The TextPrinter caches results by default to make this faster.
  • Text printing itself is relatively dumb: a plain list of textured, alpha-blended quads. The TextPrinter uses display lists for cached text, which makes it completely fillrate limited (note: IGPs and shared memory architectures have notoriously low fillrate).
  • TextQuality.Medium uses Alpha textures instead of RGBA, which can boost performance on weak video cards.
  • You must specify TextPrinterOptions.NoCache for dynamic text (i.e. text that changes per-frame, like time or fps counters). Failing to do so, will slaughter performance.

To answer your questions:

  1. Text printing is inherently slow. The TextPrinter is quite fast, as text printers go (three different caches, plus display lists). It's relatively easy to abuse, but the new API should be more robust.
  2. Yes and no. Yes, the TextPrinter uses subpixel antialiasing in TextQuality.High and plain greyscale antialiasing in TextQuality.Medium - both look great as long as you keep text at 1:1 zoom. No, you cannot use FSAA with the TextPrinter. Typical FSAA will have no effect and transparency FSAA will reduce quality.
  3. No, of course not. If you want to implement zoomable 2d text, check out this paper: Improved Alpha-Tested Magnification for Vector Textures and Special Effects. Easy to implement with great results.
Kamujin's picture

I am not sure this answer is suitable to your situation, but I faced a similar problem with doing the GUI system for OOGL.

Not only was the text printing slow, but layering all of the window frame components was also inefficient.

The solution that I implemented was to flag any changes to the window frame that would effect it visibly. This includes things like frame resize events, button presses, or textbox text value updates.

When changes are detected, I render the window frame to a Frame Buffer Object (FBO). I then repeatedly use the texture associated with the FBO during the screen render operations until the next change is detected.

The speedup from this is quite significant.

If you'd like to see the code for this, it is available at http://www.opentk.com/project/OOGL

Soundbomber's picture

Thanks for the tips guys.
OpenTK version 0.9.8, NVidia Quadro FX 3450/4000 SDI, driver version 8.1.7.6, currently displaying 7 characters for testing purposes but will require closer to 50.
I am calculating 2D projections on the fly (every time a zoom or reposition occurs). I am drawing fonts at 1:1 ratio and changing the font size to accommodate the zoom level.
I have set TextPrinterOptions.NoCache and am using TextQuality.Low.
This still seems to yield unsatisfactory results.
I have been toying with using GDI (I have previously used this in a 2D environment with very nice results) - tried drawing on the OpenTK control surface but came accross the double buffering problem. Then tried using a transparent overlay control but not much success so far.

objarni's picture

Why NoCache?

Soundbomber's picture

Just trying Fiddlers suggestion for dynamic text.

the Fiddler's picture

Unfortunately, changing the font size is a *very* slow operation. It involves rasterizing new glyphs and copying data from GDI -> GDI+ -> OpenGL (the GDI -> GDI+ part is a killer).

The easy way out is to reduce the amount of available zoom-levels. For example, Google Earth does not zoom text at all; you could conceivably use 3 zoom levels for text and choose the best dynamically.

If you can't work around this requirement, I would suggest following Valve's paper, which presents a great way to implement true zoomable text. By storing distance fields instead of alpha levels, you can use a simple shader (or alpha-testing) to resolve text at the desired zoom-level. A single 24x24 distance field tile can resolve a glyph at most zoom levels with very good quality.

The only difficult part is calculating the actual distance field. IIRC, the simple, brute force algorithm is O(n^3), which is rather slow, considering that the input image should be large (Valve proposes performing this step offline on 2048x2048 images). Rendering is dead simple and you can use the TextPrinter to perform layout with kerning.

Soundbomber's picture

@Fiddler - Have you ever tried to implement this?
My text is dynamic (i.e. changes with user input). So I won't necessarily be able to use 'pre-saved' bitmaps.

objarni's picture

Soundbomber: have you considered fixed-width font rendering, via texture coordinates?

If you only need english letters + digits that should work alright.

Here is a bitmap I found via google "font bitmap":

the Fiddler's picture

@SoundBomber: Yes, actually I have implemented this, using System.Drawing rather than OpenGL. It worked pretty nicely, but I can't find the source code.

Valve's method works fine with dynamic text: instead of saving the final, composed text, you save individual glyphs. You can then use TextPrinter.Measure() and render the glyphs at the positions returned by this call.

@Objarni: The issue is that this method does not support zoomable text (the TextPrinter uses an advanced form of this method). For zoomable text, you either need vector graphics (very complicated) or an approximation of vector graphics (such as distance fields, i.e. Valve's paper).

objarni's picture

@Fiddler

How zoomable?

With a high-res texture, say 1024x1024, it should be quite alright even with letters filling say 20% of the screen height.

I guess it depends :) The answer to everything.