raphamorim / rio

A hardware-accelerated GPU terminal emulator focusing to run in desktops and browsers.
https://raphamorim.io/rio
MIT License
4.09k stars 136 forks source link

Disable anti-alias on font rendering #732

Open melroy89 opened 1 month ago

melroy89 commented 1 month ago

Me again. 😆 Since Rio is rendering from it's own GPU engine it will not use the ~/.config/fontconfig/fonts.conf like all my other programs.

For example I use:

  <match target="pattern">
    <test qual="any" name="family"><string>DejaVuSansM Nerd Font Mono</string></test>
    <edit name="antialias" mode="assign"><bool>false</bool></edit>
    <edit name="hintstyle" mode="assign"><const>hintslight</const></edit>
    <edit name="hinting" mode="assign"><bool>false</bool></edit>
    <edit name="rgba" mode="assign"><const>rgb</const></edit>
    <edit name="lcdfilter" mode="assign"><const>lcddefault</const></edit>
  </match>

Yeah, I really dislike anti-alias. I use a very specific font that is very crisp (especially) when anti-alias is disabled. Which looks so much better (believe me).

It would therefor be nice to have a rendering option to turn off anti-alias.


For reference, here is a next to next comparison (left is my old XFCE terminal, anti-alias off, hinting off. On the right is Rio).

image

(Important: Open the image is a new tab, so you don't get browser blurry artifacts!)

raphamorim commented 1 month ago

Of course! I also think it should be configurable!

Will mark this to take a look

raphamorim commented 1 month ago

Implemented part of it on 5d6bb98 (now can disable hinting)

melroy89 commented 1 month ago

Implemented part of it on 5d6bb98 (now can disable hinting)

You're just as quick as me ;P well done with the hinting option already!

melroy89 commented 3 weeks ago

OK, debugging & learning the project for about 2 hours now (plus I'm new to Rust.. 😆 ).

TLDR: I have no idea to disable anti-alias, haha!

Correct me if I'm wrong, but here is my story:

Background story:

You first load all the fonts/glyphs in the font loader. Sugarloaf gives you a content, in the content you can add for example text (add_text). Then your text is added to fragments with an fragment style. Then during a build you convert all the lines and other stuff and move it into render_data. Then somehow, a bit too much code for me now.. eventually... during rendering I guess, it will use the rich_text module with the RichTextBrush.

This is using a wgpu::SamplerDescriptor, which is this struct in the wgpu crate: https://docs.rs/wgpu/latest/wgpu/struct.SamplerDescriptor.html

And I guess this wgpu struct is responsible for rendering the text using the glyphs? And looking at this:

https://github.com/raphamorim/rio/blob/main/sugarloaf/src/components/rich_text/mod.rs#L131

The wgpu::SamplerDescriptor has already the following options nearest, but there is no option None:

            address_mode_u: wgpu::AddressMode::ClampToEdge,
            address_mode_v: wgpu::AddressMode::ClampToEdge,
            address_mode_w: wgpu::AddressMode::ClampToEdge,
            mag_filter: wgpu::FilterMode::Nearest, // <-- You can't set it to None or something
            min_filter: wgpu::FilterMode::Nearest, // <-- You can't set it to None or something
            mipmap_filter: wgpu::FilterMode::Nearest ,// <-- You can't set it to None or something
            lod_min_clamp: 0f32,
            lod_max_clamp: 0f32,

Or it might be using the ScalerBuilder (then again it's maybe only focused on font, and it's not wgpu):

https://github.com/raphamorim/rio/blob/b53acf9c37428e87fdca1b537567c07063ca0965/sugarloaf/src/components/rich_text/image_cache/glyph.rs#L137

But ScalerBuilder by swash, this crate struct: https://docs.rs/swash/latest/swash/scale/struct.ScalerBuilder.html. But Swash is also not providing anything except for hinting..

Long story short, I'm not sure if wgpu can even render without anti-alias? Maybe it's just me...

Again, also if I got something wrong (and most likely something is missing in my story). Let me know 😄 , like I said I'm also still learning this code base. After all rio is "only" ~150.000 lines of actual code.

raphamorim commented 3 weeks ago

OK, debugging & learning the project for about 2 hours now (plus I'm new to Rust.. 😆 ).

TLDR: I have no idea to disable anti-alias, haha!

Correct me if I'm wrong, but here is my story:

haha love it!

The missing piece of turn anti-alias off (considering that hinting is off as well) is disable subpixel rendering and use https://docs.rs/zeno/latest/zeno/enum.Format.html#variant.Alpha (if i am not mistaken)

https://github.com/raphamorim/rio/blob/b53acf9c37428e87fdca1b537567c07063ca0965/sugarloaf/src/components/rich_text/image_cache/glyph.rs#L150-L152

melroy89 commented 3 weeks ago

OK check, it seems CustomSubpixel is the one indeed. Since a format() is required to set to fill the glyphs, I just used:

.format(Format::CustomSubpixel([0., 0., 0.]))

That seems to disable anti-alias.

However, this won't look still not very good under the text example. I tried.. Since I dunno what you're doing there, but setting the font_size and sugarloaf_layout it not really making it better. https://github.com/raphamorim/rio/blob/b53acf9c37428e87fdca1b537567c07063ca0965/sugarloaf/examples/text.rs#L57

So I also tried the multi_text example, and the text in the right box, looks the best thus far for sure (maybe it has no scale factor?).. Anyhow, look at this:

Before (subpixel rendering enabled):

image

After (subpixel rendering disabled, aka disabled anti-alias):

image

Or gif (1:1 ratio):

before_after_subpixel_rendering

As you can see disabling subpixel rendering make the font so much sharper.

Or this video (zoomed-in):

https://github.com/user-attachments/assets/7b56399d-3249-49ee-930a-bbf4abc97cbb

But just note that increasing the font-size (scaling or whatever) can and most likely make will make the text blurry again:

image

And a comparison between XFCE terminal with Rio terminal. Despite disabling supixel rendering, the XFCE terminal still seem to produce sharper text somehow. Yes, I use the same font. Yes, I also disabled hinting in Rio settings...

image

Rio seems to use 9pt in this example, and XFCE terminal is set to 11pt.

Edit: 11pt is apparently ~15px or 95%. Now 12 pt also still looks good in my terminal, which is ~16px and exactly 1em (100%).

The font I'm using is a TTF monofont called: DejaVuSansM Nerd Font Mono Regular. https://github.com/ryanoasis/nerd-fonts/releases/download/v3.2.1/DejaVuSansMono.zip

And you can see 11pt is about the sweet spot in terms of text size and sharpness:

image


More screens of XFCE.

9pt:

image

10pt:

image

11pt:

image

12pt:

image

13pt (it becomes bold?):

image