Coding Adventure: Rendering Text

1.2M views · 2 years ago · explainer · intermediate · evergreen

Sebastian Lague's Coding Adventure on how text gets rendered. He builds it up from font glyph curves, trying different ways to rasterize them, on the CPU and the GPU, and checking how well each one works.

HN people give it as the go-to explainer on font rendering techniques, and cite it as a source when they write about their own glyph rendering.

“Sebastian Lague has a good video covering many different font rendering techniques.”

7 comments from Hacker News

v
@vinhnx2026 · in “Coding Adventure: Rendering Text [video]”
Submitted the video to Hacker News.
RecommendsView on HN
v
@variadix2024 · in “Texture-Less Text Rendering”
Sebastian Lague has a good video covering many different font rendering techniques. ▶ this video
RecommendsView on HN
m
@marvinborner2024 · in “Coding Adventure: Rendering Text [video]”
Submitted the video to Hacker News.
RecommendsView on HN
e
@exDM692026 · in “SDF vs. MSDF vs. Slug: GPU Text Rendering”
As hobby project, I wrote a font rasterizer algorithm (two algorithms actually) that produces pixel perfect anti-aliased images (like Slug) using a similar but different algorithm. Rather than using Slug's clever root classifier for Bezier curves, I subdivide Bezier curves into monotonic sections where evaluating the winding number is much simpler and can be done in parallel for a group of pixels. It works nicely on GPU with warp/wave/subgroup operations and CPU using SIMD. At first glance, subdividing the Bezier curves sounds like a bad idea (more Beziers to rasterize) but it opens doors for some parallelism, and most Bezier curves that appear in fonts are monotonic in the first place (so the increase is very modest). This was inspired by this entertaining but not very serious video about font rasterization [0]. The first parallelism optimization is checking against the curve bounding box vs. a rectangular (in uv-space) region of pixels, and this can quickly determine if the Bezier needs to be evaluated in the first place. This can be done per GPU warp. The second optimization works only for rectilinear transformation (no rotation, skew or perspective). Solving the quadratic equation involves a square root and a division (which alone are >30% of the computation), which can be computed for each row and column of pixels instead of for each pixel (2n instead of n^2). Both optimizations rely on mathematical invariants of monotonicity, ie. the derivative of the Bezier curve must be non-zero. All Bezier curves can be robustly subdivided into monotonic sections using de Casteljau's algorithm. My simple benchmarks compare favorably to Slug on the GPU and to "fast" rasterization algorithms on the CPU (which is an order of magnitude faster than "fancy" rasterization algorithms with hinting etc). Unfortunately there are so many hobby projects and so little time. All I have is messy shaders that draw individual characters and a few benchmarks to see how quickly (and something similar for the CPU). Going from there to a complete text rendering system would be a lot of work. Writing a more detailed article with illustrative code examples is something I'd want to do but haven't gotten around to. If you want to offer words of encouragement or geek out about rasterization algorithms, I welcome any input. [0] ▶ this video Sebastian Lague - Coding Adventures: Rendering text.
CitesView on HN
r
@rhdunn2025 · in “Drawing Text Isn't Simple: Benchmarking Console vs. Graphical Rendering”
Here's Sabastian Lague's (Coding Adventure) video on font rendering -- ▶ this video
e
@exDM692025 · in “Rendering Crispy Text on the GPU”
Very cool stuff, text rendering is a really hairy problem. I also got nerd sniped by Sebastian Lague's recent video on text rendering [0] (also linked to in the article) and started writing my own GPU glyph rasterizer. In the video, Lague makes a key observation: most curves in fonts (at least for Latin alphabet) are monotonic. Monotonic Bezier curves are contained within the bounding box of its end points (applies to any monotonic curve, not just Bezier). The curves that are not monotonic are very easy to split by solving the zeros of the derivative (linear equation) and then split the curve at that point. This is also where Lague went astray and attempted a complex procedure using geometric invariants, when it's trivially easy to split Beziers using de Casteljau's algorithm as described in [1]. It made for entertaining video content but I was yelling at the screen for him to open Pomax's Bezier curve primer [1] and just get on with it. For monotonic curves, it is computationally easy to solve the winding number for any pixel outside the bounding box of the curve. It's +1 if the pixel is to the right or below the bounding box, -1 if left or above and 0 if outside of the "plus sign" shaped region off to the diagonals. Further more, this can be expanded to solving the winding number for an entire axis aligned box. This can be done for an entire GPU warp (32 to 64 threads): each thread in a warp looks at one curve and checks if the winding number is the same for the whole warp and accumulate, if not, set a a bit that this curve needs to be evaluated per thread. In this way, very few pixels actually need to solve the quadratic equation for a curve in the contour. There's still one optimization I haven't done: solving the quadratic equation in for 2x2 pixel quads. I solve both vertical and horizontal winding number for good robustness of horizontal and vertical lines. But the solution for the horizontal quadratic for a pixel and the pixel below it is the same +/- 1, and ditto for vertical. So you can solve the quadratic for two curves (a square root and a division, expensive arithmetic ops) for the price of one if you do it for 2x2 quads and use warp level swap to exchange the results and add or subtract 1. This can only be done in orthographic projection without rotation, but the rest of the method also works in with perspective, rotation and skew. For a bit of added robustness, Jim Blinn's "How to solve a quadratic equation?" [2] can be used to get rid of some pesky numerical instability. I'm not quite done yet, and I've only got a rasterizer, not the other parts you need for a text rendering system (font file i/o, text shaping etc). But the results are promising: I started at 250 ms per frame at a 4k rendering of a '@' character with 80 quadratic Bezier curves, evaluating each curve at each pixel, but I got down to 15 ms per frame by applying the warp vs. monotonic bounding box optimizations. These numbers are not very impressive because they are measured on a 10 year old integrated laptop GPU. It's so much faster on a discrete gaming GPU that I could stop optimizing here if it was my target HW. But it's already fast enough for real time in practical use on the laptop because I was drawing an entire screen sized glyphs for the benchmark. [0] ▶ this video [1] link [2] link
CitesView on HN
g
@gamedever2025 · in “100 Most-Watched Software Engineering Talks of 2024”
this is a list from their videos, not all videos. There's plenty of software engineering videos with 5x or 10x more views Here's 850k views ▶ this video look up "how to build and LLM" and your find plenty of videos with more than a million views from 2024