tor-browser

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

blend.glsl (9349B)


      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 #include gpu_buffer
      6 
      7 #define COMPONENT_TRANSFER_IDENTITY 0
      8 #define COMPONENT_TRANSFER_TABLE 1
      9 #define COMPONENT_TRANSFER_DISCRETE 2
     10 #define COMPONENT_TRANSFER_LINEAR 3
     11 #define COMPONENT_TRANSFER_GAMMA 4
     12 
     13 // Must be kept in sync with `Filter::as_int` in internal_types.rs
     14 // Not all filters are defined here because some filter use different shaders.
     15 #define FILTER_CONTRAST            0
     16 #define FILTER_GRAYSCALE           1
     17 #define FILTER_HUE_ROTATE          2
     18 #define FILTER_INVERT              3
     19 #define FILTER_SATURATE            4
     20 #define FILTER_SEPIA               5
     21 #define FILTER_BRIGHTNESS          6
     22 #define FILTER_COLOR_MATRIX        7
     23 #define FILTER_SRGB_TO_LINEAR      8
     24 #define FILTER_LINEAR_TO_SRGB      9
     25 #define FILTER_FLOOD               10
     26 #define FILTER_COMPONENT_TRANSFER  11
     27 
     28 #ifdef WR_VERTEX_SHADER
     29 void SetupFilterParams(
     30     int op,
     31     float amount,
     32     int gpu_data_address,
     33     out vec4 color_offset,
     34     out mat4 color_mat,
     35     out highp int table_address
     36 ) {
     37     float lumR = 0.2126;
     38     float lumG = 0.7152;
     39     float lumB = 0.0722;
     40     float oneMinusLumR = 1.0 - lumR;
     41     float oneMinusLumG = 1.0 - lumG;
     42     float oneMinusLumB = 1.0 - lumB;
     43     float invAmount = 1.0 - amount;
     44 
     45     if (op == FILTER_GRAYSCALE) {
     46         color_mat = mat4(
     47             vec4(lumR + oneMinusLumR * invAmount, lumR - lumR * invAmount, lumR - lumR * invAmount, 0.0),
     48             vec4(lumG - lumG * invAmount, lumG + oneMinusLumG * invAmount, lumG - lumG * invAmount, 0.0),
     49             vec4(lumB - lumB * invAmount, lumB - lumB * invAmount, lumB + oneMinusLumB * invAmount, 0.0),
     50             vec4(0.0, 0.0, 0.0, 1.0)
     51         );
     52         color_offset = vec4(0.0);
     53     } else if (op ==  FILTER_HUE_ROTATE) {
     54         float c = cos(amount);
     55         float s = sin(amount);
     56         color_mat = mat4(
     57             vec4(lumR + oneMinusLumR * c - lumR * s, lumR - lumR * c + 0.143 * s, lumR - lumR * c - oneMinusLumR * s, 0.0),
     58             vec4(lumG - lumG * c - lumG * s, lumG + oneMinusLumG * c + 0.140 * s, lumG - lumG * c + lumG * s, 0.0),
     59             vec4(lumB - lumB * c + oneMinusLumB * s, lumB - lumB * c - 0.283 * s, lumB + oneMinusLumB * c + lumB * s, 0.0),
     60             vec4(0.0, 0.0, 0.0, 1.0)
     61         );
     62         color_offset = vec4(0.0);
     63     } else if (op ==   FILTER_SATURATE) {
     64         color_mat = mat4(
     65             vec4(invAmount * lumR + amount, invAmount * lumR, invAmount * lumR, 0.0),
     66             vec4(invAmount * lumG, invAmount * lumG + amount, invAmount * lumG, 0.0),
     67             vec4(invAmount * lumB, invAmount * lumB, invAmount * lumB + amount, 0.0),
     68             vec4(0.0, 0.0, 0.0, 1.0)
     69         );
     70         color_offset = vec4(0.0);
     71     } else if (op == FILTER_SEPIA) {
     72         color_mat = mat4(
     73             vec4(0.393 + 0.607 * invAmount, 0.349 - 0.349 * invAmount, 0.272 - 0.272 * invAmount, 0.0),
     74             vec4(0.769 - 0.769 * invAmount, 0.686 + 0.314 * invAmount, 0.534 - 0.534 * invAmount, 0.0),
     75             vec4(0.189 - 0.189 * invAmount, 0.168 - 0.168 * invAmount, 0.131 + 0.869 * invAmount, 0.0),
     76             vec4(0.0, 0.0, 0.0, 1.0)
     77         );
     78         color_offset = vec4(0.0);
     79     } else if (op == FILTER_COLOR_MATRIX) {
     80         vec4 mat_data[4] = fetch_from_gpu_buffer_4f(gpu_data_address);
     81         vec4 offset_data = fetch_from_gpu_buffer_1f(gpu_data_address + 4);
     82         color_mat = mat4(mat_data[0], mat_data[1], mat_data[2], mat_data[3]);
     83         color_offset = offset_data;
     84     } else if (op == FILTER_COMPONENT_TRANSFER) {
     85         table_address = gpu_data_address;
     86     } else if (op == FILTER_FLOOD) {
     87         color_offset = fetch_from_gpu_buffer_1f(gpu_data_address);
     88     }
     89 }
     90 #endif
     91 
     92 #ifdef WR_FRAGMENT_SHADER
     93 vec3 Contrast(vec3 Cs, float amount) {
     94     return clamp(Cs.rgb * amount - 0.5 * amount + 0.5, 0.0, 1.0);
     95 }
     96 
     97 vec3 Invert(vec3 Cs, float amount) {
     98     return mix(Cs.rgb, vec3(1.0) - Cs.rgb, amount);
     99 }
    100 
    101 vec3 Brightness(vec3 Cs, float amount) {
    102     // Apply the brightness factor.
    103     // Resulting color needs to be clamped to output range
    104     // since we are pre-multiplying alpha in the shader.
    105     return clamp(Cs.rgb * amount, vec3(0.0), vec3(1.0));
    106 }
    107 
    108 // Based on the Gecko's implementation in
    109 // https://hg.mozilla.org/mozilla-central/file/91b4c3687d75/gfx/src/FilterSupport.cpp#l24
    110 // These could be made faster by sampling a lookup table stored in a float texture
    111 // with linear interpolation.
    112 
    113 vec3 SrgbToLinear(vec3 color) {
    114     vec3 c1 = color / 12.92;
    115     vec3 c2 = pow(color / 1.055 + vec3(0.055 / 1.055), vec3(2.4));
    116     return if_then_else(lessThanEqual(color, vec3(0.04045)), c1, c2);
    117 }
    118 
    119 vec3 LinearToSrgb(vec3 color) {
    120     vec3 c1 = color * 12.92;
    121     vec3 c2 = vec3(1.055) * pow(color, vec3(1.0 / 2.4)) - vec3(0.055);
    122     return if_then_else(lessThanEqual(color, vec3(0.0031308)), c1, c2);
    123 }
    124 
    125 // This function has to be factored out due to the following issue:
    126 // https://github.com/servo/webrender/wiki/Driver-issues#bug-1532245---switch-statement-inside-control-flow-inside-switch-statement-fails-to-compile-on-some-android-phones
    127 // (and now the words "default: default:" so angle_shader_validation.rs passes)
    128 vec4 ComponentTransfer(vec4 colora, vec4 vfuncs, highp int table_address) {
    129     // We push a different amount of data to the gpu cache depending on the
    130     // function type.
    131     // Identity => 0 blocks
    132     // Table/Discrete => 64 blocks (256 values)
    133     // Linear => 1 block (2 values)
    134     // Gamma => 1 block (3 values)
    135     // We loop through the color components and increment the offset (for the
    136     // next color component) into the gpu cache based on how many blocks that
    137     // function type put into the gpu cache.
    138     // Table/Discrete use a 256 entry look up table.
    139     // Linear/Gamma are a simple calculation.
    140 
    141     // Both offset and k must be marked as highp due to a Adreno 3xx bug likely
    142     // to do with converting between precisions (as they would otherwise be
    143     // promoted when adding to table_address).
    144     highp int offset = 0;
    145     highp int k;
    146 
    147     vec4 texel;
    148 
    149     // Dynamically indexing a vector is buggy on some platforms, so use a temporary array
    150     int[4] funcs = int[4](int(vfuncs.r), int(vfuncs.g), int(vfuncs.b), int(vfuncs.a));
    151     for (int i = 0; i < 4; i++) {
    152         switch (funcs[i]) {
    153             case COMPONENT_TRANSFER_IDENTITY:
    154                 break;
    155             case COMPONENT_TRANSFER_TABLE:
    156             case COMPONENT_TRANSFER_DISCRETE: {
    157                 // fetch value from lookup table
    158                 k = int(floor(colora[i]*255.0 + 0.5));
    159                 texel = fetch_from_gpu_buffer_1f(table_address + offset + k/4);
    160                 colora[i] = clamp(texel[k % 4], 0.0, 1.0);
    161                 // offset plus 256/4 blocks
    162                 offset = offset + 64;
    163                 break;
    164             }
    165             case COMPONENT_TRANSFER_LINEAR: {
    166                 // fetch the two values for use in the linear equation
    167                 texel = fetch_from_gpu_buffer_1f(table_address + offset);
    168                 colora[i] = clamp(texel[0] * colora[i] + texel[1], 0.0, 1.0);
    169                 // offset plus 1 block
    170                 offset = offset + 1;
    171                 break;
    172             }
    173             case COMPONENT_TRANSFER_GAMMA: {
    174                 // fetch the three values for use in the gamma equation
    175                 texel = fetch_from_gpu_buffer_1f(table_address + offset);
    176                 colora[i] = clamp(texel[0] * pow(colora[i], texel[1]) + texel[2], 0.0, 1.0);
    177                 // offset plus 1 block
    178                 offset = offset + 1;
    179                 break;
    180             }
    181             default:
    182                 // shouldn't happen
    183                 break;
    184         }
    185     }
    186     return colora;
    187 }
    188 
    189 void CalculateFilter(
    190     vec4 Cs,
    191     int op,
    192     float amount,
    193     highp int table_address,
    194     vec4 color_offset,
    195     mat4 color_mat,
    196     vec4 v_funcs,
    197     out vec3 color,
    198     out float alpha
    199 ) {
    200     // Un-premultiply the input.
    201     alpha = Cs.a;
    202     color = alpha != 0.0 ? Cs.rgb / alpha : Cs.rgb;
    203 
    204     switch (op) {
    205         case FILTER_CONTRAST:
    206             color = Contrast(color, amount);
    207             break;
    208         case FILTER_INVERT:
    209             color = Invert(color, amount);
    210             break;
    211         case FILTER_BRIGHTNESS:
    212             color = Brightness(color, amount);
    213             break;
    214         case FILTER_SRGB_TO_LINEAR:
    215             color = SrgbToLinear(color);
    216             break;
    217         case FILTER_LINEAR_TO_SRGB:
    218             color = LinearToSrgb(color);
    219             break;
    220         case FILTER_COMPONENT_TRANSFER: {
    221             // Get the unpremultiplied color with alpha.
    222             vec4 colora = vec4(color, alpha);
    223             colora = ComponentTransfer(colora, v_funcs, table_address);
    224             color = colora.rgb;
    225             alpha = colora.a;
    226             break;
    227         }
    228         case FILTER_FLOOD:
    229             color = color_offset.rgb;
    230             alpha = color_offset.a;
    231             break;
    232         default:
    233             // Color matrix type filters (sepia, hue-rotate, etc...)
    234             vec4 result = color_mat * vec4(color, alpha) + color_offset;
    235             result = clamp(result, vec4(0.0), vec4(1.0));
    236             color = result.rgb;
    237             alpha = result.a;
    238     }
    239 }
    240 #endif