diff --git a/src/components/compositing/compositor.rs b/src/components/compositing/compositor.rs index eec1b90936d..8a357e059b4 100644 --- a/src/components/compositing/compositor.rs +++ b/src/components/compositing/compositor.rs @@ -6,7 +6,7 @@ use compositor_data::{CompositorData, WantsScrollEvents}; use compositor_task::{Msg, CompositorTask, Exit, ChangeReadyState, SetIds, LayerProperties}; use compositor_task::{GetGraphicsMetadata, CreateOrUpdateRootLayer, CreateOrUpdateDescendantLayer}; use compositor_task::{SetLayerClipRect, Paint, ScrollFragmentPoint, LoadComplete}; -use compositor_task::{ShutdownComplete, ChangeRenderState}; +use compositor_task::{ShutdownComplete, ChangeRenderState, ReRenderMsgDiscarded}; use constellation::SendableFrameTree; use events; use pipeline::CompositionPipeline; @@ -90,6 +90,9 @@ pub struct IOCompositor { /// Tracks whether we need to re-composite a page. recomposite: bool, + /// Tracks outstanding ReRenderMsg's sent to the render tasks. + outstanding_rerendermsgs: uint, + /// Tracks whether the zoom action has happend recently. zoom_action: bool, @@ -166,7 +169,8 @@ impl IOCompositor { constellation_chan: constellation_chan, time_profiler_chan: time_profiler_chan, memory_profiler_chan: memory_profiler_chan, - fragment_point: None + fragment_point: None, + outstanding_rerendermsgs: 0, } } @@ -278,6 +282,10 @@ impl IOCompositor { self.change_render_state(render_state); } + (Ok(ReRenderMsgDiscarded), NotShuttingDown) => { + self.remove_outstanding_rerendermsg(); + } + (Ok(SetIds(frame_tree, response_chan, new_constellation_chan)), _) => { self.set_ids(frame_tree, response_chan, new_constellation_chan); } @@ -304,6 +312,7 @@ impl IOCompositor { for (layer_id, new_layer_buffer_set) in replies.move_iter() { self.paint(pipeline_id, layer_id, new_layer_buffer_set, epoch); } + self.remove_outstanding_rerendermsg(); } (Ok(ScrollFragmentPoint(pipeline_id, layer_id, point)), NotShuttingDown) => { @@ -329,6 +338,35 @@ impl IOCompositor { } } + fn has_rerendermsg_tracking(&self) -> bool { + // only track ReRenderMsg's if the compositor outputs to a file. + self.opts.output_file.is_some() + } + + fn has_outstanding_rerendermsgs(&self) -> bool { + self.has_rerendermsg_tracking() && self.outstanding_rerendermsgs > 0 + } + + fn add_outstanding_rerendermsg(&mut self, count: uint) { + // return early if not tracking ReRenderMsg's + if !self.has_rerendermsg_tracking() { + return; + } + debug!("add_outstanding_rerendermsg {}", self.outstanding_rerendermsgs); + self.outstanding_rerendermsgs += count; + } + + fn remove_outstanding_rerendermsg(&mut self) { + if !self.has_rerendermsg_tracking() { + return; + } + if self.outstanding_rerendermsgs > 0 { + self.outstanding_rerendermsgs -= 1; + } else { + debug!("too many rerender msgs completed"); + } + } + fn set_ids(&mut self, frame_tree: SendableFrameTree, response_chan: Sender<()>, @@ -749,8 +787,9 @@ impl IOCompositor { fn ask_for_tiles(&mut self) { let scale = self.device_pixels_per_page_px(); let page_window = self.page_window(); + let mut num_rerendermsgs_sent = 0; match self.scene.root { - Some(ref mut layer) => { + Some(ref layer) => { let rect = Rect(Point2D(0f32, 0f32), page_window.to_untyped()); let mut request_map = HashMap::new(); let recomposite = @@ -759,12 +798,14 @@ impl IOCompositor { rect, scale.get()); for (_pipeline_id, (chan, requests)) in request_map.move_iter() { + num_rerendermsgs_sent += 1; let _ = chan.send_opt(ReRenderMsg(requests)); } self.recomposite = self.recomposite || recomposite; } None => { } } + self.add_outstanding_rerendermsg(num_rerendermsgs_sent); } fn composite(&mut self) { @@ -788,7 +829,7 @@ impl IOCompositor { // Render to PNG. We must read from the back buffer (ie, before // self.window.present()) as OpenGL ES 2 does not have glReadBuffer(). if self.load_complete && self.ready_state == FinishedLoading - && self.opts.output_file.is_some() { + && self.opts.output_file.is_some() && !self.has_outstanding_rerendermsgs() { let (width, height) = (self.window_size.width.get(), self.window_size.height.get()); let path = from_str::(self.opts.output_file.get_ref().as_slice()).unwrap(); let mut pixels = gl2::read_pixels(0, 0, diff --git a/src/components/compositing/compositor_task.rs b/src/components/compositing/compositor_task.rs index 25116b5692b..073d27e2fe5 100644 --- a/src/components/compositing/compositor_task.rs +++ b/src/components/compositing/compositor_task.rs @@ -122,6 +122,10 @@ impl RenderListener for CompositorChan { } } + fn rerendermsg_discarded(&self) { + self.chan.send(ReRenderMsgDiscarded); + } + fn set_layer_clip_rect(&self, pipeline_id: PipelineId, layer_id: LayerId, @@ -184,6 +188,8 @@ pub enum Msg { ChangeReadyState(ReadyState), /// Alerts the compositor to the current status of rendering. ChangeRenderState(RenderState), + /// Alerts the compositor that the ReRenderMsg has been discarded. + ReRenderMsgDiscarded, /// Sets the channel to the current layout and render tasks, along with their id SetIds(SendableFrameTree, Sender<()>, ConstellationChan), /// The load of a page for a given URL has completed. diff --git a/src/components/compositing/headless.rs b/src/components/compositing/headless.rs index a76cbfa9905..028dbb8c1e0 100644 --- a/src/components/compositing/headless.rs +++ b/src/components/compositing/headless.rs @@ -5,7 +5,7 @@ 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}; +use compositor_task::{ShutdownComplete, ChangeRenderState, ReRenderMsgDiscarded}; use geom::scale_factor::ScaleFactor; use geom::size::TypedSize2D; @@ -92,7 +92,7 @@ impl NullCompositor { CreateOrUpdateDescendantLayer(..) | SetLayerClipRect(..) | Paint(..) | ChangeReadyState(..) | ChangeRenderState(..) | ScrollFragmentPoint(..) | - LoadComplete(..) => () + LoadComplete(..) | ReRenderMsgDiscarded(..) => () } } } diff --git a/src/components/gfx/render_task.rs b/src/components/gfx/render_task.rs index d80eb050715..e81f36162c0 100644 --- a/src/components/gfx/render_task.rs +++ b/src/components/gfx/render_task.rs @@ -242,6 +242,7 @@ impl RenderTask { debug!("render_task: render ready msg"); let ConstellationChan(ref mut c) = self.constellation_chan; c.send(RendererReadyMsg(self.id)); + self.compositor.rerendermsg_discarded(); continue; } diff --git a/src/components/msg/compositor_msg.rs b/src/components/msg/compositor_msg.rs index 48d7600a0ae..8020c01ffc8 100644 --- a/src/components/msg/compositor_msg.rs +++ b/src/components/msg/compositor_msg.rs @@ -105,6 +105,7 @@ pub trait RenderListener { epoch: Epoch, replies: Vec<(LayerId, Box)>); + fn rerendermsg_discarded(&self); fn set_render_state(&self, render_state: RenderState); }