Bug 1458457 - Move the logic that we use whether the previous time stamp or the last compose time stamp into SampleAnimationForEachNode. r?birtles draft
authorHiroyuki Ikezoe <hikezoe@mozilla.com>
Tue, 08 May 2018 12:58:42 +0900
changeset 792290 5c2110d892a495fdff71937a3eb32ac9fc309a05
parent 792270 59005ba3cd3e7b3f9e8804bea881bf4c3a755d7c
child 792291 2334971b8d8c8b1c163943f3bc9c127f4207d22d
child 792299 15d27a88267ce1e411b84726be188e26a51e989d
child 792312 03c0271bee30e252b6870382334a1cfdba84b28b
push id109070
push userhikezoe@mozilla.com
push dateTue, 08 May 2018 06:17:51 +0000
reviewersbirtles
bugs1458457
milestone62.0a1
Bug 1458457 - Move the logic that we use whether the previous time stamp or the last compose time stamp into SampleAnimationForEachNode. r?birtles So that we can do an additional check depending on each animation in a subsequent patch in this patch series. MozReview-Commit-ID: C1ZJMdwraVk
gfx/layers/AnimationHelper.cpp
gfx/layers/AnimationHelper.h
gfx/layers/composite/AsyncCompositionManager.cpp
gfx/layers/wr/WebRenderBridgeParent.cpp
--- a/gfx/layers/AnimationHelper.cpp
+++ b/gfx/layers/AnimationHelper.cpp
@@ -143,17 +143,18 @@ CompositorAnimationStorage::SetAnimation
   MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
   AnimationArray* value = new AnimationArray(aValue);
   mAnimations.Put(aId, value);
 }
 
 
 AnimationHelper::SampleResult
 AnimationHelper::SampleAnimationForEachNode(
-  TimeStamp aTime,
+  TimeStamp aPreviousFrameTime,
+  TimeStamp aCurrentFrameTime,
   AnimationArray& aAnimations,
   InfallibleTArray<AnimData>& aAnimationData,
   RefPtr<RawServoAnimationValue>& aAnimationValue)
 {
   MOZ_ASSERT(!aAnimations.IsEmpty(), "Should be called with animations");
 
   bool hasInEffectAnimations = false;
 #ifdef DEBUG
@@ -170,23 +171,33 @@ AnimationHelper::SampleAnimationForEachN
     AnimData& animData = aAnimationData[i];
 
     MOZ_ASSERT((!animation.originTime().IsNull() &&
                 animation.startTime().type() ==
                   MaybeTimeDuration::TTimeDuration) ||
                animation.isNotPlaying(),
                "If we are playing, we should have an origin time and a start"
                " time");
+
+    // Use a previous vsync time to make main thread animations and compositor
+    // more in sync with each other.
+    // On the initial frame we use the current frame time here so the timestamp
+    // on the second frame are the same as the initial frame, but it does not
+    // matter.
+    const TimeStamp& timeStamp = !aPreviousFrameTime.IsNull()
+      ? aPreviousFrameTime
+      : aCurrentFrameTime;
+
     // If the animation is not currently playing, e.g. paused or
     // finished, then use the hold time to stay at the same position.
     TimeDuration elapsedDuration =
       animation.isNotPlaying() ||
       animation.startTime().type() != MaybeTimeDuration::TTimeDuration
       ? animation.holdTime()
-      : (aTime - animation.originTime() -
+      : (timeStamp - animation.originTime() -
          animation.startTime().get_TimeDuration())
         .MultDouble(animation.playbackRate());
 
     ComputedTiming computedTiming =
       dom::AnimationEffectReadOnly::GetComputedTimingAt(
         dom::Nullable<TimeDuration>(elapsedDuration), animData.mTiming,
         animation.playbackRate());
 
@@ -566,17 +577,18 @@ AnimationHelper::GetNextCompositorAnimat
   uint32_t procId = static_cast<uint32_t>(base::GetCurrentProcId());
   uint64_t nextId = procId;
   nextId = nextId << 32 | sNextId;
   return nextId;
 }
 
 void
 AnimationHelper::SampleAnimations(CompositorAnimationStorage* aStorage,
-                                  TimeStamp aTime)
+                                  TimeStamp aPreviousFrameTime,
+                                  TimeStamp aCurrentFrameTime)
 {
   MOZ_ASSERT(aStorage);
 
   // Do nothing if there are no compositor animations
   if (!aStorage->AnimationsCount()) {
     return;
   }
 
@@ -589,17 +601,18 @@ AnimationHelper::SampleAnimations(Compos
     }
 
     RefPtr<RawServoAnimationValue> animationValue;
     InfallibleTArray<AnimData> animationData;
     AnimationHelper::SetAnimations(*animations,
                                    animationData,
                                    animationValue);
     AnimationHelper::SampleResult sampleResult =
-      AnimationHelper::SampleAnimationForEachNode(aTime,
+      AnimationHelper::SampleAnimationForEachNode(aPreviousFrameTime,
+                                                  aCurrentFrameTime,
                                                   *animations,
                                                   animationData,
                                                   animationValue);
 
     if (sampleResult != AnimationHelper::SampleResult::Sampled) {
       continue;
     }
 
--- a/gfx/layers/AnimationHelper.h
+++ b/gfx/layers/AnimationHelper.h
@@ -209,25 +209,29 @@ public:
     None,
     Skipped,
     Sampled
   };
 
   /**
    * Sample animations based on a given time stamp for a element(layer) with
    * its animation data.
+   * Generally |aPreviousFrameTimeStamp| is used for the sampling if it's
+   * supplied to make the animation more in sync with other animations on the
+   * main-thread.
    *
    * Returns SampleResult::None if none of the animations are producing a result
    * (e.g. they are in the delay phase with no backwards fill),
    * SampleResult::Skipped if the animation output did not change since the last
    * call of this function,
    * SampleResult::Sampled if the animation output was updated.
    */
   static SampleResult
-  SampleAnimationForEachNode(TimeStamp aTime,
+  SampleAnimationForEachNode(TimeStamp aPreviousFrameTime,
+                             TimeStamp aCurrentFrameTime,
                              AnimationArray& aAnimations,
                              InfallibleTArray<AnimData>& aAnimationData,
                              RefPtr<RawServoAnimationValue>& aAnimationValue);
   /**
    * Populates AnimData stuctures into |aAnimData| and |aBaseAnimationStyle|
    * based on |aAnimations|.
    */
   static void
@@ -246,15 +250,16 @@ public:
 
   /**
    * Sample animation based a given time stamp |aTime| and the animation
    * data inside CompositorAnimationStorage |aStorage|. The animated values
    * after sampling will be stored in CompositorAnimationStorage as well.
    */
   static void
   SampleAnimations(CompositorAnimationStorage* aStorage,
-                   TimeStamp aTime);
+                   TimeStamp aPreviousFrameTime,
+                   TimeStamp aCurrentFrameTime);
 };
 
 } // namespace layers
 } // namespace mozilla
 
 #endif // mozilla_layers_AnimationHelper_h
--- a/gfx/layers/composite/AsyncCompositionManager.cpp
+++ b/gfx/layers/composite/AsyncCompositionManager.cpp
@@ -668,33 +668,35 @@ ApplyAnimatedValue(Layer* aLayer,
     default:
       MOZ_ASSERT_UNREACHABLE("Unhandled animated property");
   }
 }
 
 static bool
 SampleAnimations(Layer* aLayer,
                  CompositorAnimationStorage* aStorage,
-                 TimeStamp aTime)
+                 TimeStamp aPreviousFrameTime,
+                 TimeStamp aCurrentFrameTime)
 {
   bool isAnimating = false;
 
   ForEachNode<ForwardIterator>(
       aLayer,
       [&] (Layer* layer)
       {
         AnimationArray& animations = layer->GetAnimations();
         if (animations.IsEmpty()) {
           return;
         }
         isAnimating = true;
         RefPtr<RawServoAnimationValue> animationValue =
           layer->GetBaseAnimationStyle();
         AnimationHelper::SampleResult sampleResult =
-          AnimationHelper::SampleAnimationForEachNode(aTime,
+          AnimationHelper::SampleAnimationForEachNode(aPreviousFrameTime,
+                                                      aCurrentFrameTime,
                                                       animations,
                                                       layer->GetAnimationData(),
                                                       animationValue);
         switch (sampleResult) {
           case AnimationHelper::SampleResult::Sampled: {
             Animation& animation = animations.LastElement();
             ApplyAnimatedValue(layer,
                                aStorage,
@@ -1254,25 +1256,21 @@ AsyncCompositionManager::TransformShadow
     return false;
   }
 
   CompositorAnimationStorage* storage =
     mCompositorBridge->GetAnimationStorage();
   // First, compute and set the shadow transforms from OMT animations.
   // NB: we must sample animations *before* sampling pan/zoom
   // transforms.
-  // Use a previous vsync time to make main thread animations and compositor
-  // more in sync with each other.
-  // On the initial frame we use aVsyncTimestamp here so the timestamp on the
-  // second frame are the same as the initial frame, but it does not matter.
   bool wantNextFrame =
     SampleAnimations(root,
                      storage,
-                     !mPreviousFrameTimeStamp.IsNull() ?
-                       mPreviousFrameTimeStamp : aCurrentFrame);
+                     mPreviousFrameTimeStamp,
+                     aCurrentFrame);
 
   if (!wantNextFrame) {
     // Clean up the CompositorAnimationStorage because
     // there are no active animations running
     storage->Clear();
   }
 
   // Advance animations to the next expected vsync timestamp, if we can
--- a/gfx/layers/wr/WebRenderBridgeParent.cpp
+++ b/gfx/layers/wr/WebRenderBridgeParent.cpp
@@ -1217,28 +1217,27 @@ WebRenderBridgeParent::AdvanceAnimations
   if (CompositorBridgeParent* cbp = GetRootCompositorBridgeParent()) {
     Maybe<TimeStamp> testingTimeStamp = cbp->GetTestingTimeStamp();
     if (testingTimeStamp) {
       // If we are on testing refresh mode, use the testing time stamp.  And
       // also we don't update mPreviousFrameTimeStamp since unlike normal
       // refresh mode, on the testing mode animations on the compositor are
       // synchronously composed, so we don't need to worry about the time gap
       // between the main thread and compositor thread.
-      AnimationHelper::SampleAnimations(mAnimStorage, *testingTimeStamp);
+      AnimationHelper::SampleAnimations(mAnimStorage,
+                                        *testingTimeStamp,
+                                        *testingTimeStamp);
       return;
     }
   }
 
   TimeStamp lastComposeTime = mCompositorScheduler->GetLastComposeTime();
-  // if we have already mPreviousTimeStamp, use it since on the compositor the
-  // time in the previous tick is more closer to the main-thread tick time.
   AnimationHelper::SampleAnimations(mAnimStorage,
-      !mPreviousFrameTimeStamp.IsNull()
-      ? mPreviousFrameTimeStamp
-      : lastComposeTime);
+                                    mPreviousFrameTimeStamp,
+                                    lastComposeTime);
 
   // Reset the previous time stamp if we don't already have any running
   // animations to avoid using the time which is far behind for newly
   // started animations.
   mPreviousFrameTimeStamp =
     mAnimStorage->AnimatedValueCount() ? lastComposeTime : TimeStamp();
 }