Bug 1213095 - Ensure that stale FrameMetrics do not clobber more recent metrics for paint requests. r=botond
authorKartikaya Gupta <kgupta@mozilla.com>
Mon, 18 Jan 2016 15:23:08 -0500
changeset 280406 a829107699f097eac9819d5371421af7f4012f48
parent 280405 1e5a5bfc9561b611aff4f8f6dd5816d26eb8d027
child 280407 d7c04b4c6cffc62ed92f8cc2c5e5dbb4f49a7a23
push id70434
push userkgupta@mozilla.com
push dateMon, 18 Jan 2016 20:24:53 +0000
treeherdermozilla-inbound@d7c04b4c6cff [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbotond
bugs1213095
milestone46.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1213095 - Ensure that stale FrameMetrics do not clobber more recent metrics for paint requests. r=botond
gfx/layers/apz/src/AsyncPanZoomController.cpp
gfx/layers/apz/src/AsyncPanZoomController.h
--- a/gfx/layers/apz/src/AsyncPanZoomController.cpp
+++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp
@@ -2800,16 +2800,31 @@ bool AsyncPanZoomController::IsPannable(
 }
 
 int32_t AsyncPanZoomController::GetLastTouchIdentifier() const {
   RefPtr<GestureEventListener> listener = GetGestureEventListener();
   return listener ? listener->GetLastTouchIdentifier() : -1;
 }
 
 void AsyncPanZoomController::RequestContentRepaint() {
+  // Reinvoke this method on the main thread if it's not there already. It's
+  // important to do this before the call to CalculatePendingDisplayPort, so
+  // that CalculatePendingDisplayPort uses the most recent available version of
+  // mFrameMetrics, just before the paint request is dispatched to content.
+  if (!NS_IsMainThread()) {
+    // use the local variable to resolve the function overload.
+    auto func = static_cast<void (AsyncPanZoomController::*)()>
+        (&AsyncPanZoomController::RequestContentRepaint);
+    NS_DispatchToMainThread(NS_NewRunnableMethod(this, func));
+    return;
+  }
+
+  MOZ_ASSERT(NS_IsMainThread());
+
+  ReentrantMonitorAutoEnter lock(mMonitor);
   ParentLayerPoint velocity = GetVelocityVector();
   mFrameMetrics.SetDisplayPortMargins(CalculatePendingDisplayPort(mFrameMetrics, velocity));
   mFrameMetrics.SetUseDisplayPortMargins(true);
   mFrameMetrics.SetPaintRequestTime(TimeStamp::Now());
   RequestContentRepaint(mFrameMetrics, velocity);
 }
 
 /*static*/ CSSRect
@@ -2822,16 +2837,18 @@ GetDisplayPortRect(const FrameMetrics& a
   baseRect.Inflate(aFrameMetrics.GetDisplayPortMargins() / aFrameMetrics.DisplayportPixelsPerCSSPixel());
   return baseRect;
 }
 
 void
 AsyncPanZoomController::RequestContentRepaint(const FrameMetrics& aFrameMetrics,
                                               const ParentLayerPoint& aVelocity)
 {
+  MOZ_ASSERT(NS_IsMainThread());
+
   // If we're trying to paint what we already think is painted, discard this
   // request since it's a pointless paint.
   ScreenMargin marginDelta = (mLastPaintRequestMetrics.GetDisplayPortMargins()
                            - aFrameMetrics.GetDisplayPortMargins());
   if (fabsf(marginDelta.left) < EPSILON &&
       fabsf(marginDelta.top) < EPSILON &&
       fabsf(marginDelta.right) < EPSILON &&
       fabsf(marginDelta.bottom) < EPSILON &&
@@ -2858,22 +2875,17 @@ AsyncPanZoomController::RequestContentRe
     std::stringstream info;
     info << " velocity " << aVelocity;
     std::string str = info.str();
     mCheckerboardEvent->UpdateRendertraceProperty(
         CheckerboardEvent::RequestedDisplayPort, GetDisplayPortRect(aFrameMetrics),
         str);
   }
 
-  if (NS_IsMainThread()) {
-    controller->RequestContentRepaint(aFrameMetrics);
-  } else {
-    NS_DispatchToMainThread(NS_NewRunnableMethodWithArg<FrameMetrics>(
-      controller, &GeckoContentController::RequestContentRepaint, aFrameMetrics));
-  }
+  controller->RequestContentRepaint(aFrameMetrics);
   mExpectedGeckoMetrics = aFrameMetrics;
   mLastPaintRequestMetrics = aFrameMetrics;
 }
 
 bool AsyncPanZoomController::UpdateAnimation(const TimeStamp& aSampleTime,
                                              Vector<Task*>* aOutDeferredTasks)
 {
   APZThreadUtils::AssertOnCompositorThread();
@@ -3462,17 +3474,26 @@ void AsyncPanZoomController::ZoomToRect(
 
     // Schedule a repaint now, so the new displayport will be painted before the
     // animation finishes.
     ParentLayerPoint velocity(0, 0);
     endZoomToMetrics.SetDisplayPortMargins(
       CalculatePendingDisplayPort(endZoomToMetrics, velocity));
     endZoomToMetrics.SetUseDisplayPortMargins(true);
     endZoomToMetrics.SetPaintRequestTime(TimeStamp::Now());
-    RequestContentRepaint(endZoomToMetrics, velocity);
+    if (NS_IsMainThread()) {
+      RequestContentRepaint(endZoomToMetrics, velocity);
+    } else {
+      // use a local var to resolve the function overload
+      auto func = static_cast<void (AsyncPanZoomController::*)(const FrameMetrics&, const ParentLayerPoint&)>
+          (&AsyncPanZoomController::RequestContentRepaint);
+      NS_DispatchToMainThread(
+          NS_NewRunnableMethodWithArgs<FrameMetrics, ParentLayerPoint>(
+              this, func, endZoomToMetrics, velocity));
+    }
   }
 }
 
 CancelableBlockState*
 AsyncPanZoomController::CurrentInputBlock() const
 {
   return GetInputQueue()->CurrentBlock();
 }
--- a/gfx/layers/apz/src/AsyncPanZoomController.h
+++ b/gfx/layers/apz/src/AsyncPanZoomController.h
@@ -572,23 +572,26 @@ protected:
   /**
    * Does any panning required due to a new touch event.
    */
   void TrackTouch(const MultiTouchInput& aEvent);
 
   /**
    * Utility function to send updated FrameMetrics to Gecko so that it can paint
    * the displayport area. Calls into GeckoContentController to do the actual
-   * work. This call will use the current metrics.
+   * work. This call will use the current metrics. If this function is called
+   * from a non-main thread, it will redispatch itself to the main thread, and
+   * use the latest metrics during the redispatch.
    */
   void RequestContentRepaint();
 
   /**
    * Send the provided metrics to Gecko to trigger a repaint. This function
-   * may filter duplicate calls with the same metrics.
+   * may filter duplicate calls with the same metrics. This function must be
+   * called on the main thread.
    */
   void RequestContentRepaint(const FrameMetrics& aFrameMetrics,
                              const ParentLayerPoint& aVelocity);
 
   /**
    * Gets the current frame metrics. This is *not* the Gecko copy stored in the
    * layers code.
    */