tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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