> So I tried something unconventional: draw each character once, cache it as a texture, and then just copy those textures around.
That’s more like the most conventional way to draw characters ever. Nobody goes around rendering filled Béziers any more than absolutely necessary. And conventionally conventionally, fonts were bitmaps in the first place!
Yeah, I confess I would have assumed that this was more common than otherwise.
Makes me curious how much of computing is losing perceived speed because we have moved to calculating everything on the fly? Easy example is website layout. Yes, some dynamic sites need to calculate a ton on the fly. Most sites, though, probably don't need to reflow everything nearly as often as they do. And fitting everything into the mechanism that is the document flow remains baffling to me.
SDF seems to be one of the better solutions for text rendering.
Valve had this problem solved since 2007. I'd argue this technique is a big part of what gave TF2 its impressive visual style. That game ran at 100+ fps on hardware like the 8800GT at the time.
That really was just the most absurd argument for Microsoft developers to engage in. It felt like a parody of the "optimisation is unnecessary because us developers are such Prima Donnas and simply toooooo expensive to lower ourselves to such levels" attitude that some people have.
He used a cache. A simple hashtable. That's it. He got an absurd speedup of something like hundreds of times faster.
What are developers smoking these days that they can't even envision ever doing something like this without undertaking a research program?
To this day people will debate this, as if there's a valid debate to be had!
"No, no, no, it's premature to optimise software that is... being released to a billion users in production."
"Casey is adding unnecessary complexity that will be hard to maintain... by using a fraction of the code Microsoft did to solve the same problem."
"It must be full of errors... well... other than the superior Unicode compliance."
"It's so much longer to develop high-performance code... the evidence is that it took Casey two weekends to write a nearly complete terminal emulator!"
Etc...
Look where we are today. Microsoft still steadfastly refuses to even look at Casey's solution, let alone adopt it wholesale. Years later there are still blog articles being written about the performance issues of the Windows Terminal.
PS: Notepad and Calculator got the same "treatment" and now struggle to keep up with key presses.
what's worse is that scrolling doesn't actually work unless you have the text area focused/under the wheel... very weird. Which is even worse for PgUp/Down as who would think to focus the area first for scrolling???
I wonder how the GPU version is implemented. One quad and one texture draw per glyph sounds very not scalable, but one quad per terminal, one texture atlas and one shader to draw glyphs from the atlas already sounds much better.
That's nothing for a modern GPU. For example, this benchmark[1] says to expect on the order of 10-800 million tri/s. At the low end of that, you'd have a frame time of 3.427ms -- 292 fps.
The original Playstation could do 180 000 textured polygons per second[2], so it could've managed ~5 fps. Of course, you wouldn't render that many chars at its available output resolutions anyway. :)
One quad per glyph is very scalable, especially if you use instanced rendering. Each quad is just reading from a single texture atlas. GPUs are beastly blitting machines.
Runs at ~1500 FPS with a 6K screen of full text on my machine even when text is being updated at about the pace of a 150 WPM typist but you only update quads that strictly need to change and store font metrics on the GPU in a buffer. A full screen refresh where you send quad data for 750 Lorem ipsum paragraphs every frame runs at 300 FPS on my hardware.
Caching the fonts to a texture atlas is not an unusual idea. https://github.com/memononen/fontstash is a well known example of this. Odin has a native port meant to work in conjunction with its bindings to NanoVG. The Odin code is coupled to stb_freetype.
> So I tried something unconventional: draw each character once, cache it as a texture, and then just copy those textures around.
That’s more like the most conventional way to draw characters ever. Nobody goes around rendering filled Béziers any more than absolutely necessary. And conventionally conventionally, fonts were bitmaps in the first place!
> And conventionally conventionally, fonts were bitmaps in the first place!
Bitmaps in ROM on early machines.
https://en.wikipedia.org/wiki/Motorola_6845
Bitmaps in diode arrays on even earlier machines
Yeah, I confess I would have assumed that this was more common than otherwise.
Makes me curious how much of computing is losing perceived speed because we have moved to calculating everything on the fly? Easy example is website layout. Yes, some dynamic sites need to calculate a ton on the fly. Most sites, though, probably don't need to reflow everything nearly as often as they do. And fitting everything into the mechanism that is the document flow remains baffling to me.
SDF seems to be one of the better solutions for text rendering.
Valve had this problem solved since 2007. I'd argue this technique is a big part of what gave TF2 its impressive visual style. That game ran at 100+ fps on hardware like the 8800GT at the time.
https://www.redblobgames.com/x/2403-distance-field-fonts/
Thanks for the link, clicking around led to the discovery of this basic, yet fascinating 3D text demo
https://chlumsky.appspot.com/msdf-demo
SDF is awesome but even then it's not a silver bullet. It's a raster technique and some people want vector fonts or subpixel rendering.
I can imagine subpixel rendering being rather easy for SDF fonts. But, I can’t say I’ve seen it done.
This is "an entire doctoral research project in performant terminal emulation".
https://github.com/microsoft/terminal/issues/10362#issuecomm...
I was wondering if Casey would end up a mention on this topic.
That really was just the most absurd argument for Microsoft developers to engage in. It felt like a parody of the "optimisation is unnecessary because us developers are such Prima Donnas and simply toooooo expensive to lower ourselves to such levels" attitude that some people have.
He used a cache. A simple hashtable. That's it. He got an absurd speedup of something like hundreds of times faster.
What are developers smoking these days that they can't even envision ever doing something like this without undertaking a research program?
To this day people will debate this, as if there's a valid debate to be had!
"No, no, no, it's premature to optimise software that is... being released to a billion users in production."
"Casey is adding unnecessary complexity that will be hard to maintain... by using a fraction of the code Microsoft did to solve the same problem."
"It must be full of errors... well... other than the superior Unicode compliance."
"It's so much longer to develop high-performance code... the evidence is that it took Casey two weekends to write a nearly complete terminal emulator!"
Etc...
Look where we are today. Microsoft still steadfastly refuses to even look at Casey's solution, let alone adopt it wholesale. Years later there are still blog articles being written about the performance issues of the Windows Terminal.
PS: Notepad and Calculator got the same "treatment" and now struggle to keep up with key presses.
On the other hand you have the new Microsoft Edit which is some guy’s weekend TUI project that got canonized by MS.
I recommend the following reading (from https://news.ycombinator.com/item?id=36478892).
https://faultlore.com/blah/text-hates-you/
This website almost crashed my m1 macbook pro (renders at 1 fps or something), so I guess point taken: rendering text is not simple!
Looks like it's caused by `backdrop-filter: blur(6px);` on `.menu-content`. After disabling that it's slow, but not that slow.
Edit: This is with Firefox 144 on Ubuntu 22.04
With what browser? Seems fine with Chrome.
And on my desktop, scrolling this page is painfully slow.
Author: frontend technical lead, setting high code standards
what's worse is that scrolling doesn't actually work unless you have the text area focused/under the wheel... very weird. Which is even worse for PgUp/Down as who would think to focus the area first for scrolling???
> who would think to focus the area first for scrolling???
Sadly, this problem is common enough that click-before-keyboard-scrolling has become second nature for me.
> Author: frontend technical lead, setting high code standards
Haha, to be fair it's common to half-ass personal projects even if it's your primary domain.
MSDF is worth looking at:
https://github.com/Chlumsky/msdfgen
and
https://steamcdn-a.akamaihd.net/apps/valve/2007/SIGGRAPH2007...
The context is GPU's, things like three.js
But yes, drawing text is hard.
Here's Sabastian Lague's (Coding Adventure) video on font rendering -- https://www.youtube.com/watch?v=SO83KQuuZvg.
I wonder how the GPU version is implemented. One quad and one texture draw per glyph sounds very not scalable, but one quad per terminal, one texture atlas and one shader to draw glyphs from the atlas already sounds much better.
A terminal maximized on my screen says:
That's nothing for a modern GPU. For example, this benchmark[1] says to expect on the order of 10-800 million tri/s. At the low end of that, you'd have a frame time of 3.427ms -- 292 fps.The original Playstation could do 180 000 textured polygons per second[2], so it could've managed ~5 fps. Of course, you wouldn't render that many chars at its available output resolutions anyway. :)
[1] https://github.com/ctsilva/triangle-rendering-benchmarks#:~:... [2] https://en.wikipedia.org/wiki/PlayStation_technical_specific...
But if they naively execute 15120 draw calls...
One quad per glyph is very scalable, especially if you use instanced rendering. Each quad is just reading from a single texture atlas. GPUs are beastly blitting machines.
Runs at ~1500 FPS with a 6K screen of full text on my machine even when text is being updated at about the pace of a 150 WPM typist but you only update quads that strictly need to change and store font metrics on the GPU in a buffer. A full screen refresh where you send quad data for 750 Lorem ipsum paragraphs every frame runs at 300 FPS on my hardware.
Meta: this is kind of a repost, not even a month since last time [1].
[1]: https://news.ycombinator.com/item?id=45580559
Stupid question but what are the units used in the results tables??
fps?
Caching the fonts to a texture atlas is not an unusual idea. https://github.com/memononen/fontstash is a well known example of this. Odin has a native port meant to work in conjunction with its bindings to NanoVG. The Odin code is coupled to stb_freetype.
And another website made unusable thanks to inconsiderate use of javascript.