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 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 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<DrawTarget>); fn begin_drawing(next_dt: pipes::Chan<LayerBuffer>);
fn draw(next_dt: pipes::Chan<DrawTarget>, +draw_me: DrawTarget); fn draw(next_dt: pipes::Chan<LayerBuffer>, +draw_me: LayerBuffer);
fn add_event_listener(listener: comm::Chan<Event>); fn add_event_listener(listener: comm::Chan<Event>);
} }

View file

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

View file

@ -25,8 +25,6 @@ use text::text_run::TextRun;
use text::font::Font; use text::font::Font;
use text::font_cache::FontCache; use text::font_cache::FontCache;
pub type Renderer = comm::Chan<Msg>; pub type Renderer = comm::Chan<Msg>;
pub enum Msg { pub enum Msg {
@ -34,8 +32,13 @@ pub enum Msg {
ExitMsg(pipes::Chan<()>) ExitMsg(pipes::Chan<()>)
} }
struct LayerBuffer {
draw_target: DrawTarget,
size: Size2D<uint>
}
struct RenderContext { struct RenderContext {
canvas: &DrawTarget, canvas: &LayerBuffer,
font_cache: @FontCache, font_cache: @FontCache,
} }
@ -43,48 +46,47 @@ pub type RenderTask = comm::Chan<Msg>;
pub fn RenderTask<C: Compositor Send>(compositor: C) -> RenderTask { pub fn RenderTask<C: Compositor Send>(compositor: C) -> RenderTask {
do task::spawn_listener |po: comm::Port<Msg>| { do task::spawn_listener |po: comm::Port<Msg>| {
let (draw_target_ch, draw_target_po) = pipes::stream(); let (layer_buffer_channel, layer_buffer_port) = pipes::stream();
let mut draw_target_ch = draw_target_ch; let mut layer_buffer_channel = layer_buffer_channel;
let mut draw_target_po = draw_target_po; let mut layer_buffer_port = layer_buffer_port;
let font_cache = FontCache(); let font_cache = FontCache();
debug!("renderer: beginning rendering loop"); debug!("renderer: beginning rendering loop");
compositor.begin_drawing(draw_target_ch); compositor.begin_drawing(move layer_buffer_channel);
loop { loop {
match po.recv() { match po.recv() {
RenderMsg(display_list) => { RenderMsg(display_list) => {
#debug("renderer: got render request"); #debug("renderer: got render request");
let draw_target = Cell(draw_target_po.recv()); let layer_buffer = Cell(layer_buffer_port.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);
do draw_target.with_ref |draw_target| { let (layer_buffer_channel, new_layer_buffer_port) = pipes::stream();
let ctx = RenderContext { let layer_buffer_channel = Cell(move layer_buffer_channel);
canvas: draw_target, layer_buffer_port = new_layer_buffer_port;
font_cache: font_cache
};
clear(&ctx); #debug("renderer: rendering");
display_list.draw(&ctx)
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) => {
ExitMsg(response_ch) => { response_ch.send(());
response_ch.send(()); break;
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, b.to_float() as AzFloat,
1f 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>) { 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 size = Size2D(image.width as i32, image.height as i32);
let stride = image.width * 4; let stride = image.width * 4;
let azure_surface = ctx.canvas.create_source_surface_from_data(image.data, size, stride as i32, let draw_target_ref = &ctx.canvas.draw_target;
B8G8R8A8); 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), let source_rect = Rect(Point2D(0 as AzFloat, 0 as AzFloat),
Size2D(image.width as AzFloat, image.height as AzFloat)); Size2D(image.width as AzFloat, image.height as AzFloat));
let dest_rect = bounds.to_azure_rect(); let dest_rect = bounds.to_azure_rect();
let draw_surface_options = DrawSurfaceOptions(Linear, true); let draw_surface_options = DrawSurfaceOptions(Linear, true);
let draw_options = DrawOptions(1.0f as AzFloat, 0); let draw_options = DrawOptions(1.0f as AzFloat, 0);
ctx.canvas.draw_surface(azure_surface, dest_rect, source_rect, draw_surface_options, draw_target_ref.draw_surface(azure_surface, dest_rect, source_rect, draw_surface_options,
draw_options); draw_options);
} }
pub fn draw_text(ctx: &RenderContext, bounds: Rect<au>, run: &TextRun, offset: uint, length: uint) { 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 // TODO: this call needs to move into azure_hl.rs
AzDrawTargetFillGlyphs(ctx.canvas.azure_draw_target, azfont, to_unsafe_ptr(&glyphbuf), AzDrawTargetFillGlyphs(ctx.canvas.draw_target.azure_draw_target, azfont,
pattern, to_unsafe_ptr(&options), null()); to_unsafe_ptr(&glyphbuf), pattern, to_unsafe_ptr(&options), null());
AzReleaseColorPattern(pattern); AzReleaseColorPattern(pattern);
AzReleaseScaledFont(azfont); AzReleaseScaledFont(azfont);
@ -273,5 +276,5 @@ fn get_cairo_font(font: &Font) -> *cairo_scaled_font_t {
fn clear(ctx: &RenderContext) { fn clear(ctx: &RenderContext) {
let pattern = ColorPattern(Color(1f as AzFloat, 1f as AzFloat, 1f as AzFloat, 1f as AzFloat)); 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)); 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 dvec::DVec;
use azure::cairo::cairo_surface_t; use azure::cairo::cairo_surface_t;
use gfx::compositor::Compositor; use gfx::compositor::Compositor;
use gfx::render_task::LayerBuffer;
use dom::event::{Event, ResizeEvent}; use dom::event::{Event, ResizeEvent};
use layers::ImageLayer; use layers::ImageLayer;
use geom::size::Size2D; use geom::size::Size2D;
@ -28,8 +29,8 @@ enum Window {
} }
pub enum Msg { pub enum Msg {
BeginDrawing(pipes::Chan<DrawTarget>), BeginDrawing(pipes::Chan<LayerBuffer>),
Draw(pipes::Chan<DrawTarget>, DrawTarget), Draw(pipes::Chan<LayerBuffer>, LayerBuffer),
AddKeyHandler(pipes::Chan<()>), AddKeyHandler(pipes::Chan<()>),
AddEventListener(comm::Chan<Event>), AddEventListener(comm::Chan<Event>),
Exit Exit
@ -40,6 +41,7 @@ fn OSMain() -> OSMain {
do platform::runmain { do platform::runmain {
#debug("preparing to enter main loop"); #debug("preparing to enter main loop");
// FIXME: Use the servo options.
let mode; let mode;
match os::getenv("SERVO_SHARE") { match os::getenv("SERVO_SHARE") {
Some(_) => mode = ShareMode, Some(_) => mode = ShareMode,
@ -162,10 +164,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<DrawTarget>) { fn begin_drawing(next_dt: pipes::Chan<LayerBuffer>) {
self.send(BeginDrawing(next_dt)) 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)) self.send(Draw(next_dt, draw_me))
} }
fn add_event_listener(listener: comm::Chan<Event>) { fn add_event_listener(listener: comm::Chan<Event>) {
@ -178,13 +180,17 @@ struct SurfaceSet {
mut back: Surface, 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? // 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 = azure_hl::clone_mutable_draw_target(&mut surfaces.front.draw_target); let draw_target_ref = &mut surfaces.front.layer_buffer.draw_target;
#debug("osmain: lending surface %?", draw_target); let layer_buffer = LayerBuffer {
receiver.send(draw_target); 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 // Now we don't have it
surfaces.front.have = false; surfaces.front.have = false;
// But we (hopefully) have another! // But we (hopefully) have another!
@ -193,14 +199,15 @@ fn lend_surface(surfaces: &SurfaceSet, receiver: pipes::Chan<DrawTarget>) {
assert surfaces.front.have; assert surfaces.front.have;
} }
fn return_surface(surfaces: &SurfaceSet, draw_target: DrawTarget) { fn return_surface(surfaces: &SurfaceSet, layer_buffer: LayerBuffer) {
#debug("osmain: returning surface %?", draw_target); #debug("osmain: returning surface %?", layer_buffer);
// 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;
// FIXME: This is incompatible with page resizing. // 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 // Now we have it again
surfaces.back.have = true; surfaces.back.have = true;
@ -212,14 +219,15 @@ fn SurfaceSet() -> SurfaceSet {
struct Surface { struct Surface {
cairo_surface: ImageSurface, cairo_surface: ImageSurface,
draw_target: DrawTarget, layer_buffer: LayerBuffer,
mut have: bool, mut have: bool,
} }
fn Surface() -> Surface { fn Surface() -> Surface {
let cairo_surface = ImageSurface(cairo::CAIRO_FORMAT_RGB24, 800, 600); let cairo_surface = ImageSurface(cairo::CAIRO_FORMAT_RGB24, 800, 600);
let draw_target = DrawTarget(&cairo_surface); 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 /// A function for spawning into the platform's main thread