Make compositor layer creation atomic

Instead of creating, sizing, and setting up layers using several
messages use only one. If the layer already exists, it will be updated
to reflect the new properties. The clip rect is still set in a separate
message, but that will be eliminated in a later commit.
This commit is contained in:
Martin Robinson 2014-07-08 09:49:26 -07:00
parent a9e5457588
commit 5e52023177
4 changed files with 196 additions and 243 deletions

View file

@ -3,9 +3,8 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use compositor_data::CompositorData;
use compositor_task::{Msg, CompositorTask, Exit, ChangeReadyState, SetUnRenderedColor};
use compositor_task::{SetIds, GetGraphicsMetadata, CreateRootCompositorLayerIfNecessary};
use compositor_task::{CreateDescendantCompositorLayerIfNecessary, SetLayerPageSize};
use compositor_task::{Msg, CompositorTask, Exit, ChangeReadyState, SetIds};
use compositor_task::{GetGraphicsMetadata, CreateOrUpdateRootLayer, CreateOrUpdateDescendantLayer};
use compositor_task::{SetLayerClipRect, Paint, ScrollFragmentPoint, LoadComplete};
use compositor_task::{ShutdownComplete, ChangeRenderState};
use constellation::SendableFrameTree;
@ -279,10 +278,6 @@ impl IOCompositor {
self.change_render_state(render_state);
}
(Ok(SetUnRenderedColor(pipeline_id, layer_id, color)), NotShuttingDown) => {
self.set_unrendered_color(pipeline_id, layer_id, color);
}
(Ok(SetIds(frame_tree, response_chan, new_constellation_chan)), _) => {
self.set_ids(frame_tree, response_chan, new_constellation_chan);
}
@ -291,27 +286,28 @@ impl IOCompositor {
chan.send(Some(azure_hl::current_graphics_metadata()));
}
(Ok(CreateRootCompositorLayerIfNecessary(pipeline_id, layer_id, size, color)),
(Ok(CreateOrUpdateRootLayer(pipeline_id, layer_id, epoch, size, color)),
NotShuttingDown) => {
self.create_root_compositor_layer_if_necessary(pipeline_id,
layer_id,
size,
color);
self.create_or_update_root_layer(pipeline_id,
layer_id,
epoch,
size,
color);
}
(Ok(CreateDescendantCompositorLayerIfNecessary(pipeline_id,
layer_id,
rect,
scroll_behavior)),
(Ok(CreateOrUpdateDescendantLayer(pipeline_id,
layer_id,
epoch,
rect,
scroll_behavior,
color)),
NotShuttingDown) => {
self.create_descendant_compositor_layer_if_necessary(pipeline_id,
layer_id,
rect,
scroll_behavior);
}
(Ok(SetLayerPageSize(pipeline_id, layer_id, new_size, epoch)), NotShuttingDown) => {
self.set_layer_page_size(pipeline_id, layer_id, new_size, epoch);
self.create_or_update_descendant_layer(pipeline_id,
layer_id,
epoch,
rect,
scroll_behavior,
color);
}
(Ok(SetLayerClipRect(pipeline_id, layer_id, new_rect)), NotShuttingDown) => {
@ -346,20 +342,6 @@ impl IOCompositor {
}
}
fn set_unrendered_color(&mut self, pipeline_id: PipelineId, layer_id: LayerId, color: Color) {
match self.scene.root {
Some(ref root_layer) => {
match CompositorData::find_layer_with_pipeline_and_layer_id(root_layer.clone(),
pipeline_id,
layer_id) {
Some(ref layer) => CompositorData::set_unrendered_color(layer.clone(), color),
None => { }
}
}
None => { }
}
}
fn set_ids(&mut self,
frame_tree: SendableFrameTree,
response_chan: Sender<()>,
@ -373,40 +355,67 @@ impl IOCompositor {
self.send_window_size();
}
fn create_root_compositor_layer_if_necessary(&mut self,
id: PipelineId,
layer_id: LayerId,
size: Size2D<f32>,
unrendered_color: Color) {
let (root_pipeline, root_layer_id) = match self.scene.root {
Some(ref root_layer) if root_layer.extra_data.borrow().pipeline.id == id => {
(root_layer.extra_data.borrow().pipeline.clone(),
CompositorData::id_of_first_child(root_layer.clone()))
}
_ => {
match self.root_pipeline {
Some(ref root_pipeline) => {
(root_pipeline.clone(), LayerId::null())
},
_ => fail!("Compositor: Received new layer without initialized pipeline"),
}
}
};
fn update_layer_if_exists(&mut self,
pipeline_id: PipelineId,
layer_id: LayerId,
epoch: Epoch,
rect: Rect<f32>,
unrendered_color: Color)
-> bool {
if layer_id != root_layer_id {
match self.scene.root {
Some(ref root_layer) => {
match CompositorData::find_layer_with_pipeline_and_layer_id(root_layer.clone(),
pipeline_id,
layer_id) {
Some(existing_layer) => {
CompositorData::update_layer(existing_layer.clone(),
epoch,
rect,
unrendered_color);
true
}
None => false,
}
}
None => false,
}
}
fn create_or_update_root_layer(&mut self,
pipeline_id: PipelineId,
layer_id: LayerId,
epoch: Epoch,
size: Size2D<f32>,
unrendered_color: Color) {
let new_root_rect = Rect(Point2D(0f32, 0f32), size);
let need_new_root_layer = !self.update_layer_if_exists(pipeline_id,
layer_id,
epoch,
new_root_rect,
unrendered_color);
if need_new_root_layer {
let root_pipeline = match self.root_pipeline {
Some(ref root_pipeline) => root_pipeline.clone(),
None => fail!("Compositor: Making new layer without initialized pipeline"),
};
let new_compositor_data = CompositorData::new_root(root_pipeline,
epoch,
size,
self.opts.cpu_painting);
self.opts.cpu_painting,
unrendered_color);
let new_root = Rc::new(Layer::new(size,
self.opts.tile_size,
new_compositor_data));
new_root.extra_data.borrow_mut().unrendered_color = unrendered_color;
CompositorData::add_child_if_necessary(new_root.clone(),
layer_id,
Rect(Point2D(0f32, 0f32), size),
size,
Scrollable);
CompositorData::add_child(new_root.clone(),
layer_id,
epoch,
new_root_rect,
size,
Scrollable,
unrendered_color);
// Release all tiles from the layer before dropping it.
match self.scene.root {
@ -416,14 +425,41 @@ impl IOCompositor {
self.scene.root = Some(new_root);
}
self.scroll_layer_to_fragment_point_if_necessary(pipeline_id, layer_id);
self.ask_for_tiles();
}
fn create_descendant_compositor_layer_if_necessary(&mut self,
pipeline_id: PipelineId,
layer_id: LayerId,
rect: Rect<f32>,
scroll_policy: ScrollPolicy) {
fn create_or_update_descendant_layer(&mut self,
pipeline_id: PipelineId,
layer_id: LayerId,
epoch: Epoch,
rect: Rect<f32>,
scroll_policy: ScrollPolicy,
unrendered_color: Color) {
if !self.update_layer_if_exists(pipeline_id,
layer_id,
epoch,
rect,
unrendered_color) {
self.create_descendant_layer(pipeline_id,
layer_id,
epoch,
rect,
scroll_policy,
unrendered_color);
}
self.scroll_layer_to_fragment_point_if_necessary(pipeline_id, layer_id);
self.ask_for_tiles();
}
fn create_descendant_layer(&self,
pipeline_id: PipelineId,
layer_id: LayerId,
epoch: Epoch,
rect: Rect<f32>,
scroll_policy: ScrollPolicy,
unrendered_color: Color) {
match self.scene.root {
Some(ref root_layer) => {
let parent_layer_id = root_layer.extra_data.borrow().id;
@ -432,11 +468,13 @@ impl IOCompositor {
parent_layer_id) {
Some(ref mut parent_layer) => {
let page_size = root_layer.extra_data.borrow().page_size.unwrap();
CompositorData::add_child_if_necessary(parent_layer.clone(),
layer_id,
rect,
page_size,
scroll_policy);
CompositorData::add_child(parent_layer.clone(),
layer_id,
epoch,
rect,
page_size,
scroll_policy,
unrendered_color);
}
None => {
fail!("Compositor: couldn't find parent layer");
@ -445,8 +483,6 @@ impl IOCompositor {
}
None => fail!("Compositor: Received new layer without initialized pipeline")
}
self.ask_for_tiles();
}
/// The size of the content area in CSS px at the current zoom level
@ -467,33 +503,24 @@ impl IOCompositor {
}));
}
fn set_layer_page_size(&mut self,
pipeline_id: PipelineId,
layer_id: LayerId,
new_size: Size2D<f32>,
epoch: Epoch) {
fn scroll_layer_to_fragment_point_if_necessary(&mut self,
pipeline_id: PipelineId,
layer_id: LayerId) {
let page_window = self.page_window();
let (ask, move): (bool, bool) = match self.scene.root {
Some(ref layer) => {
CompositorData::resize(layer.clone(),
pipeline_id,
layer_id,
new_size,
page_window,
epoch);
let move = self.fragment_point.take().map_or(false, |point| {
CompositorData::move(layer.clone(), pipeline_id, layer_id, point, page_window)
});
(true, move)
let needs_recomposite = match self.scene.root {
Some(ref mut root_layer) => {
self.fragment_point.take().map_or(false, |fragment_point| {
CompositorData::move(root_layer.clone(),
pipeline_id,
layer_id,
fragment_point,
page_window)
})
}
None => (false, false)
None => fail!("Compositor: Tried to scroll to fragment without root layer."),
};
if ask {
self.recomposite_if(move);
self.ask_for_tiles();
}
self.recomposite_if(needs_recomposite);
}
fn set_layer_clip_rect(&mut self,

View file

@ -13,7 +13,6 @@ use geom::point::{Point2D, TypedPoint2D};
use geom::rect::{Rect, TypedRect};
use geom::size::{Size2D, TypedSize2D};
use gfx::render_task::{ReRenderMsg, UnusedBufferMsg};
use gfx;
use layers::layers::{Layer, Flip, LayerBuffer, LayerBufferSet, NoFlip, TextureLayer};
use layers::quadtree::{Tile, Normal, Hidden};
use layers::platform::surface::{NativeCompositingGraphicsContext, NativeSurfaceMethods};
@ -103,71 +102,65 @@ impl Clampable for f32 {
impl CompositorData {
pub fn new(pipeline: CompositionPipeline,
layer_id: LayerId,
epoch: Epoch,
bounds: Rect<f32>,
page_size: Option<Size2D<f32>>,
cpu_painting: bool,
wants_scroll_events: WantsScrollEventsFlag,
scroll_policy: ScrollPolicy,
hidden: bool) -> CompositorData {
unrendered_color: Color)
-> CompositorData {
CompositorData {
pipeline: pipeline,
id: layer_id,
scroll_offset: TypedPoint2D(0f32, 0f32),
bounds: bounds,
page_size: page_size,
hidden: hidden,
hidden: false,
wants_scroll_events: wants_scroll_events,
scroll_policy: scroll_policy,
cpu_painting: cpu_painting,
unrendered_color: gfx::color::rgba(0.0, 0.0, 0.0, 0.0),
unrendered_color: unrendered_color,
scissor: None,
epoch: Epoch(0),
epoch: epoch,
}
}
pub fn new_root(pipeline: CompositionPipeline,
epoch: Epoch,
page_size: Size2D<f32>,
cpu_painting: bool) -> CompositorData {
cpu_painting: bool,
unrendered_color: Color) -> CompositorData {
CompositorData::new(pipeline,
LayerId::null(),
epoch,
Rect(Point2D(0f32, 0f32), page_size),
Some(page_size),
cpu_painting,
WantsScrollEvents,
FixedPosition,
false)
}
pub fn id_of_first_child(layer: Rc<Layer<CompositorData>>) -> LayerId {
layer.children().iter().next().expect("no first child!").extra_data.borrow().id
unrendered_color)
}
/// Adds a child layer to the layer with the given ID and the given pipeline, if it doesn't
/// exist yet. The child layer will have the same pipeline, tile size, memory limit, and CPU
/// painting status as its parent.
pub fn add_child_if_necessary(layer: Rc<Layer<CompositorData>>,
child_layer_id: LayerId,
rect: Rect<f32>,
page_size: Size2D<f32>,
scroll_policy: ScrollPolicy) {
// See if we've already made this child layer.
let pipeline_id = layer.extra_data.borrow().pipeline.id;
if layer.children().iter().any(|kid| {
kid.extra_data.borrow().pipeline.id == pipeline_id &&
kid.extra_data.borrow().id == child_layer_id
}) {
return;
}
pub fn add_child(layer: Rc<Layer<CompositorData>>,
child_layer_id: LayerId,
epoch: Epoch,
rect: Rect<f32>,
page_size: Size2D<f32>,
scroll_policy: ScrollPolicy,
unrendered_color: Color) {
let new_compositor_data = CompositorData::new(layer.extra_data.borrow().pipeline.clone(),
child_layer_id,
epoch,
rect,
Some(page_size),
layer.extra_data.borrow().cpu_painting,
DoesntWantScrollEvents,
scroll_policy,
false);
unrendered_color);
let new_kid = Rc::new(Layer::new(page_size,
Layer::tile_size(layer.clone()),
new_compositor_data));
@ -423,46 +416,45 @@ impl CompositorData {
}
}
// Set the layer's page size. This signals that the renderer is ready for BufferRequests.
// If the layer is hidden and has a defined clipping rect, unhide it.
// This method returns false if the specified layer is not found.
pub fn resize(layer: Rc<Layer<CompositorData>>,
pipeline_id: PipelineId,
layer_id: LayerId,
new_size: Size2D<f32>,
window_size: TypedSize2D<PagePx, f32>,
epoch: Epoch)
-> bool {
debug!("compositor_data: starting resize()");
if layer.extra_data.borrow().pipeline.id != pipeline_id ||
layer.extra_data.borrow().id != layer_id {
return CompositorData::resize_helper(layer.clone(),
pipeline_id,
layer_id,
new_size,
epoch)
}
debug!("compositor_data: layer found for resize()");
pub fn update_layer(layer: Rc<Layer<CompositorData>>,
epoch: Epoch,
rect: Rect<f32>,
unrendered_color: Color) {
layer.extra_data.borrow_mut().epoch = epoch;
layer.extra_data.borrow_mut().unrendered_color = unrendered_color;
CompositorData::resize(layer.clone(), rect.size);
}
// Resize and unhide a pre-existing layer. A new layer's size is set during creation.
fn resize(layer: Rc<Layer<CompositorData>>,
new_size: Size2D<f32>) {
debug!("compositor_data: starting resize_helper()");
debug!("compositor_data: layer found for resize_helper()");
layer.extra_data.borrow_mut().page_size = Some(new_size);
let unused_buffers = Layer::resize(layer.clone(), new_size);
if !unused_buffers.is_empty() {
let _ = layer.extra_data.borrow().pipeline
.render_chan
.send_opt(UnusedBufferMsg(unused_buffers));
let msg = UnusedBufferMsg(unused_buffers);
let _ = layer.extra_data.borrow().pipeline.render_chan.send_opt(msg);
}
let scissor_clone = layer.extra_data.borrow().scissor.clone();
match scissor_clone {
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.
let size: TypedSize2D<PagePx, f32> = Size2D::from_untyped(&scissor.size);
CompositorData::handle_scroll_event(layer.clone(),
TypedPoint2D(0f32, 0f32),
TypedPoint2D(-1f32, -1f32),
size);
layer.extra_data.borrow_mut().hidden = false;
}
None => {} // Nothing to do
}
// 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.
CompositorData::handle_scroll_event(layer.clone(),
TypedPoint2D(0f32, 0f32),
TypedPoint2D(-1f32, -1f32),
window_size);
layer.extra_data.borrow_mut().hidden = false;
CompositorData::set_occlusions(layer.clone());
true
}
pub fn move(layer: Rc<Layer<CompositorData>>,
@ -537,8 +529,6 @@ impl CompositorData {
(NoFlip, TextureTarget2D)
}
fn find_child_with_pipeline_and_layer_id(layer: Rc<Layer<CompositorData>>,
pipeline_id: PipelineId,
layer_id: LayerId)
@ -573,60 +563,6 @@ impl CompositorData {
return None;
}
// A helper method to resize sublayers.
fn resize_helper(layer: Rc<Layer<CompositorData>>,
pipeline_id: PipelineId,
layer_id: LayerId,
new_size: Size2D<f32>,
epoch: Epoch)
-> bool {
debug!("compositor_data: starting resize_helper()");
let found = match CompositorData::find_child_with_pipeline_and_layer_id(layer.clone(),
pipeline_id,
layer_id) {
Some(child) => {
debug!("compositor_data: layer found for resize_helper()");
child.extra_data.borrow_mut().epoch = epoch;
child.extra_data.borrow_mut().page_size = Some(new_size);
let unused_buffers = Layer::resize(child.clone(), new_size);
if !unused_buffers.is_empty() {
let msg = UnusedBufferMsg(unused_buffers);
let _ = child.extra_data.borrow().pipeline.render_chan.send_opt(msg);
}
let scissor_clone = child.extra_data.borrow().scissor.clone();
match scissor_clone {
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.
let size: TypedSize2D<PagePx, f32> = Size2D::from_untyped(&scissor.size);
CompositorData::handle_scroll_event(child.clone(),
TypedPoint2D(0f32, 0f32),
TypedPoint2D(-1f32, -1f32),
size);
child.extra_data.borrow_mut().hidden = false;
}
None => {} // Nothing to do
}
true
}
None => false,
};
if found { // Boolean flag to get around double borrow of self
CompositorData::set_occlusions(layer.clone());
return true
}
// If we got here, the layer's ID does not match ours, so recurse on descendents (including
// hidden children).
layer.children().iter().any(|kid| {
CompositorData::resize_helper(kid.clone(), pipeline_id, layer_id, new_size, epoch)
})
}
// Collect buffers from the quadtree. This method IS NOT recursive, so child layers
// are not rebuilt directly from this method.
pub fn build_layer_tree(layer: Rc<Layer<CompositorData>>,
@ -766,9 +702,5 @@ impl CompositorData {
CompositorData::forget_all_tiles(kid.clone());
}
}
pub fn set_unrendered_color(layer: Rc<Layer<CompositorData>>, color: Color) {
layer.extra_data.borrow_mut().unrendered_color = color;
}
}

View file

@ -92,23 +92,22 @@ impl RenderListener for CompositorChan {
metadata.position.size.height as f32);
let rect = Rect(origin, size);
if first {
self.chan.send(CreateRootCompositorLayerIfNecessary(pipeline_id,
metadata.id,
size,
metadata.background_color));
self.chan.send(CreateOrUpdateRootLayer(pipeline_id,
metadata.id,
epoch,
size,
metadata.background_color));
first = false
} else {
self.chan
.send(CreateDescendantCompositorLayerIfNecessary(pipeline_id,
metadata.id,
rect,
metadata.scroll_policy));
.send(CreateOrUpdateDescendantLayer(pipeline_id,
metadata.id,
epoch,
rect,
metadata.scroll_policy,
metadata.background_color));
}
self.chan.send(SetUnRenderedColor(pipeline_id,
metadata.id,
metadata.background_color));
self.chan.send(SetLayerPageSize(pipeline_id, metadata.id, size, epoch));
self.chan.send(SetLayerClipRect(pipeline_id, metadata.id, rect));
}
}
@ -161,12 +160,10 @@ pub enum Msg {
/// Tells the compositor to create the root layer for a pipeline if necessary (i.e. if no layer
/// with that ID exists).
CreateRootCompositorLayerIfNecessary(PipelineId, LayerId, Size2D<f32>, Color),
CreateOrUpdateRootLayer(PipelineId, LayerId, Epoch, Size2D<f32>, Color),
/// Tells the compositor to create a descendant layer for a pipeline if necessary (i.e. if no
/// layer with that ID exists).
CreateDescendantCompositorLayerIfNecessary(PipelineId, LayerId, Rect<f32>, ScrollPolicy),
/// Alerts the compositor that the specified layer has changed size.
SetLayerPageSize(PipelineId, LayerId, Size2D<f32>, Epoch),
CreateOrUpdateDescendantLayer(PipelineId, LayerId, Epoch, Rect<f32>, ScrollPolicy, Color),
/// Alerts the compositor that the specified layer's clipping rect has changed.
SetLayerClipRect(PipelineId, LayerId, Rect<f32>),
/// Scroll a page in a window
@ -179,8 +176,6 @@ pub enum Msg {
ChangeRenderState(RenderState),
/// Sets the channel to the current layout and render tasks, along with their id
SetIds(SendableFrameTree, Sender<()>, ConstellationChan),
/// Sets the color of unrendered content for a layer.
SetUnRenderedColor(PipelineId, LayerId, Color),
/// The load of a page for a given URL has completed.
LoadComplete(PipelineId, Url),
}

View file

@ -2,9 +2,8 @@
* 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 compositor_task::{Msg, Exit, ChangeReadyState, SetUnRenderedColor};
use compositor_task::{SetIds, GetGraphicsMetadata, CreateRootCompositorLayerIfNecessary};
use compositor_task::{CreateDescendantCompositorLayerIfNecessary, SetLayerPageSize};
use compositor_task::{Msg, Exit, ChangeReadyState, SetIds};
use compositor_task::{GetGraphicsMetadata, CreateOrUpdateRootLayer, CreateOrUpdateDescendantLayer};
use compositor_task::{SetLayerClipRect, Paint, ScrollFragmentPoint, LoadComplete};
use compositor_task::{ShutdownComplete, ChangeRenderState};
@ -89,11 +88,11 @@ impl NullCompositor {
// we'll notice and think about whether it needs a response, like
// SetIds.
CreateRootCompositorLayerIfNecessary(..) |
CreateDescendantCompositorLayerIfNecessary(..) | SetLayerPageSize(..) |
CreateOrUpdateRootLayer(..) |
CreateOrUpdateDescendantLayer(..) |
SetLayerClipRect(..) | Paint(..) |
ChangeReadyState(..) | ChangeRenderState(..) | ScrollFragmentPoint(..) |
SetUnRenderedColor(..) | LoadComplete(..) => ()
LoadComplete(..) => ()
}
}
}