Fix quadtree zoom and request flood bugs

This commit is contained in:
eschweic 2013-07-11 15:30:09 -07:00
parent 783e898c60
commit dd061cfdc0
2 changed files with 67 additions and 90 deletions

View file

@ -240,6 +240,15 @@ impl CompositorTask {
// Iterate over the children of the container layer. // Iterate over the children of the container layer.
let mut current_layer_child = root_layer.first_child; let mut current_layer_child = root_layer.first_child;
// Delete old layer
while current_layer_child.is_some() {
let trash = current_layer_child.get();
do current_layer_child.get().with_common |common| {
current_layer_child = common.next_sibling;
}
root_layer.remove_child(trash);
}
let all_tiles = quad.get_all_tiles(); let all_tiles = quad.get_all_tiles();
for all_tiles.iter().advance |buffer| { for all_tiles.iter().advance |buffer| {
let width = buffer.screen_pos.size.width as uint; let width = buffer.screen_pos.size.width as uint;
@ -278,14 +287,6 @@ impl CompositorTask {
} }
// Delete leftover layers
while current_layer_child.is_some() {
let trash = current_layer_child.get();
do current_layer_child.get().with_common |common| {
current_layer_child = common.next_sibling;
}
root_layer.remove_child(trash);
}
// Reset zoom // Reset zoom
*local_zoom = 1f32; *local_zoom = 1f32;
root_layer.common.set_transform(identity().translate(-world_offset.x, root_layer.common.set_transform(identity().translate(-world_offset.x,
@ -438,7 +439,7 @@ impl CompositorTask {
for new_layer_buffer_set.buffers.iter().advance |buffer| { for new_layer_buffer_set.buffers.iter().advance |buffer| {
// FIXME: Don't copy the buffers here // FIXME: Don't copy the buffers here
quad.add_tile(buffer.screen_pos.origin.x, buffer.screen_pos.origin.y, quad.add_tile(buffer.screen_pos.origin.x, buffer.screen_pos.origin.y,
*world_zoom, ~buffer.clone()); buffer.resolution, ~buffer.clone());
} }
*page_size = Size2D(new_size.width as f32, new_size.height as f32); *page_size = Size2D(new_size.width as f32, new_size.height as f32);
@ -493,9 +494,6 @@ impl CompositorTask {
root_layer.common.set_transform(scroll_transform); root_layer.common.set_transform(scroll_transform);
// FIXME: ask_for_tiles() should be called here, but currently this sends a flood of requests
// to the renderer, which slows the application dramatically. Instead, ask_for_tiles() is only
// called on a click event.
ask_for_tiles(); ask_for_tiles();
*recomposite = true; *recomposite = true;

View file

@ -86,7 +86,7 @@ impl<T> Quadtree<T> {
pub fn remove_tile(&mut self, x: uint, y: uint, scale: f32) { pub fn remove_tile(&mut self, x: uint, y: uint, scale: f32) {
self.root.remove_tile(x as f32 / scale, y as f32 / scale); self.root.remove_tile(x as f32 / scale, y as f32 / scale);
} }
/// Given a window rect in page coordinates and a function to check if an existing tile is "valid" /// Given a window rect in pixel coordinates and a function to check if an existing tile is "valid"
/// (i.e. is the correct resolution), this function returns a list of BufferRequests for tiles that /// (i.e. is the correct resolution), this function returns a list of BufferRequests for tiles that
/// need to be rendered. It also returns a boolean if the window needs to be redisplayed, i.e. if /// need to be rendered. It also returns a boolean if the window needs to be redisplayed, i.e. if
/// no tiles need to be rendered, but the display tree needs to be rebuilt. This can occur when the /// no tiles need to be rendered, but the display tree needs to be rebuilt. This can occur when the
@ -97,6 +97,7 @@ impl<T> Quadtree<T> {
self.root.get_tile_rects(Rect(Point2D(window.origin.x as f32 / scale, window.origin.y as f32 / scale), self.root.get_tile_rects(Rect(Point2D(window.origin.x as f32 / scale, window.origin.y as f32 / scale),
Size2D(window.size.width as f32 / scale, window.size.height as f32 / scale)), Size2D(window.size.width as f32 / scale, window.size.height as f32 / scale)),
valid, scale, self.max_tile_size as f32 / scale) valid, scale, self.max_tile_size as f32 / scale)
} }
/// Generate html to visualize the tree. For debugging purposes only. /// Generate html to visualize the tree. For debugging purposes only.
@ -148,15 +149,10 @@ impl<T> QuadtreeNode<T> {
} }
} }
/// Get all tiles in the tree, parents first. /// Get all tiles in the tree, parents last.
fn get_all_tiles<'r>(&'r self) -> ~[&'r T] { fn get_all_tiles<'r>(&'r self) -> ~[&'r T] {
let mut ret = ~[]; let mut ret = ~[];
match self.tile {
Some(ref tile) => ret = ~[tile],
None => {}
}
for self.quadrants.iter().advance |quad| { for self.quadrants.iter().advance |quad| {
match *quad { match *quad {
Some(ref child) => ret = ret + child.get_all_tiles(), Some(ref child) => ret = ret + child.get_all_tiles(),
@ -164,6 +160,12 @@ impl<T> QuadtreeNode<T> {
} }
} }
match self.tile {
Some(ref tile) => ret = ret + ~[tile],
None => {}
}
return ret; return ret;
} }
@ -231,6 +233,7 @@ impl<T> QuadtreeNode<T> {
let self_x = (self.origin.x * scale).ceil() as uint; let self_x = (self.origin.x * scale).ceil() as uint;
let self_y = (self.origin.y * scale).ceil() as uint; let self_y = (self.origin.y * scale).ceil() as uint;
let self_size = (self.size * scale).ceil() as uint; let self_size = (self.size * scale).ceil() as uint;
self.render_flag = true;
return BufferRequest(Rect(Point2D(self_x, self_y), Size2D(self_size, self_size)), return BufferRequest(Rect(Point2D(self_x, self_y), Size2D(self_size, self_size)),
Rect(Point2D(self.origin.x, self.origin.y), Size2D(self.size, self.size))); Rect(Point2D(self.origin.x, self.origin.y), Size2D(self.size, self.size)));
} }
@ -248,7 +251,6 @@ impl<T> QuadtreeNode<T> {
BL | BR => self.origin.y + new_size, BL | BR => self.origin.y + new_size,
}; };
let mut c = ~QuadtreeNode::new_child(new_x, new_y, new_size); let mut c = ~QuadtreeNode::new_child(new_x, new_y, new_size);
c.render_flag = true;
let result = c.get_tile_rect(x, y, scale, tile_size); let result = c.get_tile_rect(x, y, scale, tile_size);
self.quadrants[quad as int] = Some(c); self.quadrants[quad as int] = Some(c);
result result
@ -340,12 +342,14 @@ impl<T> QuadtreeNode<T> {
if w_x < s_x || w_x + w_width > s_x + s_size if w_x < s_x || w_x + w_width > s_x + s_size
|| w_y < s_y || w_y + w_height > s_y + s_size { || w_y < s_y || w_y + w_height > s_y + s_size {
println(fmt!("window: %?, %?, %?, %?; self: %?, %?, %?", w_x, w_y, w_width, w_height, s_x, s_y, s_size)); println(fmt!("window: %?, %?, %?, %?; self: %?, %?, %?",
w_x, w_y, w_width, w_height, s_x, s_y, s_size));
fail!("Quadtree: tried to query an invalid tile rect"); fail!("Quadtree: tried to query an invalid tile rect");
} }
if s_size <= tile_size { // We are the child if s_size <= tile_size { // We are the child
match self.tile { return match self.tile {
_ if self.render_flag => (~[], false),
Some(ref tile) if valid(tile) => { Some(ref tile) if valid(tile) => {
let redisplay = match self.quadrants { let redisplay = match self.quadrants {
[None, None, None, None] => false, [None, None, None, None] => false,
@ -358,14 +362,9 @@ impl<T> QuadtreeNode<T> {
self.quadrants[*quad as int] = None; self.quadrants[*quad as int] = None;
} }
} }
return (~[], redisplay); (~[], redisplay)
}
None if self.render_flag => {
return(~[], false);
}
_ => {
return (~[self.get_tile_rect(s_x, s_y, scale, tile_size)], false);
} }
_ => (~[self.get_tile_rect(s_x, s_y, scale, tile_size)], false),
} }
} }
@ -403,8 +402,6 @@ impl<T> QuadtreeNode<T> {
let mut redisplay = false; let mut redisplay = false;
for quads_to_check.iter().advance |quad| { for quads_to_check.iter().advance |quad| {
match self.quadrants[*quad as int] {
Some(ref mut child) => {
// Recurse into child // Recurse into child
let new_window = match *quad { let new_window = match *quad {
TL => Rect(window.origin, TL => Rect(window.origin,
@ -424,48 +421,30 @@ impl<T> QuadtreeNode<T> {
w_height.min(&(w_y + w_height - (s_y + s_size / 2.0))))), w_height.min(&(w_y + w_height - (s_y + s_size / 2.0))))),
}; };
let (c_ret, c_redisplay) = child.get_tile_rects(new_window, |x| valid(x), scale, tile_size);
let (c_ret, c_redisplay) = match self.quadrants[*quad as int] {
Some(ref mut child) => child.get_tile_rects(new_window, |x| valid(x), scale, tile_size),
None => {
// Create new child
let new_size = self.size / 2.0;
let new_x = match *quad {
TL | BL => self.origin.x,
TR | BR => self.origin.x + new_size,
};
let new_y = match *quad {
TL | TR => self.origin.y,
BL | BR => self.origin.y + new_size,
};
let mut child = ~QuadtreeNode::new_child(new_x, new_y, new_size);
let (a, b) = child.get_tile_rects(new_window, |x| valid(x), scale, tile_size);
self.quadrants[*quad as int] = Some(child);
(a, b)
}
};
ret = ret + c_ret; ret = ret + c_ret;
redisplay = redisplay || c_redisplay; redisplay = redisplay || c_redisplay;
} }
None => {
// Figure out locations of future children
let (x_start, y_start, x_end, y_end) = match *quad {
TL => (w_x,
w_y,
(w_x + w_width).min(&(s_x + s_size / 2.0)),
(w_y + w_height).min(&(s_y + s_size / 2.0))),
TR => (w_x.max(&(s_x + s_size / 2.0)),
w_y,
(w_x + w_width + tile_size).min(&(s_x + s_size)),
(w_y + w_height).min(&(s_y + s_size / 2.0))),
BL => (w_x,
w_y.max(&(s_y + s_size / 2.0)),
(w_x + w_width).min(&(s_x + s_size / 2.0)),
(w_y + w_height + tile_size).min(&(s_y + s_size))),
BR => (w_x.max(&(s_x + s_size / 2.0)),
w_y.max(&(s_y + s_size / 2.0)),
(w_x + w_width + tile_size).min(&(s_x + s_size)),
(w_y + w_height + tile_size).min(&(s_y + s_size))),
};
let size = (((x_end - x_start) / tile_size).ceil() *
((y_end - y_start) / tile_size).ceil()) as uint;
let builder = |push: &fn(BufferRequest)| {
let mut y = y_start;
while y < y_end {
let mut x = x_start;
while x < x_end {
push(self.get_tile_rect(x, y, scale, tile_size));
x = x + tile_size;
}
y = y + tile_size;
}
};
ret = ret + build_sized(size, builder);
}
}
}
(ret, redisplay) (ret, redisplay)
} }