diff options
author | Glenn Watson <gw@intuitionlibrary.com> | 2014-06-26 14:25:28 +1000 |
---|---|---|
committer | Glenn Watson <gw@intuitionlibrary.com> | 2014-06-26 14:25:28 +1000 |
commit | 14653adda2404e6a7f315e51bd87c293b7b30b2a (patch) | |
tree | 5a74c8b80ebd18396ab3c91b628404d6ea497aa0 | |
parent | 358708723daab932ba231f82dcfe5c82f7df9fb1 (diff) | |
download | servo-14653adda2404e6a7f315e51bd87c293b7b30b2a.tar.gz servo-14653adda2404e6a7f315e51bd87c293b7b30b2a.zip |
Revert parallel render patch due to issue #2718.
-rw-r--r-- | src/components/embedding/core.rs | 1 | ||||
-rw-r--r-- | src/components/gfx/render_task.rs | 380 | ||||
-rw-r--r-- | src/components/main/servo.rs | 60 | ||||
-rw-r--r-- | src/components/msg/compositor_msg.rs | 3 | ||||
-rw-r--r-- | src/components/util/opts.rs | 27 |
5 files changed, 176 insertions, 295 deletions
diff --git a/src/components/embedding/core.rs b/src/components/embedding/core.rs index 301e5312942..4529d3799f6 100644 --- a/src/components/embedding/core.rs +++ b/src/components/embedding/core.rs @@ -59,7 +59,6 @@ pub extern "C" fn cef_run_message_loop() { headless: false, hard_fail: false, bubble_widths_separately: false, - native_threading: false }; native::start(0, 0 as **u8, proc() { servo::run(opts); diff --git a/src/components/gfx/render_task.rs b/src/components/gfx/render_task.rs index cfcd45935bb..f8411e3714a 100644 --- a/src/components/gfx/render_task.rs +++ b/src/components/gfx/render_task.rs @@ -105,6 +105,7 @@ pub struct RenderTask<C> { port: Receiver<Msg>, compositor: C, constellation_chan: ConstellationChan, + font_ctx: Box<FontContext>, opts: Opts, /// A channel to the profiler. @@ -113,6 +114,9 @@ pub struct RenderTask<C> { /// The graphics context to use. graphics_context: GraphicsContext, + /// The native graphics context. + native_graphics_context: Option<NativePaintingGraphicsContext>, + /// The layers to be rendered. render_layers: SmallVec1<RenderLayer>, @@ -122,11 +126,8 @@ pub struct RenderTask<C> { /// A counter for epoch messages epoch: Epoch, - /// Renderer workers - worker_txs: Vec<Sender<WorkerMsg>>, - - /// The receiver on which we receive rendered buffers from the workers - worker_result_rx: Receiver<Box<LayerBuffer>> + /// A data structure to store unused LayerBuffers + buffer_map: BufferMap<Box<LayerBuffer>>, } // If we implement this as a function, we get borrowck errors from borrowing @@ -137,13 +138,6 @@ macro_rules! native_graphics_context( ) ) -enum WorkerMsg { - // This is tupled so all the data can be pulled out of the message as one variable - WorkerRender((BufferRequest, Arc<DisplayList>, uint, uint, f32)), - WorkerUnusedBuffer(Box<LayerBuffer>), - WorkerExit(Sender<()>) -} - fn initialize_layers<C:RenderListener>( compositor: &mut C, pipeline_id: PipelineId, @@ -174,17 +168,22 @@ impl<C:RenderListener + Send> RenderTask<C> { send_on_failure(&mut builder, FailureMsg(failure_msg), c); builder.spawn(proc() { - { + { // Ensures RenderTask and graphics context are destroyed before shutdown msg + let native_graphics_context = compositor.get_graphics_metadata().map( + |md| NativePaintingGraphicsContext::from_metadata(&md)); let cpu_painting = opts.cpu_painting; - let (worker_result_tx, worker_result_rx) = channel(); - // FIXME: rust/#5967 let mut render_task = RenderTask { id: id, port: port, compositor: compositor, constellation_chan: constellation_chan, + font_ctx: box FontContext::new(FontContextInfo { + backend: opts.render_backend.clone(), + needs_font_list: false, + profiler_chan: profiler_chan.clone(), + }), opts: opts, profiler_chan: profiler_chan, @@ -194,21 +193,22 @@ impl<C:RenderListener + Send> RenderTask<C> { GpuGraphicsContext }, + native_graphics_context: native_graphics_context, + render_layers: SmallVec1::new(), paint_permission: false, epoch: Epoch(0), - worker_txs: vec![], - worker_result_rx: worker_result_rx + buffer_map: BufferMap::new(10000000), }; - // Now spawn the workers. We're only doing this after creating - // the RenderTask object because spawn_workers was originally - // written to be run afterward, and was refactored like so. - let worker_txs = render_task.spawn_workers(worker_result_tx); - render_task.worker_txs = worker_txs; - render_task.start(); + + // Destroy all the buffers. + match render_task.native_graphics_context.as_ref() { + Some(ctx) => render_task.buffer_map.clear(ctx), + None => (), + } } debug!("render_task: shutdown_chan send"); @@ -246,7 +246,7 @@ impl<C:RenderListener + Send> RenderTask<C> { } UnusedBufferMsg(unused_buffers) => { for buffer in unused_buffers.move_iter().rev() { - self.worker_txs.get(buffer.render_idx).send(WorkerUnusedBuffer(buffer)); + self.buffer_map.insert(native_graphics_context!(self), buffer); } } PaintPermissionGranted => { @@ -267,11 +267,6 @@ impl<C:RenderListener + Send> RenderTask<C> { self.paint_permission = false; } ExitMsg(response_ch) => { - for worker_tx in self.worker_txs.iter() { - let (tx, rx) = channel(); - worker_tx.send(WorkerExit(tx)); - rx.recv(); - } debug!("render_task: exitmsg response send"); response_ch.map(|ch| ch.send(())); break; @@ -280,204 +275,12 @@ impl<C:RenderListener + Send> RenderTask<C> { } } - fn spawn_workers(&mut self, result_tx: Sender<Box<LayerBuffer>>) -> Vec<Sender<WorkerMsg>> { - let mut worker_chans = vec![]; - for render_idx in range(0, self.opts.n_render_threads) { - let (tx, rx) = channel(); - let result_tx = result_tx.clone(); - - let opts = self.opts.clone(); - let graphics_context = self.graphics_context; - let render_backend = self.opts.render_backend; - let native_graphics_context = self.compositor.get_graphics_metadata().map( - |md| NativePaintingGraphicsContext::from_metadata(&md)); - let font_ctx_info = FontContextInfo { - backend: self.opts.render_backend, - needs_font_list: false, - profiler_chan: self.profiler_chan.clone(), - }; - let profiler_chan = self.profiler_chan.clone(); - let buffer_map: BufferMap<Box<LayerBuffer>> = BufferMap::new(10000000); - - spawn(proc() { - let mut buffer_map = buffer_map; - loop { - let render_msg: WorkerMsg = rx.recv(); - let render_data = match render_msg { - WorkerRender(render_data) => render_data, - WorkerUnusedBuffer(buffer) => { - match native_graphics_context { - None => {} - Some(ref native_graphics_context) => { - buffer_map.insert(native_graphics_context, - buffer); - } - } - continue - } - WorkerExit(tx) => { - // Cleanup and tell the RenderTask we're done - match native_graphics_context { - None => {} - Some(native_graphics_context) => { - buffer_map.clear( - &native_graphics_context); - } - } - tx.send(()); - break - } - }; - let (tile, - display_list, - layer_position_x, - layer_position_y, - scale) = render_data; - - // Optimize the display list for this tile. - let page_rect_au = geometry::f32_rect_to_au_rect(tile.page_rect); - let optimizer = DisplayListOptimizer::new(display_list, - page_rect_au); - let display_list = optimizer.optimize(); - - let width = tile.screen_rect.size.width; - let height = tile.screen_rect.size.height; - - let size = Size2D(width as i32, height as i32); - let draw_target = match graphics_context { - CpuGraphicsContext => { - DrawTarget::new(render_backend, size, B8G8R8A8) - } - GpuGraphicsContext => { - // FIXME(pcwalton): Cache the components of draw targets - // (texture color buffer, renderbuffers) instead of recreating them. - let draw_target = - DrawTarget::new_with_fbo(render_backend, - native_graphics_context.get_ref(), - size, - B8G8R8A8); - draw_target.make_current(); - draw_target - } - }; - - { - let mut font_ctx = box FontContext::new(font_ctx_info.clone()); - // Build the render context. - let mut ctx = RenderContext { - draw_target: &draw_target, - font_ctx: &mut font_ctx, - opts: &opts, - page_rect: tile.page_rect, - screen_rect: tile.screen_rect, - }; - - // Apply the translation to render the tile we want. - let matrix: Matrix2D<AzFloat> = Matrix2D::identity(); - let matrix = matrix.scale(scale as AzFloat, scale as AzFloat); - let matrix = matrix.translate(-(tile.page_rect.origin.x) as AzFloat, - -(tile.page_rect.origin.y) as AzFloat); - let matrix = matrix.translate(-(layer_position_x as AzFloat), - -(layer_position_y as AzFloat)); - - ctx.draw_target.set_transform(&matrix); - - // Clear the buffer. - ctx.clear(); - - // Draw the display list. - profile(time::RenderingDrawingCategory, profiler_chan.clone(), || { - display_list.draw_into_context(&mut ctx); - ctx.draw_target.flush(); - }); - } - - // Extract the texture from the draw target and place it into its slot in the - // buffer. If using CPU rendering, upload it first. - // - // FIXME(pcwalton): We should supply the texture and native surface *to* the - // draw target in GPU rendering mode, so that it doesn't have to recreate it. - let buffer = match graphics_context { - CpuGraphicsContext => { - let maybe_buffer = buffer_map.find(tile.screen_rect.size); - let buffer = match maybe_buffer { - Some(buffer) => { - let mut buffer = buffer; - buffer.rect = tile.page_rect; - buffer.screen_pos = tile.screen_rect; - buffer.resolution = scale; - buffer.native_surface.mark_wont_leak(); - buffer - } - None => { - // Create an empty native surface. We mark it as not leaking - // in case it dies in transit to the compositor task. - let mut native_surface: NativeSurface = - layers::platform::surface::NativeSurfaceMethods::new( - native_graphics_context.get_ref(), - Size2D(width as i32, height as i32), - width as i32 * 4); - native_surface.mark_wont_leak(); - - box LayerBuffer { - native_surface: native_surface, - rect: tile.page_rect, - screen_pos: tile.screen_rect, - resolution: scale, - stride: (width * 4) as uint, - render_idx: render_idx - } - } - }; - - draw_target.snapshot().get_data_surface().with_data(|data| { - buffer.native_surface.upload(native_graphics_context.get_ref(), data); - debug!("RENDERER uploading to native surface {:d}", - buffer.native_surface.get_id() as int); - }); - - buffer - } - GpuGraphicsContext => { - draw_target.make_current(); - let StolenGLResources { - surface: native_surface - } = draw_target.steal_gl_resources().unwrap(); - - // We mark the native surface as not leaking in case the surfaces - // die on their way to the compositor task. - let mut native_surface: NativeSurface = - NativeSurfaceAzureMethods::from_azure_surface(native_surface); - native_surface.mark_wont_leak(); - - box LayerBuffer { - native_surface: native_surface, - rect: tile.page_rect, - screen_pos: tile.screen_rect, - resolution: scale, - stride: (width * 4) as uint, - render_idx: render_idx - } - } - }; - - result_tx.send(buffer); - } - }); - worker_chans.push(tx) - } - - return worker_chans; - } - /// Renders one layer and sends the tiles back to the layer. /// /// FIXME(pcwalton): We will probably want to eventually send all layers belonging to a page in /// one transaction, to avoid the user seeing inconsistent states. fn render(&mut self, tiles: Vec<BufferRequest>, scale: f32, layer_id: LayerId) { - let mut tiles = Some(tiles); time::profile(time::RenderingCategory, self.profiler_chan.clone(), || { - let tiles = tiles.take_unwrap(); // FIXME: Try not to create a new array here. let mut new_buffers = vec!(); @@ -489,24 +292,132 @@ impl<C:RenderListener + Send> RenderTask<C> { self.compositor.set_render_state(RenderingRenderState); - // Distribute the tiles to the workers - let num_tiles = tiles.len(); - let mut worker_idx = 0; + // Divide up the layer into tiles. + for tile in tiles.iter() { + // Optimize the display list for this tile. + let page_rect_au = geometry::f32_rect_to_au_rect(tile.page_rect); + let optimizer = DisplayListOptimizer::new(render_layer.display_list.clone(), + page_rect_au); + let display_list = optimizer.optimize(); + + let width = tile.screen_rect.size.width; + let height = tile.screen_rect.size.height; + + let size = Size2D(width as i32, height as i32); + let draw_target = match self.graphics_context { + CpuGraphicsContext => { + DrawTarget::new(self.opts.render_backend, size, B8G8R8A8) + } + GpuGraphicsContext => { + // FIXME(pcwalton): Cache the components of draw targets + // (texture color buffer, renderbuffers) instead of recreating them. + let draw_target = + DrawTarget::new_with_fbo(self.opts.render_backend, + native_graphics_context!(self), + size, + B8G8R8A8); + draw_target.make_current(); + draw_target + } + }; + + { + // Build the render context. + let mut ctx = RenderContext { + draw_target: &draw_target, + font_ctx: &mut self.font_ctx, + opts: &self.opts, + page_rect: tile.page_rect, + screen_rect: tile.screen_rect, + }; - for tile in tiles.move_iter() { + // Apply the translation to render the tile we want. + let matrix: Matrix2D<AzFloat> = Matrix2D::identity(); + let matrix = matrix.scale(scale as AzFloat, scale as AzFloat); + let matrix = matrix.translate(-(tile.page_rect.origin.x) as AzFloat, + -(tile.page_rect.origin.y) as AzFloat); + let matrix = matrix.translate(-(render_layer.position.origin.x as AzFloat), + -(render_layer.position.origin.y as AzFloat)); - let display_list = render_layer.display_list.clone(); - let layer_position_x = render_layer.position.origin.x; - let layer_position_y = render_layer.position.origin.y; + ctx.draw_target.set_transform(&matrix); - self.worker_txs.get(worker_idx).send(WorkerRender((tile, display_list, layer_position_x, layer_position_y, scale))); + // Clear the buffer. + ctx.clear(); - // Round-robin the work - worker_idx = (worker_idx + 1) % self.worker_txs.len(); - } + // Draw the display list. + profile(time::RenderingDrawingCategory, self.profiler_chan.clone(), || { + display_list.draw_into_context(&mut ctx); + ctx.draw_target.flush(); + }); + } + + // Extract the texture from the draw target and place it into its slot in the + // buffer. If using CPU rendering, upload it first. + // + // FIXME(pcwalton): We should supply the texture and native surface *to* the + // draw target in GPU rendering mode, so that it doesn't have to recreate it. + let buffer = match self.graphics_context { + CpuGraphicsContext => { + let buffer = match self.buffer_map.find(tile.screen_rect.size) { + Some(buffer) => { + let mut buffer = buffer; + buffer.rect = tile.page_rect; + buffer.screen_pos = tile.screen_rect; + buffer.resolution = scale; + buffer.native_surface.mark_wont_leak(); + buffer + } + None => { + // Create an empty native surface. We mark it as not leaking + // in case it dies in transit to the compositor task. + let mut native_surface: NativeSurface = + layers::platform::surface::NativeSurfaceMethods::new( + native_graphics_context!(self), + Size2D(width as i32, height as i32), + width as i32 * 4); + native_surface.mark_wont_leak(); + + box LayerBuffer { + native_surface: native_surface, + rect: tile.page_rect, + screen_pos: tile.screen_rect, + resolution: scale, + stride: (width * 4) as uint + } + } + }; - for _ in range(0, num_tiles) { - new_buffers.push(self.worker_result_rx.recv()); + draw_target.snapshot().get_data_surface().with_data(|data| { + buffer.native_surface.upload(native_graphics_context!(self), data); + debug!("RENDERER uploading to native surface {:d}", + buffer.native_surface.get_id() as int); + }); + + buffer + } + GpuGraphicsContext => { + draw_target.make_current(); + let StolenGLResources { + surface: native_surface + } = draw_target.steal_gl_resources().unwrap(); + + // We mark the native surface as not leaking in case the surfaces + // die on their way to the compositor task. + let mut native_surface: NativeSurface = + NativeSurfaceAzureMethods::from_azure_surface(native_surface); + native_surface.mark_wont_leak(); + + box LayerBuffer { + native_surface: native_surface, + rect: tile.page_rect, + screen_pos: tile.screen_rect, + resolution: scale, + stride: (width * 4) as uint + } + } + }; + + new_buffers.push(buffer); } let layer_buffer_set = box LayerBufferSet { @@ -525,3 +436,4 @@ impl<C:RenderListener + Send> RenderTask<C> { }) } } + diff --git a/src/components/main/servo.rs b/src/components/main/servo.rs index d7c6fda9b89..c7a2a6150b7 100644 --- a/src/components/main/servo.rs +++ b/src/components/main/servo.rs @@ -51,15 +51,23 @@ extern crate core_graphics; #[cfg(target_os="macos")] extern crate core_text; +#[cfg(not(test))] use compositing::{CompositorChan, CompositorTask}; +#[cfg(not(test))] use constellation::Constellation; +#[cfg(not(test))] use servo_msg::constellation_msg::{ConstellationChan, InitLoadUrlMsg}; +#[cfg(not(test))] use servo_net::image_cache_task::{ImageCacheTask, SyncImageCacheTask}; +#[cfg(not(test))] use servo_net::resource_task::ResourceTask; +#[cfg(not(test))] use servo_util::time::Profiler; +#[cfg(not(test))] use servo_util::opts; +#[cfg(not(test))] use servo_util::url::parse_url; @@ -67,7 +75,9 @@ use servo_util::url::parse_url; use std::os; #[cfg(not(test), target_os="android")] use std::str; +#[cfg(not(test))] use std::task::TaskOpts; +#[cfg(not(test))] use url::Url; @@ -151,41 +161,11 @@ pub extern "C" fn android_start(argc: int, argv: **u8) -> int { }) } -fn spawn_main(opts: opts::Opts, - compositor_port: Receiver<compositing::Msg>, - profiler_chan: servo_util::time::ProfilerChan, - result_port: Receiver<ConstellationChan>, - p: proc(): Send) { - if !opts.native_threading { - let mut pool_config = green::PoolConfig::new(); - pool_config.event_loop_factory = rustuv::event_loop; - let mut pool = green::SchedPool::new(pool_config); - - pool.spawn(TaskOpts::new(), p); - - let constellation_chan = result_port.recv(); - - debug!("preparing to enter main loop"); - CompositorTask::create(opts, - compositor_port, - constellation_chan, - profiler_chan); - - pool.shutdown(); - - } else { - native::task::spawn(p); - let constellation_chan = result_port.recv(); - - debug!("preparing to enter main loop"); - CompositorTask::create(opts, - compositor_port, - constellation_chan, - profiler_chan); - } -} - +#[cfg(not(test))] pub fn run(opts: opts::Opts) { + let mut pool_config = green::PoolConfig::new(); + pool_config.event_loop_factory = rustuv::event_loop; + let mut pool = green::SchedPool::new(pool_config); let (compositor_port, compositor_chan) = CompositorChan::new(); let profiler_chan = Profiler::create(opts.profiler_period); @@ -194,7 +174,7 @@ pub fn run(opts: opts::Opts) { let profiler_chan_clone = profiler_chan.clone(); let (result_chan, result_port) = channel(); - spawn_main(opts.clone(), compositor_port, profiler_chan, result_port, proc() { + pool.spawn(TaskOpts::new(), proc() { let opts = &opts_clone; // Create a Servo instance. let resource_task = ResourceTask(); @@ -230,5 +210,15 @@ pub fn run(opts: opts::Opts) { // Send the constallation Chan as the result result_chan.send(constellation_chan); }); + + let constellation_chan = result_port.recv(); + + debug!("preparing to enter main loop"); + CompositorTask::create(opts, + compositor_port, + constellation_chan, + profiler_chan); + + pool.shutdown(); } diff --git a/src/components/msg/compositor_msg.rs b/src/components/msg/compositor_msg.rs index 8e2991e1eee..d96798b3184 100644 --- a/src/components/msg/compositor_msg.rs +++ b/src/components/msg/compositor_msg.rs @@ -30,9 +30,6 @@ pub struct LayerBuffer { /// NB: stride is in pixels, like OpenGL GL_UNPACK_ROW_LENGTH. pub stride: uint, - - /// Used by the RenderTask to route buffers to the correct graphics context for recycling - pub render_idx: uint } /// A set of layer buffers. This is an atomic unit used to switch between the front and back diff --git a/src/components/util/opts.rs b/src/components/util/opts.rs index 123507dd16f..166ff0a9a9a 100644 --- a/src/components/util/opts.rs +++ b/src/components/util/opts.rs @@ -61,9 +61,6 @@ pub struct Opts { /// may wish to turn this flag on in order to benchmark style recalculation against other /// browser engines. pub bubble_widths_separately: bool, - - /// Use native threads instead of green threads - pub native_threading: bool } fn print_usage(app: &str, opts: &[getopts::OptGroup]) { @@ -80,22 +77,21 @@ pub fn from_cmdline_args(args: &[String]) -> Option<Opts> { let app_name = args[0].to_str(); let args = args.tail(); - let opts = vec![ + let opts = vec!( getopts::optflag("c", "cpu", "CPU rendering"), getopts::optopt("o", "output", "Output file", "output.png"), getopts::optopt("r", "rendering", "Rendering backend", "direct2d|core-graphics|core-graphics-accelerated|cairo|skia."), getopts::optopt("s", "size", "Size of tiles", "512"), getopts::optopt("", "device-pixel-ratio", "Device pixels per px", ""), + getopts::optopt("t", "threads", "Number of render threads", "1"), getopts::optflagopt("p", "profile", "Profiler flag and output interval", "10"), getopts::optflag("x", "exit", "Exit after load flag"), - getopts::optopt("t", "threads", "Number of render threads", "[n-cores]"), - getopts::optopt("y", "layout-threads", "Number of layout threads", "1"), + getopts::optopt("y", "layout-threads", "Number of threads to use for layout", "1"), getopts::optflag("z", "headless", "Headless mode"), getopts::optflag("f", "hard-fail", "Exit on task failure instead of displaying about:failure"), getopts::optflag("b", "bubble-widths", "Bubble intrinsic widths separately like other engines"), - getopts::optflag("n", "native-threading", "Use native threading instead of green threading"), getopts::optflag("h", "help", "Print this message") - ]; + ); let opt_match = match getopts::getopts(args, opts.as_slice()) { Ok(m) => m, @@ -148,17 +144,7 @@ pub fn from_cmdline_args(args: &[String]) -> Option<Opts> { let n_render_threads: uint = match opt_match.opt_str("t") { Some(n_render_threads_str) => from_str(n_render_threads_str.as_slice()).unwrap(), - None => { - // FIXME (rust/14707): This still isn't exposed publicly via std::rt?? - // FIXME (rust/14704): Terrible name for this lint, which here is allowing - // Rust types, not C types - #[allow(ctypes)] - extern { - fn rust_get_num_cpus() -> uint; - } - - unsafe { rust_get_num_cpus() as uint } - } + None => 1, // FIXME: Number of cores. }; // if only flag is present, default to 5 second period @@ -173,8 +159,6 @@ pub fn from_cmdline_args(args: &[String]) -> Option<Opts> { None => cmp::max(rt::default_sched_threads() * 3 / 4, 1), }; - let native_threading = opt_match.opt_present("n"); - Some(Opts { urls: urls, render_backend: render_backend, @@ -189,6 +173,5 @@ pub fn from_cmdline_args(args: &[String]) -> Option<Opts> { headless: opt_match.opt_present("z"), hard_fail: opt_match.opt_present("f"), bubble_widths_separately: opt_match.opt_present("b"), - native_threading: native_threading }) } |