Bug 1069037 - Prevent touch events from piling up on the main thread. r=mwu
authorMason Chang <mchang@mozilla.com>
Thu, 16 Oct 2014 14:02:00 +0200
changeset 211099 d2cbf090111f66eb9f5265578ba0ab855ec4fff9
parent 211098 6250e897cd5dc474167a52d80310800576bdd79c
child 211100 458b83f2eaf411620e9ce2be80cd39c9ebd46697
push id50644
push usercbook@mozilla.com
push dateMon, 20 Oct 2014 08:01:27 +0000
treeherdermozilla-inbound@2c52ec780e67 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmwu
bugs1069037
milestone36.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 1069037 - Prevent touch events from piling up on the main thread. r=mwu
gfx/thebes/gfxPrefs.h
widget/gonk/GeckoTouchDispatcher.cpp
widget/gonk/GeckoTouchDispatcher.h
--- a/gfx/thebes/gfxPrefs.h
+++ b/gfx/thebes/gfxPrefs.h
@@ -204,16 +204,17 @@ private:
 
   // Use vsync events generated by hardware
   DECL_GFX_PREF(Once, "gfx.frameuniformity.hw-vsync",          FrameUniformityHWVsyncEnabled, bool, false);
   DECL_GFX_PREF(Once, "gfx.touch.resample",                    TouchResampling, bool, false);
   // These times should be in nanoseconds
   DECL_GFX_PREF(Once, "gfx.touch.resample.max-predict",        TouchResampleMaxPredict, int32_t, 8000000);
   DECL_GFX_PREF(Once, "gfx.touch.resample.vsync-adjust",       TouchVsyncSampleAdjust, int32_t, 5000000);
   DECL_GFX_PREF(Once, "gfx.touch.resample.min-resample",       TouchResampleMinTime, int32_t, 2000000);
+  DECL_GFX_PREF(Once, "gfx.touch.resample.delay-threshold",    TouchResampleVsyncDelayThreshold, int32_t, 20000000);
 
   DECL_GFX_PREF(Live, "gl.msaa-level",                         MSAALevel, uint32_t, 2);
 
   DECL_GFX_PREF(Once, "image.cache.timeweight",                ImageCacheTimeWeight, int32_t, 500);
   DECL_GFX_PREF(Once, "image.cache.size",                      ImageCacheSize, int32_t, 5*1024*1024);
   DECL_GFX_PREF(Live, "image.high_quality_downscaling.enabled", ImageHQDownscalingEnabled, bool, false);
   DECL_GFX_PREF(Live, "image.high_quality_downscaling.min_factor", ImageHQDownscalingMinFactor, uint32_t, 1000);
   DECL_GFX_PREF(Live, "image.high_quality_upscaling.max_size", ImageHQUpscalingMaxSize, uint32_t, 20971520);
--- a/widget/gonk/GeckoTouchDispatcher.cpp
+++ b/widget/gonk/GeckoTouchDispatcher.cpp
@@ -66,16 +66,17 @@ GeckoTouchDispatcher::GeckoTouchDispatch
   gfxPrefs::GetSingleton();
 
   mEnabledUniformityInfo = gfxPrefs::UniformityInfo();
   mResamplingEnabled = gfxPrefs::TouchResampling() &&
                        gfxPrefs::FrameUniformityHWVsyncEnabled();
   mVsyncAdjust = gfxPrefs::TouchVsyncSampleAdjust();
   mMaxPredict = gfxPrefs::TouchResampleMaxPredict();
   mMinResampleTime = gfxPrefs::TouchResampleMinTime();
+  mDelayedVsyncThreshold = gfxPrefs::TouchResampleVsyncDelayThreshold();
   sTouchDispatcher = this;
   ClearOnShutdown(&sTouchDispatcher);
 }
 
 class DispatchTouchEventsMainThread : public nsRunnable
 {
 public:
   DispatchTouchEventsMainThread(GeckoTouchDispatcher* aTouchDispatcher,
@@ -136,60 +137,74 @@ GeckoTouchDispatcher::NotifyVsync(uint64
     NS_DispatchToMainThread(new DispatchTouchEventsMainThread(sTouchDispatcher, aVsyncTimestamp));
   }
 
   return haveTouchData;
 }
 
 // Touch data timestamps are in milliseconds, aEventTime is in nanoseconds
 void
-GeckoTouchDispatcher::NotifyTouch(MultiTouchInput& aData, uint64_t aEventTime)
+GeckoTouchDispatcher::NotifyTouch(MultiTouchInput& aTouch, uint64_t aEventTime)
 {
-  if (mResamplingEnabled) {
-    switch (aData.mType) {
-      case MultiTouchInput::MULTITOUCH_MOVE:
-      {
-        MutexAutoLock lock(mTouchQueueLock);
-        mTouchMoveEvents.push_back(aData);
-        mTouchTimeDiff = aEventTime - mLastTouchTime;
-        mLastTouchTime = aEventTime;
-        return;
-      }
-      default:
-        break;
+  if (aTouch.mType == MultiTouchInput::MULTITOUCH_MOVE) {
+    MutexAutoLock lock(mTouchQueueLock);
+    if (mResamplingEnabled) {
+      mTouchMoveEvents.push_back(aTouch);
+      mTouchTimeDiff = aEventTime - mLastTouchTime;
+      mLastTouchTime = aEventTime;
+      return;
     }
-  }
 
-  NS_DispatchToMainThread(new DispatchSingleTouchMainThread(this, aData));
+    if (mTouchMoveEvents.empty()) {
+      mTouchMoveEvents.push_back(aTouch);
+    } else {
+      // Coalesce touch move events
+      mTouchMoveEvents.back() = aTouch;
+    }
+
+    NS_DispatchToMainThread(new DispatchTouchEventsMainThread(this, 0));
+  } else {
+    NS_DispatchToMainThread(new DispatchSingleTouchMainThread(this, aTouch));
+  }
 }
 
 void
 GeckoTouchDispatcher::DispatchTouchMoveEvents(uint64_t aVsyncTime)
 {
   MultiTouchInput touchMove;
 
   {
     MutexAutoLock lock(mTouchQueueLock);
     if (mTouchMoveEvents.empty()) {
       return;
     }
 
-    int touchCount = mTouchMoveEvents.size();
-    // Both aVsynctime and mLastTouchTime are uint64_t
-    // Need to store as a signed int.
-    int64_t vsyncTouchDiff = aVsyncTime - mLastTouchTime;
-    bool resample = (touchCount > 1) &&
-                    (vsyncTouchDiff > mMinResampleTime);
+    if (mResamplingEnabled) {
+      int touchCount = mTouchMoveEvents.size();
+      // Both aVsynctime and mLastTouchTime are uint64_t
+      // Need to store as a signed int.
+      int64_t vsyncTouchDiff = aVsyncTime - mLastTouchTime;
+      bool resample = (touchCount > 1) &&
+        (vsyncTouchDiff > mMinResampleTime);
+      // The delay threshold is a positive pref, but we're testing to see if the
+      // vsync time is delayed from the touch, so add a negative sign.
+      bool isDelayedVsyncEvent = vsyncTouchDiff < -mDelayedVsyncThreshold;
 
-    if (!resample) {
+      if (!resample) {
+        touchMove = mTouchMoveEvents.back();
+        mTouchMoveEvents.clear();
+        if (!isDelayedVsyncEvent) {
+          mTouchMoveEvents.push_back(touchMove);
+        }
+      } else {
+        ResampleTouchMoves(touchMove, aVsyncTime);
+      }
+    } else {
       touchMove = mTouchMoveEvents.back();
       mTouchMoveEvents.clear();
-      mTouchMoveEvents.push_back(touchMove);
-    } else {
-      ResampleTouchMoves(touchMove, aVsyncTime);
     }
   }
 
   DispatchTouchEvent(touchMove);
 }
 
 static int
 Interpolate(int start, int end, int64_t aFrameDiff, int64_t aTouchDiff)
--- a/widget/gonk/GeckoTouchDispatcher.h
+++ b/widget/gonk/GeckoTouchDispatcher.h
@@ -39,17 +39,17 @@ class WidgetMouseEvent;
 // time. The magic numbers defined as constants are taken from android
 // InputTransport.cpp.
 class GeckoTouchDispatcher
 {
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GeckoTouchDispatcher)
 
 public:
   GeckoTouchDispatcher();
-  void NotifyTouch(MultiTouchInput& aData, uint64_t aEventTime);
+  void NotifyTouch(MultiTouchInput& aTouch, uint64_t aEventTime);
   void DispatchTouchEvent(MultiTouchInput& aMultiTouch);
   void DispatchTouchMoveEvents(uint64_t aVsyncTime);
   static bool NotifyVsync(uint64_t aVsyncTimestamp);
 
 private:
   int32_t InterpolateTouch(MultiTouchInput& aOutTouch, uint64_t aSampleTime);
   int32_t ExtrapolateTouch(MultiTouchInput& aOutTouch, uint64_t aSampleTime);
   void ResampleTouchMoves(MultiTouchInput& aOutTouch, uint64_t vsyncTime);
@@ -75,12 +75,15 @@ private:
   // resample
   int32_t mMinResampleTime;
 
   // The time difference between the last two touch move events
   int64_t mTouchTimeDiff;
 
   // The system time at which the last touch event occured
   uint64_t mLastTouchTime;
+
+  // Threshold if a vsync event runs too far behind touch events
+  uint64_t mDelayedVsyncThreshold;
 };
 
 } // namespace mozilla
 #endif // GECKO_TOUCH_INPUT_DISPATCHER_h