mirror of
https://github.com/servo/servo.git
synced 2025-06-19 14:48:59 +01:00
Implement epochs; fix integration bugs
This commit is contained in:
parent
f2c00f7e28
commit
eb6973c7dc
9 changed files with 114 additions and 48 deletions
|
@ -32,7 +32,7 @@ pub struct RenderLayer {
|
|||
|
||||
pub enum Msg {
|
||||
RenderMsg(RenderLayer),
|
||||
ReRenderMsg(~[BufferRequest], f32, PipelineId),
|
||||
ReRenderMsg(~[BufferRequest], f32, PipelineId, uint),
|
||||
PaintPermissionGranted,
|
||||
PaintPermissionRevoked,
|
||||
ExitMsg(Chan<()>),
|
||||
|
@ -89,6 +89,8 @@ struct RenderTask<C> {
|
|||
paint_permission: bool,
|
||||
/// Cached copy of last layers rendered
|
||||
last_paint_msg: Option<(arc::Arc<LayerBufferSet>, Size2D<uint>)>,
|
||||
/// A counter for epoch messages
|
||||
epoch_counter: uint,
|
||||
}
|
||||
|
||||
impl<C: RenderListener + Send> RenderTask<C> {
|
||||
|
@ -123,6 +125,7 @@ impl<C: RenderListener + Send> RenderTask<C> {
|
|||
|
||||
paint_permission: false,
|
||||
last_paint_msg: None,
|
||||
epoch_counter: 0,
|
||||
};
|
||||
|
||||
render_task.start();
|
||||
|
@ -136,18 +139,24 @@ impl<C: RenderListener + Send> RenderTask<C> {
|
|||
match self.port.recv() {
|
||||
RenderMsg(render_layer) => {
|
||||
if self.paint_permission {
|
||||
self.compositor.set_layer_page_size(self.id, render_layer.size);
|
||||
self.epoch_counter += 1;
|
||||
self.compositor.set_layer_page_size(self.id, render_layer.size, self.epoch_counter);
|
||||
}
|
||||
self.render_layer = Some(render_layer);
|
||||
}
|
||||
ReRenderMsg(tiles, scale, id) => {
|
||||
ReRenderMsg(tiles, scale, id, epoch) => {
|
||||
if self.epoch_counter == epoch {
|
||||
self.render(tiles, scale, id);
|
||||
} else {
|
||||
debug!("renderer epoch mismatch: %? != %?", self.epoch_counter, epoch);
|
||||
}
|
||||
}
|
||||
PaintPermissionGranted => {
|
||||
self.paint_permission = true;
|
||||
match self.render_layer {
|
||||
Some(ref render_layer) => {
|
||||
self.compositor.set_layer_page_size(self.id, render_layer.size);
|
||||
self.epoch_counter += 1;
|
||||
self.compositor.set_layer_page_size(self.id, render_layer.size, self.epoch_counter);
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
|
@ -235,7 +244,7 @@ impl<C: RenderListener + Send> RenderTask<C> {
|
|||
|
||||
debug!("render_task: returning surface");
|
||||
if self.paint_permission {
|
||||
self.compositor.paint(id, layer_buffer_set.clone());
|
||||
self.compositor.paint(id, layer_buffer_set.clone(), self.epoch_counter);
|
||||
}
|
||||
debug!("caching paint msg");
|
||||
self.last_paint_msg = Some((layer_buffer_set, render_layer.size));
|
||||
|
|
|
@ -43,6 +43,9 @@ pub struct CompositorLayer {
|
|||
/// 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: uint,
|
||||
}
|
||||
|
||||
/// Helper struct for keeping CompositorLayer children organized.
|
||||
|
@ -79,7 +82,8 @@ impl CompositorLayer {
|
|||
max_mem)),
|
||||
},
|
||||
root_layer: @mut ContainerLayer(),
|
||||
hidden: true,
|
||||
hidden: page_size.is_none(),
|
||||
epoch: 0,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -89,20 +93,38 @@ impl CompositorLayer {
|
|||
max_mem: Option<uint>) -> CompositorLayer {
|
||||
let SendableFrameTree { pipeline, children } = frame_tree;
|
||||
let mut layer = CompositorLayer::new(pipeline, None, tile_size, max_mem);
|
||||
layer.children = (do children.consume_iter().transform |child| {
|
||||
layer.children = (do children.move_iter().map |child| {
|
||||
let SendableChildFrameTree { frame_tree, rect } = child;
|
||||
let container = @mut ContainerLayer();
|
||||
container.scissor = rect;
|
||||
match rect {
|
||||
Some(rect) => {
|
||||
container.scissor = Some(Rect(Point2D(100f32, 200f32), Size2D(700f32, 800f32)));
|
||||
container.common.transform = identity().translate(100f32, 200f32, 0f32);
|
||||
|
||||
// FIXME: The top two lines are temporary until layout window sizes are fixed.
|
||||
// When they are, uncomment the next 2 lines:
|
||||
|
||||
// container.scissor = Some(rect);
|
||||
// container.common.transform = identity().translate(rect.origin.x,
|
||||
// rect.origin.y,
|
||||
// 0f32);
|
||||
|
||||
}
|
||||
None => {}
|
||||
};
|
||||
|
||||
let child_layer = ~CompositorLayer::from_frame_tree(frame_tree, tile_size, max_mem);
|
||||
container.add_child(ContainerLayerKind(child_layer.root_layer));
|
||||
|
||||
CompositorLayerChild {
|
||||
child: ~CompositorLayer::from_frame_tree(frame_tree,
|
||||
tile_size,
|
||||
max_mem),
|
||||
child: child_layer,
|
||||
container: container,
|
||||
}
|
||||
}).collect();
|
||||
layer
|
||||
}
|
||||
|
||||
|
||||
// Move the layer by as relative specified amount in page coordinates. Does not change
|
||||
// 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
|
||||
|
@ -195,7 +217,7 @@ impl CompositorLayer {
|
|||
let (request, r) = quadtree.get_tile_rects_page(rect, scale);
|
||||
redisplay = r; // workaround to make redisplay visible outside block
|
||||
if !request.is_empty() {
|
||||
self.pipeline.render_chan.send(ReRenderMsg(request, scale, self.pipeline.id.clone()));
|
||||
self.pipeline.render_chan.send(ReRenderMsg(request, scale, self.pipeline.id.clone(), self.epoch));
|
||||
}
|
||||
}
|
||||
if redisplay {
|
||||
|
@ -230,7 +252,7 @@ impl CompositorLayer {
|
|||
// If the layer is hidden and has a defined page size, unhide it.
|
||||
// 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 {
|
||||
for child_node in self.children.iter() {
|
||||
for child_node in self.children.mut_iter() {
|
||||
if pipeline_id != child_node.child.pipeline.id {
|
||||
loop;
|
||||
}
|
||||
|
@ -254,8 +276,9 @@ impl CompositorLayer {
|
|||
// 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(&mut self, pipeline_id: PipelineId, new_size: Size2D<f32>, window_size: Size2D<f32>) -> bool {
|
||||
pub fn resize(&mut self, pipeline_id: PipelineId, new_size: Size2D<f32>, window_size: Size2D<f32>, epoch: uint) -> bool {
|
||||
if self.pipeline.id == pipeline_id {
|
||||
self.epoch = epoch;
|
||||
self.page_size = Some(new_size);
|
||||
// TODO: might get buffers back here
|
||||
match self.quadtree {
|
||||
|
@ -271,16 +294,17 @@ impl CompositorLayer {
|
|||
self.hidden = false;
|
||||
return true;
|
||||
}
|
||||
self.resize_helper(pipeline_id, new_size)
|
||||
self.resize_helper(pipeline_id, new_size, epoch)
|
||||
}
|
||||
|
||||
// A helper method to resize sublayers.
|
||||
fn resize_helper(&mut self, pipeline_id: PipelineId, new_size: Size2D<f32>) -> bool {
|
||||
for self.children.mut_iter().advance |child_node| {
|
||||
fn resize_helper(&mut self, pipeline_id: PipelineId, new_size: Size2D<f32>, epoch: uint) -> bool {
|
||||
for child_node in self.children.mut_iter() {
|
||||
if pipeline_id != child_node.child.pipeline.id {
|
||||
loop;
|
||||
}
|
||||
let child = &mut child_node.child;
|
||||
child.epoch = epoch;
|
||||
child.page_size = Some(new_size);
|
||||
// TODO: might get buffers back here
|
||||
match child.quadtree {
|
||||
|
@ -303,7 +327,7 @@ impl CompositorLayer {
|
|||
}
|
||||
|
||||
// ID does not match ours, so recurse on descendents (including hidden children)
|
||||
self.children.mut_iter().transform(|x| &mut x.child).any(|x| x.resize_helper(pipeline_id, new_size))
|
||||
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
|
||||
|
@ -381,8 +405,14 @@ impl CompositorLayer {
|
|||
}
|
||||
|
||||
// Add LayerBuffers to the specified layer. Returns false if the layer is not found.
|
||||
pub fn add_buffers(&mut self, pipeline_id: PipelineId, new_buffers: &LayerBufferSet) -> bool {
|
||||
// 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: uint) -> bool {
|
||||
if self.pipeline.id == pipeline_id {
|
||||
if self.epoch != epoch {
|
||||
debug!("compositor epoch mismatch: %? != %?, id: %?", self.epoch, epoch, self.pipeline.id);
|
||||
// TODO: send buffers back
|
||||
return true;
|
||||
}
|
||||
{ // block here to prevent double mutable borrow of self
|
||||
let quadtree = match self.quadtree {
|
||||
NoTree(_, _) => fail!("CompositorLayer: cannot get buffer request for %?,
|
||||
|
@ -400,7 +430,7 @@ impl CompositorLayer {
|
|||
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.add_buffers(pipeline_id, new_buffers))
|
||||
self.children.mut_iter().map(|x| &mut x.child).any(|x| x.add_buffers(pipeline_id, new_buffers, epoch))
|
||||
}
|
||||
|
||||
// Deletes a specified sublayer, including hidden children. Returns false if the layer is not found.
|
||||
|
|
|
@ -79,17 +79,17 @@ impl RenderListener for CompositorChan {
|
|||
port.recv()
|
||||
}
|
||||
|
||||
fn paint(&self, id: PipelineId, layer_buffer_set: arc::Arc<LayerBufferSet>) {
|
||||
self.chan.send(Paint(id, layer_buffer_set))
|
||||
fn paint(&self, id: PipelineId, layer_buffer_set: arc::Arc<LayerBufferSet>, epoch: uint) {
|
||||
self.chan.send(Paint(id, layer_buffer_set, epoch))
|
||||
}
|
||||
|
||||
fn new_layer(&self, id: PipelineId, page_size: Size2D<uint>) {
|
||||
let Size2D { width, height } = page_size;
|
||||
self.chan.send(NewLayer(id, Size2D(width as f32, height as f32)))
|
||||
}
|
||||
fn set_layer_page_size(&self, id: PipelineId, page_size: Size2D<uint>) {
|
||||
fn set_layer_page_size(&self, id: PipelineId, page_size: Size2D<uint>, epoch: uint) {
|
||||
let Size2D { width, height } = page_size;
|
||||
self.chan.send(SetLayerPageSize(id, Size2D(width as f32, height as f32)))
|
||||
self.chan.send(SetLayerPageSize(id, Size2D(width as f32, height as f32), epoch))
|
||||
}
|
||||
fn set_layer_clip_rect(&self, id: PipelineId, new_rect: Rect<uint>) {
|
||||
let new_rect = Rect(Point2D(new_rect.origin.x as f32,
|
||||
|
@ -136,11 +136,10 @@ pub enum Msg {
|
|||
/// Requests the compositors GL context.
|
||||
GetGLContext(Chan<AzGLContext>),
|
||||
|
||||
// TODO: Attach epochs to these messages
|
||||
/// Alerts the compositor that there is a new layer to be rendered.
|
||||
NewLayer(PipelineId, Size2D<f32>),
|
||||
/// Alerts the compositor that the specified layer's page has changed size.
|
||||
SetLayerPageSize(PipelineId, Size2D<f32>),
|
||||
SetLayerPageSize(PipelineId, Size2D<f32>, uint),
|
||||
/// Alerts the compositor that the specified layer's clipping rect has changed.
|
||||
SetLayerClipRect(PipelineId, Rect<f32>),
|
||||
/// Alerts the compositor that the specified layer has been deleted.
|
||||
|
@ -149,7 +148,7 @@ pub enum Msg {
|
|||
InvalidateRect(PipelineId, Rect<uint>),
|
||||
|
||||
/// Requests that the compositor paint the given layer buffer set for the given page size.
|
||||
Paint(PipelineId, arc::Arc<LayerBufferSet>),
|
||||
Paint(PipelineId, arc::Arc<LayerBufferSet>, uint),
|
||||
/// Alerts the compositor to the current status of page loading.
|
||||
ChangeReadyState(ReadyState),
|
||||
/// Alerts the compositor to the current status of rendering.
|
||||
|
@ -235,8 +234,12 @@ impl CompositorTask {
|
|||
let window_size_page = Size2D(window_size.width as f32 / world_zoom,
|
||||
window_size.height as f32 / world_zoom);
|
||||
for layer in compositor_layer.mut_iter() {
|
||||
if !layer.hidden {
|
||||
recomposite = layer.get_buffer_request(Rect(Point2D(0f32, 0f32), window_size_page),
|
||||
world_zoom) || recomposite;
|
||||
} else {
|
||||
debug!("layer is hidden!"); //eschweic
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -298,13 +301,12 @@ impl CompositorTask {
|
|||
ask_for_tiles();
|
||||
}
|
||||
|
||||
SetLayerPageSize(id, new_size) => {
|
||||
println(fmt!("Compositor: id %? sent new layer of size %?", id, new_size));
|
||||
SetLayerPageSize(id, new_size, epoch) => {
|
||||
match compositor_layer {
|
||||
Some(ref mut layer) => {
|
||||
let page_window = Size2D(window_size.width as f32 / world_zoom,
|
||||
window_size.height as f32 / world_zoom);
|
||||
assert!(layer.resize(id, new_size, page_window));
|
||||
assert!(layer.resize(id, new_size, page_window, epoch));
|
||||
ask_for_tiles();
|
||||
}
|
||||
None => {}
|
||||
|
@ -331,12 +333,12 @@ impl CompositorTask {
|
|||
}
|
||||
}
|
||||
|
||||
Paint(id, new_layer_buffer_set) => {
|
||||
Paint(id, new_layer_buffer_set, epoch) => {
|
||||
debug!("osmain: received new frame");
|
||||
|
||||
match compositor_layer {
|
||||
Some(ref mut layer) => {
|
||||
assert!(layer.add_buffers(id, new_layer_buffer_set.get()));
|
||||
assert!(layer.add_buffers(id, new_layer_buffer_set.get(), epoch));
|
||||
recomposite = true;
|
||||
}
|
||||
None => {
|
||||
|
|
|
@ -211,11 +211,30 @@ impl<T: Tile> Quadtree<T> {
|
|||
(ret, redisplay)
|
||||
}
|
||||
|
||||
|
||||
/// Resize the quadtree. This can add more space, changing the root node, or it can shrink, making
|
||||
/// an internal node the new root.
|
||||
/// TODO: return tiles after shrinking
|
||||
/// 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) {
|
||||
// Spaces must be squares and powers of 2, so expand the space until it is
|
||||
let longer = width.max(&height);
|
||||
let num_tiles = div_ceil(longer, self.max_tile_size);
|
||||
let power_of_two = next_power_of_two(num_tiles);
|
||||
let size = power_of_two * self.max_tile_size;
|
||||
|
||||
self.root = ~QuadtreeNode {
|
||||
tile: None,
|
||||
origin: Point2D(0f32, 0f32),
|
||||
size: size as f32,
|
||||
quadrants: [None, None, None, None],
|
||||
status: Normal,
|
||||
tile_mem: 0,
|
||||
};
|
||||
self.clip_size = Size2D(width, height);
|
||||
}
|
||||
|
||||
/// Resize the underlying quadtree without removing tiles already in place.
|
||||
/// Might be useful later on, but resize() should be used for now.
|
||||
/// TODO: return tiles after shrinking
|
||||
pub fn bad_resize(&mut self, width: uint, height: uint) {
|
||||
self.clip_size = Size2D(width, height);
|
||||
let longer = width.max(&height);
|
||||
let new_num_tiles = div_ceil(longer, self.max_tile_size);
|
||||
|
|
|
@ -26,6 +26,7 @@ use servo_util::time::ProfilerChan;
|
|||
use std::hashmap::{HashMap, HashSet};
|
||||
use std::util::replace;
|
||||
use extra::future::{Future, from_value};
|
||||
use extra::url::Url;
|
||||
|
||||
/// Maintains the pipelines and navigation context and grants permission to composite
|
||||
pub struct Constellation {
|
||||
|
@ -108,7 +109,7 @@ impl FrameTree {
|
|||
|
||||
/// Returns the frame tree whose key is id
|
||||
fn find_mut(@mut self, id: PipelineId) -> Option<@mut FrameTree> {
|
||||
do self.iter().find_ |frame_tree| {
|
||||
do self.iter().find |frame_tree| {
|
||||
id == frame_tree.pipeline.id
|
||||
}
|
||||
}
|
||||
|
@ -118,7 +119,7 @@ impl FrameTree {
|
|||
fn replace_child(@mut self,
|
||||
id: PipelineId,
|
||||
new_child: @mut FrameTree)
|
||||
-> Result<@mut FrameTree, @mut FrameTree> {
|
||||
-> Either<@mut FrameTree, @mut FrameTree> {
|
||||
let mut child = (do self.iter().filter_map |frame_tree| {
|
||||
(do frame_tree.children.iter().find |child| {
|
||||
child.frame_tree.pipeline.id == id
|
||||
|
@ -407,7 +408,7 @@ impl Constellation {
|
|||
for current_frame in self.current_frame().iter() {
|
||||
debug!("Constellation: Sending size for frame in current frame tree.");
|
||||
let source_frame = current_frame.find_mut(pipeline_id);
|
||||
for source_frame.iter().advance |source_frame| {
|
||||
for source_frame in source_frame.iter() {
|
||||
for child_frame_tree in source_frame.children.mut_iter() {
|
||||
let pipeline = &child_frame_tree.frame_tree.pipeline;
|
||||
if pipeline.subpage_id.expect("Constellation: child frame does not have a
|
||||
|
@ -646,6 +647,11 @@ impl Constellation {
|
|||
// TODO(tkuehn): In fact, this kind of message might be provably
|
||||
// impossible to occur.
|
||||
if current_frame.contains(pipeline_id) {
|
||||
//debug!("updating compositor frame tree with %?", current_frame);
|
||||
//self.set_ids(current_frame);
|
||||
for frame in current_frame.iter() {
|
||||
frame.pipeline.grant_paint_permission();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -161,7 +161,7 @@ impl Pipeline {
|
|||
}
|
||||
|
||||
pub fn reload(&mut self) {
|
||||
do self.url.clone().map_consume() |url| {
|
||||
do self.url.clone().map_move() |url| {
|
||||
self.load(url);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -59,10 +59,10 @@ pub enum ReadyState {
|
|||
pub trait RenderListener {
|
||||
fn get_gl_context(&self) -> AzGLContext;
|
||||
fn new_layer(&self, PipelineId, Size2D<uint>);
|
||||
fn set_layer_page_size(&self, PipelineId, Size2D<uint>);
|
||||
fn set_layer_page_size(&self, PipelineId, Size2D<uint>, uint);
|
||||
fn set_layer_clip_rect(&self, PipelineId, Rect<uint>);
|
||||
fn delete_layer(&self, PipelineId);
|
||||
fn paint(&self, id: PipelineId, layer_buffer_set: arc::Arc<LayerBufferSet>);
|
||||
fn paint(&self, id: PipelineId, layer_buffer_set: arc::Arc<LayerBufferSet>, uint);
|
||||
fn set_render_state(&self, render_state: RenderState);
|
||||
}
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ struct IFrameSize {
|
|||
impl IFrameSize {
|
||||
pub fn set_rect(&mut self, rect: Rect<f32>) {
|
||||
let future_chan = replace(&mut self.future_chan, None);
|
||||
do future_chan.map_consume |future_chan| {
|
||||
do future_chan.map_move |future_chan| {
|
||||
let Size2D { width, height } = rect.size;
|
||||
future_chan.send(Size2D(width as uint, height as uint));
|
||||
};
|
||||
|
|
|
@ -401,7 +401,7 @@ pub fn parse_html(cx: *JSContext,
|
|||
future_chan: Some(chan),
|
||||
constellation_chan: constellation_chan.clone(),
|
||||
});
|
||||
iframe_chan.send(HtmlDiscoveredIFrame(iframe_url, subpage_id, size_future));
|
||||
iframe_chan.send(HtmlDiscoveredIFrame((iframe_url, subpage_id, size_future)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue