bug 1083530. Part 2 Refactor GeckoTouchDispacher to use mozilla::Timestamp instead of nsecs_t. r=mwu
authorMason Chang <mchang@mozilla.com>
Wed, 29 Oct 2014 13:37:06 -0700
changeset 212966 a9748c48d9bd4d38695616440800ecf2547588f5
parent 212965 907d4f91d07c9f35ad23b790b1270da244421681
child 212967 5ad297ea2725f2e04699dd523e57f9cba778f7e6
push id27737
push usercbook@mozilla.com
push dateThu, 30 Oct 2014 11:26:06 +0000
treeherdermozilla-central@46cab998bd31 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmwu
bugs1083530
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 1083530. Part 2 Refactor GeckoTouchDispacher to use mozilla::Timestamp instead of nsecs_t. r=mwu
gfx/thebes/gfxPrefs.h
widget/VsyncDispatcher.cpp
widget/VsyncDispatcher.h
widget/gonk/GeckoTouchDispatcher.cpp
widget/gonk/GeckoTouchDispatcher.h
widget/gonk/HwcComposer2D.cpp
widget/gonk/HwcComposer2D.h
widget/gonk/nsAppShell.cpp
--- a/gfx/thebes/gfxPrefs.h
+++ b/gfx/thebes/gfxPrefs.h
@@ -201,21 +201,21 @@ private:
   DECL_GFX_PREF(Once, "gfx.work-around-driver-bugs",           WorkAroundDriverBugs, bool, true);
 
   DECL_GFX_PREF(Live, "gfx.draw-color-bars",                   CompositorDrawColorBars, bool, false);
 
   // Use vsync events generated by hardware
   DECL_GFX_PREF(Once, "gfx.vsync.hw-vsync.enabled",            HardwareVsyncEnabled, bool, false);
   DECL_GFX_PREF(Once, "gfx.vsync.compositor",                  VsyncAlignedCompositor, 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);
+  // These times should be in milliseconds
+  DECL_GFX_PREF(Once, "gfx.touch.resample.max-predict",        TouchResampleMaxPredict, int32_t, 8);
+  DECL_GFX_PREF(Once, "gfx.touch.resample.vsync-adjust",       TouchVsyncSampleAdjust, int32_t, 5);
+  DECL_GFX_PREF(Once, "gfx.touch.resample.min-resample",       TouchResampleMinTime, int32_t, 2);
+  DECL_GFX_PREF(Once, "gfx.touch.resample.delay-threshold",    TouchResampleVsyncDelayThreshold, int32_t, 20);
 
   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/VsyncDispatcher.cpp
+++ b/widget/VsyncDispatcher.cpp
@@ -37,47 +37,47 @@ VsyncDispatcher::VsyncDispatcher()
 
 VsyncDispatcher::~VsyncDispatcher()
 {
   MutexAutoLock lock(mCompositorObserverLock);
   mCompositorObservers.Clear();
 }
 
 void
-VsyncDispatcher::DispatchTouchEvents(bool aNotifiedCompositors, nsecs_t aAndroidVsyncTime)
+VsyncDispatcher::DispatchTouchEvents(bool aNotifiedCompositors, TimeStamp aVsyncTime)
 {
   // Touch events can sometimes start a composite, so make sure we dispatch touches
   // even if we don't composite
 #ifdef MOZ_WIDGET_GONK
   if (!aNotifiedCompositors && gfxPrefs::TouchResampling()) {
-    GeckoTouchDispatcher::NotifyVsync(aAndroidVsyncTime);
+    GeckoTouchDispatcher::NotifyVsync(aVsyncTime);
   }
 #endif
 }
 
 void
-VsyncDispatcher::NotifyVsync(TimeStamp aVsyncTimestamp, nsecs_t aAndroidVsyncTime)
+VsyncDispatcher::NotifyVsync(TimeStamp aVsyncTimestamp)
 {
   bool notifiedCompositors = false;
   if (gfxPrefs::VsyncAlignedCompositor()) {
     MutexAutoLock lock(mCompositorObserverLock);
     notifiedCompositors = NotifyVsyncObservers(aVsyncTimestamp, mCompositorObservers);
   }
 
-  DispatchTouchEvents(notifiedCompositors, aAndroidVsyncTime);
+  DispatchTouchEvents(notifiedCompositors, aVsyncTimestamp);
 }
 
 bool
 VsyncDispatcher::NotifyVsyncObservers(TimeStamp aVsyncTimestamp, nsTArray<nsRefPtr<VsyncObserver>>& aObservers)
 {
   // Callers should lock the respective lock for the aObservers before calling this function
   for (size_t i = 0; i < aObservers.Length(); i++) {
     aObservers[i]->NotifyVsync(aVsyncTimestamp);
  }
- return aObservers.IsEmpty();
+ return !aObservers.IsEmpty();
 }
 
 void
 VsyncDispatcher::AddCompositorVsyncObserver(VsyncObserver* aVsyncObserver)
 {
   MOZ_ASSERT(CompositorParent::IsInCompositorThread());
   MutexAutoLock lock(mCompositorObserverLock);
   if (!mCompositorObservers.Contains(aVsyncObserver)) {
--- a/widget/VsyncDispatcher.h
+++ b/widget/VsyncDispatcher.h
@@ -7,18 +7,16 @@
 #define mozilla_widget_VsyncDispatcher_h
 
 #include "base/message_loop.h"
 #include "mozilla/Mutex.h"
 #include "nsISupportsImpl.h"
 #include "nsTArray.h"
 #include "ThreadSafeRefcountingWithMainThreadDestruction.h"
 
-typedef int64_t nsecs_t; // nano-seconds
-
 class MessageLoop;
 
 namespace mozilla {
 class TimeStamp;
 
 namespace layers {
 class CompositorVsyncObserver;
 }
@@ -41,26 +39,26 @@ protected:
 // VsyncDispatcher is used to dispatch vsync events to the registered observers.
 class VsyncDispatcher
 {
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VsyncDispatcher)
 
 public:
   static VsyncDispatcher* GetInstance();
   // Called on the vsync thread when a hardware vsync occurs
-  void NotifyVsync(TimeStamp aVsyncTimestamp, nsecs_t aAndroidVsyncTime);
+  void NotifyVsync(TimeStamp aVsyncTimestamp);
 
   // Compositor vsync observers must be added/removed on the compositor thread
   void AddCompositorVsyncObserver(VsyncObserver* aVsyncObserver);
   void RemoveCompositorVsyncObserver(VsyncObserver* aVsyncObserver);
 
 private:
   VsyncDispatcher();
   virtual ~VsyncDispatcher();
-  void DispatchTouchEvents(bool aNotifiedCompositors, nsecs_t aAndroidVSyncTime);
+  void DispatchTouchEvents(bool aNotifiedCompositors, TimeStamp aVsyncTime);
 
   // Called on the vsync thread. Returns true if observers were notified
   bool NotifyVsyncObservers(TimeStamp aVsyncTimestamp, nsTArray<nsRefPtr<VsyncObserver>>& aObservers);
 
   // Can have multiple compositors. On desktop, this is 1 compositor per window
   Mutex mCompositorObserverLock;
   nsTArray<nsRefPtr<VsyncObserver>> mCompositorObservers;
 };
--- a/widget/gonk/GeckoTouchDispatcher.cpp
+++ b/widget/gonk/GeckoTouchDispatcher.cpp
@@ -42,64 +42,64 @@
 
 // uncomment to print log resample data
 // #define LOG_RESAMPLE_DATA 1
 
 namespace mozilla {
 
 // Amount of time in MS before an input is considered expired.
 static const uint64_t kInputExpirationThresholdMs = 1000;
-static int32_t nanosecToMillisec(int64_t nanosec) { return nanosec / 1000000; }
+static int32_t microsecToMillisec(int64_t microsec) { return microsec / 1000; }
 
 static StaticRefPtr<GeckoTouchDispatcher> sTouchDispatcher;
 
 GeckoTouchDispatcher::GeckoTouchDispatcher()
   : mTouchQueueLock("GeckoTouchDispatcher::mTouchQueueLock")
   , mTouchEventsFiltered(false)
   , mTouchTimeDiff(0)
-  , mLastTouchTime(0)
+  , mLastTouchTime(TimeStamp::Now())
 {
   // Since GeckoTouchDispatcher is initialized when input is initialized
   // and reads gfxPrefs, it is the first thing to touch gfxPrefs.
   // The first thing to touch gfxPrefs MUST occur on the main thread and init
   // the singleton
   MOZ_ASSERT(sTouchDispatcher == nullptr);
   MOZ_ASSERT(NS_IsMainThread());
   gfxPrefs::GetSingleton();
 
   mEnabledUniformityInfo = gfxPrefs::UniformityInfo();
   mResamplingEnabled = gfxPrefs::TouchResampling() &&
                        gfxPrefs::HardwareVsyncEnabled();
-  mVsyncAdjust = gfxPrefs::TouchVsyncSampleAdjust();
-  mMaxPredict = gfxPrefs::TouchResampleMaxPredict();
-  mMinResampleTime = gfxPrefs::TouchResampleMinTime();
-  mDelayedVsyncThreshold = gfxPrefs::TouchResampleVsyncDelayThreshold();
+  mVsyncAdjust = TimeDuration::FromMilliseconds(gfxPrefs::TouchVsyncSampleAdjust());
+  mMaxPredict = TimeDuration::FromMilliseconds(gfxPrefs::TouchResampleMaxPredict());
+  mMinResampleTime = TimeDuration::FromMilliseconds(gfxPrefs::TouchResampleMinTime());
+  mDelayedVsyncThreshold = TimeDuration::FromMilliseconds(gfxPrefs::TouchResampleVsyncDelayThreshold());
   sTouchDispatcher = this;
   ClearOnShutdown(&sTouchDispatcher);
 }
 
 class DispatchTouchEventsMainThread : public nsRunnable
 {
 public:
   DispatchTouchEventsMainThread(GeckoTouchDispatcher* aTouchDispatcher,
-                                uint64_t aVsyncTime)
+                                TimeStamp aVsyncTime)
     : mTouchDispatcher(aTouchDispatcher)
     , mVsyncTime(aVsyncTime)
   {
   }
 
   NS_IMETHOD Run()
   {
     mTouchDispatcher->DispatchTouchMoveEvents(mVsyncTime);
     return NS_OK;
   }
 
 private:
   nsRefPtr<GeckoTouchDispatcher> mTouchDispatcher;
-  uint64_t mVsyncTime;
+  TimeStamp mVsyncTime;
 };
 
 class DispatchSingleTouchMainThread : public nsRunnable
 {
 public:
   DispatchSingleTouchMainThread(GeckoTouchDispatcher* aTouchDispatcher,
                                 MultiTouchInput& aTouch)
     : mTouchDispatcher(aTouchDispatcher)
@@ -115,17 +115,17 @@ public:
 
 private:
   nsRefPtr<GeckoTouchDispatcher> mTouchDispatcher;
   MultiTouchInput mTouch;
 };
 
 // Timestamp is in nanoseconds
 /* static */ bool
-GeckoTouchDispatcher::NotifyVsync(uint64_t aVsyncTimestamp)
+GeckoTouchDispatcher::NotifyVsync(TimeStamp aVsyncTimestamp)
 {
   if (sTouchDispatcher == nullptr) {
     return false;
   }
 
   MOZ_ASSERT(sTouchDispatcher->mResamplingEnabled);
   bool haveTouchData = false;
   {
@@ -137,17 +137,17 @@ 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& aTouch, uint64_t aEventTime)
+GeckoTouchDispatcher::NotifyTouch(MultiTouchInput& aTouch, TimeStamp aEventTime)
 {
   if (aTouch.mType == MultiTouchInput::MULTITOUCH_MOVE) {
     MutexAutoLock lock(mTouchQueueLock);
     if (mResamplingEnabled) {
       mTouchMoveEvents.push_back(aTouch);
       mTouchTimeDiff = aEventTime - mLastTouchTime;
       mLastTouchTime = aEventTime;
       return;
@@ -155,38 +155,38 @@ GeckoTouchDispatcher::NotifyTouch(MultiT
 
     if (mTouchMoveEvents.empty()) {
       mTouchMoveEvents.push_back(aTouch);
     } else {
       // Coalesce touch move events
       mTouchMoveEvents.back() = aTouch;
     }
 
-    NS_DispatchToMainThread(new DispatchTouchEventsMainThread(this, 0));
+    NS_DispatchToMainThread(new DispatchTouchEventsMainThread(this, TimeStamp::Now()));
   } else {
     NS_DispatchToMainThread(new DispatchSingleTouchMainThread(this, aTouch));
   }
 }
 
 void
-GeckoTouchDispatcher::DispatchTouchMoveEvents(uint64_t aVsyncTime)
+GeckoTouchDispatcher::DispatchTouchMoveEvents(TimeStamp aVsyncTime)
 {
   MultiTouchInput touchMove;
 
   {
     MutexAutoLock lock(mTouchQueueLock);
     if (mTouchMoveEvents.empty()) {
       return;
     }
 
     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;
+      TimeDuration 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) {
         touchMove = mTouchMoveEvents.back();
@@ -266,81 +266,83 @@ ResampleTouch(MultiTouchInput& aOutTouch
         alpha, aTouchDiff, aFrameDiff);
 #endif
   }
 }
 
 // Interpolates with the touch event prior to SampleTime
 // and with the future touch event past sample time
 int32_t
-GeckoTouchDispatcher::InterpolateTouch(MultiTouchInput& aOutTouch, uint64_t aSampleTime)
+GeckoTouchDispatcher::InterpolateTouch(MultiTouchInput& aOutTouch, TimeStamp aSampleTime)
 {
   MOZ_RELEASE_ASSERT(mTouchMoveEvents.size() >= 2);
   mTouchQueueLock.AssertCurrentThreadOwns();
 
   // currentTouch < SampleTime < futureTouch
   MultiTouchInput futureTouch = mTouchMoveEvents.back();
   mTouchMoveEvents.pop_back();
   MultiTouchInput currentTouch = mTouchMoveEvents.back();
 
   mTouchMoveEvents.clear();
   mTouchMoveEvents.push_back(futureTouch);
 
-  uint64_t currentTouchTime = mLastTouchTime - mTouchTimeDiff;
-  int64_t frameDiff = aSampleTime - currentTouchTime;
-  ResampleTouch(aOutTouch, currentTouch, futureTouch, frameDiff, mTouchTimeDiff, true);
+  TimeStamp currentTouchTime = mLastTouchTime - mTouchTimeDiff;
+  int64_t frameDiff = (aSampleTime - currentTouchTime).ToMicroseconds();
+  ResampleTouch(aOutTouch, currentTouch, futureTouch, frameDiff, mTouchTimeDiff.ToMicroseconds(), true);
 
-  return nanosecToMillisec(frameDiff);
+  return microsecToMillisec(frameDiff);
 }
 
 // Extrapolates from the previous two touch events before sample time
 // and extrapolates them to sample time.
 int32_t
-GeckoTouchDispatcher::ExtrapolateTouch(MultiTouchInput& aOutTouch, uint64_t aSampleTime)
+GeckoTouchDispatcher::ExtrapolateTouch(MultiTouchInput& aOutTouch, TimeStamp aSampleTime)
 {
   MOZ_RELEASE_ASSERT(mTouchMoveEvents.size() >= 2);
   mTouchQueueLock.AssertCurrentThreadOwns();
 
   // prevTouch < currentTouch < SampleTime
   MultiTouchInput currentTouch = mTouchMoveEvents.back();
   mTouchMoveEvents.pop_back();
   MultiTouchInput prevTouch = mTouchMoveEvents.back();
   mTouchMoveEvents.clear();
   mTouchMoveEvents.push_back(currentTouch);
 
-  uint64_t currentTouchTime = mLastTouchTime;
-  int64_t maxResampleTime = std::min(mTouchTimeDiff / 2, (int64_t) mMaxPredict);
-  uint64_t maxTimestamp = currentTouchTime + maxResampleTime;
+  TimeStamp currentTouchTime = mLastTouchTime;
+  TimeDuration maxResampleTime = TimeDuration::FromMicroseconds(
+                                 std::min(mTouchTimeDiff.ToMicroseconds() / 2,
+                                          mMaxPredict.ToMicroseconds()));
+  TimeStamp maxTimestamp = currentTouchTime + maxResampleTime;
 
   if (aSampleTime > maxTimestamp) {
     aSampleTime = maxTimestamp;
     #ifdef LOG_RESAMPLE_DATA
     LOG("Overshot extrapolation time, adjusting sample time\n");
     #endif
   }
 
   // This has to be signed int since it is negative
-  int64_t frameDiff = currentTouchTime - aSampleTime;
-  ResampleTouch(aOutTouch, currentTouch, prevTouch, frameDiff, mTouchTimeDiff, false);
-  return -nanosecToMillisec(frameDiff);
+  int64_t frameDiff = (currentTouchTime - aSampleTime).ToMicroseconds();
+  ResampleTouch(aOutTouch, currentTouch, prevTouch, frameDiff, mTouchTimeDiff.ToMicroseconds(), false);
+  return -microsecToMillisec(frameDiff);
 }
 
 void
-GeckoTouchDispatcher::ResampleTouchMoves(MultiTouchInput& aOutTouch, uint64_t aVsyncTime)
+GeckoTouchDispatcher::ResampleTouchMoves(MultiTouchInput& aOutTouch, TimeStamp aVsyncTime)
 {
-  uint64_t sampleTime = aVsyncTime - mVsyncAdjust;
+  TimeStamp sampleTime = aVsyncTime - mVsyncAdjust;
   int32_t touchTimeAdjust = 0;
 
   if (mLastTouchTime > sampleTime) {
     touchTimeAdjust = InterpolateTouch(aOutTouch, sampleTime);
   } else {
     touchTimeAdjust = ExtrapolateTouch(aOutTouch, sampleTime);
   }
 
-  aOutTouch.mTimeStamp += TimeDuration::FromMilliseconds(touchTimeAdjust);
+  aOutTouch.mTimeStamp = sampleTime;
   aOutTouch.mTime += touchTimeAdjust;
 }
 
 // Some touch events get sent as mouse events. If APZ doesn't capture the event
 // and if a touch only has 1 touch input, we can send a mouse event.
 void
 GeckoTouchDispatcher::DispatchMouseEvent(MultiTouchInput& aMultiTouch,
                                          bool aForwardToChildren)
--- a/widget/gonk/GeckoTouchDispatcher.h
+++ b/widget/gonk/GeckoTouchDispatcher.h
@@ -39,51 +39,51 @@ 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& aTouch, uint64_t aEventTime);
+  void NotifyTouch(MultiTouchInput& aTouch, TimeStamp aEventTime);
   void DispatchTouchEvent(MultiTouchInput& aMultiTouch);
-  void DispatchTouchMoveEvents(uint64_t aVsyncTime);
-  static bool NotifyVsync(uint64_t aVsyncTimestamp);
+  void DispatchTouchMoveEvents(TimeStamp aVsyncTime);
+  static bool NotifyVsync(TimeStamp 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);
+  int32_t InterpolateTouch(MultiTouchInput& aOutTouch, TimeStamp aSampleTime);
+  int32_t ExtrapolateTouch(MultiTouchInput& aOutTouch, TimeStamp aSampleTime);
+  void ResampleTouchMoves(MultiTouchInput& aOutTouch, TimeStamp vsyncTime);
   void SendTouchEvent(MultiTouchInput& aData);
   void DispatchMouseEvent(MultiTouchInput& aMultiTouch,
                           bool aForwardToChildren);
   WidgetMouseEvent ToWidgetMouseEvent(const MultiTouchInput& aData, nsIWidget* aWidget) const;
 
   // mTouchQueueLock are used to protect the vector below
   // as it is accessed on the vsync thread and main thread
   Mutex mTouchQueueLock;
   std::vector<MultiTouchInput> mTouchMoveEvents;
 
   bool mResamplingEnabled;
   bool mTouchEventsFiltered;
   bool mEnabledUniformityInfo;
 
   // All times below are in nanoseconds
-  int32_t mVsyncAdjust;     // Time from vsync we create sample times from
-  int32_t mMaxPredict;      // How far into the future we're allowed to extrapolate
+  TimeDuration mVsyncAdjust;     // Time from vsync we create sample times from
+  TimeDuration mMaxPredict;      // How far into the future we're allowed to extrapolate
 
   // Amount of time between vsync and the last event that is required before we
   // resample
-  int32_t mMinResampleTime;
+  TimeDuration mMinResampleTime;
 
   // The time difference between the last two touch move events
-  int64_t mTouchTimeDiff;
+  TimeDuration mTouchTimeDiff;
 
   // The system time at which the last touch event occured
-  uint64_t mLastTouchTime;
+  TimeStamp mLastTouchTime;
 
   // Threshold if a vsync event runs too far behind touch events
-  uint64_t mDelayedVsyncThreshold;
+  TimeDuration mDelayedVsyncThreshold;
 };
 
 } // namespace mozilla
 #endif // GECKO_TOUCH_INPUT_DISPATCHER_h
--- a/widget/gonk/HwcComposer2D.cpp
+++ b/widget/gonk/HwcComposer2D.cpp
@@ -70,18 +70,16 @@
 
 using namespace android;
 using namespace mozilla::gfx;
 using namespace mozilla::layers;
 
 namespace mozilla {
 
 #if ANDROID_VERSION >= 17
-nsecs_t sAndroidInitTime = 0;
-mozilla::TimeStamp sMozInitTime;
 static void
 HookInvalidate(const struct hwc_procs* aProcs)
 {
     HwcComposer2D::GetInstance()->Invalidate();
 }
 
 static void
 HookVsync(const struct hwc_procs* aProcs, int aDisplay,
@@ -111,16 +109,17 @@ HwcComposer2D::HwcComposer2D()
     , mList(nullptr)
     , mGLContext(nullptr)
     , mMaxLayerCount(0)
     , mColorFill(false)
     , mRBSwapSupport(false)
 #if ANDROID_VERSION >= 17
     , mPrevRetireFence(Fence::NO_FENCE)
     , mPrevDisplayFence(Fence::NO_FENCE)
+    , mLastVsyncTime(0)
 #endif
     , mPrepared(false)
     , mHasHWVsync(false)
     , mLock("mozilla.HwcComposer2D.mLock")
 {
 }
 
 HwcComposer2D::~HwcComposer2D() {
@@ -156,18 +155,16 @@ HwcComposer2D::Init(hwc_display_t dpy, h
             mRBSwapSupport = !!supported;
         }
     } else {
         mColorFill = false;
         mRBSwapSupport = false;
     }
 
     if (RegisterHwcEventCallback()) {
-        sAndroidInitTime = systemTime(SYSTEM_TIME_MONOTONIC);
-        sMozInitTime = TimeStamp::Now();
         EnableVsync(true);
     }
 #else
     char propValue[PROPERTY_VALUE_MAX];
     property_get("ro.display.colorfill", propValue, "0");
     mColorFill = (atoi(propValue) == 1) ? true : false;
     mRBSwapSupport = true;
 #endif
@@ -235,26 +232,30 @@ HwcComposer2D::RunVsyncEventControl(bool
             device->eventControl(device, HWC_DISPLAY_PRIMARY, HWC_EVENT_VSYNC, aEnable);
         }
     }
 }
 
 void
 HwcComposer2D::Vsync(int aDisplay, nsecs_t aVsyncTimestamp)
 {
-    nsecs_t timeSinceInit = aVsyncTimestamp - sAndroidInitTime;
-    TimeStamp vsyncTime = sMozInitTime + TimeDuration::FromMicroseconds(timeSinceInit / 1000);
+    TimeStamp vsyncTime = mozilla::TimeStamp(aVsyncTimestamp);
+    nsecs_t vsyncInterval = aVsyncTimestamp - mLastVsyncTime;
+    if (vsyncInterval < 16000000 || vsyncInterval > 17000000) {
+      LOGE("Non-uniform vsync interval: %lld\n", vsyncInterval);
+    }
+    mLastVsyncTime = aVsyncTimestamp;
 
 #ifdef MOZ_ENABLE_PROFILER_SPS
     if (profiler_is_active()) {
         CompositorParent::PostInsertVsyncProfilerMarker(vsyncTime);
     }
 #endif
 
-    VsyncDispatcher::GetInstance()->NotifyVsync(vsyncTime, aVsyncTimestamp);
+    VsyncDispatcher::GetInstance()->NotifyVsync(vsyncTime);
 }
 
 // Called on the "invalidator" thread (run from HAL).
 void
 HwcComposer2D::Invalidate()
 {
     if (!Initialized()) {
         LOGE("HwcComposer2D::Invalidate failed!");
--- a/widget/gonk/HwcComposer2D.h
+++ b/widget/gonk/HwcComposer2D.h
@@ -124,16 +124,17 @@ private:
     bool                    mColorFill;
     bool                    mRBSwapSupport;
     //Holds all the dynamically allocated RectVectors needed
     //to render the current frame
     std::list<RectVector>   mVisibleRegions;
 #if ANDROID_VERSION >= 17
     android::sp<android::Fence> mPrevRetireFence;
     android::sp<android::Fence> mPrevDisplayFence;
+    nsecs_t                 mLastVsyncTime;
 #endif
     nsTArray<layers::LayerComposite*> mHwcLayerMap;
     bool                    mPrepared;
     bool                    mHasHWVsync;
     nsRefPtr<layers::CompositorParent> mCompositorParent;
     Mutex mLock;
 };
 
--- a/widget/gonk/nsAppShell.cpp
+++ b/widget/gonk/nsAppShell.cpp
@@ -710,17 +710,17 @@ addMultiTouch(MultiTouchInput& aMultiTou
 
 void
 GeckoInputDispatcher::notifyMotion(const NotifyMotionArgs* args)
 {
     uint32_t time = nanosecsToMillisecs(args->eventTime);
     int32_t action = args->action & AMOTION_EVENT_ACTION_MASK;
     int touchCount = args->pointerCount;
     MOZ_ASSERT(touchCount <= MAX_POINTERS);
-    TimeStamp timestamp = TimeStamp::Now();
+    TimeStamp timestamp = TimeStamp(args->eventTime);
     Modifiers modifiers = getDOMModifiers(args->metaState);
 
     MultiTouchInput::MultiTouchType touchType = MultiTouchInput::MULTITOUCH_CANCEL;
     switch (action) {
     case AMOTION_EVENT_ACTION_DOWN:
     case AMOTION_EVENT_ACTION_POINTER_DOWN:
         touchType = MultiTouchInput::MULTITOUCH_START;
         break;
@@ -755,17 +755,17 @@ GeckoInputDispatcher::notifyMotion(const
         touchIndex >>= AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
         addMultiTouch(touchData, args, touchIndex);
     } else {
         for (int32_t i = 0; i < touchCount; ++i) {
             addMultiTouch(touchData, args, i);
         }
     }
 
-    mTouchDispatcher->NotifyTouch(touchData, args->eventTime);
+    mTouchDispatcher->NotifyTouch(touchData, timestamp);
 }
 
 void GeckoInputDispatcher::notifySwitch(const NotifySwitchArgs* args)
 {
     if (!sDevInputAudioJack)
         return;
 
     bool needSwitchUpdate = false;