alacritty / alacritty/alacritty

Subpixel fonts aren't rendered correctly

Abierto
#3,756 2 comentarios 8 reacciones 0 asignados Ver en GitHub
A - needs repro B - bug S - render
Lenguaje dominante
Rust
Estrellas
65.7k
Forks
3.6k
Merge medio
3 h 5 min
PR fusionados (30 d)
3

Descripción

### System

OS: Windows
Version: alacritty 0.4.2 (f68de37)
Windows: ConPTY

### Logs

Font/Terminal size: 9 with bitstream vera sans mono

Hello! Alacritty doesn't handle rendering subpixel fonts correctly. I thought I'd document the issue in depth:

This is what an example from alacritty looks like:

![8293632 539999992_alacritty](https://user-images.githubusercontent.com/755197/82596219-db069080-9b9e-11ea-93bb-7d023e95ce65.PNG)

This is sample text rendered in a different application that is rendered incorrectly, similar settings:

![bad1](https://user-images.githubusercontent.com/755197/82602485-13ab6780-9ba9-11ea-8346-7e0cdb55865f.PNG)

This is sample text correctly rendered with sRGB correct blending:

![good1](https://user-images.githubusercontent.com/755197/82596295-f8d3f580-9b9e-11ea-8c9f-03a02d6709a5.PNG)

I had a brief look through the rendering pipeline, as far as I can tell the issue is here:

```
// Regular text glyphs.
vec3 textColor = texture(mask, TexCoords).rgb;
alphaMask = vec4(textColor, textColor.r);
color = vec4(fg, 1.0);
```

Combined with this piece of code:

```
let windowed_context =
create_gl_window(window_builder.clone(), &event_loop, false, vsync, size)
.or_else(|_| create_gl_window(window_builder, &event_loop, true, vsync, size))?;
```

This looks like it tries to create a window with sRGB disabled, followed by making one with sRGB enabled if that fails. Currently alacritty only renders text correctly with sRGB enabled, but there's no reason why both can't work

textColor here looks like alpha for subpixel fonts, which is good, although strictly speaking it is alpha, not colour. The blend equation is

```
gl::BlendFunc(gl::SRC1_COLOR, gl::ONE_MINUS_SRC1_COLOR);
```

Using dual source blending, where src1_color = alphaMask, here the linear subpixels

This gives the final result: Foreground_colour * subpixel_alpha3 + destination_colour * (1-subpixel_alpha3). The problem is, foreground colour and destination colour are both in sRGB for the blend equation when sRGB framebuffers are disabled, which makes this blending incorrect. Its pretty straightforward to convert foreground colour to linear colour if the render window doesn't have srgb enabled (although if you use pow(colour, 2.2) i'll complain very loudly, [see this](https://chilliant.blogspot.com/2012/08/srgb-approximations-for-hlsl.html)), which makes destination colour the issue

One way to resolve this would be to render to an offscreen render target instead in linear colour, which is 4 component linear floats, then manually gamma correct afterwards when you blit back to the main render window. Or, you could create an offscreen sRGB enabled offscreen texture (which shouldn't run into to pixel format issues) and render to that before blitting. Or do both, conditionally depending on whether or not sRGB is available (unlikely to be an issue targeting desktop, but some linux drivers implement sRGB textures weirdly)

Decoupling the correctness of the text from the render window format is probably a good idea, given that it seems to have issues with getting the correct pixel formats from a look at the commit history. The issues here also apply to general colour rendering, and probably the emojis too, but I have skipped over all of that for simplicity

Thanks!

Guía de contribución

Abrir la guía de contribución

Evaluación

Este issue todavía no se ha evaluado.

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.