Page MenuHome

BLF: Gamma Correction
ClosedPublic

Authored by Harley Acheson (harley) on Nov 26 2021, 2:27 AM.

Details

Summary

Gamma correction for glyph coverage values.


FreeType glyph rendering gives us a bitmap of coverage amounts, not alpha values. This means that a pixel that is half-covered will have a value of 0.5. But our output devices don't have such a linear response so FreeType expects us to gamma correct these values. Without doing so the antialiasing drops off too quickly and gives us results that look too thin.

This uses the highly-recommended gamma of 1.43, rather than more normal values of 2.2 or 1.8. This is best described here: https://www.puredevsoftware.com/blog/2019/01/22/sub-pixel-gamma-correct-font-rendering/

The reasons are historical. Because so many programmers have neglected gamma blending for so long, people who have created fonts have tried to work around the problem of fonts looking too thin by just making the fonts thicker! Obviously it doesn’t help the jaggedness, but it does make them look the proper weight, as originally intended. The obvious problem with this is that if we want to gamma blend correctly many older fonts will look wrong. So we compromise, and use a lower gamma value, so we get a bit better antialiasing, but the fonts don’t look too heavy.

Following shows the change. The gamma-corrected one is the "brighter" one:

It makes the characters look a bit smoother and fuller with better antialiasing. But because it is a change it might be best to pair this with a change of font too.

Diff Detail

Repository
rB Blender

Event Timeline

Harley Acheson (harley) requested review of this revision.Nov 26 2021, 2:27 AM
Harley Acheson (harley) created this revision.
Harley Acheson (harley) edited the summary of this revision. (Show Details)

Updated to the current state of master.

Harley Acheson (harley) added a project: Core.

Updated to the current state of master.

Updated to the current state of master.

Updated to the current state of master.

Updated to the current state of master.

Updated to the current state of master.

The patch seems OK although we could consider doing this in the shader too.

Adding Julian, to get a second opinion.

source/blender/blenfont/intern/blf_glyph.c
186–193

Either put comments above the function or inside the function body.

@Campbell Barton (campbellbarton) - we could consider doing this in the shader too.

Although that would be a GPU operation on every single text output, while this is a CPU operation on only the cached glyphs (on just the first “a”, not every usage of “a”). But I don’t have the GPU knowledge to really judge this TBH.

Harley Acheson (harley) marked an inline comment as done.

Correction of comment as per review.

Updated to the current state of master.

Updated to the current state of master.

Julian Eisel (Severin) requested changes to this revision.EditedAug 17 2022, 3:28 PM

This is definitely a nice improvement, and indeed gamma corrected (well, let's say applying some transform function that brings us somewhat closer to sRGB transform function) font rendering is needed for perceptually improved anti-aliasing.

However! :) There are some things to consider. I had a suspicion so I discussed this with @Troy Sobotka (sobotka) at Siggraph to confirm and clarify things.

We should apply a transform to sRGB to the entire UI, not just fonts. [1] This would also improve the anti-aliasing of widgets, other UI geometry and I think anti-aliasing of viewport contents as well (viewport as in, 3D View, Image Editor, sequencer preview, ...). More importantly, it would get the UI ready for display on HDR-ish displays. Also, if we only transformed font color, we start having some parts of the UI drawn with gamma correction, some without, and some mixed (wherever font values are not fully opaque). Not great for color managed color picking.

Now, despite all that, I think it's fine to apply this patch for now, since it's a nice visual improvement until we have the UI properly transformed to display space. Color pickers aren't color managed properly yet either, so that shouldn't be a big issue. But I'd suggest putting it behind some #ifdef USE_FONT_GAMMA_CORRECTION or similar, so it's clear what would have to be removed once that is done, together with a TODO/XXX comment. Requesting changes for that.

Also:
Grey-tones will be a bit brighter now of course. E.g. the Modo theme which has fonts with a grey value close to 50%:


I think the difference is subtle, and not worth adding versioning code for.

[1] We may be able to keep things simple, by doing drawing in linear space and simply applying the sRGB inverse EOTF transform (similar to applying a ^1/2.2 transform) on the entire framebuffer. Although widgets like color wheels, color ramps etc. may complicate this, we have to discuss this some more. Either way, we'd also have to dim down the theme colors to compensate the effective brightness. Some versioning code that applies the sRGB EOTF transform would be fine. We may have to do some trickery to still draw old fonts with reduced "gamma", to avoid the overly thickened look.


@Troy Sobotka (sobotka) any objections? Anything to add?

This revision now requires changes to proceed.Aug 17 2022, 3:28 PM

is needed for perceptually improved anti-aliasing.

This is the actual reason that the sampled values look “better”; we are reconstructing the points that, were we to see them as “on off” binary pixels, the data point the sampling crosses through would be a closer approximation. As such, it is wise to perhaps think of this operation as a “perceptual brightness” prefilter, from which the sampling pulls from. *Not* uniform tristimulus, as the reconstruction will end up too dark.

But I'd suggest putting it behind some #ifdef USE_FONT_GAMMA_CORRECTION or similar, so it's clear what would have to be removed once that is done, together with a TODO/XXX comment. Requesting changes for that.

Maybe if folks are going to read the code, it makes more sense to educate folks that the pass is not “gamma correction” but rather something more instructive such as “perceptual prefilter”?

We may be able to keep things simple, by doing drawing in linear space and simply applying the sRGB inverse EOTF transform (similar to applying a ^1/2.2 transform) on the entire framebuffer.

Remember, when downsampling, the proper domain is uniform tristimulus. When reconstructing (“upsampling” or predicting edge values) elements that do not exist, the proper domain to sample from is a perceptual-like base unit.

For further reading on this subject, and a wonderful visualization, see page 51 of “A Fresh Look at Generalized Sampling” by Diego Nehab and Hugues Hoppe.

Now behind a BLF_GAMMA_CORRECT_GLYPHS define with better comments to explain what it is doing and why. And a note about how it should be reconsidered if we transform the entire UI.

This revision is now accepted and ready to land.Aug 18 2022, 8:10 PM
This revision was automatically updated to reflect the committed changes.