Test AA changes. try: -b do -p linux64 -u all[linux64-qr] -t none
authorGlenn Watson <gwatson@mozilla.com>
Fri, 13 Oct 2017 10:07:01 +1000
changeset 1319343 3152d4985b707a6dd3419552c4762cb77c3e4d59
parent 1319228 25aad10380b10b6efa50c2b4d97245f078d870a0
child 1582990 b34b946948668cd72c2b20bfe84c995af267413f
push id227780
push usergwatson@mozilla.com
push dateFri, 13 Oct 2017 00:14:39 +0000
treeherdertry@3152d4985b70 [default view] [failures only]
milestone58.0a1
Test AA changes. try: -b do -p linux64 -u all[linux64-qr] -t none
gfx/webrender/res/cs_clip_border.glsl
gfx/webrender/res/cs_clip_rectangle.glsl
gfx/webrender/res/prim_shared.glsl
gfx/webrender/res/ps_border_corner.glsl
gfx/webrender/res/ps_border_edge.glsl
gfx/webrender/res/ps_hardware_composite.fs.glsl
gfx/webrender/res/ps_hardware_composite.glsl
gfx/webrender/res/ps_hardware_composite.vs.glsl
gfx/webrender/res/ps_line.glsl
--- a/gfx/webrender/res/cs_clip_border.glsl
+++ b/gfx/webrender/res/cs_clip_border.glsl
@@ -150,29 +150,28 @@ void main(void) {
     float d0 = distance_to_line(vPoint_Tangent0.xy,
                                 vPoint_Tangent0.zw,
                                 clip_relative_pos);
     float d1 = distance_to_line(vPoint_Tangent1.xy,
                                 vPoint_Tangent1.zw,
                                 clip_relative_pos);
 
     // Get AA widths based on zoom / scale etc.
-    vec2 fw = fwidth(local_pos);
-    float afwidth = length(fw);
+    float aa_range = compute_aa_range(local_pos);
 
     // SDF subtract edges for dash clip
     float dash_distance = max(d0, -d1);
 
     // Get distance from dot.
     float dot_distance = distance(clip_relative_pos, vDotParams.xy) - vDotParams.z;
 
     // Select between dot/dash clip based on mode.
     float d = mix(dash_distance, dot_distance, vAlphaMask.x);
 
-    // Apply AA over half a device pixel for the clip.
-    d = 1.0 - smoothstep(0.0, 0.5 * afwidth, d);
+    // Apply AA.
+    d = distance_aa(aa_range, d);
 
     // Completely mask out clip if zero'ing out the rect.
     d = d * vAlphaMask.y;
 
     oFragColor = vec4(d, 0.0, 0.0, 1.0);
 }
 #endif
--- a/gfx/webrender/res/cs_clip_rectangle.glsl
+++ b/gfx/webrender/res/cs_clip_rectangle.glsl
@@ -96,61 +96,58 @@ void main(void) {
                                  clip.bottom_left.outer_inner_radius.xy);
 }
 #endif
 
 #ifdef WR_FRAGMENT_SHADER
 float clip_against_ellipse_if_needed(vec2 pos,
                                      float current_distance,
                                      vec4 ellipse_center_radius,
-                                     vec2 sign_modifier,
-                                     float afwidth) {
+                                     vec2 sign_modifier) {
     float ellipse_distance = distance_to_ellipse(pos - ellipse_center_radius.xy,
                                                  ellipse_center_radius.zw);
-
     return mix(current_distance,
-               ellipse_distance + afwidth,
+               ellipse_distance,
                all(lessThan(sign_modifier * pos, sign_modifier * ellipse_center_radius.xy)));
 }
 
 float rounded_rect(vec2 pos) {
-    float current_distance = 0.0;
-
-    // Apply AA
-    float afwidth = 0.5 * length(fwidth(pos));
+    // Start with a negative value (means "inside") for all fragments that are not
+    // in a corner. If the fragment is in a corner, one of the clip_against_ellipse_if_needed
+    // calls below will update it.
+    float current_distance = -1.0;
 
     // Clip against each ellipse.
     current_distance = clip_against_ellipse_if_needed(pos,
                                                       current_distance,
                                                       vClipCenter_Radius_TL,
-                                                      vec2(1.0),
-                                                      afwidth);
+                                                      vec2(1.0));
 
     current_distance = clip_against_ellipse_if_needed(pos,
                                                       current_distance,
                                                       vClipCenter_Radius_TR,
-                                                      vec2(-1.0, 1.0),
-                                                      afwidth);
+                                                      vec2(-1.0, 1.0));
 
     current_distance = clip_against_ellipse_if_needed(pos,
                                                       current_distance,
                                                       vClipCenter_Radius_BR,
-                                                      vec2(-1.0),
-                                                      afwidth);
+                                                      vec2(-1.0));
 
     current_distance = clip_against_ellipse_if_needed(pos,
                                                       current_distance,
                                                       vClipCenter_Radius_BL,
-                                                      vec2(1.0, -1.0),
-                                                      afwidth);
+                                                      vec2(1.0, -1.0));
 
-    return smoothstep(0.0, afwidth, 1.0 - current_distance);
+    // Apply AA
+    // See comment in ps_border_corner about the choice of constants.
+    float aa_range = compute_aa_range(pos);
+
+    return distance_aa(aa_range, current_distance);
 }
 
-
 void main(void) {
     float alpha = 1.f;
     vec2 local_pos = init_transform_fs(vPos, alpha);
 
     float clip_alpha = rounded_rect(local_pos);
 
     float combined_alpha = min(alpha, clip_alpha);
 
--- a/gfx/webrender/res/prim_shared.glsl
+++ b/gfx/webrender/res/prim_shared.glsl
@@ -714,34 +714,60 @@ void write_clip(vec2 global_pos, ClipAre
     vec2 uv = global_pos + area.task_bounds.xy - area.screen_origin_target_index.xy;
     vClipMaskUvBounds = area.task_bounds / texture_size.xyxy;
     vClipMaskUv = vec3(uv / texture_size, area.screen_origin_target_index.z);
 }
 #endif //WR_VERTEX_SHADER
 
 #ifdef WR_FRAGMENT_SHADER
 
+/// Find the appropriate half range to apply the AA smoothstep over.
+/// This range represents a coefficient to go from one CSS pixel to half a device pixel.
+float compute_aa_range(vec2 position) {
+    // We use 0.4 instead of 0.5 here to compensate for the fact that length(fw) is equal
+    // to sqrt(2) times the device pixel ratio in the typical case.
+    // This coefficient is chosen to ensure that a sample that any sample 0.5 pixels
+    // or more inside of the shape has no anti-aliasing applied to it (since pixels are
+    // sampled at their center, such a pixel (axis aligned) is fully inside the border),
+    // so that antialiased curves properly connect with non-antialiased vertical or horizontal
+    // lines.
+    //
+    // Using larger aa steps is quite common when rendering shapes with distance fields.
+    // It gives a smoother (although blurrier look) by extending the range that is smoothed
+    // to produce the anti aliasing. In our case, however, extending the range inside of
+    // the shape causes noticeable artifacts at the junction between an antialiased corner
+    // and a straight edge.
+    return 0.35355 * length(fwidth(position));
+}
+
+/// Return the blending coefficient to for distance antialiasing.
+///
+/// 0.0 means inside the shape, 1.0 means outside.
+float distance_aa(float aa_range, float signed_distance) {
+    return 1.0 - smoothstep(-aa_range, aa_range, signed_distance);
+}
+
 #ifdef WR_FEATURE_TRANSFORM
 float signed_distance_rect(vec2 pos, vec2 p0, vec2 p1) {
     vec2 d = max(p0 - pos, pos - p1);
     return length(max(vec2(0.0), d)) + min(0.0, max(d.x, d.y));
 }
 
 vec2 init_transform_fs(vec3 local_pos, out float fragment_alpha) {
     fragment_alpha = 1.0;
     vec2 pos = local_pos.xy / local_pos.z;
 
     // Now get the actual signed distance.
     float d = signed_distance_rect(pos, vLocalBounds.xy, vLocalBounds.zw);
 
     // Find the appropriate distance to apply the AA smoothstep over.
-    float afwidth = 0.5 * length(fwidth(pos.xy));
+    float aa_range = compute_aa_range(pos.xy);
 
     // Only apply AA to fragments outside the signed distance field.
-    fragment_alpha = 1.0 - smoothstep(0.0, afwidth, d);
+    fragment_alpha = distance_aa(aa_range, d);
 
     return pos;
 }
 #endif //WR_FEATURE_TRANSFORM
 
 float do_clip() {
     // anything outside of the mask is considered transparent
     bvec4 inside = lessThanEqual(
--- a/gfx/webrender/res/ps_border_corner.glsl
+++ b/gfx/webrender/res/ps_border_corner.glsl
@@ -319,21 +319,17 @@ void main(void) {
     alpha = 0.0;
     vec2 local_pos = init_transform_fs(vLocalPos, alpha);
 #else
     vec2 local_pos = vLocalPos;
 #endif
 
     alpha = min(alpha, do_clip());
 
-    // Find the appropriate distance to apply the AA smoothstep over.
-    // Using 0.7 instead of 0.5 for the step compensates for the fact that smoothstep
-    // is smooth at its endpoints and has a steeper maximum slope than a linear ramp.
-    vec2 fw = fwidth(local_pos);
-    float aa_step = 0.7 * length(fw);
+    float aa_range = compute_aa_range(local_pos);
 
     float distance_for_color;
     float color_mix_factor;
 
     // Only apply the clip AA if inside the clip region. This is
     // necessary for correctness when the border width is greater
     // than the border radius.
     if (all(lessThan(local_pos * vClipSign, vClipCenter * vClipSign))) {
@@ -344,39 +340,36 @@ void main(void) {
         // error of half a pixel towards the exterior of the curve (See issue #1750).
         // This error is corrected by offsetting the distance by half a device pixel.
         // This not entirely correct: it leaves an error that varries between
         // 0 and (sqrt(2) - 1)/2 = 0.2 pixels but it is hardly noticeable and is better
         // than the constant sqrt(2)/2 px error without the correction.
         // To correct this exactly we would need to offset p by half a pixel in the
         // direction of the center of the ellipse (a different offset for each corner).
 
-        // A half device pixel in css pixels (using the average of width and height in case
-        // there is any kind of transform applied).
-        float half_px = 0.25 * (fw.x + fw.y);
         // Get signed distance from the inner/outer clips.
-        float d0 = distance_to_ellipse(p, vRadii0.xy) + half_px;
-        float d1 = distance_to_ellipse(p, vRadii0.zw) + half_px;
-        float d2 = distance_to_ellipse(p, vRadii1.xy) + half_px;
-        float d3 = distance_to_ellipse(p, vRadii1.zw) + half_px;
+        float d0 = distance_to_ellipse(p, vRadii0.xy);
+        float d1 = distance_to_ellipse(p, vRadii0.zw);
+        float d2 = distance_to_ellipse(p, vRadii1.xy);
+        float d3 = distance_to_ellipse(p, vRadii1.zw);
 
         // SDF subtract main radii
-        float d_main = max(d0, aa_step - d1);
+        float d_main = max(d0, -d1);
 
         // SDF subtract inner radii (double style borders)
-        float d_inner = max(d2 - aa_step, -d3);
+        float d_inner = max(d2, -d3);
 
         // Select how to combine the SDF based on border style.
         float d = mix(max(d_main, -d_inner), d_main, vSDFSelect);
 
         // Only apply AA to fragments outside the signed distance field.
-        alpha = min(alpha, 1.0 - smoothstep(0.0, aa_step, d));
+        alpha = min(alpha, distance_aa(aa_range, d));
 
         // Get the groove/ridge mix factor.
-        color_mix_factor = smoothstep(-aa_step, aa_step, -d2);
+        color_mix_factor = distance_aa(aa_range, d2);
     } else {
         // Handle the case where the fragment is outside the clip
         // region in a corner. This occurs when border width is
         // greater than border radius.
 
         // Get linear distances along horizontal and vertical edges.
         vec2 d0 = vClipSign.xx * (local_pos.xx - vEdgeDistance.xz);
         vec2 d1 = vClipSign.yy * (local_pos.yy - vEdgeDistance.yw);
@@ -398,14 +391,14 @@ void main(void) {
 
     // Mix inner/outer color.
     vec4 color0 = mix(vColor00, vColor01, color_mix_factor);
     vec4 color1 = mix(vColor10, vColor11, color_mix_factor);
 
     // Select color based on side of line. Get distance from the
     // reference line, and then apply AA along the edge.
     float ld = distance_to_line(vColorEdgeLine.xy, vColorEdgeLine.zw, local_pos);
-    float m = smoothstep(-aa_step, aa_step, ld);
+    float m = distance_aa(aa_range, -ld);
     vec4 color = mix(color0, color1, m);
 
     oFragColor = color * vec4(1.0, 1.0, 1.0, alpha);
 }
 #endif
--- a/gfx/webrender/res/ps_border_edge.glsl
+++ b/gfx/webrender/res/ps_border_edge.glsl
@@ -248,18 +248,17 @@ void main(void) {
     vec2 local_pos = init_transform_fs(vLocalPos, alpha);
 #else
     vec2 local_pos = vLocalPos;
 #endif
 
     alpha = min(alpha, do_clip());
 
     // Find the appropriate distance to apply the step over.
-    vec2 fw = fwidth(local_pos);
-    float afwidth = length(fw);
+    float aa_range = compute_aa_range(local_pos);
 
     // Applies the math necessary to draw a style: double
     // border. In the case of a solid border, the vertex
     // shader sets interpolator values that make this have
     // no effect.
 
     // Select the x/y coord, depending on which axis this edge is.
     vec2 pos = mix(local_pos.xy, local_pos.yx, vAxisSelect);
@@ -286,18 +285,16 @@ void main(void) {
     float x = mod(pos.y - vClipParams.x, vClipParams.y);
 
     // Calculate dash alpha (on/off) based on dash length
     float dash_alpha = step(x, vClipParams.z);
 
     // Get the dot alpha
     vec2 dot_relative_pos = vec2(x, pos.x) - vClipParams.zw;
     float dot_distance = length(dot_relative_pos) - vClipParams.z;
-    float dot_alpha = 1.0 - smoothstep(-0.5 * afwidth,
-                                        0.5 * afwidth,
-                                        dot_distance);
+    float dot_alpha = distance_aa(aa_range, dot_distance);
 
     // Select between dot/dash alpha based on clip mode.
     alpha = min(alpha, mix(dash_alpha, dot_alpha, vClipSelect));
 
     oFragColor = color * vec4(1.0, 1.0, 1.0, alpha);
 }
 #endif
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_hardware_composite.fs.glsl
@@ -0,0 +1,8 @@
+/* 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/. */
+
+void main(void) {
+    vec2 uv = clamp(vUv.xy, vUvBounds.xy, vUvBounds.zw);
+    oFragColor = texture(sCacheRGBA8, vec3(uv, vUv.z));
+}
--- a/gfx/webrender/res/ps_hardware_composite.glsl
+++ b/gfx/webrender/res/ps_hardware_composite.glsl
@@ -1,39 +1,8 @@
 /* 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/. */
 
 #include shared,prim_shared
 
 varying vec3 vUv;
 flat varying vec4 vUvBounds;
-
-#ifdef WR_VERTEX_SHADER
-void main(void) {
-    CompositeInstance ci = fetch_composite_instance();
-    AlphaBatchTask dest_task = fetch_alpha_batch_task(ci.render_task_index);
-    AlphaBatchTask src_task = fetch_alpha_batch_task(ci.src_task_index);
-
-    vec2 dest_origin = dest_task.render_target_origin -
-                       dest_task.screen_space_origin +
-                       vec2(ci.user_data0, ci.user_data1);
-
-    vec2 local_pos = mix(dest_origin,
-                         dest_origin + src_task.size,
-                         aPosition.xy);
-
-    vec2 texture_size = vec2(textureSize(sCacheRGBA8, 0));
-    vec2 st0 = src_task.render_target_origin;
-    vec2 st1 = src_task.render_target_origin + src_task.size;
-    vUv = vec3(mix(st0, st1, aPosition.xy) / texture_size, src_task.render_target_layer_index);
-    vUvBounds = vec4(st0 + 0.5, st1 - 0.5) / texture_size.xyxy;
-
-    gl_Position = uTransform * vec4(local_pos, ci.z, 1.0);
-}
-#endif
-
-#ifdef WR_FRAGMENT_SHADER
-void main(void) {
-    vec2 uv = clamp(vUv.xy, vUvBounds.xy, vUvBounds.zw);
-    oFragColor = texture(sCacheRGBA8, vec3(uv, vUv.z));
-}
-#endif
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_hardware_composite.vs.glsl
@@ -0,0 +1,25 @@
+/* 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/. */
+
+void main(void) {
+    CompositeInstance ci = fetch_composite_instance();
+    AlphaBatchTask dest_task = fetch_alpha_batch_task(ci.render_task_index);
+    AlphaBatchTask src_task = fetch_alpha_batch_task(ci.src_task_index);
+
+    vec2 dest_origin = dest_task.render_target_origin -
+                       dest_task.screen_space_origin +
+                       vec2(ci.user_data0, ci.user_data1);
+
+    vec2 local_pos = mix(dest_origin,
+                         dest_origin + src_task.size,
+                         aPosition.xy);
+
+    vec2 texture_size = vec2(textureSize(sCacheRGBA8, 0));
+    vec2 st0 = src_task.render_target_origin;
+    vec2 st1 = src_task.render_target_origin + src_task.size;
+    vUv = vec3(mix(st0, st1, aPosition.xy) / texture_size, src_task.render_target_layer_index);
+    vUvBounds = vec4(st0 + 0.5, st1 - 0.5) / texture_size.xyxy;
+
+    gl_Position = uTransform * vec4(local_pos, ci.z, 1.0);
+}
--- a/gfx/webrender/res/ps_line.glsl
+++ b/gfx/webrender/res/ps_line.glsl
@@ -185,18 +185,17 @@ void main(void) {
     #else
         vec2 local_pos = vLocalPos;
     #endif
 
         alpha = min(alpha, do_clip());
 #endif
 
     // Find the appropriate distance to apply the step over.
-    vec2 fw = fwidth(local_pos);
-    float afwidth = length(fw);
+    float aa_range = compute_aa_range(local_pos);
 
     // Select the x/y coord, depending on which axis this edge is.
     vec2 pos = mix(local_pos.xy, local_pos.yx, vAxisSelect);
 
     switch (vStyle) {
         case LINE_STYLE_SOLID: {
             break;
         }
@@ -210,19 +209,17 @@ void main(void) {
         }
         case LINE_STYLE_DOTTED: {
             // Get the main-axis position relative to closest dot or dash.
             float x = mod(pos.x - vLocalOrigin.x, vParams.x);
 
             // Get the dot alpha
             vec2 dot_relative_pos = vec2(x, pos.y) - vParams.yz;
             float dot_distance = length(dot_relative_pos) - vParams.y;
-            alpha = min(alpha, 1.0 - smoothstep(-0.5 * afwidth,
-                                                0.5 * afwidth,
-                                                dot_distance));
+            alpha = min(alpha, distance_aa(aa_range, dot_distance));
             break;
         }
         case LINE_STYLE_WAVY: {
             vec2 normalized_local_pos = pos - vLocalOrigin.xy;
 
             float y0 = vParams.y;
             float dy = vParams.z;
             float dx = vParams.w;
@@ -246,18 +243,16 @@ void main(void) {
             vec2 b2_1 = vec2(4.0 * dx,  y0);
             float d2 = approx_distance(normalized_local_pos, b0_1, b1_1, b2_1);
 
             // SDF union - this is needed to avoid artifacts where the
             // bezier curves join.
             float d = min(d1, d2);
 
             // Apply AA based on the thickness of the wave.
-            alpha = 1.0 - smoothstep(vParams.x - 0.5 * afwidth,
-                                     vParams.x + 0.5 * afwidth,
-                                     d);
+            alpha = distance_aa(aa_range, d - vParams.x);
             break;
         }
     }
 
     oFragColor = vColor * vec4(1.0, 1.0, 1.0, alpha);
 }
 #endif