Bug 1857841 - pt 3. Add a new page kind named "fresh" r=glandium
[gecko.git] / gfx / wr / webrender / res / brush_mix_blend.glsl
blobc18b95161bb698ed4d92f09b246bfb6be8e74bd2
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #define VECS_PER_SPECIFIC_BRUSH 3
6 #define WR_FEATURE_TEXTURE_2D
8 #include shared,prim_shared,brush
10 // UV and bounds for the source image
11 varying highp vec2 v_src_uv;
12 flat varying highp vec4 v_src_uv_sample_bounds;
14 // UV and bounds for the backdrop image
15 varying highp vec2 v_backdrop_uv;
16 flat varying highp vec4 v_backdrop_uv_sample_bounds;
18 // Flag to allow perspective interpolation of UV.
19 // Packed in to vector to work around bug 1630356.
20 flat varying mediump vec2 v_perspective;
21 // mix-blend op. Packed in to vector to work around bug 1630356.
22 flat varying mediump ivec2 v_op;
24 #ifdef WR_VERTEX_SHADER
26 void get_uv(
27     int res_address,
28     vec2 f,
29     ivec2 texture_size,
30     float perspective_f,
31     out vec2 out_uv,
32     out vec4 out_uv_sample_bounds
33 ) {
34     ImageSource res = fetch_image_source(res_address);
35     vec2 uv0 = res.uv_rect.p0;
36     vec2 uv1 = res.uv_rect.p1;
38     vec2 inv_texture_size = vec2(1.0) / vec2(texture_size);
39     f = get_image_quad_uv(res_address, f);
40     vec2 uv = mix(uv0, uv1, f);
42     out_uv = uv * inv_texture_size * perspective_f;
43     out_uv_sample_bounds = vec4(uv0 + vec2(0.5), uv1 - vec2(0.5)) * inv_texture_size.xyxy;
46 void brush_vs(
47     VertexInfo vi,
48     int prim_address,
49     RectWithEndpoint local_rect,
50     RectWithEndpoint segment_rect,
51     ivec4 prim_user_data,
52     int specific_resource_address,
53     mat4 transform,
54     PictureTask pic_task,
55     int brush_flags,
56     vec4 unused
57 ) {
58     vec2 f = (vi.local_pos - local_rect.p0) / rect_size(local_rect);
59     float perspective_interpolate = (brush_flags & BRUSH_FLAG_PERSPECTIVE_INTERPOLATION) != 0 ? 1.0 : 0.0;
60     float perspective_f = mix(vi.world_pos.w, 1.0, perspective_interpolate);
61     v_perspective.x = perspective_interpolate;
62     v_op.x = prim_user_data.x;
64     get_uv(
65         prim_user_data.y,
66         f,
67         TEX_SIZE(sColor0).xy,
68         1.0,
69         v_backdrop_uv,
70         v_backdrop_uv_sample_bounds
71     );
73     get_uv(
74         prim_user_data.z,
75         f,
76         TEX_SIZE(sColor1).xy,
77         perspective_f,
78         v_src_uv,
79         v_src_uv_sample_bounds
80     );
82 #endif
84 #ifdef WR_FRAGMENT_SHADER
85 vec3 Multiply(vec3 Cb, vec3 Cs) {
86     return Cb * Cs;
89 vec3 Screen(vec3 Cb, vec3 Cs) {
90     return Cb + Cs - (Cb * Cs);
93 vec3 HardLight(vec3 Cb, vec3 Cs) {
94     vec3 m = Multiply(Cb, 2.0 * Cs);
95     vec3 s = Screen(Cb, 2.0 * Cs - 1.0);
96     vec3 edge = vec3(0.5, 0.5, 0.5);
97     return mix(m, s, step(edge, Cs));
100 // TODO: Worth doing with mix/step? Check GLSL output.
101 float ColorDodge(float Cb, float Cs) {
102     if (Cb == 0.0)
103         return 0.0;
104     else if (Cs == 1.0)
105         return 1.0;
106     else
107         return min(1.0, Cb / (1.0 - Cs));
110 // TODO: Worth doing with mix/step? Check GLSL output.
111 float ColorBurn(float Cb, float Cs) {
112     if (Cb == 1.0)
113         return 1.0;
114     else if (Cs == 0.0)
115         return 0.0;
116     else
117         return 1.0 - min(1.0, (1.0 - Cb) / Cs);
120 float SoftLight(float Cb, float Cs) {
121     if (Cs <= 0.5) {
122         return Cb - (1.0 - 2.0 * Cs) * Cb * (1.0 - Cb);
123     } else {
124         float D;
126         if (Cb <= 0.25)
127             D = ((16.0 * Cb - 12.0) * Cb + 4.0) * Cb;
128         else
129             D = sqrt(Cb);
131         return Cb + (2.0 * Cs - 1.0) * (D - Cb);
132     }
135 vec3 Difference(vec3 Cb, vec3 Cs) {
136     return abs(Cb - Cs);
139 // These functions below are taken from the spec.
140 // There's probably a much quicker way to implement
141 // them in GLSL...
142 float Sat(vec3 c) {
143     return max(c.r, max(c.g, c.b)) - min(c.r, min(c.g, c.b));
146 float Lum(vec3 c) {
147     vec3 f = vec3(0.3, 0.59, 0.11);
148     return dot(c, f);
151 vec3 ClipColor(vec3 C) {
152     float L = Lum(C);
153     float n = min(C.r, min(C.g, C.b));
154     float x = max(C.r, max(C.g, C.b));
156     if (n < 0.0)
157         C = L + (((C - L) * L) / (L - n));
159     if (x > 1.0)
160         C = L + (((C - L) * (1.0 - L)) / (x - L));
162     return C;
165 vec3 SetLum(vec3 C, float l) {
166     float d = l - Lum(C);
167     return ClipColor(C + d);
170 void SetSatInner(inout float Cmin, inout float Cmid, inout float Cmax, float s) {
171     if (Cmax > Cmin) {
172         Cmid = (((Cmid - Cmin) * s) / (Cmax - Cmin));
173         Cmax = s;
174     } else {
175         Cmid = 0.0;
176         Cmax = 0.0;
177     }
178     Cmin = 0.0;
181 vec3 SetSat(vec3 C, float s) {
182     if (C.r <= C.g) {
183         if (C.g <= C.b) {
184             SetSatInner(C.r, C.g, C.b, s);
185         } else {
186             if (C.r <= C.b) {
187                 SetSatInner(C.r, C.b, C.g, s);
188             } else {
189                 SetSatInner(C.b, C.r, C.g, s);
190             }
191         }
192     } else {
193         if (C.r <= C.b) {
194             SetSatInner(C.g, C.r, C.b, s);
195         } else {
196             if (C.g <= C.b) {
197                 SetSatInner(C.g, C.b, C.r, s);
198             } else {
199                 SetSatInner(C.b, C.g, C.r, s);
200             }
201         }
202     }
203     return C;
206 vec3 Hue(vec3 Cb, vec3 Cs) {
207     return SetLum(SetSat(Cs, Sat(Cb)), Lum(Cb));
210 vec3 Saturation(vec3 Cb, vec3 Cs) {
211     return SetLum(SetSat(Cb, Sat(Cs)), Lum(Cb));
214 vec3 Color(vec3 Cb, vec3 Cs) {
215     return SetLum(Cs, Lum(Cb));
218 vec3 Luminosity(vec3 Cb, vec3 Cs) {
219     return SetLum(Cb, Lum(Cs));
222 const int MixBlendMode_Multiply    = 1;
223 const int MixBlendMode_Screen      = 2;
224 const int MixBlendMode_Overlay     = 3;
225 const int MixBlendMode_Darken      = 4;
226 const int MixBlendMode_Lighten     = 5;
227 const int MixBlendMode_ColorDodge  = 6;
228 const int MixBlendMode_ColorBurn   = 7;
229 const int MixBlendMode_HardLight   = 8;
230 const int MixBlendMode_SoftLight   = 9;
231 const int MixBlendMode_Difference  = 10;
232 const int MixBlendMode_Exclusion   = 11;
233 const int MixBlendMode_Hue         = 12;
234 const int MixBlendMode_Saturation  = 13;
235 const int MixBlendMode_Color       = 14;
236 const int MixBlendMode_Luminosity  = 15;
237 const int MixBlendMode_PlusLighter = 16;
239 Fragment brush_fs() {
240     float perspective_divisor = mix(gl_FragCoord.w, 1.0, v_perspective.x);
242     vec2 src_uv = v_src_uv * perspective_divisor;
243     src_uv = clamp(src_uv, v_src_uv_sample_bounds.xy, v_src_uv_sample_bounds.zw);
245     vec2 backdrop_uv = clamp(v_backdrop_uv, v_backdrop_uv_sample_bounds.xy, v_backdrop_uv_sample_bounds.zw);
247     vec4 Cb = texture(sColor0, backdrop_uv);
248     vec4 Cs = texture(sColor1, src_uv);
250     // The mix-blend-mode functions assume no premultiplied alpha
251     if (Cb.a != 0.0) {
252         Cb.rgb /= Cb.a;
253     }
255     if (Cs.a != 0.0) {
256         Cs.rgb /= Cs.a;
257     }
259     // Return yellow if none of the branches match (shouldn't happen).
260     vec4 result = vec4(1.0, 1.0, 0.0, 1.0);
262     // On Android v_op has been packed in to a vector to avoid a driver bug
263     // on Adreno 3xx. However, this runs in to another Adreno 3xx driver bug
264     // where the switch doesn't match any cases. Unpacking the value from the
265     // vec in to a local variable prior to the switch works around this, but
266     // gets optimized away by glslopt. Adding a bitwise AND prevents that.
267     // See bug 1726755.
268     // default: default: to appease angle_shader_validation
269     switch (v_op.x & 0xFF) {
270         case MixBlendMode_Multiply:
271             result.rgb = Multiply(Cb.rgb, Cs.rgb);
272             break;
273         case MixBlendMode_Overlay:
274             // Overlay is inverse of Hardlight
275             result.rgb = HardLight(Cs.rgb, Cb.rgb);
276             break;
277         case MixBlendMode_Darken:
278             result.rgb = min(Cs.rgb, Cb.rgb);
279             break;
280         case MixBlendMode_Lighten:
281             result.rgb = max(Cs.rgb, Cb.rgb);
282             break;
283         case MixBlendMode_ColorDodge:
284             result.r = ColorDodge(Cb.r, Cs.r);
285             result.g = ColorDodge(Cb.g, Cs.g);
286             result.b = ColorDodge(Cb.b, Cs.b);
287             break;
288         case MixBlendMode_ColorBurn:
289             result.r = ColorBurn(Cb.r, Cs.r);
290             result.g = ColorBurn(Cb.g, Cs.g);
291             result.b = ColorBurn(Cb.b, Cs.b);
292             break;
293         case MixBlendMode_HardLight:
294             result.rgb = HardLight(Cb.rgb, Cs.rgb);
295             break;
296         case MixBlendMode_SoftLight:
297             result.r = SoftLight(Cb.r, Cs.r);
298             result.g = SoftLight(Cb.g, Cs.g);
299             result.b = SoftLight(Cb.b, Cs.b);
300             break;
301         case MixBlendMode_Difference:
302             result.rgb = Difference(Cb.rgb, Cs.rgb);
303             break;
304         case MixBlendMode_Hue:
305             result.rgb = Hue(Cb.rgb, Cs.rgb);
306             break;
307         case MixBlendMode_Saturation:
308             result.rgb = Saturation(Cb.rgb, Cs.rgb);
309             break;
310         case MixBlendMode_Color:
311             result.rgb = Color(Cb.rgb, Cs.rgb);
312             break;
313         case MixBlendMode_Luminosity:
314             result.rgb = Luminosity(Cb.rgb, Cs.rgb);
315             break;
316         case MixBlendMode_Screen:
317         case MixBlendMode_Exclusion:
318         case MixBlendMode_PlusLighter:
319             // This should be unreachable, since we implement
320             // MixBlendMode::Screen, MixBlendMode::Exclusion and
321             // MixBlendMode::PlusLighter using glBlendFuncSeparate.
322             break;
323         default: break;
324     }
326     result.rgb = (1.0 - Cb.a) * Cs.rgb + Cb.a * result.rgb;
327     result.a = Cs.a;
328     result.rgb *= result.a;
330     return Fragment(result);
332 #endif