aboutsummaryrefslogtreecommitdiffstats
path: root/src/components/main/compositing/compositor_layer.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/components/main/compositing/compositor_layer.rs')
-rw-r--r--src/components/main/compositing/compositor_layer.rs269
1 files changed, 204 insertions, 65 deletions
diff --git a/src/components/main/compositing/compositor_layer.rs b/src/components/main/compositing/compositor_layer.rs
index a52a519e019..13d22f6602a 100644
--- a/src/components/main/compositing/compositor_layer.rs
+++ b/src/components/main/compositing/compositor_layer.rs
@@ -2,21 +2,27 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-use std::cell::Cell;
+use compositing::quadtree::{Quadtree, Normal, Invalid, Hidden};
+use constellation::{SendableChildFrameTree, SendableFrameTree};
+use geom::matrix::identity;
use geom::point::Point2D;
-use geom::size::Size2D;
use geom::rect::Rect;
-use geom::matrix::identity;
+use geom::size::Size2D;
use gfx::render_task::{ReRenderMsg, UnusedBufferMsg};
-use servo_msg::compositor_msg::{LayerBuffer, LayerBufferSet, Epoch};
-use servo_msg::constellation_msg::PipelineId;
+use layers::layers::{ContainerLayerKind, ContainerLayer, Flip, NoFlip, TextureLayer};
+use layers::layers::{TextureLayerKind, VerticalFlip};
+use layers::platform::surface::{NativeCompositingGraphicsContext, NativeSurfaceMethods};
+use layers::texturegl::{Texture, TextureTarget, TextureTargetRectangle};
+use pipeline::Pipeline;
use script::dom::event::{ClickEvent, MouseDownEvent, MouseUpEvent};
use script::script_task::SendEventMsg;
+use servo_msg::compositor_msg::{LayerBuffer, LayerBufferSet, Epoch, Tile};
+use servo_msg::constellation_msg::PipelineId;
+use std::cell::Cell;
use windowing::{MouseWindowEvent, MouseWindowClickEvent, MouseWindowMouseDownEvent, MouseWindowMouseUpEvent};
-use compositing::quadtree::{Quadtree, Normal, Invalid, Hidden};
-use layers::layers::{ContainerLayerKind, ContainerLayer, TextureLayerKind, TextureLayer, TextureManager};
-use pipeline::Pipeline;
-use constellation::{SendableChildFrameTree, SendableFrameTree};
+
+#[cfg(not(target_os="macos"))]
+use layers::texturegl::TextureTarget2D;
/// The CompositorLayer represents an element on a page that has a unique scroll
/// or animation behavior. This can include absolute positioned elements, iframes, etc.
@@ -24,31 +30,42 @@ use constellation::{SendableChildFrameTree, SendableFrameTree};
pub struct CompositorLayer {
/// This layer's pipeline. BufferRequests and mouse events will be sent through this.
pipeline: Pipeline,
+
/// The size of the underlying page in page coordinates. This is an option
/// because we may not know the size of the page until layout is finished completely.
/// if we have no size yet, the layer is hidden until a size message is recieved.
page_size: Option<Size2D<f32>>,
+
/// The offset of the page due to scrolling. (0,0) is when the window sees the
/// top left corner of the page.
scroll_offset: Point2D<f32>,
+
/// This layer's children. These could be iframes or any element which
/// differs in scroll behavior from its parent. Each is associated with a
/// ContainerLayer which determines its position relative to its parent and
/// clipping rect. Children are stored in the order in which they are drawn.
children: ~[CompositorLayerChild],
+
/// This layer's quadtree. This is where all buffers are stored for this layer.
quadtree: MaybeQuadtree,
+
/// The root layer of this CompositorLayer's layer tree. Buffers are collected
/// from the quadtree and inserted here when the layer is painted to the screen.
root_layer: @mut ContainerLayer,
+
/// When set to true, this layer is ignored by its parents. This is useful for
/// soft deletion or when waiting on a page size.
hidden: bool,
+
/// A monotonically increasing counter that keeps track of the current epoch.
/// add_buffer() calls that don't match the current epoch will be ignored.
epoch: Epoch,
+
/// The behavior of this layer when a scroll message is received.
scroll_behavior: ScrollBehavior,
+
+ /// True if CPU rendering is enabled, false if we're using GPU rendering.
+ cpu_painting: bool,
}
/// Helper struct for keeping CompositorLayer children organized.
@@ -75,13 +92,16 @@ enum ScrollBehavior {
/// passed on to child layers.
FixedPosition,
}
-
impl CompositorLayer {
/// Creates a new CompositorLayer with an optional page size. If no page size is given,
/// the layer is initially hidden and initialized without a quadtree.
- pub fn new(pipeline: Pipeline, page_size: Option<Size2D<f32>>, tile_size: uint, max_mem: Option<uint>)
- -> CompositorLayer {
+ pub fn new(pipeline: Pipeline,
+ page_size: Option<Size2D<f32>>,
+ tile_size: uint,
+ max_mem: Option<uint>,
+ cpu_painting: bool)
+ -> CompositorLayer {
CompositorLayer {
pipeline: pipeline,
page_size: page_size,
@@ -89,8 +109,8 @@ impl CompositorLayer {
children: ~[],
quadtree: match page_size {
None => NoTree(tile_size, max_mem),
- Some(page_size) => Tree(Quadtree::new(page_size.width as uint,
- page_size.height as uint,
+ Some(page_size) => Tree(Quadtree::new(Size2D(page_size.width as uint,
+ page_size.height as uint),
tile_size,
max_mem)),
},
@@ -98,15 +118,18 @@ impl CompositorLayer {
hidden: true,
epoch: Epoch(0),
scroll_behavior: Scroll,
+ cpu_painting: cpu_painting,
}
}
/// Constructs a CompositorLayer tree from a frame tree.
pub fn from_frame_tree(frame_tree: SendableFrameTree,
tile_size: uint,
- max_mem: Option<uint>) -> CompositorLayer {
+ max_mem: Option<uint>,
+ cpu_painting: bool)
+ -> CompositorLayer {
let SendableFrameTree { pipeline, children } = frame_tree;
- let mut layer = CompositorLayer::new(pipeline, None, tile_size, max_mem);
+ let mut layer = CompositorLayer::new(pipeline, None, tile_size, max_mem, cpu_painting);
layer.children = (do children.move_iter().map |child| {
let SendableChildFrameTree { frame_tree, rect } = child;
let container = @mut ContainerLayer();
@@ -121,7 +144,10 @@ impl CompositorLayer {
None => {}
}
- let child_layer = ~CompositorLayer::from_frame_tree(frame_tree, tile_size, max_mem);
+ let child_layer = ~CompositorLayer::from_frame_tree(frame_tree,
+ tile_size,
+ max_mem,
+ cpu_painting);
container.add_child_start(ContainerLayerKind(child_layer.root_layer));
CompositorLayerChild {
@@ -137,7 +163,8 @@ impl CompositorLayer {
// the position of the layer relative to its parent. This also takes in a cursor position
// to see if the mouse is over child layers first. If a layer successfully scrolled, returns
// true; otherwise returns false, so a parent layer can scroll instead.
- pub fn scroll(&mut self, delta: Point2D<f32>, cursor: Point2D<f32>, window_size: Size2D<f32>) -> bool {
+ pub fn scroll(&mut self, delta: Point2D<f32>, cursor: Point2D<f32>, window_size: Size2D<f32>)
+ -> bool {
let cursor = cursor - self.scroll_offset;
for child in self.children.mut_iter().filter(|x| !x.child.hidden) {
match child.container.scissor {
@@ -218,7 +245,11 @@ impl CompositorLayer {
// Given the current window size, determine which tiles need to be (re)rendered
// and sends them off the the appropriate renderer.
// Returns a bool that is true if the scene should be repainted.
- pub fn get_buffer_request(&mut self, window_rect: Rect<f32>, scale: f32) -> bool {
+ pub fn get_buffer_request(&mut self,
+ graphics_context: &NativeCompositingGraphicsContext,
+ window_rect: Rect<f32>,
+ scale: f32)
+ -> bool {
let rect = Rect(Point2D(-self.scroll_offset.x + window_rect.origin.x,
-self.scroll_offset.y + window_rect.origin.y),
window_rect.size);
@@ -239,7 +270,7 @@ impl CompositorLayer {
}
}
if redisplay {
- self.build_layer_tree();
+ self.build_layer_tree(graphics_context);
}
let transform = |x: &mut CompositorLayerChild| -> bool {
match x.container.scissor {
@@ -252,7 +283,7 @@ impl CompositorLayer {
// to make the child_rect appear in coordinates local to it.
let child_rect = Rect(new_rect.origin.sub(&scissor.origin),
new_rect.size);
- x.child.get_buffer_request(child_rect, scale)
+ x.child.get_buffer_request(graphics_context, child_rect, scale)
}
None => {
false //Layer is offscreen
@@ -324,10 +355,10 @@ impl CompositorLayer {
new_size.height as uint)));
}
NoTree(tile_size, max_mem) => {
- self.quadtree = Tree(Quadtree::new(new_size.width as uint,
- new_size.height as uint,
+ self.quadtree = Tree(Quadtree::new(Size2D(new_size.width as uint,
+ new_size.height as uint),
tile_size,
- max_mem));
+ max_mem))
}
}
// Call scroll for bounds checking if the page shrunk. Use (-1, -1) as the cursor position
@@ -340,6 +371,23 @@ impl CompositorLayer {
self.resize_helper(pipeline_id, new_size, epoch)
}
}
+
+ // Returns whether the layer should be vertically flipped. and
+ #[cfg(target_os="macos")]
+ fn texture_flip_and_target(cpu_painting: bool, size: Size2D<uint>) -> (Flip, TextureTarget) {
+ let flip = if cpu_painting {
+ NoFlip
+ } else {
+ VerticalFlip
+ };
+
+ (flip, TextureTargetRectangle(size))
+ }
+
+ #[cfg(not(target_os="macos"))]
+ fn texture_flip_and_target(_: bool, _: Size2D<uint>) -> (Flip, TextureTarget) {
+ (NoFlip, TextureTarget2D)
+ }
// A helper method to resize sublayers.
fn resize_helper(&mut self, pipeline_id: PipelineId, new_size: Size2D<f32>, epoch: Epoch) -> bool {
@@ -355,10 +403,10 @@ impl CompositorLayer {
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,
+ child.quadtree = Tree(Quadtree::new(Size2D(new_size.width as uint,
+ new_size.height as uint),
tile_size,
- max_mem));
+ max_mem))
}
}
match child_node.container.scissor {
@@ -386,7 +434,7 @@ impl CompositorLayer {
// Collect buffers from the quadtree. This method IS NOT recursive, so child CompositorLayers
// are not rebuilt directly from this method.
- pub fn build_layer_tree(&mut self) {
+ pub fn build_layer_tree(&mut self, graphics_context: &NativeCompositingGraphicsContext) {
// Iterate over the children of the container layer.
let mut current_layer_child = self.root_layer.first_child;
@@ -409,21 +457,39 @@ impl CompositorLayer {
let all_tiles = quadtree.get_all_tiles();
for buffer in all_tiles.iter() {
debug!("osmain: compositing buffer rect %?", &buffer.rect);
-
+
+ let size = Size2D(buffer.screen_pos.size.width as int,
+ buffer.screen_pos.size.height as int);
+
// 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);
+
+ // Determine, in a platform-specific way, whether we should flip the texture
+ // and which target to use.
+ let (flip, target) =
+ CompositorLayer::texture_flip_and_target(self.cpu_painting,
+ buffer.screen_pos.size);
+
+ // Make a new texture and bind the layer buffer's surface to it.
+ let texture = Texture::new(target);
+ debug!("COMPOSITOR binding to native surface %d",
+ buffer.native_surface.get_id() as int);
+ buffer.native_surface.bind_to_texture(graphics_context, &texture, size);
+
+ // Make a texture layer and add it.
+ texture_layer = @mut TextureLayer::new(texture, buffer.screen_pos.size, flip);
self.root_layer.add_child_end(TextureLayerKind(texture_layer));
None
}
Some(TextureLayerKind(existing_texture_layer)) => {
texture_layer = existing_texture_layer;
- texture_layer.manager = @buffer.draw_target.clone() as @TextureManager;
-
+
+ let texture = &texture_layer.texture;
+ buffer.native_surface.bind_to_texture(graphics_context, texture, size);
+
// Move on to the next sibling.
do current_layer_child.unwrap().with_common |common| {
common.next_sibling
@@ -431,10 +497,9 @@ impl CompositorLayer {
}
Some(_) => fail!(~"found unexpected layer kind"),
};
-
- let rect = buffer.rect;
// Set the layer's transform.
+ let rect = buffer.rect;
let transform = identity().translate(rect.origin.x, rect.origin.y, 0.0);
let transform = transform.scale(rect.size.width, rect.size.height, 1.0);
texture_layer.common.set_transform(transform);
@@ -455,21 +520,32 @@ impl CompositorLayer {
}
};
}
-
-
}
- // Add LayerBuffers to the specified layer. Returns false if the layer is not found.
- // If the epoch of the message does not match the layer's epoch, the message is ignored.
- pub fn add_buffers(&mut self, pipeline_id: PipelineId, new_buffers: ~LayerBufferSet, epoch: Epoch) -> bool {
+ // Add LayerBuffers to the specified layer. Returns the layer buffer set back if the layer that
+ // matches the given pipeline ID was not found; otherwise returns None and consumes the layer
+ // buffer set.
+ //
+ // If the epoch of the message does not match the layer's epoch, the message is ignored, the
+ // layer buffer set is consumed, and None is returned.
+ pub fn add_buffers(&mut self,
+ graphics_context: &NativeCompositingGraphicsContext,
+ pipeline_id: PipelineId,
+ new_buffers: ~LayerBufferSet,
+ epoch: Epoch)
+ -> Option<~LayerBufferSet> {
let cell = Cell::new(new_buffers);
if self.pipeline.id == pipeline_id {
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);
self.pipeline.render_chan.send(UnusedBufferMsg(cell.take().buffers));
- return true;
+ return None;
}
- { // block here to prevent double mutable borrow of self
+ {
+ // Block here to prevent double mutable borrow of self.
let quadtree = match self.quadtree {
NoTree(*) => fail!("CompositorLayer: cannot add buffers, no quadtree initialized"),
Tree(ref mut quadtree) => quadtree,
@@ -486,22 +562,30 @@ impl CompositorLayer {
self.pipeline.render_chan.send(UnusedBufferMsg(unused_tiles));
}
}
- self.build_layer_tree();
- 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| {
- let buffers = cell.take();
- let result = x.add_buffers(pipeline_id, buffers.clone(), epoch);
- cell.put_back(buffers);
- result
- })
+ self.build_layer_tree(graphics_context);
+ return None;
}
+
+ // ID does not match ours, so recurse on descendents (including hidden children).
+ for child_layer in self.children.mut_iter() {
+ match child_layer.child.add_buffers(graphics_context,
+ pipeline_id,
+ cell.take(),
+ epoch) {
+ None => return None,
+ Some(buffers) => cell.put_back(buffers),
+ }
+ }
+
+ // Not found. Give the caller the buffers back.
+ Some(cell.take())
}
// 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,
+ graphics_context: &NativeCompositingGraphicsContext,
+ pipeline_id: PipelineId)
+ -> bool {
match self.children.iter().position(|x| x.child.pipeline.id == pipeline_id) {
Some(i) => {
let mut child = self.children.remove(i);
@@ -516,18 +600,16 @@ impl CompositorLayer {
}
}
}
- 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();
+
+ // Send back all tiles to renderer.
+ child.child.clear();
+
+ self.build_layer_tree(graphics_context);
true
}
None => {
- self.children.mut_iter().map(|x| &mut x.child).any(|x| x.delete(pipeline_id))
+ self.children.mut_iter().map(|x| &mut x.child)
+ .any(|x| x.delete(graphics_context, pipeline_id))
}
}
}
@@ -554,7 +636,11 @@ impl CompositorLayer {
container.common.set_transform(identity().translate(clipping_rect.origin.x,
clipping_rect.origin.y,
0.0));
- let child = ~CompositorLayer::new(pipeline, page_size, tile_size, max_mem);
+ let child = ~CompositorLayer::new(pipeline,
+ page_size,
+ tile_size,
+ max_mem,
+ self.cpu_painting);
container.add_child_start(ContainerLayerKind(child.root_layer));
self.children.push(CompositorLayerChild {
child: child,
@@ -582,4 +668,57 @@ impl CompositorLayer {
child.child.set_occlusions();
}
}
+
+ /// Destroys all quadtree tiles, sending the buffers back to the renderer to be destroyed or
+ /// reused.
+ fn clear(&mut self) {
+ match self.quadtree {
+ NoTree(*) => {}
+ Tree(ref mut quadtree) => {
+ let mut tiles = quadtree.collect_tiles();
+
+ // We have no way of knowing without a race whether the render task is even up and
+ // running, but mark the tiles as not leaking. If the render task died, then the
+ // tiles are going to be cleaned up.
+ for tile in tiles.mut_iter() {
+ tile.mark_wont_leak()
+ }
+
+ self.pipeline.render_chan.send(UnusedBufferMsg(tiles))
+ }
+ }
+ }
+
+ /// Destroys all quadtree tiles of all layers, including child layers, sending the buffers
+ /// back to the renderer to be destroyed or reused.
+ pub fn clear_all(&mut self) {
+ self.clear();
+
+ for kid in self.children.mut_iter() {
+ kid.child.clear_all()
+ }
+ }
+
+ /// Destroys all tiles of all layers, including children, *without* sending them back to the
+ /// renderer. You must call this only when the render task is destined to be going down;
+ /// otherwise, you will leak tiles.
+ ///
+ /// This is used during shutdown, when we know the render task is going away.
+ pub fn forget_all_tiles(&mut self) {
+ match self.quadtree {
+ NoTree(*) => {}
+ Tree(ref mut quadtree) => {
+ let tiles = quadtree.collect_tiles();
+ for tile in tiles.move_iter() {
+ let mut tile = tile;
+ tile.mark_wont_leak()
+ }
+ }
+ }
+
+ for kid in self.children.mut_iter() {
+ kid.child.forget_all_tiles();
+ }
+ }
}
+