Bug 799401 - Throttle APZC paint requests. r=cjones
authorAnthony Jones <ajones@mozilla.com>
Mon, 10 Dec 2012 08:50:24 -0500
changeset 124599 8b1d3367ca5d8ea0059a80b52d4da6c38adc3e17
parent 124598 78a9c289f6f1f91fdc18121ac6feaa7b5fd09dc2
child 124600 195b2469641e3e46684b5929bd659ec4a6a0268f
push id2151
push userlsblakk@mozilla.com
push dateTue, 19 Feb 2013 18:06:57 +0000
treeherdermozilla-beta@4952e88741ec [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscjones
bugs799401
milestone20.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 799401 - Throttle APZC paint requests. r=cjones
gfx/layers/Makefile.in
gfx/layers/ipc/AsyncPanZoomController.cpp
gfx/layers/ipc/AsyncPanZoomController.h
gfx/layers/ipc/TaskThrottler.cpp
gfx/layers/ipc/TaskThrottler.h
--- a/gfx/layers/Makefile.in
+++ b/gfx/layers/Makefile.in
@@ -137,16 +137,17 @@ EXPORTS_mozilla/layers =\
         ImageContainerParent.h \
         ShadowLayers.h \
         ShadowLayersChild.h \
         ShadowLayersParent.h \
         ShadowLayersManager.h \
         RenderTrace.h \
         SharedImageUtils.h \
         ShmemYCbCrImage.h \
+        TaskThrottler.h \
         $(NULL)
 
 CPPSRCS += \
         AsyncPanZoomController.cpp \
         Axis.cpp \
         CompositorCocoaWidgetHelper.cpp \
         CompositorChild.cpp \
         CompositorParent.cpp \
@@ -156,16 +157,17 @@ CPPSRCS += \
         ImageContainerChild.cpp \
         ImageContainerParent.cpp \
         ShadowLayers.cpp \
         ShadowLayerChild.cpp \
         ShadowLayersChild.cpp \
         ShadowLayerParent.cpp \
         ShadowLayersParent.cpp \
         ShmemYCbCrImage.cpp \
+        TaskThrottler.cpp \
         $(NULL)
 
 ifdef MOZ_X11 #{
 EXPORTS_mozilla/layers += ShadowLayerUtilsX11.h
 CPPSRCS += ShadowLayerUtilsX11.cpp
 endif #}
 
 ifdef MOZ_ENABLE_D3D10_LAYER
--- a/gfx/layers/ipc/AsyncPanZoomController.cpp
+++ b/gfx/layers/ipc/AsyncPanZoomController.cpp
@@ -962,17 +962,21 @@ void AsyncPanZoomController::RequestCont
             float(MIN_ZOOM) / 2.0f, float(MAX_ZOOM));
   // Scale down the resolution a bit based on acceleration.
   mFrameMetrics.mZoom.width = mFrameMetrics.mZoom.height =
                               actualZoom / accelerationFactor;
 
   // This message is compressed, so fire whether or not we already have a paint
   // queued up. We need to know whether or not a paint was requested anyways,
   // for the purposes of content calling window.scrollTo().
-  mGeckoContentController->RequestContentRepaint(mFrameMetrics);
+  mPaintThrottler.PostTask(
+    FROM_HERE,
+    NewRunnableMethod(mGeckoContentController.get(),
+                      &GeckoContentController::RequestContentRepaint,
+                      mFrameMetrics));
   mLastPaintRequestMetrics = mFrameMetrics;
   mWaitingForContentToPaint = true;
 
   // Set the zoom back to what it was for the purpose of logic control.
   mFrameMetrics.mZoom = gfxSize(actualZoom, actualZoom);
 }
 
 bool AsyncPanZoomController::SampleContentTransformForFrame(const TimeStamp& aSampleTime,
@@ -1076,16 +1080,18 @@ bool AsyncPanZoomController::SampleConte
   mLastSampleTime = aSampleTime;
 
   return requestAnimationFrame;
 }
 
 void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aViewportFrame, bool aIsFirstPaint) {
   MonitorAutoLock monitor(mMonitor);
 
+  mPaintThrottler.TaskComplete();
+
   mLastContentPaintMetrics = aViewportFrame;
 
   if (mWaitingForContentToPaint) {
     // Remove the oldest sample we have if adding a new sample takes us over our
     // desired number of samples.
     if (mPreviousPaintDurations.Length() >= NUM_PAINT_DURATION_SAMPLES) {
       mPreviousPaintDurations.RemoveElementAt(0);
     }
--- a/gfx/layers/ipc/AsyncPanZoomController.h
+++ b/gfx/layers/ipc/AsyncPanZoomController.h
@@ -10,16 +10,17 @@
 #include "GeckoContentController.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/Monitor.h"
 #include "mozilla/RefPtr.h"
 #include "mozilla/TimeStamp.h"
 #include "InputData.h"
 #include "Axis.h"
 #include "nsContentUtils.h"
+#include "TaskThrottler.h"
 
 #include "base/message_loop.h"
 
 namespace mozilla {
 namespace layers {
 
 class CompositorParent;
 class GestureEventListener;
@@ -453,16 +454,17 @@ private:
   /**
    * Helper to set the current state. Holds the monitor before actually setting
    * it. If the monitor is already held by the current thread, it is safe to
    * instead use: |mState = NEWSTATE;|
    */
   void SetState(PanZoomState aState);
 
   nsRefPtr<CompositorParent> mCompositorParent;
+  TaskThrottler mPaintThrottler;
   nsRefPtr<GeckoContentController> mGeckoContentController;
   nsRefPtr<GestureEventListener> mGestureEventListener;
 
   // Both |mFrameMetrics| and |mLastContentPaintMetrics| are protected by the
   // monitor. Do not read from or modify either of them without locking.
   FrameMetrics mFrameMetrics;
   // These are the metrics at last content paint, the most recent
   // values we were notified of in NotifyLayersUpdate().
new file mode 100644
--- /dev/null
+++ b/gfx/layers/ipc/TaskThrottler.cpp
@@ -0,0 +1,49 @@
+/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 8; -*- */
+/* vim: set sw=2 sts=2 ts=8 et tw=80 : */
+/* 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/. */
+
+#include "base/basictypes.h"
+#include "base/message_loop.h"
+#include "TaskThrottler.h"
+
+namespace mozilla {
+namespace layers {
+
+TaskThrottler::TaskThrottler()
+  : mOutstanding(false)
+  , mQueuedTask(nullptr)
+{ }
+
+void
+TaskThrottler::PostTask(const tracked_objects::Location& aLocation,
+                        CancelableTask* aTask)
+{
+  aTask->SetBirthPlace(aLocation);
+
+  if (mOutstanding) {
+    if (mQueuedTask) {
+      mQueuedTask->Cancel();
+    }
+    mQueuedTask = aTask;
+  } else {
+    aTask->Run();
+    delete aTask;
+    mOutstanding = true;
+  }
+}
+
+void
+TaskThrottler::TaskComplete()
+{
+  if (mQueuedTask) {
+    mQueuedTask->Run();
+    mQueuedTask = nullptr;
+  } else {
+    mOutstanding = false;
+  }
+}
+
+}
+}
new file mode 100644
--- /dev/null
+++ b/gfx/layers/ipc/TaskThrottler.h
@@ -0,0 +1,56 @@
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2; -*- */
+/* vim: set sw=4 ts=8 et tw=80 : */
+/* 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/. */
+
+#ifndef mozilla_dom_TaskThrottler_h
+#define mozilla_dom_TaskThrottler_h
+
+#include "nsAutoPtr.h"
+
+class CancelableTask;
+namespace tracked_objects {
+  class Location;
+}
+
+namespace mozilla {
+namespace layers {
+
+/** The TaskThrottler prevents update event overruns. It is used in cases where
+ * you're sending an async message and waiting for a reply. You need to call
+ * PostTask to queue a task and TaskComplete when you get a response.
+ *
+ * The call to TaskComplete will run the recent task posted since the last
+ * request was sent, if any. This means that at any time there can be at most 1
+ * outstanding request being processed and at most 1 queued behind it.
+ *
+ * This is used in the context of repainting a scrollable region. While another
+ * process is painting you might get several updates from the UI thread but when
+ * the paint is complete you want to send the most recent.
+ */
+
+class TaskThrottler {
+public:
+  TaskThrottler();
+
+  /** Post a task to be run as soon as there are no outstanding tasks.
+   *
+   * @param aLocation Use the macro FROM_HERE
+   * @param aTask     Ownership of this object is transferred to TaskThrottler
+   *                  which will delete it when it is either run or becomes
+   *                  obsolete or the TaskThrottler is destructed.
+   */
+  void PostTask(const tracked_objects::Location& aLocation,
+                CancelableTask* aTask);
+  void TaskComplete();
+
+private:
+  bool mOutstanding;
+  nsAutoPtr<CancelableTask> mQueuedTask;
+};
+
+}
+}
+
+#endif // mozilla_dom_TaskThrottler_h