Bug 1534885 - Change clip mask rendering to not rely on render task data. r=kvark
authorGlenn Watson <github@intuitionlibrary.com>
Wed, 13 Mar 2019 19:28:36 +0000
changeset 524757 360f4359ab669cd5d4fcc7b641c0a6dd8fb65341
parent 524756 a4d1dd58552d02854ce438e11dc4c97ec885f166
child 524758 f04779216e2b928707a1c848ccd135a7b9def3c2
push id2032
push userffxbld-merge
push dateMon, 13 May 2019 09:36:57 +0000
treeherdermozilla-release@455c1065dcbe [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskvark
bugs1534885
milestone67.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 1534885 - Change clip mask rendering to not rely on render task data. r=kvark As a general principle, we're trying to remove most usage of the render task data that gets stored in a texture (bind_frame_data is slow on many platforms, and it's somewhat inflexible with the amount of data that can be provided). This also lays some foundations for possibly drawing clip masks with alternative techniques on mobile / tiled GPU architectures, where we may not need / want a render task for clip masks. Differential Revision: https://phabricator.services.mozilla.com/D23271
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
gfx/wr/webrender/src/batch.rs
gfx/wr/webrender/src/gpu_types.rs
gfx/wr/webrender/src/render_task.rs
gfx/wr/webrender/src/renderer.rs
gfx/wr/webrender/src/tiling.rs
--- a/gfx/wr/webrender/res/clip_shared.glsl
+++ b/gfx/wr/webrender/res/clip_shared.glsl
@@ -1,50 +1,53 @@
 /* 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 rect,render_task,gpu_cache,snap,transform
 
 #ifdef WR_VERTEX_SHADER
 
-in int aClipRenderTaskAddress;
-in int aClipTransformId;
-in int aPrimTransformId;
-in int aClipSegment;
+in ivec2 aTransformIds;
 in ivec4 aClipDataResourceAddress;
 in vec2 aClipLocalPos;
 in vec4 aClipTileRect;
 in vec4 aClipDeviceArea;
 in vec4 aClipSnapOffsets;
+in vec4 aClipOrigins;
+in float aDevicePixelScale;
 
 struct ClipMaskInstance {
-    int render_task_address;
     int clip_transform_id;
     int prim_transform_id;
     ivec2 clip_data_address;
     ivec2 resource_address;
     vec2 local_pos;
     RectWithSize tile_rect;
     RectWithSize sub_rect;
     vec4 snap_offsets;
+    vec2 task_origin;
+    vec2 screen_origin;
+    float device_pixel_scale;
 };
 
 ClipMaskInstance fetch_clip_item() {
     ClipMaskInstance cmi;
 
-    cmi.render_task_address = aClipRenderTaskAddress;
-    cmi.clip_transform_id = aClipTransformId;
-    cmi.prim_transform_id = aPrimTransformId;
+    cmi.clip_transform_id = aTransformIds.x;
+    cmi.prim_transform_id = aTransformIds.y;
     cmi.clip_data_address = aClipDataResourceAddress.xy;
     cmi.resource_address = aClipDataResourceAddress.zw;
     cmi.local_pos = aClipLocalPos;
     cmi.tile_rect = RectWithSize(aClipTileRect.xy, aClipTileRect.zw);
     cmi.sub_rect = RectWithSize(aClipDeviceArea.xy, aClipDeviceArea.zw);
     cmi.snap_offsets = aClipSnapOffsets;
+    cmi.task_origin = aClipOrigins.xy;
+    cmi.screen_origin = aClipOrigins.zw;
+    cmi.device_pixel_scale = aDevicePixelScale;
 
     return cmi;
 }
 
 struct ClipVertexInfo {
     vec3 local_pos;
     RectWithSize clipped_local_rect;
 };
@@ -54,43 +57,44 @@ RectWithSize intersect_rect(RectWithSize
     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,
-                                      ClipArea area,
                                       RectWithSize sub_rect,
-                                      vec4 snap_offsets) {
-    vec2 device_pos = area.screen_origin + sub_rect.p0 +
-                      aPosition.xy * sub_rect.size;
+                                      vec4 snap_offsets,
+                                      vec2 task_origin,
+                                      vec2 screen_origin,
+                                      float device_pixel_scale) {
+    vec2 device_pos = screen_origin + sub_rect.p0 + aPosition.xy * sub_rect.size;
 
     // If the primitive we are drawing a clip mask for was snapped, then
     // remove the effect of that snapping, so that the local position
     // interpolation below works correctly relative to the clip item.
     vec2 snap_offset = mix(
         snap_offsets.xy,
         snap_offsets.zw,
         aPosition.xy
     );
 
     device_pos -= snap_offset;
 
-    vec2 world_pos = device_pos / area.device_pixel_scale;
+    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 vertex_pos = vec4(
-        area.common_data.task_rect.p0 + sub_rect.p0 + aPosition.xy * sub_rect.size,
+        task_origin + sub_rect.p0 + aPosition.xy * sub_rect.size,
         0.0,
         1.0
     );
 
     gl_Position = uTransform * vertex_pos;
 
     init_transform_vs(vec4(local_clip_rect.p0, local_clip_rect.p0 + local_clip_rect.size));
 
--- a/gfx/wr/webrender/res/cs_clip_box_shadow.glsl
+++ b/gfx/wr/webrender/res/cs_clip_box_shadow.glsl
@@ -35,32 +35,33 @@ BoxShadowData fetch_data(ivec2 address) 
         int(data[1].y),
         dest_rect
     );
     return bs_data;
 }
 
 void main(void) {
     ClipMaskInstance cmi = fetch_clip_item();
-    ClipArea area = fetch_clip_area(cmi.render_task_address);
     Transform clip_transform = fetch_transform(cmi.clip_transform_id);
     Transform prim_transform = fetch_transform(cmi.prim_transform_id);
     BoxShadowData bs_data = fetch_data(cmi.clip_data_address);
     ImageResource res = fetch_image_resource_direct(cmi.resource_address);
 
     RectWithSize dest_rect = bs_data.dest_rect;
     dest_rect.p0 += cmi.local_pos;
 
     ClipVertexInfo vi = write_clip_tile_vertex(
         dest_rect,
         prim_transform,
         clip_transform,
-        area,
         cmi.sub_rect,
-        cmi.snap_offsets
+        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;
 
--- a/gfx/wr/webrender/res/cs_clip_image.glsl
+++ b/gfx/wr/webrender/res/cs_clip_image.glsl
@@ -19,30 +19,31 @@ struct ImageMaskData {
 ImageMaskData fetch_mask_data(ivec2 address) {
     vec4 data = fetch_from_gpu_cache_1_direct(address);
     ImageMaskData mask_data = ImageMaskData(data.xy);
     return mask_data;
 }
 
 void main(void) {
     ClipMaskInstance cmi = fetch_clip_item();
-    ClipArea area = fetch_clip_area(cmi.render_task_address);
     Transform clip_transform = fetch_transform(cmi.clip_transform_id);
     Transform prim_transform = fetch_transform(cmi.prim_transform_id);
     ImageMaskData mask = fetch_mask_data(cmi.clip_data_address);
     RectWithSize local_rect = RectWithSize(cmi.local_pos, mask.local_mask_size);
     ImageResource res = fetch_image_resource_direct(cmi.resource_address);
 
     ClipVertexInfo vi = write_clip_tile_vertex(
         local_rect,
         prim_transform,
         clip_transform,
-        area,
         cmi.sub_rect,
-        cmi.snap_offsets
+        cmi.snap_offsets,
+        cmi.task_origin,
+        cmi.screen_origin,
+        cmi.device_pixel_scale
     );
     vLocalPos = vi.local_pos.xy / vi.local_pos.z;
     vLayer = res.layer;
     vClipMaskImageUv = (vLocalPos - cmi.tile_rect.p0) / 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);
--- a/gfx/wr/webrender/res/cs_clip_rectangle.glsl
+++ b/gfx/wr/webrender/res/cs_clip_rectangle.glsl
@@ -54,31 +54,32 @@ ClipData fetch_clip(ivec2 address) {
     clip.bottom_left = fetch_clip_corner(address, 2.0);
     clip.bottom_right = fetch_clip_corner(address, 3.0);
 
     return clip;
 }
 
 void main(void) {
     ClipMaskInstance cmi = fetch_clip_item();
-    ClipArea area = fetch_clip_area(cmi.render_task_address);
     Transform clip_transform = fetch_transform(cmi.clip_transform_id);
     Transform prim_transform = fetch_transform(cmi.prim_transform_id);
     ClipData clip = fetch_clip(cmi.clip_data_address);
 
     RectWithSize local_rect = clip.rect.rect;
     local_rect.p0 = cmi.local_pos;
 
     ClipVertexInfo vi = write_clip_tile_vertex(
         local_rect,
         prim_transform,
         clip_transform,
-        area,
         cmi.sub_rect,
-        cmi.snap_offsets
+        cmi.snap_offsets,
+        cmi.task_origin,
+        cmi.screen_origin,
+        cmi.device_pixel_scale
     );
 
     vLocalPos = vi.local_pos;
     vClipMode = clip.rect.mode.x;
 
     RectWithEndpoint clip_rect = to_rect_with_endpoint(local_rect);
 
     vec2 r_tl = clip.top_left.outer_inner_radius.xy;
--- a/gfx/wr/webrender/src/batch.rs
+++ b/gfx/wr/webrender/src/batch.rs
@@ -2701,31 +2701,35 @@ impl ClipBatcher {
             primary_clips: ClipBatchList::new(),
             secondary_clips: ClipBatchList::new(),
             gpu_supports_fast_clears,
         }
     }
 
     pub fn add_clip_region(
         &mut self,
-        task_address: RenderTaskAddress,
         clip_data_address: GpuCacheAddress,
         local_pos: LayoutPoint,
         sub_rect: DeviceRect,
+        task_origin: DevicePoint,
+        screen_origin: DevicePoint,
+        device_pixel_scale: f32,
     ) {
         let instance = ClipMaskInstance {
-            render_task_address: task_address,
             clip_transform_id: TransformPaletteId::IDENTITY,
             prim_transform_id: TransformPaletteId::IDENTITY,
             clip_data_address,
             resource_address: GpuCacheAddress::invalid(),
             local_pos,
             tile_rect: LayoutRect::zero(),
             sub_rect,
             snap_offsets: SnapOffsets::empty(),
+            task_origin,
+            screen_origin,
+            device_pixel_scale,
         };
 
         self.primary_clips.rectangles.push(instance);
     }
 
     /// Where appropriate, draw a clip rectangle as a small series of tiles,
     /// instead of one large rectangle.
     fn add_tiled_clip_mask(
@@ -2827,29 +2831,30 @@ impl ClipBatcher {
             &mut self.primary_clips
         } else {
             &mut self.secondary_clips
         }
     }
 
     pub fn add(
         &mut self,
-        task_address: RenderTaskAddress,
         clip_node_range: ClipNodeRange,
         root_spatial_node_index: SpatialNodeIndex,
         resource_cache: &ResourceCache,
         gpu_cache: &GpuCache,
         clip_store: &ClipStore,
         clip_scroll_tree: &ClipScrollTree,
         transforms: &mut TransformPalette,
         clip_data_store: &ClipDataStore,
         actual_rect: DeviceIntRect,
         world_rect: &WorldRect,
         device_pixel_scale: DevicePixelScale,
         snap_offsets: SnapOffsets,
+        task_origin: DevicePoint,
+        screen_origin: DevicePoint,
     ) {
         let mut is_first_clip = true;
 
         for i in 0 .. clip_node_range.count {
             let clip_instance = clip_store.get_instance_from_range(&clip_node_range, i);
             let clip_node = &clip_data_store[clip_instance.handle];
 
             let clip_transform_id = transforms.get_id(
@@ -2860,28 +2865,30 @@ impl ClipBatcher {
 
             let prim_transform_id = transforms.get_id(
                 root_spatial_node_index,
                 ROOT_SPATIAL_NODE_INDEX,
                 clip_scroll_tree,
             );
 
             let instance = ClipMaskInstance {
-                render_task_address: task_address,
                 clip_transform_id,
                 prim_transform_id,
                 clip_data_address: GpuCacheAddress::invalid(),
                 resource_address: GpuCacheAddress::invalid(),
                 local_pos: clip_instance.local_pos,
                 tile_rect: LayoutRect::zero(),
                 sub_rect: DeviceRect::new(
                     DevicePoint::zero(),
                     actual_rect.size.to_f32(),
                 ),
                 snap_offsets,
+                task_origin,
+                screen_origin,
+                device_pixel_scale: device_pixel_scale.0,
             };
 
             let added_clip = match clip_node.item {
                 ClipItem::Image { image, size, .. } => {
                     let request = ImageRequest {
                         key: image,
                         rendering: ImageRendering::Auto,
                         tile: None,
--- a/gfx/wr/webrender/src/gpu_types.rs
+++ b/gfx/wr/webrender/src/gpu_types.rs
@@ -132,25 +132,27 @@ pub struct BorderInstance {
 /// A clipping primitive drawn into the clipping mask.
 /// Could be an image or a rectangle, which defines the
 /// way `address` is treated.
 #[derive(Debug, Copy, Clone)]
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 #[repr(C)]
 pub struct ClipMaskInstance {
-    pub render_task_address: RenderTaskAddress,
     pub clip_transform_id: TransformPaletteId,
     pub prim_transform_id: TransformPaletteId,
     pub clip_data_address: GpuCacheAddress,
     pub resource_address: GpuCacheAddress,
     pub local_pos: LayoutPoint,
     pub tile_rect: LayoutRect,
     pub sub_rect: DeviceRect,
     pub snap_offsets: SnapOffsets,
+    pub task_origin: DevicePoint,
+    pub screen_origin: DevicePoint,
+    pub device_pixel_scale: f32,
 }
 
 /// A border corner dot or dash drawn into the clipping mask.
 #[derive(Debug, Copy, Clone)]
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 #[repr(C)]
 pub struct ClipMaskBorderCornerDotDash {
--- a/gfx/wr/webrender/src/render_task.rs
+++ b/gfx/wr/webrender/src/render_task.rs
@@ -275,17 +275,17 @@ pub struct CacheMaskTask {
 }
 
 #[derive(Debug)]
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 pub struct ClipRegionTask {
     pub clip_data_address: GpuCacheAddress,
     pub local_pos: LayoutPoint,
-    device_pixel_scale: DevicePixelScale,
+    pub device_pixel_scale: DevicePixelScale,
 }
 
 #[derive(Debug)]
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 pub struct TileBlit {
     pub target: CacheItem,
     pub src_offset: DeviceIntPoint,
--- a/gfx/wr/webrender/src/renderer.rs
+++ b/gfx/wr/webrender/src/renderer.rs
@@ -584,28 +584,18 @@ pub(crate) mod desc {
             VertexAttribute {
                 name: "aPosition",
                 count: 2,
                 kind: VertexAttributeKind::F32,
             },
         ],
         instance_attributes: &[
             VertexAttribute {
-                name: "aClipRenderTaskAddress",
-                count: 1,
-                kind: VertexAttributeKind::I32,
-            },
-            VertexAttribute {
-                name: "aClipTransformId",
-                count: 1,
-                kind: VertexAttributeKind::I32,
-            },
-            VertexAttribute {
-                name: "aPrimTransformId",
-                count: 1,
+                name: "aTransformIds",
+                count: 2,
                 kind: VertexAttributeKind::I32,
             },
             VertexAttribute {
                 name: "aClipDataResourceAddress",
                 count: 4,
                 kind: VertexAttributeKind::U16,
             },
             VertexAttribute {
@@ -622,17 +612,27 @@ pub(crate) mod desc {
                 name: "aClipDeviceArea",
                 count: 4,
                 kind: VertexAttributeKind::F32,
             },
             VertexAttribute {
                 name: "aClipSnapOffsets",
                 count: 4,
                 kind: VertexAttributeKind::F32,
-            }
+            },
+            VertexAttribute {
+                name: "aClipOrigins",
+                count: 4,
+                kind: VertexAttributeKind::F32,
+            },
+            VertexAttribute {
+                name: "aDevicePixelScale",
+                count: 1,
+                kind: VertexAttributeKind::F32,
+            },
         ],
     };
 
     pub const GPU_CACHE_UPDATE: VertexDescriptor = VertexDescriptor {
         vertex_attributes: &[
             VertexAttribute {
                 name: "aPosition",
                 count: 2,
--- a/gfx/wr/webrender/src/tiling.rs
+++ b/gfx/wr/webrender/src/tiling.rs
@@ -630,16 +630,17 @@ impl RenderTarget for AlphaRenderTarget 
         ctx: &RenderTargetContext,
         gpu_cache: &mut GpuCache,
         render_tasks: &RenderTaskTree,
         clip_store: &ClipStore,
         transforms: &mut TransformPalette,
         _: &mut Vec<DeferredResolve>,
     ) {
         let task = &render_tasks[task_id];
+        let (target_rect, _) = task.get_target_rect();
 
         match task.clear_mode {
             ClearMode::Zero => {
                 self.zero_clears.push(task_id);
             }
             ClearMode::One => {
                 self.one_clears.push(task_id);
             }
@@ -671,44 +672,45 @@ impl RenderTarget for AlphaRenderTarget 
                 info.add_instances(
                     &mut self.horizontal_blurs,
                     BlurDirection::Horizontal,
                     render_tasks.get_task_address(task_id),
                     render_tasks.get_task_address(task.children[0]),
                 );
             }
             RenderTaskKind::CacheMask(ref task_info) => {
-                let task_address = render_tasks.get_task_address(task_id);
                 self.clip_batcher.add(
-                    task_address,
                     task_info.clip_node_range,
                     task_info.root_spatial_node_index,
                     ctx.resource_cache,
                     gpu_cache,
                     clip_store,
                     ctx.clip_scroll_tree,
                     transforms,
                     &ctx.data_stores.clip,
                     task_info.actual_rect,
                     &ctx.screen_world_rect,
                     task_info.device_pixel_scale,
                     task_info.snap_offsets,
+                    target_rect.origin.to_f32(),
+                    task_info.actual_rect.origin.to_f32(),
                 );
             }
             RenderTaskKind::ClipRegion(ref region_task) => {
-                let task_address = render_tasks.get_task_address(task_id);
                 let device_rect = DeviceRect::new(
                     DevicePoint::zero(),
-                    task.get_dynamic_size().to_f32(),
+                    target_rect.size.to_f32(),
                 );
                 self.clip_batcher.add_clip_region(
-                    task_address,
                     region_task.clip_data_address,
                     region_task.local_pos,
                     device_rect,
+                    target_rect.origin.to_f32(),
+                    DevicePoint::zero(),
+                    region_task.device_pixel_scale.0,
                 );
             }
             RenderTaskKind::Scaling(ref info) => {
                 info.add_instances(
                     &mut self.scalings,
                     render_tasks.get_task_address(task_id),
                     render_tasks.get_task_address(task.children[0]),
                 );