Bug 1501869 - Part 2: Stop calling VR tasks when they are at background. r=kip
authorDaosheng Mu <daoshengmu@gmail.com>
Sun, 28 Oct 2018 22:49:15 +0000
changeset 443267 dfb96d3d4e0a573056334c2f8dc0bb5243f49efb
parent 443266 fcadaf0b5611d25760f6f5f09198152418d7a965
child 443268 d9b93ea9b5c442c401c50a779af2f3ab7382ffb8
push id34950
push usercsabou@mozilla.com
push dateMon, 29 Oct 2018 04:16:25 +0000
treeherdermozilla-central@d2e24bdf0648 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskip
bugs1501869
milestone65.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 1501869 - Part 2: Stop calling VR tasks when they are at background. r=kip Differential Revision: https://phabricator.services.mozilla.com/D9880
dom/base/nsGlobalWindowInner.cpp
dom/base/nsGlobalWindowInner.h
dom/base/nsGlobalWindowOuter.cpp
dom/vr/VREventObserver.cpp
dom/vr/VREventObserver.h
gfx/vr/VRManager.h
gfx/vr/ipc/PVRManager.ipdl
gfx/vr/ipc/VRManagerChild.cpp
gfx/vr/ipc/VRManagerChild.h
gfx/vr/ipc/VRManagerParent.cpp
gfx/vr/ipc/VRManagerParent.h
--- a/dom/base/nsGlobalWindowInner.cpp
+++ b/dom/base/nsGlobalWindowInner.cpp
@@ -4441,16 +4441,32 @@ nsGlobalWindowInner::DisableVRUpdates()
 void
 nsGlobalWindowInner::ResetVRTelemetry(bool aUpdate)
 {
   if (mVREventObserver) {
     mVREventObserver->UpdateSpentTimeIn2DTelemetry(aUpdate);
   }
 }
 
+void
+nsGlobalWindowInner::StartVRActivity()
+{
+  if (mVREventObserver) {
+    mVREventObserver->StartActivity();
+  }
+}
+
+void
+nsGlobalWindowInner::StopVRActivity()
+{
+  if (mVREventObserver) {
+    mVREventObserver->StopActivity();
+  }
+}
+
 #ifndef XP_WIN // This guard should match the guard at the callsite.
 static bool ShouldShowFocusRingIfFocusedByMouse(nsIContent* aNode)
 {
   if (!aNode) {
     return true;
   }
   return !nsContentUtils::ContentIsLink(aNode) &&
     !aNode->IsAnyOfHTMLElements(nsGkAtoms::video, nsGkAtoms::audio);
--- a/dom/base/nsGlobalWindowInner.h
+++ b/dom/base/nsGlobalWindowInner.h
@@ -554,16 +554,19 @@ public:
   // Enable/disable updates for VR
   void EnableVRUpdates();
   void DisableVRUpdates();
   // Reset telemetry data when switching windows.
   // aUpdate, true for accumulating the result to the histogram.
   // false for only resetting the timestamp.
   void ResetVRTelemetry(bool aUpdate);
 
+  void StartVRActivity();
+  void StopVRActivity();
+
   // Update the VR displays for this window
   bool UpdateVRDisplays(nsTArray<RefPtr<mozilla::dom::VRDisplay>>& aDisplays);
 
   // Inner windows only.
   // Called to inform that the set of active VR displays has changed.
   void NotifyActiveVRDisplaysChanged();
   void NotifyPresentationGenerationChanged(uint32_t aDisplayID);
 
--- a/dom/base/nsGlobalWindowOuter.cpp
+++ b/dom/base/nsGlobalWindowOuter.cpp
@@ -6636,28 +6636,30 @@ nsGlobalWindowOuter::SetIsBackground(boo
 
   if (aIsBackground) {
     // Notify gamepadManager we are at the background window,
     // we need to stop vibrate.
     // Stop the vr telemery time spent when it switches to
     // the background window.
     if (inner && changed) {
       inner->StopGamepadHaptics();
+      inner->StopVRActivity();
       // true is for asking to set the delta time to
       // the telemetry.
       inner->ResetVRTelemetry(true);
     }
     return;
   }
 
   if (inner) {
     // When switching to be as a top tab, restart the telemetry.
     // false is for only resetting the timestamp.
     inner->ResetVRTelemetry(false);
     inner->SyncGamepadState();
+    inner->StartVRActivity();
   }
 }
 
 void
 nsGlobalWindowOuter::SetIsBackgroundInternal(bool aIsBackground)
 {
   if (mIsBackground != aIsBackground) {
     TabGroup()->WindowChangedBackgroundStatus(aIsBackground);
--- a/dom/vr/VREventObserver.cpp
+++ b/dom/vr/VREventObserver.cpp
@@ -21,16 +21,17 @@ using namespace gfx;
  * This class is used by nsGlobalWindow to implement window.onvrdisplayactivate,
  * window.onvrdisplaydeactivate, window.onvrdisplayconnected,
  * window.onvrdisplaydisconnected, and window.onvrdisplaypresentchange.
  */
 VREventObserver::VREventObserver(nsGlobalWindowInner* aGlobalWindow)
   : mWindow(aGlobalWindow)
   , mIs2DView(true)
   , mHasReset(false)
+  , mStopActivity(false)
 {
   MOZ_ASSERT(aGlobalWindow);
 
   UpdateSpentTimeIn2DTelemetry(false);
   VRManagerChild* vmc = VRManagerChild::Get();
   if (vmc) {
     vmc->AddListener(this);
   }
@@ -50,16 +51,17 @@ VREventObserver::DisconnectFromOwner()
   UpdateSpentTimeIn2DTelemetry(true);
   mWindow = nullptr;
 
   // Unregister from VRManagerChild
   if (VRManagerChild::IsCreated()) {
     VRManagerChild* vmc = VRManagerChild::Get();
     vmc->RemoveListener(this);
   }
+  mStopActivity = true;
 }
 
 void
 VREventObserver::UpdateSpentTimeIn2DTelemetry(bool aUpdate)
 {
   // mHasReset for avoiding setting the telemetry continuously
   // for the telemetry is already been set when it is at the background.
   // then, it would be set again when the process is exit and calling
@@ -73,16 +75,38 @@ VREventObserver::UpdateSpentTimeIn2DTele
     mHasReset = false;
   } else if (!aUpdate) {
     mSpendTimeIn2DView = TimeStamp::Now();
     mHasReset = true;
   }
 }
 
 void
+VREventObserver::StartActivity()
+{
+  mStopActivity = false;
+  VRManagerChild* vmc = VRManagerChild::Get();
+  vmc->StartActivity();
+}
+
+void
+VREventObserver::StopActivity()
+{
+  mStopActivity = true;
+  VRManagerChild* vmc = VRManagerChild::Get();
+  vmc->StopActivity();
+}
+
+bool
+VREventObserver::GetStopActivityStatus()
+{
+  return mStopActivity;
+}
+
+void
 VREventObserver::NotifyAfterLoad()
 {
   if (VRManagerChild::IsCreated()) {
     VRManagerChild* vmc = VRManagerChild::Get();
     vmc->FireDOMVRDisplayConnectEventsForLoad(this);
   }
 }
 
--- a/dom/vr/VREventObserver.h
+++ b/dom/vr/VREventObserver.h
@@ -28,24 +28,28 @@ public:
   void NotifyVRDisplayRequested(uint32_t aDisplayID);
   void NotifyVRDisplayConnect(uint32_t aDisplayID);
   void NotifyVRDisplayDisconnect(uint32_t aDisplayID);
   void NotifyVRDisplayPresentChange(uint32_t aDisplayID);
   void NotifyPresentationGenerationChanged(uint32_t aDisplayID);
 
   void DisconnectFromOwner();
   void UpdateSpentTimeIn2DTelemetry(bool aUpdate);
+  void StartActivity();
+  void StopActivity();
+  bool GetStopActivityStatus();
 
 private:
   ~VREventObserver();
 
   RefPtr<nsGlobalWindowInner> mWindow;
   // For WebVR telemetry for tracking users who view content
   // in the 2D view.
   TimeStamp mSpendTimeIn2DView;
   bool mIs2DView;
   bool mHasReset;
+  bool mStopActivity;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_VREventObserver_h
--- a/gfx/vr/VRManager.h
+++ b/gfx/vr/VRManager.h
@@ -28,17 +28,16 @@ class VRDisplayHost;
 class VRService;
 #endif
 class VRSystemManagerPuppet;
 class VRSystemManagerExternal;
 
 class VRManager
 {
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(mozilla::gfx::VRManager)
-  friend class VRManagerParent;
 
 public:
   static void ManagerInit();
   static VRManager* Get();
 
   void AddVRManagerParent(VRManagerParent* aVRManagerParent);
   void RemoveVRManagerParent(VRManagerParent* aVRManagerParent);
 
--- a/gfx/vr/ipc/PVRManager.ipdl
+++ b/gfx/vr/ipc/PVRManager.ipdl
@@ -62,16 +62,18 @@ parent:
 
   async NewButtonEventToMockController(uint32_t aDeviceID, long aButton,
                                        bool aPressed);
   async NewAxisMoveEventToMockController(uint32_t aDeviceID, long aAxis,
                                          double aValue);
   async NewPoseMoveToMockController(uint32_t aDeviceID, GamepadPoseState aPose);
   async StartVRNavigation(uint32_t aDeviceID);
   async StopVRNavigation(uint32_t aDeviceID, TimeDuration aDuration);
+  async StartActivity();
+  async StopActivity();
 
 child:
   // Notify children of updated VR display enumeration and details.  This will
   // be sent to all children when the parent receives RefreshDisplays, even
   // if no changes have been detected.  This ensures that Promises exposed
   // through DOM calls are always resolved.
   async UpdateDisplayInfo(VRDisplayInfo[] aDisplayUpdates);
 
--- a/gfx/vr/ipc/VRManagerChild.cpp
+++ b/gfx/vr/ipc/VRManagerChild.cpp
@@ -614,16 +614,35 @@ VRManagerChild::RemoveListener(dom::VREv
 
   mListeners.RemoveElement(aObserver);
   if (mListeners.IsEmpty()) {
     Unused << SendSetHaveEventListener(false);
   }
 }
 
 void
+VRManagerChild::StartActivity()
+{
+  Unused << SendStartActivity();
+}
+
+void
+VRManagerChild::StopActivity()
+{
+  for (auto& listener : mListeners) {
+    if (!listener->GetStopActivityStatus()) {
+      // We are still showing VR in the active window.
+      return;
+    }
+  }
+
+  Unused << SendStopActivity();
+}
+
+void
 VRManagerChild::HandleFatalError(const char* aMsg) const
 {
   dom::ContentChild::FatalErrorIfNotUsingGPUProcess(aMsg, OtherPid());
 }
 
 void
 VRManagerChild::AddPromise(const uint32_t& aID, dom::Promise* aPromise)
 {
--- a/gfx/vr/ipc/VRManagerChild.h
+++ b/gfx/vr/ipc/VRManagerChild.h
@@ -37,16 +37,18 @@ public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VRManagerChild);
 
   static VRManagerChild* Get();
 
   // Indicate that an observer wants to receive VR events.
   void AddListener(dom::VREventObserver* aObserver);
   // Indicate that an observer should no longer receive VR events.
   void RemoveListener(dom::VREventObserver* aObserver);
+  void StartActivity();
+  void StopActivity();
 
   bool GetVRDisplays(nsTArray<RefPtr<VRDisplayClient> >& aDisplays);
   bool RefreshVRDisplaysWithCallback(uint64_t aWindowId);
   void AddPromise(const uint32_t& aID, dom::Promise* aPromise);
 
   void CreateVRServiceTestDisplay(const nsCString& aID, dom::Promise* aPromise);
   void CreateVRServiceTestController(const nsCString& aID, dom::Promise* aPromise);
 
--- a/gfx/vr/ipc/VRManagerParent.cpp
+++ b/gfx/vr/ipc/VRManagerParent.cpp
@@ -19,16 +19,17 @@ namespace mozilla {
 using namespace layers;
 namespace gfx {
 
 VRManagerParent::VRManagerParent(ProcessId aChildProcessId, bool aIsContentChild)
   : mControllerTestID(1)
   , mHaveEventListener(false)
   , mHaveControllerListener(false)
   , mIsContentChild(aIsContentChild)
+  , mVRActiveStatus(true)
 {
   MOZ_COUNT_CTOR(VRManagerParent);
   MOZ_ASSERT(NS_IsMainThread());
 
   SetOtherProcessId(aChildProcessId);
 }
 
 VRManagerParent::~VRManagerParent()
@@ -199,25 +200,35 @@ VRManagerParent::RecvSetGroupMask(const 
     display->SetGroupMask(aGroupMask);
   }
   return IPC_OK();
 }
 
 bool
 VRManagerParent::HaveEventListener()
 {
+  if (!mVRActiveStatus) {
+    return false;
+  }
+
   return mHaveEventListener;
 }
 
 bool
 VRManagerParent::HaveControllerListener()
 {
   return mHaveControllerListener;
 }
 
+bool
+VRManagerParent::GetVRActiveStatus()
+{
+  return mVRActiveStatus;
+}
+
 mozilla::ipc::IPCResult
 VRManagerParent::RecvSetHaveEventListener(const bool& aHaveEventListener)
 {
   mHaveEventListener = aHaveEventListener;
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
@@ -464,10 +475,24 @@ VRManagerParent::RecvStartVRNavigation(c
 mozilla::ipc::IPCResult
 VRManagerParent::RecvStopVRNavigation(const uint32_t& aDeviceID, const TimeDuration& aTimeout)
 {
   VRManager* vm = VRManager::Get();
   vm->StopVRNavigation(aDeviceID, aTimeout);
   return IPC_OK();
 }
 
+mozilla::ipc::IPCResult
+VRManagerParent::RecvStartActivity()
+{
+  mVRActiveStatus = true;
+  return IPC_OK();
+}
+
+mozilla::ipc::IPCResult
+VRManagerParent::RecvStopActivity()
+{
+  mVRActiveStatus = false;
+  return IPC_OK();
+}
+
 } // namespace gfx
 } // namespace mozilla
--- a/gfx/vr/ipc/VRManagerParent.h
+++ b/gfx/vr/ipc/VRManagerParent.h
@@ -34,16 +34,17 @@ public:
 
   static VRManagerParent* CreateSameProcess();
   static bool CreateForGPUProcess(Endpoint<PVRManagerParent>&& aEndpoint);
   static bool CreateForContent(Endpoint<PVRManagerParent>&& aEndpoint);
 
   bool IsSameProcess() const;
   bool HaveEventListener();
   bool HaveControllerListener();
+  bool GetVRActiveStatus();
   bool SendGamepadUpdate(const GamepadChangeEvent& aGamepadEvent);
   bool SendReplyGamepadVibrateHaptic(const uint32_t& aPromiseID);
 
 protected:
   ~VRManagerParent();
 
   virtual PVRLayerParent* AllocPVRLayerParent(const uint32_t& aDisplayID,
                                               const uint32_t& aGroup) override;
@@ -70,16 +71,19 @@ protected:
                                                                   const VRHMDSensorState& aSensorState) override;
   virtual mozilla::ipc::IPCResult RecvNewButtonEventToMockController(const uint32_t& aDeviceID, const long& aButton,
                                                                      const bool& aPressed) override;
   virtual mozilla::ipc::IPCResult RecvNewAxisMoveEventToMockController(const uint32_t& aDeviceID, const long& aAxis,
                                                                        const double& aValue) override;
   virtual mozilla::ipc::IPCResult RecvNewPoseMoveToMockController(const uint32_t& aDeviceID, const GamepadPoseState& pose) override;
   virtual mozilla::ipc::IPCResult RecvStartVRNavigation(const uint32_t& aDeviceID) override;
   virtual mozilla::ipc::IPCResult RecvStopVRNavigation(const uint32_t& aDeviceID, const TimeDuration& aTimeout) override;
+  virtual mozilla::ipc::IPCResult RecvStartActivity() override;
+  virtual mozilla::ipc::IPCResult RecvStopActivity() override;
+
 private:
   void RegisterWithManager();
   void UnregisterFromManager();
 
   void Bind(Endpoint<PVRManagerParent>&& aEndpoint);
 
   static void RegisterVRManagerInCompositorThread(VRManagerParent* aVRManager);
 
@@ -94,16 +98,20 @@ private:
 
   // Keep the VRManager alive, until we have destroyed ourselves.
   RefPtr<VRManager> mVRManagerHolder;
   nsRefPtrHashtable<nsUint32HashKey, impl::VRControllerPuppet> mVRControllerTests;
   uint32_t mControllerTestID;
   bool mHaveEventListener;
   bool mHaveControllerListener;
   bool mIsContentChild;
+
+  // When VR tabs are switched the background, we won't need to
+  // initialize its session in VRService thread.
+  bool mVRActiveStatus;
 };
 
 class VRManagerPromise final
 {
   friend class VRManager;
 
 public:
   explicit VRManagerPromise(RefPtr<VRManagerParent> aParent, uint32_t aPromiseID)