diff --git a/components/compositing/compositor.rs b/components/compositing/compositor.rs index cb2abb781fa..f6f1a02fcc5 100644 --- a/components/compositing/compositor.rs +++ b/components/compositing/compositor.rs @@ -6,7 +6,6 @@ use CompositionPipeline; use SendableFrameTree; use compositor_thread::{CompositorProxy, CompositorReceiver}; use compositor_thread::{InitialCompositorState, Msg, RenderListener}; -use delayed_composition::DelayedCompositionTimerProxy; use euclid::{Point2D, TypedPoint2D, TypedVector2D, TypedRect, ScaleFactor, TypedSize2D}; use gfx_traits::Epoch; use gleam::gl; @@ -131,9 +130,6 @@ pub struct IOCompositor { channel_to_self: CompositorProxy, - /// A handle to the delayed composition timer. - delayed_composition_timer: DelayedCompositionTimerProxy, - /// The type of composition to perform composite_target: CompositeTarget, @@ -207,7 +203,6 @@ struct ScrollZoomEvent { #[derive(PartialEq, Debug)] enum CompositionRequest { NoCompositingNecessary, - DelayedComposite(u64), CompositeNow(CompositingReason), } @@ -363,7 +358,6 @@ impl IOCompositor { scale: ScaleFactor::new(1.0), scale_factor: scale_factor, channel_to_self: state.sender.clone_compositor_proxy(), - delayed_composition_timer: DelayedCompositionTimerProxy::new(state.sender), composition_request: CompositionRequest::NoCompositingNecessary, touch_handler: TouchHandler::new(), pending_scroll_zoom_events: Vec::new(), @@ -437,8 +431,6 @@ impl IOCompositor { let _ = receiver.recv(); } - self.delayed_composition_timer.shutdown(); - self.shutdown_state = ShutdownState::FinishedShuttingDown; } @@ -524,16 +516,6 @@ impl IOCompositor { } } - (Msg::DelayedCompositionTimeout(timestamp), ShutdownState::NotShuttingDown) => { - if let CompositionRequest::DelayedComposite(this_timestamp) = - self.composition_request { - if timestamp == this_timestamp { - self.composition_request = CompositionRequest::CompositeNow( - CompositingReason::DelayedCompositeTimeout) - } - } - } - (Msg::Recomposite(reason), ShutdownState::NotShuttingDown) => { self.composition_request = CompositionRequest::CompositeNow(reason) } @@ -753,18 +735,6 @@ impl IOCompositor { } } - fn schedule_delayed_composite_if_necessary(&mut self) { - match self.composition_request { - CompositionRequest::CompositeNow(_) => return, - CompositionRequest::DelayedComposite(_) | - CompositionRequest::NoCompositingNecessary => {} - } - - let timestamp = precise_time_ns(); - self.delayed_composition_timer.schedule_composite(timestamp); - self.composition_request = CompositionRequest::DelayedComposite(timestamp); - } - fn scroll_fragment_to_point(&mut self, id: ClipId, point: Point2D) { self.webrender_api.scroll_node_with_id(LayoutPoint::from_untyped(&point), id, ScrollClamping::ToContentBounds); @@ -1235,13 +1205,18 @@ impl IOCompositor { pipeline_ids.push(*pipeline_id); } } + let animation_state = if pipeline_ids.is_empty() { + windowing::AnimationState::Idle + } else { + windowing::AnimationState::Animating + }; + self.window.set_animation_state(animation_state); for pipeline_id in &pipeline_ids { self.tick_animations_for_pipeline(*pipeline_id) } } fn tick_animations_for_pipeline(&mut self, pipeline_id: PipelineId) { - self.schedule_delayed_composite_if_necessary(); let animation_callbacks_running = self.pipeline_details(pipeline_id).animation_callbacks_running; if animation_callbacks_running { let msg = ConstellationMsg::TickAnimation(pipeline_id, AnimationTickType::Script); @@ -1635,14 +1610,6 @@ impl IOCompositor { _ => compositor_messages.push(msg), } } - if found_recomposite_msg { - compositor_messages.retain(|msg| { - match *msg { - Msg::DelayedCompositionTimeout(_) => false, - _ => true, - } - }) - } for msg in compositor_messages { if !self.handle_browser_message(msg) { break @@ -1664,8 +1631,7 @@ impl IOCompositor { } match self.composition_request { - CompositionRequest::NoCompositingNecessary | - CompositionRequest::DelayedComposite(_) => {} + CompositionRequest::NoCompositingNecessary => {} CompositionRequest::CompositeNow(_) => { self.composite() } diff --git a/components/compositing/compositor_thread.rs b/components/compositing/compositor_thread.rs index 4ff18471ea8..4081d420369 100644 --- a/components/compositing/compositor_thread.rs +++ b/components/compositing/compositor_thread.rs @@ -100,8 +100,6 @@ pub enum Msg { HistoryChanged(Vec, usize), /// Wether or not to follow a link AllowNavigation(ServoUrl, IpcSender), - /// We hit the delayed composition timeout. (See `delayed_composition.rs`.) - DelayedCompositionTimeout(u64), /// Composite. Recomposite(CompositingReason), /// Sends an unconsumed key event back to the compositor. @@ -160,7 +158,6 @@ impl Debug for Msg { Msg::AllowNavigation(..) => write!(f, "AllowNavigation"), Msg::LoadStart => write!(f, "LoadStart"), Msg::HistoryChanged(..) => write!(f, "HistoryChanged"), - Msg::DelayedCompositionTimeout(..) => write!(f, "DelayedCompositionTimeout"), Msg::Recomposite(..) => write!(f, "Recomposite"), Msg::KeyEvent(..) => write!(f, "KeyEvent"), Msg::TouchEventProcessed(..) => write!(f, "TouchEventProcessed"), diff --git a/components/compositing/delayed_composition.rs b/components/compositing/delayed_composition.rs deleted file mode 100644 index 1ea1fe13a4f..00000000000 --- a/components/compositing/delayed_composition.rs +++ /dev/null @@ -1,107 +0,0 @@ -/* 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/. */ - -//! A timer thread that composites near the end of the frame. -//! -//! This is useful when we need to composite next frame but we want to opportunistically give the -//! painting thread time to paint if it can. - -use compositor_thread::{CompositorProxy, Msg}; -use std::sync::mpsc::{Receiver, Sender, channel}; -use std::thread::{self, Builder}; -use std::time::Duration; -use std::u32; -use time; - -/// The amount of time in nanoseconds that we give to the painting thread to paint. When this -/// expires, we give up and composite anyway. -static TIMEOUT: u64 = 12_000_000; - -pub struct DelayedCompositionTimerProxy { - sender: Sender, -} - -struct DelayedCompositionTimer { - compositor_proxy: CompositorProxy, - receiver: Receiver, -} - -enum ToDelayedCompositionTimerMsg { - Exit, - ScheduleComposite(u64), -} - -impl DelayedCompositionTimerProxy { - pub fn new(compositor_proxy: CompositorProxy) -> DelayedCompositionTimerProxy { - let (to_timer_sender, to_timer_receiver) = channel(); - Builder::new().spawn(move || { - let mut timer = DelayedCompositionTimer { - compositor_proxy: compositor_proxy, - receiver: to_timer_receiver, - }; - timer.run(); - }).unwrap(); - DelayedCompositionTimerProxy { - sender: to_timer_sender, - } - } - - pub fn schedule_composite(&mut self, timestamp: u64) { - self.sender.send(ToDelayedCompositionTimerMsg::ScheduleComposite(timestamp)).unwrap() - } - - pub fn shutdown(&mut self) { - self.sender.send(ToDelayedCompositionTimerMsg::Exit).unwrap() - } -} - -impl DelayedCompositionTimer { - fn run(&mut self) { - 'outer: loop { - let mut timestamp; - loop { - match self.receiver.recv() { - Ok(ToDelayedCompositionTimerMsg::ScheduleComposite(this_timestamp)) => { - timestamp = this_timestamp; - break - } - Ok(ToDelayedCompositionTimerMsg::Exit) => break 'outer, - _ => break 'outer, - } - } - - // Drain all messages from the queue. - loop { - match self.receiver.try_recv() { - Ok(ToDelayedCompositionTimerMsg::ScheduleComposite(this_timestamp)) => { - timestamp = this_timestamp; - break - } - _ => break, - } - } - - let target = timestamp + TIMEOUT; - let now = time::precise_time_ns(); - if target > now { - let delta_ns = target - now; - thread::sleep(duration_from_nanoseconds(delta_ns)); - } - self.compositor_proxy.send(Msg::DelayedCompositionTimeout(timestamp)); - } - } -} - -fn duration_from_nanoseconds(nanos: u64) -> Duration { - pub const NANOS_PER_SEC: u32 = 1_000_000_000; - - // Get number of seconds. - let secs = nanos / NANOS_PER_SEC as u64; - - // Get number of extra nanoseconds. This should always fit in a u32, but check anyway. - let subsec_nanos = nanos % NANOS_PER_SEC as u64; - assert!(subsec_nanos <= u32::MAX as u64); - - Duration::new(secs, subsec_nanos as u32) -} diff --git a/components/compositing/lib.rs b/components/compositing/lib.rs index a11c444609b..8b8fa28b703 100644 --- a/components/compositing/lib.rs +++ b/components/compositing/lib.rs @@ -35,7 +35,6 @@ use style_traits::CSSPixel; mod compositor; pub mod compositor_thread; -mod delayed_composition; mod touch; pub mod windowing; diff --git a/components/compositing/windowing.rs b/components/compositing/windowing.rs index 436f084fecf..ac8d6a8ea21 100644 --- a/components/compositing/windowing.rs +++ b/components/compositing/windowing.rs @@ -102,6 +102,12 @@ impl Debug for WindowEvent { } } +#[derive(Debug, Copy, Clone, PartialEq)] +pub enum AnimationState { + Idle, + Animating, +} + pub trait WindowMethods { /// Returns the rendering area size in hardware pixels. fn framebuffer_size(&self) -> TypedSize2D; @@ -163,4 +169,10 @@ pub trait WindowMethods { /// Return the GL function pointer trait. fn gl(&self) -> Rc; + + /// Set whether the application is currently animating. + /// Typically, when animations are active, the window + /// will want to avoid blocking on UI events, and just + /// run the event loop at the vsync interval. + fn set_animation_state(&self, _state: AnimationState) {} } diff --git a/ports/glutin/window.rs b/ports/glutin/window.rs index 47282e633c0..c82327b2335 100644 --- a/ports/glutin/window.rs +++ b/ports/glutin/window.rs @@ -6,7 +6,7 @@ use NestedEventLoopListener; use compositing::compositor_thread::EventLoopWaker; -use compositing::windowing::{MouseWindowEvent, WindowNavigateMsg}; +use compositing::windowing::{AnimationState, MouseWindowEvent, WindowNavigateMsg}; use compositing::windowing::{WindowEvent, WindowMethods}; use euclid::{Point2D, Size2D, TypedPoint2D, TypedVector2D, TypedRect, ScaleFactor, TypedSize2D}; #[cfg(target_os = "windows")] @@ -196,6 +196,8 @@ pub struct Window { #[cfg(not(target_os = "windows"))] pressed_key_map: RefCell>, + animation_state: Cell, + gl: Rc, } @@ -316,6 +318,7 @@ impl Window { #[cfg(target_os = "windows")] last_pressed_key: Cell::new(None), gl: gl.clone(), + animation_state: Cell::new(AnimationState::Idle), }; window.present(); @@ -655,10 +658,14 @@ impl Window { let mut events = mem::replace(&mut *self.event_queue.borrow_mut(), Vec::new()); let mut close_event = false; + let poll = self.animation_state.get() == AnimationState::Animating || + opts::get().output_file.is_some() || + opts::get().exit_after_load || + opts::get().headless; // When writing to a file then exiting, use event // polling so that we don't block on a GUI event // such as mouse click. - if opts::get().output_file.is_some() || opts::get().exit_after_load || opts::get().headless { + if poll { match self.kind { WindowKind::Window(ref window) => { while let Some(event) = window.poll_events().next() { @@ -1005,6 +1012,10 @@ impl WindowMethods for Window { } + fn set_animation_state(&self, state: AnimationState) { + self.animation_state.set(state); + } + fn set_inner_size(&self, size: Size2D) { match self.kind { WindowKind::Window(ref window) => {