Bug 1147390. Enable / disable vsync on the vsync thread only. r=kats
authorMason Chang <mchang@mozilla.com>
Fri, 10 Apr 2015 07:59:21 -0700
changeset 268520 39f5e5456b5f0830bcbe618d8d9896cc116b9ad9
parent 268519 ad1cd598bb350306283e0ae63e4da6a7770b69a8
child 268521 cafa3b191f6e8827f2f99df7560484565279b0e9
push id4830
push userjlund@mozilla.com
push dateMon, 29 Jun 2015 20:18:48 +0000
treeherdermozilla-beta@4c2175bb0420 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskats
bugs1147390
milestone40.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 1147390. Enable / disable vsync on the vsync thread only. r=kats
gfx/thebes/SoftwareVsyncSource.cpp
gfx/thebes/SoftwareVsyncSource.h
--- a/gfx/thebes/SoftwareVsyncSource.cpp
+++ b/gfx/thebes/SoftwareVsyncSource.cpp
@@ -12,76 +12,79 @@ SoftwareVsyncSource::SoftwareVsyncSource
 {
   MOZ_ASSERT(NS_IsMainThread());
   mGlobalDisplay = new SoftwareDisplay();
 }
 
 SoftwareVsyncSource::~SoftwareVsyncSource()
 {
   MOZ_ASSERT(NS_IsMainThread());
-  // Ensure we disable vsync on the main thread here
-  mGlobalDisplay->DisableVsync();
+  mGlobalDisplay->Shutdown();
   mGlobalDisplay = nullptr;
 }
 
 SoftwareDisplay::SoftwareDisplay()
-  : mVsyncEnabled(false)
-  , mCurrentTaskMonitor("SoftwareVsyncCurrentTaskMonitor")
+  : mCurrentVsyncTask(nullptr)
+  , mVsyncEnabled(false)
 {
   // Mimic 60 fps
   MOZ_ASSERT(NS_IsMainThread());
   const double rate = 1000 / 60.0;
   mVsyncRate = mozilla::TimeDuration::FromMilliseconds(rate);
   mVsyncThread = new base::Thread("SoftwareVsyncThread");
   MOZ_RELEASE_ASSERT(mVsyncThread->Start(), "Could not start software vsync thread");
 }
 
+SoftwareDisplay::~SoftwareDisplay() {}
+
 void
 SoftwareDisplay::EnableVsync()
 {
-  MOZ_ASSERT(NS_IsMainThread());
-  if (IsVsyncEnabled()) {
+  MOZ_ASSERT(mVsyncThread->IsRunning());
+  if (NS_IsMainThread()) {
+    if (mVsyncEnabled) {
+      return;
+    }
+    mVsyncEnabled = true;
+
+    mVsyncThread->message_loop()->PostTask(FROM_HERE,
+      NewRunnableMethod(this, &SoftwareDisplay::EnableVsync));
     return;
   }
 
-  { // scope lock
-    mozilla::MonitorAutoLock lock(mCurrentTaskMonitor);
-    mVsyncEnabled = true;
-    MOZ_ASSERT(mVsyncThread->IsRunning());
-    mCurrentVsyncTask = NewRunnableMethod(this,
-        &SoftwareDisplay::NotifyVsync,
-        mozilla::TimeStamp::Now());
-    mVsyncThread->message_loop()->PostTask(FROM_HERE, mCurrentVsyncTask);
-  }
+  MOZ_ASSERT(IsInSoftwareVsyncThread());
+  NotifyVsync(mozilla::TimeStamp::Now());
 }
 
 void
 SoftwareDisplay::DisableVsync()
 {
-  MOZ_ASSERT(NS_IsMainThread());
-  if (!IsVsyncEnabled()) {
+  MOZ_ASSERT(mVsyncThread->IsRunning());
+  if (NS_IsMainThread()) {
+    if (!mVsyncEnabled) {
+      return;
+    }
+    mVsyncEnabled = false;
+
+    mVsyncThread->message_loop()->PostTask(FROM_HERE,
+      NewRunnableMethod(this, &SoftwareDisplay::DisableVsync));
     return;
   }
 
-  MOZ_ASSERT(mVsyncThread->IsRunning());
-  { // scope lock
-    mozilla::MonitorAutoLock lock(mCurrentTaskMonitor);
-    mVsyncEnabled = false;
-    if (mCurrentVsyncTask) {
-      mCurrentVsyncTask->Cancel();
-      mCurrentVsyncTask = nullptr;
-    }
+  MOZ_ASSERT(IsInSoftwareVsyncThread());
+  if (mCurrentVsyncTask) {
+    mCurrentVsyncTask->Cancel();
+    mCurrentVsyncTask = nullptr;
   }
 }
 
 bool
 SoftwareDisplay::IsVsyncEnabled()
 {
   MOZ_ASSERT(NS_IsMainThread());
-  mozilla::MonitorAutoLock lock(mCurrentTaskMonitor);
   return mVsyncEnabled;
 }
 
 bool
 SoftwareDisplay::IsInSoftwareVsyncThread()
 {
   return mVsyncThread->thread_id() == PlatformThread::CurrentId();
 }
@@ -113,29 +116,25 @@ SoftwareDisplay::ScheduleNextVsync(mozil
 {
   MOZ_ASSERT(IsInSoftwareVsyncThread());
   mozilla::TimeStamp nextVsync = aVsyncTimestamp + mVsyncRate;
   mozilla::TimeDuration delay = nextVsync - mozilla::TimeStamp::Now();
   if (delay.ToMilliseconds() < 0) {
     delay = mozilla::TimeDuration::FromMilliseconds(0);
   }
 
-  mozilla::MonitorAutoLock lock(mCurrentTaskMonitor);
-  // We could've disabled vsync between this posted task and when it actually
-  // executes
-  if (!mVsyncEnabled) {
-    return;
-  }
   mCurrentVsyncTask = NewRunnableMethod(this,
       &SoftwareDisplay::NotifyVsync,
       nextVsync);
 
   mVsyncThread->message_loop()->PostDelayedTask(FROM_HERE,
       mCurrentVsyncTask,
       delay.ToMilliseconds());
 }
 
-SoftwareDisplay::~SoftwareDisplay()
+void
+SoftwareDisplay::Shutdown()
 {
   MOZ_ASSERT(NS_IsMainThread());
+  DisableVsync();
   mVsyncThread->Stop();
   delete mVsyncThread;
 }
--- a/gfx/thebes/SoftwareVsyncSource.h
+++ b/gfx/thebes/SoftwareVsyncSource.h
@@ -23,28 +23,27 @@ class SoftwareDisplay final : public moz
 public:
   SoftwareDisplay();
   virtual void EnableVsync() override;
   virtual void DisableVsync() override;
   virtual bool IsVsyncEnabled() override;
   bool IsInSoftwareVsyncThread();
   virtual void NotifyVsync(mozilla::TimeStamp aVsyncTimestamp) override;
   void ScheduleNextVsync(mozilla::TimeStamp aVsyncTimestamp);
+  void Shutdown();
 
 protected:
   ~SoftwareDisplay();
 
 private:
   mozilla::TimeDuration mVsyncRate;
   // Use a chromium thread because nsITimers* fire on the main thread
   base::Thread* mVsyncThread;
-  bool mVsyncEnabled;
-  CancelableTask* mCurrentVsyncTask;
-  // Locks against both mCurrentVsyncTask and mVsyncEnabled
-  mozilla::Monitor mCurrentTaskMonitor;
+  CancelableTask* mCurrentVsyncTask; // only access on vsync thread
+  bool mVsyncEnabled; // Only access on main thread
 }; // SoftwareDisplay
 
 // Fallback option to use a software timer to mimic vsync. Useful for gtests
 // To mimic a hardware vsync thread, we create a dedicated software timer
 // vsync thread.
 class SoftwareVsyncSource : public mozilla::gfx::VsyncSource
 {
 public: