mirror of
https://github.com/servo/servo.git
synced 2025-08-06 22:15:33 +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 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>);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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]
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue