Bug 1406327 - Part 1: Shutdown VR listener thread when no VR content in seconds; r?kip, dvander draft
authorDaosheng Mu <daoshengmu@gmail.com>
Thu, 26 Oct 2017 16:51:14 +0800
changeset 694064 9177cd0de22fc3a7e69a5fa64108f2b625f97c0a
parent 689820 ee21e5f7f1c1726e0ed2697eb45df54cdceedd36
child 694065 eb8ce4aa9017d162567303a57b71d9c5a140b574
push id88034
push userbmo:dmu@mozilla.com
push dateTue, 07 Nov 2017 10:40:18 +0000
reviewerskip, dvander
bugs1406327
milestone58.0a1
Bug 1406327 - Part 1: Shutdown VR listener thread when no VR content in seconds; r?kip, dvander MozReview-Commit-ID: AnYJT8WBkI7
gfx/ipc/GPUParent.cpp
gfx/layers/ipc/CompositorBridgeParent.cpp
gfx/layers/ipc/CompositorVsyncScheduler.cpp
gfx/layers/ipc/CompositorVsyncScheduler.h
gfx/thebes/gfxPlatform.cpp
gfx/vr/VRThread.cpp
gfx/vr/VRThread.h
--- a/gfx/ipc/GPUParent.cpp
+++ b/gfx/ipc/GPUParent.cpp
@@ -116,18 +116,16 @@ GPUParent::Init(base::ProcessId aParentP
   DeviceManagerDx::Init();
 #endif
 
   if (NS_FAILED(NS_InitMinimalXPCOM())) {
     return false;
   }
 
   CompositorThreadHolder::Start();
-  // TODO: Bug 1406327, Start VRListenerThreadHolder when loading VR content.
-  VRListenerThreadHolder::Start();
   APZThreadUtils::SetControllerThread(CompositorThreadHolder::Loop());
   APZCTreeManager::InitializeGlobalState();
   LayerTreeOwnerTracker::Initialize();
   mozilla::ipc::SetThisProcessName("GPU Process");
 #ifdef XP_WIN
   wmf::MFStartup();
 #endif
   return true;
--- a/gfx/layers/ipc/CompositorBridgeParent.cpp
+++ b/gfx/layers/ipc/CompositorBridgeParent.cpp
@@ -27,17 +27,16 @@
 #include "mozilla/DebugOnly.h"          // for DebugOnly
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/TabParent.h"
 #include "mozilla/gfx/2D.h"          // for DrawTarget
 #include "mozilla/gfx/GPUChild.h"       // for GfxPrefValue
 #include "mozilla/gfx/Point.h"          // for IntSize
 #include "mozilla/gfx/Rect.h"          // for IntSize
 #include "mozilla/gfx/gfxVars.h"        // for gfxVars
-#include "VRManager.h"                  // for VRManager
 #include "mozilla/ipc/Transport.h"      // for Transport
 #include "mozilla/gfx/gfxVars.h"
 #include "mozilla/gfx/GPUParent.h"
 #include "mozilla/layers/AnimationHelper.h" // for CompositorAnimationStorage
 #include "mozilla/layers/APZCTreeManager.h"  // for APZCTreeManager
 #include "mozilla/layers/APZCTreeManagerParent.h"  // for APZCTreeManagerParent
 #include "mozilla/layers/APZThreadUtils.h"  // for APZCTreeManager
 #include "mozilla/layers/AsyncCompositionManager.h"
--- a/gfx/layers/ipc/CompositorVsyncScheduler.cpp
+++ b/gfx/layers/ipc/CompositorVsyncScheduler.cpp
@@ -128,29 +128,48 @@ CompositorVsyncScheduler::PostCompositeT
     RefPtr<CancelableRunnable> task = NewCancelableRunnableMethod<TimeStamp>(
       "layers::CompositorVsyncScheduler::Composite",
       this,
       &CompositorVsyncScheduler::Composite,
       aCompositeTimestamp);
     mCurrentCompositeTask = task;
     ScheduleTask(task.forget(), 0);
   }
-  if (mCurrentVRListenerTask == nullptr && VRListenerThreadHolder::Loop()) {
-    RefPtr<CancelableRunnable> task = NewCancelableRunnableMethod<TimeStamp>(
-      "layers::CompositorVsyncScheduler::DispatchVREvents",
-      this,
-      &CompositorVsyncScheduler::DispatchVREvents,
-      aCompositeTimestamp);
-    mCurrentVRListenerTask = task;
-    MOZ_ASSERT(VRListenerThreadHolder::Loop());
-    VRListenerThreadHolder::Loop()->PostDelayedTask(Move(task.forget()), 0);
+  if (mCurrentVRListenerTask == nullptr && VRListenerThreadHolder::IsActive()) {
+    const TimeDuration timeout = TimeDuration::FromSeconds(45);
+    VRManager* vm = VRManager::Get();
+    TimeStamp activeTime(vm->GetLastVRListenerThreadActiveTime());
+
+    // Shutdown VR listener thread when no VR content in 45 sec. Shutdown threads
+    // only allows to be run at the main thread.
+    if (!activeTime.IsNull() && ((aCompositeTimestamp - activeTime) > timeout)) {
+      RefPtr<Runnable> runnable = NewRunnableMethod(
+        "layers::CompositorVsyncScheduler::ShutdownVRListenerThread",
+        this, &CompositorVsyncScheduler::ShutdownVRListenerThread);
+      NS_DispatchToMainThread(runnable.forget());
+    } else {
+      RefPtr<CancelableRunnable> task = NewCancelableRunnableMethod<TimeStamp>(
+        "layers::CompositorVsyncScheduler::DispatchVREvents",
+        this,
+        &CompositorVsyncScheduler::DispatchVREvents,
+        aCompositeTimestamp);
+      mCurrentVRListenerTask = task;
+      MOZ_ASSERT(VRListenerThreadHolder::Loop());
+      VRListenerThreadHolder::Loop()->PostTask(Move(task.forget()));
+    }
   }
 }
 
 void
+CompositorVsyncScheduler::ShutdownVRListenerThread()
+{
+  VRListenerThreadHolder::Shutdown();
+}
+
+void
 CompositorVsyncScheduler::ScheduleComposition()
 {
   MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
   if (!mVsyncObserver) {
     // Destroy was already called on this object.
     return;
   }
 
--- a/gfx/layers/ipc/CompositorVsyncScheduler.h
+++ b/gfx/layers/ipc/CompositorVsyncScheduler.h
@@ -78,16 +78,17 @@ private:
   virtual ~CompositorVsyncScheduler();
 
   void NotifyCompositeTaskExecuted();
   void ObserveVsync();
   void UnobserveVsync();
   void DispatchTouchEvents(TimeStamp aVsyncTimestamp);
   void DispatchVREvents(TimeStamp aVsyncTimestamp);
   void CancelCurrentSetNeedsCompositeTask();
+  void ShutdownVRListenerThread();
 
   class Observer final : public VsyncObserver
   {
   public:
     explicit Observer(CompositorVsyncScheduler* aOwner);
     virtual bool NotifyVsync(TimeStamp aVsyncTimestamp) override;
     void Destroy();
   private:
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -1039,17 +1039,16 @@ gfxPlatform::InitLayersIPC()
       layers::PaintThread::Start();
     }
   } else if (XRE_IsParentProcess()) {
     if (gfxVars::UseWebRender()) {
       wr::RenderThread::Start();
     }
 
     layers::CompositorThreadHolder::Start();
-    gfx::VRListenerThreadHolder::Start();
   }
 }
 
 /* static */ void
 gfxPlatform::ShutdownLayersIPC()
 {
     if (!sLayersIPCIsUp) {
       return;
--- a/gfx/vr/VRThread.cpp
+++ b/gfx/vr/VRThread.cpp
@@ -8,16 +8,17 @@
 #include "VRThread.h"
 #include "nsThreadUtils.h"
 
 namespace mozilla {
 
 namespace gfx {
 
 static StaticRefPtr<VRListenerThreadHolder> sVRListenerThreadHolder;
+static TimeStamp sStartTime;
 static bool sFinishedVRListenerShutDown = false;
 
 VRListenerThreadHolder* GetVRListenerThreadHolder()
 {
   return sVRListenerThreadHolder;
 }
 
 base::Thread*
@@ -89,34 +90,45 @@ VRListenerThreadHolder::CreateThread()
 
 void
 VRListenerThreadHolder::Start()
 {
   MOZ_ASSERT(NS_IsMainThread(), "Should be on the main thread!");
   MOZ_ASSERT(!sVRListenerThreadHolder, "The VR listener thread has already been started!");
 
   sVRListenerThreadHolder = new VRListenerThreadHolder();
+  sStartTime = TimeStamp::Now();
+}
+
+TimeStamp
+VRListenerThreadHolder::GetStartTime()
+{
+  return sStartTime;
 }
 
 void
 VRListenerThreadHolder::Shutdown()
 {
+  if (!IsActive()) {
+    return;
+  }
+
   MOZ_ASSERT(NS_IsMainThread(), "Should be on the main thread!");
   MOZ_ASSERT(sVRListenerThreadHolder, "The VR listener thread has already been shut down!");
 
   sVRListenerThreadHolder = nullptr;
 
   SpinEventLoopUntil([&]() { return sFinishedVRListenerShutDown; });
 }
 
 /* static */ bool
 VRListenerThreadHolder::IsInVRListenerThread()
 {
   return VRListenerThread() &&
-		 VRListenerThread()->thread_id() == PlatformThread::CurrentId();
+         VRListenerThread()->thread_id() == PlatformThread::CurrentId();
 }
 
 } // namespace gfx
 } // namespace mozilla
 
 bool
 NS_IsInVRListenerThread()
 {
--- a/gfx/vr/VRThread.h
+++ b/gfx/vr/VRThread.h
@@ -22,31 +22,32 @@ public:
 
   base::Thread* GetThread() const {
     return mThread;
   }
 
   static VRListenerThreadHolder* GetSingleton();
 
   static bool IsActive() {
-    return !!GetSingleton();
+    return !!GetSingleton() && !!Loop();
   }
 
   static void Start();
   static void Shutdown();
   static MessageLoop* Loop();
   static bool IsInVRListenerThread();
+  static TimeStamp GetStartTime();
 
 private:
   ~VRListenerThreadHolder();
 
-  base::Thread* const mThread;
-
   static base::Thread* CreateThread();
   static void DestroyThread(base::Thread* aThread);
+
+  base::Thread* const mThread;
 };
 
 base::Thread* VRListenerThread();
 
 } // namespace gfx
 } // namespace mozilla
 
 #endif // GFX_VR_THREAD_H
\ No newline at end of file