@@ -44,38 +44,60 @@ var s_diffuse: sampler;
44
44
45
45
@fragment
46
46
fn 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 ;
50
50
}
51
51
52
52
let viewport_coordinate = (in . tex_coords - constants . viewport_offset) * constants . viewport_scale;
53
53
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 );
60
56
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
+ }
63
66
}
64
67
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 ));
68
69
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 )));
75
75
}
76
76
77
77
fn blend (fg : vec4 <f32 >, bg : vec4 <f32 >) -> vec4 <f32 > {
78
78
let a = fg . a + bg . a * (1.0 - fg . a);
79
79
let rgb = fg . rgb * fg . a + bg . rgb * bg . a * (1.0 - fg . a);
80
80
return vec4 <f32 >(rgb , a );
81
81
}
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