From 8b4adf43303aa4a881138da3c2afef0302876dc2 Mon Sep 17 00:00:00 2001 From: Dennis Kobert Date: Tue, 5 Aug 2025 12:08:14 +0200 Subject: [PATCH] Desktop: Fix Vello rendering colors with doubly-applied gamma by converting to linear in the shader (#2998) * Fix gamma issue by applying tone mapping in the shader Vello renders it's values to an RgbaUnorm texture but if we try to use this in the main rendering pipeline which renders to an Srgb surface gamma mapping is applied twice. * Add comment explaining why we do this to the shader * Rename variables --- desktop/src/render/composite_shader.wgsl | 26 +++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/desktop/src/render/composite_shader.wgsl b/desktop/src/render/composite_shader.wgsl index b939ecbf..3232e44f 100644 --- a/desktop/src/render/composite_shader.wgsl +++ b/desktop/src/render/composite_shader.wgsl @@ -49,17 +49,29 @@ fn fs_main(in: VertexOutput) -> @location(0) vec4 { return ui; } - let vp_cord = (in.tex_coords - constants.viewport_offset) * constants.viewport_scale; + let viewport_coordinate = (in.tex_coords - constants.viewport_offset) * constants.viewport_scale; - let ov = textureSample(t_overlays, s_diffuse, vp_cord); - let vp = textureSample(t_viewport, s_diffuse, vp_cord); + // Vello renders its values to an `RgbaUnorm` texture, but if we try to use this in the main rendering pipeline + // which renders to an `Srgb` surface, gamma mapping is applied twice. This converts back to linear to compensate. + let overlay_raw = textureSample(t_overlays, s_diffuse, viewport_coordinate); + let overlay = vec4(srgb_to_linear(overlay_raw.rgb), overlay_raw.a); + let viewport_raw = textureSample(t_viewport, s_diffuse, viewport_coordinate); + let viewport = vec4(srgb_to_linear(viewport_raw.rgb), viewport_raw.a); - if (ov.a < 0.001) { - return blend(ui, vp); + if (overlay.a < 0.001) { + return blend(ui, viewport); } - let comp = blend(ov, vp); - return blend(ui, comp); + let composite = blend(overlay, viewport); + return blend(ui, composite); +} + +fn srgb_to_linear(srgb: vec3) -> vec3 { + return select( + pow((srgb + 0.055) / 1.055, vec3(2.4)), + srgb / 12.92, + srgb <= vec3(0.04045) + ); } fn blend(fg: vec4, bg: vec4) -> vec4 {