Bug 1351048 - Do not load VR libraries until necessary, Oculus cleanup draft
authorKearwood Gilbert <kgilbert@mozilla.com>
Thu, 30 Mar 2017 09:35:49 -0400
changeset 560024 40ab7a585e7dadbc9a6cb89e47e24ebfe6b8b262
parent 559749 b1364675bdf5dffe63fd60373034293de0b513d5
child 623578 aea039a4829329b5719503c098ab4dca1ffcc47e
push id53291
push userbmo:kgilbert@mozilla.com
push dateMon, 10 Apr 2017 23:30:49 +0000
bugs1351048
milestone55.0a1
Bug 1351048 - Do not load VR libraries until necessary, Oculus cleanup - I have refactored the Oculus and OpenVR interfaces in gfx/vr so that initialization of the VR libraries only happens once a WebVR site is detected. - The Oculus interface has been cleaned up and updated to unload the Oculus runtime library when not in use. - The browser can now re-connect to Oculus home if it was restarted, without restarting the browser. - We no longer submit a black frame at the end of VR presentation, as this appears to be handled by the latest Oculus runtime automatically. - As we only hold on to the Oculus runtime when needed, this should reduce the likelihood of the GPU process being killed by the Oculus software updater. MozReview-Commit-ID: AyWeD4CxXLD
dom/base/Navigator.cpp
gfx/vr/VRManager.cpp
gfx/vr/VRManager.h
gfx/vr/gfxVR.h
gfx/vr/gfxVROSVR.cpp
gfx/vr/gfxVROSVR.h
gfx/vr/gfxVROculus.cpp
gfx/vr/gfxVROculus.h
gfx/vr/gfxVROpenVR.cpp
gfx/vr/gfxVROpenVR.h
gfx/vr/gfxVRPuppet.cpp
gfx/vr/gfxVRPuppet.h
gfx/vr/ovr_capi_dynamic.h
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -1569,16 +1569,20 @@ void
 Navigator::NotifyActiveVRDisplaysChanged()
 {
   NavigatorBinding::ClearCachedActiveVRDisplaysValue(this);
 }
 
 VRServiceTest*
 Navigator::RequestVRServiceTest()
 {
+  // Ensure that the Mock VR devices are not released prematurely
+  nsGlobalWindow* win = nsGlobalWindow::Cast(mWindow);
+  win->NotifyVREventListenerAdded();
+
   if (!mVRServiceTest) {
     mVRServiceTest = VRServiceTest::CreateTestService(mWindow);
   }
   return mVRServiceTest;
 }
 
 //*****************************************************************************
 //    Navigator::nsIMozNavigatorNetwork
--- a/gfx/vr/VRManager.cpp
+++ b/gfx/vr/VRManager.cpp
@@ -112,22 +112,28 @@ VRManager::Destroy()
   for (uint32_t i = 0; i < mManagers.Length(); ++i) {
     mManagers[i]->Destroy();
   }
 
   mInitialized = false;
 }
 
 void
+VRManager::Shutdown()
+{
+  mVRDisplays.Clear();
+  mVRControllers.Clear();
+  for (uint32_t i = 0; i < mManagers.Length(); ++i) {
+    mManagers[i]->Shutdown();
+  }
+}
+
+void
 VRManager::Init()
 {
-  for (uint32_t i = 0; i < mManagers.Length(); ++i) {
-    mManagers[i]->Init();
-  }
-
   mInitialized = true;
 }
 
 /* static */VRManager*
 VRManager::Get()
 {
   MOZ_ASSERT(sVRManagerSingleton != nullptr);
 
@@ -154,29 +160,33 @@ VRManager::RemoveVRManagerParent(VRManag
 
 void
 VRManager::NotifyVsync(const TimeStamp& aVsyncTimestamp)
 {
   const double kVRDisplayRefreshMaxDuration = 5000; // milliseconds
 
   bool bHaveEventListener = false;
   bool bHaveControllerListener = false;
+  bool bHaveActiveDisplay = false;
 
   for (auto iter = mVRManagerParents.Iter(); !iter.Done(); iter.Next()) {
     VRManagerParent *vmp = iter.Get()->GetKey();
     if (mVRDisplays.Count()) {
       Unused << vmp->SendNotifyVSync();
     }
     bHaveEventListener |= vmp->HaveEventListener();
     bHaveControllerListener |= vmp->HaveControllerListener();
   }
 
   for (auto iter = mVRDisplays.Iter(); !iter.Done(); iter.Next()) {
     gfx::VRDisplayHost* display = iter.UserData();
     display->NotifyVSync();
+    if (display->GetDisplayInfo().GetIsPresenting()) {
+      bHaveActiveDisplay = true;
+    }
   }
 
   if (bHaveEventListener) {
     // If content has set an EventHandler to be notified of VR display events
     // we must continually refresh the VR display enumeration to check
     // for events that we must fire such as Window.onvrdisplayconnect
     // Note that enumeration itself may activate display hardware, such
     // as Oculus, so we only do this when we know we are displaying content
@@ -204,16 +214,21 @@ VRManager::NotifyVsync(const TimeStamp& 
     if (bHaveControllerListener) {
       for (const auto& manager: mManagers) {
         if (!manager->GetIsPresenting()) {
           manager->HandleInput();
         }
       }
     }
   }
+
+  if (!bHaveEventListener && !bHaveControllerListener && !bHaveActiveDisplay) {
+    // Shut down the VR devices when not in use
+    Shutdown();
+  }
 }
 
 void
 VRManager::NotifyVRVsync(const uint32_t& aDisplayID)
 {
   for (const auto& manager: mManagers) {
     if (manager->GetIsPresenting()) {
       manager->HandleInput();
@@ -401,17 +416,16 @@ void
 VRManager::CreateVRTestSystem()
 {
   if (mVRTestSystemCreated) {
     return;
   }
 
   RefPtr<VRSystemManager> mgr = VRSystemManagerPuppet::Create();
   if (mgr) {
-    mgr->Init();
     mManagers.AppendElement(mgr);
     mVRTestSystemCreated = true;
   }
 }
 
 template<class T>
 void
 VRManager::NotifyGamepadChange(const T& aInfo)
--- a/gfx/vr/VRManager.h
+++ b/gfx/vr/VRManager.h
@@ -58,16 +58,17 @@ protected:
   VRManager();
   ~VRManager();
 
 private:
   RefPtr<layers::TextureHost> mLastFrame;
 
   void Init();
   void Destroy();
+  void Shutdown();
 
   void DispatchVRDisplayInfoUpdate();
   void RefreshVRControllers();
 
   typedef nsTHashtable<nsRefPtrHashKey<VRManagerParent>> VRManagerParentSet;
   VRManagerParentSet mVRManagerParents;
 
   typedef nsTArray<RefPtr<VRSystemManager>> VRSystemManagerArray;
--- a/gfx/vr/gfxVR.h
+++ b/gfx/vr/gfxVR.h
@@ -246,18 +246,18 @@ public:
   static uint32_t AllocateDisplayID();
 
 protected:
   static Atomic<uint32_t> sDisplayBase;
 
 public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VRSystemManager)
 
-  virtual bool Init() = 0;
   virtual void Destroy() = 0;
+  virtual void Shutdown() = 0;
   virtual void GetHMDs(nsTArray<RefPtr<VRDisplayHost>>& aHMDResult) = 0;
   virtual bool GetIsPresenting() = 0;
   virtual void HandleInput() = 0;
   virtual void GetControllers(nsTArray<RefPtr<VRControllerHost>>& aControllerResult) = 0;
   virtual void ScanForControllers() = 0;
   virtual void RemoveControllers() = 0;
   virtual void VibrateHaptic(uint32_t aControllerIdx, uint32_t aHapticIndex,
                              double aIntensity, double aDuration, uint32_t aPromiseID) = 0;
--- a/gfx/vr/gfxVROSVR.cpp
+++ b/gfx/vr/gfxVROSVR.cpp
@@ -489,16 +489,22 @@ VRSystemManagerOSVR::Init()
   }
 
   return mOSVRInitialized;
 }
 
 void
 VRSystemManagerOSVR::Destroy()
 {
+  Shutdown();
+}
+
+void
+VRSystemManagerOSVR::Shutdown()
+{
   if (mOSVRInitialized) {
     MOZ_ASSERT(NS_GetCurrentThread() == mOSVRThread);
     mOSVRThread = nullptr;
     mHMDInfo = nullptr;
     mOSVRInitialized = false;
   }
   // client context may not have been initialized
   if (m_ctx) {
@@ -510,17 +516,17 @@ VRSystemManagerOSVR::Destroy()
 }
 
 void
 VRSystemManagerOSVR::GetHMDs(nsTArray<RefPtr<VRDisplayHost>>& aHMDResult)
 {
   // make sure context, interface and display are initialized
   CheckOSVRStatus();
 
-  if (!mOSVRInitialized) {
+  if (!Init()) {
     return;
   }
 
   mHMDInfo = new VRDisplayOSVR(&m_ctx, &m_iface, &m_display);
 
   if (mHMDInfo) {
     aHMDResult.AppendElement(mHMDInfo);
   }
--- a/gfx/vr/gfxVROSVR.h
+++ b/gfx/vr/gfxVROSVR.h
@@ -59,18 +59,18 @@ protected:
 };
 
 } // namespace impl
 
 class VRSystemManagerOSVR : public VRSystemManager
 {
 public:
   static already_AddRefed<VRSystemManagerOSVR> Create();
-  virtual bool Init() override;
   virtual void Destroy() override;
+  virtual void Shutdown() override;
   virtual void GetHMDs(nsTArray<RefPtr<VRDisplayHost>>& aHMDResult) override;
   virtual bool GetIsPresenting() override;
   virtual void HandleInput() override;
   virtual void GetControllers(nsTArray<RefPtr<VRControllerHost>>&
                               aControllerResult) override;
   virtual void ScanForControllers() override;
   virtual void RemoveControllers() override;
   virtual void VibrateHaptic(uint32_t aControllerIdx, uint32_t aHapticIndex,
@@ -84,16 +84,18 @@ protected:
     , mDisplayConfigInitialized(false)
     , mInterfaceInitialized(false)
     , m_ctx(nullptr)
     , m_iface(nullptr)
     , m_display(nullptr)
   {
   }
 
+  bool Init();
+
   RefPtr<impl::VRDisplayOSVR> mHMDInfo;
   bool mOSVRInitialized;
   bool mClientContextInitialized;
   bool mDisplayConfigInitialized;
   bool mInterfaceInitialized;
   RefPtr<nsIThread> mOSVRThread;
 
   OSVR_ClientContext m_ctx;
--- a/gfx/vr/gfxVROculus.cpp
+++ b/gfx/vr/gfxVROculus.cpp
@@ -52,17 +52,16 @@ extern ShaderBytes sLayerQuadVS;
 using namespace mozilla;
 using namespace mozilla::gfx;
 using namespace mozilla::gfx::impl;
 using namespace mozilla::layers;
 using namespace mozilla::dom;
 
 namespace {
 
-#ifdef OVR_CAPI_LIMITED_MOZILLA
 static pfn_ovr_Initialize ovr_Initialize = nullptr;
 static pfn_ovr_Shutdown ovr_Shutdown = nullptr;
 static pfn_ovr_GetLastErrorInfo ovr_GetLastErrorInfo = nullptr;
 static pfn_ovr_GetVersionString ovr_GetVersionString = nullptr;
 static pfn_ovr_TraceMessage ovr_TraceMessage = nullptr;
 static pfn_ovr_GetHmdDesc ovr_GetHmdDesc = nullptr;
 static pfn_ovr_GetTrackerCount ovr_GetTrackerCount = nullptr;
 static pfn_ovr_GetTrackerDesc ovr_GetTrackerDesc = nullptr;
@@ -143,73 +142,61 @@ enum class OculusRightControllerButtonTy
   NumButtonType
 };
 
 static const uint32_t kNumOculusButton = static_cast<uint32_t>
                                          (OculusLeftControllerButtonType::
                                          NumButtonType);
 static const uint32_t kNumOculusHaptcs = 1;
 
+ovrFovPort
+ToFovPort(const VRFieldOfView& aFOV)
+{
+  ovrFovPort fovPort;
+  fovPort.LeftTan = tan(aFOV.leftDegrees * M_PI / 180.0);
+  fovPort.RightTan = tan(aFOV.rightDegrees * M_PI / 180.0);
+  fovPort.UpTan = tan(aFOV.upDegrees * M_PI / 180.0);
+  fovPort.DownTan = tan(aFOV.downDegrees * M_PI / 180.0);
+  return fovPort;
+}
 
-static bool
-InitializeOculusCAPI()
+VRFieldOfView
+FromFovPort(const ovrFovPort& aFOV)
 {
-  static PRLibrary *ovrlib = nullptr;
+  VRFieldOfView fovInfo;
+  fovInfo.leftDegrees = atan(aFOV.LeftTan) * 180.0 / M_PI;
+  fovInfo.rightDegrees = atan(aFOV.RightTan) * 180.0 / M_PI;
+  fovInfo.upDegrees = atan(aFOV.UpTan) * 180.0 / M_PI;
+  fovInfo.downDegrees = atan(aFOV.DownTan) * 180.0 / M_PI;
+  return fovInfo;
+}
 
-  if (!ovrlib) {
+} // namespace
+
+bool
+VRSystemManagerOculus::LoadOvrLib()
+{
+  if (!mOvrLib) {
     nsTArray<nsCString> libSearchPaths;
     nsCString libName;
     nsCString searchPath;
 
 #if defined(_WIN32)
     static const char dirSep = '\\';
-#else
-    static const char dirSep = '/';
-#endif
-
-#if defined(_WIN32)
     static const int pathLen = 260;
     searchPath.SetCapacity(pathLen);
     int realLen = ::GetSystemDirectoryA(searchPath.BeginWriting(), pathLen);
     if (realLen != 0 && realLen < pathLen) {
       searchPath.SetLength(realLen);
       libSearchPaths.AppendElement(searchPath);
     }
     libName.AppendPrintf("LibOVRRT%d_%d.dll", BUILD_BITS, OVR_PRODUCT_VERSION);
-#elif defined(__APPLE__)
-    searchPath.Truncate();
-    searchPath.AppendPrintf("/Library/Frameworks/LibOVRRT_%d.framework/Versions/%d", OVR_PRODUCT_VERSION, OVR_MAJOR_VERSION);
-    libSearchPaths.AppendElement(searchPath);
-
-    if (PR_GetEnv("HOME")) {
-      searchPath.Truncate();
-      searchPath.AppendPrintf("%s/Library/Frameworks/LibOVRRT_%d.framework/Versions/%d", PR_GetEnv("HOME"), OVR_PRODUCT_VERSION, OVR_MAJOR_VERSION);
-      libSearchPaths.AppendElement(searchPath);
-    }
-    // The following will match the va_list overload of AppendPrintf if the product version is 0
-    // That's bad times.
-    //libName.AppendPrintf("LibOVRRT_%d", OVR_PRODUCT_VERSION);
-    libName.Append("LibOVRRT_");
-    libName.AppendInt(OVR_PRODUCT_VERSION);
 #else
-    libSearchPaths.AppendElement(nsCString("/usr/local/lib"));
-    libSearchPaths.AppendElement(nsCString("/usr/lib"));
-    libName.AppendPrintf("libOVRRT%d_%d.so.%d", BUILD_BITS, OVR_PRODUCT_VERSION, OVR_MAJOR_VERSION);
+#error "Unsupported platform!"
 #endif
-    
-    // If the pref is present, we override libName
-    nsAdoptingCString prefLibPath = mozilla::Preferences::GetCString("dom.vr.ovr_lib_path");
-    if (prefLibPath && prefLibPath.get()) {
-      libSearchPaths.InsertElementsAt(0, 1, prefLibPath);
-    }
-
-    nsAdoptingCString prefLibName = mozilla::Preferences::GetCString("dom.vr.ovr_lib_name");
-    if (prefLibName && prefLibName.get()) {
-      libName.Assign(prefLibName);
-    }
 
     // search the path/module dir
     libSearchPaths.InsertElementsAt(0, 1, nsCString());
 
     // If the env var is present, we override libName
     if (PR_GetEnv("OVR_LIB_PATH")) {
       searchPath = PR_GetEnv("OVR_LIB_PATH");
       libSearchPaths.InsertElementsAt(0, 1, searchPath);
@@ -223,32 +210,29 @@ InitializeOculusCAPI()
       nsCString& libPath = libSearchPaths[i];
       nsCString fullName;
       if (libPath.Length() == 0) {
         fullName.Assign(libName);
       } else {
         fullName.AppendPrintf("%s%c%s", libPath.BeginReading(), dirSep, libName.BeginReading());
       }
 
-      ovrlib = PR_LoadLibrary(fullName.BeginReading());
-      if (ovrlib)
+      mOvrLib = PR_LoadLibrary(fullName.BeginReading());
+      if (mOvrLib) {
         break;
+      }
     }
 
-    if (!ovrlib) {
+    if (!mOvrLib) {
       return false;
     }
   }
 
-  // was it already initialized?
-  if (ovr_Initialize)
-    return true;
-
 #define REQUIRE_FUNCTION(_x) do { \
-    *(void **)&_x = (void *) PR_FindSymbol(ovrlib, #_x);                \
+    *(void **)&_x = (void *) PR_FindSymbol(mOvrLib, #_x);                \
     if (!_x) { printf_stderr(#_x " symbol missing\n"); goto fail; }       \
   } while (0)
 
   REQUIRE_FUNCTION(ovr_Initialize);
   REQUIRE_FUNCTION(ovr_Shutdown);
   REQUIRE_FUNCTION(ovr_GetLastErrorInfo);
   REQUIRE_FUNCTION(ovr_GetVersionString);
   REQUIRE_FUNCTION(ovr_TraceMessage);
@@ -305,53 +289,30 @@ InitializeOculusCAPI()
   REQUIRE_FUNCTION(ovr_GetMirrorTextureBufferGL);
 
 #undef REQUIRE_FUNCTION
 
   return true;
 
  fail:
   ovr_Initialize = nullptr;
+  PR_UnloadLibrary(mOvrLib);
+  mOvrLib = nullptr;
   return false;
 }
 
-#else
-#include <OVR_Version.h>
-// we're statically linked; it's available
-static bool InitializeOculusCAPI()
-{
-  return true;
-}
-
-#endif
-
-ovrFovPort
-ToFovPort(const VRFieldOfView& aFOV)
+void
+VRSystemManagerOculus::UnloadOvrLib()
 {
-  ovrFovPort fovPort;
-  fovPort.LeftTan = tan(aFOV.leftDegrees * M_PI / 180.0);
-  fovPort.RightTan = tan(aFOV.rightDegrees * M_PI / 180.0);
-  fovPort.UpTan = tan(aFOV.upDegrees * M_PI / 180.0);
-  fovPort.DownTan = tan(aFOV.downDegrees * M_PI / 180.0);
-  return fovPort;
+  if (mOvrLib) {
+    PR_UnloadLibrary(mOvrLib);
+    mOvrLib = nullptr;
+  }
 }
 
-VRFieldOfView
-FromFovPort(const ovrFovPort& aFOV)
-{
-  VRFieldOfView fovInfo;
-  fovInfo.leftDegrees = atan(aFOV.LeftTan) * 180.0 / M_PI;
-  fovInfo.rightDegrees = atan(aFOV.RightTan) * 180.0 / M_PI;
-  fovInfo.upDegrees = atan(aFOV.UpTan) * 180.0 / M_PI;
-  fovInfo.downDegrees = atan(aFOV.DownTan) * 180.0 / M_PI;
-  return fovInfo;
-}
-
-} // namespace
-
 VRDisplayOculus::VRDisplayOculus(ovrSession aSession)
   : VRDisplayHost(VRDeviceType::Oculus)
   , mSession(aSession)
   , mTextureSet(nullptr)
   , mQuadVS(nullptr)
   , mQuadPS(nullptr)
   , mLinearSamplerState(nullptr)
   , mVSConstantBuffer(nullptr)
@@ -679,18 +640,16 @@ VRDisplayOculus::StartPresentation()
 void
 VRDisplayOculus::StopPresentation()
 {
   if (!mIsPresenting) {
     return;
   }
   mIsPresenting = false;
 
-  ovr_SubmitFrame(mSession, 0, nullptr, nullptr, 0);
-
   if (mTextureSet) {
     ovr_DestroyTextureSwapChain(mSession, mTextureSet);
     mTextureSet = nullptr;
   }
 }
 
 already_AddRefed<CompositingRenderTargetD3D11>
 VRDisplayOculus::GetNextRenderTarget()
@@ -1103,67 +1062,77 @@ VRSystemManagerOculus::Create()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (!gfxPrefs::VREnabled() || !gfxPrefs::VROculusEnabled())
   {
     return nullptr;
   }
 
-  if (!InitializeOculusCAPI()) {
-    return nullptr;
-  }
-
   RefPtr<VRSystemManagerOculus> manager = new VRSystemManagerOculus();
   return manager.forget();
 }
 
 bool
-VRSystemManagerOculus::Init()
+VRSystemManagerOculus::Startup()
 {
-  if (!mOculusInitialized) {
-    nsIThread* thread = nullptr;
-    NS_GetCurrentThread(&thread);
-    mOculusThread = already_AddRefed<nsIThread>(thread);
+  if (mStarted) {
+    return true;
+  }
 
-    ovrInitParams params;
-    memset(&params, 0, sizeof(params));
-    params.Flags = ovrInit_RequestVersion;
-    params.RequestedMinorVersion = OVR_MINOR_VERSION;
-    params.LogCallback = nullptr;
-    params.ConnectionTimeoutMS = 0;
-
-    ovrResult orv = ovr_Initialize(&params);
-
-    if (orv == ovrSuccess) {
-      mOculusInitialized = true;
-    }
+  if (!LoadOvrLib()) {
+    return false;
   }
 
-  return mOculusInitialized;
+  nsIThread* thread = nullptr;
+  NS_GetCurrentThread(&thread);
+  mOculusThread = already_AddRefed<nsIThread>(thread);
+
+  ovrInitParams params;
+  memset(&params, 0, sizeof(params));
+  params.Flags = ovrInit_RequestVersion;
+  params.RequestedMinorVersion = OVR_MINOR_VERSION;
+  params.LogCallback = nullptr;
+  params.ConnectionTimeoutMS = 0;
+
+  ovrResult orv = ovr_Initialize(&params);
+
+  if (orv == ovrSuccess) {
+    mStarted = true;
+  }
+
+  return mStarted;
 }
 
 void
 VRSystemManagerOculus::Destroy()
 {
-  if (mOculusInitialized) {
+  Shutdown();
+}
+
+void
+VRSystemManagerOculus::Shutdown()
+{
+  if (mStarted) {
+    RemoveControllers();
     MOZ_ASSERT(NS_GetCurrentThread() == mOculusThread);
     mOculusThread = nullptr;
     mSession = nullptr;
     mHMDInfo = nullptr;
 
     ovr_Shutdown();
-    mOculusInitialized = false;
+    UnloadOvrLib();
+    mStarted = false;
   }
 }
 
 void
 VRSystemManagerOculus::GetHMDs(nsTArray<RefPtr<VRDisplayHost>>& aHMDResult)
 {
-  if (!mOculusInitialized) {
+  if (!Startup()) {
     return;
   }
 
   // ovr_Create can be slow when no HMD is present and we wish
   // to keep the same oculus session when possible, so we detect
   // presence of an HMD with ovr_GetHmdDesc before calling ovr_Create
   ovrHmdDesc desc = ovr_GetHmdDesc(NULL);
   if (desc.Type == ovrHmd_None) {
@@ -1429,20 +1398,16 @@ VRSystemManagerOculus::StopVibrateHaptic
 
   controller->StopVibrateHaptic();
 }
 
 void
 VRSystemManagerOculus::GetControllers(nsTArray<RefPtr<VRControllerHost>>&
                                       aControllerResult)
 {
-  if (!mOculusInitialized) {
-    return;
-  }
-
   aControllerResult.Clear();
   for (uint32_t i = 0; i < mOculusController.Length(); ++i) {
     aControllerResult.AppendElement(mOculusController[i]);
   }
 }
 
 void
 VRSystemManagerOculus::ScanForControllers()
--- a/gfx/vr/gfxVROculus.h
+++ b/gfx/vr/gfxVROculus.h
@@ -131,52 +131,56 @@ private:
 };
 
 } // namespace impl
 
 class VRSystemManagerOculus : public VRSystemManager
 {
 public:
   static already_AddRefed<VRSystemManagerOculus> Create();
-  virtual bool Init() override;
   virtual void Destroy() override;
+  virtual void Shutdown() override;
   virtual void GetHMDs(nsTArray<RefPtr<VRDisplayHost> >& aHMDResult) override;
   virtual bool GetIsPresenting() override;
   virtual void HandleInput() override;
   virtual void GetControllers(nsTArray<RefPtr<VRControllerHost>>&
                               aControllerResult) override;
   virtual void ScanForControllers() override;
   virtual void RemoveControllers() override;
   virtual void VibrateHaptic(uint32_t aControllerIdx, uint32_t aHapticIndex,
                              double aIntensity, double aDuration, uint32_t aPromiseID) override;
   virtual void StopVibrateHaptic(uint32_t aControllerIdx) override;
 
 protected:
   VRSystemManagerOculus()
-    : mSession(nullptr), mOculusInitialized(false)
+    : mOvrLib(nullptr), mSession(nullptr), mStarted(false)
   { }
 
+  bool Startup();
+  bool LoadOvrLib();
+  void UnloadOvrLib();
+
 private:
   void HandleButtonPress(uint32_t aControllerIdx,
                          uint32_t aButton,
                          uint64_t aButtonMask,
                          uint64_t aButtonPressed);
   void HandleAxisMove(uint32_t aControllerIdx, uint32_t aAxis,
                       float aValue);
   void HandlePoseTracking(uint32_t aControllerIdx,
                           const dom::GamepadPoseState& aPose,
                           VRControllerHost* aController);
   void HandleTriggerPress(uint32_t aControllerIdx, uint32_t aButton,
                           float aValue);
   void HandleTouchEvent(uint32_t aControllerIdx, uint32_t aButton,
                         uint64_t aTouchMask, uint64_t aTouched);
-
+  PRLibrary* mOvrLib;
   RefPtr<impl::VRDisplayOculus> mHMDInfo;
   nsTArray<RefPtr<impl::VRControllerOculus>> mOculusController;
   RefPtr<nsIThread> mOculusThread;
   ovrSession mSession;
-  bool mOculusInitialized;
+  bool mStarted;
 };
 
 } // namespace gfx
 } // namespace mozilla
 
 #endif /* GFX_VR_OCULUS_H */
--- a/gfx/vr/gfxVROpenVR.cpp
+++ b/gfx/vr/gfxVROpenVR.cpp
@@ -537,70 +537,59 @@ VRControllerOpenVR::VibrateHaptic(vr::IV
 void
 VRControllerOpenVR::StopVibrateHaptic()
 {
   mIsVibrateStopped = true;
 }
 
 VRSystemManagerOpenVR::VRSystemManagerOpenVR()
   : mVRSystem(nullptr)
-  , mOpenVRInstalled(false)
 {
 }
 
 /*static*/ already_AddRefed<VRSystemManagerOpenVR>
 VRSystemManagerOpenVR::Create()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (!gfxPrefs::VREnabled() || !gfxPrefs::VROpenVREnabled()) {
     return nullptr;
   }
 
   if (!LoadOpenVRRuntime()) {
     return nullptr;
   }
 
+  if (!vr_IsRuntimeInstalled()) {
+    return nullptr;
+  }
+
   RefPtr<VRSystemManagerOpenVR> manager = new VRSystemManagerOpenVR();
   return manager.forget();
 }
 
-bool
-VRSystemManagerOpenVR::Init()
-{
-  if (mOpenVRInstalled)
-    return true;
-
-  if (!vr_IsRuntimeInstalled())
-    return false;
-
-  mOpenVRInstalled = true;
-  return true;
-}
-
 void
 VRSystemManagerOpenVR::Destroy()
 {
-  if (mOpenVRInstalled) {
-    if (mOpenVRHMD) {
-      mOpenVRHMD = nullptr;
-    }
-    RemoveControllers();
-    mVRSystem = nullptr;
-    mOpenVRInstalled = false;
+  Shutdown();
+}
+
+void
+VRSystemManagerOpenVR::Shutdown()
+{
+  if (mOpenVRHMD) {
+    mOpenVRHMD = nullptr;
   }
+  RemoveControllers();
+  mVRSystem = nullptr;
 }
 
 void
 VRSystemManagerOpenVR::GetHMDs(nsTArray<RefPtr<VRDisplayHost>>& aHMDResult)
 {
-  if (!mOpenVRInstalled) {
-    return;
-  }
-
   if (!vr_IsHmdPresent()) {
     if (mOpenVRHMD) {
       mOpenVRHMD = nullptr;
     }
   } else if (mOpenVRHMD == nullptr) {
     ::vr::HmdError err;
 
     vr_InitInternal(&err, ::vr::EVRApplicationType::VRApplication_Scene);
@@ -893,20 +882,16 @@ VRSystemManagerOpenVR::StopVibrateHaptic
   MOZ_ASSERT(controller);
 
   controller->StopVibrateHaptic();
 }
 
 void
 VRSystemManagerOpenVR::GetControllers(nsTArray<RefPtr<VRControllerHost>>& aControllerResult)
 {
-  if (!mOpenVRInstalled) {
-    return;
-  }
-
   aControllerResult.Clear();
   for (uint32_t i = 0; i < mOpenVRController.Length(); ++i) {
     aControllerResult.AppendElement(mOpenVRController[i]);
   }
 }
 
 void
 VRSystemManagerOpenVR::ScanForControllers()
--- a/gfx/vr/gfxVROpenVR.h
+++ b/gfx/vr/gfxVROpenVR.h
@@ -106,18 +106,18 @@ private:
 
 } // namespace impl
 
 class VRSystemManagerOpenVR : public VRSystemManager
 {
 public:
   static already_AddRefed<VRSystemManagerOpenVR> Create();
 
-  virtual bool Init() override;
   virtual void Destroy() override;
+  virtual void Shutdown() override;
   virtual void GetHMDs(nsTArray<RefPtr<VRDisplayHost> >& aHMDResult) override;
   virtual bool GetIsPresenting() override;
   virtual void HandleInput() override;
   virtual void GetControllers(nsTArray<RefPtr<VRControllerHost>>&
                               aControllerResult) override;
   virtual void ScanForControllers() override;
   virtual void RemoveControllers() override;
   virtual void VibrateHaptic(uint32_t aControllerIdx,
@@ -145,16 +145,15 @@ private:
   void HandlePoseTracking(uint32_t aControllerIdx,
                           const dom::GamepadPoseState& aPose,
                           VRControllerHost* aController);
 
   // there can only be one
   RefPtr<impl::VRDisplayOpenVR> mOpenVRHMD;
   nsTArray<RefPtr<impl::VRControllerOpenVR>> mOpenVRController;
   vr::IVRSystem *mVRSystem;
-  bool mOpenVRInstalled;
 };
 
 } // namespace gfx
 } // namespace mozilla
 
 
 #endif /* GFX_VR_OPENVR_H */
--- a/gfx/vr/gfxVRPuppet.cpp
+++ b/gfx/vr/gfxVRPuppet.cpp
@@ -318,24 +318,24 @@ VRSystemManagerPuppet::Create()
   if (!gfxPrefs::VREnabled() || !gfxPrefs::VRPuppetEnabled()) {
     return nullptr;
   }
 
   RefPtr<VRSystemManagerPuppet> manager = new VRSystemManagerPuppet();
   return manager.forget();
 }
 
-bool
-VRSystemManagerPuppet::Init()
+void
+VRSystemManagerPuppet::Destroy()
 {
-  return true;
+  Shutdown();
 }
 
 void
-VRSystemManagerPuppet::Destroy()
+VRSystemManagerPuppet::Shutdown()
 {
   mPuppetHMD = nullptr;
 }
 
 void
 VRSystemManagerPuppet::GetHMDs(nsTArray<RefPtr<VRDisplayHost>>& aHMDResult)
 {
   if (mPuppetHMD == nullptr) {
--- a/gfx/vr/gfxVRPuppet.h
+++ b/gfx/vr/gfxVRPuppet.h
@@ -81,18 +81,18 @@ private:
 
 } // namespace impl
 
 class VRSystemManagerPuppet : public VRSystemManager
 {
 public:
   static already_AddRefed<VRSystemManagerPuppet> Create();
 
-  virtual bool Init() override;
   virtual void Destroy() override;
+  virtual void Shutdown() override;
   virtual void GetHMDs(nsTArray<RefPtr<VRDisplayHost>>& aHMDResult) override;
   virtual bool GetIsPresenting() override;
   virtual void HandleInput() override;
   virtual void GetControllers(nsTArray<RefPtr<VRControllerHost>>&
                               aControllerResult) override;
   virtual void ScanForControllers() override;
   virtual void RemoveControllers() override;
   virtual void VibrateHaptic(uint32_t aControllerIdx,
--- a/gfx/vr/ovr_capi_dynamic.h
+++ b/gfx/vr/ovr_capi_dynamic.h
@@ -18,18 +18,16 @@
 #endif
 #define mozilla_ovr_capi_dynamic_h_
 
 #else
 
 #ifndef mozilla_ovr_capi_dynamic_h_
 #define mozilla_ovr_capi_dynamic_h_
 
-#define OVR_CAPI_LIMITED_MOZILLA 1
-
 #ifdef HAVE_64BIT_BUILD
 #define OVR_PTR_SIZE 8
 #define OVR_ON64(x)     x
 #else
 #define OVR_PTR_SIZE 4
 #define OVR_ON64(x)     /**/
 #endif