1.11.0.1
Prysm
SDF on GPU

Experimental font generation on the GPU

Notice/Limitations:

Even though the feature has been tested internally, it is likely that there are still some issues with it. There are some planned optimizations in different steps of the process, but its core idea will remain intact. It doesn't work on all platforms - some GLES2 and DirectX9 devices don't support it, it has some known issues on Nintendo Switch and it hasn't been tested on Linux. The Nintendo Switch and Linux issues will be resolved in a newer version, the GLES2/DirectX9 ones will most likely not be solved as they are caused by platform limitations - that's why a fallback to the algorithm that has been used so far is implemented there.

What is the new feature?

It's a new way to generate text atlases. So far we have been generating glyphs on the CPU. At lower generation size, there were some visual quality problems. At higher generation size the cost was usually prohibitively expensive in terms of processing power. Furthermore that approach was stopping us from implementing another important feature, which we will implement in the following releases - text outlines used for stroked text. The new experimental solution does most of the work on the GPU and that gives us the ability to generate even higher resolution text atlases without increase in CPU usage. This allows users to choose desired generation to best suit their use case and balance between text visual quality required and memory used.

Comparison with the old algorithm

We have already mentioned that the new algorithm is very scalable in regard to glyph generation size as it relates to CPU usage whereas the old one wasn't. It also allows us to implement nice-looking outlines - again something that the old algorithm wasn't capable of. A picture says a thousand words, so...

Before @ default(52px) generation size:

before_052.png

SDFGPU @ default(52px) generation size:

after_052.png

Outlines @ default(52px) generation size with 8px spread:

outlines.png

How to use it?

  • The feature is disabled by default and our rendering library is using the old CPU-heavy algorithm. The new SDF-on-GPU feature can be enabled by using the "--allowSDFonGPU" developer option.
  • The main controller of visual quality to memory consumption is the generation size of glyphs. Bigger glyphs lead to better quality, but also consume more space in the texture atlas. The algorithm uses a default generation size unless the "--sdfCharacterSize X" or the "--sdfCharacterSize=X" options override it.
  • Another controller of visual quality to memory consumption is the distance field spread. It also affects the maximum size of text outlines. Bigger spread leads to better quality and bigger maximal outline width, but also uses more memory. The algorithm uses a default spread unless the "--sdfSpread X" or the "--sdfSpread=X" options are provided. Spread specifies the size of the distance field that is generated around the glyph and is used both for quality edges and for specifying the maximal outline width. The maximal size of the outline can be calculated in the following way - maxOutlineWidth = ((SPREAD * TEXT_SIZE) / GENERATION_SIZE) - 1.0, where all variables are measured in pixels and SPREAD is the spread that has been used to generate the glyphs, TEXT_SIZE is the size of the currently rendered text and GENERATION_SIZE is the generation size of the font atlas.

Atlas with different generation size:

SDFGPU atlas @ default(52px) generation size:

atlas_052.png

SDFGPU atlas @ 96px generation size:

atlas_096.png

SDFGPU atlas @ 128px generation size:

atlas_128.png

Text quality with different generation size:

SDFGPU text quality @ default(52px) generation size:

after_052.png

SDFGPU text quality @ 96px generation size:

after_096.png

SDFGPU text quality @ 128px generation size:

after_128.png

Atlas with different spread:

SDFGPU atlas @ 128px generation size with 2px spread:

atlas_128_02.png

SDFGPU atlas @ 128px generation size with 8px spread:

atlas_128_08.png

SDFGPU atlas @ 128px generation size with 12px spread:

atlas_128_12.png

Outline width with different spread:

Outline width 52px - capped to maxOutlineWidth @ 128px generation size with 2px spread:

outlines_02.png

Outline width 52px - capped to maxOutlineWidth @ 128px generation size with 8px spread:

outlines_08.png

Outline width 52px - capped to maxOutlineWidth @ 128px generation size with 12px spread:

outlines_12.png