Stop copying buffers when sending them to quadtrees

This commit is contained in:
eschweic 2013-08-06 16:28:35 -07:00
parent abccd82eba
commit 02ae7bdd34
5 changed files with 34 additions and 26 deletions

View file

@ -19,7 +19,7 @@ use servo_net::image::base::Image;
use extra::arc::Arc;
pub struct RenderContext<'self> {
canvas: &'self LayerBuffer,
canvas: &'self ~LayerBuffer,
font_ctx: @mut FontContext,
opts: &'self Opts
}

View file

@ -35,7 +35,7 @@ pub struct RenderLayer<T> {
pub enum Msg<T> {
RenderMsg(RenderLayer<T>),
ReRenderMsg(~[BufferRequest], f32, PipelineId, Epoch),
ReRenderMsg(~[BufferRequest], f32, Epoch),
PaintPermissionGranted,
PaintPermissionRevoked,
ExitMsg(Chan<()>),
@ -91,7 +91,7 @@ struct RenderTask<C,T> {
/// Permission to send paint messages to the compositor
paint_permission: bool,
/// Cached copy of last layers rendered
last_paint_msg: Option<(arc::Arc<LayerBufferSet>, Size2D<uint>)>,
last_paint_msg: Option<~LayerBufferSet>,
/// A counter for epoch messages
epoch: Epoch,
}
@ -147,9 +147,9 @@ impl<C: RenderListener + Send,T:Send+Freeze> RenderTask<C,T> {
}
self.render_layer = Some(render_layer);
}
ReRenderMsg(tiles, scale, id, epoch) => {
ReRenderMsg(tiles, scale, epoch) => {
if self.epoch == epoch {
self.render(tiles, scale, id);
self.render(tiles, scale);
} else {
debug!("renderer epoch mismatch: %? != %?", self.epoch, epoch);
}
@ -163,6 +163,16 @@ impl<C: RenderListener + Send,T:Send+Freeze> RenderTask<C,T> {
}
None => {}
}
// FIXME: This sends the last paint request, anticipating what
// the compositor will ask for. However, even if it sends the right
// tiles, the compositor still asks for them, and they will be
// re-rendered redundantly.
match self.last_paint_msg {
Some(ref layer_buffer_set) => {
self.compositor.paint(self.id, layer_buffer_set.clone());
}
None => {} // Nothing to do
}
}
PaintPermissionRevoked => {
self.paint_permission = false;
@ -175,7 +185,7 @@ impl<C: RenderListener + Send,T:Send+Freeze> RenderTask<C,T> {
}
}
fn render(&mut self, tiles: ~[BufferRequest], scale: f32, id: PipelineId) {
fn render(&mut self, tiles: ~[BufferRequest], scale: f32) {
let render_layer;
match self.render_layer {
Some(ref r_layer) => {
@ -196,7 +206,7 @@ impl<C: RenderListener + Send,T:Send+Freeze> RenderTask<C,T> {
let width = tile.screen_rect.size.width;
let height = tile.screen_rect.size.height;
let buffer = LayerBuffer {
let buffer = ~LayerBuffer {
draw_target: DrawTarget::new_with_fbo(self.opts.render_backend,
self.share_gl_context,
Size2D(width as i32, height as i32),
@ -240,17 +250,16 @@ impl<C: RenderListener + Send,T:Send+Freeze> RenderTask<C,T> {
}
let layer_buffer_set = LayerBufferSet {
let layer_buffer_set = ~LayerBufferSet {
buffers: new_buffers,
};
let layer_buffer_set = arc::Arc::new(layer_buffer_set);
debug!("render_task: returning surface");
if self.paint_permission {
self.compositor.paint(id, layer_buffer_set.clone(), self.epoch);
self.compositor.paint(self.id, layer_buffer_set.clone(), self.epoch);
}
debug!("caching paint msg");
self.last_paint_msg = Some((layer_buffer_set, render_layer.size));
self.last_paint_msg = Some(layer_buffer_set);
self.compositor.set_render_state(IdleRenderState);
}
}

View file

@ -2,6 +2,7 @@
* 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 geom::point::Point2D;
use geom::size::Size2D;
use geom::rect::Rect;
@ -210,7 +211,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.epoch));
self.pipeline.render_chan.send(ReRenderMsg(request, scale, self.epoch));
}
}
if redisplay {
@ -399,7 +400,8 @@ 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 {
pub fn add_buffers(&mut self, pipeline_id: PipelineId, new_buffers: ~LayerBufferSet, epoch: Epoch) -> bool {
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);
@ -408,22 +410,21 @@ impl CompositorLayer {
}
{ // block here to prevent double mutable borrow of self
let quadtree = match self.quadtree {
NoTree(_, _) => fail!("CompositorLayer: cannot get buffer request for %?,
no quadtree initialized", self.pipeline.id),
NoTree(_, _) => fail!("CompositorLayer: cannot add buffers, no quadtree initialized"),
Tree(ref mut quadtree) => quadtree,
};
for buffer in new_buffers.buffers.iter() {
for buffer in cell.take().buffers.consume_rev_iter() {
// TODO: This may return old buffers, which should be sent back to the renderer.
quadtree.add_tile_pixel(buffer.screen_pos.origin.x, buffer.screen_pos.origin.y,
buffer.resolution, ~buffer.clone());
buffer.resolution, buffer);
}
}
self.build_layer_tree();
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, epoch))
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.

View file

@ -40,7 +40,6 @@ use servo_util::time::ProfilerChan;
use extra::future::from_value;
use extra::time::precise_time_s;
use extra::arc;
use constellation::SendableFrameTree;
use compositing::compositor_layer::CompositorLayer;
@ -79,7 +78,7 @@ impl RenderListener for CompositorChan {
port.recv()
}
fn paint(&self, id: PipelineId, layer_buffer_set: arc::Arc<LayerBufferSet>, epoch: Epoch) {
fn paint(&self, id: PipelineId, layer_buffer_set: ~LayerBufferSet, epoch: Epoch) {
self.chan.send(Paint(id, layer_buffer_set, epoch))
}
@ -148,7 +147,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>, Epoch),
Paint(PipelineId, ~LayerBufferSet, Epoch),
/// Alerts the compositor to the current status of page loading.
ChangeReadyState(ReadyState),
/// Alerts the compositor to the current status of rendering.
@ -338,7 +337,7 @@ impl CompositorTask {
match compositor_layer {
Some(ref mut layer) => {
assert!(layer.add_buffers(id, new_layer_buffer_set.get(), epoch));
assert!(layer.add_buffers(id, new_layer_buffer_set, epoch));
recomposite = true;
}
None => {

View file

@ -8,8 +8,6 @@ use geom::rect::Rect;
use geom::size::Size2D;
use constellation_msg::PipelineId;
use extra::arc;
#[deriving(Clone)]
pub struct LayerBuffer {
@ -31,8 +29,9 @@ pub struct LayerBuffer {
/// A set of layer buffers. This is an atomic unit used to switch between the front and back
/// buffers.
#[deriving(Clone)]
pub struct LayerBufferSet {
buffers: ~[LayerBuffer]
buffers: ~[~LayerBuffer]
}
/// The status of the renderer.
@ -72,7 +71,7 @@ pub trait RenderListener {
fn set_layer_page_size(&self, PipelineId, Size2D<uint>, Epoch);
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>, Epoch);
fn paint(&self, id: PipelineId, layer_buffer_set: ~LayerBufferSet, Epoch);
fn set_render_state(&self, render_state: RenderState);
}