@@ -44,38 +44,60 @@ var s_diffuse: sampler;
4444
4545@fragment
4646fn fs_main (in : VertexOutput ) -> @location (0 ) vec4 <f32 > {
47- let ui = textureSample (t_ui , s_diffuse , in . tex_coords );
48- if (ui . a >= 0 .999 ) {
49- return ui ;
47+ let ui_linear = textureSample (t_ui , s_diffuse , in . tex_coords );
48+ if (ui_linear . a >= 0 .999 ) {
49+ return ui_linear ;
5050 }
5151
5252 let viewport_coordinate = (in . tex_coords - constants . viewport_offset ) * constants . viewport_scale ;
5353
54- // Vello renders its values to an `RgbaUnorm` texture, but if we try to use this in the main rendering pipeline
55- // which renders to an `Srgb` surface, gamma mapping is applied twice. This converts back to linear to compensate.
56- let overlay_raw = textureSample (t_overlays , s_diffuse , viewport_coordinate );
57- let overlay = vec4 <f32 >(srgb_to_linear (overlay_raw . rgb ), overlay_raw . a );
58- let viewport_raw = textureSample (t_viewport , s_diffuse , viewport_coordinate );
59- let viewport = vec4 <f32 >(srgb_to_linear (viewport_raw . rgb ), viewport_raw . a );
54+ let overlay_srgb = textureSample (t_overlays , s_diffuse , viewport_coordinate );
55+ let viewport_srgb = textureSample (t_viewport , s_diffuse , viewport_coordinate );
6056
61- if (overlay . a < 0 .001 ) {
62- return blend (ui , viewport );
57+ // UI texture is premultiplied, we need to unpremultiply before blending
58+ let ui_srgb = linear_to_srgb (unpremultiply (ui_linear ));
59+
60+ if (overlay_srgb . a < 0 .001 ) {
61+ if (ui_srgb . a < 0 .001 ) {
62+ return srgb_to_linear (viewport_srgb );
63+ } else {
64+ return srgb_to_linear (blend (ui_srgb , viewport_srgb ));
65+ }
6366 }
6467
65- let composite = blend (overlay , viewport );
66- return blend (ui , composite );
67- }
68+ let composite_linear = blend (srgb_to_linear (overlay_srgb ), srgb_to_linear (viewport_srgb ));
6869
69- fn srgb_to_linear (srgb : vec3 <f32 >) -> vec3 <f32 > {
70- return select (
71- pow ((srgb + 0 .055 ) / 1 .055 , vec3 <f32 >(2 .4 )),
72- srgb / 12 .92 ,
73- srgb <= vec3 <f32 >(0 .04045 )
74- );
70+ if (ui_srgb . a < 0 .001 ) {
71+ return composite_linear ;
72+ }
73+
74+ return srgb_to_linear (blend (ui_srgb , linear_to_srgb (composite_linear )));
7575}
7676
7777fn blend (fg : vec4 <f32 >, bg : vec4 <f32 >) -> vec4 <f32 > {
7878 let a = fg . a + bg . a * (1 .0 - fg . a );
7979 let rgb = fg . rgb * fg . a + bg . rgb * bg . a * (1 .0 - fg . a );
8080 return vec4 <f32 >(rgb , a );
8181}
82+
83+ fn linear_to_srgb (in : vec4 <f32 >) -> vec4 <f32 > {
84+ let cutoff = vec3 <f32 >(0 .0031308 );
85+ let lo = in . rgb * 12 .92 ;
86+ let hi = 1 .055 * pow (max (in . rgb , vec3 <f32 >(0 .0 )), vec3 <f32 >(1 .0 / 2 .4 )) - 0 .055 ;
87+ return vec4 <f32 >(select (lo , hi , in . rgb > cutoff ), in . a );
88+ }
89+
90+ fn srgb_to_linear (in : vec4 <f32 >) -> vec4 <f32 > {
91+ let cutoff = vec3 <f32 >(0 .04045 );
92+ let lo = in . rgb / 12 .92 ;
93+ let hi = pow ((in . rgb + 0 .055 ) / 1 .055 , vec3 <f32 >(2 .4 ));
94+ return vec4 <f32 >(select (lo , hi , in . rgb > cutoff ), in . a );
95+ }
96+
97+ fn unpremultiply (in : vec4 <f32 >) -> vec4 <f32 > {
98+ if (in . a > 0 .0 ) {
99+ return vec4 <f32 >((in . rgb / in . a ), in . a );
100+ } else {
101+ return vec4 <f32 >(0 .0 );
102+ }
103+ }
0 commit comments