mirror of
https://github.com/servo/servo.git
synced 2025-06-25 01:24:37 +01:00
Implement compositor layer occlusion; clean up
This commit is contained in:
parent
a07ff5d1b5
commit
81da3b980e
2 changed files with 150 additions and 71 deletions
|
@ -13,7 +13,7 @@ use servo_msg::constellation_msg::PipelineId;
|
||||||
use script::dom::event::{ClickEvent, MouseDownEvent, MouseUpEvent};
|
use script::dom::event::{ClickEvent, MouseDownEvent, MouseUpEvent};
|
||||||
use script::script_task::SendEventMsg;
|
use script::script_task::SendEventMsg;
|
||||||
use windowing::{MouseWindowEvent, MouseWindowClickEvent, MouseWindowMouseDownEvent, MouseWindowMouseUpEvent};
|
use windowing::{MouseWindowEvent, MouseWindowClickEvent, MouseWindowMouseDownEvent, MouseWindowMouseUpEvent};
|
||||||
use compositing::quadtree::{Quadtree, Invalid};
|
use compositing::quadtree::{Quadtree, Normal, Invalid, Hidden};
|
||||||
use layers::layers::{ContainerLayerKind, ContainerLayer, TextureLayerKind, TextureLayer, TextureManager};
|
use layers::layers::{ContainerLayerKind, ContainerLayer, TextureLayerKind, TextureLayer, TextureManager};
|
||||||
use pipeline::Pipeline;
|
use pipeline::Pipeline;
|
||||||
use constellation::{SendableChildFrameTree, SendableFrameTree};
|
use constellation::{SendableChildFrameTree, SendableFrameTree};
|
||||||
|
@ -116,6 +116,7 @@ impl CompositorLayer {
|
||||||
container: container,
|
container: container,
|
||||||
}
|
}
|
||||||
}).collect();
|
}).collect();
|
||||||
|
layer.set_occlusions();
|
||||||
layer
|
layer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,6 +141,7 @@ impl CompositorLayer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Scroll this layer!
|
||||||
let old_origin = self.scroll_offset;
|
let old_origin = self.scroll_offset;
|
||||||
self.scroll_offset = self.scroll_offset + delta;
|
self.scroll_offset = self.scroll_offset + delta;
|
||||||
|
|
||||||
|
@ -204,8 +206,8 @@ impl CompositorLayer {
|
||||||
let mut redisplay: bool;
|
let mut redisplay: bool;
|
||||||
{ // block here to prevent double mutable borrow of self
|
{ // block here to prevent double mutable borrow of self
|
||||||
let quadtree = match self.quadtree {
|
let quadtree = match self.quadtree {
|
||||||
NoTree(_, _) => fail!("CompositorLayer: cannot get buffer request for %?,
|
NoTree(*) => fail!("CompositorLayer: cannot get buffer request for %?,
|
||||||
no quadtree initialized", self.pipeline.id),
|
no quadtree initialized", self.pipeline.id),
|
||||||
Tree(ref mut quadtree) => quadtree,
|
Tree(ref mut quadtree) => quadtree,
|
||||||
};
|
};
|
||||||
let (request, unused) = quadtree.get_tile_rects_page(rect, scale);
|
let (request, unused) = quadtree.get_tile_rects_page(rect, scale);
|
||||||
|
@ -249,24 +251,39 @@ impl CompositorLayer {
|
||||||
// If the layer is hidden and has a defined page size, unhide it.
|
// If the layer is hidden and has a defined page size, unhide it.
|
||||||
// This method returns false if the specified layer is not found.
|
// This method returns false if the specified layer is not found.
|
||||||
pub fn set_clipping_rect(&mut self, pipeline_id: PipelineId, new_rect: Rect<f32>) -> bool {
|
pub fn set_clipping_rect(&mut self, pipeline_id: PipelineId, new_rect: Rect<f32>) -> bool {
|
||||||
for child_node in self.children.mut_iter() {
|
match self.children.iter().position(|x| pipeline_id == x.child.pipeline.id) {
|
||||||
if pipeline_id != child_node.child.pipeline.id {
|
Some(i) => {
|
||||||
loop;
|
let child_node = &mut self.children[i];
|
||||||
|
let con = child_node.container;
|
||||||
|
con.common.set_transform(identity().translate(new_rect.origin.x,
|
||||||
|
new_rect.origin.y,
|
||||||
|
0.0));
|
||||||
|
let old_rect = con.scissor;
|
||||||
|
con.scissor = Some(new_rect);
|
||||||
|
match self.quadtree {
|
||||||
|
NoTree(*) => {} // Nothing to do
|
||||||
|
Tree(ref mut quadtree) => {
|
||||||
|
match old_rect {
|
||||||
|
Some(old_rect) => {
|
||||||
|
quadtree.set_status_page(old_rect, Normal, false); // Rect is unhidden
|
||||||
|
}
|
||||||
|
None => {} // Nothing to do
|
||||||
|
}
|
||||||
|
quadtree.set_status_page(new_rect, Hidden, false); // Hide the new rect
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If possible, unhide child
|
||||||
|
if child_node.child.hidden && child_node.child.page_size.is_some() {
|
||||||
|
child_node.child.hidden = false;
|
||||||
|
}
|
||||||
|
true
|
||||||
}
|
}
|
||||||
let con = child_node.container;
|
None => {
|
||||||
con.common.set_transform(identity().translate(new_rect.origin.x,
|
// ID does not match any of our immediate children, so recurse on
|
||||||
new_rect.origin.y,
|
// descendents (including hidden children)
|
||||||
0.0));
|
self.children.mut_iter().map(|x| &mut x.child).any(|x| x.set_clipping_rect(pipeline_id, new_rect))
|
||||||
con.scissor = Some(new_rect);
|
|
||||||
// If possible, unhide child
|
|
||||||
if child_node.child.hidden && child_node.child.page_size.is_some() {
|
|
||||||
child_node.child.hidden = false;
|
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ID does not match any of our immediate children, so recurse on descendents (including hidden children)
|
|
||||||
self.children.mut_iter().map(|x| &mut x.child).any(|x| x.set_clipping_rect(pipeline_id, new_rect))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -277,54 +294,70 @@ impl CompositorLayer {
|
||||||
if self.pipeline.id == pipeline_id {
|
if self.pipeline.id == pipeline_id {
|
||||||
self.epoch = epoch;
|
self.epoch = epoch;
|
||||||
self.page_size = Some(new_size);
|
self.page_size = Some(new_size);
|
||||||
// TODO: might get buffers back here
|
|
||||||
match self.quadtree {
|
match self.quadtree {
|
||||||
Tree(ref mut quadtree) => quadtree.resize(new_size.width as uint, new_size.height as uint),
|
Tree(ref mut quadtree) => {
|
||||||
NoTree(tile_size, max_mem) => self.quadtree = Tree(Quadtree::new(new_size.width as uint,
|
self.pipeline.render_chan.send(UnusedBufferMsg(quadtree.resize(new_size.width as uint,
|
||||||
new_size.height as uint,
|
new_size.height as uint)));
|
||||||
tile_size,
|
}
|
||||||
max_mem)),
|
NoTree(tile_size, max_mem) => {
|
||||||
|
self.quadtree = Tree(Quadtree::new(new_size.width as uint,
|
||||||
|
new_size.height as uint,
|
||||||
|
tile_size,
|
||||||
|
max_mem));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Call scroll for bounds checking if the page shrunk. Use (-1, -1) as the cursor position
|
// Call scroll for bounds checking if the page shrunk. Use (-1, -1) as the cursor position
|
||||||
// to make sure the scroll isn't propagated downwards.
|
// to make sure the scroll isn't propagated downwards.
|
||||||
self.scroll(Point2D(0f32, 0f32), Point2D(-1f32, -1f32), window_size);
|
self.scroll(Point2D(0f32, 0f32), Point2D(-1f32, -1f32), window_size);
|
||||||
self.hidden = false;
|
self.hidden = false;
|
||||||
return true;
|
self.set_occlusions();
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
self.resize_helper(pipeline_id, new_size, epoch)
|
||||||
}
|
}
|
||||||
self.resize_helper(pipeline_id, new_size, epoch)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// A helper method to resize sublayers.
|
// A helper method to resize sublayers.
|
||||||
fn resize_helper(&mut self, pipeline_id: PipelineId, new_size: Size2D<f32>, epoch: Epoch) -> bool {
|
fn resize_helper(&mut self, pipeline_id: PipelineId, new_size: Size2D<f32>, epoch: Epoch) -> bool {
|
||||||
for child_node in self.children.mut_iter() {
|
let found = match self.children.iter().position(|x| pipeline_id == x.child.pipeline.id) {
|
||||||
if pipeline_id != child_node.child.pipeline.id {
|
Some(i) => {
|
||||||
loop;
|
let child_node = &mut self.children[i];
|
||||||
}
|
let child = &mut child_node.child;
|
||||||
let child = &mut child_node.child;
|
child.epoch = epoch;
|
||||||
child.epoch = epoch;
|
child.page_size = Some(new_size);
|
||||||
child.page_size = Some(new_size);
|
match child.quadtree {
|
||||||
// TODO: might get buffers back here
|
Tree(ref mut quadtree) => {
|
||||||
match child.quadtree {
|
child.pipeline.render_chan.send(UnusedBufferMsg(quadtree.resize(new_size.width as uint,
|
||||||
Tree(ref mut quadtree) => quadtree.resize(new_size.width as uint, new_size.height as uint),
|
new_size.height as uint)));
|
||||||
NoTree(tile_size, max_mem) => child.quadtree = Tree(Quadtree::new(new_size.width as uint,
|
}
|
||||||
new_size.height as uint,
|
NoTree(tile_size, max_mem) => {
|
||||||
tile_size,
|
child.quadtree = Tree(Quadtree::new(new_size.width as uint,
|
||||||
max_mem)),
|
new_size.height as uint,
|
||||||
}
|
tile_size,
|
||||||
match child_node.container.scissor {
|
max_mem));
|
||||||
Some(scissor) => {
|
}
|
||||||
// Call scroll for bounds checking if the page shrunk. Use (-1, -1) as the cursor position
|
|
||||||
// to make sure the scroll isn't propagated downwards.
|
|
||||||
child.scroll(Point2D(0f32, 0f32), Point2D(-1f32, -1f32), scissor.size);
|
|
||||||
child.hidden = false;
|
|
||||||
}
|
}
|
||||||
None => {} // Nothing to do
|
match child_node.container.scissor {
|
||||||
|
Some(scissor) => {
|
||||||
|
// Call scroll for bounds checking if the page shrunk. Use (-1, -1) as the cursor position
|
||||||
|
// to make sure the scroll isn't propagated downwards.
|
||||||
|
child.scroll(Point2D(0f32, 0f32), Point2D(-1f32, -1f32), scissor.size);
|
||||||
|
child.hidden = false;
|
||||||
|
}
|
||||||
|
None => {} // Nothing to do
|
||||||
|
}
|
||||||
|
true
|
||||||
}
|
}
|
||||||
return true;
|
None => false,
|
||||||
}
|
};
|
||||||
|
|
||||||
// ID does not match ours, so recurse on descendents (including hidden children)
|
if found { // Boolean flag to get around double borrow of self
|
||||||
self.children.mut_iter().map(|x| &mut x.child).any(|x| x.resize_helper(pipeline_id, new_size, epoch))
|
self.set_occlusions();
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
// ID does not match ours, so recurse on descendents (including hidden children)
|
||||||
|
self.children.mut_iter().map(|x| &mut x.child).any(|x| x.resize_helper(pipeline_id, new_size, epoch))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect buffers from the quadtree. This method IS NOT recursive, so child CompositorLayers
|
// Collect buffers from the quadtree. This method IS NOT recursive, so child CompositorLayers
|
||||||
|
@ -344,8 +377,8 @@ impl CompositorLayer {
|
||||||
|
|
||||||
// Add new tiles.
|
// Add new tiles.
|
||||||
let quadtree = match self.quadtree {
|
let quadtree = match self.quadtree {
|
||||||
NoTree(_, _) => fail!("CompositorLayer: cannot get build layer tree for %?,
|
NoTree(*) => fail!("CompositorLayer: cannot build layer tree for %?,
|
||||||
no quadtree initialized", self.pipeline.id),
|
no quadtree initialized", self.pipeline.id),
|
||||||
Tree(ref mut quadtree) => quadtree,
|
Tree(ref mut quadtree) => quadtree,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -409,12 +442,12 @@ impl CompositorLayer {
|
||||||
if self.pipeline.id == pipeline_id {
|
if self.pipeline.id == pipeline_id {
|
||||||
if self.epoch != epoch {
|
if self.epoch != epoch {
|
||||||
debug!("compositor epoch mismatch: %? != %?, id: %?", self.epoch, epoch, self.pipeline.id);
|
debug!("compositor epoch mismatch: %? != %?, id: %?", self.epoch, epoch, self.pipeline.id);
|
||||||
// TODO: send buffers back
|
self.pipeline.render_chan.send(UnusedBufferMsg(cell.take().buffers));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
{ // block here to prevent double mutable borrow of self
|
{ // block here to prevent double mutable borrow of self
|
||||||
let quadtree = match self.quadtree {
|
let quadtree = match self.quadtree {
|
||||||
NoTree(_, _) => fail!("CompositorLayer: cannot add buffers, no quadtree initialized"),
|
NoTree(*) => fail!("CompositorLayer: cannot add buffers, no quadtree initialized"),
|
||||||
Tree(ref mut quadtree) => quadtree,
|
Tree(ref mut quadtree) => quadtree,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -430,18 +463,37 @@ impl CompositorLayer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.build_layer_tree();
|
self.build_layer_tree();
|
||||||
return true;
|
true
|
||||||
|
} else {
|
||||||
|
// ID does not match ours, so recurse on descendents (including hidden children).
|
||||||
|
self.children.mut_iter().map(|x| &mut x.child)
|
||||||
|
.any(|x| x.add_buffers(pipeline_id, cell.take(), epoch))
|
||||||
}
|
}
|
||||||
// ID does not match ours, so recurse on descendents (including hidden children).
|
|
||||||
self.children.mut_iter().map(|x| &mut x.child).any(|x| x.add_buffers(pipeline_id, cell.take(), epoch))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deletes a specified sublayer, including hidden children. Returns false if the layer is not found.
|
// Deletes a specified sublayer, including hidden children. Returns false if the layer is not found.
|
||||||
pub fn delete(&mut self, pipeline_id: PipelineId) -> bool {
|
pub fn delete(&mut self, pipeline_id: PipelineId) -> bool {
|
||||||
match self.children.rposition(|x| x.child.pipeline.id == pipeline_id) {
|
match self.children.iter().position(|x| x.child.pipeline.id == pipeline_id) {
|
||||||
Some(index) => {
|
Some(i) => {
|
||||||
// TODO: send buffers back to renderer when layer is deleted
|
let mut child = self.children.remove(i);
|
||||||
self.children.remove(index);
|
match self.quadtree {
|
||||||
|
NoTree(*) => {} // Nothing to do
|
||||||
|
Tree(ref mut quadtree) => {
|
||||||
|
match child.container.scissor {
|
||||||
|
Some(rect) => {
|
||||||
|
quadtree.set_status_page(rect, Normal, false); // Unhide this rect
|
||||||
|
}
|
||||||
|
None => {} // Nothing to do
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
match child.child.quadtree {
|
||||||
|
NoTree(*) => {} // Nothing to do
|
||||||
|
Tree(ref mut quadtree) => {
|
||||||
|
// Send back all tiles to renderer.
|
||||||
|
child.child.pipeline.render_chan.send(UnusedBufferMsg(quadtree.collect_tiles()));
|
||||||
|
}
|
||||||
|
}
|
||||||
self.build_layer_tree();
|
self.build_layer_tree();
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
@ -454,14 +506,15 @@ impl CompositorLayer {
|
||||||
pub fn invalidate_rect(&mut self, pipeline_id: PipelineId, rect: Rect<f32>) -> bool {
|
pub fn invalidate_rect(&mut self, pipeline_id: PipelineId, rect: Rect<f32>) -> bool {
|
||||||
if self.pipeline.id == pipeline_id {
|
if self.pipeline.id == pipeline_id {
|
||||||
let quadtree = match self.quadtree {
|
let quadtree = match self.quadtree {
|
||||||
NoTree(_, _) => return true, // Nothing to do
|
NoTree(*) => return true, // Nothing to do
|
||||||
Tree(ref mut quadtree) => quadtree,
|
Tree(ref mut quadtree) => quadtree,
|
||||||
};
|
};
|
||||||
quadtree.set_status_page(rect, Invalid, true);
|
quadtree.set_status_page(rect, Invalid, true);
|
||||||
return true;
|
true
|
||||||
|
} else {
|
||||||
|
// 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))
|
||||||
}
|
}
|
||||||
// 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.
|
// Adds a child.
|
||||||
|
@ -478,6 +531,26 @@ impl CompositorLayer {
|
||||||
child: child,
|
child: child,
|
||||||
container: container,
|
container: container,
|
||||||
});
|
});
|
||||||
|
self.set_occlusions();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recursively sets occluded portions of quadtrees to Hidden, so that they do not ask for
|
||||||
|
// tile requests. If layers are moved, resized, or deleted, these portions may be updated.
|
||||||
|
fn set_occlusions(&mut self) {
|
||||||
|
let quadtree = match self.quadtree {
|
||||||
|
NoTree(*) => return, // Cannot calculate occlusions
|
||||||
|
Tree(ref mut quadtree) => quadtree,
|
||||||
|
};
|
||||||
|
for child in self.children.iter().filter(|x| !x.child.hidden) {
|
||||||
|
match child.container.scissor {
|
||||||
|
None => {} // Nothing to do
|
||||||
|
Some(rect) => {
|
||||||
|
quadtree.set_status_page(rect, Hidden, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for child in self.children.mut_iter().filter(|x| !x.child.hidden) {
|
||||||
|
child.child.set_occlusions();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -217,14 +217,13 @@ impl<T: Tile> Quadtree<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new quadtree at the specified size. This should be called when the window changes size.
|
/// Creates a new quadtree at the specified size. This should be called when the window changes size.
|
||||||
/// TODO: return old tiles.
|
pub fn resize(&mut self, width: uint, height: uint) -> ~[T] {
|
||||||
pub fn resize(&mut self, width: uint, height: uint) {
|
|
||||||
// Spaces must be squares and powers of 2, so expand the space until it is
|
// Spaces must be squares and powers of 2, so expand the space until it is
|
||||||
let longer = width.max(&height);
|
let longer = width.max(&height);
|
||||||
let num_tiles = div_ceil(longer, self.max_tile_size);
|
let num_tiles = div_ceil(longer, self.max_tile_size);
|
||||||
let power_of_two = next_power_of_two(num_tiles);
|
let power_of_two = next_power_of_two(num_tiles);
|
||||||
let size = power_of_two * self.max_tile_size;
|
let size = power_of_two * self.max_tile_size;
|
||||||
|
let ret = self.root.collect_tiles();
|
||||||
self.root = ~QuadtreeNode {
|
self.root = ~QuadtreeNode {
|
||||||
tile: None,
|
tile: None,
|
||||||
origin: Point2D(0f32, 0f32),
|
origin: Point2D(0f32, 0f32),
|
||||||
|
@ -234,6 +233,7 @@ impl<T: Tile> Quadtree<T> {
|
||||||
tile_mem: 0,
|
tile_mem: 0,
|
||||||
};
|
};
|
||||||
self.clip_size = Size2D(width, height);
|
self.clip_size = Size2D(width, height);
|
||||||
|
ret
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Resize the underlying quadtree without removing tiles already in place.
|
/// Resize the underlying quadtree without removing tiles already in place.
|
||||||
|
@ -290,6 +290,12 @@ impl<T: Tile> Quadtree<T> {
|
||||||
self.root.set_status(rect, status, include_border);
|
self.root.set_status(rect, status, include_border);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Remove and return all tiles in the tree. Use this before deleting the quadtree to prevent
|
||||||
|
/// a GC pause.
|
||||||
|
pub fn collect_tiles(&mut self) -> ~[T] {
|
||||||
|
self.root.collect_tiles()
|
||||||
|
}
|
||||||
|
|
||||||
/// Generate html to visualize the tree. For debugging purposes only.
|
/// Generate html to visualize the tree. For debugging purposes only.
|
||||||
pub fn get_html(&self) -> ~str {
|
pub fn get_html(&self) -> ~str {
|
||||||
static HEADER: &'static str = "<!DOCTYPE html><html>";
|
static HEADER: &'static str = "<!DOCTYPE html><html>";
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue