mirror of
https://github.com/servo/servo.git
synced 2025-08-05 13:40:08 +01:00
Implement parallel rendering
This commit is contained in:
parent
a338c76bc6
commit
4303419865
3 changed files with 82 additions and 32 deletions
|
@ -10,6 +10,8 @@ use geom::matrix2d::Matrix2D;
|
||||||
use geom::point::Point2D;
|
use geom::point::Point2D;
|
||||||
use geom::rect::Rect;
|
use geom::rect::Rect;
|
||||||
use geom::size::Size2D;
|
use geom::size::Size2D;
|
||||||
|
use std::arc::ARC;
|
||||||
|
use std::arc;
|
||||||
|
|
||||||
const TILE_SIZE: uint = 512;
|
const TILE_SIZE: uint = 512;
|
||||||
|
|
||||||
|
@ -18,13 +20,15 @@ pub struct RenderLayer {
|
||||||
size: Size2D<uint>
|
size: Size2D<uint>
|
||||||
}
|
}
|
||||||
|
|
||||||
type RenderFn = &fn(layer: &RenderLayer, buffer: LayerBuffer, return_buffer: Chan<LayerBuffer>);
|
type RenderFn = &fn(layer: *RenderLayer,
|
||||||
|
buffer: LayerBuffer,
|
||||||
|
return_buffer: Chan<LayerBuffer>);
|
||||||
|
|
||||||
/// Given a layer and a buffer, either reuses the buffer (if it's of the right size and format)
|
/// Given a layer and a buffer, either reuses the buffer (if it's of the right size and format)
|
||||||
/// or creates a new buffer (if it's not of the appropriate size and format) and invokes the
|
/// or creates a new buffer (if it's not of the appropriate size and format) and invokes the
|
||||||
/// given callback with the render layer and the buffer. Returns the resulting layer buffer (which
|
/// given callback with the render layer and the buffer. Returns the resulting layer buffer (which
|
||||||
/// might be the old layer buffer if it had the appropriate size and format).
|
/// might be the old layer buffer if it had the appropriate size and format).
|
||||||
pub fn render_layers(layer: &RenderLayer,
|
pub fn render_layers(layer_ref: *RenderLayer,
|
||||||
buffer_set: LayerBufferSet,
|
buffer_set: LayerBufferSet,
|
||||||
opts: &Opts,
|
opts: &Opts,
|
||||||
f: RenderFn) -> LayerBufferSet {
|
f: RenderFn) -> LayerBufferSet {
|
||||||
|
@ -34,6 +38,7 @@ pub fn render_layers(layer: &RenderLayer,
|
||||||
let new_buffer_ports = dvec::DVec();
|
let new_buffer_ports = dvec::DVec();
|
||||||
|
|
||||||
// Divide up the layer into tiles.
|
// Divide up the layer into tiles.
|
||||||
|
let layer: &RenderLayer = unsafe { cast::transmute(layer_ref) };
|
||||||
let mut y = 0;
|
let mut y = 0;
|
||||||
while y < layer.size.height {
|
while y < layer.size.height {
|
||||||
let mut x = 0;
|
let mut x = 0;
|
||||||
|
@ -107,7 +112,8 @@ pub fn render_layers(layer: &RenderLayer,
|
||||||
let (new_buffer_chan, new_buffer_port) = pipes::stream();
|
let (new_buffer_chan, new_buffer_port) = pipes::stream();
|
||||||
|
|
||||||
// Send the buffer to the child.
|
// Send the buffer to the child.
|
||||||
f(layer, move buffer, move new_buffer_chan);
|
// FIXME: Don't copy the RenderLayer.
|
||||||
|
f(layer_ref, move buffer, move new_buffer_chan);
|
||||||
|
|
||||||
// Enqueue the port.
|
// Enqueue the port.
|
||||||
new_buffer_ports.push(move new_buffer_port);
|
new_buffer_ports.push(move new_buffer_port);
|
||||||
|
|
|
@ -11,8 +11,12 @@ use core::comm::*;
|
||||||
use core::libc::size_t;
|
use core::libc::size_t;
|
||||||
use core::libc::types::common::c99::uint16_t;
|
use core::libc::types::common::c99::uint16_t;
|
||||||
use core::pipes::{Port, Chan};
|
use core::pipes::{Port, Chan};
|
||||||
|
use core::task::SingleThreaded;
|
||||||
use geom::matrix2d::Matrix2D;
|
use geom::matrix2d::Matrix2D;
|
||||||
|
use std::arc::ARC;
|
||||||
|
use std::arc;
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
|
use std::thread_pool::ThreadPool;
|
||||||
|
|
||||||
pub enum Msg {
|
pub enum Msg {
|
||||||
RenderMsg(RenderLayer),
|
RenderMsg(RenderLayer),
|
||||||
|
@ -30,22 +34,47 @@ pub fn RenderTask<C: Compositor Send>(compositor: C, opts: Opts) -> RenderTask {
|
||||||
let compositor = compositor_cell.take();
|
let compositor = compositor_cell.take();
|
||||||
compositor.begin_drawing(move layer_buffer_channel);
|
compositor.begin_drawing(move layer_buffer_channel);
|
||||||
|
|
||||||
|
// FIXME: Annoying three-cell dance here. We need one-shot closures.
|
||||||
|
let opts = opts_cell.with_ref(|o| copy *o);
|
||||||
|
let n_threads = opts.n_render_threads;
|
||||||
|
let new_opts_cell = Cell(move opts);
|
||||||
|
|
||||||
|
let thread_pool = do ThreadPool::new(n_threads, Some(SingleThreaded))
|
||||||
|
|move new_opts_cell| {
|
||||||
|
let opts_cell = Cell(new_opts_cell.with_ref(|o| copy *o));
|
||||||
|
let f: ~fn(uint) -> ThreadRenderContext = |thread_index, move opts_cell| {
|
||||||
|
ThreadRenderContext {
|
||||||
|
thread_index: thread_index,
|
||||||
|
font_ctx: @FontContext::new(opts_cell.with_ref(|o| o.render_backend), false),
|
||||||
|
opts: opts_cell.with_ref(|o| copy *o),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
move f
|
||||||
|
};
|
||||||
|
|
||||||
Renderer {
|
Renderer {
|
||||||
port: po,
|
port: po,
|
||||||
compositor: move compositor,
|
compositor: move compositor,
|
||||||
mut layer_buffer_set_port: Cell(move layer_buffer_set_port),
|
mut layer_buffer_set_port: Cell(move layer_buffer_set_port),
|
||||||
font_ctx: @FontContext::new(opts_cell.with_ref(|o| o.render_backend), false),
|
thread_pool: move thread_pool,
|
||||||
opts: opts_cell.take()
|
opts: opts_cell.take()
|
||||||
}.start();
|
}.start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Data that needs to be kept around for each render thread.
|
||||||
|
priv struct ThreadRenderContext {
|
||||||
|
thread_index: uint,
|
||||||
|
font_ctx: @FontContext,
|
||||||
|
opts: Opts,
|
||||||
|
}
|
||||||
|
|
||||||
priv struct Renderer<C: Compositor Send> {
|
priv struct Renderer<C: Compositor Send> {
|
||||||
port: comm::Port<Msg>,
|
port: comm::Port<Msg>,
|
||||||
compositor: C,
|
compositor: C,
|
||||||
layer_buffer_set_port: Cell<pipes::Port<LayerBufferSet>>,
|
layer_buffer_set_port: Cell<pipes::Port<LayerBufferSet>>,
|
||||||
font_ctx: @FontContext,
|
thread_pool: ThreadPool<ThreadRenderContext>,
|
||||||
opts: Opts
|
opts: Opts,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C: Compositor Send> Renderer<C> {
|
impl<C: Compositor Send> Renderer<C> {
|
||||||
|
@ -76,44 +105,51 @@ impl<C: Compositor Send> Renderer<C> {
|
||||||
let (layer_buffer_set_channel, new_layer_buffer_set_port) = pipes::stream();
|
let (layer_buffer_set_channel, new_layer_buffer_set_port) = pipes::stream();
|
||||||
self.layer_buffer_set_port.put_back(move new_layer_buffer_set_port);
|
self.layer_buffer_set_port.put_back(move new_layer_buffer_set_port);
|
||||||
|
|
||||||
let render_layer_cell = Cell(move render_layer);
|
|
||||||
let layer_buffer_set_cell = Cell(move layer_buffer_set);
|
let layer_buffer_set_cell = Cell(move layer_buffer_set);
|
||||||
let layer_buffer_set_channel_cell = Cell(move layer_buffer_set_channel);
|
let layer_buffer_set_channel_cell = Cell(move layer_buffer_set_channel);
|
||||||
|
|
||||||
#debug("renderer: rendering");
|
#debug("renderer: rendering");
|
||||||
|
|
||||||
do util::time::time(~"rendering") {
|
do util::time::time(~"rendering") {
|
||||||
let render_layer = render_layer_cell.take();
|
|
||||||
let layer_buffer_set = layer_buffer_set_cell.take();
|
let layer_buffer_set = layer_buffer_set_cell.take();
|
||||||
let layer_buffer_set_channel = layer_buffer_set_channel_cell.take();
|
let layer_buffer_set_channel = layer_buffer_set_channel_cell.take();
|
||||||
|
|
||||||
let layer_buffer_set = do render_layers(&render_layer,
|
let layer_buffer_set = do render_layers(ptr::to_unsafe_ptr(&render_layer),
|
||||||
move layer_buffer_set,
|
move layer_buffer_set,
|
||||||
&self.opts)
|
&self.opts)
|
||||||
|render_layer, layer_buffer, buffer_chan| {
|
|render_layer_ref, layer_buffer, buffer_chan| {
|
||||||
{
|
let layer_buffer_cell = Cell(move layer_buffer);
|
||||||
// Build the render context.
|
do self.thread_pool.execute |thread_render_context,
|
||||||
let ctx = RenderContext {
|
move render_layer_ref,
|
||||||
canvas: &layer_buffer,
|
move buffer_chan,
|
||||||
font_ctx: self.font_ctx,
|
move layer_buffer_cell| {
|
||||||
opts: &self.opts
|
do layer_buffer_cell.with_ref |layer_buffer| {
|
||||||
};
|
// Build the render context.
|
||||||
|
let ctx = RenderContext {
|
||||||
|
canvas: layer_buffer,
|
||||||
|
font_ctx: thread_render_context.font_ctx,
|
||||||
|
opts: &thread_render_context.opts
|
||||||
|
};
|
||||||
|
|
||||||
// Apply the translation to render the tile we want.
|
// Apply the translation to render the tile we want.
|
||||||
let matrix: Matrix2D<AzFloat> = Matrix2D::identity();
|
let matrix: Matrix2D<AzFloat> = Matrix2D::identity();
|
||||||
let matrix = matrix.translate(&-(layer_buffer.rect.origin.x as AzFloat),
|
let matrix = matrix.translate(&-(layer_buffer.rect.origin.x as AzFloat),
|
||||||
&-(layer_buffer.rect.origin.y as AzFloat));
|
&-(layer_buffer.rect.origin.y as AzFloat));
|
||||||
layer_buffer.draw_target.set_transform(&matrix);
|
layer_buffer.draw_target.set_transform(&matrix);
|
||||||
|
|
||||||
// Clear the buffer.
|
// Clear the buffer.
|
||||||
ctx.clear();
|
ctx.clear();
|
||||||
|
|
||||||
// Draw the display list.
|
// Draw the display list.
|
||||||
render_layer.display_list.draw_into_context(&ctx);
|
let render_layer: &RenderLayer = unsafe {
|
||||||
|
cast::transmute(render_layer_ref)
|
||||||
|
};
|
||||||
|
render_layer.display_list.draw_into_context(&ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send back the buffer.
|
||||||
|
buffer_chan.send(layer_buffer_cell.take());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send back the buffer.
|
|
||||||
buffer_chan.send(move layer_buffer);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#debug("renderer: returning surface");
|
#debug("renderer: returning surface");
|
||||||
|
|
|
@ -7,7 +7,8 @@ use azure::azure_hl::{CoreGraphicsAcceleratedBackend, Direct2DBackend, SkiaBacke
|
||||||
pub struct Opts {
|
pub struct Opts {
|
||||||
urls: ~[~str],
|
urls: ~[~str],
|
||||||
render_mode: RenderMode,
|
render_mode: RenderMode,
|
||||||
render_backend: BackendType
|
render_backend: BackendType,
|
||||||
|
n_render_threads: uint,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum RenderMode {
|
pub enum RenderMode {
|
||||||
|
@ -23,7 +24,8 @@ pub fn from_cmdline_args(args: &[~str]) -> Opts {
|
||||||
|
|
||||||
let opts = ~[
|
let opts = ~[
|
||||||
getopts::optopt(~"o"),
|
getopts::optopt(~"o"),
|
||||||
getopts::optopt(~"r")
|
getopts::optopt(~"r"),
|
||||||
|
getopts::optopt(~"t"),
|
||||||
];
|
];
|
||||||
|
|
||||||
let opt_match = match getopts::getopts(args, opts) {
|
let opt_match = match getopts::getopts(args, opts) {
|
||||||
|
@ -42,7 +44,7 @@ pub fn from_cmdline_args(args: &[~str]) -> Opts {
|
||||||
None => { Screen }
|
None => { Screen }
|
||||||
};
|
};
|
||||||
|
|
||||||
let render_backend = match getopts::opt_maybe_str(move opt_match, ~"r") {
|
let render_backend = match getopts::opt_maybe_str(copy opt_match, ~"r") {
|
||||||
Some(move backend_str) => {
|
Some(move backend_str) => {
|
||||||
if backend_str == ~"direct2d" {
|
if backend_str == ~"direct2d" {
|
||||||
Direct2DBackend
|
Direct2DBackend
|
||||||
|
@ -61,9 +63,15 @@ pub fn from_cmdline_args(args: &[~str]) -> Opts {
|
||||||
None => CairoBackend
|
None => CairoBackend
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let n_render_threads: uint = match getopts::opt_maybe_str(move opt_match, ~"t") {
|
||||||
|
Some(move n_render_threads_str) => from_str::from_str(n_render_threads_str).get(),
|
||||||
|
None => 2, // FIXME: Number of cores.
|
||||||
|
};
|
||||||
|
|
||||||
Opts {
|
Opts {
|
||||||
urls: move urls,
|
urls: move urls,
|
||||||
render_mode: move render_mode,
|
render_mode: move render_mode,
|
||||||
render_backend: move render_backend,
|
render_backend: move render_backend,
|
||||||
|
n_render_threads: n_render_threads,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue