brush_mix_blend.glsl (9359B)
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/. */ 4 5 #define VECS_PER_SPECIFIC_BRUSH 3 6 #define WR_FEATURE_TEXTURE_2D 7 8 #include shared,prim_shared,brush,image_source 9 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; 13 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; 17 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; 23 24 #ifdef WR_VERTEX_SHADER 25 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; 37 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); 41 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; 44 } 45 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; 63 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 ); 72 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 ); 81 } 82 #endif 83 84 #ifdef WR_FRAGMENT_SHADER 85 vec3 Multiply(vec3 Cb, vec3 Cs) { 86 return Cb * Cs; 87 } 88 89 vec3 Screen(vec3 Cb, vec3 Cs) { 90 return Cb + Cs - (Cb * Cs); 91 } 92 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)); 98 } 99 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)); 108 } 109 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); 118 } 119 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; 125 126 if (Cb <= 0.25) 127 D = ((16.0 * Cb - 12.0) * Cb + 4.0) * Cb; 128 else 129 D = sqrt(Cb); 130 131 return Cb + (2.0 * Cs - 1.0) * (D - Cb); 132 } 133 } 134 135 vec3 Difference(vec3 Cb, vec3 Cs) { 136 return abs(Cb - Cs); 137 } 138 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)); 144 } 145 146 float Lum(vec3 c) { 147 vec3 f = vec3(0.3, 0.59, 0.11); 148 return dot(c, f); 149 } 150 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)); 155 156 if (n < 0.0) 157 C = L + (((C - L) * L) / (L - n)); 158 159 if (x > 1.0) 160 C = L + (((C - L) * (1.0 - L)) / (x - L)); 161 162 return C; 163 } 164 165 vec3 SetLum(vec3 C, float l) { 166 float d = l - Lum(C); 167 return ClipColor(C + d); 168 } 169 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; 179 } 180 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; 204 } 205 206 vec3 Hue(vec3 Cb, vec3 Cs) { 207 return SetLum(SetSat(Cs, Sat(Cb)), Lum(Cb)); 208 } 209 210 vec3 Saturation(vec3 Cb, vec3 Cs) { 211 return SetLum(SetSat(Cb, Sat(Cs)), Lum(Cb)); 212 } 213 214 vec3 Color(vec3 Cb, vec3 Cs) { 215 return SetLum(Cs, Lum(Cb)); 216 } 217 218 vec3 Luminosity(vec3 Cb, vec3 Cs) { 219 return SetLum(Cb, Lum(Cs)); 220 } 221 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; 238 239 Fragment brush_fs() { 240 float perspective_divisor = mix(gl_FragCoord.w, 1.0, v_perspective.x); 241 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); 244 245 vec2 backdrop_uv = clamp(v_backdrop_uv, v_backdrop_uv_sample_bounds.xy, v_backdrop_uv_sample_bounds.zw); 246 247 vec4 Cb = texture(sColor0, backdrop_uv); 248 vec4 Cs = texture(sColor1, src_uv); 249 250 // The mix-blend-mode functions assume no premultiplied alpha 251 if (Cb.a != 0.0) { 252 Cb.rgb /= Cb.a; 253 } 254 255 if (Cs.a != 0.0) { 256 Cs.rgb /= Cs.a; 257 } 258 259 // Return yellow if none of the branches match (shouldn't happen). 260 vec4 result = vec4(1.0, 1.0, 0.0, 1.0); 261 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 } 325 326 result.rgb = (1.0 - Cb.a) * Cs.rgb + Cb.a * result.rgb; 327 result.a = Cs.a; 328 result.rgb *= result.a; 329 330 return Fragment(result); 331 } 332 #endif