diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
commit | 2aa4a82499d4becd2284cdb482213d541b8804dd (patch) | |
tree | b80bf8bf13c3766139fbacc530efd0dd9d54394c /gfx/wr/webrender/res/ellipse.glsl | |
parent | Initial commit. (diff) | |
download | firefox-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/ellipse.glsl')
-rw-r--r-- | gfx/wr/webrender/res/ellipse.glsl | 81 |
1 files changed, 81 insertions, 0 deletions
diff --git a/gfx/wr/webrender/res/ellipse.glsl b/gfx/wr/webrender/res/ellipse.glsl new file mode 100644 index 0000000000..04dc890b51 --- /dev/null +++ b/gfx/wr/webrender/res/ellipse.glsl @@ -0,0 +1,81 @@ +/* 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/. */ + +// Preprocess the radii for computing the distance approximation. This should +// be used in the vertex shader if possible to avoid doing expensive division +// in the fragment shader. When dealing with a point (zero radii), approximate +// it as an ellipse with very small radii so that we don't need to branch. +vec2 inverse_radii_squared(vec2 radii) { + return any(lessThanEqual(radii, vec2(0.0))) + ? vec2(1.0 / (1.0e-3 * 1.0e-3)) + : 1.0 / (radii * radii); +} + +#ifdef WR_FRAGMENT_SHADER + +// One iteration of Newton's method on the 2D equation of an ellipse: +// +// E(x, y) = x^2/a^2 + y^2/b^2 - 1 +// +// The Jacobian of this equation is: +// +// J(E(x, y)) = [ 2*x/a^2 2*y/b^2 ] +// +// We approximate the distance with: +// +// E(x, y) / ||J(E(x, y))|| +// +// See G. Taubin, "Distance Approximations for Rasterizing Implicit +// Curves", section 3. +float distance_to_ellipse_approx(vec2 p, vec2 inv_radii_sq) { + float g = dot(p * p, inv_radii_sq) - 1.0; + vec2 dG = 2.0 * p * inv_radii_sq; + return g * inversesqrt(dot(dG, dG)); +} + +// Slower but more accurate version that uses the exact distance when dealing +// with a 0-radius point distance and otherwise uses the faster approximation +// when dealing with non-zero radii. +float distance_to_ellipse(vec2 p, vec2 radii) { + return any(lessThanEqual(radii, vec2(0.0))) + ? length(p) + : distance_to_ellipse_approx(p, 1.0 / (radii * radii)); +} + +float clip_against_ellipse_if_needed( + vec2 pos, + vec4 ellipse_center_radius, + vec2 sign_modifier +) { + vec2 p = pos - ellipse_center_radius.xy; + // If we're not within the distance bounds of both of the radii (in the + // corner), then return a large magnitude negative value to cause us to + // clamp off the anti-aliasing. + return all(lessThan(sign_modifier * p, vec2(0.0))) + ? distance_to_ellipse_approx(p, ellipse_center_radius.zw) + : -1.0e6; +} + +float rounded_rect(vec2 pos, + vec4 clip_center_radius_tl, + vec4 clip_center_radius_tr, + vec4 clip_center_radius_br, + vec4 clip_center_radius_bl, + float aa_range) { + // Clip against each ellipse. If the fragment is in a corner, one of the + // clip_against_ellipse_if_needed calls below will update it. If outside + // any ellipse, the clip routine will return a negative value so that max() + // will choose the greatest amount of applicable anti-aliasing. + float current_distance = + max(max(clip_against_ellipse_if_needed(pos, clip_center_radius_tl, vec2(1.0)), + clip_against_ellipse_if_needed(pos, clip_center_radius_tr, vec2(-1.0, 1.0))), + max(clip_against_ellipse_if_needed(pos, clip_center_radius_br, vec2(-1.0)), + clip_against_ellipse_if_needed(pos, clip_center_radius_bl, vec2(1.0, -1.0)))); + + // Apply AA + // See comment in ps_border_corner about the choice of constants. + + return distance_aa(aa_range, current_distance); +} +#endif |