[HN Gopher] Rendering Crispy Text on the GPU
___________________________________________________________________
Rendering Crispy Text on the GPU
Author : ibobev
Score : 381 points
Date : 2025-06-13 02:27 UTC (20 hours ago)
(HTM) web link (osor.io)
(TXT) w3m dump (osor.io)
| dustbunny wrote:
| This is incredibly well written, interesting and useful.
| favorited wrote:
| I watched a conference talk[0] about using MSDFs for GPU text
| rendering recently, really interesting stuff!
|
| [0] https://www.youtube.com/watch?v=eQefdC2xDY4
| jbrooks84 wrote:
| Love high ppi retina displays for crispy text
| vecplane wrote:
| Subpixel font rendering is critical for readability but, as the
| author points out, it's a tragedy that we can't get pixel layout
| specs from the existing display standards.
| jasonthorsness wrote:
| I don't understand why, this has been a thing for decades :(.
| The article is excellent and links to this "subpixel zoo"
| highlighting the variety:
| https://geometrian.com/resources/subpixelzoo/
| crazygringo wrote:
| Only on standard resolution displays. And it's not even
| "critical" then, it's just a nice-to-have.
|
| But the world has increasingly moved to Retina-type displays,
| and there's very little reason for subpixel rendering there.
|
| Plus it just has so many headaches, like screenshots get tied
| to one subpixel layout, you can't scale bitmaps, etc.
|
| It was a temporary innovation for the LCD era between CRT and
| Retina, but at this point it's backwards-looking. There's a
| good reason Apple removed it from macOS years ago.
| f33d5173 wrote:
| Because apple controls all their hardware and can assume that
| everyone has a particulr set of features and not care about
| those without. The rest of the industry doesn't have that
| luxury.
| akdor1154 wrote:
| Apple could easily have ensured screens across their whole
| ecosystem had a specific subpixel alignment - yet they
| still nixed the feature.
| LoganDark wrote:
| The artifacts created by subpixel AA are dumb and
| unnecessary when the pixel density is high enough for
| grayscale to look good. Plus, with display scaling,
| subpixel AA creates artifacts. (Not like display scaling
| itself doesn't also create artifacts - I cannot tolerate
| the scaling artifacts on iPad, for example)
| wpm wrote:
| Apple cannot guarantee the pixel density will actually be
| high enough. They make computers and tablets that can
| attach to any external monitor.
|
| macOS looks *awful* on anything that isn't precisely
| 218ppi. Other than Apple's overpriced profit-machine
| displays, there are two displays that reach this: LG's
| Ultrafine 5K, and Dell's 6K (with its ugly, extraneous
| webcam attached to the top). Other 6K monitors were shown
| at CES this year but so far, I haven't actually found any
| for sale. EDIT: Correction, LG apparently doesn't sell
| the 5K Ultrafine anymore, at least on their website.
|
| That means, the odds are incredibly high that unless you
| buy the LG, or drop a wad on an overpriced Studio Display
| or the even worse valued Pro Display, your experience
| with macOS on an external monitor will be awful.
|
| That's even before we get into the terrible control we
| have in the OS over connection settings. I shouldn't have
| to buy BetterDisplay to pick a refresh rate I know my
| display is capable of on the port it's plugged into.
| eviks wrote:
| But the world has done nothing of the sorts: what's your
| assessment of what % of *all* used displays are of retina
| type?
| jeroenhd wrote:
| The funny thing is that in some ways it's true. Modern
| phones are all retina (because even 1080p at such a
| resolution is indistinguishable from pixelless). Tablets,
| even cheap ones, have impressive screen resolutions. I
| think the highest tea device I own may be my Galaxy Tab S7
| FE at 1600x2500.
|
| Computers, on the other hand, have stuck with 1080p, unless
| you're spending a fortune.
|
| I can only attribute it to penny pinching by the large
| computer manufacturers, because with the high-res tablets
| coming to market for Chromebook prices, I doubt they're
| unable to put a similarly high-res display in a similarly
| sized laptop without bumping the price up by 500 euros like
| I've seen them do.
| NoGravitas wrote:
| Even on standard resolution displays with standard subpixel
| layout, I see color fringing with subpixel rendering. I don't
| actually have hidpi displays anywhere but my phone, but I
| still don't want subpixel text rendering. People act like
| it's a panacea, but honestly the history of how we ended up
| with it is pretty specific and kind of weird.
| zozbot234 wrote:
| > ...I see color fringing with subpixel rendering.
|
| Have you tried adjusting your display gamma for each RGB
| subchannel? Subpixel antialiasing relies on accurate color
| space information, even more than other types of anti-
| aliased rendering.
| jeroenhd wrote:
| > the world has increasingly moved to Retina-type displays
|
| Not my world. Even the display hooked up to the crispy work
| MacBook is still 1080p (which looks really funky on macOS for
| some reason).
|
| Even in tech circles, almost everyone I know still has a
| 1080p laptop. Maybe some funky 1200p resolution to make the
| screen a bit bigger, but the world is not as retina as you
| may think it is.
|
| For some reason, there's actually quite a price jump from
| 1080p to 4k unless you're buying a television. I know the
| panels are more expensive, but I doubt the manufacturer is
| indeed paying twice the price for them.
| HappMacDonald wrote:
| Reading this message on a 4k (3840x2160 UHD) monitor I
| bought ten (10) years ago for $250usd.
|
| Still bemoaning the loss of the basically impossible (50"?
| I can't remember precisely) 4k TV we bought that same year
| for $800usd when every other 4k model that existed at the
| time was $3.3k and up.
|
| It's black point was "when rendering a black frame the set
| 100% appears to be unpowered" and the whitepoint was
| "congratulations, this is what it looks like to stare into
| baseball stadium floodlights". We kept it at 10% brightness
| as a matter of course and still playing arbitrary content
| obviated the need for any other form of lighting in our
| living room and dining room combined at night.
|
| It was too pure for this world and got destroyed by one of
| the kids throwing something about in the living room. :(
| josephg wrote:
| My desktop monitor is a 47" display ... also running at 4k.
| It's essentially a TV, adapted into a computer monitor. It
| takes up the whole width of my desk.
|
| It's an utterly glorious display for programming. I can
| have 3 full width columns of code side by side. Or 2
| columns and a terminal window.
|
| But the pixels are still the "normal" size. Text looks
| noticeably sharper with sub-pixel rendering. I get that
| subpixel rendering is complex and difficult to implement
| correctly, but it's good tech. It's still much cheaper to
| have a low resolution display with subpixel font rendering
| than render 4x as many pixels. To get the same clean text
| rendering at this size, I'd need an 8k display. Not only
| would that cost way more money, but rendering an 8k image
| would bring just about any computer to its knees.
|
| It's too early to kill sub pixel font rendering. It's good.
| We still need it.
| gfody wrote:
| > like screenshots get tied to one subpixel layout
|
| we could do with a better image format for screenshots -
| something that preserves vectors and text instead of
| rasterizing. HDR screenshots on Windows are busted for
| similar reasons.
| mrob wrote:
| Subpixel rendering isn't necessary in most languages. Bitmap
| fonts or hinted vector fonts without antialiasing give
| excellent readability. Only if the language uses characters
| with very intricate details such as Chinese or Japanese is
| subpixel rendering important.
| Fraterkes wrote:
| Ah so only 20% of the global population? Nbd
| zozbot234 wrote:
| It looks like the DisplayID standard (the modern successor to
| EDID) is at least intended to allow for this, per
| https://en.wikipedia.org/wiki/DisplayID#0x0C_Display_device_...
| . Do display manufacturers not implement this? Either way, it's
| information that could be easily derived and stored in a
| hardware-info database, at least for the most common display
| models.
| jeroenhd wrote:
| I don't think any OS exposes an API for this. There's a Linux
| tool I sometimes use to control the brightness of my screen
| that works by basically talking directly to the hardware over
| the GPU.
|
| Unfortunately, EDID isn't always reliable, either: you need
| to know the screen's orientation as well or rotated screens
| are going to look awful. You're probably going to need
| administrator access on computers to even access the hardware
| to get the necessary data, which can also be a problem for
| security and ease-of-use reasons.
|
| Plus, some vendors just seem to lie in the EDID. Like with
| other information tables (ACPI comes to mind), it looks
| almost like they just copy the config from another product
| and adjust whatever metadata they remember to update before
| shipping.
| layer8 wrote:
| "Tragedy" is a bit overstating it. Each OS could provide the
| equivalent of Window's former ClearType tuner for that purpose,
| and remember the results per screen or monitor model. You'd
| also want that in the inevitable case where monitors report the
| wrong layout.
| dcrazy wrote:
| The Slug library [1] is a commercial middleware that implements
| such a GPU glyph rasterizer.
|
| [1]: https://sluglibrary.com/
| bschwindHN wrote:
| They describe a fair amount of their algorithm directly on
| their website. Do they have patents for it? It would be fun to
| make an open source wgpu version, maybe using some stuff from
| cosmic-text for font parsing and layout. But if at the end of
| that I'd get sued by Slug, that would be no fun.
| grovesNL wrote:
| Slug is patented but there are other similar approaches being
| worked on (e.g., vello
| https://news.ycombinator.com/item?id=44236423 that uses
| wgpu).
|
| I also created glyphon (https://github.com/grovesNL/glyphon)
| which renders 2D text using wgpu and cosmic-text. It uses a
| dynamic glyph texture atlas, which works fine in practice for
| most 2D use cases (I use it in production).
| bschwindHN wrote:
| I did something similar with cosmic-text and glium, but it
| would be fun to have a vector rendering mode to do fancier
| stuff with glyph outlines and transforms for games and 3D
| stuff. And open source, of course.
|
| I suppose vello is heading there but whenever I tried it
| the examples always broke in some way.
| mxplerin wrote:
| I have an abandoned proof-of-concept of something similar
| that might be worth checking out
| https://github.com/mxple/fim
| vFunct wrote:
| I still don't understand why we need text rendered offline and
| stored in an atlas alongside tricks like SDFs, when GPUs have
| like infinite vertex/pixel drawing capabilities.. Even the
| article mentions writing glyph curves to an atlas. Why can't the
| shaders render text directly? There has to be a way to convert
| bezier to triangle meshes. I'm about to embark on a GPU text
| renderer for a CAD app and I hope to figure out why soon.
| dustbunny wrote:
| As far as I understand it, this is exactly what this article is
| about
| spookie wrote:
| Thin tris -> performance nuke
| modeless wrote:
| It's simply less expensive in most cases to cache the results
| of rendering when you render the same glyph over and over. GPUs
| are fast but not infinitely fast, and they are extremely good
| at sampling from prerendered textures.
|
| Also it's not just about speed, but power consumption. Once you
| are fast enough to hit the monitor frame rate then further
| performance improvements won't improve responsiveness, but you
| may notice your battery lasting longer. So there's no such
| thing as "fast enough" when it comes to rendering. You can
| always benefit from going faster.
| account42 wrote:
| > Once you are fast enough to hit the monitor frame rate then
| further performance improvements won't improve responsiveness
|
| This is not true, if your rendering is faster then you can
| delay the start of rendering and processing of input to be
| closer to the frame display time thus reducing input latency.
| modeless wrote:
| This is true but very rarely implemented.
| animal531 wrote:
| That's true, but in this case one can cache the output of
| e.g. a rendered letter and re-use that, without the
| intermediate SDF etc. steps.
|
| Of course for e.g. games that breaks if the font size
| changes, letters rotate and/or become skewed etc.
| MindSpunk wrote:
| The triangle density of even a basic font is crazy high at
| typical display sizes. All modern GPU architectures are very
| bad at handling high density geometry. It's very inefficient to
| just blast triangles at the GPU for these cases compared to
| using an atlas or some other scheme.
|
| Most GPUs dispatch pixel shaders in groups of 4. If all your
| triangles are only 1 pixel big then you end up with 3 of those
| shader threads not contributing to the output visually. It's
| called 'quad overdraw'. You also spend a lot of time processing
| vertices for no real reason too.
| dxuh wrote:
| GPUs are very fast, but not quite infinite. If you spend your
| GPU time on text, you can't spend it on something else. And
| almost always you would like to spend it on something else.
| Also the more GPU time you require, the faster the minimum
| required hardware needs to be. Text is cool and important, but
| maybe not important enough to lose users or customers.
| WithinReason wrote:
| Triangles are the wrong choice, but otherwise you make a good
| point. This guy uses an atlas because he renders fonts by super
| sampling bezier curves using up to 512 samples per pixel, which
| is very expensive. However, you could e.g. compute the integral
| of the intersection of the bezier curve area with the subpixel
| area much faster, which I think could run in real time without
| a need for an atlas and would be more accurate than
| supersampling.
| ben-schaaf wrote:
| GPUs don't have infinite vertex/pixel drawing capabilities.
| Rendering text directly is simply more expensive. Yes, you can
| do it, but you'll be giving up a portion of your frame budget
| and increasing power usage for no real benefit.
| account42 wrote:
| To expand on this, GPUs cannot rasterize text directly
| because they only work with triangles. You need to either
| implement the rasterization in shaders or convert the smooth
| curves in the font into enough triangles that the result
| doesn't look different (number of triangles required
| increases with font pixel size).
| andsoitis wrote:
| > Why can't the shaders render text directly?
|
| https://sluglibrary.com/ implements Dynamic GPU Font Rendering
| and Advanced Text Layout
| account42 wrote:
| GPU rasterizers don't do sub-pixel rendering. This is OK for
| most 3D geometry but for small text you want to take advantage
| of any additional resolution you can squeeze out.
|
| On the other hand, if you are rendering to an atlas anyway then
| you don't really need to bother with a GPU implementation for
| that an can just use an existing software font rasterizer like
| FreeType to generate that atlas for you.
| kvemkon wrote:
| GTK4 moved rendering to GPU and gave up on RGB subpixel
| rendering. I've heard, that this GPU-centric decision made it
| impractical to continue with RGB subpixel rendering. The article
| shows it is possible. So perhaps, the reason for GTK was another
| one or the presented solution would have disadvantages or just
| not integrate in the stack...
| dbcooper wrote:
| Cosmic Text (Cosmic DE) might do this on the GPU via swash. It
| has subpixel rendering.
| shmerl wrote:
| _> One of those new OLEDs that look so nice, but that have
| fringing issues because of their non-standard subpixel structure_
|
| From what I understood, it's even worse. Not just non standard,
| but multiple incompatible subpixel layouts that OLEDs have.
| That's the reason freetype didn't implement subpixel rendering
| for OLEDs and it's a reason to avoid OLEDs when you need to work
| with text. But it's also not limited to freetype, a lot of things
| like GUI toolkits (Qt, GTK. etc.) need to play along too.
|
| Not really sure if there is any progress on solving this.
|
| _> I really wish that having access to arbitrary subpixel
| structures of monitors was possible, perhaps given via the common
| display protocols._
|
| Yeah, this is a good point. May be this should be communicated in
| EDIDs.
| ipsum2 wrote:
| In theory, yes, but in practice, I write code on a 4k OLED
| display and haven't noticed any artifacting.
| shmerl wrote:
| Higher resolution might mask the issue more, but it's still
| there.
| account42 wrote:
| There are oleds with somewhat standard subpixel layouts. E.g.
| my laptop has a vertical(!) BGR layout that FreeType and KDE
| support just fine.
|
| I think the weird layouts are mostly due to needing different
| sizes for the different colors in HDR displays in order to not
| burn out one color (blue) too fast.
| shmerl wrote:
| May be, but I've seen bug reports with a bunch of layouts and
| nothing looks standard there. Steam Deck OLED is such
| example, Lenovo laptops, LG UltreaGear OLEDs and etc. I don't
| really see any commonality.
|
| * https://bugs.kde.org/show_bug.cgi?id=472340
|
| * https://gitlab.freedesktop.org/freetype/freetype/-/issues/1
| 1...
| oofabz wrote:
| Very impressive work. For those who aren't familiar with this
| field, Valve invented SDF text rendering for their games. They
| published a groundbreaking paper on the subject in 2007. It
| remains a very popular technique in video games with few changes.
|
| In 2012, Behdad Esfahbod wrote Glyphy, an implementation of SDF
| that runs on the GPU using OpenGL ES. It has been widely admired
| for its performance and enabling new capabilities like rapidly
| transforming text. However it has not been widely used.
|
| Modern operating systems and web browsers do not use either of
| these techniques, preferring to rely on 1990s-style Truetype
| rasterization. This is a lightweight and effective approach but
| it lacks many capabilities. It can't do subpixel alignment or
| arbitrary subpixel layout, as demonstrated in the article.
| Zooming carries a heavy performance penalty and more complex
| transforms like skew, rotation, or 3d transforms can't be done in
| the text rendering engine. If you must have rotated or
| transformed text you are stuck resampling bitmaps, which looks
| terrible as it destroys all the small features that make text
| legible.
|
| Why the lack of advancement? Maybe it's just too much work and
| too much risk for too little gain. Can you imagine rewriting a
| modern web browser engine to use GPU-accelerated text rendering?
| It would be a daunting task. Rendering glyphs is one thing but
| how about handling line breaking? Seems like it would require a
| lot of communication between CPU and GPU, which is slow, and deep
| integration between the software and the GPU, which is difficult.
| moron4hire wrote:
| SDF is not a panacea.
|
| SDF works by encoding a localized _D_istance from a given pixel
| to the edge of character as a _F_ield, i.e. a 2d array of data,
| using a _S_ign bit to indicate whether that distance is inside
| or outside of the character. Each character has its own little
| map of data that gets packed together into an image file of
| some GPU-friendly type (generically called a "map" when it does
| not represent an image meant for human consumption), along with
| a descriptor file of where to find the sub-image of each
| character in that image, to work with the SDF rendering shader.
|
| This definition of a character turns out to be very robust
| against linear interpolation between field values, enabling
| near-perfect zoom capability for relatively low resolution
| maps. And GPUs are pretty good at interpolating pixel values in
| a map.
|
| But most significantly, those maps have to be pre-processed
| during development from existing font systems for every
| character you care to render. Every. Character. Your. Font.
| Supports. It's significantly less data than rendering every
| character at high resolution to a bitmap font. But, it's also
| significantly more data than the font contour definition
| itself.
|
| Anything that wants to support all the potential text of the
| world--like an OS or a browser--cannot use SDF as the text
| rendering system because it would require the SDF maps for the
| entire Unicode character set. That would be far too large for
| consumption. It really only works for games because games can
| (generally) get away with not being localized very well, not
| displaying completely arbitrary text, etc.
|
| The original SDF also cannot support Emoji, because it only
| encodes distance to the edges of a glyph and not anything about
| color inside the glyph. Though there are enhancements to the
| algorithm to support multiple colors (Multichannel SDF), the
| total number of colors is limited.
|
| Indeed, if you look closely at games that A) utilize SDF for
| in-game text and B) have chat systems in which global
| communities interact, you'll very likely see differences in the
| text rendering for the in-game text and the chat system.
| rudedogg wrote:
| If I understand correctly, the authors approach doesn't
| really have this problem since they only upload the glyphs
| being used to the GPU (at runtime). Yes you still have to
| pre-compute them for your font, but that should be fine.
| chii wrote:
| but the grandparent post is talking about a browser - how
| would a browser pre-compute a font, when the fonts are
| specified by the webpage being loaded?
| onion2k wrote:
| The most common way this is done is by parsing the font
| and generating the SDF fields on the fly (usually using
| Troika - https://github.com/protectwise/troika/blob/main/
| packages/tro...). It slows down the time to the first
| render, but it's only a matter of hundreds of ms not
| seconds, and as part of rendering 3D on webpage no one
| really expects it to be _that_ fast to start up.
| fc417fc802 wrote:
| > It slows down the time to the first render
|
| Would caching (domain restricted ofc) not trivially fix
| that? I don't expect a given website to use very many
| fonts or that they would change frequently.
| krona wrote:
| webassembly hosting freetype in a webworker. not too
| difficult.
| cyberax wrote:
| Why not prepare SDFs on-demand, as the text comes in?
| Realistically, even for CJK fonts you only need a couple
| thousand characters. Ditto for languages with complex
| characters.
| meindnoch wrote:
| Because it's slow.
| kevingadd wrote:
| Generating SDFs is _really_ slow, especially if you can 't
| use the GPU to do it, and if you use a faster algorithm it
| tends to produce fields with glitches in them
| Am4TIfIsER0ppos wrote:
| > complex transforms like skew, rotation, or 3d transforms
| can't be done
|
| Good. My text document viewer only needs to render text in
| straight lines left to right. I assume right to left is almost
| as easy. Do the Chinese still want top to bottom?
| Fraterkes wrote:
| God I hope that you don't work on anything text-related
| ulfbert_inc wrote:
| If you work with ASCII-only monospaced-only text, then yeah
| sure. It gets weird real quick outside of those boundaries.
| adwn wrote:
| > _Good. My text document viewer only needs to render text in
| straight lines left to right._
|
| Yes, _inconceivable_ that somebody might ever want to render
| text in anything but a "text document viewer"!
| Philpax wrote:
| Believe it or not, other people who aren't you exist.
| ChrisClark wrote:
| A classic example of main character syndrome, pun not
| intended :D
| vendiddy wrote:
| Thanks for the breakdown! I love reading quick overviews like
| this.
| chrismorgan wrote:
| > _Can you imagine rewriting a modern web browser engine to use
| GPU-accelerated text rendering? [...] Rendering glyphs is one
| thing but how about handling line breaking?_
|
| I'm not sure why you're saying this: text shaping and layout
| (including line breaking) are almost completely unrelated to
| rendering.
| zozbot234 wrote:
| > Can you imagine rewriting a modern web browser engine to use
| GPU-accelerated text rendering?
|
| https://github.com/servo/pathfinder uses GPU compute shaders to
| do this, which has way better performance than trying to fit
| this task into the hardware 3D rendering pipeline (the SDF
| approach).
| Someone wrote:
| > Can you imagine rewriting a modern web browser engine to use
| GPU-accelerated text rendering?
|
| It is tricky, but I thought they already (partly) do that.
| https://keithclark.co.uk/articles/gpu-text-rendering-in-webk...
| (2014):
|
| _"If an element is promoted to the GPU in current versions of
| Chrome, Safari or Opera then you lose subpixel antialiasing and
| text is rendered using the greyscale method"_
|
| So, what's missing? Given that comment, at least part of the
| step from UTF-8 string to bitmap can be done on the GPU, can't
| it?
| zozbot234 wrote:
| The issue is not subpixel rendering per se (at least if
| you're willing to go with the GPU compute shader approach,
| for a pixel-perfect result), it's just that you lose the
| complex software hinting that TrueType and OpenType fonts
| have. But then the whole point of rendering fonts on the GPU
| is to support smooth animation, whereas a software-hinted
| font is statically "snapped" to the pixel/subpixel grid. The
| two use cases are inherently incompatible.
| kevingadd wrote:
| Just for the record, text rendering - including with subpixel
| antialiasing - has been GPU accelerated on Windows for ages and
| in Chrome/Firefox for ages. Probably Safari too but I can't
| testify to that personally.
|
| The idea that the state of the art or what's being shipped to
| customers haven't advanced is false.
| rossant wrote:
| I can't find the link to the code is it available?
| xiaoiver wrote:
| If you're interested in how to implement SDF and MSDF in WebGL /
| WebGPU, take a look at this tutorial I wrote:
| https://infinitecanvas.cc/guide/lesson-015#msdf.
| Buttons840 wrote:
| This looks great. I have some interest in WGPU (Rust's WebGPU
| implementation), and your tutorial here appears to be an
| advance course on it--thought it doesn't advertise itself as
| such. I've translated JavaScript examples to Rust before, and
| it's ideal for learning, because I can't just copy/paste code,
| but the APIs are close enough that it's easy to port the code
| and it gives you an excuse to get used to using the WGPU docs.
| tamat wrote:
| wow, I love the format of the site.
|
| Can you tell me more about it? I love making tutorials about
| GPU stuff and I would love to structure them like yours.
|
| Is it an existing template? Is it part of some sort of course?
| EnPissant wrote:
| It's important to point out that SDFs compute a pixel distance to
| the closest edge, while a more traditional font renderer computes
| pixel coverage. Pixel coverage is optimal. For small fonts, SDFs
| can look bad in places where edges meet. Maybe this is less of an
| issue on high PPI displays. Source: I implemented a SDF renderer
| and it looked worse than freetype.
| account42 wrote:
| The coverage/distance distinction isn't relevant - you can
| trivially compute the coverage in your distance field renderer.
|
| The point about intersections (or hard corners in general) is
| _the_ issue with distance fields though. You can counteract it
| a bit by having multiple distance fields and rendering the
| intersection of them. See e.g.
| https://github.com/Chlumsky/msdfgen
| EnPissant wrote:
| You don't have the information to compute the coverage. Hard
| corners is only an issue when scaling up. I am saying they
| are worse even at 100% scale.
| pjmlp wrote:
| While the article is great, I am missing a WebGL/WebGPU demo to
| go along the article, instead of videos only.
| xiaoiver wrote:
| Maybe you can take a look at this tutorial I wrote:
| https://infinitecanvas.cc/guide/lesson-015#msdf.
| pjmlp wrote:
| Thanks, looks like a nice reading over the weekend.
| kh_hk wrote:
| This is a good resource and looks very well written. Many
| thanks for sharing!
| z3t4 wrote:
| When making a text editor from scratch my biggest surprise was
| how slow/costly text rendering is.
| eptcyka wrote:
| Would be great if the videos in the article were muted so that
| iOS didn't stop playing my music whilst reading this.
| osor_io wrote:
| Author here, didn't expect the post to make it here! Thanks so
| much to everyone who's reading it and participating in the
| interesting chat <3
| muglug wrote:
| It's a great post!
|
| What happened to the dot of the italic "j" in the first video?
| Bengalilol wrote:
| Amazing read, I am so envious of being able to go down such
| "holes".
|
| As a side note, from the first "menu UI" until the end, I had the
| Persona music in my head ^^ (It was a surprise reading the final
| words)
| meindnoch wrote:
| Impressive work!
|
| But subpixel AA is futile in my opinion. It was a nice hack in
| the aughts when we had 72dpi monitors, but on modern "retina"
| screens it's imperceptible. And for a teeny tiny improvement, you
| get many drawbacks:
|
| - it only works over opaque backgrounds
|
| - can't apply any effect on the rasterized results (e.g.
| resizing, mirroring, blurring, etc.)
|
| - screenshots look bad when viewed on a different display
| mistercow wrote:
| Also, even if, as the author wishes, there were a protocol for
| learning the subpixel layout of a display, and that got
| widespread adoption, you can bet that some manufacturers would
| screw it up and cause rendering issues that would be very
| difficult for end users to understand.
| ahartmetz wrote:
| This kind of problem has been dealt with before. It has a
| known solution:
|
| - A protocol to ask the hardware
|
| - A database of quirks about hardware that is known to
| provide wrong information
|
| - A user override for when neither of the previous options do
| the job
| ahartmetz wrote:
| What you're saying is "I have a high DPI screen, don't care
| about those who don't". Because these other arguments are
| really unimportant compared to the the better results of
| subpixel rendering where applicable.
| NoGravitas wrote:
| Not sure about that. I don't really like subpixel rendering
| on a 100dpi screen very much because of color fringing. But
| add in the other disadvantages and it just seems not worth
| it.
| ahartmetz wrote:
| Subpixel rendering is configurable. Some algorithms are
| patented, but the patents have expired. I'm not sure if the
| "good" algorithms have made it to all corners of computing.
| I use latest Kubuntu, slight hinting and subpixel
| rendering. It looks very good to me.
|
| On my rarely used Windows partition, I have used ClearType
| Tuner (name?) to set up ClearType to my preferences. The
| results are still somewhat grainy and thin, but that's a
| general property of Windows font rendering.
| fleabitdev wrote:
| Getting rid of subpixel AA would be a huge simplification, but
| quite a lot of desktop users are still on low-DPI monitors. The
| Firefox hardware survey [1] reports that 16% of users have a
| display resolution of 1366x768.
|
| This isn't just legacy hardware; 96dpi monitors and notebooks
| are still being produced today.
|
| [1]: https://data.firefox.com/dashboard/hardware
| vitorsr wrote:
| See also Linux Hardware Database (developer biased) [1] and
| Steam Hardware & Software Survey (gamer biased) [2].
|
| [1] https://linux-hardware.org/?view=mon_resolution
|
| [2] https://store.steampowered.com/hwsurvey
| layer8 wrote:
| Even more strikingly, two-thirds are using a resolution of
| FHD or lower, and only around a sixth are using QHD or 4K.
| Low-DPI is still the predominant display situation on the
| desktop.
| exDM69 wrote:
| 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] https://www.youtube.com/watch?v=SO83KQuuZvg [1]
| https://pomax.github.io/bezierinfo/#splitting [2]
| https://ieeexplore.ieee.org/document/1528437
| meindnoch wrote:
| >Monotonic Bezier curves are contained within the bounding box
| of its end points
|
| What's a "monotonic Bezier curve"?
|
| Btw, _every_ Bezier curve is contained within its control
| points ' convex hull. It follows from the fact that all points
| on a Bezier curve are some convex combination of the control
| points. In other words, the Bezier basis functions sum to 1,
| and are nonnegative everywhere.
| exDM69 wrote:
| > What's a "monotonic Bezier curve"?
|
| Good question!
|
| It's a Bezier curve that has a non-zero derivative for t=0..1
| (exclusive).
|
| Just your high school calculus definition of monotonic.
|
| To get from a general quadratic Bezier to monotonic sections,
| you solve the derivative for zeros in x and y direction (a
| linear equation). If the zeros are between 0 and 1
| (exclusive), split the Bezier curve using de Casteljau's at
| t=t_0x and t=t_0y. For each quadratic Bezier you get one to
| three monotonic sections.
|
| > every Bezier curve is contained within its control points'
| convex hull.
|
| This is true, but only monotonic Bezier curves are contained
| between the AABB formed by the two end points (so control
| points in the middle don't need to be considered outside the
| AABB).
|
| For a quadratic Bezier this means that it is monotonic iff
| the middle control point is inside the AABB of the two end
| points.
|
| The monotonicity is a requirement for all the GPU warp level
| AABB magic to happen (which is a nice 10x to 20x perf
| increase in my benchmarks). At worst you'd have to deal with
| 3x the number of curves after splitting (still a win), but
| because _most curves in fonts are monotonic_ the splitting
| doesn 't increase the the number of curves a lot in practice.
|
| Monotonicity also implies that the quadratic equations have
| only one unique solution for any horizontal or vertical line.
| No need to classify the roots as in Lengyel's method.
| purplesyringa wrote:
| This sounds amazing, personally I'd love to take a look at the
| project or read a blog post when you're done.
| exDM69 wrote:
| Thanks for the words of encouragement. I need more time to
| turn this prototype into a practical piece of software and/or
| a publication (blog post or research paper). Unfortunately
| there are only so many hours in a day.
|
| To actually render text I would still need to add text
| shaping to get from strings of text to pixels on the screen.
|
| But a bigger problem is how to integrate it into someone
| else's software project. I have the rasterizer GPU shader and
| some CPU preprocessing code and the required 3d API code (I'm
| using Vulkan). I'm not sure how people usually integrate this
| kind of components to their software, do they just want the
| shader and preprocessor or do they expect the 3d API code
| too. Packaging it into a library that has the Vulkan code too
| has its own problems with interoperability.
|
| You need to hope that it rains during my summer vacation,
| maybe this project will see some progress :)
| animal531 wrote:
| I find it amazing how many people are working and/or playing
| with text rendering at the moment. I work in Unity and have
| also been dipping my toes, but trying to think of doing some
| modern enhancements to the whole thing.
|
| The Unity solution is quite limiting, someone about 10 years
| ago made a great asset and was actively developing it, but then
| they bought it and integrated it into their subsystem, after
| that all development basically stopped. Now in modern times a
| lot of games are using Slug, and it renders some really
| beautiful text, but unfortunately they are doing large scale
| licensing to big companies only.
|
| Some thoughts I've come up with: 1. Creating text is basically
| a case of texture synthesis. We used to just throw it into
| textures and let the GPU handle it, but obviously its a general
| purpose device and not meant to know what information (such as
| edges) are more important than others. Even a 2k texture of a
| letter doesn't look 100% when you view it at full screen size.
|
| 2. Edge Lines: I have a little business card here from my
| Doctor's office. At e.g. 20-30cm normal human reading distance
| the text on it looks great, but zooming in close you can see a
| lot of differences. The card material isn't anywhere close to
| flat and the edge lines are really all over the place, in all
| kinds of interesting ways.
|
| 3. Filling: The same happens for the center filled part of a
| letter or vector, when you zoom in you can see a lot of flaws
| creep in, e.g. 5% of the visible layer has some or the other
| color flaw. There are black flecks on the white card,
| white/black flecks in a little apple logo they have etc.
|
| 4. So basically I want to add a distance parameter as well as
| using size. Both these cases for just rendering normal 2d text
| is relatively irrelevant, but in 3d people will often go stand
| right up against something, so the extra detailing will add a
| lot. For the synthesis part, there's no reason that any of the
| lines should be a solid fill instead of for example some
| artistic brush stroke, or using some derivative noise curves to
| create extra/stable information/detailing.
|
| 5. Another thing to look at might be work subdivision. Instead
| of rendering a whole set of letters in N time, if the camera is
| relatively stable we can refine those over successive frames to
| improve detailing, for example go from 2 to M subdivisions per
| curve.
|
| 6. There are numerous available examples such as the following
| concurrent B-Tree: https://www.youtube.com/watch?v=-Ce-XC4MtWk
| In their demo they fly into e.g. a planetary body and keep
| subdividing the visible terrain on-screen to some minimum size;
| then they can synthesize extra coherent detailing that matches
| that zoom level from some map, in their case e.g. noise for the
| moon, or code for water etc.
|
| I find that a lot of the people working on text are sort of
| doing their own thing data structure wise, instead of looking
| at these already implemented and proven concurrent solutions.
| Here is another interesting paper, DLHT: A Non-blocking
| Resizable Hashtable with Fast Deletes and Memory-awareness /
| https://arxiv.org/abs/2406.09986
|
| Not to say that those are the way to parallelize the work, or
| even if that is necessary, but it might be an interesting area
| where one can increase detailing.
| enriquto wrote:
| > You might want to place the glyph at any position on the
| screen, not necessarily aligned with the pixel grid
|
| No. I don't. This is a horrifying concept. It implies that the
| same character may look different every time is printed! This is
| extremely noticeable and really awful. For example when you align
| equal signs on consecutive lines of code, you notice straight
| away whether the characters are different.
|
| Nowadays pixels are so small that I don't understand why don't we
| all just use good quality bitmap fonts. I do, and couldn't be
| happier with them. They are crisp to a fault, and their correct
| rendering does not depend on the gamma of the display (which is a
| serious problem that TFA does not even get into).
| purplesyringa wrote:
| I mean, there's literally an example animation in the post.
| Maybe you don't want subpixel positioning in long texts, but
| you absolutely need it whenever you need animated transitions
| or animation in general.
| b0a04gl wrote:
| if we can stream video textures to gpu in real time, why can't we
| stream sdf glyphs the same way? what makes text rendering need so
| much prep upfront?
| neurostimulant wrote:
| I wonder if editors that use gpu text rendering like Zed would
| use something like this to improve their text rendering. Or maybe
| they already do?
| pimlottc wrote:
| "Crisp text" would be more accurate, I thought maybe this was
| going to be about rendering intentionally degraded text, like in
| memes
| elia_42 wrote:
| Really interesting!
| adamrezich wrote:
| Nobody here seems to have noticed but the "pseudocode" in the
| article is in fact Jai code, which you can tell by the `xx` in
| base_slot_coordinates := decode_morton2_16(xx index);
|
| which in Jai means "autocast".
| king_geedorah wrote:
| Indeed it is. Nice.
| tuna74 wrote:
| To all people that want sub-pixel rendering: Unless you know the
| sub-pixel grid on the display it is going to look worse.
| Therefore the only good UX that you can do is to ask the user for
| every display they use if they want to turn it on for that
| specific display. The OS also have to handle rotations etc as
| well.
| strongpigeon wrote:
| Even better would be as the author suggests: having a way for
| the display to indicate its subpixel structure to the system.
| atoav wrote:
| Well it is a style of text you _could_ use to emphasize
| certain words, which for most people translates to a
| different pronounciation of said word in their heads.
| mananaysiempre wrote:
| I always think about the Samsung SyncMaster 173P I used to
| have once. It was good for its time, but not usable with any
| kind of subpixel antialiasing (even on Gnome which allowed to
| you to choose between horizontal and vertical RGB and BGR):
| the subpixel grid on it was _diagonal_. Absolutely tractable
| as far as the signal-processing math, yet would be unlikely
| to fit in any reasonable protocol.
| tuna74 wrote:
| There is, but displays do not send out correct information
| unfortunately.
| cchance wrote:
| After seeing the cursive all i immediately thought was "who the
| fuck ever thought cursive was a good idea" lol
| adiabatichottub wrote:
| People who wrote lots of letters, that's who. The internet and
| free long-distance calling killed cursive.
| jml7c5 wrote:
| People who handwrote. (And especially people who handwrote with
| quills and fountain pens -- usable ballpoint pens are only 70
| years old.)
| moralestapia wrote:
| Lots of downvotes on this.
|
| Why? There is absolutely nothing wrong with this comment.
|
| @dang I know one is not supposed to complain about this, but this
| has become noticeably bad in the past ... two years? This is not
| good in the long term.
| tomhow wrote:
| We don't know why people downvote things but it may be because
| people think it's nitpicking. A few people upvoted it, a few
| downvoted it. It's no big deal and nothing new. Please stop
| doing this.
___________________________________________________________________
(page generated 2025-06-13 23:01 UTC)