From 199c72de14eae1f65db08d9e1074ed82177d8e12 Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Fri, 6 Apr 2018 16:02:32 -0400 Subject: [PATCH 1/2] Avoid drawing empty border edges --- webrender/src/border.rs | 228 +++++++++++++++++++--------------------- 1 file changed, 107 insertions(+), 121 deletions(-) diff --git a/webrender/src/border.rs b/webrender/src/border.rs index 1e01e9d20e..badf524558 100644 --- a/webrender/src/border.rs +++ b/webrender/src/border.rs @@ -103,134 +103,116 @@ pub enum BorderEdgeKind { Clip, } -trait NormalBorderHelpers { - fn get_corner( - &self, - edge0: &BorderSide, - width0: f32, - edge1: &BorderSide, - width1: f32, - radius: &LayerSize, - corner: BorderCorner, - border_rect: &LayerRect, - ) -> BorderCornerKind; +fn get_corner( + edge0: &BorderSide, + width0: f32, + edge1: &BorderSide, + width1: f32, + radius: &LayerSize, + corner: BorderCorner, + border_rect: &LayerRect, +) -> BorderCornerKind { + // If both widths are zero, a corner isn't formed. + if width0 == 0.0 && width1 == 0.0 { + return BorderCornerKind::None; + } - fn get_edge(&self, edge: &BorderSide, width: f32) -> (BorderEdgeKind, f32); -} + // If both edges are transparent, no corner is formed. + if edge0.color.a == 0.0 && edge1.color.a == 0.0 { + return BorderCornerKind::None; + } -impl NormalBorderHelpers for NormalBorder { - fn get_corner( - &self, - edge0: &BorderSide, - width0: f32, - edge1: &BorderSide, - width1: f32, - radius: &LayerSize, - corner: BorderCorner, - border_rect: &LayerRect, - ) -> BorderCornerKind { - // If both widths are zero, a corner isn't formed. - if width0 == 0.0 && width1 == 0.0 { - return BorderCornerKind::None; + match (edge0.style, edge1.style) { + // If both edges are none or hidden, no corner is needed. + (BorderStyle::None, BorderStyle::None) | + (BorderStyle::None, BorderStyle::Hidden) | + (BorderStyle::Hidden, BorderStyle::None) | + (BorderStyle::Hidden, BorderStyle::Hidden) => { + BorderCornerKind::None } - // If both edges are transparent, no corner is formed. - if edge0.color.a == 0.0 && edge1.color.a == 0.0 { - return BorderCornerKind::None; + // If one of the edges is none or hidden, we just draw one style. + (BorderStyle::None, _) | + (_, BorderStyle::None) | + (BorderStyle::Hidden, _) | + (_, BorderStyle::Hidden) => { + BorderCornerKind::Clip(BorderCornerInstance::Single) } - match (edge0.style, edge1.style) { - // If both edges are none or hidden, no corner is needed. - (BorderStyle::None, BorderStyle::None) | - (BorderStyle::None, BorderStyle::Hidden) | - (BorderStyle::Hidden, BorderStyle::None) | - (BorderStyle::Hidden, BorderStyle::Hidden) => { - BorderCornerKind::None - } - - // If one of the edges is none or hidden, we just draw one style. - (BorderStyle::None, _) | - (_, BorderStyle::None) | - (BorderStyle::Hidden, _) | - (_, BorderStyle::Hidden) => { - BorderCornerKind::Clip(BorderCornerInstance::Single) - } - - // If both borders are solid, we can draw them with a simple rectangle if - // both the colors match and there is no radius. - (BorderStyle::Solid, BorderStyle::Solid) => { - if edge0.color == edge1.color && radius.width == 0.0 && radius.height == 0.0 { - BorderCornerKind::Solid - } else { - BorderCornerKind::Clip(BorderCornerInstance::Single) - } - } - - // Inset / outset borders just modify the color of edges, so can be - // drawn with the normal border corner shader. - (BorderStyle::Outset, BorderStyle::Outset) | - (BorderStyle::Inset, BorderStyle::Inset) | - (BorderStyle::Double, BorderStyle::Double) | - (BorderStyle::Groove, BorderStyle::Groove) | - (BorderStyle::Ridge, BorderStyle::Ridge) => { + // If both borders are solid, we can draw them with a simple rectangle if + // both the colors match and there is no radius. + (BorderStyle::Solid, BorderStyle::Solid) => { + if edge0.color == edge1.color && radius.width == 0.0 && radius.height == 0.0 { + BorderCornerKind::Solid + } else { BorderCornerKind::Clip(BorderCornerInstance::Single) } - - // Dashed and dotted border corners get drawn into a clip mask. - (BorderStyle::Dashed, BorderStyle::Dashed) => BorderCornerKind::new_mask( - BorderCornerClipKind::Dash, - width0, - width1, - corner, - *radius, - *border_rect, - ), - (BorderStyle::Dotted, BorderStyle::Dotted) => BorderCornerKind::new_mask( - BorderCornerClipKind::Dot, - width0, - width1, - corner, - *radius, - *border_rect, - ), - - // Draw border transitions with dots and/or dashes as - // solid segments. The old border path didn't support - // this anyway, so we might as well start using the new - // border path here, since the dashing in the edges is - // much higher quality anyway. - (BorderStyle::Dotted, _) | - (_, BorderStyle::Dotted) | - (BorderStyle::Dashed, _) | - (_, BorderStyle::Dashed) => BorderCornerKind::Clip(BorderCornerInstance::Single), - - // Everything else can be handled by drawing the corner twice, - // where the shader outputs zero alpha for the side it's not - // drawing. This is somewhat inefficient in terms of pixels - // written, but it's a fairly rare case, and we can optimize - // this case later. - _ => BorderCornerKind::Clip(BorderCornerInstance::Double), } - } - fn get_edge(&self, edge: &BorderSide, width: f32) -> (BorderEdgeKind, f32) { - if width == 0.0 { - return (BorderEdgeKind::None, 0.0); + // Inset / outset borders just modify the color of edges, so can be + // drawn with the normal border corner shader. + (BorderStyle::Outset, BorderStyle::Outset) | + (BorderStyle::Inset, BorderStyle::Inset) | + (BorderStyle::Double, BorderStyle::Double) | + (BorderStyle::Groove, BorderStyle::Groove) | + (BorderStyle::Ridge, BorderStyle::Ridge) => { + BorderCornerKind::Clip(BorderCornerInstance::Single) } - match edge.style { - BorderStyle::None | BorderStyle::Hidden => (BorderEdgeKind::None, 0.0), + // Dashed and dotted border corners get drawn into a clip mask. + (BorderStyle::Dashed, BorderStyle::Dashed) => BorderCornerKind::new_mask( + BorderCornerClipKind::Dash, + width0, + width1, + corner, + *radius, + *border_rect, + ), + (BorderStyle::Dotted, BorderStyle::Dotted) => BorderCornerKind::new_mask( + BorderCornerClipKind::Dot, + width0, + width1, + corner, + *radius, + *border_rect, + ), + + // Draw border transitions with dots and/or dashes as + // solid segments. The old border path didn't support + // this anyway, so we might as well start using the new + // border path here, since the dashing in the edges is + // much higher quality anyway. + (BorderStyle::Dotted, _) | + (_, BorderStyle::Dotted) | + (BorderStyle::Dashed, _) | + (_, BorderStyle::Dashed) => BorderCornerKind::Clip(BorderCornerInstance::Single), + + // Everything else can be handled by drawing the corner twice, + // where the shader outputs zero alpha for the side it's not + // drawing. This is somewhat inefficient in terms of pixels + // written, but it's a fairly rare case, and we can optimize + // this case later. + _ => BorderCornerKind::Clip(BorderCornerInstance::Double), + } +} + +fn get_edge(edge: &BorderSide, width: f32, height: f32) -> (BorderEdgeKind, f32) { + if width == 0.0 || height <= 0.0 { + return (BorderEdgeKind::None, 0.0); + } - BorderStyle::Solid | BorderStyle::Inset | BorderStyle::Outset => { - (BorderEdgeKind::Solid, width) - } + match edge.style { + BorderStyle::None | BorderStyle::Hidden => (BorderEdgeKind::None, 0.0), - BorderStyle::Double | - BorderStyle::Groove | - BorderStyle::Ridge | - BorderStyle::Dashed | - BorderStyle::Dotted => (BorderEdgeKind::Clip, width), + BorderStyle::Solid | BorderStyle::Inset | BorderStyle::Outset => { + (BorderEdgeKind::Solid, width) } + + BorderStyle::Double | + BorderStyle::Groove | + BorderStyle::Ridge | + BorderStyle::Dashed | + BorderStyle::Dotted => (BorderEdgeKind::Clip, width), } } @@ -431,7 +413,7 @@ impl<'a> DisplayListFlattener<'a> { } let corners = [ - border.get_corner( + get_corner( left, widths.left, top, @@ -440,7 +422,7 @@ impl<'a> DisplayListFlattener<'a> { BorderCorner::TopLeft, &info.rect, ), - border.get_corner( + get_corner( right, widths.right, top, @@ -449,7 +431,7 @@ impl<'a> DisplayListFlattener<'a> { BorderCorner::TopRight, &info.rect, ), - border.get_corner( + get_corner( right, widths.right, bottom, @@ -458,7 +440,7 @@ impl<'a> DisplayListFlattener<'a> { BorderCorner::BottomRight, &info.rect, ), - border.get_corner( + get_corner( left, widths.left, bottom, @@ -469,10 +451,14 @@ impl<'a> DisplayListFlattener<'a> { ), ]; - let (left_edge, left_len) = border.get_edge(left, widths.left); - let (top_edge, top_len) = border.get_edge(top, widths.top); - let (right_edge, right_len) = border.get_edge(right, widths.right); - let (bottom_edge, bottom_len) = border.get_edge(bottom, widths.bottom); + let (left_edge, left_len) = get_edge(left, widths.left, + info.rect.size.height - radius.top_left.height - radius.bottom_left.height); + let (top_edge, top_len) = get_edge(top, widths.top, + info.rect.size.width - radius.top_left.width - radius.top_right.width); + let (right_edge, right_len) = get_edge(right, widths.right, + info.rect.size.height - radius.top_right.height - radius.bottom_right.height); + let (bottom_edge, bottom_len) = get_edge(bottom, widths.bottom, + info.rect.size.width - radius.bottom_right.width - radius.bottom_left.width); let edges = [left_edge, top_edge, right_edge, bottom_edge]; From 9e0e9263be00dbb0a2386b64e42d4eb5e0c7985d Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Fri, 6 Apr 2018 16:12:34 -0400 Subject: [PATCH 2/2] Don't create empty border batches --- webrender/src/batch.rs | 50 +++++++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/webrender/src/batch.rs b/webrender/src/batch.rs index 6a9ff9cdad..eadb75f288 100644 --- a/webrender/src/batch.rs +++ b/webrender/src/batch.rs @@ -975,23 +975,17 @@ impl AlphaBatchBuilder { let border_cpu = &ctx.prim_store.cpu_borders[prim_metadata.cpu_prim_index.0]; // TODO(gw): Select correct blend mode for edges and corners!! - let corner_kind = BatchKind::Transformable( - transform_kind, - TransformBatchKind::BorderCorner, - ); - let corner_key = BatchKey::new(corner_kind, non_segmented_blend_mode, no_textures); - let edge_kind = BatchKind::Transformable( - transform_kind, - TransformBatchKind::BorderEdge, - ); - let edge_key = BatchKey::new(edge_kind, non_segmented_blend_mode, no_textures); - - // Work around borrow ck on borrowing batch_list twice. - { - let batch = - self.batch_list.get_suitable_batch(corner_key, &task_relative_bounding_rect); - for (i, instance_kind) in border_cpu.corner_instances.iter().enumerate() - { + + if border_cpu.corner_instances.iter().any(|&kind| kind != BorderCornerInstance::None) { + let corner_kind = BatchKind::Transformable( + transform_kind, + TransformBatchKind::BorderCorner, + ); + let corner_key = BatchKey::new(corner_kind, non_segmented_blend_mode, no_textures); + let batch = self.batch_list + .get_suitable_batch(corner_key, &task_relative_bounding_rect); + + for (i, instance_kind) in border_cpu.corner_instances.iter().enumerate() { let sub_index = i as i32; match *instance_kind { BorderCornerInstance::None => {} @@ -1018,12 +1012,22 @@ impl AlphaBatchBuilder { } } - let batch = self.batch_list.get_suitable_batch(edge_key, &task_relative_bounding_rect); - for (border_segment, instance_kind) in border_cpu.edges.iter().enumerate() { - match *instance_kind { - BorderEdgeKind::None => {}, - _ => { - batch.push(base_instance.build(border_segment as i32, 0, 0)); + if border_cpu.edges.iter().any(|&kind| kind != BorderEdgeKind::None) { + let edge_kind = BatchKind::Transformable( + transform_kind, + TransformBatchKind::BorderEdge, + ); + let edge_key = BatchKey::new(edge_kind, non_segmented_blend_mode, no_textures); + let batch = self.batch_list + .get_suitable_batch(edge_key, &task_relative_bounding_rect); + + for (border_segment, instance_kind) in border_cpu.edges.iter().enumerate() { + match *instance_kind { + BorderEdgeKind::None => {}, + BorderEdgeKind::Solid | + BorderEdgeKind::Clip => { + batch.push(base_instance.build(border_segment as i32, 0, 0)); + } } } }