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 IOCompositor { 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..c5c262d0abc 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; @@ -40,7 +39,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, pub layout_shutdown_port: Receiver<()>, pub paint_shutdown_port: Receiver<()>, /// URL corresponding to the most recently-loaded page. @@ -60,7 +59,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, } impl Pipeline { @@ -84,7 +83,8 @@ impl Pipeline { device_pixel_ratio: ScaleFactor) -> (Pipeline, PipelineContent) where LTF: LayoutTaskFactory, STF:ScriptTaskFactory { - let (paint_port, paint_chan) = PaintChan::new(); + let (layout_to_paint_chan, layout_to_paint_port) = 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 +123,7 @@ impl Pipeline { new_pipeline_id: id, subpage_id: subpage_id, load_data: load_data.clone(), - paint_chan: box paint_chan.clone() as Box, + paint_chan: box layout_to_paint_chan.clone() as Box, failure: failure, pipeline_port: mem::replace(&mut pipeline_port, None).unwrap(), layout_shutdown_chan: layout_shutdown_chan.clone(), @@ -144,7 +144,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 +167,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 +183,7 @@ impl Pipeline { parent_info: Option<(PipelineId, SubpageId)>, script_chan: ScriptControlChan, layout_chan: LayoutControlChan, - paint_chan: PaintChan, + chrome_to_paint_chan: Sender, layout_shutdown_port: Receiver<()>, paint_shutdown_port: Receiver<()>, url: Url, @@ -192,7 +194,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 +206,12 @@ impl Pipeline { } pub fn grant_paint_permission(&self) { - let _ = self.paint_chan.send(PaintMsg::PaintPermissionGranted); + drop(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); + drop(self.chrome_to_paint_chan.send(ChromeToPaintMsg::PaintPermissionRevoked)); } pub fn exit(&self, exit_type: PipelineExitType) { @@ -242,7 +244,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 +257,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 +300,10 @@ pub struct PipelineContent { load_data: LoadData, failure: Failure, script_port: Option>, - paint_chan: PaintChan, - paint_port: Option>, + layout_to_paint_chan: Sender, + chrome_to_paint_chan: Sender, + layout_to_paint_port: Option>, + chrome_to_paint_port: Option>, paint_shutdown_chan: Sender<()>, pipeline_port: Option>, layout_shutdown_chan: Sender<()>, @@ -344,7 +350,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 +361,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/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), CanvasLayer(LayerId, IpcSender), + Exit(Option>, PipelineExitType), +} + +pub enum ChromeToPaintMsg { Paint(Vec, FrameTreeId), PaintPermissionGranted, PaintPermissionRevoked, CollectReports(ReportsChan), - Exit(Option>, PipelineExitType), -} - -#[derive(Clone)] -pub struct PaintChan(Sender); - -impl PaintChan { - pub fn new() -> (Receiver, 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>, PipelineExitType), } pub struct PaintTask { id: PipelineId, _url: Url, - port: Receiver, + layout_to_paint_port: Receiver, + chrome_to_paint_port: Receiver, compositor: C, constellation_chan: ConstellationChan, @@ -137,8 +129,9 @@ macro_rules! native_display( impl PaintTask where C: PaintListener + Send + 'static { pub fn create(id: PipelineId, url: Url, - chan: PaintChan, - port: Receiver, + chrome_to_paint_chan: Sender, + layout_to_paint_port: Receiver, + chrome_to_paint_port: Receiver, compositor: C, constellation_chan: ConstellationChan, font_cache_task: FontCacheTask, @@ -162,7 +155,8 @@ impl PaintTask 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 PaintTask where C: PaintListener + Send + 'static { let reporter_name = format!("paint-reporter-{}", id.0); let (reporter_sender, reporter_receiver) = ipc::channel::().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 PaintTask 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 PaintTask 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 PaintTask 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/layout/layout_task.rs b/components/layout/layout_task.rs index 803b8fb1a0a..61ebd29deb9 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; @@ -188,7 +187,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: Sender, /// The channel on which messages can be sent to the time profiler. pub time_profiler_chan: time::ProfilerChan, @@ -228,7 +227,7 @@ impl LayoutTaskFactory for LayoutTask { constellation_chan: ConstellationChan, failure_msg: Failure, script_chan: ScriptControlChan, - paint_chan: PaintChan, + paint_chan: Sender, image_cache_task: ImageCacheTask, font_cache_task: FontCacheTask, time_profiler_chan: time::ProfilerChan, @@ -318,7 +317,7 @@ impl LayoutTask { pipeline_port: IpcReceiver, constellation_chan: ConstellationChan, script_chan: ScriptControlChan, - paint_chan: PaintChan, + paint_chan: Sender, image_cache_task: ImageCacheTask, font_cache_task: FontCacheTask, time_profiler_chan: time::ProfilerChan, @@ -647,7 +646,9 @@ impl LayoutTask { info.constellation_chan, info.failure, ScriptControlChan(info.script_chan.clone()), - *info.paint_chan.downcast::().unwrap(), + *info.paint_chan + .downcast::>() + .unwrap(), self.image_cache_task.clone(), self.font_cache_task.clone(), self.time_profiler_chan.clone(), @@ -689,7 +690,7 @@ impl LayoutTask { fn exit_now<'a>(&'a self, possibly_locked_rw_data: &mut Option>, 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 +700,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 +1072,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 +1178,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..436bccde8a4 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; @@ -49,7 +49,7 @@ pub trait LayoutTaskFactory { constellation_chan: ConstellationChan, failure_msg: Failure, script_chan: ScriptControlChan, - paint_chan: PaintChan, + layout_to_paint_chan: Sender, image_cache_task: ImageCacheTask, font_cache_task: FontCacheTask, time_profiler_chan: time::ProfilerChan,