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,26 +870,27 @@ 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);
let mut root_stacking_context = if flow::base(&**layout_root).restyle_damage.contains(REPAINT) ||
StackingContext::new(StackingContextId::new(0), rw_data.display_list.is_none() {
StackingContextType::Real, let mut root_stacking_context =
&Rect::zero(), StackingContext::new(StackingContextId::new(0),
&Rect::zero(), StackingContextType::Real,
0, &Rect::zero(),
filter::T::new(Vec::new()), &Rect::zero(),
mix_blend_mode::T::normal, 0,
Matrix4::identity(), filter::T::new(Vec::new()),
Matrix4::identity(), mix_blend_mode::T::normal,
true, Matrix4::identity(),
false, Matrix4::identity(),
None); true,
false,
None);
let display_list_entries = let display_list_entries =
sequential::build_display_list_for_subtree(layout_root, sequential::build_display_list_for_subtree(layout_root,
&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 =
ScrollPolicy::Scrollable, Some(LayerInfo::new(layout_root.layer_id(),
None, ScrollPolicy::Scrollable,
root_background_color)); None,
root_background_color));
rw_data.display_list =
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();
let display_list = DisplayList::new(root_stacking_context,
&mut Some(display_list_entries));
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,10 +948,13 @@ 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(
root_background_color.g, flow_ref::deref_mut(layout_root));
root_background_color.b, let root_background_color =
root_background_color.a); webrender_traits::ColorF::new(root_background_color.r,
root_background_color.g,
root_background_color.b,
root_background_color.a);
let viewport_size = Size2D::new(self.viewport_size.width.to_f32_px(), let viewport_size = Size2D::new(self.viewport_size.width.to_f32_px(),
self.viewport_size.height.to_f32_px()); self.viewport_size.height.to_f32_px());
@ -1323,26 +1332,28 @@ 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.
profile(time::ProfilerCategory::LayoutMain, if flow::base(&*root_flow).restyle_damage.intersects(REFLOW | REFLOW_OUT_OF_FLOW) {
self.profiler_metadata(), profile(time::ProfilerCategory::LayoutMain,
self.time_profiler_chan.clone(), self.profiler_metadata(),
|| { self.time_profiler_chan.clone(),
let profiler_metadata = self.profiler_metadata(); || {
match self.parallel_traversal { let profiler_metadata = self.profiler_metadata();
None => { match self.parallel_traversal {
// Sequential mode. None => {
LayoutThread::solve_constraints(&mut root_flow, &layout_context) // Sequential mode.
LayoutThread::solve_constraints(&mut root_flow, &layout_context)
}
Some(ref mut parallel) => {
// Parallel mode.
LayoutThread::solve_constraints_parallel(parallel,
&mut root_flow,
profiler_metadata,
self.time_profiler_chan.clone(),
&*layout_context);
}
} }
Some(ref mut parallel) => { });
// Parallel mode. }
LayoutThread::solve_constraints_parallel(parallel,
&mut root_flow,
profiler_metadata,
self.time_profiler_chan.clone(),
&*layout_context);
}
}
});
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");
self.pending_reflow_count.set(0); // 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);
}
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