diff options
author | bors-servo <metajack+bors@gmail.com> | 2015-07-31 09:43:40 -0600 |
---|---|---|
committer | bors-servo <metajack+bors@gmail.com> | 2015-07-31 09:43:40 -0600 |
commit | c4480b5d0309acc7f154166b91992f73a85de57f (patch) | |
tree | 494001ef3527c23854439ddca953a7443025712c /components | |
parent | 33bc16fe353be237855d006b34e96fbe59f24846 (diff) | |
parent | 17ead8716b53715086c990dc16e20e1cf6462c16 (diff) | |
download | servo-c4480b5d0309acc7f154166b91992f73a85de57f.tar.gz servo-c4480b5d0309acc7f154166b91992f73a85de57f.zip |
Auto merge of #6795 - pcwalton:display-list-e10s-fixes, r=glennw
Send display lists over IPC in multiprocess mode.
This patch set introduces the `--multiprocess` (`-M`) switch. Right now, all it does it cause display lists to be serialized, but eventually it will cause actual processes to be spawned.
r? @metajack
<!-- Reviewable:start -->
[<img src="https://reviewable.io/review_button.png" height=40 alt="Review on Reviewable"/>](https://reviewable.io/reviews/servo/servo/6795)
<!-- Reviewable:end -->
Diffstat (limited to 'components')
-rw-r--r-- | components/compositing/compositor.rs | 10 | ||||
-rw-r--r-- | components/compositing/pipeline.rs | 49 | ||||
-rw-r--r-- | components/gfx/display_list/mod.rs | 64 | ||||
-rw-r--r-- | components/gfx/font_context.rs | 2 | ||||
-rw-r--r-- | components/gfx/lib.rs | 1 | ||||
-rw-r--r-- | components/gfx/paint_task.rs | 87 | ||||
-rw-r--r-- | components/gfx/platform/macos/font.rs | 2 | ||||
-rw-r--r-- | components/gfx/platform/macos/font_template.rs | 22 | ||||
-rw-r--r-- | components/layout/layout_task.rs | 24 | ||||
-rw-r--r-- | components/layout_traits/lib.rs | 5 | ||||
-rw-r--r-- | components/servo/Cargo.lock | 3 | ||||
-rw-r--r-- | components/util/Cargo.toml | 3 | ||||
-rw-r--r-- | components/util/ipc.rs | 94 | ||||
-rw-r--r-- | components/util/lib.rs | 2 | ||||
-rw-r--r-- | components/util/linked_list.rs | 73 | ||||
-rw-r--r-- | components/util/opts.rs | 6 |
16 files changed, 258 insertions, 189 deletions
diff --git a/components/compositing/compositor.rs b/components/compositing/compositor.rs index 0061a4baa40..b3830a11140 100644 --- a/components/compositing/compositor.rs +++ b/components/compositing/compositor.rs @@ -4,8 +4,7 @@ use surface_map::SurfaceMap; use compositor_layer::{CompositorData, CompositorLayer, WantsScrollEventsFlag}; -use compositor_task::{CompositorEventListener, CompositorProxy, CompositorReceiver}; -use compositor_task::Msg; +use compositor_task::{CompositorEventListener, CompositorProxy, CompositorReceiver, Msg}; use constellation::SendableFrameTree; use pipeline::CompositionPipeline; use scrolling::ScrollingTimerProxy; @@ -18,8 +17,7 @@ use euclid::rect::{Rect, TypedRect}; use euclid::scale_factor::ScaleFactor; use euclid::size::{Size2D, TypedSize2D}; use gfx_traits::color; -use gfx::paint_task::Msg as PaintMsg; -use gfx::paint_task::PaintRequest; +use gfx::paint_task::{ChromeToPaintMsg, PaintRequest}; use gleam::gl::types::{GLint, GLsizei}; use gleam::gl; use ipc_channel::ipc; @@ -1306,8 +1304,8 @@ impl<Window: WindowMethods> IOCompositor<Window> { self.convert_buffer_requests_to_pipeline_requests_map(layers_and_requests); for (pipeline_id, requests) in pipeline_requests.into_iter() { - let msg = PaintMsg::Paint(requests, self.frame_tree_id); - let _ = self.get_pipeline(pipeline_id).paint_chan.send(msg); + let msg = ChromeToPaintMsg::Paint(requests, self.frame_tree_id); + let _ = self.get_pipeline(pipeline_id).chrome_to_paint_chan.send(msg); } true diff --git a/components/compositing/pipeline.rs b/components/compositing/pipeline.rs index d1acc51b641..83e5c0c2bc1 100644 --- a/components/compositing/pipeline.rs +++ b/components/compositing/pipeline.rs @@ -11,8 +11,7 @@ use compositor_task; use devtools_traits::{DevtoolsControlChan, DevtoolsControlMsg, ScriptToDevtoolsControlMsg}; use euclid::rect::{TypedRect}; use euclid::scale_factor::ScaleFactor; -use gfx::paint_task::Msg as PaintMsg; -use gfx::paint_task::{PaintChan, PaintTask}; +use gfx::paint_task::{ChromeToPaintMsg, LayoutToPaintMsg, PaintTask}; use gfx::font_cache_task::FontCacheTask; use ipc_channel::ipc::{self, IpcReceiver, IpcSender}; use ipc_channel::router::ROUTER; @@ -30,7 +29,9 @@ use std::mem; use std::sync::mpsc::{Receiver, Sender, channel}; use std::thread; use url::Url; +use util; use util::geometry::{PagePx, ViewportPx}; +use util::ipc::OptionalIpcSender; use util::opts; /// A uniquely-identifiable pipeline of script task, layout task, and paint task. @@ -40,7 +41,7 @@ pub struct Pipeline { pub script_chan: ScriptControlChan, /// A channel to layout, for performing reflows and shutdown. pub layout_chan: LayoutControlChan, - pub paint_chan: PaintChan, + pub chrome_to_paint_chan: Sender<ChromeToPaintMsg>, pub layout_shutdown_port: Receiver<()>, pub paint_shutdown_port: Receiver<()>, /// URL corresponding to the most recently-loaded page. @@ -60,7 +61,7 @@ pub struct CompositionPipeline { pub id: PipelineId, pub script_chan: ScriptControlChan, pub layout_chan: LayoutControlChan, - pub paint_chan: PaintChan, + pub chrome_to_paint_chan: Sender<ChromeToPaintMsg>, } impl Pipeline { @@ -84,7 +85,8 @@ impl Pipeline { device_pixel_ratio: ScaleFactor<ViewportPx, DevicePixel, f32>) -> (Pipeline, PipelineContent) where LTF: LayoutTaskFactory, STF:ScriptTaskFactory { - let (paint_port, paint_chan) = PaintChan::new(); + let (layout_to_paint_chan, layout_to_paint_port) = util::ipc::optional_ipc_channel(); + let (chrome_to_paint_chan, chrome_to_paint_port) = channel(); let (paint_shutdown_chan, paint_shutdown_port) = channel(); let (layout_shutdown_chan, layout_shutdown_port) = channel(); let (pipeline_chan, pipeline_port) = ipc::channel().unwrap(); @@ -123,7 +125,7 @@ impl Pipeline { new_pipeline_id: id, subpage_id: subpage_id, load_data: load_data.clone(), - paint_chan: box paint_chan.clone() as Box<Any + Send>, + paint_chan: box layout_to_paint_chan.clone() as Box<Any + Send>, failure: failure, pipeline_port: mem::replace(&mut pipeline_port, None).unwrap(), layout_shutdown_chan: layout_shutdown_chan.clone(), @@ -144,7 +146,7 @@ impl Pipeline { parent_info, script_chan.clone(), LayoutControlChan(pipeline_chan), - paint_chan.clone(), + chrome_to_paint_chan.clone(), layout_shutdown_port, paint_shutdown_port, load_data.url.clone(), @@ -167,8 +169,10 @@ impl Pipeline { load_data: load_data, failure: failure, script_port: script_port, - paint_chan: paint_chan, - paint_port: Some(paint_port), + layout_to_paint_chan: layout_to_paint_chan, + chrome_to_paint_chan: chrome_to_paint_chan, + layout_to_paint_port: Some(layout_to_paint_port), + chrome_to_paint_port: Some(chrome_to_paint_port), pipeline_port: pipeline_port, paint_shutdown_chan: paint_shutdown_chan, layout_shutdown_chan: layout_shutdown_chan, @@ -181,7 +185,7 @@ impl Pipeline { parent_info: Option<(PipelineId, SubpageId)>, script_chan: ScriptControlChan, layout_chan: LayoutControlChan, - paint_chan: PaintChan, + chrome_to_paint_chan: Sender<ChromeToPaintMsg>, layout_shutdown_port: Receiver<()>, paint_shutdown_port: Receiver<()>, url: Url, @@ -192,7 +196,7 @@ impl Pipeline { parent_info: parent_info, script_chan: script_chan, layout_chan: layout_chan, - paint_chan: paint_chan, + chrome_to_paint_chan: chrome_to_paint_chan, layout_shutdown_port: layout_shutdown_port, paint_shutdown_port: paint_shutdown_port, url: url, @@ -204,12 +208,12 @@ impl Pipeline { } pub fn grant_paint_permission(&self) { - let _ = self.paint_chan.send(PaintMsg::PaintPermissionGranted); + let _ = self.chrome_to_paint_chan.send(ChromeToPaintMsg::PaintPermissionGranted); } pub fn revoke_paint_permission(&self) { debug!("pipeline revoking paint channel paint permission"); - let _ = self.paint_chan.send(PaintMsg::PaintPermissionRevoked); + let _ = self.chrome_to_paint_chan.send(ChromeToPaintMsg::PaintPermissionRevoked); } pub fn exit(&self, exit_type: PipelineExitType) { @@ -242,7 +246,9 @@ impl Pipeline { let _ = script_channel.send( ConstellationControlMsg::ExitPipeline(self.id, PipelineExitType::PipelineOnly)).unwrap(); - let _ = self.paint_chan.send(PaintMsg::Exit(None, PipelineExitType::PipelineOnly)); + let _ = self.chrome_to_paint_chan.send(ChromeToPaintMsg::Exit( + None, + PipelineExitType::PipelineOnly)); let LayoutControlChan(ref layout_channel) = self.layout_chan; let _ = layout_channel.send( LayoutControlMsg::ExitNow(PipelineExitType::PipelineOnly)).unwrap(); @@ -253,7 +259,7 @@ impl Pipeline { id: self.id.clone(), script_chan: self.script_chan.clone(), layout_chan: self.layout_chan.clone(), - paint_chan: self.paint_chan.clone(), + chrome_to_paint_chan: self.chrome_to_paint_chan.clone(), } } @@ -296,8 +302,10 @@ pub struct PipelineContent { load_data: LoadData, failure: Failure, script_port: Option<Receiver<ConstellationControlMsg>>, - paint_chan: PaintChan, - paint_port: Option<Receiver<PaintMsg>>, + layout_to_paint_chan: OptionalIpcSender<LayoutToPaintMsg>, + chrome_to_paint_chan: Sender<ChromeToPaintMsg>, + layout_to_paint_port: Option<Receiver<LayoutToPaintMsg>>, + chrome_to_paint_port: Option<Receiver<ChromeToPaintMsg>>, paint_shutdown_chan: Sender<()>, pipeline_port: Option<IpcReceiver<LayoutControlMsg>>, layout_shutdown_chan: Sender<()>, @@ -344,7 +352,7 @@ impl PipelineContent { self.constellation_chan, self.failure, self.script_chan.clone(), - self.paint_chan.clone(), + self.layout_to_paint_chan.clone(), self.image_cache_task, self.font_cache_task, self.time_profiler_chan, @@ -355,8 +363,9 @@ impl PipelineContent { pub fn start_paint_task(&mut self) { PaintTask::create(self.id, self.load_data.url.clone(), - self.paint_chan.clone(), - mem::replace(&mut self.paint_port, None).unwrap(), + self.chrome_to_paint_chan.clone(), + mem::replace(&mut self.layout_to_paint_port, None).unwrap(), + mem::replace(&mut self.chrome_to_paint_port, None).unwrap(), self.compositor_proxy.clone_compositor_proxy(), self.constellation_chan.clone(), self.font_cache_task.clone(), diff --git a/components/gfx/display_list/mod.rs b/components/gfx/display_list/mod.rs index 9610c78b80f..e87a5888ea9 100644 --- a/components/gfx/display_list/mod.rs +++ b/components/gfx/display_list/mod.rs @@ -42,7 +42,7 @@ use style::computed_values::{pointer_events}; use style::properties::ComputedValues; use util::cursor::Cursor; use util::geometry::{self, Au, MAX_RECT, ZERO_RECT}; -use util::linked_list::{SerializableLinkedList, prepend_from}; +use util::linked_list::prepend_from; use util::mem::HeapSizeOf; use util::opts; use util::range::Range; @@ -84,19 +84,19 @@ impl OpaqueNode { #[derive(HeapSizeOf, Deserialize, Serialize)] pub struct DisplayList { /// The border and backgrounds for the root of this stacking context: steps 1 and 2. - pub background_and_borders: SerializableLinkedList<DisplayItem>, + pub background_and_borders: LinkedList<DisplayItem>, /// Borders and backgrounds for block-level descendants: step 4. - pub block_backgrounds_and_borders: SerializableLinkedList<DisplayItem>, + pub block_backgrounds_and_borders: LinkedList<DisplayItem>, /// Floats: step 5. These are treated as pseudo-stacking contexts. - pub floats: SerializableLinkedList<DisplayItem>, + pub floats: LinkedList<DisplayItem>, /// All non-positioned content. - pub content: SerializableLinkedList<DisplayItem>, + pub content: LinkedList<DisplayItem>, /// All positioned content that does not get a stacking context. - pub positioned_content: SerializableLinkedList<DisplayItem>, + pub positioned_content: LinkedList<DisplayItem>, /// Outlines: step 10. - pub outlines: SerializableLinkedList<DisplayItem>, + pub outlines: LinkedList<DisplayItem>, /// Child stacking contexts. - pub children: SerializableLinkedList<Arc<StackingContext>>, + pub children: LinkedList<Arc<StackingContext>>, } impl DisplayList { @@ -104,13 +104,13 @@ impl DisplayList { #[inline] pub fn new() -> DisplayList { DisplayList { - background_and_borders: SerializableLinkedList::new(LinkedList::new()), - block_backgrounds_and_borders: SerializableLinkedList::new(LinkedList::new()), - floats: SerializableLinkedList::new(LinkedList::new()), - content: SerializableLinkedList::new(LinkedList::new()), - positioned_content: SerializableLinkedList::new(LinkedList::new()), - outlines: SerializableLinkedList::new(LinkedList::new()), - children: SerializableLinkedList::new(LinkedList::new()), + background_and_borders: LinkedList::new(), + block_backgrounds_and_borders: LinkedList::new(), + floats: LinkedList::new(), + content: LinkedList::new(), + positioned_content: LinkedList::new(), + outlines: LinkedList::new(), + children: LinkedList::new(), } } @@ -118,34 +118,34 @@ impl DisplayList { /// `other` in the process. #[inline] pub fn append_from(&mut self, other: &mut DisplayList) { - self.background_and_borders.append(&mut *other.background_and_borders); - self.block_backgrounds_and_borders.append(&mut *other.block_backgrounds_and_borders); - self.floats.append(&mut *other.floats); - self.content.append(&mut *other.content); - self.positioned_content.append(&mut *other.positioned_content); - self.outlines.append(&mut *other.outlines); - self.children.append(&mut *other.children); + self.background_and_borders.append(&mut other.background_and_borders); + self.block_backgrounds_and_borders.append(&mut other.block_backgrounds_and_borders); + self.floats.append(&mut other.floats); + self.content.append(&mut other.content); + self.positioned_content.append(&mut other.positioned_content); + self.outlines.append(&mut other.outlines); + self.children.append(&mut other.children); } /// Merges all display items from all non-float stacking levels to the `float` stacking level. #[inline] pub fn form_float_pseudo_stacking_context(&mut self) { - prepend_from(&mut *self.floats, &mut *self.outlines); - prepend_from(&mut *self.floats, &mut *self.positioned_content); - prepend_from(&mut *self.floats, &mut *self.content); - prepend_from(&mut *self.floats, &mut *self.block_backgrounds_and_borders); - prepend_from(&mut *self.floats, &mut *self.background_and_borders); + prepend_from(&mut self.floats, &mut self.outlines); + prepend_from(&mut self.floats, &mut self.positioned_content); + prepend_from(&mut self.floats, &mut self.content); + prepend_from(&mut self.floats, &mut self.block_backgrounds_and_borders); + prepend_from(&mut self.floats, &mut self.background_and_borders); } /// Merges all display items from all non-positioned-content stacking levels to the /// positioned-content stacking level. #[inline] pub fn form_pseudo_stacking_context_for_positioned_content(&mut self) { - prepend_from(&mut *self.positioned_content, &mut *self.outlines); - prepend_from(&mut *self.positioned_content, &mut *self.content); - prepend_from(&mut *self.positioned_content, &mut *self.floats); - prepend_from(&mut *self.positioned_content, &mut *self.block_backgrounds_and_borders); - prepend_from(&mut *self.positioned_content, &mut *self.background_and_borders); + prepend_from(&mut self.positioned_content, &mut self.outlines); + prepend_from(&mut self.positioned_content, &mut self.content); + prepend_from(&mut self.positioned_content, &mut self.floats); + prepend_from(&mut self.positioned_content, &mut self.block_backgrounds_and_borders); + prepend_from(&mut self.positioned_content, &mut self.background_and_borders); } /// Returns a list of all items in this display list concatenated together. This is extremely diff --git a/components/gfx/font_context.rs b/components/gfx/font_context.rs index 5621807827f..718e64c7e91 100644 --- a/components/gfx/font_context.rs +++ b/components/gfx/font_context.rs @@ -42,7 +42,7 @@ fn create_scaled_font(template: &Arc<FontTemplateData>, pt_size: Au) -> ScaledFo #[cfg(target_os="macos")] fn create_scaled_font(template: &Arc<FontTemplateData>, pt_size: Au) -> ScaledFont { - let cgfont = template.ctfont.as_ref().unwrap().copy_to_CGFont(); + let cgfont = template.ctfont().as_ref().unwrap().copy_to_CGFont(); ScaledFont::new(BackendType::Skia, &cgfont, pt_size.to_f32_px()) } diff --git a/components/gfx/lib.rs b/components/gfx/lib.rs index abeaea80b0e..d13251123ca 100644 --- a/components/gfx/lib.rs +++ b/components/gfx/lib.rs @@ -9,6 +9,7 @@ #![feature(custom_derive)] #![feature(hashmap_hasher)] #![cfg_attr(any(target_os="linux", target_os = "android"), feature(heap_api))] +#![feature(mpsc_select)] #![feature(plugin)] #![feature(str_char)] #![feature(vec_push_all)] diff --git a/components/gfx/paint_task.rs b/components/gfx/paint_task.rs index ba9f73a154d..39f0ace7155 100644 --- a/components/gfx/paint_task.rs +++ b/components/gfx/paint_task.rs @@ -32,7 +32,7 @@ use skia::gl_context::GLContext; use std::borrow::ToOwned; use std::mem as std_mem; use std::sync::Arc; -use std::sync::mpsc::{Receiver, Sender, channel}; +use std::sync::mpsc::{Receiver, Select, Sender, channel}; use std::collections::HashMap; use url::Url; use util::geometry::{Au, ZERO_POINT}; @@ -72,38 +72,30 @@ pub struct PaintRequest { } pub enum Msg { + FromLayout(LayoutToPaintMsg), + FromChrome(ChromeToPaintMsg), +} + +#[derive(Deserialize, Serialize)] +pub enum LayoutToPaintMsg { PaintInit(Epoch, Arc<StackingContext>), CanvasLayer(LayerId, IpcSender<CanvasMsg>), + Exit(Option<IpcSender<()>>, PipelineExitType), +} + +pub enum ChromeToPaintMsg { Paint(Vec<PaintRequest>, FrameTreeId), PaintPermissionGranted, PaintPermissionRevoked, CollectReports(ReportsChan), - Exit(Option<Sender<()>>, PipelineExitType), -} - -#[derive(Clone)] -pub struct PaintChan(Sender<Msg>); - -impl PaintChan { - pub fn new() -> (Receiver<Msg>, PaintChan) { - let (chan, port) = channel(); - (port, PaintChan(chan)) - } - - pub fn send(&self, msg: Msg) { - assert!(self.send_opt(msg).is_ok(), "PaintChan.send: paint port closed") - } - - pub fn send_opt(&self, msg: Msg) -> Result<(), Msg> { - let &PaintChan(ref chan) = self; - chan.send(msg).map_err(|e| e.0) - } + Exit(Option<IpcSender<()>>, PipelineExitType), } pub struct PaintTask<C> { id: PipelineId, _url: Url, - port: Receiver<Msg>, + layout_to_paint_port: Receiver<LayoutToPaintMsg>, + chrome_to_paint_port: Receiver<ChromeToPaintMsg>, compositor: C, constellation_chan: ConstellationChan, @@ -137,8 +129,9 @@ macro_rules! native_display( impl<C> PaintTask<C> where C: PaintListener + Send + 'static { pub fn create(id: PipelineId, url: Url, - chan: PaintChan, - port: Receiver<Msg>, + chrome_to_paint_chan: Sender<ChromeToPaintMsg>, + layout_to_paint_port: Receiver<LayoutToPaintMsg>, + chrome_to_paint_port: Receiver<ChromeToPaintMsg>, compositor: C, constellation_chan: ConstellationChan, font_cache_task: FontCacheTask, @@ -162,7 +155,8 @@ impl<C> PaintTask<C> where C: PaintListener + Send + 'static { let mut paint_task = PaintTask { id: id, _url: url, - port: port, + layout_to_paint_port: layout_to_paint_port, + chrome_to_paint_port: chrome_to_paint_port, compositor: compositor, constellation_chan: constellation_chan, time_profiler_chan: time_profiler_chan, @@ -177,12 +171,12 @@ impl<C> PaintTask<C> where C: PaintListener + Send + 'static { let reporter_name = format!("paint-reporter-{}", id.0); let (reporter_sender, reporter_receiver) = ipc::channel::<ReporterRequest>().unwrap(); - let paint_chan_for_reporter = chan.clone(); + let paint_chan_for_reporter = chrome_to_paint_chan.clone(); ROUTER.add_route(reporter_receiver.to_opaque(), box move |message| { // Just injects an appropriate event into the paint task's queue. let request: ReporterRequest = message.to().unwrap(); - paint_chan_for_reporter.0.send(Msg::CollectReports(request.reports_channel)) - .unwrap(); + paint_chan_for_reporter.send(ChromeToPaintMsg::CollectReports( + request.reports_channel)).unwrap(); }); mem_profiler_chan.send(mem::ProfilerMsg::RegisterReporter( reporter_name.clone(), @@ -208,8 +202,26 @@ impl<C> PaintTask<C> where C: PaintListener + Send + 'static { debug!("PaintTask: beginning painting loop"); loop { - match self.port.recv().unwrap() { - Msg::PaintInit(epoch, stacking_context) => { + let message = { + let select = Select::new(); + let mut layout_to_paint_handle = select.handle(&self.layout_to_paint_port); + let mut chrome_to_paint_handle = select.handle(&self.chrome_to_paint_port); + unsafe { + layout_to_paint_handle.add(); + chrome_to_paint_handle.add(); + } + let result = select.wait(); + if result == layout_to_paint_handle.id() { + Msg::FromLayout(self.layout_to_paint_port.recv().unwrap()) + } else if result == chrome_to_paint_handle.id() { + Msg::FromChrome(self.chrome_to_paint_port.recv().unwrap()) + } else { + panic!("unexpected select result") + } + }; + + match message { + Msg::FromLayout(LayoutToPaintMsg::PaintInit(epoch, stacking_context)) => { self.current_epoch = Some(epoch); self.root_stacking_context = Some(stacking_context.clone()); @@ -223,11 +235,11 @@ impl<C> PaintTask<C> where C: PaintListener + Send + 'static { self.initialize_layers(); } // Inserts a new canvas renderer to the layer map - Msg::CanvasLayer(layer_id, canvas_renderer) => { + Msg::FromLayout(LayoutToPaintMsg::CanvasLayer(layer_id, canvas_renderer)) => { debug!("Renderer received for canvas with layer {:?}", layer_id); self.canvas_map.insert(layer_id, canvas_renderer); } - Msg::Paint(requests, frame_tree_id) => { + Msg::FromChrome(ChromeToPaintMsg::Paint(requests, frame_tree_id)) => { if !self.paint_permission { debug!("PaintTask: paint ready msg"); let ConstellationChan(ref mut c) = self.constellation_chan; @@ -254,27 +266,28 @@ impl<C> PaintTask<C> where C: PaintListener + Send + 'static { replies, frame_tree_id); } - Msg::PaintPermissionGranted => { + Msg::FromChrome(ChromeToPaintMsg::PaintPermissionGranted) => { self.paint_permission = true; if self.root_stacking_context.is_some() { self.initialize_layers(); } } - Msg::PaintPermissionRevoked => { + Msg::FromChrome(ChromeToPaintMsg::PaintPermissionRevoked) => { self.paint_permission = false; } - Msg::CollectReports(ref channel) => { + Msg::FromChrome(ChromeToPaintMsg::CollectReports(ref channel)) => { // FIXME(njn): should eventually measure the paint task. channel.send(Vec::new()) } - Msg::Exit(response_channel, _) => { + Msg::FromLayout(LayoutToPaintMsg::Exit(ref response_channel, _)) | + Msg::FromChrome(ChromeToPaintMsg::Exit(ref response_channel, _)) => { // Ask the compositor to remove any layers it is holding for this paint task. // FIXME(mrobinson): This can probably move back to the constellation now. self.compositor.notify_paint_task_exiting(self.id); debug!("PaintTask: Exiting."); - response_channel.map(|channel| channel.send(())); + response_channel.as_ref().map(|channel| channel.send(())); break; } } diff --git a/components/gfx/platform/macos/font.rs b/components/gfx/platform/macos/font.rs index a6e431407e1..b8474aa6da9 100644 --- a/components/gfx/platform/macos/font.rs +++ b/components/gfx/platform/macos/font.rs @@ -64,7 +64,7 @@ impl FontHandleMethods for FontHandle { Some(s) => s.to_f64_px(), None => 0.0 }; - match *template.ctfont { + match template.ctfont() { Some(ref ctfont) => { Ok(FontHandle { font_data: template.clone(), diff --git a/components/gfx/platform/macos/font_template.rs b/components/gfx/platform/macos/font_template.rs index e5c0c9c194b..e84691971ac 100644 --- a/components/gfx/platform/macos/font_template.rs +++ b/components/gfx/platform/macos/font_template.rs @@ -11,6 +11,7 @@ use serde::de::{Error, Visitor}; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use std::borrow::ToOwned; use std::ops::Deref; +use std::sync::Mutex; use string_cache::Atom; /// Platform specific font representation for mac. @@ -26,7 +27,7 @@ pub struct FontTemplateData { /// When sending a `FontTemplateData` instance across processes, this will be set to `None` on /// the other side, because `CTFont` instances cannot be sent across processes. This is /// harmless, however, because it can always be recreated. - pub ctfont: CachedCTFont, + ctfont: CachedCTFont, pub identifier: Atom, pub font_data: Option<Vec<u8>> @@ -52,18 +53,27 @@ impl FontTemplateData { }; FontTemplateData { - ctfont: CachedCTFont(ctfont), + ctfont: CachedCTFont(Mutex::new(ctfont)), identifier: identifier.to_owned(), font_data: font_data } } + + /// Retrieves the Core Text font instance, instantiating it if necessary. + pub fn ctfont(&self) -> Option<CTFont> { + let mut ctfont = self.ctfont.lock().unwrap(); + if ctfont.is_none() { + *ctfont = core_text::font::new_from_name(self.identifier.as_slice(), 0.0).ok() + } + ctfont.as_ref().map(|ctfont| (*ctfont).clone()) + } } -pub struct CachedCTFont(Option<CTFont>); +pub struct CachedCTFont(Mutex<Option<CTFont>>); impl Deref for CachedCTFont { - type Target = Option<CTFont>; - fn deref(&self) -> &Option<CTFont> { + type Target = Mutex<Option<CTFont>>; + fn deref(&self) -> &Mutex<Option<CTFont>> { &self.0 } } @@ -84,7 +94,7 @@ impl Deserialize for CachedCTFont { #[inline] fn visit_none<E>(&mut self) -> Result<CachedCTFont,E> where E: Error { - Ok(CachedCTFont(None)) + Ok(CachedCTFont(Mutex::new(None))) } } diff --git a/components/layout/layout_task.rs b/components/layout/layout_task.rs index 803b8fb1a0a..001f8f42d2a 100644 --- a/components/layout/layout_task.rs +++ b/components/layout/layout_task.rs @@ -37,8 +37,7 @@ use gfx_traits::color; use gfx::display_list::{ClippingRegion, DisplayItemMetadata, DisplayList, OpaqueNode}; use gfx::display_list::StackingContext; use gfx::font_cache_task::FontCacheTask; -use gfx::paint_task::Msg as PaintMsg; -use gfx::paint_task::{PaintChan, PaintLayer}; +use gfx::paint_task::{LayoutToPaintMsg, PaintLayer}; use ipc_channel::ipc::{self, IpcReceiver, IpcSender}; use ipc_channel::router::ROUTER; use layout_traits::LayoutTaskFactory; @@ -79,6 +78,7 @@ use style::stylesheets::{Origin, Stylesheet, CSSRuleIteratorExt}; use url::Url; use util::cursor::Cursor; use util::geometry::{Au, MAX_RECT, ZERO_POINT}; +use util::ipc::OptionalIpcSender; use util::logical_geometry::{LogicalPoint, WritingMode}; use util::mem::HeapSizeOf; use util::opts; @@ -188,7 +188,7 @@ pub struct LayoutTask { pub script_chan: ScriptControlChan, /// The channel on which messages can be sent to the painting task. - pub paint_chan: PaintChan, + pub paint_chan: OptionalIpcSender<LayoutToPaintMsg>, /// The channel on which messages can be sent to the time profiler. pub time_profiler_chan: time::ProfilerChan, @@ -228,7 +228,7 @@ impl LayoutTaskFactory for LayoutTask { constellation_chan: ConstellationChan, failure_msg: Failure, script_chan: ScriptControlChan, - paint_chan: PaintChan, + paint_chan: OptionalIpcSender<LayoutToPaintMsg>, image_cache_task: ImageCacheTask, font_cache_task: FontCacheTask, time_profiler_chan: time::ProfilerChan, @@ -318,7 +318,7 @@ impl LayoutTask { pipeline_port: IpcReceiver<LayoutControlMsg>, constellation_chan: ConstellationChan, script_chan: ScriptControlChan, - paint_chan: PaintChan, + paint_chan: OptionalIpcSender<LayoutToPaintMsg>, image_cache_task: ImageCacheTask, font_cache_task: FontCacheTask, time_profiler_chan: time::ProfilerChan, @@ -647,7 +647,9 @@ impl LayoutTask { info.constellation_chan, info.failure, ScriptControlChan(info.script_chan.clone()), - *info.paint_chan.downcast::<PaintChan>().unwrap(), + *info.paint_chan + .downcast::<OptionalIpcSender<LayoutToPaintMsg>>() + .unwrap(), self.image_cache_task.clone(), self.font_cache_task.clone(), self.time_profiler_chan.clone(), @@ -689,7 +691,7 @@ impl LayoutTask { fn exit_now<'a>(&'a self, possibly_locked_rw_data: &mut Option<MutexGuard<'a, LayoutTaskData>>, exit_type: PipelineExitType) { - let (response_chan, response_port) = channel(); + let (response_chan, response_port) = ipc::channel().unwrap(); { let mut rw_data = self.lock_rw_data(possibly_locked_rw_data); @@ -699,7 +701,7 @@ impl LayoutTask { LayoutTask::return_rw_data(possibly_locked_rw_data, rw_data); } - self.paint_chan.send(PaintMsg::Exit(Some(response_chan), exit_type)); + self.paint_chan.send(LayoutToPaintMsg::Exit(Some(response_chan), exit_type)).unwrap(); response_port.recv().unwrap() } @@ -1071,7 +1073,9 @@ impl LayoutTask { debug!("Layout done!"); rw_data.epoch.next(); - self.paint_chan.send(PaintMsg::PaintInit(rw_data.epoch, stacking_context)); + self.paint_chan + .send(LayoutToPaintMsg::PaintInit(rw_data.epoch, stacking_context)) + .unwrap(); } }); } @@ -1175,7 +1179,7 @@ impl LayoutTask { // Send new canvas renderers to the paint task while let Ok((layer_id, renderer)) = self.canvas_layers_receiver.try_recv() { // Just send if there's an actual renderer - self.paint_chan.send(PaintMsg::CanvasLayer(layer_id, renderer)); + self.paint_chan.send(LayoutToPaintMsg::CanvasLayer(layer_id, renderer)).unwrap(); } // Perform post-style recalculation layout passes. diff --git a/components/layout_traits/lib.rs b/components/layout_traits/lib.rs index 361ba3c2654..d75817911a7 100644 --- a/components/layout_traits/lib.rs +++ b/components/layout_traits/lib.rs @@ -22,7 +22,7 @@ extern crate util; // that these modules won't have to depend on layout. use gfx::font_cache_task::FontCacheTask; -use gfx::paint_task::PaintChan; +use gfx::paint_task::LayoutToPaintMsg; use ipc_channel::ipc::{IpcReceiver, IpcSender}; use msg::constellation_msg::{ConstellationChan, Failure, PipelineId}; use profile_traits::mem; @@ -31,6 +31,7 @@ use net_traits::image_cache_task::ImageCacheTask; use script_traits::{LayoutControlMsg, ScriptControlChan, OpaqueScriptLayoutChannel}; use std::sync::mpsc::Sender; use url::Url; +use util::ipc::OptionalIpcSender; /// A channel wrapper for constellation messages #[derive(Clone, Deserialize, Serialize)] @@ -49,7 +50,7 @@ pub trait LayoutTaskFactory { constellation_chan: ConstellationChan, failure_msg: Failure, script_chan: ScriptControlChan, - paint_chan: PaintChan, + layout_to_paint_chan: OptionalIpcSender<LayoutToPaintMsg>, image_cache_task: ImageCacheTask, font_cache_task: FontCacheTask, time_profiler_chan: time::ProfilerChan, diff --git a/components/servo/Cargo.lock b/components/servo/Cargo.lock index 26bd154f535..c1c4a62cd58 100644 --- a/components/servo/Cargo.lock +++ b/components/servo/Cargo.lock @@ -225,7 +225,7 @@ dependencies = [ [[package]] name = "core-text" version = "0.1.0" -source = "git+https://github.com/servo/core-text-rs#c12e41b35141e094bf784017ca4a6f71d90c9877" +source = "git+https://github.com/servo/core-text-rs#d97cd4ae33509857f956e64c71f43cc71c98430f" dependencies = [ "core-foundation 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "core-graphics 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1497,6 +1497,7 @@ dependencies = [ "bitflags 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "cssparser 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "ipc-channel 0.1.0 (git+https://github.com/pcwalton/ipc-channel)", "lazy_static 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/components/util/Cargo.toml b/components/util/Cargo.toml index a61600c8d5a..6558792b21b 100644 --- a/components/util/Cargo.toml +++ b/components/util/Cargo.toml @@ -25,6 +25,9 @@ git = "https://github.com/servo/rust-azure" version = "0.3" features = [ "serde-serialization" ] +[dependencies.ipc-channel] +git = "https://github.com/pcwalton/ipc-channel" + [dependencies] log = "0.3" bitflags = "0.3" diff --git a/components/util/ipc.rs b/components/util/ipc.rs new file mode 100644 index 00000000000..7e47ff696f7 --- /dev/null +++ b/components/util/ipc.rs @@ -0,0 +1,94 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use opts; + +use ipc_channel::ipc::{self, IpcSender}; +use ipc_channel::router::ROUTER; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; +use std::any::Any; +use std::collections::HashMap; +use std::sync::Mutex; +use std::sync::atomic::{ATOMIC_USIZE_INIT, AtomicUsize, Ordering}; +use std::sync::mpsc::{self, Receiver, Sender}; + +lazy_static! { + static ref IN_PROCESS_SENDERS: Mutex<HashMap<usize,Box<Any + Send>>> = + Mutex::new(HashMap::new()); +} + +static NEXT_SENDER_ID: AtomicUsize = ATOMIC_USIZE_INIT; + +pub enum OptionalIpcSender<T> where T: Deserialize + Serialize + Send + Any { + OutOfProcess(IpcSender<T>), + InProcess(Sender<T>), +} + +impl<T> OptionalIpcSender<T> where T: Deserialize + Serialize + Send + Any { + pub fn send(&self, value: T) -> Result<(),()> { + match *self { + OptionalIpcSender::OutOfProcess(ref ipc_sender) => ipc_sender.send(value), + OptionalIpcSender::InProcess(ref sender) => sender.send(value).map_err(|_| ()), + } + } +} + +impl<T> Clone for OptionalIpcSender<T> where T: Deserialize + Serialize + Send + Any { + fn clone(&self) -> OptionalIpcSender<T> { + match *self { + OptionalIpcSender::OutOfProcess(ref ipc_sender) => { + OptionalIpcSender::OutOfProcess((*ipc_sender).clone()) + } + OptionalIpcSender::InProcess(ref sender) => { + OptionalIpcSender::InProcess((*sender).clone()) + } + } + } +} + +impl<T> Deserialize for OptionalIpcSender<T> where T: Deserialize + Serialize + Send + Any { + fn deserialize<D>(deserializer: &mut D) + -> Result<OptionalIpcSender<T>,D::Error> where D: Deserializer { + if opts::get().multiprocess { + return Ok(OptionalIpcSender::OutOfProcess(try!(Deserialize::deserialize( + deserializer)))) + } + let id: usize = try!(Deserialize::deserialize(deserializer)); + let sender = (*IN_PROCESS_SENDERS.lock() + .unwrap() + .remove(&id) + .unwrap() + .downcast_ref::<Sender<T>>() + .unwrap()).clone(); + Ok(OptionalIpcSender::InProcess(sender)) + } +} + +impl<T> Serialize for OptionalIpcSender<T> where T: Deserialize + Serialize + Send + Any { + fn serialize<S>(&self, serializer: &mut S) -> Result<(),S::Error> where S: Serializer { + match *self { + OptionalIpcSender::OutOfProcess(ref ipc_sender) => ipc_sender.serialize(serializer), + OptionalIpcSender::InProcess(ref sender) => { + let id = NEXT_SENDER_ID.fetch_add(1, Ordering::SeqCst); + IN_PROCESS_SENDERS.lock() + .unwrap() + .insert(id, Box::new((*sender).clone()) as Box<Any + Send>); + id.serialize(serializer) + } + } + } +} + +pub fn optional_ipc_channel<T>() -> (OptionalIpcSender<T>, Receiver<T>) + where T: Deserialize + Serialize + Send + Any { + if opts::get().multiprocess { + let (ipc_sender, ipc_receiver) = ipc::channel().unwrap(); + let receiver = ROUTER.route_ipc_receiver_to_new_mpsc_receiver(ipc_receiver); + (OptionalIpcSender::OutOfProcess(ipc_sender), receiver) + } else { + let (sender, receiver) = mpsc::channel(); + (OptionalIpcSender::InProcess(sender), receiver) + } +} + diff --git a/components/util/lib.rs b/components/util/lib.rs index b108c516acc..8db4b17f5ec 100644 --- a/components/util/lib.rs +++ b/components/util/lib.rs @@ -31,6 +31,7 @@ extern crate alloc; #[macro_use] extern crate cssparser; extern crate euclid; extern crate getopts; +extern crate ipc_channel; extern crate libc; extern crate num as num_lib; extern crate num_cpus; @@ -49,6 +50,7 @@ pub mod debug_utils; pub mod deque; pub mod linked_list; pub mod geometry; +pub mod ipc; pub mod logical_geometry; pub mod mem; pub mod opts; diff --git a/components/util/linked_list.rs b/components/util/linked_list.rs index bf20f434d54..5114f02c0e4 100644 --- a/components/util/linked_list.rs +++ b/components/util/linked_list.rs @@ -4,81 +4,8 @@ //! Utility functions for doubly-linked lists. -use mem::HeapSizeOf; - -use serde::de::{Error, SeqVisitor, Visitor}; -use serde::ser::impls::SeqIteratorVisitor; -use serde::{Deserialize, Deserializer, Serialize, Serializer}; use std::collections::LinkedList; -use std::marker::PhantomData; use std::mem; -use std::ops::{Deref, DerefMut}; - -pub struct SerializableLinkedList<T>(LinkedList<T>); - -impl<T> SerializableLinkedList<T> { - pub fn new(linked_list: LinkedList<T>) -> SerializableLinkedList<T> { - SerializableLinkedList(linked_list) - } -} - -impl<T> Deref for SerializableLinkedList<T> { - type Target = LinkedList<T>; - - fn deref(&self) -> &LinkedList<T> { - &self.0 - } -} - -impl<T> DerefMut for SerializableLinkedList<T> { - fn deref_mut(&mut self) -> &mut LinkedList<T> { - &mut self.0 - } -} - -impl<T: HeapSizeOf> HeapSizeOf for SerializableLinkedList<T> { - fn heap_size_of_children(&self) -> usize { - self.0.heap_size_of_children() - } -} - -impl<T> Serialize for SerializableLinkedList<T> where T: Serialize { - fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error> where S: Serializer { - serializer.visit_seq(SeqIteratorVisitor::new(self.0.iter(), Some(self.0.len()))) - } -} - -impl<T> Deserialize for SerializableLinkedList<T> where T: Deserialize { - fn deserialize<D>(deserializer: &mut D) -> Result<SerializableLinkedList<T>, D::Error> - where D: Deserializer { - struct SerializableLinkedListVisitor<T> { - marker: PhantomData<T>, - } - - impl<T> Visitor for SerializableLinkedListVisitor<T> where T: Deserialize { - type Value = SerializableLinkedList<T>; - - #[inline] - fn visit_seq<V>(&mut self, mut visitor: V) - -> Result<SerializableLinkedList<T>, V::Error> - where V: SeqVisitor { - let mut list = LinkedList::new(); - for _ in 0..visitor.size_hint().0 { - match try!(visitor.visit()) { - Some(element) => list.push_back(element), - None => return Err(Error::end_of_stream_error()), - } - } - try!(visitor.end()); - Ok(SerializableLinkedList(list)) - } - } - - deserializer.visit_seq(SerializableLinkedListVisitor { - marker: PhantomData, - }) - } -} /// Splits the head off a list in O(1) time, and returns the head. pub fn split_off_head<T>(list: &mut LinkedList<T>) -> LinkedList<T> { diff --git a/components/util/opts.rs b/components/util/opts.rs index c8f65c97e54..efc580bd5e6 100644 --- a/components/util/opts.rs +++ b/components/util/opts.rs @@ -132,6 +132,9 @@ pub struct Opts { /// An optional string allowing the user agent to be set for testing. pub user_agent: Option<String>, + /// Whether to run in multiprocess mode. + pub multiprocess: bool, + /// Dumps the flow tree after a layout. pub dump_flow_tree: bool, @@ -251,6 +254,7 @@ pub fn default_opts() -> Opts { webdriver_port: None, initial_window_size: Size2D::typed(800, 600), user_agent: None, + multiprocess: false, dump_flow_tree: false, dump_display_list: false, dump_display_list_json: false, @@ -291,6 +295,7 @@ pub fn from_cmdline_args(args: &[String]) { getopts::optflagopt("", "webdriver", "Start remote WebDriver server on port", "7000"), getopts::optopt("", "resolution", "Set window resolution.", "800x600"), getopts::optopt("u", "user-agent", "Set custom user agent string", "NCSA Mosaic/1.0 (X11;SunOS 4.1.4 sun4m)"), + getopts::optflag("M", "multiprocess", "Run in multiprocess mode"), getopts::optopt("Z", "debug", "A comma-separated string of debug options. Pass help to show available options.", ""), getopts::optflag("h", "help", "Print this message"), @@ -421,6 +426,7 @@ pub fn from_cmdline_args(args: &[String]) { webdriver_port: webdriver_port, initial_window_size: initial_window_size, user_agent: opt_match.opt_str("u"), + multiprocess: opt_match.opt_present("M"), show_debug_borders: debug_options.contains(&"show-compositor-borders"), show_debug_fragment_borders: debug_options.contains(&"show-fragment-borders"), show_debug_parallel_paint: debug_options.contains(&"show-parallel-paint"), |