gfx: Micro-optimize DList and StackingContext a bit.

I'm sad to say that this improved performance significantly. A lot of
this win is due to the Rust compiler not being smart about not zeroing
objects out if it doesn't need to.
This commit is contained in:
Patrick Walton 2014-11-05 00:51:21 -08:00
parent ffae110498
commit bdab68ab60
2 changed files with 50 additions and 49 deletions

View file

@ -95,31 +95,34 @@ struct StackingContext {
} }
impl StackingContext { impl StackingContext {
/// Creates a stacking context from a display list, consuming that display list in the process. /// Creates a new empty stacking context.
fn new(list: &mut DisplayList) -> StackingContext { #[inline]
let mut stacking_context = StackingContext { fn new() -> StackingContext {
StackingContext {
background_and_borders: DisplayList::new(), background_and_borders: DisplayList::new(),
block_backgrounds_and_borders: DisplayList::new(), block_backgrounds_and_borders: DisplayList::new(),
floats: DisplayList::new(), floats: DisplayList::new(),
content: DisplayList::new(), content: DisplayList::new(),
positioned_descendants: Vec::new(), positioned_descendants: Vec::new(),
}; }
}
/// Initializes a stacking context from a display list, consuming that display list in the
/// process.
fn init_from_list(&mut self, list: &mut DisplayList) {
while !list.list.is_empty() { while !list.list.is_empty() {
let mut head = DisplayList::from_list(servo_dlist::split(&mut list.list)); let mut head = DisplayList::from_list(servo_dlist::split(&mut list.list));
match head.front().unwrap().base().level { match head.front().unwrap().base().level {
BackgroundAndBordersStackingLevel => { BackgroundAndBordersStackingLevel => {
stacking_context.background_and_borders.append_from(&mut head) self.background_and_borders.append_from(&mut head)
} }
BlockBackgroundsAndBordersStackingLevel => { BlockBackgroundsAndBordersStackingLevel => {
stacking_context.block_backgrounds_and_borders.append_from(&mut head) self.block_backgrounds_and_borders.append_from(&mut head)
} }
FloatStackingLevel => stacking_context.floats.append_from(&mut head), FloatStackingLevel => self.floats.append_from(&mut head),
ContentStackingLevel => stacking_context.content.append_from(&mut head), ContentStackingLevel => self.content.append_from(&mut head),
PositionedDescendantStackingLevel(z_index) => { PositionedDescendantStackingLevel(z_index) => {
match stacking_context.positioned_descendants match self.positioned_descendants.iter_mut().find(|& &(z, _)| z_index == z) {
.iter_mut()
.find(|& &(z, _)| z_index == z) {
Some(&(_, ref mut my_list)) => { Some(&(_, ref mut my_list)) => {
my_list.append_from(&mut head); my_list.append_from(&mut head);
continue continue
@ -127,12 +130,10 @@ impl StackingContext {
None => {} None => {}
} }
stacking_context.positioned_descendants.push((z_index, head)) self.positioned_descendants.push((z_index, head))
} }
} }
} }
stacking_context
} }
} }
@ -237,43 +238,38 @@ impl DisplayList {
return return
} }
let StackingContext { let mut stacking_context = StackingContext::new();
mut background_and_borders, stacking_context.init_from_list(self);
mut block_backgrounds_and_borders,
mut floats,
mut content,
mut positioned_descendants
} = StackingContext::new(self);
debug_assert!(self.list.is_empty()); debug_assert!(self.list.is_empty());
// Steps 1 and 2: Borders and background for the root. // Steps 1 and 2: Borders and background for the root.
self.append_from(&mut background_and_borders); self.append_from(&mut stacking_context.background_and_borders);
// Sort positioned children according to z-index. // Sort positioned children according to z-index.
positioned_descendants.sort_by(|&(z_index_a, _), &(z_index_b, _)| { stacking_context.positioned_descendants.sort_by(|&(z_index_a, _), &(z_index_b, _)| {
z_index_a.cmp(&z_index_b) z_index_a.cmp(&z_index_b)
}); });
// Step 3: Positioned descendants with negative z-indices. // Step 3: Positioned descendants with negative z-indices.
for &(ref mut z_index, ref mut list) in positioned_descendants.iter_mut() { for &(ref mut z_index, ref mut list) in stacking_context.positioned_descendants.iter_mut() {
if *z_index < 0 { if *z_index < 0 {
self.append_from(list) self.append_from(list)
} }
} }
// Step 4: Block backgrounds and borders. // Step 4: Block backgrounds and borders.
self.append_from(&mut block_backgrounds_and_borders); self.append_from(&mut stacking_context.block_backgrounds_and_borders);
// Step 5: Floats. // Step 5: Floats.
self.append_from(&mut floats); self.append_from(&mut stacking_context.floats);
// TODO(pcwalton): Step 6: Inlines that generate stacking contexts. // TODO(pcwalton): Step 6: Inlines that generate stacking contexts.
// Step 7: Content. // Step 7: Content.
self.append_from(&mut content); self.append_from(&mut stacking_context.content);
// Steps 8 and 9: Positioned descendants with nonnegative z-indices. // Steps 8 and 9: Positioned descendants with nonnegative z-indices.
for &(ref mut z_index, ref mut list) in positioned_descendants.iter_mut() { for &(ref mut z_index, ref mut list) in stacking_context.positioned_descendants.iter_mut() {
if *z_index >= 0 { if *z_index >= 0 {
self.append_from(list) self.append_from(list)
} }

View file

@ -10,13 +10,13 @@ use std::ptr;
struct RawDList<T> { struct RawDList<T> {
length: uint, length: uint,
head: Option<Box<RawNode<T>>>, head: *mut RawNode<T>,
tail: *mut RawNode<T>, tail: *mut RawNode<T>,
} }
#[allow(dead_code)] #[allow(dead_code)]
struct RawNode<T> { struct RawNode<T> {
next: Option<Box<RawNode<T>>>, next: *mut RawNode<T>,
prev: *mut RawNode<T>, prev: *mut RawNode<T>,
value: T, value: T,
} }
@ -38,27 +38,32 @@ pub fn split<T>(list: &mut DList<T>) -> DList<T> {
if list.length == 0 { if list.length == 0 {
fail!("split_dlist(): empty list") fail!("split_dlist(): empty list")
} }
let mut head_node = mem::replace(&mut list.head, None); let head_node = mem::replace(&mut list.head, ptr::null_mut());
let head_node_ptr: *mut RawNode<T> = &mut **head_node.as_mut().unwrap(); let head_list = RawDList {
let mut head_list = RawDList {
length: 1, length: 1,
head: head_node, head: head_node,
tail: head_node_ptr, tail: head_node,
}; };
debug_assert!(list.head.is_none()); debug_assert!(list.head.is_null());
mem::swap(&mut head_list.head.as_mut().unwrap().next, &mut list.head);
debug_assert!(head_list.head.as_mut().unwrap().next.is_none()); unsafe {
debug_assert!(head_list.head.as_mut().unwrap().prev.is_null()); mem::swap(&mut (*head_list.head).next, &mut list.head);
head_list.head.as_mut().unwrap().prev = ptr::null_mut(); debug_assert!((*head_list.head).next.is_null());
debug_assert!((*head_list.head).prev.is_null());
(*head_list.head).prev = ptr::null_mut();
}
list.length -= 1; list.length -= 1;
if list.length == 0 { if list.length == 0 {
list.tail = ptr::null_mut() list.tail = ptr::null_mut()
} else { } else {
if list.length == 1 { if list.length == 1 {
list.tail = &mut **list.head.as_mut().unwrap() as *mut RawNode<T> list.tail = list.head
}
unsafe {
(*list.head).prev = ptr::null_mut()
} }
list.head.as_mut().unwrap().prev = ptr::null_mut()
} }
unsafe { unsafe {
@ -73,19 +78,19 @@ pub fn append_from<T>(this: &mut DList<T>, other: &mut DList<T>) {
let this = mem::transmute::<&mut DList<T>,&mut RawDList<T>>(this); let this = mem::transmute::<&mut DList<T>,&mut RawDList<T>>(this);
let other = mem::transmute::<&mut DList<T>,&mut RawDList<T>>(other); let other = mem::transmute::<&mut DList<T>,&mut RawDList<T>>(other);
if this.length == 0 { if this.length == 0 {
this.head = mem::replace(&mut other.head, None); this.head = mem::replace(&mut other.head, ptr::null_mut());
this.tail = mem::replace(&mut other.tail, ptr::null_mut()); this.tail = mem::replace(&mut other.tail, ptr::null_mut());
this.length = mem::replace(&mut other.length, 0); this.length = mem::replace(&mut other.length, 0);
return return
} }
(*this.tail).next = match mem::replace(&mut other.head, None) { let old_other_head = mem::replace(&mut other.head, ptr::null_mut());
None => return, if old_other_head.is_null() {
Some(mut head) => { return
head.prev = this.tail; }
Some(head) (*old_other_head).prev = this.tail;
} (*this.tail).next = old_other_head;
};
this.tail = mem::replace(&mut other.tail, ptr::null_mut()); this.tail = mem::replace(&mut other.tail, ptr::null_mut());
this.length += other.length; this.length += other.length;
other.length = 0; other.length = 0;