Add a LayerBuffer abstraction instead of sending around DrawTargets directly.

A step on the way toward window resizing.
This commit is contained in:
Patrick Walton 2012-10-11 14:57:40 -07:00
parent d21d27e086
commit ea432a28c6
4 changed files with 83 additions and 68 deletions

View file

@ -1,13 +1,13 @@
use dom::event::Event;
use azure::azure_hl::DrawTarget;
use gfx::render_task::LayerBuffer;
/**
The interface used to by the renderer to aquire draw targets for
each rendered frame and submit them to be drawn to the display
*/
trait Compositor {
fn begin_drawing(next_dt: pipes::Chan<DrawTarget>);
fn draw(next_dt: pipes::Chan<DrawTarget>, +draw_me: DrawTarget);
fn begin_drawing(next_dt: pipes::Chan<LayerBuffer>);
fn draw(next_dt: pipes::Chan<LayerBuffer>, +draw_me: LayerBuffer);
fn add_event_listener(listener: comm::Chan<Event>);
}

View file

@ -27,20 +27,22 @@ use dvec::DVec;
use display_list::DisplayList;
use std::cell::Cell;
use core::io::BytesWriter;
use gfx::render_task::LayerBuffer;
use geom::size::Size2D;
pub type PngCompositor = Chan<Msg>;
pub enum Msg {
BeginDrawing(pipes::Chan<DrawTarget>),
Draw(pipes::Chan<DrawTarget>, DrawTarget),
BeginDrawing(pipes::Chan<LayerBuffer>),
Draw(pipes::Chan<LayerBuffer>, LayerBuffer),
Exit
}
impl Chan<Msg> : Compositor {
fn begin_drawing(next_dt: pipes::Chan<DrawTarget>) {
fn begin_drawing(next_dt: pipes::Chan<LayerBuffer>) {
self.send(BeginDrawing(next_dt))
}
fn draw(next_dt: pipes::Chan<DrawTarget>, draw_me: DrawTarget) {
fn draw(next_dt: pipes::Chan<LayerBuffer>, draw_me: LayerBuffer) {
self.send(Draw(next_dt, draw_me))
}
fn add_event_listener(_listener: Chan<Event>) {
@ -51,17 +53,19 @@ impl Chan<Msg> : Compositor {
pub fn PngCompositor(output: Chan<~[u8]>) -> PngCompositor {
do spawn_listener |po: Port<Msg>| {
let cairo_surface = ImageSurface(CAIRO_FORMAT_ARGB32, 800, 600);
let draw_target = Cell(DrawTarget(&cairo_surface));
let draw_target = DrawTarget(&cairo_surface);
let layer_buffer = LayerBuffer { draw_target: move draw_target, size: Size2D(800u, 600u) };
let layer_buffer = Cell(move layer_buffer);
loop {
match po.recv() {
BeginDrawing(sender) => {
debug!("png_compositor: begin_drawing");
sender.send(draw_target.take());
sender.send(layer_buffer.take());
}
Draw(move sender, move dt) => {
Draw(move sender, move layer_buffer) => {
debug!("png_compositor: draw");
do_draw(sender, dt, output, &cairo_surface);
do_draw(sender, layer_buffer, output, &cairo_surface);
}
Exit => break
}
@ -69,8 +73,8 @@ pub fn PngCompositor(output: Chan<~[u8]>) -> PngCompositor {
}
}
fn do_draw(sender: pipes::Chan<DrawTarget>,
dt: DrawTarget,
fn do_draw(sender: pipes::Chan<LayerBuffer>,
layer_buffer: LayerBuffer,
output: Chan<~[u8]>,
cairo_surface: &ImageSurface) {
let buffer = BytesWriter();
@ -78,7 +82,7 @@ fn do_draw(sender: pipes::Chan<DrawTarget>,
output.send(buffer.buf.get());
// Send the next draw target to the renderer
sender.send(move dt);
sender.send(move layer_buffer);
}
#[test]

View file

@ -25,8 +25,6 @@ use text::text_run::TextRun;
use text::font::Font;
use text::font_cache::FontCache;
pub type Renderer = comm::Chan<Msg>;
pub enum Msg {
@ -34,8 +32,13 @@ pub enum Msg {
ExitMsg(pipes::Chan<()>)
}
struct LayerBuffer {
draw_target: DrawTarget,
size: Size2D<uint>
}
struct RenderContext {
canvas: &DrawTarget,
canvas: &LayerBuffer,
font_cache: @FontCache,
}
@ -43,48 +46,47 @@ pub type RenderTask = comm::Chan<Msg>;
pub fn RenderTask<C: Compositor Send>(compositor: C) -> RenderTask {
do task::spawn_listener |po: comm::Port<Msg>| {
let (draw_target_ch, draw_target_po) = pipes::stream();
let mut draw_target_ch = draw_target_ch;
let mut draw_target_po = draw_target_po;
let (layer_buffer_channel, layer_buffer_port) = pipes::stream();
let mut layer_buffer_channel = layer_buffer_channel;
let mut layer_buffer_port = layer_buffer_port;
let font_cache = FontCache();
debug!("renderer: beginning rendering loop");
compositor.begin_drawing(draw_target_ch);
compositor.begin_drawing(move layer_buffer_channel);
loop {
match po.recv() {
RenderMsg(display_list) => {
#debug("renderer: got render request");
let draw_target = Cell(draw_target_po.recv());
let (ch, po) = pipes::stream();
let mut draw_target_ch_ = Some(ch);
draw_target_po = po;
#debug("renderer: rendering");
do util::time::time(~"rendering") {
let mut draw_target_ch = None;
draw_target_ch_ <-> draw_target_ch;
let draw_target_ch = option::unwrap(draw_target_ch);
RenderMsg(display_list) => {
#debug("renderer: got render request");
let layer_buffer = Cell(layer_buffer_port.recv());
do draw_target.with_ref |draw_target| {
let ctx = RenderContext {
canvas: draw_target,
font_cache: font_cache
};
let (layer_buffer_channel, new_layer_buffer_port) = pipes::stream();
let layer_buffer_channel = Cell(move layer_buffer_channel);
layer_buffer_port = new_layer_buffer_port;
clear(&ctx);
display_list.draw(&ctx)
#debug("renderer: rendering");
do util::time::time(~"rendering") {
do layer_buffer.with_ref |layer_buffer_ref| {
let ctx = RenderContext {
canvas: layer_buffer_ref,
font_cache: font_cache
};
clear(&ctx);
display_list.draw(&ctx)
}
#debug("renderer: returning surface");
compositor.draw(layer_buffer_channel.take(), layer_buffer.take());
}
#debug("renderer: returning surface");
compositor.draw(draw_target_ch, draw_target.take());
}
}
ExitMsg(response_ch) => {
response_ch.send(());
break;
}
ExitMsg(response_ch) => {
response_ch.send(());
break;
}
}
}
}
@ -117,7 +119,7 @@ pub fn draw_solid_color(ctx: &RenderContext, bounds: &Rect<au>, r: u8, g: u8, b:
b.to_float() as AzFloat,
1f as AzFloat);
ctx.canvas.fill_rect(&bounds.to_azure_rect(), &ColorPattern(color));
ctx.canvas.draw_target.fill_rect(&bounds.to_azure_rect(), &ColorPattern(color));
}
pub fn draw_image(ctx: &RenderContext, bounds: Rect<au>, image: ARC<~Image>) {
@ -125,15 +127,16 @@ pub fn draw_image(ctx: &RenderContext, bounds: Rect<au>, image: ARC<~Image>) {
let size = Size2D(image.width as i32, image.height as i32);
let stride = image.width * 4;
let azure_surface = ctx.canvas.create_source_surface_from_data(image.data, size, stride as i32,
B8G8R8A8);
let draw_target_ref = &ctx.canvas.draw_target;
let azure_surface = draw_target_ref.create_source_surface_from_data(image.data, size,
stride as i32, B8G8R8A8);
let source_rect = Rect(Point2D(0 as AzFloat, 0 as AzFloat),
Size2D(image.width as AzFloat, image.height as AzFloat));
let dest_rect = bounds.to_azure_rect();
let draw_surface_options = DrawSurfaceOptions(Linear, true);
let draw_options = DrawOptions(1.0f as AzFloat, 0);
ctx.canvas.draw_surface(azure_surface, dest_rect, source_rect, draw_surface_options,
draw_options);
draw_target_ref.draw_surface(azure_surface, dest_rect, source_rect, draw_surface_options,
draw_options);
}
pub fn draw_text(ctx: &RenderContext, bounds: Rect<au>, run: &TextRun, offset: uint, length: uint) {
@ -204,8 +207,8 @@ pub fn draw_text(ctx: &RenderContext, bounds: Rect<au>, run: &TextRun, offset: u
}};
// TODO: this call needs to move into azure_hl.rs
AzDrawTargetFillGlyphs(ctx.canvas.azure_draw_target, azfont, to_unsafe_ptr(&glyphbuf),
pattern, to_unsafe_ptr(&options), null());
AzDrawTargetFillGlyphs(ctx.canvas.draw_target.azure_draw_target, azfont,
to_unsafe_ptr(&glyphbuf), pattern, to_unsafe_ptr(&options), null());
AzReleaseColorPattern(pattern);
AzReleaseScaledFont(azfont);
@ -273,5 +276,5 @@ fn get_cairo_font(font: &Font) -> *cairo_scaled_font_t {
fn clear(ctx: &RenderContext) {
let pattern = ColorPattern(Color(1f as AzFloat, 1f as AzFloat, 1f as AzFloat, 1f as AzFloat));
let rect = Rect(Point2D(0 as AzFloat, 0 as AzFloat), Size2D(800 as AzFloat, 600 as AzFloat));
ctx.canvas.fill_rect(&rect, &pattern);
ctx.canvas.draw_target.fill_rect(&rect, &pattern);
}

View file

@ -5,6 +5,7 @@ use azure::cairo_hl::ImageSurface;
use dvec::DVec;
use azure::cairo::cairo_surface_t;
use gfx::compositor::Compositor;
use gfx::render_task::LayerBuffer;
use dom::event::{Event, ResizeEvent};
use layers::ImageLayer;
use geom::size::Size2D;
@ -28,8 +29,8 @@ enum Window {
}
pub enum Msg {
BeginDrawing(pipes::Chan<DrawTarget>),
Draw(pipes::Chan<DrawTarget>, DrawTarget),
BeginDrawing(pipes::Chan<LayerBuffer>),
Draw(pipes::Chan<LayerBuffer>, LayerBuffer),
AddKeyHandler(pipes::Chan<()>),
AddEventListener(comm::Chan<Event>),
Exit
@ -40,6 +41,7 @@ fn OSMain() -> OSMain {
do platform::runmain {
#debug("preparing to enter main loop");
// FIXME: Use the servo options.
let mode;
match os::getenv("SERVO_SHARE") {
Some(_) => mode = ShareMode,
@ -162,10 +164,10 @@ Implementation to allow the osmain channel to be used as a graphics
compositor for the renderer
*/
impl OSMain : Compositor {
fn begin_drawing(next_dt: pipes::Chan<DrawTarget>) {
fn begin_drawing(next_dt: pipes::Chan<LayerBuffer>) {
self.send(BeginDrawing(next_dt))
}
fn draw(next_dt: pipes::Chan<DrawTarget>, draw_me: DrawTarget) {
fn draw(next_dt: pipes::Chan<LayerBuffer>, draw_me: LayerBuffer) {
self.send(Draw(next_dt, draw_me))
}
fn add_event_listener(listener: comm::Chan<Event>) {
@ -178,13 +180,17 @@ struct SurfaceSet {
mut back: Surface,
}
fn lend_surface(surfaces: &SurfaceSet, receiver: pipes::Chan<DrawTarget>) {
fn lend_surface(surfaces: &SurfaceSet, receiver: pipes::Chan<LayerBuffer>) {
// We are in a position to lend out the surface?
assert surfaces.front.have;
// Ok then take it
let draw_target = azure_hl::clone_mutable_draw_target(&mut surfaces.front.draw_target);
#debug("osmain: lending surface %?", draw_target);
receiver.send(draw_target);
let draw_target_ref = &mut surfaces.front.layer_buffer.draw_target;
let layer_buffer = LayerBuffer {
draw_target: azure_hl::clone_mutable_draw_target(draw_target_ref),
size: copy surfaces.front.layer_buffer.size
};
#debug("osmain: lending surface %?", layer_buffer);
receiver.send(layer_buffer);
// Now we don't have it
surfaces.front.have = false;
// But we (hopefully) have another!
@ -193,14 +199,15 @@ fn lend_surface(surfaces: &SurfaceSet, receiver: pipes::Chan<DrawTarget>) {
assert surfaces.front.have;
}
fn return_surface(surfaces: &SurfaceSet, draw_target: DrawTarget) {
#debug("osmain: returning surface %?", draw_target);
fn return_surface(surfaces: &SurfaceSet, layer_buffer: LayerBuffer) {
#debug("osmain: returning surface %?", layer_buffer);
// We have room for a return
assert surfaces.front.have;
assert !surfaces.back.have;
// FIXME: This is incompatible with page resizing.
assert surfaces.back.draw_target.azure_draw_target == draw_target.azure_draw_target;
assert surfaces.back.layer_buffer.draw_target.azure_draw_target ==
layer_buffer.draw_target.azure_draw_target;
// Now we have it again
surfaces.back.have = true;
@ -212,14 +219,15 @@ fn SurfaceSet() -> SurfaceSet {
struct Surface {
cairo_surface: ImageSurface,
draw_target: DrawTarget,
layer_buffer: LayerBuffer,
mut have: bool,
}
fn Surface() -> Surface {
let cairo_surface = ImageSurface(cairo::CAIRO_FORMAT_RGB24, 800, 600);
let draw_target = DrawTarget(&cairo_surface);
Surface { cairo_surface: cairo_surface, draw_target: draw_target, have: true }
let layer_buffer = LayerBuffer { draw_target: move draw_target, size: Size2D(800u, 600u) };
Surface { cairo_surface: cairo_surface, layer_buffer: move layer_buffer, have: true }
}
/// A function for spawning into the platform's main thread