GPU text rendering: when SDF stops being good enough

5 min read 1 source explainer
├── "GPU text rendering is an unsolved problem where every technique forces an unacceptable tradeoff"
│  └── AlphaPixel (alphapixeldev.com) → read

The article frames SDF, MSDF, Slug, and Rive not as a progression toward a correct answer but as competing theories of what a glyph even is. Nearly two decades after Valve's 2007 SDF paper, the default technique is still broken in the same ways, and every engine must inherit one failure mode or another.

├── "Standard SDF is fundamentally limited by sampling theory and cannot represent sharp corners at high resolution"
│  └── AlphaPixel (alphapixeldev.com) → read

A single-channel bilinearly-sampled distance field cannot encode two edges meeting at an acute angle — the corner rounds to whatever radius the atlas resolution allows. The failure is invisible at 32px/em but becomes glaring at Retina-class 300px/em sizes, which is why MSDF and Slug exist at all.

├── "Analytic Bézier evaluation (Slug) is philosophically superior to atlas-based approximations"
│  └── AlphaPixel (alphapixeldev.com) → read

The article contrasts SDF's 'blurry blob you threshold into existence' and MSDF's intersection of three such blobs with Slug's approach of evaluating the actual Bézier math in the fragment shader. Framing Slug as 'actual math' versus the others' approximations positions analytic curve evaluation as the theoretically correct answer, even if it costs more per pixel.

└── "This topic matters enough to developers that it reliably attracts attention despite being 'solved' in theory"
  └── @ibobev (Hacker News, 142 pts) → view

By submitting the AlphaPixel breakdown to HN, where it climbed to 142 points and 55 comments, ibobev signals that practitioners still treat GPU text rendering as a live and consequential problem. The ranking reflects a community consensus that typography tradeoffs will outlive the products that make them.

What happened

AlphaPixel's rundown of GPU text rendering techniques — comparing Signed Distance Fields, Multi-channel SDF, Slug, and Rive's approach — climbed to 142 points on Hacker News, which is a reminder that despite text rendering being a solved problem on paper for about 50 years, nobody has solved it well on the GPU. Every modern engine, UI framework, and game has to pick a tradeoff that will haunt its typography for the life of the product.

The lineage goes back to Chris Green's 2007 Valve paper, which proposed baking a glyph's shape into a texture where each pixel stores the signed distance to the nearest edge. Sample that texture, threshold at zero, and you get a resolution-independent letterform from a tiny atlas. It shipped in TF2, got copied into Unity, Unreal, Three.js, imgui, and roughly every WebGL app that cares about scaling text. Nearly two decades later it is still the default — and still broken in the same ways.

MSDF, introduced by Viktor Chlumský in 2015, encodes three distance fields into RGB channels so sharp corners survive the bilinear filter. Slug, developed by Eric Lengyel at Terathon, abandons the atlas entirely and evaluates Bézier curves analytically in the fragment shader. Rive's text engine takes a hybrid route tuned for animation. The question is no longer "does GPU text work" — it's which failure mode you'd like to inherit.

Why it matters

The three techniques are not three steps on a quality ladder; they are three different theories about what a glyph is. SDF treats a letter as a blurry blob you threshold into existence, MSDF treats it as the intersection of three blurry blobs, and Slug treats it as actual math.

Standard SDF's problem is Nyquist. A single-channel distance field, sampled bilinearly, cannot represent two edges meeting at a sharp angle — the corner gets rounded to whatever radius your texture resolution supports. At 32px per em this is invisible; at 300px per em on a Retina display it looks like your fonts were made of Play-Doh. Teams work around it by baking atlases at higher resolution, which blows up VRAM, especially for CJK scripts where a usable subset is 3,000+ glyphs. A 64px MSDF atlas for Noto Sans CJK is already pushing 100MB.

MSDF solves the corner problem elegantly but introduces its own gotchas. The encoding depends on correctly classifying each edge, and real-world fonts — especially hand-digitized ones with overlapping contours or self-intersecting Béziers — produce atlas artifacts that look like dropped pixels. Chlumský's `msdfgen` has heuristics for this; they work until they don't. If you have ever shipped a product with one specific weight of one specific font that renders a stray green pixel inside the counter of a lowercase 'e', MSDF is why.

Slug sidesteps the atlas by storing the glyph's Bézier curves in a buffer and letting the fragment shader compute coverage analytically for every pixel. The results are indistinguishable from CPU-rendered text at any zoom level, which is the dream. The catch is cost: Slug is patent-encumbered, commercially licensed, and the shader is heavy enough that filling a screen with text can cost more than filling it with PBR geometry. For a flight sim HUD or a CAD app it is worth every cent. For a React Native replacement it is not.

Rive's approach is interesting precisely because it is pragmatic. Rive animates vector art, so its text pipeline has to interoperate with the same renderer that draws arbitrary paths. Rather than pick a side it leans on its tessellator, which means text quality tracks whatever the path renderer is doing that frame — great for motion, less great for the kind of 10px body copy a documentation site cares about.

The HN thread, predictably, split along domain lines. Game developers defended MSDF as "good enough." UI framework authors wanted Slug or something like it. The one point of consensus: nobody is happy with their current solution, and everyone has a story about a glyph that renders differently on an iPhone than on an Android tablet than on a desktop GPU.

What this means for your stack

If you are building a game and shipping to consoles or mobile, MSDF via `msdfgen` is still the right default. The memory profile is tractable, the shader is cheap, and the artifacts are survivable if you pick fonts with simple contours. Skip plain SDF — the extra 2x storage for MSDF is dramatically cheaper than the engineering time you'll spend explaining to a designer why their logo's corner looks rounded.

If you are building productivity software — anything with a lot of small text that users will stare at for 8 hours — the equation flips. The atlas-based approaches struggle at the exact size range where typography matters most, 8-14px, because that's where hinting and subpixel positioning carry the most weight. Here the right answer is often "don't render text on the GPU at all": rasterize with FreeType or CoreText on the CPU, upload the result, and treat text as an image. This is what web browsers do, and it is not an accident.

If you have the budget and the use case, Slug is a legitimate option that most teams dismiss too quickly on licensing grounds. Lengyel's work is genuinely novel and the quality is unmatched. For a locked-down vertical — flight sim, trading terminal, medical imaging — paying for Slug is cheaper than two weeks of a senior graphics engineer trying to make MSDF look right.

The one option worth avoiding: rolling your own. Text rendering is one of those domains where the published papers underspecify the hard parts, and the hard parts are 90% of the work. Font formats contain decades of accreted edge cases — ligatures, GPOS tables, variable axes, color emoji — and your SDF generator will punt on all of them, which means your text engine ships with an invisible asterisk that reads "English only, no kerning."

Looking ahead

The interesting frontier is compute shaders. Slug-style analytical rendering is tractable on modern GPUs in a way it wasn't when Lengyel started, and Linebender's Vello project is quietly building an open-source alternative that treats text as a special case of its path renderer. If any of that lands as a drop-in Rust/WebGPU library in the next 18 months, it changes the calculus — and it would be the first time in 20 years the default answer to "how do I draw text on the GPU" wasn't "ship an SDF atlas and apologize to your designers."

Hacker News 169 pts 64 comments

SDF vs. MSDF vs. Slug: GPU Text Rendering

→ read on Hacker News

// share this

// get daily digest

Top 10 dev stories every morning at 8am UTC. AI-curated. Retro terminal HTML email.