Skip to content

Commit

Permalink
script: Avoid needless ChangeRunningAnimationsState messages during
Browse files Browse the repository at this point in the history
typical `requestAnimationFrame()` animations.

This skips useless message traffic when `requestAnimationFrame()` is
called during an animation frame callback. It reduces CPU usage of the
following snippet by 49%:

    <script>
        function foo() {
            requestAnimationFrame(foo);
        }
    </script>
    <button onclick="foo()">Start rAF</button>

Partially addresses #9844.
  • Loading branch information
pcwalton committed May 17, 2016
1 parent 82036b5 commit 8a83261
Showing 1 changed file with 22 additions and 4 deletions.
26 changes: 22 additions & 4 deletions components/script/dom/document.rs
Expand Up @@ -201,6 +201,11 @@ pub struct Document {
/// List of animation frame callbacks
#[ignore_heap_size_of = "closures are hard"]
animation_frame_list: DOMRefCell<BTreeMap<u32, Box<FnBox(f64)>>>,
/// Whether we're in the process of running animation callbacks.
///
/// Tracking this is not necessary for correctness. Instead, it is an optimization to avoid
/// sending needless `ChangeRunningAnimationsState` messages to the compositor.
running_animation_callbacks: Cell<bool>,
/// Tracks all outstanding loads related to this document.
loader: DOMRefCell<DocumentLoader>,
/// The current active HTML parser, to allow resuming after interruptions.
Expand Down Expand Up @@ -1281,11 +1286,20 @@ impl Document {
self.animation_frame_ident.set(ident);
self.animation_frame_list.borrow_mut().insert(ident, callback);

// No need to send a `ChangeRunningAnimationsState` if we're running animation callbacks:
// we're guaranteed to already be in the "animation callbacks present" state.
//
// This reduces CPU usage by avoiding needless thread wakeups in the common case of
// repeated rAF.
//
// TODO: Should tick animation only when document is visible
let ConstellationChan(ref chan) = *self.window.constellation_chan();
let event = ConstellationMsg::ChangeRunningAnimationsState(self.window.pipeline(),
AnimationState::AnimationCallbacksPresent);
chan.send(event).unwrap();
if !self.running_animation_callbacks.get() {
let ConstellationChan(ref chan) = *self.window.constellation_chan();
let event = ConstellationMsg::ChangeRunningAnimationsState(
self.window.pipeline(),
AnimationState::AnimationCallbacksPresent);
chan.send(event).unwrap();
}

ident
}
Expand All @@ -1305,6 +1319,7 @@ impl Document {
pub fn run_the_animation_frame_callbacks(&self) {
let animation_frame_list =
mem::replace(&mut *self.animation_frame_list.borrow_mut(), BTreeMap::new());
self.running_animation_callbacks.set(true);
let performance = self.window.Performance();
let performance = performance.r();
let timing = performance.Now();
Expand All @@ -1324,6 +1339,8 @@ impl Document {
chan.send(event).unwrap();
}

self.running_animation_callbacks.set(false);

self.window.reflow(ReflowGoal::ForDisplay,
ReflowQueryType::NoQuery,
ReflowReason::RequestAnimationFrame);
Expand Down Expand Up @@ -1676,6 +1693,7 @@ impl Document {
scripting_enabled: Cell::new(browsing_context.is_some()),
animation_frame_ident: Cell::new(0),
animation_frame_list: DOMRefCell::new(BTreeMap::new()),
running_animation_callbacks: Cell::new(false),
loader: DOMRefCell::new(doc_loader),
current_parser: Default::default(),
reflow_timeout: Cell::new(None),
Expand Down

0 comments on commit 8a83261

Please sign in to comment.