aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPatrick Walton <pcwalton@mimiga.net>2012-11-09 17:58:51 -0800
committerPatrick Walton <pcwalton@mimiga.net>2012-11-09 17:58:51 -0800
commit430341986564af1bd1d200f86fc819aeae5e58fc (patch)
treeece5aa91370039534858cfc4ae9f757409e28799
parenta338c76bc6569ce4de39a36f576102b0aff3470a (diff)
downloadservo-430341986564af1bd1d200f86fc819aeae5e58fc.tar.gz
servo-430341986564af1bd1d200f86fc819aeae5e58fc.zip
Implement parallel rendering
-rw-r--r--src/servo/gfx/render_layers.rs12
-rw-r--r--src/servo/gfx/render_task.rs94
-rw-r--r--src/servo/opts.rs14
3 files changed, 85 insertions, 35 deletions
diff --git a/src/servo/gfx/render_layers.rs b/src/servo/gfx/render_layers.rs
index 2a4b0dd380c..1173fd61cc0 100644
--- a/src/servo/gfx/render_layers.rs
+++ b/src/servo/gfx/render_layers.rs
@@ -10,6 +10,8 @@ use geom::matrix2d::Matrix2D;
use geom::point::Point2D;
use geom::rect::Rect;
use geom::size::Size2D;
+use std::arc::ARC;
+use std::arc;
const TILE_SIZE: uint = 512;
@@ -18,13 +20,15 @@ pub struct RenderLayer {
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)
/// 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
/// 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,
opts: &Opts,
f: RenderFn) -> LayerBufferSet {
@@ -34,6 +38,7 @@ pub fn render_layers(layer: &RenderLayer,
let new_buffer_ports = dvec::DVec();
// Divide up the layer into tiles.
+ let layer: &RenderLayer = unsafe { cast::transmute(layer_ref) };
let mut y = 0;
while y < layer.size.height {
let mut x = 0;
@@ -107,7 +112,8 @@ pub fn render_layers(layer: &RenderLayer,
let (new_buffer_chan, new_buffer_port) = pipes::stream();
// 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.
new_buffer_ports.push(move new_buffer_port);
diff --git a/src/servo/gfx/render_task.rs b/src/servo/gfx/render_task.rs
index 28d60dc9496..157a4f0b376 100644
--- a/src/servo/gfx/render_task.rs
+++ b/src/servo/gfx/render_task.rs
@@ -11,8 +11,12 @@ use core::comm::*;
use core::libc::size_t;
use core::libc::types::common::c99::uint16_t;
use core::pipes::{Port, Chan};
+use core::task::SingleThreaded;
use geom::matrix2d::Matrix2D;
+use std::arc::ARC;
+use std::arc;
use std::cell::Cell;
+use std::thread_pool::ThreadPool;
pub enum Msg {
RenderMsg(RenderLayer),
@@ -30,22 +34,47 @@ pub fn RenderTask<C: Compositor Send>(compositor: C, opts: Opts) -> RenderTask {
let compositor = compositor_cell.take();
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 {
port: po,
compositor: move compositor,
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()
}.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> {
port: comm::Port<Msg>,
compositor: C,
layer_buffer_set_port: Cell<pipes::Port<LayerBufferSet>>,
- font_ctx: @FontContext,
- opts: Opts
+ thread_pool: ThreadPool<ThreadRenderContext>,
+ opts: Opts,
}
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();
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_channel_cell = Cell(move layer_buffer_set_channel);
#debug("renderer: 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_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,
&self.opts)
- |render_layer, layer_buffer, buffer_chan| {
- {
- // Build the render context.
- let ctx = RenderContext {
- canvas: &layer_buffer,
- font_ctx: self.font_ctx,
- opts: &self.opts
- };
-
- // Apply the translation to render the tile we want.
- let matrix: Matrix2D<AzFloat> = Matrix2D::identity();
- let matrix = matrix.translate(&-(layer_buffer.rect.origin.x as AzFloat),
- &-(layer_buffer.rect.origin.y as AzFloat));
- layer_buffer.draw_target.set_transform(&matrix);
-
- // Clear the buffer.
- ctx.clear();
-
- // Draw the display list.
- render_layer.display_list.draw_into_context(&ctx);
+ |render_layer_ref, layer_buffer, buffer_chan| {
+ let layer_buffer_cell = Cell(move layer_buffer);
+ do self.thread_pool.execute |thread_render_context,
+ move render_layer_ref,
+ move buffer_chan,
+ move layer_buffer_cell| {
+ 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.
+ let matrix: Matrix2D<AzFloat> = Matrix2D::identity();
+ let matrix = matrix.translate(&-(layer_buffer.rect.origin.x as AzFloat),
+ &-(layer_buffer.rect.origin.y as AzFloat));
+ layer_buffer.draw_target.set_transform(&matrix);
+
+ // Clear the buffer.
+ ctx.clear();
+
+ // Draw the display list.
+ 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");
diff --git a/src/servo/opts.rs b/src/servo/opts.rs
index 4db8cd8a0cd..2460587994a 100644
--- a/src/servo/opts.rs
+++ b/src/servo/opts.rs
@@ -7,7 +7,8 @@ use azure::azure_hl::{CoreGraphicsAcceleratedBackend, Direct2DBackend, SkiaBacke
pub struct Opts {
urls: ~[~str],
render_mode: RenderMode,
- render_backend: BackendType
+ render_backend: BackendType,
+ n_render_threads: uint,
}
pub enum RenderMode {
@@ -23,7 +24,8 @@ pub fn from_cmdline_args(args: &[~str]) -> Opts {
let opts = ~[
getopts::optopt(~"o"),
- getopts::optopt(~"r")
+ getopts::optopt(~"r"),
+ getopts::optopt(~"t"),
];
let opt_match = match getopts::getopts(args, opts) {
@@ -42,7 +44,7 @@ pub fn from_cmdline_args(args: &[~str]) -> Opts {
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) => {
if backend_str == ~"direct2d" {
Direct2DBackend
@@ -61,9 +63,15 @@ pub fn from_cmdline_args(args: &[~str]) -> Opts {
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 {
urls: move urls,
render_mode: move render_mode,
render_backend: move render_backend,
+ n_render_threads: n_render_threads,
}
}