Bug 1184283 - change PVsync to implement gfx::VsyncSource, and to track a gfx::VsyncSource on parent draft
authorVladimir Vukicevic <vladimir@pobox.com>
Mon, 25 Jan 2016 16:53:29 -0500
changeset 356571 fba4f556c693bb70e5c7d98b41ba3474a54afdae
parent 356570 29148bb40b80bc0cf3a30f6dba364c4526a8f1c4
child 356572 e94f603f176480b9cc5a0c976759b957180282a6
push id16548
push userbmo:vladimir@pobox.com
push dateTue, 26 Apr 2016 17:19:15 +0000
bugs1184283
milestone49.0a1
Bug 1184283 - change PVsync to implement gfx::VsyncSource, and to track a gfx::VsyncSource on parent
ipc/glue/BackgroundChildImpl.cpp
ipc/glue/BackgroundChildImpl.h
ipc/glue/BackgroundParentImpl.cpp
ipc/glue/BackgroundParentImpl.h
ipc/glue/PBackground.ipdl
layout/ipc/PVsync.ipdl
layout/ipc/VsyncChild.cpp
layout/ipc/VsyncChild.h
layout/ipc/VsyncParent.cpp
layout/ipc/VsyncParent.h
--- a/ipc/glue/BackgroundChildImpl.cpp
+++ b/ipc/glue/BackgroundChildImpl.cpp
@@ -225,19 +225,19 @@ BackgroundChildImpl::DeallocPFileDescrip
 {
   MOZ_ASSERT(aActor);
 
   delete static_cast<FileDescriptorSetChild*>(aActor);
   return true;
 }
 
 BackgroundChildImpl::PVsyncChild*
-BackgroundChildImpl::AllocPVsyncChild()
+BackgroundChildImpl::AllocPVsyncChild(const nsID& aDisplayIdentifier)
 {
-  RefPtr<mozilla::layout::VsyncChild> actor = new mozilla::layout::VsyncChild();
+  RefPtr<mozilla::layout::VsyncChild> actor = new mozilla::layout::VsyncChild(aDisplayIdentifier);
   // There still has one ref-count after return, and it will be released in
   // DeallocPVsyncChild().
   return actor.forget().take();
 }
 
 bool
 BackgroundChildImpl::DeallocPVsyncChild(PVsyncChild* aActor)
 {
--- a/ipc/glue/BackgroundChildImpl.h
+++ b/ipc/glue/BackgroundChildImpl.h
@@ -83,17 +83,17 @@ protected:
 
   virtual PCamerasChild*
   AllocPCamerasChild() override;
 
   virtual bool
   DeallocPCamerasChild(PCamerasChild* aActor) override;
 
   virtual PVsyncChild*
-  AllocPVsyncChild() override;
+  AllocPVsyncChild(const nsID& aDisplayIdentifier) override;
 
   virtual bool
   DeallocPVsyncChild(PVsyncChild* aActor) override;
 
   virtual PUDPSocketChild*
   AllocPUDPSocketChild(const OptionalPrincipalInfo& aPrincipalInfo,
                        const nsCString& aFilter) override;
   virtual bool
--- a/ipc/glue/BackgroundParentImpl.cpp
+++ b/ipc/glue/BackgroundParentImpl.cpp
@@ -301,23 +301,23 @@ BackgroundParentImpl::RecvPNuwaConstruct
 
 bool
 BackgroundParentImpl::DeallocPNuwaParent(PNuwaParent *aActor)
 {
   return mozilla::dom::NuwaParent::Dealloc(aActor);
 }
 
 BackgroundParentImpl::PVsyncParent*
-BackgroundParentImpl::AllocPVsyncParent()
+BackgroundParentImpl::AllocPVsyncParent(const nsID& aDisplayIdentifier)
 {
   AssertIsInMainProcess();
   AssertIsOnBackgroundThread();
 
   RefPtr<mozilla::layout::VsyncParent> actor =
-      mozilla::layout::VsyncParent::Create();
+      mozilla::layout::VsyncParent::Create(aDisplayIdentifier);
   // There still has one ref-count after return, and it will be released in
   // DeallocPVsyncParent().
   return actor.forget().take();
 }
 
 bool
 BackgroundParentImpl::DeallocPVsyncParent(PVsyncParent* aActor)
 {
--- a/ipc/glue/BackgroundParentImpl.h
+++ b/ipc/glue/BackgroundParentImpl.h
@@ -75,17 +75,17 @@ protected:
   AllocPFileDescriptorSetParent(const FileDescriptor& aFileDescriptor)
                                 override;
 
   virtual bool
   DeallocPFileDescriptorSetParent(PFileDescriptorSetParent* aActor)
                                   override;
 
   virtual PVsyncParent*
-  AllocPVsyncParent() override;
+  AllocPVsyncParent(const nsID& aDisplayIdentifier) override;
 
   virtual bool
   DeallocPVsyncParent(PVsyncParent* aActor) override;
 
   virtual PBroadcastChannelParent*
   AllocPBroadcastChannelParent(const PrincipalInfo& aPrincipalInfo,
                                const nsCString& aOrigin,
                                const nsString& aChannel,
--- a/ipc/glue/PBackground.ipdl
+++ b/ipc/glue/PBackground.ipdl
@@ -67,17 +67,19 @@ parent:
 
   async PBackgroundIDBFactory(LoggingInfo loggingInfo);
 
   async PBackgroundIndexedDBUtils();
 
   // Use only for testing!
   async FlushPendingFileDeletions();
 
-  async PVsync();
+  // Create a PVsync for the given source ID.  If you don't know which one you need,
+  // use mozilla::gfx::VsyncManager::kGlobalDisplaySourceID
+  async PVsync(nsID aSourceID);
 
   async PCameras();
 
   async PUDPSocket(OptionalPrincipalInfo pInfo, nsCString filter);
   async PBroadcastChannel(PrincipalInfo pInfo, nsCString origin, nsString channel,
                           bool privateBrowsing);
 
   async PServiceWorkerManager();
--- a/layout/ipc/PVsync.ipdl
+++ b/layout/ipc/PVsync.ipdl
@@ -18,24 +18,24 @@ namespace layout {
 async protocol PVsync
 {
   manager PBackground;
 
 child:
   // Send vsync event from chrome to content process.
   async Notify(TimeStamp aVsyncTimestamp) compress;
 
-  // Send the vsync rate to the content process.
-  async VsyncRate(float aVsyncRate);
+  // Send the vsync interval (time between vsyncs) to the content process.
+  async VsyncInterval(float aVsyncInterval);
 
 parent:
   // Content process use these messages to acquire the vsync event.
   async Observe();
   async Unobserve();
-  async RequestVsyncRate();
+  async RequestVsyncInterval();
 
   // This message is never sent. Each PVsync actor will stay alive as long as
   // its PBackground manager.
   async __delete__();
 };
 
 } // namespace layout
 } // namespace mozilla
--- a/layout/ipc/VsyncChild.cpp
+++ b/layout/ipc/VsyncChild.cpp
@@ -1,94 +1,114 @@
 /* -*- 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 "VsyncChild.h"
+#include "gfxVsync.h"
 
-#include "mozilla/VsyncDispatcher.h"
 #include "nsThreadUtils.h"
 
+extern PRLogModuleInfo *gVsyncLog;
+#define VSYNC_LOG(...)  MOZ_LOG(gVsyncLog, mozilla::LogLevel::Debug, (__VA_ARGS__))
+
 namespace mozilla {
 namespace layout {
 
-VsyncChild::VsyncChild()
-  : mObservingVsync(false)
+VsyncChild::VsyncChild(const nsID& aDisplayIdentifier)
+  : VsyncSource(aDisplayIdentifier)
+  , mObservingVsync(false)
   , mIsShutdown(false)
-  , mVsyncRate(TimeDuration::Forever())
+  , mVsyncInterval(TimeDuration::Forever())
 {
+  char idstr[NSID_LENGTH];
+  mID.ToProvidedString(idstr);
+  VSYNC_LOG("[%s]: VsyncChild %p created for display ID %s\n", XRE_GetProcessTypeString(), this, idstr);
+
   MOZ_ASSERT(NS_IsMainThread());
 }
 
 VsyncChild::~VsyncChild()
 {
+  VSYNC_LOG("[%s]: VsyncChild %p destroyed\n", XRE_GetProcessTypeString(), this);
   MOZ_ASSERT(NS_IsMainThread());
 }
 
+void
+VsyncChild::EnableVsync()
+{
+  SendObserve();
+}
+
+void
+VsyncChild::DisableVsync()
+{
+  SendUnobserve();
+}
+
 bool
 VsyncChild::SendObserve()
 {
   MOZ_ASSERT(NS_IsMainThread());
+  VSYNC_LOG("[%s]: VsyncChild %p observing\n", XRE_GetProcessTypeString(), this);
   if (!mObservingVsync && !mIsShutdown) {
     mObservingVsync = true;
     PVsyncChild::SendObserve();
   }
   return true;
 }
 
 bool
 VsyncChild::SendUnobserve()
 {
   MOZ_ASSERT(NS_IsMainThread());
+  VSYNC_LOG("[%s]: VsyncChild %p unobserving\n", XRE_GetProcessTypeString(), this);
   if (mObservingVsync && !mIsShutdown) {
     mObservingVsync = false;
     PVsyncChild::SendUnobserve();
   }
   return true;
 }
 
 void
 VsyncChild::ActorDestroy(ActorDestroyReason aActorDestroyReason)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(!mIsShutdown);
   mIsShutdown = true;
-  mObserver = nullptr;
+
+  // clear up the VsyncSource's observers
+  Shutdown();
+
+  VSYNC_LOG("[%s]: VsyncChild %p actor destroyed\n", XRE_GetProcessTypeString(), this);
 }
 
 bool
 VsyncChild::RecvNotify(const TimeStamp& aVsyncTimestamp)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(!mIsShutdown);
-  if (mObservingVsync && mObserver) {
-    mObserver->NotifyVsync(aVsyncTimestamp);
+  if (mObservingVsync) {
+    OnVsync(aVsyncTimestamp);
   }
   return true;
 }
 
-void
-VsyncChild::SetVsyncObserver(VsyncObserver* aVsyncObserver)
+TimeDuration
+VsyncChild::GetVsyncInterval()
 {
-  MOZ_ASSERT(NS_IsMainThread());
-  mObserver = aVsyncObserver;
-}
-
-TimeDuration
-VsyncChild::GetVsyncRate()
-{
-  if (mVsyncRate == TimeDuration::Forever()) {
-    PVsyncChild::SendRequestVsyncRate();
+  if (mVsyncInterval == TimeDuration::Forever()) {
+    PVsyncChild::SendRequestVsyncInterval();
   }
 
-  return mVsyncRate;
+  return mVsyncInterval;
 }
 
 bool
-VsyncChild::RecvVsyncRate(const float& aVsyncRate)
+VsyncChild::RecvVsyncInterval(const float& aVsyncInterval)
 {
-  mVsyncRate = TimeDuration::FromMilliseconds(aVsyncRate);
+  mVsyncInterval = TimeDuration::FromMilliseconds(aVsyncInterval);
   return true;
 }
 
 } // namespace layout
 } // namespace mozilla
--- a/layout/ipc/VsyncChild.h
+++ b/layout/ipc/VsyncChild.h
@@ -4,59 +4,63 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_layout_ipc_VsyncChild_h
 #define mozilla_layout_ipc_VsyncChild_h
 
 #include "mozilla/layout/PVsyncChild.h"
 #include "nsISupportsImpl.h"
 #include "mozilla/RefPtr.h"
+#include "gfxVsync.h"
 
 namespace mozilla {
-
-class VsyncObserver;
-
 namespace ipc {
 class BackgroundChildImpl;
 } // namespace ipc
 
 namespace layout {
 
 // The PVsyncChild actor receives a vsync event from the main process and
 // delivers it to the child process. Currently this is restricted to the main
 // thread only. The actor will stay alive until the process dies or its
 // PVsyncParent actor dies.
-class VsyncChild final : public PVsyncChild
+class VsyncChild final :
+    public PVsyncChild,
+    public gfx::VsyncSource
 {
-  NS_INLINE_DECL_REFCOUNTING(VsyncChild)
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VsyncChild, override)
 
   friend class mozilla::ipc::BackgroundChildImpl;
 
 public:
-  // Hide the SendObserve/SendUnobserve in PVsyncChild. We add an flag
-  // mObservingVsync to handle the race problem of unobserving vsync event.
+  // VsyncSource implementation
+  void EnableVsync() override;
+  void DisableVsync() override;
+  bool IsVsyncEnabled() override { return mObservingVsync; }
+
+  TimeDuration GetVsyncInterval() override;
+
+  const nsID& DisplayIdentifier() const { return mDisplayIdentifier; }
+
+private:
+  explicit VsyncChild(const nsID& aDisplayIdentifier);
+  virtual ~VsyncChild();
+
+  // Notify the other end whether we want to receive vsync events. We
+  // add an flag mObservingVsync to handle the race problem of
+  // unobserving vsync event.
   bool SendObserve();
   bool SendUnobserve();
 
-  // Bind a VsyncObserver into VsyncChild after ipc channel connected.
-  void SetVsyncObserver(VsyncObserver* aVsyncObserver);
-  TimeDuration GetVsyncRate();
-
-private:
-  VsyncChild();
-  virtual ~VsyncChild();
-
   virtual bool RecvNotify(const TimeStamp& aVsyncTimestamp) override;
-  virtual bool RecvVsyncRate(const float& aVsyncRate) override;
+  virtual bool RecvVsyncInterval(const float& aVsyncInterval) override;
   virtual void ActorDestroy(ActorDestroyReason aActorDestroyReason) override;
 
+  nsID mDisplayIdentifier;
   bool mObservingVsync;
   bool mIsShutdown;
-
-  // The content side vsync observer.
-  RefPtr<VsyncObserver> mObserver;
-  TimeDuration mVsyncRate;
+  TimeDuration mVsyncInterval;
 };
 
 } // namespace layout
 } // namespace mozilla
 
 #endif  // mozilla_layout_ipc_VsyncChild_h
--- a/layout/ipc/VsyncParent.cpp
+++ b/layout/ipc/VsyncParent.cpp
@@ -6,31 +6,30 @@
 #include "VsyncParent.h"
 
 #include "BackgroundParent.h"
 #include "BackgroundParentImpl.h"
 #include "gfxPlatform.h"
 #include "mozilla/unused.h"
 #include "nsIThread.h"
 #include "nsThreadUtils.h"
-#include "VsyncSource.h"
+#include "gfxVsync.h"
 
 namespace mozilla {
 
 using namespace ipc;
 
 namespace layout {
 
 /*static*/ already_AddRefed<VsyncParent>
-VsyncParent::Create()
+VsyncParent::Create(const nsID& aSourceID)
 {
   AssertIsOnBackgroundThread();
-  RefPtr<gfx::VsyncSource> vsyncSource = gfxPlatform::GetPlatform()->GetHardwareVsync();
   RefPtr<VsyncParent> vsyncParent = new VsyncParent();
-  vsyncParent->mVsyncDispatcher = vsyncSource->GetRefreshTimerVsyncDispatcher();
+  vsyncParent->mSourceID = aSourceID;
   return vsyncParent.forget();
 }
 
 VsyncParent::VsyncParent()
   : mObservingVsync(false)
   , mDestroyed(false)
   , mBackgroundThread(NS_GetCurrentThread())
 {
@@ -39,27 +38,29 @@ VsyncParent::VsyncParent()
 }
 
 VsyncParent::~VsyncParent()
 {
   // Since we use NS_INLINE_DECL_THREADSAFE_REFCOUNTING, we can't make sure
   // VsyncParent is always released on the background thread.
 }
 
-bool
+void
 VsyncParent::NotifyVsync(TimeStamp aTimeStamp)
 {
   // Called on hardware vsync thread. We should post to current ipc thread.
   MOZ_ASSERT(!IsOnBackgroundThread());
+
   nsCOMPtr<nsIRunnable> vsyncEvent =
     NS_NewRunnableMethodWithArg<TimeStamp>(this,
                                            &VsyncParent::DispatchVsyncEvent,
                                            aTimeStamp);
-  MOZ_ALWAYS_SUCCEEDS(mBackgroundThread->Dispatch(vsyncEvent, NS_DISPATCH_NORMAL));
-  return true;
+  // This dispatch might fail, if we're in the middle of shutting down when
+  // a vsync comes in.  Ignore that failure.
+  Unused << mBackgroundThread->Dispatch(vsyncEvent, NS_DISPATCH_NORMAL);
 }
 
 void
 VsyncParent::DispatchVsyncEvent(TimeStamp aTimeStamp)
 {
   AssertIsOnBackgroundThread();
 
   // If we call NotifyVsync() when we handle ActorDestroy() message, we might
@@ -68,54 +69,56 @@ VsyncParent::DispatchVsyncEvent(TimeStam
   // NotifyVsync(). We use mObservingVsync and mDestroyed flags to skip this
   // notification.
   if (mObservingVsync && !mDestroyed) {
     Unused << SendNotify(aTimeStamp);
   }
 }
 
 bool
-VsyncParent::RecvRequestVsyncRate()
+VsyncParent::RecvRequestVsyncInterval()
 {
   AssertIsOnBackgroundThread();
-  TimeDuration vsyncRate = gfxPlatform::GetPlatform()->GetHardwareVsync()->GetGlobalDisplay().GetVsyncRate();
-  Unused << SendVsyncRate(vsyncRate.ToMilliseconds());
+  RefPtr<gfx::VsyncSource> source = gfxPlatform::GetPlatform()->GetHardwareVsync()->GetSource(mSourceID);
+  Unused << SendVsyncInterval(source->GetVsyncInterval().ToMilliseconds());
   return true;
 }
 
 bool
 VsyncParent::RecvObserve()
 {
   AssertIsOnBackgroundThread();
   if (!mObservingVsync) {
-    mVsyncDispatcher->AddChildRefreshTimer(this);
+    RefPtr<gfx::VsyncSource> source = gfxPlatform::GetPlatform()->GetHardwareVsync()->GetSource(mSourceID);
+    source->AddVsyncObserver(this);
     mObservingVsync = true;
     return true;
   }
   return false;
 }
 
 bool
 VsyncParent::RecvUnobserve()
 {
   AssertIsOnBackgroundThread();
   if (mObservingVsync) {
-    mVsyncDispatcher->RemoveChildRefreshTimer(this);
+    MOZ_ASSERT(AttachedSource(), "RecvUnobserve, but we don't seem to have a source attached?");
+    AttachedSource()->RemoveVsyncObserver(this);
     mObservingVsync = false;
     return true;
   }
   return false;
 }
 
 void
 VsyncParent::ActorDestroy(ActorDestroyReason aReason)
 {
   MOZ_ASSERT(!mDestroyed);
   AssertIsOnBackgroundThread();
-  if (mObservingVsync) {
-    mVsyncDispatcher->RemoveChildRefreshTimer(this);
+  if (mObservingVsync && AttachedSource()) {
+    AttachedSource()->RemoveVsyncObserver(this);
+    mObservingVsync = false;
   }
-  mVsyncDispatcher = nullptr;
   mDestroyed = true;
 }
 
 } // namespace layout
 } // namespace mozilla
--- a/layout/ipc/VsyncParent.h
+++ b/layout/ipc/VsyncParent.h
@@ -2,55 +2,61 @@
 /* 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_layout_ipc_VsyncParent_h
 #define mozilla_layout_ipc_VsyncParent_h
 
 #include "mozilla/layout/PVsyncParent.h"
-#include "mozilla/VsyncDispatcher.h"
 #include "nsCOMPtr.h"
 #include "mozilla/RefPtr.h"
+#include "gfxVsync.h"
 
 class nsIThread;
 
 namespace mozilla {
 
+namespace gfx {
+class VsyncManager;
+class VsyncSource;
+} // namespace gfx
+
 namespace ipc {
 class BackgroundParentImpl;
 } // namespace ipc
 
 namespace layout {
 
 // Use PBackground thread in the main process to send vsync notifications to
 // content process. This actor will be released when its parent protocol calls
 // DeallocPVsyncParent().
 class VsyncParent final : public PVsyncParent,
-                          public VsyncObserver
+                          public gfx::VsyncObserver
 {
   friend class mozilla::ipc::BackgroundParentImpl;
 
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VsyncParent, override)
 private:
-  static already_AddRefed<VsyncParent> Create();
+  static already_AddRefed<VsyncParent> Create(const nsID& aSourceID);
 
   VsyncParent();
   virtual ~VsyncParent();
 
-  virtual bool NotifyVsync(TimeStamp aTimeStamp) override;
-  virtual bool RecvRequestVsyncRate() override;
+  virtual void NotifyVsync(TimeStamp aTimeStamp) override;
+  virtual bool RecvRequestVsyncInterval() override;
 
   virtual bool RecvObserve() override;
   virtual bool RecvUnobserve() override;
   virtual void ActorDestroy(ActorDestroyReason aActorDestroyReason) override;
 
   void DispatchVsyncEvent(TimeStamp aTimeStamp);
 
   bool mObservingVsync;
   bool mDestroyed;
   nsCOMPtr<nsIThread> mBackgroundThread;
-  RefPtr<RefreshTimerVsyncDispatcher> mVsyncDispatcher;
+  nsID mSourceID;
 };
 
 } // namespace layout
 } // namespace mozilla
 
 #endif  //mozilla_layout_ipc_VsyncParent_h