From ea432a28c6368f8331796823a00723ffdb68a175 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Thu, 11 Oct 2012 14:57:40 -0700 Subject: [PATCH] Add a LayerBuffer abstraction instead of sending around DrawTargets directly. A step on the way toward window resizing. --- src/servo/gfx/compositor.rs | 6 +-- src/servo/gfx/png_compositor.rs | 26 +++++----- src/servo/gfx/render_task.rs | 85 +++++++++++++++++---------------- src/servo/platform/osmain.rs | 34 ++++++++----- 4 files changed, 83 insertions(+), 68 deletions(-) diff --git a/src/servo/gfx/compositor.rs b/src/servo/gfx/compositor.rs index 394b02bfe36..1776c4534ea 100644 --- a/src/servo/gfx/compositor.rs +++ b/src/servo/gfx/compositor.rs @@ -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); - fn draw(next_dt: pipes::Chan, +draw_me: DrawTarget); + fn begin_drawing(next_dt: pipes::Chan); + fn draw(next_dt: pipes::Chan, +draw_me: LayerBuffer); fn add_event_listener(listener: comm::Chan); } diff --git a/src/servo/gfx/png_compositor.rs b/src/servo/gfx/png_compositor.rs index e42ac307d79..6e429d42484 100644 --- a/src/servo/gfx/png_compositor.rs +++ b/src/servo/gfx/png_compositor.rs @@ -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; pub enum Msg { - BeginDrawing(pipes::Chan), - Draw(pipes::Chan, DrawTarget), + BeginDrawing(pipes::Chan), + Draw(pipes::Chan, LayerBuffer), Exit } impl Chan : Compositor { - fn begin_drawing(next_dt: pipes::Chan) { + fn begin_drawing(next_dt: pipes::Chan) { self.send(BeginDrawing(next_dt)) } - fn draw(next_dt: pipes::Chan, draw_me: DrawTarget) { + fn draw(next_dt: pipes::Chan, draw_me: LayerBuffer) { self.send(Draw(next_dt, draw_me)) } fn add_event_listener(_listener: Chan) { @@ -51,17 +53,19 @@ impl Chan : Compositor { pub fn PngCompositor(output: Chan<~[u8]>) -> PngCompositor { do spawn_listener |po: Port| { 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, - dt: DrawTarget, +fn do_draw(sender: pipes::Chan, + layer_buffer: LayerBuffer, output: Chan<~[u8]>, cairo_surface: &ImageSurface) { let buffer = BytesWriter(); @@ -78,7 +82,7 @@ fn do_draw(sender: pipes::Chan, output.send(buffer.buf.get()); // Send the next draw target to the renderer - sender.send(move dt); + sender.send(move layer_buffer); } #[test] diff --git a/src/servo/gfx/render_task.rs b/src/servo/gfx/render_task.rs index 1f76ec1ca6b..7422429991a 100644 --- a/src/servo/gfx/render_task.rs +++ b/src/servo/gfx/render_task.rs @@ -25,8 +25,6 @@ use text::text_run::TextRun; use text::font::Font; use text::font_cache::FontCache; - - pub type Renderer = comm::Chan; pub enum Msg { @@ -34,8 +32,13 @@ pub enum Msg { ExitMsg(pipes::Chan<()>) } +struct LayerBuffer { + draw_target: DrawTarget, + size: Size2D +} + struct RenderContext { - canvas: &DrawTarget, + canvas: &LayerBuffer, font_cache: @FontCache, } @@ -43,48 +46,47 @@ pub type RenderTask = comm::Chan; pub fn RenderTask(compositor: C) -> RenderTask { do task::spawn_listener |po: comm::Port| { - 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, 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, image: ARC<~Image>) { @@ -125,15 +127,16 @@ pub fn draw_image(ctx: &RenderContext, bounds: Rect, 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, run: &TextRun, offset: uint, length: uint) { @@ -204,8 +207,8 @@ pub fn draw_text(ctx: &RenderContext, bounds: Rect, 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); } diff --git a/src/servo/platform/osmain.rs b/src/servo/platform/osmain.rs index 3f842d1e962..a70d5a98ea7 100644 --- a/src/servo/platform/osmain.rs +++ b/src/servo/platform/osmain.rs @@ -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), - Draw(pipes::Chan, DrawTarget), + BeginDrawing(pipes::Chan), + Draw(pipes::Chan, LayerBuffer), AddKeyHandler(pipes::Chan<()>), AddEventListener(comm::Chan), 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) { + fn begin_drawing(next_dt: pipes::Chan) { self.send(BeginDrawing(next_dt)) } - fn draw(next_dt: pipes::Chan, draw_me: DrawTarget) { + fn draw(next_dt: pipes::Chan, draw_me: LayerBuffer) { self.send(Draw(next_dt, draw_me)) } fn add_event_listener(listener: comm::Chan) { @@ -178,13 +180,17 @@ struct SurfaceSet { mut back: Surface, } -fn lend_surface(surfaces: &SurfaceSet, receiver: pipes::Chan) { +fn lend_surface(surfaces: &SurfaceSet, receiver: pipes::Chan) { // 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) { 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