separate waking the event loop, from communicating with a compositor

This commit is contained in:
Gregory Terzian 2017-05-28 11:43:49 +08:00
parent eac4f407e2
commit 3a693c7a23
9 changed files with 103 additions and 108 deletions

View file

@ -103,7 +103,7 @@ pub struct IOCompositor<Window: WindowMethods> {
window: Rc<Window>, window: Rc<Window>,
/// The port on which we receive messages. /// The port on which we receive messages.
port: Box<CompositorReceiver>, port: CompositorReceiver,
/// The root pipeline. /// The root pipeline.
root_pipeline: Option<CompositionPipeline>, root_pipeline: Option<CompositionPipeline>,
@ -133,7 +133,7 @@ pub struct IOCompositor<Window: WindowMethods> {
/// The device pixel ratio for this window. /// The device pixel ratio for this window.
scale_factor: ScaleFactor<f32, DeviceIndependentPixel, DevicePixel>, scale_factor: ScaleFactor<f32, DeviceIndependentPixel, DevicePixel>,
channel_to_self: Box<CompositorProxy + Send>, channel_to_self: CompositorProxy,
/// A handle to the delayed composition timer. /// A handle to the delayed composition timer.
delayed_composition_timer: DelayedCompositionTimerProxy, delayed_composition_timer: DelayedCompositionTimerProxy,
@ -317,11 +317,11 @@ fn initialize_png(gl: &gl::Gl, width: usize, height: usize) -> RenderTargetInfo
} }
struct RenderNotifier { struct RenderNotifier {
compositor_proxy: Box<CompositorProxy>, compositor_proxy: CompositorProxy,
} }
impl RenderNotifier { impl RenderNotifier {
fn new(compositor_proxy: Box<CompositorProxy>, fn new(compositor_proxy: CompositorProxy,
_: Sender<ConstellationMsg>) -> RenderNotifier { _: Sender<ConstellationMsg>) -> RenderNotifier {
RenderNotifier { RenderNotifier {
compositor_proxy: compositor_proxy, compositor_proxy: compositor_proxy,
@ -341,7 +341,7 @@ impl webrender_traits::RenderNotifier for RenderNotifier {
// Used to dispatch functions from webrender to the main thread's event loop. // Used to dispatch functions from webrender to the main thread's event loop.
struct CompositorThreadDispatcher { struct CompositorThreadDispatcher {
compositor_proxy: Box<CompositorProxy> compositor_proxy: CompositorProxy
} }
impl webrender_traits::RenderDispatcher for CompositorThreadDispatcher { impl webrender_traits::RenderDispatcher for CompositorThreadDispatcher {

View file

@ -22,32 +22,46 @@ use style_traits::viewport::ViewportConstraints;
use webrender; use webrender;
use webrender_traits; use webrender_traits;
/// Sends messages to the compositor. This is a trait supplied by the port because the method used
/// to communicate with the compositor may have to kick OS event loops awake, communicate cross- /// Used to wake up the event loop, provided by the servo port/embedder.
/// process, and so forth. pub trait EventLoopWaker : 'static + Send {
pub trait CompositorProxy : 'static + Send { fn clone(&self) -> Box<EventLoopWaker + Send>;
/// Sends a message to the compositor. fn wake(&self);
fn send(&self, msg: Msg);
/// Clones the compositor proxy.
fn clone_compositor_proxy(&self) -> Box<CompositorProxy + 'static + Send>;
} }
/// The port that the compositor receives messages on. As above, this is a trait supplied by the /// Sends messages to the compositor.
/// Servo port. pub struct CompositorProxy {
pub trait CompositorReceiver : 'static { pub sender: Sender<Msg>,
/// Receives the next message inbound for the compositor. This must not block. pub event_loop_waker: Box<EventLoopWaker>,
fn try_recv_compositor_msg(&mut self) -> Option<Msg>;
/// Synchronously waits for, and returns, the next message inbound for the compositor.
fn recv_compositor_msg(&mut self) -> Msg;
} }
/// A convenience implementation of `CompositorReceiver` for a plain old Rust `Receiver`. impl CompositorProxy {
impl CompositorReceiver for Receiver<Msg> { pub fn send(&self, msg: Msg) {
fn try_recv_compositor_msg(&mut self) -> Option<Msg> { // Send a message and kick the OS event loop awake.
self.try_recv().ok() if let Err(err) = self.sender.send(msg) {
warn!("Failed to send response ({}).", err);
}
self.event_loop_waker.wake();
} }
fn recv_compositor_msg(&mut self) -> Msg { pub fn clone_compositor_proxy(&self) -> CompositorProxy {
self.recv().unwrap() CompositorProxy {
sender: self.sender.clone(),
event_loop_waker: self.event_loop_waker.clone(),
}
}
}
/// The port that the compositor receives messages on.
pub struct CompositorReceiver {
pub receiver: Receiver<Msg>
}
impl CompositorReceiver {
pub fn try_recv_compositor_msg(&mut self) -> Option<Msg> {
self.receiver.try_recv().ok()
}
pub fn recv_compositor_msg(&mut self) -> Msg {
self.receiver.recv().unwrap()
} }
} }
@ -55,7 +69,7 @@ pub trait RenderListener {
fn recomposite(&mut self, reason: CompositingReason); fn recomposite(&mut self, reason: CompositingReason);
} }
impl RenderListener for Box<CompositorProxy + 'static> { impl RenderListener for CompositorProxy {
fn recomposite(&mut self, reason: CompositingReason) { fn recomposite(&mut self, reason: CompositingReason) {
self.send(Msg::Recomposite(reason)); self.send(Msg::Recomposite(reason));
} }
@ -173,9 +187,9 @@ impl Debug for Msg {
/// Data used to construct a compositor. /// Data used to construct a compositor.
pub struct InitialCompositorState { pub struct InitialCompositorState {
/// A channel to the compositor. /// A channel to the compositor.
pub sender: Box<CompositorProxy + Send>, pub sender: CompositorProxy,
/// A port on which messages inbound to the compositor can be received. /// A port on which messages inbound to the compositor can be received.
pub receiver: Box<CompositorReceiver>, pub receiver: CompositorReceiver,
/// A channel to the constellation. /// A channel to the constellation.
pub constellation_chan: Sender<ConstellationMsg>, pub constellation_chan: Sender<ConstellationMsg>,
/// A channel to the time profiler thread. /// A channel to the time profiler thread.

View file

@ -23,7 +23,7 @@ pub struct DelayedCompositionTimerProxy {
} }
struct DelayedCompositionTimer { struct DelayedCompositionTimer {
compositor_proxy: Box<CompositorProxy>, compositor_proxy: CompositorProxy,
receiver: Receiver<ToDelayedCompositionTimerMsg>, receiver: Receiver<ToDelayedCompositionTimerMsg>,
} }
@ -33,7 +33,7 @@ enum ToDelayedCompositionTimerMsg {
} }
impl DelayedCompositionTimerProxy { impl DelayedCompositionTimerProxy {
pub fn new(compositor_proxy: Box<CompositorProxy + Send>) -> DelayedCompositionTimerProxy { pub fn new(compositor_proxy: CompositorProxy) -> DelayedCompositionTimerProxy {
let (to_timer_sender, to_timer_receiver) = channel(); let (to_timer_sender, to_timer_receiver) = channel();
Builder::new().spawn(move || { Builder::new().spawn(move || {
let mut timer = DelayedCompositionTimer { let mut timer = DelayedCompositionTimer {

View file

@ -4,7 +4,7 @@
//! Abstract windowing methods. The concrete implementations of these can be found in `platform/`. //! Abstract windowing methods. The concrete implementations of these can be found in `platform/`.
use compositor_thread::{CompositorProxy, CompositorReceiver}; use compositor_thread::EventLoopWaker;
use euclid::{Point2D, Size2D}; use euclid::{Point2D, Size2D};
use euclid::point::TypedPoint2D; use euclid::point::TypedPoint2D;
use euclid::rect::TypedRect; use euclid::rect::TypedRect;
@ -144,12 +144,8 @@ pub trait WindowMethods {
/// Returns the scale factor of the system (device pixels / device independent pixels). /// Returns the scale factor of the system (device pixels / device independent pixels).
fn hidpi_factor(&self) -> ScaleFactor<f32, DeviceIndependentPixel, DevicePixel>; fn hidpi_factor(&self) -> ScaleFactor<f32, DeviceIndependentPixel, DevicePixel>;
/// Creates a channel to the compositor. The dummy parameter is needed because we don't have /// Returns a thread-safe object to wake up the window's event loop.
/// UFCS in Rust yet. fn create_event_loop_waker(&self) -> Box<EventLoopWaker>;
///
/// This is part of the windowing system because its implementation often involves OS-specific
/// magic to wake the up window's event loop.
fn create_compositor_channel(&self) -> (Box<CompositorProxy + Send>, Box<CompositorReceiver>);
/// Requests that the window system prepare a composite. Typically this will involve making /// Requests that the window system prepare a composite. Typically this will involve making
/// some type of platform-specific graphics context current. Returns true if the composite may /// some type of platform-specific graphics context current. Returns true if the composite may

View file

@ -172,7 +172,7 @@ pub struct Constellation<Message, LTF, STF> {
/// A channel (the implementation of which is port-specific) for the /// A channel (the implementation of which is port-specific) for the
/// constellation to send messages to the compositor thread. /// constellation to send messages to the compositor thread.
compositor_proxy: Box<CompositorProxy>, compositor_proxy: CompositorProxy,
/// Channels for the constellation to send messages to the public /// Channels for the constellation to send messages to the public
/// resource-related threads. There are two groups of resource /// resource-related threads. There are two groups of resource
@ -302,7 +302,7 @@ pub struct Constellation<Message, LTF, STF> {
/// State needed to construct a constellation. /// State needed to construct a constellation.
pub struct InitialConstellationState { pub struct InitialConstellationState {
/// A channel through which messages can be sent to the compositor. /// A channel through which messages can be sent to the compositor.
pub compositor_proxy: Box<CompositorProxy + Send>, pub compositor_proxy: CompositorProxy,
/// A channel to the debugger, if applicable. /// A channel to the debugger, if applicable.
pub debugger_chan: Option<debugger::Sender>, pub debugger_chan: Option<debugger::Sender>,

View file

@ -69,7 +69,7 @@ pub struct Pipeline {
pub layout_chan: IpcSender<LayoutControlMsg>, pub layout_chan: IpcSender<LayoutControlMsg>,
/// A channel to the compositor. /// A channel to the compositor.
pub compositor_proxy: Box<CompositorProxy + 'static + Send>, pub compositor_proxy: CompositorProxy,
/// The most recently loaded URL in this pipeline. /// The most recently loaded URL in this pipeline.
/// Note that this URL can change, for example if the page navigates /// Note that this URL can change, for example if the page navigates
@ -123,7 +123,7 @@ pub struct InitialPipelineState {
pub scheduler_chan: IpcSender<TimerSchedulerMsg>, pub scheduler_chan: IpcSender<TimerSchedulerMsg>,
/// A channel to the compositor. /// A channel to the compositor.
pub compositor_proxy: Box<CompositorProxy + 'static + Send>, pub compositor_proxy: CompositorProxy,
/// A channel to the developer tools, if applicable. /// A channel to the developer tools, if applicable.
pub devtools_chan: Option<Sender<DevtoolsControlMsg>>, pub devtools_chan: Option<Sender<DevtoolsControlMsg>>,
@ -303,7 +303,7 @@ impl Pipeline {
parent_info: Option<(PipelineId, FrameType)>, parent_info: Option<(PipelineId, FrameType)>,
event_loop: Rc<EventLoop>, event_loop: Rc<EventLoop>,
layout_chan: IpcSender<LayoutControlMsg>, layout_chan: IpcSender<LayoutControlMsg>,
compositor_proxy: Box<CompositorProxy + 'static + Send>, compositor_proxy: CompositorProxy,
is_private: bool, is_private: bool,
url: ServoUrl, url: ServoUrl,
visible: bool) visible: bool)

View file

@ -68,8 +68,8 @@ fn webdriver(_port: u16, _constellation: Sender<ConstellationMsg>) { }
use bluetooth::BluetoothThreadFactory; use bluetooth::BluetoothThreadFactory;
use bluetooth_traits::BluetoothRequest; use bluetooth_traits::BluetoothRequest;
use compositing::{CompositorProxy, IOCompositor}; use compositing::IOCompositor;
use compositing::compositor_thread::InitialCompositorState; use compositing::compositor_thread::{self, CompositorProxy, CompositorReceiver, InitialCompositorState};
use compositing::windowing::WindowEvent; use compositing::windowing::WindowEvent;
use compositing::windowing::WindowMethods; use compositing::windowing::WindowMethods;
use constellation::{Constellation, InitialConstellationState, UnprivilegedPipelineContent}; use constellation::{Constellation, InitialConstellationState, UnprivilegedPipelineContent};
@ -97,7 +97,7 @@ use std::borrow::Cow;
use std::cmp::max; use std::cmp::max;
use std::path::PathBuf; use std::path::PathBuf;
use std::rc::Rc; use std::rc::Rc;
use std::sync::mpsc::Sender; use std::sync::mpsc::{Sender, channel};
use webrender::renderer::RendererKind; use webrender::renderer::RendererKind;
use webvr::{WebVRThread, WebVRCompositorHandler}; use webvr::{WebVRThread, WebVRCompositorHandler};
@ -134,7 +134,7 @@ impl<Window> Browser<Window> where Window: WindowMethods + 'static {
// messages to client may need to pump a platform-specific event loop // messages to client may need to pump a platform-specific event loop
// to deliver the message. // to deliver the message.
let (compositor_proxy, compositor_receiver) = let (compositor_proxy, compositor_receiver) =
window.create_compositor_channel(); create_compositor_channel(window.create_event_loop_waker());
let supports_clipboard = window.supports_clipboard(); let supports_clipboard = window.supports_clipboard();
let time_profiler_chan = profile_time::Profiler::create(&opts.time_profiling, let time_profiler_chan = profile_time::Profiler::create(&opts.time_profiling,
opts.time_profiler_trace_path.clone()); opts.time_profiler_trace_path.clone());
@ -273,10 +273,22 @@ impl<Window> Browser<Window> where Window: WindowMethods + 'static {
} }
} }
fn create_compositor_channel(event_loop_waker: Box<compositor_thread::EventLoopWaker>)
-> (CompositorProxy, CompositorReceiver) {
let (sender, receiver) = channel();
(CompositorProxy {
sender: sender,
event_loop_waker: event_loop_waker,
},
CompositorReceiver {
receiver: receiver
})
}
fn create_constellation(user_agent: Cow<'static, str>, fn create_constellation(user_agent: Cow<'static, str>,
config_dir: Option<PathBuf>, config_dir: Option<PathBuf>,
url: Option<ServoUrl>, url: Option<ServoUrl>,
compositor_proxy: Box<CompositorProxy + Send>, compositor_proxy: CompositorProxy,
time_profiler_chan: time::ProfilerChan, time_profiler_chan: time::ProfilerChan,
mem_profiler_chan: mem::ProfilerChan, mem_profiler_chan: mem::ProfilerChan,
debugger_chan: Option<debugger::Sender>, debugger_chan: Option<debugger::Sender>,

View file

@ -17,7 +17,7 @@ use render_handler::CefRenderHandlerExtensions;
use types::{cef_cursor_handle_t, cef_cursor_type_t, cef_rect_t}; use types::{cef_cursor_handle_t, cef_cursor_type_t, cef_rect_t};
use wrappers::CefWrap; use wrappers::CefWrap;
use compositing::compositor_thread::{self, CompositorProxy, CompositorReceiver}; use compositing::compositor_thread::EventLoopWaker;
use compositing::windowing::{WindowEvent, WindowMethods}; use compositing::windowing::{WindowEvent, WindowMethods};
use euclid::point::{Point2D, TypedPoint2D}; use euclid::point::{Point2D, TypedPoint2D};
use euclid::rect::TypedRect; use euclid::rect::TypedRect;
@ -295,13 +295,17 @@ impl WindowMethods for Window {
} }
} }
fn create_compositor_channel(&self) fn create_event_loop_waker(&self) -> Box<EventLoopWaker> {
-> (Box<CompositorProxy+Send>, Box<CompositorReceiver>) { struct CefEventLoopWaker;
let (sender, receiver) = channel(); impl EventLoopWaker for CefEventLoopWaker {
(box CefCompositorProxy { fn wake(&self) {
sender: sender, app_wakeup();
} as Box<CompositorProxy+Send>, }
box receiver as Box<CompositorReceiver>) fn clone(&self) -> Box<EventLoopWaker + Send> {
box CefEventLoopWaker
}
}
box CefEventLoopWaker
} }
fn prepare_for_composite(&self, width: usize, height: usize) -> bool { fn prepare_for_composite(&self, width: usize, height: usize) -> bool {
@ -500,23 +504,6 @@ impl WindowMethods for Window {
} }
} }
struct CefCompositorProxy {
sender: Sender<compositor_thread::Msg>,
}
impl CompositorProxy for CefCompositorProxy {
fn send(&self, msg: compositor_thread::Msg) {
self.sender.send(msg).unwrap();
app_wakeup();
}
fn clone_compositor_proxy(&self) -> Box<CompositorProxy+Send> {
box CefCompositorProxy {
sender: self.sender.clone(),
} as Box<CompositorProxy+Send>
}
}
#[cfg(target_os="macos")] #[cfg(target_os="macos")]
pub fn app_wakeup() { pub fn app_wakeup() {
use cocoa::appkit::{NSApp, NSApplication, NSApplicationDefined}; use cocoa::appkit::{NSApp, NSApplication, NSApplicationDefined};

View file

@ -5,7 +5,7 @@
//! A windowing implementation using glutin. //! A windowing implementation using glutin.
use NestedEventLoopListener; use NestedEventLoopListener;
use compositing::compositor_thread::{self, CompositorProxy, CompositorReceiver}; use compositing::compositor_thread::EventLoopWaker;
use compositing::windowing::{MouseWindowEvent, WindowNavigateMsg}; use compositing::windowing::{MouseWindowEvent, WindowNavigateMsg};
use compositing::windowing::{WindowEvent, WindowMethods}; use compositing::windowing::{WindowEvent, WindowMethods};
use euclid::{Point2D, Size2D, TypedPoint2D}; use euclid::{Point2D, Size2D, TypedPoint2D};
@ -41,7 +41,6 @@ use std::mem;
use std::os::raw::c_void; use std::os::raw::c_void;
use std::ptr; use std::ptr;
use std::rc::Rc; use std::rc::Rc;
use std::sync::mpsc::{Sender, channel};
use style_traits::cursor::Cursor; use style_traits::cursor::Cursor;
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
use user32; use user32;
@ -1047,17 +1046,27 @@ impl WindowMethods for Window {
} }
} }
fn create_compositor_channel(&self) fn create_event_loop_waker(&self) -> Box<EventLoopWaker> {
-> (Box<CompositorProxy + Send>, Box<CompositorReceiver>) { struct GlutinEventLoopWaker {
let (sender, receiver) = channel(); window_proxy: Option<glutin::WindowProxy>,
}
impl EventLoopWaker for GlutinEventLoopWaker {
fn wake(&self) {
// kick the OS event loop awake.
if let Some(ref window_proxy) = self.window_proxy {
window_proxy.wakeup_event_loop()
}
}
fn clone(&self) -> Box<EventLoopWaker + Send> {
box GlutinEventLoopWaker {
window_proxy: self.window_proxy.clone(),
}
}
}
let window_proxy = create_window_proxy(self); let window_proxy = create_window_proxy(self);
box GlutinEventLoopWaker {
(box GlutinCompositorProxy { window_proxy: window_proxy,
sender: sender, }
window_proxy: window_proxy,
} as Box<CompositorProxy + Send>,
box receiver as Box<CompositorReceiver>)
} }
#[cfg(not(target_os = "windows"))] #[cfg(not(target_os = "windows"))]
@ -1289,29 +1298,6 @@ impl WindowMethods for Window {
} }
} }
struct GlutinCompositorProxy {
sender: Sender<compositor_thread::Msg>,
window_proxy: Option<glutin::WindowProxy>,
}
impl CompositorProxy for GlutinCompositorProxy {
fn send(&self, msg: compositor_thread::Msg) {
// Send a message and kick the OS event loop awake.
if let Err(err) = self.sender.send(msg) {
warn!("Failed to send response ({}).", err);
}
if let Some(ref window_proxy) = self.window_proxy {
window_proxy.wakeup_event_loop()
}
}
fn clone_compositor_proxy(&self) -> Box<CompositorProxy + Send> {
box GlutinCompositorProxy {
sender: self.sender.clone(),
window_proxy: self.window_proxy.clone(),
} as Box<CompositorProxy + Send>
}
}
fn glutin_phase_to_touch_event_type(phase: TouchPhase) -> TouchEventType { fn glutin_phase_to_touch_event_type(phase: TouchPhase) -> TouchEventType {
match phase { match phase {
TouchPhase::Started => TouchEventType::Down, TouchPhase::Started => TouchEventType::Down,