diff options
author | Patrick Walton <pcwalton@mimiga.net> | 2012-11-09 17:58:51 -0800 |
---|---|---|
committer | Patrick Walton <pcwalton@mimiga.net> | 2012-11-09 17:58:51 -0800 |
commit | 430341986564af1bd1d200f86fc819aeae5e58fc (patch) | |
tree | ece5aa91370039534858cfc4ae9f757409e28799 | |
parent | a338c76bc6569ce4de39a36f576102b0aff3470a (diff) | |
download | servo-430341986564af1bd1d200f86fc819aeae5e58fc.tar.gz servo-430341986564af1bd1d200f86fc819aeae5e58fc.zip |
Implement parallel rendering
-rw-r--r-- | src/servo/gfx/render_layers.rs | 12 | ||||
-rw-r--r-- | src/servo/gfx/render_task.rs | 94 | ||||
-rw-r--r-- | src/servo/opts.rs | 14 |
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, } } |