Fonts optimized for gpu rendering?

original question

The typical setup for ttf rendering on gpu tends to be:

  1. convert to sdf or multi-channel sdf; render as bitmap

  2. take the ttf, flatten / approximate the bezier curves; render as triangles + shader that can handle bezier

==

In the OCR world, there are fonts: ocr-a ocr-b, designed to be easy to ocr.

Are there any fonts designed with the constraints of gpu in mind, and designed for gpu rendering ?

edited in response to "why this forum"

I am building a game in Rust/wgpu/wasm32. I need a way to render text. Existing Rust solutions (makepad, egui, rusttype, ab_glyph) seems to fall into the categories of bitmap, sdf, multi channel sdf, or using shaders to render simplified bezier curves.

I am wondering if there is an alternative solution, perhaps a font designed with the architecture of webgl2 / wgpu / shaders in mind.

Thanks!

Sorry to ask, but why are you asking this in this forum? This has nothing to do with Rust.

1 Like

You've already listed all the things I've seen, but I'd hardly consider myself an expert.

Off the top of my head, perhaps some approach that tiles opcodes similar to how an old Microsoft Research project I remember did vector rendering with shaders, but I can't imagine the trade-offs being that useful compared to SDF approaches. Maybe if you had some really large text (like 100px+) the blobby corners could still bite on some fonts without an unreasonably large atlas?

GPUs have historically been better at filling a few triangles with a texture than rendering a lot of small triangles, so a bitmap-based approach feels pretty "optimized for GPU" to me.

I don't know of any offhand, but I suspect you can find fonts that are designed to have whole-pixel kerning for common sizes, which would let you cache bitmaps of each glyph without worrying about odd hinting variations from subpixel positions.

This article might be relevant for your case: Leveraging Rust and the GPU to render user interfaces at 120 FPS

2 Likes

I use alacritty for my terminal. It is super fast.

In my "imagination" it should be "easy" to put a glow rectangle in egui for rendering alacritty.

Possibly, in a similar way that bitmap fonts are optimized for rasterizing very specific font sizes. But these are going to be very "situational". And if they exist at all, they will probably lack a lot of Unicode that might matter to you (due to the previous point). So forget about font fallback and so on.

Most of the modern typographical enhancements have focused on legibility. Performance is secondary at best. And most of the attempts to optimize performance with GPUs have been done over the "typographical highly legible" fonts that already exist. I don't think I've ever seen a font that is optimized for high performance GPU rasterization.

Pretty specific constraints. The answer is almost certainly "no". But if you drop "GPU optimized font format", then you can find some prior art:

(Not an endorsement.)

personally, for rendering 2D GUI widgets, I would go with a big enough glyph atlas as texture for individual characters. the zed blog post linked above is using this technique too.

I believe ttf fonts (with truetype outlines) only uses quadratic bezier splines (I think technically ttf fonts can use postscript outlines too, but I have yet to see one of them). and there's algorithms to approximate cubic bezier curves using quadratic ones.

just in case you're not aware, for closed outlines consists of quadratic bezier segments,there's a trivial algorithm to render using traditional rasterizer. (the closed requirement is not strict, but without it, the algorithm is not really "trivial")

the idea is very simple, once you understand it. basically, a quadratic bezier segment has three control points, which forms a triangle, and the curve is just a parabola inside the triangle. just as all the parabolas are the same, all quadratic bezier curve segments are the same,!

so if you know how to draw a special curve, you can render every bezier curve. and the special curve is... y = x ^ 2, or equivalently, v = u ^ 2 (once you understand the transformation, you'll see really any quadratic curve will do, but this one makes the uv mapping easier)

imagine a triangle in the u-v space, where the three vertices are (0, 0), (0,5, 0), (1, 1), and the curve is v = u ^ 2. if you fill the pixels where v > u ^ 2, it's the portion "above" the curve. if you fill the pixels where v < U ^ 2, it's the portion "below" the curve. so the fragment shader is literally a single conditional branch.

it's hard to describe using words, but you can check out this paper, there are diagrams and pictures to illustrate:

EDIT:

the paper I was referring to was actually [loop, C. 2005], some how my search hit another similar result. sorry for the confusion. the link I intended is

https://www.microsoft.com/en-us/research/wp-content/uploads/2005/01/p1000-loop.pdf

edit again: the presentation in the following link is actually quite relevant. I recommend to watch the video.

/EDIT

https://dl.acm.org/doi/10.1145/1179849.1179997

also there's an implementation using some language I don't know of, but the code is readable, and there's an awesome blog post explaining the algorithm with very helpful animated pictures.

one neat trick is for straight line segments, just map uv of all 3 vertices to somewhere "above" the curve, e.g. (0.0, 1.0), and this is done at font mesh loading time, so you only need one pipeline.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.