mirror of
https://github.com/servo/servo.git
synced 2025-06-25 09:34:32 +01:00
commit
667f887f49
7 changed files with 59 additions and 8 deletions
|
@ -79,6 +79,10 @@ pub struct SharedLayoutContext {
|
||||||
|
|
||||||
/// The dirty rectangle, used during display list building.
|
/// The dirty rectangle, used during display list building.
|
||||||
pub dirty: Rect<Au>,
|
pub dirty: Rect<Au>,
|
||||||
|
|
||||||
|
/// Starts at zero, and increased by one every time a layout completes.
|
||||||
|
/// This can be used to easily check for invalid stale data.
|
||||||
|
pub generation: uint,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct LayoutContext<'a> {
|
pub struct LayoutContext<'a> {
|
||||||
|
|
|
@ -17,6 +17,7 @@ use servo_util::cache::{Cache, LRUCache, SimpleHashCache};
|
||||||
use servo_util::namespace::Null;
|
use servo_util::namespace::Null;
|
||||||
use servo_util::smallvec::{SmallVec, SmallVec16};
|
use servo_util::smallvec::{SmallVec, SmallVec16};
|
||||||
use servo_util::str::DOMString;
|
use servo_util::str::DOMString;
|
||||||
|
use servo_util::tid::tid;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::hash::{Hash, sip};
|
use std::hash::{Hash, sip};
|
||||||
use std::slice::Items;
|
use std::slice::Items;
|
||||||
|
|
|
@ -88,6 +88,10 @@ pub struct LayoutTaskData {
|
||||||
|
|
||||||
/// The dirty rect. Used during display list construction.
|
/// The dirty rect. Used during display list construction.
|
||||||
pub dirty: Rect<Au>,
|
pub dirty: Rect<Au>,
|
||||||
|
|
||||||
|
/// Starts at zero, and increased by one every time a layout completes.
|
||||||
|
/// This can be used to easily check for invalid stale data.
|
||||||
|
pub generation: uint,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Information needed by the layout task.
|
/// Information needed by the layout task.
|
||||||
|
@ -413,6 +417,7 @@ impl LayoutTask {
|
||||||
stylist: box Stylist::new(),
|
stylist: box Stylist::new(),
|
||||||
parallel_traversal: parallel_traversal,
|
parallel_traversal: parallel_traversal,
|
||||||
dirty: Rect::zero(),
|
dirty: Rect::zero(),
|
||||||
|
generation: 0,
|
||||||
})),
|
})),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -443,6 +448,7 @@ impl LayoutTask {
|
||||||
reflow_root: OpaqueNodeMethods::from_layout_node(reflow_root),
|
reflow_root: OpaqueNodeMethods::from_layout_node(reflow_root),
|
||||||
opts: self.opts.clone(),
|
opts: self.opts.clone(),
|
||||||
dirty: Rect::zero(),
|
dirty: Rect::zero(),
|
||||||
|
generation: rw_data.generation,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -925,6 +931,8 @@ impl LayoutTask {
|
||||||
layout_debug::end_trace();
|
layout_debug::end_trace();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rw_data.generation += 1;
|
||||||
|
|
||||||
// Tell script that we're done.
|
// Tell script that we're done.
|
||||||
//
|
//
|
||||||
// FIXME(pcwalton): This should probably be *one* channel, but we can't fix this without
|
// FIXME(pcwalton): This should probably be *one* channel, but we can't fix this without
|
||||||
|
|
|
@ -22,6 +22,7 @@ use wrapper::{ThreadSafeLayoutNode, UnsafeLayoutNode};
|
||||||
|
|
||||||
use gfx::display_list::OpaqueNode;
|
use gfx::display_list::OpaqueNode;
|
||||||
use servo_util::bloom::BloomFilter;
|
use servo_util::bloom::BloomFilter;
|
||||||
|
use servo_util::tid::tid;
|
||||||
use servo_util::time::{TimeProfilerChan, profile};
|
use servo_util::time::{TimeProfilerChan, profile};
|
||||||
use servo_util::time;
|
use servo_util::time;
|
||||||
use servo_util::workqueue::{WorkQueue, WorkUnit, WorkerProxy};
|
use servo_util::workqueue::{WorkQueue, WorkUnit, WorkerProxy};
|
||||||
|
@ -216,6 +217,10 @@ impl<'a> ParallelPreorderFlowTraversal for AssignISizesTraversal<'a> {
|
||||||
|
|
||||||
impl<'a> ParallelPostorderFlowTraversal for AssignBSizesAndStoreOverflowTraversal<'a> {}
|
impl<'a> ParallelPostorderFlowTraversal for AssignBSizesAndStoreOverflowTraversal<'a> {}
|
||||||
|
|
||||||
|
/// Every time we do another layout, the old bloom filters are invalid. This is
|
||||||
|
/// detected by ticking a generation number every layout.
|
||||||
|
type Generation = uint;
|
||||||
|
|
||||||
/// A pair of the bloom filter used for css selector matching, and the node to
|
/// A pair of the bloom filter used for css selector matching, and the node to
|
||||||
/// which it applies. This is used to efficiently do `Descendant` selector
|
/// which it applies. This is used to efficiently do `Descendant` selector
|
||||||
/// matches. Thanks to the bloom filter, we can avoid walking up the tree
|
/// matches. Thanks to the bloom filter, we can avoid walking up the tree
|
||||||
|
@ -236,7 +241,7 @@ impl<'a> ParallelPostorderFlowTraversal for AssignBSizesAndStoreOverflowTraversa
|
||||||
/// Since a work-stealing queue is used for styling, sometimes, the bloom filter
|
/// Since a work-stealing queue is used for styling, sometimes, the bloom filter
|
||||||
/// will no longer be the for the parent of the node we're currently on. When
|
/// will no longer be the for the parent of the node we're currently on. When
|
||||||
/// this happens, the task local bloom filter will be thrown away and rebuilt.
|
/// this happens, the task local bloom filter will be thrown away and rebuilt.
|
||||||
local_data_key!(style_bloom: (BloomFilter, UnsafeLayoutNode))
|
local_data_key!(style_bloom: (BloomFilter, UnsafeLayoutNode, Generation))
|
||||||
|
|
||||||
/// Returns the task local bloom filter.
|
/// Returns the task local bloom filter.
|
||||||
///
|
///
|
||||||
|
@ -251,6 +256,9 @@ fn take_task_local_bloom_filter(
|
||||||
|p: Option<LayoutNode>| -> BloomFilter {
|
|p: Option<LayoutNode>| -> BloomFilter {
|
||||||
let mut bf = BloomFilter::new(style::RECOMMENDED_SELECTOR_BLOOM_FILTER_SIZE);
|
let mut bf = BloomFilter::new(style::RECOMMENDED_SELECTOR_BLOOM_FILTER_SIZE);
|
||||||
p.map(|p| insert_ancestors_into_bloom_filter(&mut bf, p, layout_context));
|
p.map(|p| insert_ancestors_into_bloom_filter(&mut bf, p, layout_context));
|
||||||
|
if p.is_none() {
|
||||||
|
debug!("[{}] No parent, but new bloom filter!", tid());
|
||||||
|
}
|
||||||
bf
|
bf
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -260,9 +268,11 @@ fn take_task_local_bloom_filter(
|
||||||
// No bloom filter for this thread yet.
|
// No bloom filter for this thread yet.
|
||||||
(Some(p), None) => new_bloom(Some(p)),
|
(Some(p), None) => new_bloom(Some(p)),
|
||||||
// Found cached bloom filter.
|
// Found cached bloom filter.
|
||||||
(Some(p), Some((bf, old_node))) => {
|
(Some(p), Some((bf, old_node, old_generation))) => {
|
||||||
// Hey, the cached parent is our parent! We can reuse the bloom filter.
|
// Hey, the cached parent is our parent! We can reuse the bloom filter.
|
||||||
if old_node == layout_node_to_unsafe_layout_node(&p) {
|
if old_node == layout_node_to_unsafe_layout_node(&p) &&
|
||||||
|
old_generation == layout_context.shared.generation {
|
||||||
|
debug!("[{}] Parent matches (={}). Reusing bloom filter.", tid(), old_node.val0());
|
||||||
bf
|
bf
|
||||||
// Oh no. the cached parent is stale. I guess we need a new one...
|
// Oh no. the cached parent is stale. I guess we need a new one...
|
||||||
} else {
|
} else {
|
||||||
|
@ -272,8 +282,8 @@ fn take_task_local_bloom_filter(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn put_task_local_bloom_filter(bf: BloomFilter, unsafe_node: &UnsafeLayoutNode) {
|
fn put_task_local_bloom_filter(bf: BloomFilter, unsafe_node: &UnsafeLayoutNode, layout_context: &LayoutContext) {
|
||||||
match style_bloom.replace(Some((bf, *unsafe_node))) {
|
match style_bloom.replace(Some((bf, *unsafe_node, layout_context.shared.generation))) {
|
||||||
None => {},
|
None => {},
|
||||||
Some(_) => fail!("Putting into a never-taken task-local bloom filter"),
|
Some(_) => fail!("Putting into a never-taken task-local bloom filter"),
|
||||||
}
|
}
|
||||||
|
@ -282,13 +292,18 @@ fn put_task_local_bloom_filter(bf: BloomFilter, unsafe_node: &UnsafeLayoutNode)
|
||||||
/// "Ancestors" in this context is inclusive of ourselves.
|
/// "Ancestors" in this context is inclusive of ourselves.
|
||||||
fn insert_ancestors_into_bloom_filter(
|
fn insert_ancestors_into_bloom_filter(
|
||||||
bf: &mut BloomFilter, mut n: LayoutNode, layout_context: &LayoutContext) {
|
bf: &mut BloomFilter, mut n: LayoutNode, layout_context: &LayoutContext) {
|
||||||
|
debug!("[{}] Inserting ancestors.", tid());
|
||||||
|
let mut ancestors = 0u;
|
||||||
loop {
|
loop {
|
||||||
|
ancestors += 1;
|
||||||
|
|
||||||
n.insert_into_bloom_filter(bf);
|
n.insert_into_bloom_filter(bf);
|
||||||
n = match parent_node(&n, layout_context) {
|
n = match parent_node(&n, layout_context) {
|
||||||
None => return,
|
None => break,
|
||||||
Some(p) => p,
|
Some(p) => p,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
debug!("[{}] Inserted {} ancestors.", tid(), ancestors);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parent_node<'ln>(node: &LayoutNode<'ln>, layout_context: &LayoutContext) -> Option<LayoutNode<'ln>> {
|
fn parent_node<'ln>(node: &LayoutNode<'ln>, layout_context: &LayoutContext) -> Option<LayoutNode<'ln>> {
|
||||||
|
@ -378,6 +393,7 @@ fn recalc_style_for_node(mut unsafe_layout_node: UnsafeLayoutNode,
|
||||||
|
|
||||||
// Before running the children, we need to insert our nodes into the bloom
|
// Before running the children, we need to insert our nodes into the bloom
|
||||||
// filter.
|
// filter.
|
||||||
|
debug!("[{}] + {:X}", tid(), unsafe_layout_node.val0());
|
||||||
bf.as_mut().map(|bf| node.insert_into_bloom_filter(bf));
|
bf.as_mut().map(|bf| node.insert_into_bloom_filter(bf));
|
||||||
|
|
||||||
// It's *very* important that this block is in a separate scope to the block above,
|
// It's *very* important that this block is in a separate scope to the block above,
|
||||||
|
@ -399,7 +415,7 @@ fn recalc_style_for_node(mut unsafe_layout_node: UnsafeLayoutNode,
|
||||||
construct_flows(&mut unsafe_layout_node, &mut bf, &layout_context);
|
construct_flows(&mut unsafe_layout_node, &mut bf, &layout_context);
|
||||||
}
|
}
|
||||||
|
|
||||||
bf.map(|bf| put_task_local_bloom_filter(bf, &unsafe_layout_node));
|
bf.map(|bf| put_task_local_bloom_filter(bf, &unsafe_layout_node, &layout_context));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn construct_flows<'a>(unsafe_layout_node: &mut UnsafeLayoutNode,
|
fn construct_flows<'a>(unsafe_layout_node: &mut UnsafeLayoutNode,
|
||||||
|
@ -437,9 +453,11 @@ fn construct_flows<'a>(unsafe_layout_node: &mut UnsafeLayoutNode,
|
||||||
// If this is the reflow root, we're done.
|
// If this is the reflow root, we're done.
|
||||||
let opaque_node: OpaqueNode = OpaqueNodeMethods::from_layout_node(&node);
|
let opaque_node: OpaqueNode = OpaqueNodeMethods::from_layout_node(&node);
|
||||||
if layout_context.shared.reflow_root == opaque_node {
|
if layout_context.shared.reflow_root == opaque_node {
|
||||||
|
debug!("[{}] - {:X}, and deleting BF.", tid(), unsafe_layout_node.val0());
|
||||||
*parent_bf = None;
|
*parent_bf = None;
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
|
debug!("[{}] - {:X}", tid(), unsafe_layout_node.val0());
|
||||||
parent_bf.as_mut().map(|parent_bf| node.remove_from_bloom_filter(parent_bf));
|
parent_bf.as_mut().map(|parent_bf| node.remove_from_bloom_filter(parent_bf));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -611,6 +629,7 @@ fn build_display_list(mut unsafe_flow: UnsafeFlow,
|
||||||
pub fn recalc_style_for_subtree(root_node: &LayoutNode,
|
pub fn recalc_style_for_subtree(root_node: &LayoutNode,
|
||||||
shared_layout_context: &SharedLayoutContext,
|
shared_layout_context: &SharedLayoutContext,
|
||||||
queue: &mut WorkQueue<*const SharedLayoutContext,UnsafeLayoutNode>) {
|
queue: &mut WorkQueue<*const SharedLayoutContext,UnsafeLayoutNode>) {
|
||||||
|
debug!("[{}] Style Recalc START", tid());
|
||||||
queue.data = shared_layout_context as *const _;
|
queue.data = shared_layout_context as *const _;
|
||||||
|
|
||||||
// Enqueue the root node.
|
// Enqueue the root node.
|
||||||
|
|
|
@ -44,6 +44,7 @@ pub mod smallvec;
|
||||||
pub mod sort;
|
pub mod sort;
|
||||||
pub mod str;
|
pub mod str;
|
||||||
pub mod task;
|
pub mod task;
|
||||||
|
pub mod tid;
|
||||||
pub mod time;
|
pub mod time;
|
||||||
pub mod vec;
|
pub mod vec;
|
||||||
pub mod workqueue;
|
pub mod workqueue;
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
#[deriving(Eq, PartialEq, Clone, Encodable, Hash)]
|
#[deriving(Eq, PartialEq, Clone, Encodable, Hash, Show)]
|
||||||
pub enum Namespace {
|
pub enum Namespace {
|
||||||
Null,
|
Null,
|
||||||
HTML,
|
HTML,
|
||||||
|
|
18
components/util/tid.rs
Normal file
18
components/util/tid.rs
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
use std::sync::atomics::{AtomicUint, INIT_ATOMIC_UINT, SeqCst};
|
||||||
|
|
||||||
|
static mut next_tid: AtomicUint = INIT_ATOMIC_UINT;
|
||||||
|
|
||||||
|
local_data_key!(task_local_tid: uint)
|
||||||
|
|
||||||
|
/// Every task gets one, that's unique.
|
||||||
|
pub fn tid() -> uint {
|
||||||
|
let ret =
|
||||||
|
match task_local_tid.replace(None) {
|
||||||
|
None => unsafe { next_tid.fetch_add(1, SeqCst) },
|
||||||
|
Some(x) => x,
|
||||||
|
};
|
||||||
|
|
||||||
|
task_local_tid.replace(Some(ret));
|
||||||
|
|
||||||
|
ret
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue