Auto merge of #10021 - pcwalton:skip-layout-traversals, r=mbrubeck

layout: Skip layout traversals that obviously won't do anything.

This reduces CPU usage when mousing over simple pages (example.com). More complex pages (Wikipedia) still reflow a lot due to other bugs.

Additionally, this change causes Servo to stop painting the results of hit test queries. This is also a win for CPU usage.

This significantly improves #9999, though there's more that can be done. I'll leave it open in case @paulrouget thinks this PR isn't enough.

r? @mbrubeck

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="35" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/10021)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2016-03-22 03:37:49 +05:30
commit 9813d11f86
4 changed files with 71 additions and 56 deletions

View file

@ -167,7 +167,8 @@ pub fn compute_damage(old: Option<&Arc<ComputedValues>>, new: &ComputedValues) -
[ REPAINT ], [ [ REPAINT ], [
get_color.color, get_background.background_color, get_color.color, get_background.background_color,
get_border.border_top_color, get_border.border_right_color, get_border.border_top_color, get_border.border_right_color,
get_border.border_bottom_color, get_border.border_left_color get_border.border_bottom_color, get_border.border_left_color,
get_effects.transform, get_box.z_index
]); ]);
add_if_not_equal!(old, new, damage, add_if_not_equal!(old, new, damage,
@ -252,7 +253,6 @@ impl<'a> LayoutDamageComputation for &'a mut Flow {
has_counter_affecting_children = has_counter_affecting_children || has_counter_affecting_children = has_counter_affecting_children ||
flow::base(kid).flags.intersects(AFFECTS_COUNTERS | flow::base(kid).flags.intersects(AFFECTS_COUNTERS |
HAS_COUNTER_AFFECTING_CHILDREN); HAS_COUNTER_AFFECTING_CHILDREN);
} }
} }

View file

@ -30,7 +30,8 @@ use gfx::font_context;
use gfx::paint_thread::LayoutToPaintMsg; use gfx::paint_thread::LayoutToPaintMsg;
use gfx_traits::{color, Epoch, LayerId, ScrollPolicy}; use gfx_traits::{color, Epoch, LayerId, ScrollPolicy};
use heapsize::HeapSizeOf; use heapsize::HeapSizeOf;
use incremental::{LayoutDamageComputation, REFLOW, REFLOW_ENTIRE_DOCUMENT, REPAINT}; use incremental::{LayoutDamageComputation, REFLOW, REFLOW_ENTIRE_DOCUMENT, REFLOW_OUT_OF_FLOW};
use incremental::{REPAINT};
use ipc_channel::ipc::{self, IpcReceiver, IpcSender}; use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
use ipc_channel::router::ROUTER; use ipc_channel::router::ROUTER;
use layout_debug; use layout_debug;
@ -869,6 +870,8 @@ impl LayoutThread {
flow::mut_base(flow_ref::deref_mut(layout_root)).clip = flow::mut_base(flow_ref::deref_mut(layout_root)).clip =
ClippingRegion::from_rect(&data.page_clip_rect); ClippingRegion::from_rect(&data.page_clip_rect);
if flow::base(&**layout_root).restyle_damage.contains(REPAINT) ||
rw_data.display_list.is_none() {
let mut root_stacking_context = let mut root_stacking_context =
StackingContext::new(StackingContextId::new(0), StackingContext::new(StackingContextId::new(0),
StackingContextType::Real, StackingContextType::Real,
@ -888,7 +891,6 @@ impl LayoutThread {
&mut root_stacking_context, &mut root_stacking_context,
shared_layout_context); shared_layout_context);
if data.goal == ReflowGoal::ForDisplay {
debug!("Done building display list."); debug!("Done building display list.");
let root_background_color = get_root_flow_background_color( let root_background_color = get_root_flow_background_color(
@ -905,13 +907,20 @@ impl LayoutThread {
let origin = Rect::new(Point2D::new(Au(0), Au(0)), root_size); let origin = Rect::new(Point2D::new(Au(0), Au(0)), root_size);
root_stacking_context.bounds = origin; root_stacking_context.bounds = origin;
root_stacking_context.overflow = origin; root_stacking_context.overflow = origin;
root_stacking_context.layer_info = Some(LayerInfo::new(layout_root.layer_id(), root_stacking_context.layer_info =
Some(LayerInfo::new(layout_root.layer_id(),
ScrollPolicy::Scrollable, ScrollPolicy::Scrollable,
None, None,
root_background_color)); root_background_color));
let display_list = DisplayList::new(root_stacking_context, rw_data.display_list =
&mut Some(display_list_entries)); Some(Arc::new(DisplayList::new(root_stacking_context,
&mut Some(display_list_entries))))
}
if data.goal == ReflowGoal::ForDisplay {
let display_list = (*rw_data.display_list.as_ref().unwrap()).clone();
if opts::get().dump_display_list { if opts::get().dump_display_list {
display_list.print(); display_list.print();
} }
@ -919,9 +928,6 @@ impl LayoutThread {
println!("{}", serde_json::to_string_pretty(&display_list).unwrap()); println!("{}", serde_json::to_string_pretty(&display_list).unwrap());
} }
let display_list = Arc::new(display_list);
rw_data.display_list = Some(display_list.clone());
debug!("Layout done!"); debug!("Layout done!");
self.epoch.next(); self.epoch.next();
@ -942,7 +948,10 @@ impl LayoutThread {
epoch, epoch,
Some(root_scroll_layer_id), Some(root_scroll_layer_id),
&mut auxiliary_lists_builder); &mut auxiliary_lists_builder);
let root_background_color = webrender_traits::ColorF::new(root_background_color.r, let root_background_color = get_root_flow_background_color(
flow_ref::deref_mut(layout_root));
let root_background_color =
webrender_traits::ColorF::new(root_background_color.r,
root_background_color.g, root_background_color.g,
root_background_color.b, root_background_color.b,
root_background_color.a); root_background_color.a);
@ -1323,6 +1332,7 @@ impl LayoutThread {
// Perform the primary layout passes over the flow tree to compute the locations of all // Perform the primary layout passes over the flow tree to compute the locations of all
// the boxes. // the boxes.
if flow::base(&*root_flow).restyle_damage.intersects(REFLOW | REFLOW_OUT_OF_FLOW) {
profile(time::ProfilerCategory::LayoutMain, profile(time::ProfilerCategory::LayoutMain,
self.profiler_metadata(), self.profiler_metadata(),
self.time_profiler_chan.clone(), self.time_profiler_chan.clone(),
@ -1343,6 +1353,7 @@ impl LayoutThread {
} }
} }
}); });
}
profile(time::ProfilerCategory::LayoutStoreOverflow, profile(time::ProfilerCategory::LayoutStoreOverflow,
self.profiler_metadata(), self.profiler_metadata(),

View file

@ -234,6 +234,6 @@ impl<'a> BuildDisplayList<'a> {
#[inline] #[inline]
fn should_process(&self) -> bool { fn should_process(&self) -> bool {
self.state.layout_context.shared_context().goal == ReflowGoal::ForDisplay true
} }
} }

View file

@ -1021,7 +1021,11 @@ impl Window {
debug!("script: layout joined"); debug!("script: layout joined");
// Pending reflows require display, so only reset the pending reflow count if this reflow
// was to be displayed.
if goal == ReflowGoal::ForDisplay {
self.pending_reflow_count.set(0); self.pending_reflow_count.set(0);
}
if let Some(marker) = marker { if let Some(marker) = marker {
self.emit_timeline_marker(marker.end()); self.emit_timeline_marker(marker.end());
@ -1104,7 +1108,7 @@ impl Window {
pub fn hit_test_query(&self, hit_test_request: Point2D<f32>, update_cursor: bool) pub fn hit_test_query(&self, hit_test_request: Point2D<f32>, update_cursor: bool)
-> Option<UntrustedNodeAddress> { -> Option<UntrustedNodeAddress> {
self.reflow(ReflowGoal::ForDisplay, self.reflow(ReflowGoal::ForScriptQuery,
ReflowQueryType::HitTestQuery(hit_test_request, update_cursor), ReflowQueryType::HitTestQuery(hit_test_request, update_cursor),
ReflowReason::Query); ReflowReason::Query);
self.layout_rpc.hit_test().node_address self.layout_rpc.hit_test().node_address