Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Progressive Rendering #557

Merged
merged 9 commits into from Jul 11, 2013
Prev

Address pcwalton's nits; automatic rendering after scrolling

  • Loading branch information
eschweic
eschweic committed Jul 11, 2013
commit 8a0878a41c53405af77ea33b08a34fbcd1b8c74b
@@ -235,6 +235,64 @@ impl CompositorTask {
let zoom_action = @mut false;
let zoom_time = @mut 0f;

// Extract tiles from the given quadtree and build and display the render tree.
let build_layer_tree: @fn(&Quadtree<~LayerBuffer>) = |quad: &Quadtree<~LayerBuffer>| {
// Iterate over the children of the container layer.
let mut current_layer_child = root_layer.first_child;

let all_tiles = quad.get_all_tiles();
for all_tiles.iter().advance |buffer| {
let width = buffer.screen_pos.size.width as uint;
let height = buffer.screen_pos.size.height as uint;
debug!("osmain: compositing buffer rect %?", &buffer.rect);

// Find or create a texture layer.
let texture_layer;
current_layer_child = match current_layer_child {
None => {
debug!("osmain: adding new texture layer");
texture_layer = @mut TextureLayer::new(@buffer.draw_target.clone() as @TextureManager,
buffer.screen_pos.size);
root_layer.add_child(TextureLayerKind(texture_layer));
None
}
Some(TextureLayerKind(existing_texture_layer)) => {
texture_layer = existing_texture_layer;
texture_layer.manager = @buffer.draw_target.clone() as @TextureManager;

// Move on to the next sibling.
do current_layer_child.get().with_common |common| {
common.next_sibling
}
}
Some(_) => fail!(~"found unexpected layer kind"),
};

let origin = buffer.rect.origin;
let origin = Point2D(origin.x as f32, origin.y as f32);

// Set the layer's transform.
let transform = identity().translate(origin.x * *world_zoom, origin.y * *world_zoom, 0.0);
let transform = transform.scale(width as f32 * *world_zoom / buffer.resolution, height as f32 * *world_zoom / buffer.resolution, 1.0);
texture_layer.common.set_transform(transform);

}

// 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
*local_zoom = 1f32;
root_layer.common.set_transform(identity().translate(-world_offset.x,
-world_offset.y,
0.0));
*recomposite = true;
};

let ask_for_tiles: @fn() = || {
match *quadtree {
@@ -256,7 +314,7 @@ impl CompositorTask {
}
}
} else if redisplay {
// TODO: move display code to its own closure and call that here
build_layer_tree(quad);
}
}
_ => {
@@ -313,11 +371,6 @@ impl CompositorTask {

}
WindowMouseUpEvent(button, layer_mouse_point) => {

// FIXME: this should happen on a scroll/zoom event instead,
// but is here temporarily to prevent request floods to the renderer
ask_for_tiles();

event = MouseUpEvent(button, world_mouse_point(layer_mouse_point));
}
}
@@ -371,85 +424,29 @@ impl CompositorTask {
Some(pipeline_id) => if id != pipeline_id { loop; },
None => { loop; },
}
debug!("osmain: received new frame");

debug!("osmain: received new frame");


let quad;
match *quadtree {
Some(ref mut q) => quad = q,
None => fail!("Compositor: given paint command with no quadtree initialized"),
}

*page_size = Size2D(new_size.width as f32, new_size.height as f32);


let new_layer_buffer_set = new_layer_buffer_set.get();
for new_layer_buffer_set.buffers.iter().advance |buffer| {
// FIXME: Don't copy the buffers here
quad.add_tile(buffer.screen_pos.origin.x, buffer.screen_pos.origin.y,
*world_zoom, ~buffer.clone());
}


// Iterate over the children of the container layer.
let mut current_layer_child = root_layer.first_child;
*page_size = Size2D(new_size.width as f32, new_size.height as f32);

let all_tiles = quad.get_all_tiles();
for all_tiles.iter().advance |buffer| {
let width = buffer.screen_pos.size.width as uint;
let height = buffer.screen_pos.size.height as uint;
debug!("osmain: compositing buffer rect %?", &buffer.rect);

// Find or create a texture layer.
let texture_layer;
current_layer_child = match current_layer_child {
None => {
debug!("osmain: adding new texture layer");
texture_layer = @mut TextureLayer::new(@buffer.draw_target.clone() as @TextureManager,
buffer.screen_pos.size);
root_layer.add_child(TextureLayerKind(texture_layer));
None
}
Some(TextureLayerKind(existing_texture_layer)) => {
texture_layer = existing_texture_layer;
texture_layer.manager = @buffer.draw_target.clone() as @TextureManager;

// Move on to the next sibling.
do current_layer_child.get().with_common |common| {
common.next_sibling
}
}
Some(_) => fail!(~"found unexpected layer kind"),
};

let origin = buffer.rect.origin;
let origin = Point2D(origin.x as f32, origin.y as f32);

// Set the layer's transform.
let transform = identity().translate(origin.x * *world_zoom, origin.y * *world_zoom, 0.0);
let transform = transform.scale(width as f32 * *world_zoom / buffer.resolution, height as f32 * *world_zoom / buffer.resolution, 1.0);
texture_layer.common.set_transform(transform);

}

// 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
*local_zoom = 1f32;
root_layer.common.set_transform(identity().translate(-world_offset.x,
-world_offset.y,
0.0));
build_layer_tree(quad);

// TODO: Recycle the old buffers; send them back to the renderer to reuse if
// it wishes.

*recomposite = true;
}
}
}
@@ -499,7 +496,7 @@ impl CompositorTask {
// 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;
}
@@ -23,12 +23,14 @@ pub struct Quadtree<T> {
struct QuadtreeNode<T> {
/// The tile belonging to this node. Note that parent nodes can have tiles.
tile: Option<T>,
/// The positiong of the node in page coordinates.
/// The position of the node in page coordinates.
origin: Point2D<f32>,
/// The width and hight of the node in page coordinates.
/// The width and height of the node in page coordinates.
size: f32,
/// The node's children.
quadrants: [Option<~QuadtreeNode<T>>, ..4],
/// If this node is marked for rendering
render_flag: bool,
}

priv enum Quadrant {
@@ -53,6 +55,7 @@ impl<T> Quadtree<T> {
origin: Point2D(x as f32, y as f32),
size: size as f32,
quadrants: [None, None, None, None],
render_flag: false,
},
max_tile_size: tile_size,
}
@@ -71,7 +74,7 @@ impl<T> Quadtree<T> {
self.root.add_tile(x as f32 / scale, y as f32 / scale, tile, self.max_tile_size as f32 / scale);
}
/// Get the tile rect in screen and page coordinates for a given pixel position
pub fn get_tile_rect(&self, x: uint, y: uint, scale: f32) -> BufferRequest {
pub fn get_tile_rect(&mut self, x: uint, y: uint, scale: f32) -> BufferRequest {
self.root.get_tile_rect(x as f32 / scale, y as f32 / scale, scale, self.max_tile_size as f32 / scale)
}
/// Get all the tiles in the tree
@@ -96,10 +99,10 @@ impl<T> Quadtree<T> {
valid, scale, self.max_tile_size as f32 / scale)
}

/// Generate html to visualize the tree
/// Generate html to visualize the tree. For debugging purposes only.
pub fn get_html(&self) -> ~str {
let header = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\"> <html xmlns=\"http://www.w3.org/1999/xhtml\">";
fmt!("%s<body>%s</body></html>", header, self.root.get_html())
static HEADER: &'static str = "<!DOCTYPE html><html>";
fmt!("%s<body>%s</body></html>", HEADER, self.root.get_html())
}

}
@@ -112,6 +115,7 @@ impl<T> QuadtreeNode<T> {
origin: Point2D(x, y),
size: size,
quadrants: [None, None, None, None],
render_flag: false,
}
}

@@ -149,7 +153,7 @@ impl<T> QuadtreeNode<T> {
let mut ret = ~[];

match self.tile {
Some (ref tile) => ret = ~[tile],
Some(ref tile) => ret = ~[tile],
None => {}
}

@@ -180,6 +184,7 @@ impl<T> QuadtreeNode<T> {
for quads.iter().advance |quad| {
self.quadrants[*quad as int] = None;
}
self.render_flag = false;
} else { // Send tile to children
let quad = self.get_quadrant(x, y);
match self.quadrants[quad as int] {
@@ -216,7 +221,7 @@ impl<T> QuadtreeNode<T> {
}

/// Get a tile rect in screen and page coords for a given position in page coords
fn get_tile_rect(&self, x: f32, y: f32, scale: f32, tile_size: f32) -> BufferRequest {
fn get_tile_rect(&mut self, x: f32, y: f32, scale: f32, tile_size: f32) -> BufferRequest {
if x >= self.origin.x + self.size || x < self.origin.x
|| y >= self.origin.y + self.size || y < self.origin.y {
fail!("Quadtree: Tried to query a tile rect outside of range");
@@ -230,24 +235,25 @@ impl<T> QuadtreeNode<T> {
Rect(Point2D(self.origin.x, self.origin.y), Size2D(self.size, self.size)));
}

let index = self.get_quadrant(x,y) as int;
match self.quadrants[index] {
let quad = self.get_quadrant(x,y);
match self.quadrants[quad as int] {
None => {
// Calculate where the new tile should go
let factor = self.size / tile_size;
let divisor = next_power_of_two(factor.ceil() as uint);
let new_size_page = self.size / (divisor as f32);
let new_size_pixel = (new_size_page * scale).ceil() as uint;

let new_x_page = self.origin.x + new_size_page * ((x - self.origin.x) / new_size_page).floor();
let new_y_page = self.origin.y + new_size_page * ((y - self.origin.y) / new_size_page).floor();
let new_x_pixel = (new_x_page * scale).ceil() as uint;
let new_y_pixel = (new_y_page * scale).ceil() as uint;

BufferRequest(Rect(Point2D(new_x_pixel, new_y_pixel), Size2D(new_size_pixel, new_size_pixel)),
Rect(Point2D(new_x_page, new_y_page), Size2D(new_size_page, new_size_page)))
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 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);
self.quadrants[quad as int] = Some(c);
result
}
Some(ref child) => child.get_tile_rect(x, y, scale, tile_size),
Some(ref mut child) => child.get_tile_rect(x, y, scale, tile_size),
}
}

@@ -354,6 +360,9 @@ impl<T> QuadtreeNode<T> {
}
return (~[], redisplay);
}
None if self.render_flag => {
return(~[], false);
}
_ => {
return (~[self.get_tile_rect(s_x, s_y, scale, tile_size)], false);
}
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.