mirror of
https://github.com/servo/servo.git
synced 2025-08-06 06:00:15 +01:00
Add a LayerBuffer abstraction instead of sending around DrawTargets directly.
A step on the way toward window resizing.
This commit is contained in:
parent
d21d27e086
commit
ea432a28c6
4 changed files with 83 additions and 68 deletions
|
@ -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>);
|
||||
}
|
||||
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue