Skip to content

Commit

Permalink
Add NodeStatus enum, infrastructure for compositor-side invalidation
Browse files Browse the repository at this point in the history
  • Loading branch information
eschweic committed Aug 19, 2013
1 parent 2359587 commit f9df745
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 16 deletions.
15 changes: 14 additions & 1 deletion src/components/main/compositing/compositor_layer.rs
Expand Up @@ -12,7 +12,7 @@ use servo_msg::constellation_msg::PipelineId;
use script::dom::event::{ClickEvent, MouseDownEvent, MouseUpEvent};
use script::script_task::SendEventMsg;
use windowing::{MouseWindowEvent, MouseWindowClickEvent, MouseWindowMouseDownEvent, MouseWindowMouseUpEvent};
use compositing::quadtree::Quadtree;
use compositing::quadtree::{Quadtree, Invalid};
use layers::layers::{ContainerLayerKind, ContainerLayer, TextureLayerKind, TextureLayer, TextureManager};
use pipeline::Pipeline;

Expand Down Expand Up @@ -366,6 +366,19 @@ impl CompositorLayer {
}
}
}

pub fn invalidate_rect(&mut self, pipeline_id: PipelineId, rect: Rect<f32>) -> bool {
if self.pipeline.id == pipeline_id {
let quadtree = match self.quadtree {
NoTree(_, _) => return true, // Nothing to do
Tree(ref mut quadtree) => quadtree,
};
quadtree.set_status_page(rect, Invalid, true);
return true;
}
// ID does not match ours, so recurse on descendents (including hidden children).
self.children.mut_iter().map(|x| &mut x.child).any(|x| x.invalidate_rect(pipeline_id, rect))
}

// Adds a child.
pub fn add_child(&mut self, pipeline: Pipeline, page_size: Option<Size2D<f32>>, tile_size: uint,
Expand Down
19 changes: 19 additions & 0 deletions src/components/main/compositing/mod.rs
Expand Up @@ -66,6 +66,10 @@ impl ScriptListener for CompositorChan {
self.chan.send(msg);
}

fn invalidate_rect(&self, id: PipelineId, rect: Rect<uint>) {
self.chan.send(InvalidateRect(id, rect));
}

}

/// Implementation of the abstract `RenderListener` interface.
Expand Down Expand Up @@ -131,6 +135,8 @@ pub enum Msg {
ResizeLayer(PipelineId, Size2D<uint>),
/// Alerts the compositor that the specified layer has been deleted.
DeleteLayer(PipelineId),
/// Invalidate a rect for a given layer
InvalidateRect(PipelineId, Rect<uint>),

/// Requests that the compositor paint the given layer buffer set for the given page size.
Paint(PipelineId, arc::Arc<LayerBufferSet>),
Expand Down Expand Up @@ -312,6 +318,19 @@ impl CompositorTask {
// TODO: Recycle the old buffers; send them back to the renderer to reuse if
// it wishes.
}

InvalidateRect(id, rect) => {
match compositor_layer {
Some(ref mut layer) => {
layer.invalidate_rect(id, Rect(Point2D(rect.origin.x as f32,
rect.origin.y as f32),
Size2D(rect.size.width as f32,
rect.size.height as f32)));
ask_for_tiles();
}
None => {} // Nothing to do
}
}
}
}
};
Expand Down
92 changes: 77 additions & 15 deletions src/components/main/compositing/quadtree.rs
Expand Up @@ -41,10 +41,24 @@ struct QuadtreeNode<T> {
size: f32,
/// The node's children.
quadrants: [Option<~QuadtreeNode<T>>, ..4],
/// If this node is marked for rendering
render_flag: bool,
/// Combined size of self.tile and tiles of all descendants
tile_mem: uint,
/// The current status of this node. See below for details.
status: NodeStatus,
}

/// The status of a QuadtreeNode. This determines the behavior of the node
/// when querying for tile requests.
#[deriving(Eq)]
pub enum NodeStatus {
/// If we have no valid tile, request one; otherwise, don't send a request.
Normal,
/// Render request has been sent; ignore this node until tile is inserted.
Rendering,
/// Do not send tile requests. Overrides Invalid.
Hidden,
/// Send tile requests, even if the node has (or child nodes have) a valid tile.
Invalid,
}

enum Quadrant {
Expand Down Expand Up @@ -72,8 +86,8 @@ impl<T: Tile> Quadtree<T> {
origin: Point2D(0f32, 0f32),
size: size as f32,
quadrants: [None, None, None, None],
render_flag: false,
tile_mem: 0,
status: Normal,
},
clip_size: Size2D(width, height),
max_tile_size: tile_size,
Expand Down Expand Up @@ -184,7 +198,7 @@ impl<T: Tile> Quadtree<T> {
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(self.clip_size.width as f32, self.clip_size.height as f32),
scale, self.max_tile_size as f32 / scale);
scale, self.max_tile_size as f32 / scale, false);
(ret, redisplay)
}

Expand All @@ -193,7 +207,7 @@ impl<T: Tile> Quadtree<T> {
let (ret, redisplay, _) = self.root.get_tile_rects(
window,
Size2D(self.clip_size.width as f32, self.clip_size.height as f32),
scale, self.max_tile_size as f32 / scale);
scale, self.max_tile_size as f32 / scale, false);
(ret, redisplay)
}

Expand All @@ -218,8 +232,8 @@ impl<T: Tile> Quadtree<T> {
origin: Point2D(0f32, 0f32),
size: new_size as f32 / ((difference - i - 1) as f32).exp2(),
quadrants: [None, None, None, None],
render_flag: false,
tile_mem: self.root.tile_mem,
status: Normal,
};
self.root.quadrants[TL as int] = Some(replace(&mut self.root, new_root));
}
Expand All @@ -235,8 +249,8 @@ impl<T: Tile> Quadtree<T> {
origin: Point2D(0f32, 0f32),
size: new_size as f32,
quadrants: [None, None, None, None],
render_flag: false,
tile_mem: 0,
status: Normal,
};
break;
}
Expand All @@ -245,6 +259,13 @@ impl<T: Tile> Quadtree<T> {
}
}

/// Set the status of all quadtree nodes within the given rect in page coordinates. If
/// include_border is true, then nodes on the edge of the rect will be included; otherwise,
/// only nodes completely occluded by the rect will be changed.
pub fn set_status_page(&mut self, rect: Rect<f32>, status: NodeStatus, include_border: bool) {
self.root.set_status(rect, status, include_border);
}

/// Generate html to visualize the tree. For debugging purposes only.
pub fn get_html(&self) -> ~str {
static HEADER: &'static str = "<!DOCTYPE html><html>";
Expand All @@ -261,8 +282,8 @@ impl<T: Tile> QuadtreeNode<T> {
origin: Point2D(x, y),
size: size,
quadrants: [None, None, None, None],
render_flag: false,
tile_mem: 0,
status: Normal,
}
}

Expand Down Expand Up @@ -335,7 +356,7 @@ impl<T: Tile> QuadtreeNode<T> {
for quad in quads.iter() {
self.quadrants[*quad as int] = None;
}
self.render_flag = false;
self.status = Normal;
self.tile_mem as int - old_size as int
} else { // Send tile to children
let quad = self.get_quadrant(x, y);
Expand Down Expand Up @@ -380,7 +401,7 @@ impl<T: Tile> QuadtreeNode<T> {
let page_height = (clip_y - self.origin.y).min(&self.size);
let pix_width = (page_width * scale).ceil() as uint;
let pix_height = (page_height * scale).ceil() as uint;
self.render_flag = true;
self.status = Rendering;
return BufferRequest(Rect(Point2D(pix_x, pix_y), Size2D(pix_width, pix_height)),
Rect(Point2D(self.origin.x, self.origin.y), Size2D(page_width, page_height)));
}
Expand Down Expand Up @@ -477,9 +498,11 @@ impl<T: Tile> QuadtreeNode<T> {

/// Given a window rect in page coordinates, returns a BufferRequest array,
/// a redisplay boolean, and the difference in tile memory between the new and old quadtree nodes.
/// The override bool will be true if a parent node was marked as invalid; child nodes will be
/// treated as invalid as well.
/// NOTE: this method will sometimes modify the tree by deleting tiles.
/// See the QuadTree function description for more details.
fn get_tile_rects(&mut self, window: Rect<f32>, clip: Size2D<f32>, scale: f32, tile_size: f32) ->
fn get_tile_rects(&mut self, window: Rect<f32>, clip: Size2D<f32>, scale: f32, tile_size: f32, override: bool) ->
(~[BufferRequest], bool, int) {

let w_x = window.origin.x;
Expand All @@ -503,8 +526,9 @@ impl<T: Tile> QuadtreeNode<T> {

if s_size <= tile_size { // We are the child
return match self.tile {
_ if self.render_flag => (~[], false, 0),
Some(ref tile) if tile.is_valid(scale) => {
_ if self.status == Rendering || self.status == Hidden => (~[], false, 0),
Some(ref tile) if tile.is_valid(scale) && !override
&& self.status != Invalid => {
let redisplay = match self.quadrants {
[None, None, None, None] => false,
_ => true,
Expand Down Expand Up @@ -582,8 +606,10 @@ impl<T: Tile> QuadtreeNode<T> {

};

let override = override || self.status == Invalid;
self.status = Normal;
let (c_ret, c_redisplay, c_delta) = match self.quadrants[*quad as int] {
Some(ref mut child) => child.get_tile_rects(new_window, clip, scale, tile_size),
Some(ref mut child) => child.get_tile_rects(new_window, clip, scale, tile_size, override),
None => {
// Create new child
let new_size = self.size / 2.0;
Expand All @@ -596,7 +622,7 @@ impl<T: Tile> QuadtreeNode<T> {
BL | BR => self.origin.y + new_size,
};
let mut child = ~QuadtreeNode::new_child(new_x, new_y, new_size);
let ret = child.get_tile_rects(new_window, clip, scale, tile_size);
let ret = child.get_tile_rects(new_window, clip, scale, tile_size, override);
self.quadrants[*quad as int] = Some(child);
ret
}
Expand All @@ -610,6 +636,42 @@ impl<T: Tile> QuadtreeNode<T> {
(ret, redisplay, delta)
}

/// Set the status of nodes contained within the rect. See the quadtree method for
/// more info.
fn set_status(&mut self, rect: Rect<f32>, status: NodeStatus, borders: bool) {
let self_rect = Rect(self.origin, Size2D(self.size, self.size));
let intersect = rect.intersection(&self_rect);
let intersect = match intersect {
None => return, // We do not intersect the rect, nothing to do
Some(rect) => rect,
};

if self_rect == intersect { // We are completely contained in the rect
if !(self.status == Hidden && status == Invalid) { // Hidden trumps Invalid
self.status = status;
}
return; // No need to recurse
}

match self.quadrants {
[None, None, None, None] => { // We are a leaf
if borders && !(self.status == Hidden && status == Invalid) {
self.status = status;
}
}
_ => { // We are internal
for quad in self.quadrants.mut_iter() {
match *quad {
None => {} // Nothing to do
Some(ref mut child) => {
child.set_status(intersect, status, borders);
}
}
}
}
}
}

/// Generate html to visualize the tree.
/// This is really inefficient, but it's for testing only.
fn get_html(&self) -> ~str {
Expand Down
1 change: 1 addition & 0 deletions src/components/msg/compositor_msg.rs
Expand Up @@ -69,6 +69,7 @@ pub trait RenderListener {
/// which is used in displaying the appropriate message in the window's title.
pub trait ScriptListener : Clone {
fn set_ready_state(&self, ReadyState);
fn invalidate_rect(&self, PipelineId, Rect<uint>);
}

/// The interface used by the quadtree to get info about LayerBuffers
Expand Down

5 comments on commit f9df745

@bors-servo
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

saw approval from kmcallister
at eschweic@f9df745

@bors-servo
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

merging eschweic/servo/dlbi = f9df745 into auto

@bors-servo
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

eschweic/servo/dlbi = f9df745 merged ok, testing candidate = 4407e52

@bors-servo
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bors-servo
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fast-forwarding master to auto = 4407e52

Please sign in to comment.