Nothing Special   »   [go: up one dir, main page]

Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

common: render text buffers with opaque background #1631

Merged
merged 1 commit into from
Mar 17, 2024

Conversation

jlindgren90
Copy link
Contributor

After a roundabout discussion[1] with wlroots devs, it's become apparent that subpixel text rendering (a.k.a. "ClearType") does not work properly when rendering over a transparent background, as labwc currently does.

Basically it comes down to the fact that the color of semi-transparent pixels (which is adjusted redder or bluer to compensate for RGB subpixel alignment) depends somewhat on background color. When rendering over transparency, the text engine doesn't know the intended background color and can't adjust the pixel colors correctly.

With Pango/Cairo, the end result can range from grayscale rendering (no subpixel rendering at all) to wrong/oversaturated colors (for example, bright pink pixels when rendering white text on blue background).

This change solves the issue by first filling the text buffer with an opaque background color before rendering the text over it. Currently, this is easy since the background is always a solid color. It may be a little more complex (but doable) if we implement gradients in future.

Note that GTK 4 (and to some degree, recent versions of Microsoft Windows) avoid this issue by disabling subpixel rendering altogether. I would much prefer that labwc NOT do this -- it results in noticeably blurrier text on non-retina LCD screens, which are still common.

[1] https://gitlab.freedesktop.org/wlroots/wlroots/-/issues/3822

Screenshots (zoom in to see detail):

White on blue, WLR_RENDERER=vulkan, before/after:
vulkan-before
vulkan-after

Black on white, WLR_RENDERER=pixman, before/after:
pixman-bw-before
pixman-bw-after

After a roundabout discussion[1] with wlroots devs, it's become apparent
that subpixel text rendering (a.k.a. "ClearType") does not work properly
when rendering over a transparent background, as labwc currently does.

Basically it comes down to the fact that the color of semi-transparent
pixels (which is adjusted redder or bluer to compensate for RGB subpixel
alignment) depends somewhat on background color. When rendering over
transparency, the text engine doesn't know the intended background color
and can't adjust the pixel colors correctly.

With Pango/Cairo, the end result can range from grayscale rendering (no
subpixel rendering at all) to wrong/oversaturated colors (for example,
bright pink pixels when rendering white text on blue background).

This change solves the issue by first filling the text buffer with an
opaque background color before rendering the text over it. Currently,
this is easy since the background is always a solid color. It may be a
little more complex (but doable) if we implement gradients in future.

Note that GTK 4 (and to some degree, recent versions of Microsoft
Windows) avoid this issue by disabling subpixel rendering altogether. I
would much prefer that labwc NOT do this -- it results in noticeably
blurrier text on non-retina LCD screens, which are still common.

[1] https://gitlab.freedesktop.org/wlroots/wlroots/-/issues/3822
@ahesford
Copy link
Member

Nice find! I noticed the strange coloration with sub-pixel rendering (which seems worse with Vulkan), but never would have figured this was related to transparent backgrounds.

@Consolatis
Copy link
Member
Consolatis commented Mar 17, 2024

Very nice find indeed!

LGTM, didn't test.

Edit:

Currently, this is easy since the background is always a solid color. It may be a little more complex (but doable) if we implement gradients in future.

Lets deal with that when we actually do support gradients. We might also want to auto scale the gradients based on the output they are currently rendered on. So maybe we can just render the pango text directly on the gradient buffer.

Edit 2:
Actually, after reading though the linked wlroots issue:
We do create the cairo surface with CAIRO_FORMAT_ARGB32 and then set the wlroots buffer format to DRM_FORMAT_ARGB8888.
I don't know enough about color formats to verify if that is actually correct.

See src/buffer.c buffer_create_cairo().

@jlindgren90
Copy link
Contributor Author

Edit 2: Actually, after reading though the linked wlroots issue: We do create the cairo surface with CAIRO_FORMAT_ARGB32 and then set the wlroots buffer format to DRM_FORMAT_ARGB8888. I don't know enough about color formats to verify if that is actually correct.

For what it's worth, most of the discussion on the wlroots issue (before Félix weighed in) ended up being irrelevant. My original theories were wrong, and the pixel/color formats themselves are fine.

The issue is really just that Pango/Cairo does not behave properly (and in some cases actually produces out-of-range RGB values, which is a bug) when doing subpixel rendering over transparency. The behavior could be improved (e.g. limit the RGB values to be no greater than the alpha value -- I tried that as a post-processing step, and it helped) but the result would still be less than ideal. The subpixel rendering really needs to be done over an opaque background to work correctly. That's my understanding, anyway.

@Consolatis
Copy link
Member

For what it's worth, most of the discussion on the wlroots issue (before Félix weighed in) ended up being irrelevant. My original theories were wrong, and the pixel/color formats themselves are fine.

Well it was interesting nevertheless. Even though I will likely have forgotten everything within two weeks again.
The intimate details of color formats are just not my cup of tea, I prefer things to be slightly higher level.

The subpixel rendering really needs to be done over an opaque background to work correctly. That's my understanding, anyway.

Should we add the cairo issue within the comment?

Anyway, feel free to go for the rebase and merge if you are happy with the PR. You have invested way more time in debugging and testing the solution / workaround than all of us and are thus the most qualified person to judge it.

@ahesford
Copy link
Member

Just tested this on my laptop, and the difference is immediately visible. I always assumed the color artifacts were caused by resampling issues with fractional scaling.

@johanmalm johanmalm merged commit 4fa51b9 into labwc:master Mar 17, 2024
6 checks passed
@jlindgren90 jlindgren90 deleted the opaque-text-bg branch March 17, 2024 19:14
@johanmalm
Copy link
Collaborator

Thanks. Fantastic work.

This adds a limitation to how we composite SSD, but that's a discussion for a different day.

For what it's worth, I'm increasingly thinking that that we ought to consider assembling multiple "parts" in one cairo-surface anyway. This needs to experimentation, speed-testing and a strategy. For example, I think we ought to consider just creating one surface for the whole titlebar (incl. corners).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants