Bug 1118841 - Implement the RefreshTimerVsyncDispatcher. r=kats
authorJerryShih <hshih@mozilla.com>
Wed, 07 Jan 2015 18:17:36 -0800
changeset 235611 6d8e998d62122ef75626c0889f9185977b229cc1
parent 235610 83f3a7efed212ef4e7d1acf58cccce2e91f44880
child 235612 88492808aea554d9c0e6222874a2fb971a391589
push id366
push usercmanchester@mozilla.com
push dateThu, 08 Jan 2015 16:40:24 +0000
reviewerskats
bugs1118841
milestone37.0a1
Bug 1118841 - Implement the RefreshTimerVsyncDispatcher. r=kats
gfx/thebes/VsyncSource.cpp
widget/VsyncDispatcher.cpp
widget/VsyncDispatcher.h
--- a/gfx/thebes/VsyncSource.cpp
+++ b/gfx/thebes/VsyncSource.cpp
@@ -2,16 +2,17 @@
  * 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 "VsyncSource.h"
 #include "gfxPlatform.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/VsyncDispatcher.h"
+#include "MainThreadUtils.h"
 
 using namespace mozilla;
 using namespace mozilla::gfx;
 
 void
 VsyncSource::AddCompositorVsyncDispatcher(CompositorVsyncDispatcher* aCompositorVsyncDispatcher)
 {
   MOZ_ASSERT(NS_IsMainThread());
--- a/widget/VsyncDispatcher.cpp
+++ b/widget/VsyncDispatcher.cpp
@@ -1,73 +1,121 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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 "MainThreadUtils.h"
 #include "VsyncDispatcher.h"
-#include "mozilla/ClearOnShutdown.h"
+#include "VsyncSource.h"
+#include "gfxPlatform.h"
 #include "mozilla/layers/CompositorParent.h"
-#include "gfxPrefs.h"
-#include "gfxPlatform.h"
-#include "VsyncSource.h"
 
 #ifdef MOZ_ENABLE_PROFILER_SPS
 #include "GeckoProfiler.h"
 #include "ProfilerMarkers.h"
 #endif
 
-#ifdef MOZ_WIDGET_GONK
-#include "GeckoTouchDispatcher.h"
-#endif
-
-using namespace mozilla::layers;
-
 namespace mozilla {
 
 CompositorVsyncDispatcher::CompositorVsyncDispatcher()
   : mCompositorObserverLock("CompositorObserverLock")
 {
   MOZ_ASSERT(XRE_IsParentProcess());
+  MOZ_ASSERT(NS_IsMainThread());
   gfxPlatform::GetPlatform()->GetHardwareVsync()->AddCompositorVsyncDispatcher(this);
 }
 
 CompositorVsyncDispatcher::~CompositorVsyncDispatcher()
 {
+  MOZ_ASSERT(XRE_IsParentProcess());
   // We auto remove this vsync dispatcher from the vsync source in the nsBaseWidget
   MOZ_ASSERT(NS_IsMainThread());
 }
 
 void
 CompositorVsyncDispatcher::NotifyVsync(TimeStamp aVsyncTimestamp)
 {
   // In hardware vsync thread
 #ifdef MOZ_ENABLE_PROFILER_SPS
     if (profiler_is_active()) {
-        CompositorParent::PostInsertVsyncProfilerMarker(aVsyncTimestamp);
+        layers::CompositorParent::PostInsertVsyncProfilerMarker(aVsyncTimestamp);
     }
 #endif
 
   MutexAutoLock lock(mCompositorObserverLock);
-  if (gfxPrefs::VsyncAlignedCompositor() && mCompositorVsyncObserver) {
+  if (mCompositorVsyncObserver) {
     mCompositorVsyncObserver->NotifyVsync(aVsyncTimestamp);
   }
 }
 
 void
 CompositorVsyncDispatcher::SetCompositorVsyncObserver(VsyncObserver* aVsyncObserver)
 {
-  MOZ_ASSERT(CompositorParent::IsInCompositorThread());
+  MOZ_ASSERT(layers::CompositorParent::IsInCompositorThread());
   MutexAutoLock lock(mCompositorObserverLock);
   mCompositorVsyncObserver = aVsyncObserver;
 }
 
 void
 CompositorVsyncDispatcher::Shutdown()
 {
   // Need to explicitly remove CompositorVsyncDispatcher when the nsBaseWidget shuts down.
   // Otherwise, we would get dead vsync notifications between when the nsBaseWidget
   // shuts down and the CompositorParent shuts down.
   MOZ_ASSERT(XRE_IsParentProcess());
   MOZ_ASSERT(NS_IsMainThread());
   gfxPlatform::GetPlatform()->GetHardwareVsync()->RemoveCompositorVsyncDispatcher(this);
 }
+
+RefreshTimerVsyncDispatcher::RefreshTimerVsyncDispatcher()
+  : mRefreshTimersLock("RefreshTimers lock")
+{
+  MOZ_ASSERT(XRE_IsParentProcess());
+  MOZ_ASSERT(NS_IsMainThread());
+}
+
+RefreshTimerVsyncDispatcher::~RefreshTimerVsyncDispatcher()
+{
+  MOZ_ASSERT(XRE_IsParentProcess());
+  MOZ_ASSERT(NS_IsMainThread());
+}
+
+void
+RefreshTimerVsyncDispatcher::NotifyVsync(TimeStamp aVsyncTimestamp)
+{
+  MutexAutoLock lock(mRefreshTimersLock);
+
+  for (size_t i = 0; i < mChildRefreshTimers.Length(); i++) {
+    mChildRefreshTimers[i]->NotifyVsync(aVsyncTimestamp);
+  }
+
+  if (mParentRefreshTimer) {
+    mParentRefreshTimer->NotifyVsync(aVsyncTimestamp);
+  }
+}
+
+void
+RefreshTimerVsyncDispatcher::SetParentRefreshTimer(VsyncObserver* aVsyncObserver)
+{
+  MutexAutoLock lock(mRefreshTimersLock);
+  mParentRefreshTimer = aVsyncObserver;
+}
+
+void
+RefreshTimerVsyncDispatcher::AddChildRefreshTimer(VsyncObserver* aVsyncObserver)
+{
+  MutexAutoLock lock(mRefreshTimersLock);
+  MOZ_ASSERT(aVsyncObserver);
+  if (!mChildRefreshTimers.Contains(aVsyncObserver)) {
+    mChildRefreshTimers.AppendElement(aVsyncObserver);
+  }
+}
+
+void
+RefreshTimerVsyncDispatcher::RemoveChildRefreshTimer(VsyncObserver* aVsyncObserver)
+{
+  MutexAutoLock lock(mRefreshTimersLock);
+  MOZ_ASSERT(aVsyncObserver);
+  mChildRefreshTimers.RemoveElement(aVsyncObserver);
+}
+
 } // namespace mozilla
--- a/widget/VsyncDispatcher.h
+++ b/widget/VsyncDispatcher.h
@@ -1,46 +1,46 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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_widget_VsyncDispatcher_h
 #define mozilla_widget_VsyncDispatcher_h
 
-#include "base/message_loop.h"
 #include "mozilla/Mutex.h"
+#include "mozilla/TimeStamp.h"
 #include "nsISupportsImpl.h"
 #include "nsTArray.h"
-#include "ThreadSafeRefcountingWithMainThreadDestruction.h"
+#include "nsRefPtr.h"
 
 namespace mozilla {
-class TimeStamp;
-
-namespace layers {
-class CompositorVsyncObserver;
-}
 
 class VsyncObserver
 {
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VsyncObserver)
 
 public:
   // The method called when a vsync occurs. Return true if some work was done.
-  // Vsync notifications will occur on the hardware vsync thread
+  // In general, this vsync notification will occur on the hardware vsync
+  // thread from VsyncSource. But it might also be called on PVsync ipc thread
+  // if this notification is cross process. Thus all observer should check the
+  // thread model before handling the real task.
   virtual bool NotifyVsync(TimeStamp aVsyncTimestamp) = 0;
 
 protected:
   VsyncObserver() {}
   virtual ~VsyncObserver() {}
 }; // VsyncObserver
 
+// Used to dispatch vsync events in the parent process to compositors
 class CompositorVsyncDispatcher MOZ_FINAL
 {
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CompositorVsyncDispatcher)
+
 public:
   CompositorVsyncDispatcher();
 
   // Called on the vsync thread when a hardware vsync occurs
   // The aVsyncTimestamp can mean different things depending on the platform:
   // b2g - The vsync timestamp of the previous frame that was just displayed
   // OSX - The vsync timestamp of the upcoming frame
   // TODO: Windows / Linux. DOCUMENT THIS WHEN IMPLEMENTING ON THOSE PLATFORMS
@@ -48,15 +48,46 @@ public:
   void NotifyVsync(TimeStamp aVsyncTimestamp);
 
   // Compositor vsync observers must be added/removed on the compositor thread
   void SetCompositorVsyncObserver(VsyncObserver* aVsyncObserver);
   void Shutdown();
 
 private:
   virtual ~CompositorVsyncDispatcher();
+
   Mutex mCompositorObserverLock;
   nsRefPtr<VsyncObserver> mCompositorVsyncObserver;
 };
 
+// Dispatch vsync event to ipc actor parent and chrome RefreshTimer.
+class RefreshTimerVsyncDispatcher MOZ_FINAL
+{
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RefreshTimerVsyncDispatcher)
+
+public:
+  RefreshTimerVsyncDispatcher();
+
+  // Please check CompositorVsyncDispatcher::NotifyVsync().
+  void NotifyVsync(TimeStamp aVsyncTimestamp);
+
+  // Set chrome process's RefreshTimer to this dispatcher.
+  // This function can be called from any thread.
+  void SetParentRefreshTimer(VsyncObserver* aVsyncObserver);
+
+  // Add or remove the content process' RefreshTimer to this dispatcher. This
+  // will be a no-op for AddChildRefreshTimer() if the observer is already
+  // registered.
+  // These functions can be called from any thread.
+  void AddChildRefreshTimer(VsyncObserver* aVsyncObserver);
+  void RemoveChildRefreshTimer(VsyncObserver* aVsyncObserver);
+
+private:
+  virtual ~RefreshTimerVsyncDispatcher();
+
+  Mutex mRefreshTimersLock;
+  nsRefPtr<VsyncObserver> mParentRefreshTimer;
+  nsTArray<nsRefPtr<VsyncObserver>> mChildRefreshTimers;
+};
+
 } // namespace mozilla
 
-#endif // __mozilla_widget_VsyncDispatcher_h
+#endif // mozilla_widget_VsyncDispatcher_h