gfx: Use layer buffer sets instead of a single layer buffer

This commit is contained in:
Patrick Walton 2012-10-25 16:20:39 -07:00
parent 467c799532
commit 5c373c21d8
5 changed files with 87 additions and 71 deletions

View file

@ -16,12 +16,18 @@ struct LayerBuffer {
stride: uint stride: uint
} }
/// A set of layer buffers. This is an atomic unit used to switch between the front and back
/// buffers.
struct LayerBufferSet {
buffers: ~[LayerBuffer]
}
/** /**
The interface used to by the renderer to aquire draw targets for The interface used to by the renderer to aquire draw targets for
each rendered frame and submit them to be drawn to the display each rendered frame and submit them to be drawn to the display
*/ */
trait Compositor { trait Compositor {
fn begin_drawing(next_dt: pipes::Chan<LayerBuffer>); fn begin_drawing(next_dt: pipes::Chan<LayerBufferSet>);
fn draw(next_dt: pipes::Chan<LayerBuffer>, +draw_me: LayerBuffer); fn draw(next_dt: pipes::Chan<LayerBufferSet>, +draw_me: LayerBufferSet);
} }

View file

@ -12,8 +12,8 @@ use azure::azure_hl::DrawTarget;
use cairo::cairo_hl::ImageSurface; use cairo::cairo_hl::ImageSurface;
use cairo::{CAIRO_FORMAT_ARGB32, cairo_surface_t, cairo_status_t, CAIRO_STATUS_SUCCESS}; use cairo::{CAIRO_FORMAT_ARGB32, cairo_surface_t, cairo_status_t, CAIRO_STATUS_SUCCESS};
use cairo_bg = cairo::bindgen; use cairo_bg = cairo::bindgen;
use cairo_bg::{cairo_image_surface_create, cairo_surface_destroy, use cairo_bg::{cairo_image_surface_create, cairo_surface_destroy};
cairo_surface_write_to_png_stream}; use cairo_bg::{cairo_surface_write_to_png_stream};
use compositor::Compositor; use compositor::Compositor;
use render_task::{RenderTask, RenderMsg}; use render_task::{RenderTask, RenderMsg};
use task::spawn_listener; use task::spawn_listener;
@ -25,23 +25,23 @@ use dvec::DVec;
use display_list::DisplayList; use display_list::DisplayList;
use std::cell::Cell; use std::cell::Cell;
use core::io::BytesWriter; use core::io::BytesWriter;
use gfx::compositor::LayerBuffer; use gfx::compositor::{LayerBuffer, LayerBufferSet};
use geom::size::Size2D; use geom::size::Size2D;
use gfx::render_layers::RenderLayer; use gfx::render_layers::RenderLayer;
pub type PngCompositor = Chan<Msg>; pub type PngCompositor = Chan<Msg>;
pub enum Msg { pub enum Msg {
BeginDrawing(pipes::Chan<LayerBuffer>), BeginDrawing(pipes::Chan<LayerBufferSet>),
Draw(pipes::Chan<LayerBuffer>, LayerBuffer), Draw(pipes::Chan<LayerBufferSet>, LayerBufferSet),
Exit Exit
} }
impl Chan<Msg> : Compositor { impl Chan<Msg> : Compositor {
fn begin_drawing(next_dt: pipes::Chan<LayerBuffer>) { fn begin_drawing(next_dt: pipes::Chan<LayerBufferSet>) {
self.send(BeginDrawing(move next_dt)) self.send(BeginDrawing(move next_dt))
} }
fn draw(next_dt: pipes::Chan<LayerBuffer>, draw_me: LayerBuffer) { fn draw(next_dt: pipes::Chan<LayerBufferSet>, draw_me: LayerBufferSet) {
self.send(Draw(move next_dt, move draw_me)) self.send(Draw(move next_dt, move draw_me))
} }
} }
@ -56,17 +56,18 @@ pub fn PngCompositor(output: Chan<~[u8]>) -> PngCompositor {
size: Size2D(800u, 600u), size: Size2D(800u, 600u),
stride: 800 stride: 800
}; };
let layer_buffer = Cell(move layer_buffer); let layer_buffer_set = LayerBufferSet { buffers: ~[ move layer_buffer ] };
let layer_buffer_set = Cell(move layer_buffer_set);
loop { loop {
match po.recv() { match po.recv() {
BeginDrawing(sender) => { BeginDrawing(sender) => {
debug!("png_compositor: begin_drawing"); debug!("png_compositor: begin_drawing");
sender.send(layer_buffer.take()); sender.send(layer_buffer_set.take());
} }
Draw(move sender, move layer_buffer) => { Draw(move sender, move layer_buffer_set) => {
debug!("png_compositor: draw"); debug!("png_compositor: draw");
do_draw(move sender, move layer_buffer, output, &cairo_surface); do_draw(move sender, move layer_buffer_set, output, &cairo_surface);
} }
Exit => break Exit => break
} }
@ -74,8 +75,8 @@ pub fn PngCompositor(output: Chan<~[u8]>) -> PngCompositor {
} }
} }
fn do_draw(sender: pipes::Chan<LayerBuffer>, fn do_draw(sender: pipes::Chan<LayerBufferSet>,
layer_buffer: LayerBuffer, layer_buffer_set: LayerBufferSet,
output: Chan<~[u8]>, output: Chan<~[u8]>,
cairo_surface: &ImageSurface) { cairo_surface: &ImageSurface) {
let buffer = BytesWriter(); let buffer = BytesWriter();
@ -83,7 +84,7 @@ fn do_draw(sender: pipes::Chan<LayerBuffer>,
output.send(buffer.bytes.get()); output.send(buffer.bytes.get());
// Send the next draw target to the renderer // Send the next draw target to the renderer
sender.send(move layer_buffer); sender.send(move layer_buffer_set);
} }
#[test] #[test]

View file

@ -1,5 +1,5 @@
use gfx::display_list::DisplayList; use gfx::display_list::DisplayList;
use gfx::compositor::LayerBuffer; use gfx::compositor::{LayerBuffer, LayerBufferSet};
use azure::azure_hl::DrawTarget; use azure::azure_hl::DrawTarget;
use cairo::CAIRO_FORMAT_RGB24; use cairo::CAIRO_FORMAT_RGB24;
@ -17,9 +17,10 @@ pub struct RenderLayer {
/// given callback with the render layer and the buffer. Returns the resulting layer buffer (which /// given callback with the render layer and the buffer. Returns the resulting layer buffer (which
/// might be the old layer buffer if it had the appropriate size and format). /// might be the old layer buffer if it had the appropriate size and format).
pub fn render_layers(layer: &RenderLayer, pub fn render_layers(layer: &RenderLayer,
buffer: LayerBuffer, buffer_set: LayerBufferSet,
f: &fn(layer: &RenderLayer, buffer: &LayerBuffer) -> bool) -> LayerBuffer { f: &fn(layer: &RenderLayer, buffer: &LayerBuffer) -> bool) -> LayerBufferSet {
let mut buffer = move buffer; let mut buffers = match move buffer_set { LayerBufferSet { buffers: move b } => move b };
let mut buffer = buffers.pop();
if buffer.size != layer.size { if buffer.size != layer.size {
// Create a new buffer. // Create a new buffer.
@ -44,6 +45,6 @@ pub fn render_layers(layer: &RenderLayer,
} }
let _ = f(layer, &buffer); let _ = f(layer, &buffer);
return move buffer; return LayerBufferSet { buffers: ~[ move buffer ] };
} }

View file

@ -1,7 +1,7 @@
use au = gfx::geometry; use au = gfx::geometry;
use au::Au; use au::Au;
use comm::*; use comm::*;
use compositor::{Compositor, LayerBuffer}; use compositor::{Compositor, LayerBufferSet};
use dl = display_list; use dl = display_list;
use mod gfx::render_layers; use mod gfx::render_layers;
use render_layers::render_layers; use render_layers::render_layers;
@ -24,7 +24,7 @@ pub type RenderTask = comm::Chan<Msg>;
pub fn RenderTask<C: Compositor Send>(compositor: C) -> RenderTask { pub fn RenderTask<C: Compositor Send>(compositor: C) -> RenderTask {
let compositor_cell = Cell(move compositor); let compositor_cell = Cell(move compositor);
do task::spawn_listener |po: comm::Port<Msg>, move compositor_cell| { do task::spawn_listener |po: comm::Port<Msg>, move compositor_cell| {
let (layer_buffer_channel, layer_buffer_port) = pipes::stream(); let (layer_buffer_channel, layer_buffer_set_port) = pipes::stream();
let compositor = compositor_cell.take(); let compositor = compositor_cell.take();
compositor.begin_drawing(move layer_buffer_channel); compositor.begin_drawing(move layer_buffer_channel);
@ -32,7 +32,7 @@ pub fn RenderTask<C: Compositor Send>(compositor: C) -> RenderTask {
Renderer { Renderer {
port: po, port: po,
compositor: move compositor, compositor: move compositor,
mut layer_buffer_port: Cell(move layer_buffer_port), mut layer_buffer_set_port: Cell(move layer_buffer_set_port),
font_cache: FontCache(), font_cache: FontCache(),
}.start(); }.start();
} }
@ -41,7 +41,7 @@ pub fn RenderTask<C: Compositor Send>(compositor: C) -> RenderTask {
priv struct Renderer<C: Compositor Send> { priv struct Renderer<C: Compositor Send> {
port: comm::Port<Msg>, port: comm::Port<Msg>,
compositor: C, compositor: C,
layer_buffer_port: Cell<pipes::Port<LayerBuffer>>, layer_buffer_set_port: Cell<pipes::Port<LayerBufferSet>>,
font_cache: @FontCache font_cache: @FontCache
} }
@ -63,28 +63,28 @@ impl<C: Compositor Send> Renderer<C> {
fn render(render_layer: RenderLayer) { fn render(render_layer: RenderLayer) {
debug!("renderer: got render request"); debug!("renderer: got render request");
let layer_buffer_port = self.layer_buffer_port.take(); let layer_buffer_set_port = self.layer_buffer_set_port.take();
if !layer_buffer_port.peek() { if !layer_buffer_set_port.peek() {
warn!("renderer: waiting on layer buffer"); warn!("renderer: waiting on layer buffer");
} }
let layer_buffer = layer_buffer_port.recv(); let layer_buffer_set = layer_buffer_set_port.recv();
let (layer_buffer_channel, new_layer_buffer_port) = pipes::stream(); let (layer_buffer_set_channel, new_layer_buffer_set_port) = pipes::stream();
self.layer_buffer_port.put_back(move new_layer_buffer_port); self.layer_buffer_set_port.put_back(move new_layer_buffer_set_port);
let render_layer_cell = Cell(move render_layer); let render_layer_cell = Cell(move render_layer);
let layer_buffer_cell = Cell(move layer_buffer); let layer_buffer_set_cell = Cell(move layer_buffer_set);
let layer_buffer_channel_cell = Cell(move layer_buffer_channel); let layer_buffer_set_channel_cell = Cell(move layer_buffer_set_channel);
#debug("renderer: rendering"); #debug("renderer: rendering");
do util::time::time(~"rendering") { do util::time::time(~"rendering") {
let render_layer = render_layer_cell.take(); let render_layer = render_layer_cell.take();
let layer_buffer = layer_buffer_cell.take(); let layer_buffer_set = layer_buffer_set_cell.take();
let layer_buffer_channel = layer_buffer_channel_cell.take(); let layer_buffer_set_channel = layer_buffer_set_channel_cell.take();
let layer_buffer = for render_layers(&render_layer, move layer_buffer) let layer_buffer_set = for render_layers(&render_layer, move layer_buffer_set)
|render_layer, layer_buffer| { |render_layer, layer_buffer| {
let ctx = RenderContext { let ctx = RenderContext {
canvas: layer_buffer, canvas: layer_buffer,
@ -96,7 +96,7 @@ impl<C: Compositor Send> Renderer<C> {
}; };
#debug("renderer: returning surface"); #debug("renderer: returning surface");
self.compositor.draw(move layer_buffer_channel, move layer_buffer); self.compositor.draw(move layer_buffer_set_channel, move layer_buffer_set);
} }
} }
} }

View file

@ -1,20 +1,21 @@
use mod azure::azure_hl; use ShareGlContext = sharegl::platform::Context;
use azure::azure_hl;
use azure::azure_hl::DrawTarget; use azure::azure_hl::DrawTarget;
use cairo::cairo_surface_t;
use cairo::cairo_hl::ImageSurface; use cairo::cairo_hl::ImageSurface;
use dvec::DVec; use cairo::cairo_surface_t;
use gfx::compositor::{LayerBuffer, Compositor}; use core::util::replace;
use dom::event::{Event, ResizeEvent}; use dom::event::{Event, ResizeEvent};
use layers::ImageLayer; use dvec::DVec;
use geom::matrix::{Matrix4, identity}; use geom::matrix::{Matrix4, identity};
use geom::size::Size2D; use geom::size::Size2D;
use ShareGlContext = sharegl::platform::Context; use gfx::compositor::{Compositor, LayerBuffer, LayerBufferSet};
use layers::ImageLayer;
use pipes::Chan;
use resize_rate_limiter::ResizeRateLimiter;
use std::cell::Cell;
use std::cmp::FuzzyEq; use std::cmp::FuzzyEq;
use task::TaskBuilder; use task::TaskBuilder;
use vec::push; use vec::push;
use pipes::Chan;
use std::cell::Cell;
use resize_rate_limiter::ResizeRateLimiter;
pub type OSMain = comm::Chan<Msg>; pub type OSMain = comm::Chan<Msg>;
@ -30,8 +31,8 @@ enum Window {
} }
pub enum Msg { pub enum Msg {
BeginDrawing(pipes::Chan<LayerBuffer>), BeginDrawing(pipes::Chan<LayerBufferSet>),
Draw(pipes::Chan<LayerBuffer>, LayerBuffer), Draw(pipes::Chan<LayerBufferSet>, LayerBufferSet),
AddKeyHandler(pipes::Chan<()>), AddKeyHandler(pipes::Chan<()>),
Exit Exit
} }
@ -120,11 +121,12 @@ fn mainloop(mode: Mode, po: comm::Port<Msg>, dom_event_chan: pipes::SharedChan<E
return_surface(surfaces, move dt); return_surface(surfaces, move dt);
lend_surface(surfaces, move sender); lend_surface(surfaces, move sender);
let width = surfaces.front.layer_buffer.size.width as uint; let buffers = &mut surfaces.front.layer_buffer_set.buffers;
let height = surfaces.front.layer_buffer.size.height as uint; let width = buffers[0].size.width as uint;
let height = buffers[0].size.height as uint;
let image_data = @CairoSurfaceImageData { let image_data = @CairoSurfaceImageData {
cairo_surface: surfaces.front.layer_buffer.cairo_surface.clone(), cairo_surface: buffers[0].cairo_surface.clone(),
size: Size2D(width, height) size: Size2D(width, height)
}; };
let image = @layers::layers::Image::new( let image = @layers::layers::Image::new(
@ -142,7 +144,6 @@ fn mainloop(mode: Mode, po: comm::Port<Msg>, dom_event_chan: pipes::SharedChan<E
}; };
let adjust_for_window_resizing: fn@() = || { let adjust_for_window_resizing: fn@() = || {
let height = surfaces.front.layer_buffer.size.height as uint;
let window_width = glut::get(glut::WindowWidth) as uint; let window_width = glut::get(glut::WindowWidth) as uint;
let window_height = glut::get(glut::WindowHeight) as uint; let window_height = glut::get(glut::WindowHeight) as uint;
@ -167,15 +168,14 @@ fn mainloop(mode: Mode, po: comm::Port<Msg>, dom_event_chan: pipes::SharedChan<E
match window { match window {
GlutWindow(window) => { GlutWindow(window) => {
do glut::reshape_func(window) |width, height| { do glut::reshape_func(window) |width, height| {
check_for_messages();
#debug("osmain: window resized to %d,%d", width as int, height as int); #debug("osmain: window resized to %d,%d", width as int, height as int);
check_for_messages();
resize_rate_limiter.window_resized(width as uint, height as uint); resize_rate_limiter.window_resized(width as uint, height as uint);
//composite();
composite();
} }
do glut::display_func() { do glut::display_func() {
debug!("osmain: display func");
check_for_messages(); check_for_messages();
composite(); composite();
} }
@ -203,10 +203,10 @@ Implementation to allow the osmain channel to be used as a graphics
compositor for the renderer compositor for the renderer
*/ */
impl OSMain : Compositor { impl OSMain : Compositor {
fn begin_drawing(next_dt: pipes::Chan<LayerBuffer>) { fn begin_drawing(next_dt: pipes::Chan<LayerBufferSet>) {
self.send(BeginDrawing(move next_dt)) self.send(BeginDrawing(move next_dt))
} }
fn draw(next_dt: pipes::Chan<LayerBuffer>, draw_me: LayerBuffer) { fn draw(next_dt: pipes::Chan<LayerBufferSet>, draw_me: LayerBufferSet) {
self.send(Draw(move next_dt, move draw_me)) self.send(Draw(move next_dt, move draw_me))
} }
} }
@ -216,19 +216,26 @@ struct SurfaceSet {
mut back: Surface, mut back: Surface,
} }
fn lend_surface(surfaces: &SurfaceSet, receiver: pipes::Chan<LayerBuffer>) { fn lend_surface(surfaces: &SurfaceSet, receiver: pipes::Chan<LayerBufferSet>) {
// We are in a position to lend out the surface? // We are in a position to lend out the surface?
assert surfaces.front.have; assert surfaces.front.have;
// Ok then take it // Ok then take it
let draw_target_ref = &mut surfaces.front.layer_buffer.draw_target; let old_layer_buffers = replace(&mut surfaces.front.layer_buffer_set.buffers, ~[]);
let new_layer_buffers = do old_layer_buffers.map |layer_buffer| {
let draw_target_ref = &layer_buffer.draw_target;
let layer_buffer = LayerBuffer { let layer_buffer = LayerBuffer {
cairo_surface: surfaces.front.layer_buffer.cairo_surface.clone(), cairo_surface: layer_buffer.cairo_surface.clone(),
draw_target: azure_hl::clone_mutable_draw_target(draw_target_ref), draw_target: draw_target_ref.clone(),
size: copy surfaces.front.layer_buffer.size, size: copy layer_buffer.size,
stride: surfaces.front.layer_buffer.stride stride: layer_buffer.stride
}; };
#debug("osmain: lending surface %?", layer_buffer); #debug("osmain: lending surface %?", layer_buffer);
receiver.send(move layer_buffer); move layer_buffer
};
surfaces.front.layer_buffer_set.buffers = move old_layer_buffers;
let new_layer_buffer_set = LayerBufferSet { buffers: move new_layer_buffers };
receiver.send(move new_layer_buffer_set);
// Now we don't have it // Now we don't have it
surfaces.front.have = false; surfaces.front.have = false;
// But we (hopefully) have another! // But we (hopefully) have another!
@ -237,13 +244,13 @@ fn lend_surface(surfaces: &SurfaceSet, receiver: pipes::Chan<LayerBuffer>) {
assert surfaces.front.have; assert surfaces.front.have;
} }
fn return_surface(surfaces: &SurfaceSet, layer_buffer: LayerBuffer) { fn return_surface(surfaces: &SurfaceSet, layer_buffer_set: LayerBufferSet) {
#debug("osmain: returning surface %?", layer_buffer); #debug("osmain: returning surface %?", layer_buffer_set);
// We have room for a return // We have room for a return
assert surfaces.front.have; assert surfaces.front.have;
assert !surfaces.back.have; assert !surfaces.back.have;
surfaces.back.layer_buffer = move layer_buffer; surfaces.back.layer_buffer_set = move layer_buffer_set;
// Now we have it again // Now we have it again
surfaces.back.have = true; surfaces.back.have = true;
@ -254,7 +261,7 @@ fn SurfaceSet() -> SurfaceSet {
} }
struct Surface { struct Surface {
layer_buffer: LayerBuffer, layer_buffer_set: LayerBufferSet,
mut have: bool, mut have: bool,
} }
@ -267,7 +274,8 @@ fn Surface() -> Surface {
size: Size2D(800u, 600u), size: Size2D(800u, 600u),
stride: 800 stride: 800
}; };
Surface { layer_buffer: move layer_buffer, have: true } let layer_buffer_set = LayerBufferSet { buffers: ~[ move layer_buffer ] };
Surface { layer_buffer_set: move layer_buffer_set, have: true }
} }
/// A function for spawning into the platform's main thread /// A function for spawning into the platform's main thread