Bug 1474294 - Perspective clip interpolation fix r=gw
authorDzmitry Malyshau <dmalyshau@mozilla.com>
Sat, 08 Jun 2019 02:53:37 +0000
changeset 477936 24f1d034783edad57e1f8b7dadabec74cef8c047
parent 477935 d08ae3b73857fa05a83bcd320022481cf6684018
child 477937 e227ab51e4a95dfc64607fdc5407be647327fc24
push id36127
push usernbeleuzu@mozilla.com
push dateSat, 08 Jun 2019 09:39:25 +0000
treeherdermozilla-central@b26753fb35e7 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgw
bugs1474294
milestone69.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1474294 - Perspective clip interpolation fix r=gw Force perspective interpolation of UV coordinates in clip shaders. In addition to fixing the interpolation curve, also adds checks for the homogeneous coordinates to be outside of the meaningful hemisphere, forcing the clip shaders to output zeroes in those areas. Differential Revision: https://phabricator.services.mozilla.com/D34017
gfx/wr/webrender/res/clip_shared.glsl
gfx/wr/webrender/res/cs_clip_box_shadow.glsl
gfx/wr/webrender/res/cs_clip_image.glsl
gfx/wr/webrender/res/cs_clip_rectangle.glsl
--- a/gfx/wr/webrender/res/clip_shared.glsl
+++ b/gfx/wr/webrender/res/clip_shared.glsl
@@ -43,25 +43,26 @@ ClipMaskInstance fetch_clip_item() {
     cmi.task_origin = aClipOrigins.xy;
     cmi.screen_origin = aClipOrigins.zw;
     cmi.device_pixel_scale = aDevicePixelScale;
 
     return cmi;
 }
 
 struct ClipVertexInfo {
-    vec3 local_pos;
+    vec4 local_pos;
     RectWithSize clipped_local_rect;
 };
 
 RectWithSize intersect_rect(RectWithSize a, RectWithSize b) {
     vec4 p = clamp(vec4(a.p0, a.p0 + a.size), b.p0.xyxy, b.p0.xyxy + b.size.xyxy);
     return RectWithSize(p.xy, max(vec2(0.0), p.zw - p.xy));
 }
 
+
 // The transformed vertex function that always covers the whole clip area,
 // which is the intersection of all clip instances of a given primitive
 ClipVertexInfo write_clip_tile_vertex(RectWithSize local_clip_rect,
                                       Transform prim_transform,
                                       Transform clip_transform,
                                       RectWithSize sub_rect,
                                       vec4 snap_offsets,
                                       vec2 task_origin,
@@ -81,18 +82,25 @@ ClipVertexInfo write_clip_tile_vertex(Re
     device_pos -= snap_offset;
 
     vec2 world_pos = device_pos / device_pixel_scale;
 
     vec4 pos = prim_transform.m * vec4(world_pos, 0.0, 1.0);
     pos.xyz /= pos.w;
 
     vec4 p = get_node_pos(pos.xy, clip_transform);
-    vec3 local_pos = p.xyw * pos.w;
+    vec4 local_pos = p * pos.w;
 
+    //TODO: Interpolate in clip space, where "local_pos.w" contains
+    // the W of the homogeneous transform *from* clip space into the world.
+    //    float interpolate_w = 1.0 / local_pos.w;
+    // This is problematic today, because the W<=0 hemisphere is going to be
+    // clipped, while we currently want this shader to fill out the whole rect.
+    // We can therefore simplify this when the clip construction is rewritten
+    // to only affect the areas touched by a clip.
     vec4 vertex_pos = vec4(
         task_origin + sub_rect.p0 + aPosition.xy * sub_rect.size,
         0.0,
         1.0
     );
 
     gl_Position = uTransform * vertex_pos;
 
--- a/gfx/wr/webrender/res/cs_clip_box_shadow.glsl
+++ b/gfx/wr/webrender/res/cs_clip_box_shadow.glsl
@@ -1,15 +1,15 @@
 /* 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,clip_shared
 
-varying vec3 vLocalPos;
+varying vec4 vLocalPos;
 varying vec2 vUv;
 flat varying vec4 vUvBounds;
 flat varying float vLayer;
 flat varying vec4 vEdge;
 flat varying vec4 vUvBounds_NoClamp;
 flat varying float vClipMode;
 
 #define MODE_STRETCH        0
@@ -53,25 +53,22 @@ void main(void) {
         prim_transform,
         clip_transform,
         cmi.sub_rect,
         cmi.snap_offsets,
         cmi.task_origin,
         cmi.screen_origin,
         cmi.device_pixel_scale
     );
-    vLocalPos = vi.local_pos;
     vLayer = res.layer;
     vClipMode = bs_data.clip_mode;
 
-    vec2 uv0 = res.uv_rect.p0;
-    vec2 uv1 = res.uv_rect.p1;
-
     vec2 texture_size = vec2(textureSize(sColor0, 0));
-    vec2 local_pos = vLocalPos.xy / vLocalPos.z;
+    vec2 local_pos = vi.local_pos.xy / vi.local_pos.w;
+    vLocalPos = vi.local_pos;
 
     switch (bs_data.stretch_mode_x) {
         case MODE_STRETCH: {
             vEdge.x = 0.5;
             vEdge.z = (dest_rect.size.x / bs_data.src_rect_size.x) - 0.5;
             vUv.x = (local_pos.x - dest_rect.p0.x) / bs_data.src_rect_size.x;
             break;
         }
@@ -93,31 +90,34 @@ void main(void) {
         case MODE_SIMPLE:
         default: {
             vEdge.yw = vec2(1.0);
             vUv.y = (local_pos.y - dest_rect.p0.y) / dest_rect.size.y;
             break;
         }
     }
 
+    vUv *= vi.local_pos.w;
+    vec2 uv0 = res.uv_rect.p0;
+    vec2 uv1 = res.uv_rect.p1;
     vUvBounds = vec4(uv0 + vec2(0.5), uv1 - vec2(0.5)) / texture_size.xyxy;
     vUvBounds_NoClamp = vec4(uv0, uv1) / texture_size.xyxy;
 }
 #endif
 
 #ifdef WR_FRAGMENT_SHADER
 void main(void) {
-    vec2 local_pos = vLocalPos.xy / vLocalPos.z;
-
-    vec2 uv = clamp(vUv.xy, vec2(0.0), vEdge.xy);
-    uv += max(vec2(0.0), vUv.xy - vEdge.zw);
+    vec2 uv_linear = vUv / vLocalPos.w;
+    vec2 uv = clamp(uv_linear, vec2(0.0), vEdge.xy);
+    uv += max(vec2(0.0), uv_linear - vEdge.zw);
     uv = mix(vUvBounds_NoClamp.xy, vUvBounds_NoClamp.zw, uv);
     uv = clamp(uv, vUvBounds.xy, vUvBounds.zw);
 
-    float in_shadow_rect = init_transform_rough_fs(local_pos);
+    float in_shadow_rect = init_transform_rough_fs(vLocalPos.xy / vLocalPos.w);
 
     float texel = TEX_SAMPLE(sColor0, vec3(uv, vLayer)).r;
 
     float alpha = mix(texel, 1.0 - texel, vClipMode);
+    float result = vLocalPos.w > 0.0 ? mix(vClipMode, alpha, in_shadow_rect) : 0.0;
 
-    oFragColor = vec4(mix(vClipMode, alpha, in_shadow_rect));
+    oFragColor = vec4(result);
 }
 #endif
--- a/gfx/wr/webrender/res/cs_clip_image.glsl
+++ b/gfx/wr/webrender/res/cs_clip_image.glsl
@@ -1,15 +1,15 @@
 /* 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,clip_shared
 
-varying vec2 vLocalPos;
+varying vec4 vLocalPos;
 varying vec2 vClipMaskImageUv;
 
 flat varying vec4 vClipMaskUvRect;
 flat varying vec4 vClipMaskUvInnerRect;
 flat varying float vLayer;
 
 #ifdef WR_VERTEX_SHADER
 struct ImageMaskData {
@@ -35,37 +35,40 @@ void main(void) {
         prim_transform,
         clip_transform,
         cmi.sub_rect,
         cmi.snap_offsets,
         cmi.task_origin,
         cmi.screen_origin,
         cmi.device_pixel_scale
     );
-    vLocalPos = vi.local_pos.xy / vi.local_pos.z;
+    vLocalPos = vi.local_pos;
     vLayer = res.layer;
-    vClipMaskImageUv = (vLocalPos - cmi.tile_rect.p0) / cmi.tile_rect.size;
+    vClipMaskImageUv = (vi.local_pos.xy - cmi.tile_rect.p0 * vi.local_pos.w) / cmi.tile_rect.size;
+
     vec2 texture_size = vec2(textureSize(sColor0, 0));
     vClipMaskUvRect = vec4(res.uv_rect.p0, res.uv_rect.p1 - res.uv_rect.p0) / texture_size.xyxy;
     // applying a half-texel offset to the UV boundaries to prevent linear samples from the outside
     vec4 inner_rect = vec4(res.uv_rect.p0, res.uv_rect.p1);
     vClipMaskUvInnerRect = (inner_rect + vec4(0.5, 0.5, -0.5, -0.5)) / texture_size.xyxy;
 }
 #endif
 
 #ifdef WR_FRAGMENT_SHADER
 void main(void) {
-    float alpha = init_transform_fs(vLocalPos);
+    vec2 local_pos = vLocalPos.xy / vLocalPos.w;
+    float alpha = vLocalPos.w > 0.0 ? init_transform_fs(local_pos) : 0.0;
 
     // TODO: Handle repeating masks?
-    vec2 clamped_mask_uv = clamp(vClipMaskImageUv, vec2(0.0, 0.0), vec2(1.0, 1.0));
+    vec2 clamped_mask_uv = clamp(vClipMaskImageUv, vec2(0.0, 0.0), vLocalPos.ww);
 
     // Ensure we don't draw outside of our tile.
     // FIXME(emilio): Can we do this earlier?
     if (clamped_mask_uv != vClipMaskImageUv)
         discard;
 
-    vec2 source_uv = clamp(clamped_mask_uv * vClipMaskUvRect.zw + vClipMaskUvRect.xy,
+    vec2 source_uv = clamp(
+        clamped_mask_uv / vLocalPos.w * vClipMaskUvRect.zw + vClipMaskUvRect.xy,
         vClipMaskUvInnerRect.xy, vClipMaskUvInnerRect.zw);
     float clip_alpha = texture(sColor0, vec3(source_uv, vLayer)).r; //careful: texture has type A8
     oFragColor = vec4(alpha * clip_alpha, 1.0, 1.0, 1.0);
 }
 #endif
--- a/gfx/wr/webrender/res/cs_clip_rectangle.glsl
+++ b/gfx/wr/webrender/res/cs_clip_rectangle.glsl
@@ -3,17 +3,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include shared,clip_shared,ellipse
 
 #ifdef WR_FEATURE_FAST_PATH
 varying vec2 vLocalPos;
 flat varying vec3 vClipParams;      // xy = box size, z = radius
 #else
-varying vec3 vLocalPos;
+varying vec4 vLocalPos;
 flat varying vec4 vClipCenter_Radius_TL;
 flat varying vec4 vClipCenter_Radius_TR;
 flat varying vec4 vClipCenter_Radius_BL;
 flat varying vec4 vClipCenter_Radius_BR;
 #endif
 
 flat varying float vClipMode;
 
@@ -126,20 +126,19 @@ float sdf_rounded_rect(vec2 pos, vec3 cl
     return length(max(abs(pos) - clip_params.xy, 0.0)) - clip_params.z;
 }
 #endif
 
 void main(void) {
 #ifdef WR_FEATURE_FAST_PATH
     vec2 local_pos = vLocalPos.xy;
 #else
-    vec2 local_pos = vLocalPos.xy / vLocalPos.z;
+    vec2 local_pos = vLocalPos.xy / vLocalPos.w;
 #endif
-
-    float aa_range = compute_aa_range(local_pos.xy);
+    float aa_range = compute_aa_range(local_pos);
 
 #ifdef WR_FEATURE_FAST_PATH
     float d = sdf_rounded_rect(local_pos, vClipParams);
     float f = distance_aa(aa_range, d);
     float r = mix(f, 1.0 - f, vClipMode);
     oFragColor = vec4(r);
 #else
     float alpha = init_transform_fs(local_pos.xy);
@@ -150,13 +149,14 @@ void main(void) {
                                     vClipCenter_Radius_BR,
                                     vClipCenter_Radius_BL,
                                     aa_range);
 
     float combined_alpha = alpha * clip_alpha;
 
     // Select alpha or inverse alpha depending on clip in/out.
     float final_alpha = mix(combined_alpha, 1.0 - combined_alpha, vClipMode);
+    float final_final_alpha = vLocalPos.w > 0.0 ? final_alpha : 0.0;
 
-    oFragColor = vec4(final_alpha, 0.0, 0.0, 1.0);
+    oFragColor = vec4(final_final_alpha, 0.0, 0.0, 1.0);
 #endif
 }
 #endif