Yesterday, when I was implementing #18, I noticed text was rendering differently using gfx vs wgpu.
Here is how it looked when using OpenGL:
Here is how it looked when using Vulkan:
It's a subtle difference, but the OpenGL version is way more readable (look at the uppercase I glyph). The difference? Gamma correction.
This made me start researching about color spaces and how to deal with them, which almost drove me to insanity... But I think I figured out the problem, and the solution is quite simple.
Monitors display colors in the sRGB color space. Therefore, if you have a framebuffer with a (0.5, 0.5, 0.5) color value, it will always display the same grey, independently of the format of the framebuffer.
wgpu_glyph stores a cache of glyphs in a texture of alpha values. This value is then combined with the font color in the wgpu_glyph fragment shader. Then, the blending stage happens.
The blending stage basically combines the color outputs of the fragment shader with the color of the target buffer. If your buffer is not marked as Srgb, then the values from the target buffer will be read as if they were linear and combined with the fragment shader outputs directly. Finally, the combined color will be written directly into the target buffer. Thus, you end up with linear values in your frame buffer, which then are displayed by your monitor as if they were sRGB. Bad! This causes grey values to look darker than they should, like you can observe in the Vulkan example above.
However, when the target buffer is marked as Srgb, the values will be read as Srgb and converted into linear before blending. Additionally, the combined color will be converted back into Srgb on write. This is what the OpenGL implementation was doing.
This PR fixes the wgpu graphics backend to use Srgb buffers for textures and render targets, except for the SwapChain which we are currently copying into. It also fixes font and clear color, by converting the Color type (which is sRGB) into linear. I have also added a colors example to test that colors are rendering properly in both graphics backends.
Yesterday, when I was implementing #18, I noticed text was rendering differently using
gfx
vswgpu
.Here is how it looked when using OpenGL:
Here is how it looked when using Vulkan:
It's a subtle difference, but the OpenGL version is way more readable (look at the uppercase
I
glyph). The difference? Gamma correction.This made me start researching about color spaces and how to deal with them, which almost drove me to insanity... But I think I figured out the problem, and the solution is quite simple.
Monitors display colors in the sRGB color space. Therefore, if you have a framebuffer with a
(0.5, 0.5, 0.5)
color value, it will always display the same grey, independently of the format of the framebuffer.wgpu_glyph
stores a cache of glyphs in a texture of alpha values. This value is then combined with the font color in thewgpu_glyph
fragment shader. Then, the blending stage happens.The blending stage basically combines the color outputs of the fragment shader with the color of the target buffer. If your buffer is not marked as
Srgb
, then the values from the target buffer will be read as if they were linear and combined with the fragment shader outputs directly. Finally, the combined color will be written directly into the target buffer. Thus, you end up with linear values in your frame buffer, which then are displayed by your monitor as if they were sRGB. Bad! This causes grey values to look darker than they should, like you can observe in the Vulkan example above.However, when the target buffer is marked as
Srgb
, the values will be read asSrgb
and converted into linear before blending. Additionally, the combined color will be converted back intoSrgb
on write. This is what the OpenGL implementation was doing.This PR fixes the
wgpu
graphics backend to useSrgb
buffers for textures and render targets, except for theSwapChain
which we are currently copying into. It also fixes font and clear color, by converting theColor
type (which is sRGB) into linear. I have also added acolors
example to test that colors are rendering properly in both graphics backends.