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 225223 a9748c48d9bd4d38695616440800ecf2547588f5
parent 225222 907d4f91d07c9f35ad23b790b1270da244421681
child 225224 5ad297ea2725f2e04699dd523e57f9cba778f7e6
push id4311
push userraliiev@mozilla.com
push dateMon, 12 Jan 2015 19:37:41 +0000
treeherdermozilla-esr52@150c9fed433b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmwu
bugs1083530
milestone36.0a1
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;