The real difference between texture-atlas, SDF, MSDF, and Slug glyph rendering on the GPU: how each works, where each breaks, and when to use which.

132 points•ibobev•about 12 hours ago•52 comments•

52 comments

psyclyxabout 5 hours ago
Slug mentioned!

When the Slug patent was released to the public domain, I put together[1] Snail[2], a Slug implementation in Zig.

One thing I found was that it was tough to get small text to look good with some fonts. TrueType fonts often have bytecode that tweaks curve points to better fit the pixel grid at a particular size. Part of the pitch for Slug is that it doesn't require per-size glyph prep, so Slug text is just unhinted.

As monitors have gotten denser, the major font renderers have moved away from bytecode hinting, either toward auto-hinting (ignore the bytecode, look at the outline, and decide what to do) or toward no hinting at all.

Snail has GPU auto-hinting that tries to replicate a lot of that, so I could have hinted text without per-size prep. It precomputes knots at various glyph features, and the shader then moves the knots to stretch/squeeze parts of the glyph. It's not perfect (especially for serif fonts!), benefits from per-font tuning, and focuses on Latin glyphs (pretty much always draws CJK glyphs unhinted because they're too complex for the current shaders to handle). Also, cases where you want hinting and wouldn't be better served by just scissoring prepared bitmaps aren't all that common. It also includes a TrueType VM, for cases where the per-size cost is acceptable (DejaVu Mono looks decent with the auto-hinter, but it has phenomenal hinting bytecode).

It was a lot of fun to put together, I learned a lot, and as far as I know the auto-hinter is unique among Slug implementations. Slug is a very cool algorithm.

[1] through high-effort delegation to Claude [2] https://github.com/psyclyx/snail - includes some diagrams (made with Snail!) that explain most of the prep/rendering of a glyph with Slug

elcritchabout 3 hours ago
> One thing I found was that it was tough to get small text to look good with some fonts.

Same here. For scaling from medium to large fonts the MSDFs were good. However at smaller "normal" font sizes they just didn't tend to look good even with larger MSDF sizes.

Plus for font rendering the GPU overhead was too large to be worthwhile for normal GUI apps. Font atlas'es are pretty small, and most fonts for GUIs are statically sized.

However I did find MSDF are fantastic for rendering complex SVG paths with lots of benefits [1]! You can use a 64x64 SVG star and scale it up fullscreen with reasonable loss in quality [2] (or use 128x128 for almost lossless images).

I use them as the core of my GUI library to render complex SVG paths for icons and such and compose individual paths on the GPU.

You can use them to implement fair chunks of Lottie animation as well [3]. Though I never got enough into the Lottie work to go beyond basic demos, but you could easily scale MSDFs, add shadows, feathering, outlines, etc at 100+ FPS.

1: https://forum.nim-lang.org/t/14062#85314

2: https://github.com/elcritch/figdraw#msdf-bitmap-based-sdf-re...

3: https://github.com/elcritch/lotty

GuB-42about 11 hours ago
I once implemented SDF text rendering. To me, the thing I liked the most about this technique it how easy it is to add effects on top. With a few lines of shader code, I had outlines and softening of the edges (antialiasing). I didn't try the MSDF variant, as I didn't mind corners not being sharp when scaled up, so I don't know if these effects break on MSDF.

Slug doesn't seem to support any of these, it is just "for a given point, am I in or am I out?", but it doesn't tell you by how much, which is great on really high resolution displays and large sizes, but you would lose the ability to do the kind of effects you can do with SDFs, and have to deal with antialiasing separately.

exDM69about 7 hours ago
> Slug doesn't seem to support any of these, it is just "for a given point, am I in or am I out?", but it doesn't tell you by how much

It does give you an anti-aliased value between 0 and 1 that estimates how much of a pixel is being covered.

But this is a linear estimate based on horizontal and vertical distance to the Bezier curve. It does not look correct at long distances, which is why you shouldn't use it for outlines, drop shadows or the other cool things you can do with (M)SDF. A single pixel outline works fine but is not really legible with modern display resolutions (very thin lines).

For finding the minimum distance between a quadratic Bezier curve and a point would require solving a 3rd degree polynomial, where Slug's algorithm gets away with solving a quadratic equation per pixel. This is makes a big performance difference.

JoshTriplettabout 10 hours ago
Having a technique that optimizes solely for whole pixels seems relatively reasonable, given current hardware PPIs. Systems that want to handle grayscale could use a different technique for that.

That said, there are interesting effects other than grayscale antialiasing, and I wonder how well slug could handle things like outlines (useful for subtitles over video, to make them readable on any background).

eviksabout 9 hours ago
I don't follow, current hardware PPIs are generally low, while whole pixels work for high?
mattdeslabout 11 hours ago
I've also been working on a GPU curve renderer, Windfoil, based on a formulation that Fable 5 originally proposed to me during a directed search [1]. It is similar in some ways to Slug, not always as fast, but uses less shader storage (single band instead of two) and produces higher quality anti-aliasing i.e. closer to a box-filtered ground truth.

It may be of interest to some game/graphics devs here...

[1] https://github.com/texel-org/windfoil-algorithm

yeoyeo42about 11 hours ago
interesting. how does the AA work in your algorithm?

the reason slug has two bands is precisely because of its anti-aliasing. you having only one implies you do the AA differently, or are less efficient with searches off the main direction.

for readers: the slug shader traces two rays, one horizontally, and one vertically, to find out if a pixel is inside a glyph or outside. one would be enough for pure inside outside, but for anti-aliasing purposes it's also helpful to know how far away you are from the closest edge. but if you have a horizontal ray running parallel to a horizontal glyph edge (not uncommon), the ray glyph intersection will return no value at all. so slug traces two rays and blends between them for anti-aliasing that always works in both cases. the bands mentioned here are just acceleration structures, basically a list of cells where each tells you which parts of a glyph are contained within it.

it's still approximate. a true ground truth would just supersample and do many point-in-glyph tests within one real pixel - at edges some of them would be inside, and some of them would be outside, giving you a smooth value to display depending on the shape of the glyph within the edge pixel.

mattdeslabout 11 hours ago
Windfoil uses boundary integrals to average winding over a given rectangular footprint (normally one pixel, independently in a fragment shader). For many cases, like typical text glyphs, this will reproduce a box-filtered ground truth exactly, i.e. for those shapes it is not approximating AA like Slug or MSDF. But because it takes the average and then applies a fill rule after, it's not an exact in all cases (fwiw, Slug can produces similar errors with tricky self-crossing curves and such).
jdanfordabout 12 hours ago
Man, I am getting incredibly tired of reading LLM-generated writing
tokenscoperabout 7 hours ago
As much as I'm all for human generated writing, coming across and having to read through mostly-LLM-generated writing is becoming the norm (at least for me, it's true). While I may not necessarily approve of the manner in which this was written, it was still something I wanted to know more about and I read it anyway.

It does bias me negatively towards the author, and makes me a little sad that people are choosing to not put more thought and effort into their writing, but this is a trend that is here to stay.

Making a big fuss about this hasn't gone anywhere from what I can tell, and it's unlikely that the outcome will be any different going forward.

marssaxmanabout 2 hours ago
I wonder if you are more or less tired of reading LLM-generated writing than I am of reading complaints about LLM-generated writing.
20kabout 11 hours ago
What signals this as being LLM writing for you? I'm crap at noticing specifics here
furyofantares15 minutes ago
I won't try to convince anyone with specifics but it was definitely LLM generated. I think by someone who knows what topics they want to cover and did have something they wanted to post about. At a high level it is an infodump with almost no opinion expressed.

I learned a few things from it and have some interest in the topic. So this sort of a weird valley where I'm very annoyed by the writing but also getting something out of it. And it's more than I would have gotten out of promoting an LLM myself.

Which I know, because I have written a blog post about SDFs before, and I tried to author it with an LLM helping and the text just came out awful. I think I rewrote my entire post eventually - I am fairly confident at least that none of the LLM's words remained. I mention it because I've already read the SDF section of this blog largely, when an LLM generated mostly the same text 5 months ago.

tokenscoperabout 7 hours ago
For me, it was this part of the paragraph:

> There is no atlas, so a hundred thousand CJK glyphs cost a font's worth of outline data, not an atlas the size of a video. Text can change every frame at no baking cost, which is exactly what you want for live data, user input, and localized content. And it all happens in a single draw with an ordinary fragment shader, no vendor extension required.

Specifically, these sentence structures:

1. ... so <blah> costs <blah>, not <blah>.

2. And <blah>, no <blah>.

3. ... fixed resolution ahead of time, which quietly ...

nuxiabout 7 hours ago
Stuff like this is a giveaway for me:

> Drawing it on a GPU, crisply, at any size, under any 3D transform, while the text changes every frame, is not.

> One small texture, resolution independent within reason, one cheap shader.

English is not my native language, so I may be wrong here.

nurumaikabout 11 hours ago
For me it was "head to head" table. Typical complete nonsense llm-generated comparison table. Rest of the content is still quite good tbh, generated or not
poly2itabout 10 hours ago
> A note on fairness, because the technical reader will ask.

I think it's a mix of human and LLM writing.

cute_boiabout 12 hours ago
Author probably didn't even read...
kevin_thibedeauabout 11 hours ago
I think it's TLDW.
YuechenLiabout 7 hours ago
This article has some inaccurate information since MSDF atlas doesn't have to be baked statically, so the "CJK character means huge atlas" is not really an issue if you can async upload them to the atlas.(Async outline extraction is a bit harder for C libraries, so that's why the pipeline is mostly restricted to atlas upload).

The other thing is MSDF rendering is fairly cheap and can be done on the CPU quite easily without GPU shaders, the atlas generation/upload is the expensive part, but it's a one-time cost per character per font as the atlas is just a normal bitmap texture file, MSDF text have sharp edges at most zoom resolutions, and the small size text is better handled with simple CPU raster anyways.

I really failed to see significant benefit of using Slug over MSDF + raster fallback for small fonts, it's definitely more exact, but I'm not sure if the marginal resolution benefit is worth it over much more complicated GPU dependent rendering, so I'd really want to test it out myself when I have the time over taking the word of an obviously AI written article for it.

decodingabout 5 hours ago
Yes, there is at least one downside to MSDF among a set of possible downsides (huge atlas, or dynamic rebaking, or limited glyph set), and the article is written as though they all apply, which is a bit misleading. Slug is cool, glad it exists, but it isn't the right fit for my rendering project either.

Read the full thread on Hacker News →

Related stories