Bug 1392216 - Part 4: Move drawing black layer commaneds to Compositor thread when stopping presentation; r?kip draft
authorDaosheng Mu <daoshengmu@gmail.com>
Mon, 16 Oct 2017 13:30:46 +0800
changeset 680698 2c91c530d5f506dcfb91db50c256d481f5c80edf
parent 679937 eb17cd9f1b09a9f325c94464c41581a209f8be2c
child 735936 6bcc97055eac5b5b7251b3dde1e279f687b8c1a1
push id84590
push userbmo:dmu@mozilla.com
push dateMon, 16 Oct 2017 05:36:48 +0000
reviewerskip
bugs1392216
milestone58.0a1
Bug 1392216 - Part 4: Move drawing black layer commaneds to Compositor thread when stopping presentation; r?kip MozReview-Commit-ID: 6YmQ9DYp79O
gfx/vr/VRDisplayHost.cpp
gfx/vr/gfxVROculus.cpp
gfx/vr/gfxVROculus.h
--- a/gfx/vr/VRDisplayHost.cpp
+++ b/gfx/vr/VRDisplayHost.cpp
@@ -347,17 +347,17 @@ VRDisplayHost::SubmitFrame(VRLayerParent
    * fallback "watchdog" code in VRDisplayHost::NotifyVSync() will cause
    * frames to continue at a lower refresh rate until frame submission
    * succeeds again.
    */
   VRManager* vm = VRManager::Get();
   MessageLoop* loop = VRListenerThreadHolder::Loop();
 
   loop->PostTask(NewRunnableMethod<const uint32_t>(
-    "gfx::VRLayerParent::SubmitFrame",
+    "gfx::VRManager::NotifyVRVsync",
     vm, &VRManager::NotifyVRVsync, mDisplayInfo.mDisplayID
   ));
 #endif
 }
 
 bool
 VRDisplayHost::CheckClearDisplayInfoDirty()
 {
--- a/gfx/vr/gfxVROculus.cpp
+++ b/gfx/vr/gfxVROculus.cpp
@@ -13,16 +13,17 @@
 #include "prlink.h"
 #include "prenv.h"
 #include "gfxPrefs.h"
 #include "nsString.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/gfx/DeviceManagerDx.h"
+#include "mozilla/layers/CompositorThread.h"
 #include "ipc/VRLayerParent.h"
 
 #include "mozilla/gfx/Quaternion.h"
 
 #include <d3d11.h>
 #include "CompositorD3D11.h"
 #include "TextureD3D11.h"
 
@@ -193,16 +194,17 @@ FromFovPort(const ovrFovPort& aFOV)
 } // namespace
 
 VROculusSession::VROculusSession()
   : mOvrLib(nullptr)
   , mSession(nullptr)
   , mInitFlags((ovrInitFlags)0)
   , mTextureSet(nullptr)
   , mPresenting(false)
+  , mDrawBlack(false)
 {
 }
 
 ovrSession
 VROculusSession::Get()
 {
   MOZ_ASSERT(mSession);
   return mSession;
@@ -316,18 +318,24 @@ VROculusSession::StopLib()
 {
   if (mInitFlags) {
     ovr_Shutdown();
     mInitFlags = (ovrInitFlags)0;
   }
 }
 
 void
-VROculusSession::Refresh()
+VROculusSession::Refresh(bool aForceRefresh)
 {
+  // We are waiting for drawing the black layer command for
+  // Compositor thread. Ignore Refresh() calls from other threads.
+  if (mDrawBlack && !aForceRefresh) {
+    return;
+  }
+
   ovrInitFlags flags = (ovrInitFlags)(ovrInit_RequestVersion | ovrInit_MixedRendering);
   bool bInvisible = true;
   if (mPresenting) {
     bInvisible = false;
   } else if (!mLastPresentationEnd.IsNull()) {
     TimeDuration duration = TimeStamp::Now() - mLastPresentationEnd;
     TimeDuration timeout = TimeDuration::FromMilliseconds(gfxPrefs::VROculusPresentTimeout());
     if (timeout > TimeDuration(0) && duration < timeout) {
@@ -335,21 +343,35 @@ VROculusSession::Refresh()
       // the end of a VR presentation.  Waiting for the configured duraction
       // ensures that the user will not drop to Oculus Home during VR link
       // traversal.
       bInvisible = false;
 
       // While we are waiting for either the timeout or a new presentation,
       // fill the HMD with black / no layers.
       if (mSession && mTextureSet) {
+        if (!aForceRefresh) {
+          // ovr_SubmitFrame is only allowed been run at Compositor thread,
+          // so we post this task to Compositor thread and let it determine
+          // if reloading library.
+          mDrawBlack = true;
+          MessageLoop* loop = layers::CompositorThreadHolder::Loop();
+          loop->PostTask(NewRunnableMethod<bool>(
+            "gfx::VROculusSession::Refresh",
+            this,
+            &VROculusSession::Refresh, true));
+
+          return;
+        }
         ovrLayerEyeFov layer;
         memset(&layer, 0, sizeof(layer));
         layer.Header.Type = ovrLayerType_Disabled;
         ovrLayerHeader *layers = &layer.Header;
         ovr_SubmitFrame(mSession, 0, nullptr, &layers, 1);
+        mDrawBlack = false;
       }
     }
   }
   if (bInvisible) {
     flags = (ovrInitFlags)(flags | ovrInit_Invisible);
   }
 
   if (mInitFlags != flags) {
--- a/gfx/vr/gfxVROculus.h
+++ b/gfx/vr/gfxVROculus.h
@@ -35,17 +35,17 @@ enum class OculusControllerAxisType : ui
 };
 
 class VROculusSession
 {
   NS_INLINE_DECL_REFCOUNTING(VROculusSession);
   friend class VRDisplayOculus;
 public:
   VROculusSession();
-  void Refresh();
+  void Refresh(bool aForceRefresh = false);
   bool IsTrackingReady() const;
   bool IsRenderReady() const;
   ovrSession Get();
   void StartPresentation(const IntSize& aSize);
   void StopPresentation();
   void StopTracking();
   bool IsQuitTimeoutActive();
   already_AddRefed<layers::CompositingRenderTargetD3D11> GetNextRenderTarget();
@@ -60,16 +60,17 @@ private:
   IntSize mPresentationSize;
   RefPtr<ID3D11Device> mDevice;
   // The timestamp of the last time Oculus set ShouldQuit to true.
   TimeStamp mLastShouldQuit;
   // The timestamp of the last ending presentation
   TimeStamp mLastPresentationEnd;
   VRTelemetry mTelemetry;
   bool mPresenting;
+  bool mDrawBlack;
 
   ~VROculusSession();
   void Uninitialize(bool aUnloadLib);
   bool Initialize(ovrInitFlags aFlags);
   bool LoadOvrLib();
   void UnloadOvrLib();
   bool StartSession();
   void StopSession();