summaryrefslogtreecommitdiffstats
path: root/gfx/wr/webrender/res/brush_blend.glsl
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
commit2aa4a82499d4becd2284cdb482213d541b8804dd (patch)
treeb80bf8bf13c3766139fbacc530efd0dd9d54394c /gfx/wr/webrender/res/brush_blend.glsl
parentInitial commit. (diff)
downloadfirefox-2aa4a82499d4becd2284cdb482213d541b8804dd.tar.xz
firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.zip
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'gfx/wr/webrender/res/brush_blend.glsl')
-rw-r--r--gfx/wr/webrender/res/brush_blend.glsl301
1 files changed, 301 insertions, 0 deletions
diff --git a/gfx/wr/webrender/res/brush_blend.glsl b/gfx/wr/webrender/res/brush_blend.glsl
new file mode 100644
index 0000000000..67d422a81b
--- /dev/null
+++ b/gfx/wr/webrender/res/brush_blend.glsl
@@ -0,0 +1,301 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#define VECS_PER_SPECIFIC_BRUSH 3
+#define WR_FEATURE_TEXTURE_2D
+
+#define COMPONENT_TRANSFER_IDENTITY 0
+#define COMPONENT_TRANSFER_TABLE 1
+#define COMPONENT_TRANSFER_DISCRETE 2
+#define COMPONENT_TRANSFER_LINEAR 3
+#define COMPONENT_TRANSFER_GAMMA 4
+
+// Must be kept in sync with `Filter::as_int` in internal_types.rs
+// Not all filters are defined here because some filter use different shaders.
+#define FILTER_CONTRAST 0
+#define FILTER_GRAYSCALE 1
+#define FILTER_HUE_ROTATE 2
+#define FILTER_INVERT 3
+#define FILTER_SATURATE 4
+#define FILTER_SEPIA 5
+#define FILTER_BRIGHTNESS 6
+#define FILTER_COLOR_MATRIX 7
+#define FILTER_SRGB_TO_LINEAR 8
+#define FILTER_LINEAR_TO_SRGB 9
+#define FILTER_FLOOD 10
+#define FILTER_COMPONENT_TRANSFER 11
+
+#include shared,prim_shared,brush
+
+// Interpolated UV coordinates to sample.
+varying vec2 v_uv;
+varying vec2 v_local_pos;
+
+// Normalized bounds of the source image in the texture, adjusted to avoid
+// sampling artifacts.
+flat varying vec4 v_uv_sample_bounds;
+
+flat varying vec4 v_color_offset;
+
+// Flag to allow perspective interpolation of UV.
+flat varying float v_perspective;
+
+flat varying float v_amount;
+
+flat varying int v_op;
+flat varying int v_table_address;
+
+flat varying mat4 vColorMat;
+
+flat varying int vFuncs[4];
+
+#ifdef WR_VERTEX_SHADER
+
+void brush_vs(
+ VertexInfo vi,
+ int prim_address,
+ RectWithSize local_rect,
+ RectWithSize segment_rect,
+ ivec4 prim_user_data,
+ int specific_resource_address,
+ mat4 transform,
+ PictureTask pic_task,
+ int brush_flags,
+ vec4 unused
+) {
+ ImageResource res = fetch_image_resource(prim_user_data.x);
+ vec2 uv0 = res.uv_rect.p0;
+ vec2 uv1 = res.uv_rect.p1;
+
+ vec2 inv_texture_size = vec2(1.0) / vec2(textureSize(sColor0, 0).xy);
+ vec2 f = (vi.local_pos - local_rect.p0) / local_rect.size;
+ f = get_image_quad_uv(prim_user_data.x, f);
+ vec2 uv = mix(uv0, uv1, f);
+ float perspective_interpolate = (brush_flags & BRUSH_FLAG_PERSPECTIVE_INTERPOLATION) != 0 ? 1.0 : 0.0;
+
+ v_uv = uv * inv_texture_size * mix(vi.world_pos.w, 1.0, perspective_interpolate);
+ v_perspective = perspective_interpolate;
+
+ v_uv_sample_bounds = vec4(uv0 + vec2(0.5), uv1 - vec2(0.5)) * inv_texture_size.xyxy;
+
+ v_local_pos = vi.local_pos;
+
+ float lumR = 0.2126;
+ float lumG = 0.7152;
+ float lumB = 0.0722;
+ float oneMinusLumR = 1.0 - lumR;
+ float oneMinusLumG = 1.0 - lumG;
+ float oneMinusLumB = 1.0 - lumB;
+
+ float amount = float(prim_user_data.z) / 65536.0;
+ float invAmount = 1.0 - amount;
+
+ v_op = prim_user_data.y & 0xffff;
+ v_amount = amount;
+
+ // This assignment is only used for component transfer filters but this
+ // assignment has to be done here and not in the component transfer case
+ // below because it doesn't get executed on Windows because of a suspected
+ // miscompile of this shader on Windows. See
+ // https://github.com/servo/webrender/wiki/Driver-issues#bug-1505871---assignment-to-varying-flat-arrays-inside-switch-statement-of-vertex-shader-suspected-miscompile-on-windows
+ // default: just to satisfy angle_shader_validation.rs which needs one
+ // default: for every switch, even in comments.
+ vFuncs[0] = (prim_user_data.y >> 28) & 0xf; // R
+ vFuncs[1] = (prim_user_data.y >> 24) & 0xf; // G
+ vFuncs[2] = (prim_user_data.y >> 20) & 0xf; // B
+ vFuncs[3] = (prim_user_data.y >> 16) & 0xf; // A
+
+ if (v_op == FILTER_GRAYSCALE) {
+ vColorMat = mat4(
+ vec4(lumR + oneMinusLumR * invAmount, lumR - lumR * invAmount, lumR - lumR * invAmount, 0.0),
+ vec4(lumG - lumG * invAmount, lumG + oneMinusLumG * invAmount, lumG - lumG * invAmount, 0.0),
+ vec4(lumB - lumB * invAmount, lumB - lumB * invAmount, lumB + oneMinusLumB * invAmount, 0.0),
+ vec4(0.0, 0.0, 0.0, 1.0)
+ );
+ v_color_offset = vec4(0.0);
+ } else if (v_op == FILTER_HUE_ROTATE) {
+ float c = cos(amount);
+ float s = sin(amount);
+ vColorMat = mat4(
+ vec4(lumR + oneMinusLumR * c - lumR * s, lumR - lumR * c + 0.143 * s, lumR - lumR * c - oneMinusLumR * s, 0.0),
+ vec4(lumG - lumG * c - lumG * s, lumG + oneMinusLumG * c + 0.140 * s, lumG - lumG * c + lumG * s, 0.0),
+ vec4(lumB - lumB * c + oneMinusLumB * s, lumB - lumB * c - 0.283 * s, lumB + oneMinusLumB * c + lumB * s, 0.0),
+ vec4(0.0, 0.0, 0.0, 1.0)
+ );
+ v_color_offset = vec4(0.0);
+ } else if (v_op == FILTER_SATURATE) {
+ vColorMat = mat4(
+ vec4(invAmount * lumR + amount, invAmount * lumR, invAmount * lumR, 0.0),
+ vec4(invAmount * lumG, invAmount * lumG + amount, invAmount * lumG, 0.0),
+ vec4(invAmount * lumB, invAmount * lumB, invAmount * lumB + amount, 0.0),
+ vec4(0.0, 0.0, 0.0, 1.0)
+ );
+ v_color_offset = vec4(0.0);
+ } else if (v_op == FILTER_SEPIA) {
+ vColorMat = mat4(
+ vec4(0.393 + 0.607 * invAmount, 0.349 - 0.349 * invAmount, 0.272 - 0.272 * invAmount, 0.0),
+ vec4(0.769 - 0.769 * invAmount, 0.686 + 0.314 * invAmount, 0.534 - 0.534 * invAmount, 0.0),
+ vec4(0.189 - 0.189 * invAmount, 0.168 - 0.168 * invAmount, 0.131 + 0.869 * invAmount, 0.0),
+ vec4(0.0, 0.0, 0.0, 1.0)
+ );
+ v_color_offset = vec4(0.0);
+ } else if (v_op == FILTER_COLOR_MATRIX) {
+ vec4 mat_data[4] = fetch_from_gpu_cache_4(prim_user_data.z);
+ vec4 offset_data = fetch_from_gpu_cache_1(prim_user_data.z + 4);
+ vColorMat = mat4(mat_data[0], mat_data[1], mat_data[2], mat_data[3]);
+ v_color_offset = offset_data;
+ } else if (v_op == FILTER_COMPONENT_TRANSFER) {
+ v_table_address = prim_user_data.z;
+ } else if (v_op == FILTER_FLOOD) {
+ v_color_offset = fetch_from_gpu_cache_1(prim_user_data.z);
+ }
+}
+#endif
+
+#ifdef WR_FRAGMENT_SHADER
+vec3 Contrast(vec3 Cs, float amount) {
+ return Cs.rgb * amount - 0.5 * amount + 0.5;
+}
+
+vec3 Invert(vec3 Cs, float amount) {
+ return mix(Cs.rgb, vec3(1.0) - Cs.rgb, amount);
+}
+
+vec3 Brightness(vec3 Cs, float amount) {
+ // Apply the brightness factor.
+ // Resulting color needs to be clamped to output range
+ // since we are pre-multiplying alpha in the shader.
+ return clamp(Cs.rgb * amount, vec3(0.0), vec3(1.0));
+}
+
+// Based on the Gecko's implementation in
+// https://hg.mozilla.org/mozilla-central/file/91b4c3687d75/gfx/src/FilterSupport.cpp#l24
+// These could be made faster by sampling a lookup table stored in a float texture
+// with linear interpolation.
+
+vec3 SrgbToLinear(vec3 color) {
+ vec3 c1 = color / 12.92;
+ vec3 c2 = pow(color / 1.055 + vec3(0.055 / 1.055), vec3(2.4));
+ return if_then_else(lessThanEqual(color, vec3(0.04045)), c1, c2);
+}
+
+vec3 LinearToSrgb(vec3 color) {
+ vec3 c1 = color * 12.92;
+ vec3 c2 = vec3(1.055) * pow(color, vec3(1.0 / 2.4)) - vec3(0.055);
+ return if_then_else(lessThanEqual(color, vec3(0.0031308)), c1, c2);
+}
+
+// This function has to be factored out due to the following issue:
+// 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
+// (and now the words "default: default:" so angle_shader_validation.rs passes)
+vec4 ComponentTransfer(vec4 colora) {
+ // We push a different amount of data to the gpu cache depending on the
+ // function type.
+ // Identity => 0 blocks
+ // Table/Discrete => 64 blocks (256 values)
+ // Linear => 1 block (2 values)
+ // Gamma => 1 block (3 values)
+ // We loop through the color components and increment the offset (for the
+ // next color component) into the gpu cache based on how many blocks that
+ // function type put into the gpu cache.
+ // Table/Discrete use a 256 entry look up table.
+ // Linear/Gamma are a simple calculation.
+ int offset = 0;
+ vec4 texel;
+ int k;
+
+ for (int i = 0; i < 4; i++) {
+ switch (vFuncs[i]) {
+ case COMPONENT_TRANSFER_IDENTITY:
+ break;
+ case COMPONENT_TRANSFER_TABLE:
+ case COMPONENT_TRANSFER_DISCRETE: {
+ // fetch value from lookup table
+ k = int(floor(colora[i]*255.0));
+ texel = fetch_from_gpu_cache_1(v_table_address + offset + k/4);
+ colora[i] = clamp(texel[k % 4], 0.0, 1.0);
+ // offset plus 256/4 blocks
+ offset = offset + 64;
+ break;
+ }
+ case COMPONENT_TRANSFER_LINEAR: {
+ // fetch the two values for use in the linear equation
+ texel = fetch_from_gpu_cache_1(v_table_address + offset);
+ colora[i] = clamp(texel[0] * colora[i] + texel[1], 0.0, 1.0);
+ // offset plus 1 block
+ offset = offset + 1;
+ break;
+ }
+ case COMPONENT_TRANSFER_GAMMA: {
+ // fetch the three values for use in the gamma equation
+ texel = fetch_from_gpu_cache_1(v_table_address + offset);
+ colora[i] = clamp(texel[0] * pow(colora[i], texel[1]) + texel[2], 0.0, 1.0);
+ // offset plus 1 block
+ offset = offset + 1;
+ break;
+ }
+ default:
+ // shouldn't happen
+ break;
+ }
+ }
+ return colora;
+}
+
+Fragment brush_fs() {
+ float perspective_divisor = mix(gl_FragCoord.w, 1.0, v_perspective);
+ vec2 uv = v_uv * perspective_divisor;
+ // Clamp the uvs to avoid sampling artifacts.
+ uv = clamp(uv, v_uv_sample_bounds.xy, v_uv_sample_bounds.zw);
+
+ vec4 Cs = texture(sColor0, uv);
+
+ // Un-premultiply the input.
+ float alpha = Cs.a;
+ vec3 color = alpha != 0.0 ? Cs.rgb / alpha : Cs.rgb;
+
+ switch (v_op) {
+ case FILTER_CONTRAST:
+ color = Contrast(color, v_amount);
+ break;
+ case FILTER_INVERT:
+ color = Invert(color, v_amount);
+ break;
+ case FILTER_BRIGHTNESS:
+ color = Brightness(color, v_amount);
+ break;
+ case FILTER_SRGB_TO_LINEAR:
+ color = SrgbToLinear(color);
+ break;
+ case FILTER_LINEAR_TO_SRGB:
+ color = LinearToSrgb(color);
+ break;
+ case FILTER_COMPONENT_TRANSFER: {
+ // Get the unpremultiplied color with alpha.
+ vec4 colora = vec4(color, alpha);
+ colora = ComponentTransfer(colora);
+ color = colora.rgb;
+ alpha = colora.a;
+ break;
+ }
+ case FILTER_FLOOD:
+ color = v_color_offset.rgb;
+ alpha = v_color_offset.a;
+ break;
+ default:
+ // Color matrix type filters (sepia, hue-rotate, etc...)
+ vec4 result = vColorMat * vec4(color, alpha) + v_color_offset;
+ result = clamp(result, vec4(0.0), vec4(1.0));
+ color = result.rgb;
+ alpha = result.a;
+ }
+
+ #ifdef WR_FEATURE_ALPHA_PASS
+ alpha *= init_transform_fs(v_local_pos);
+ // Pre-multiply the alpha into the output value.
+ #endif
+
+ return Fragment(alpha * vec4(color, 1.0));
+}
+#endif