Bug 1392217 - Part 2: Spawn a VR submit thread in VRDisplayHost; r?kip draft
authorDaosheng Mu <daoshengmu@gmail.com>
Fri, 17 Nov 2017 16:06:59 +0800
changeset 707301 6f8fc00a733eebec1c1002c12e0141d0484cbb2e
parent 707300 5811a0b9d68ea60ac8b675c0041232487b658d7e
child 742909 3dfc642433c66bb521209b7e056104b2125ca999
push id92081
push userbmo:dmu@mozilla.com
push dateTue, 05 Dec 2017 04:08:07 +0000
reviewerskip
bugs1392217
milestone59.0a1
Bug 1392217 - Part 2: Spawn a VR submit thread in VRDisplayHost; r?kip MozReview-Commit-ID: 5xvTepEFxe0
gfx/vr/VRDisplayHost.cpp
gfx/vr/VRDisplayHost.h
gfx/vr/gfxVROSVR.cpp
gfx/vr/gfxVROculus.cpp
gfx/vr/gfxVROculus.h
gfx/vr/gfxVROpenVR.cpp
gfx/vr/gfxVRPuppet.cpp
gfx/vr/ipc/VRLayerParent.cpp
gfx/vr/ipc/VRLayerParent.h
--- a/gfx/vr/VRDisplayHost.cpp
+++ b/gfx/vr/VRDisplayHost.cpp
@@ -72,16 +72,20 @@ VRDisplayHost::VRDisplayHost(VRDeviceTyp
   mDisplayInfo.mPresentingGroups = 0;
   mDisplayInfo.mGroupMask = kVRGroupContent;
   mDisplayInfo.mFrameId = 0;
   mDisplayInfo.mPresentingGeneration = 0;
 }
 
 VRDisplayHost::~VRDisplayHost()
 {
+  if (mSubmitThread) {
+    mSubmitThread->Shutdown();
+    mSubmitThread = nullptr;
+  }
   MOZ_COUNT_DTOR(VRDisplayHost);
 }
 
 #if defined(XP_WIN)
 bool
 VRDisplayHost::CreateD3DObjects()
 {
   if (!mDevice) {
@@ -248,33 +252,24 @@ VRDisplayHost::NotifyVSync()
   if (bShouldStartFrame) {
     VRManager *vm = VRManager::Get();
     MOZ_ASSERT(vm);
     vm->NotifyVRVsync(mDisplayInfo.mDisplayID);
   }
 }
 
 void
-VRDisplayHost::SubmitFrame(VRLayerParent* aLayer,
-                           const layers::SurfaceDescriptor &aTexture,
-                           uint64_t aFrameId,
-                           const gfx::Rect& aLeftEyeRect,
-                           const gfx::Rect& aRightEyeRect)
+VRDisplayHost::SubmitFrameInternal(const layers::SurfaceDescriptor &aTexture,
+                                   uint64_t aFrameId,
+                                   const gfx::Rect& aLeftEyeRect,
+                                   const gfx::Rect& aRightEyeRect)
 {
+  MOZ_ASSERT(mSubmitThread->GetThread() == NS_GetCurrentThread());
   AUTO_PROFILER_TRACING("VR", "SubmitFrameAtVRDisplayHost");
 
-  if ((mDisplayInfo.mGroupMask & aLayer->GetGroup()) == 0) {
-    // Suppress layers hidden by the group mask
-    return;
-  }
-
-  // Ensure that we only accept the first SubmitFrame call per RAF cycle.
-  if (!mFrameStarted || aFrameId != mDisplayInfo.mFrameId) {
-    return;
-  }
   mFrameStarted = false;
   switch (aTexture.type()) {
 
 #if defined(XP_WIN)
     case SurfaceDescriptor::TSurfaceDescriptorD3D10: {
       if (!CreateD3DObjects()) {
         return;
       }
@@ -331,21 +326,21 @@ VRDisplayHost::SubmitFrame(VRLayerParent
                                      surf->GetDevicePixelHeight());
       if (!SubmitFrame(surf, texSize, aLeftEyeRect, aRightEyeRect)) {
         return;
       }
       break;
     }
 #elif defined(MOZ_ANDROID_GOOGLE_VR)
     case SurfaceDescriptor::TEGLImageDescriptor: {
-       const EGLImageDescriptor& desc = aTexture.get_EGLImageDescriptor();
-       if (!SubmitFrame(&desc, aLeftEyeRect, aRightEyeRect)) {
-         return;
-       }
-       break;
+      const EGLImageDescriptor& desc = aTexture.get_EGLImageDescriptor();
+      if (!SubmitFrame(&desc, aLeftEyeRect, aRightEyeRect)) {
+        return;
+      }
+      break;
     }
 #endif
     default: {
       NS_WARNING("Unsupported SurfaceDescriptor type for VR layer texture");
       return;
     }
   }
 
@@ -366,16 +361,45 @@ VRDisplayHost::SubmitFrame(VRLayerParent
 
   loop->PostTask(NewRunnableMethod<const uint32_t>(
     "gfx::VRManager::NotifyVRVsync",
     vm, &VRManager::NotifyVRVsync, mDisplayInfo.mDisplayID
   ));
 #endif
 }
 
+void
+VRDisplayHost::SubmitFrame(VRLayerParent* aLayer,
+                           const layers::SurfaceDescriptor &aTexture,
+                           uint64_t aFrameId,
+                           const gfx::Rect& aLeftEyeRect,
+                           const gfx::Rect& aRightEyeRect)
+{
+  if (!mSubmitThread) {
+    mSubmitThread = new VRThread(NS_LITERAL_CSTRING("VR_SubmitFrame"));
+  }
+
+  if ((mDisplayInfo.mGroupMask & aLayer->GetGroup()) == 0) {
+    // Suppress layers hidden by the group mask
+    return;
+  }
+
+  // Ensure that we only accept the first SubmitFrame call per RAF cycle.
+  if (!mFrameStarted || aFrameId != mDisplayInfo.mFrameId) {
+    return;
+  }
+
+  mSubmitThread->Start();
+  mSubmitThread->PostTask(
+    NewRunnableMethod<StoreCopyPassByConstLRef<layers::SurfaceDescriptor>, uint64_t,
+      StoreCopyPassByConstLRef<gfx::Rect>, StoreCopyPassByConstLRef<gfx::Rect>>(
+      "gfx::VRDisplayHost::SubmitFrameInternal", this, &VRDisplayHost::SubmitFrameInternal,
+      aTexture, aFrameId, aLeftEyeRect, aRightEyeRect));
+}
+
 bool
 VRDisplayHost::CheckClearDisplayInfoDirty()
 {
   if (mDisplayInfo == mLastUpdateDisplayInfo) {
     return false;
   }
   mLastUpdateDisplayInfo = mDisplayInfo;
   return true;
--- a/gfx/vr/VRDisplayHost.h
+++ b/gfx/vr/VRDisplayHost.h
@@ -22,16 +22,17 @@
 
 #if defined(XP_WIN)
 #include <d3d11_1.h>
 #elif defined(XP_MACOSX)
 class MacIOSurface;
 #endif
 namespace mozilla {
 namespace gfx {
+class VRThread;
 class VRLayerParent;
 
 class VRDisplayHost {
 public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VRDisplayHost)
 
   const VRDisplayInfo& GetDisplayInfo() const { return mDisplayInfo; }
 
@@ -95,17 +96,23 @@ protected:
 
   nsTArray<VRLayerParent *> mLayers;
   // Weak reference to mLayers entries are cleared in
   // VRLayerParent destructor
 
 protected:
   virtual VRHMDSensorState GetSensorState() = 0;
 
+  RefPtr<VRThread> mSubmitThread;
 private:
+  void SubmitFrameInternal(const layers::SurfaceDescriptor& aTexture,
+                           uint64_t aFrameId,
+                           const gfx::Rect& aLeftEyeRect,
+                           const gfx::Rect& aRightEyeRect);
+
   VRDisplayInfo mLastUpdateDisplayInfo;
   TimeStamp mLastFrameStart;
   bool mFrameStarted;
 
 #if defined(XP_WIN)
 protected:
   bool CreateD3DObjects();
   RefPtr<ID3D11Device1> mDevice;
--- a/gfx/vr/gfxVROSVR.cpp
+++ b/gfx/vr/gfxVROSVR.cpp
@@ -349,27 +349,29 @@ VRDisplayOSVR::SubmitFrame(ID3D11Texture
 
 bool
 VRDisplayOSVR::SubmitFrame(MacIOSurface* aMacIOSurface,
                            const IntSize& aSize,
                            const gfx::Rect& aLeftEyeRect,
                            const gfx::Rect& aRightEyeRect)
 {
   // XXX Add code to submit frame
+  MOZ_ASSERT(mSubmitThread->GetThread() == NS_GetCurrentThread());
   return false;
 }
 
 #elif defined(MOZ_ANDROID_GOOGLE_VR)
 
 bool
 VRDisplayOSVR::SubmitFrame(const mozilla::layers::EGLImageDescriptor*,
                            const gfx::Rect& aLeftEyeRect,
                            const gfx::Rect& aRightEyeRect)
 {
   // XXX Add code to submit frame
+  MOZ_ASSERT(mSubmitThread->GetThread() == NS_GetCurrentThread());
   return false;
 }
 
 #endif
 
 void
 VRDisplayOSVR::StartPresentation()
 {
--- a/gfx/vr/gfxVROculus.cpp
+++ b/gfx/vr/gfxVROculus.cpp
@@ -279,16 +279,17 @@ VROculusSession::StopPresentation()
       }
     }
     Refresh();
   }
 }
 
 VROculusSession::~VROculusSession()
 {
+  mSubmitThread = nullptr;
   Uninitialize(true);
 }
 
 void
 VROculusSession::Uninitialize(bool aUnloadLib)
 {
   StopRendering();
   StopSession();
@@ -351,26 +352,29 @@ VROculusSession::Refresh(bool aForceRefr
       // 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.
+          // VROculusSession didn't start submitting frames yet.
+          if (!mSubmitThread) {
+            return;
+          }
+          // ovr_SubmitFrame is running at VR Submit thread,
+          // so we post this task to VR Submit thread and let it paint
+          // a black frame.
           mDrawBlack = true;
-          MessageLoop* loop = layers::CompositorThreadHolder::Loop();
-          loop->PostTask(NewRunnableMethod<bool>(
+          MOZ_ASSERT(mSubmitThread->IsActive());
+          mSubmitThread->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;
@@ -1090,16 +1094,17 @@ VRDisplayOculus::UpdateConstantBuffers()
 }
 
 bool
 VRDisplayOculus::SubmitFrame(ID3D11Texture2D* aSource,
                              const IntSize& aSize,
                              const gfx::Rect& aLeftEyeRect,
                              const gfx::Rect& aRightEyeRect)
 {
+  MOZ_ASSERT(mSubmitThread->GetThread() == NS_GetCurrentThread());
   if (!CreateD3DObjects()) {
     return false;
   }
 
   AutoRestoreRenderState restoreState(this);
   if (!restoreState.IsSuccess()) {
     return false;
   }
@@ -1240,16 +1245,17 @@ VRDisplayOculus::SubmitFrame(ID3D11Textu
      * "health and safety warning", orv will be > 0 (OVR_SUCCESS but not
      * OVR_UNQUALIFIED_SUCCESS) and ovr_SubmitFrame will not block.
      * In this case, returning true would have resulted in an unthrottled
      * render loop hiting excessive frame rates and consuming resources.
      */
     return false;
   }
 
+  mSession->mSubmitThread = mSubmitThread;
   return true;
 }
 
 void
 VRDisplayOculus::NotifyVSync()
 {
   mSession->Refresh();
   if (mSession->IsTrackingReady()) {
--- a/gfx/vr/gfxVROculus.h
+++ b/gfx/vr/gfxVROculus.h
@@ -57,16 +57,17 @@ public:
 private:
   PRLibrary* mOvrLib;
   ovrSession mSession;
   ovrInitFlags mInitFlags;
   ovrTextureSwapChain mTextureSet;
   nsTArray<RefPtr<layers::CompositingRenderTargetD3D11>> mRenderTargets;
   IntSize mPresentationSize;
   RefPtr<ID3D11Device> mDevice;
+  RefPtr<VRThread> mSubmitThread;
   // 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;
 
--- a/gfx/vr/gfxVROpenVR.cpp
+++ b/gfx/vr/gfxVROpenVR.cpp
@@ -348,16 +348,17 @@ VRDisplayOpenVR::StopPresentation()
 
 bool
 VRDisplayOpenVR::SubmitFrame(void* aTextureHandle,
                              ::vr::ETextureType aTextureType,
                              const IntSize& aSize,
                              const gfx::Rect& aLeftEyeRect,
                              const gfx::Rect& aRightEyeRect)
 {
+  MOZ_ASSERT(mSubmitThread->GetThread() == NS_GetCurrentThread());
   if (!mIsPresenting) {
     return false;
   }
 
   ::vr::Texture_t tex;
   tex.handle = aTextureHandle;
   tex.eType = aTextureType;
   tex.eColorSpace = ::vr::EColorSpace::ColorSpace_Auto;
--- a/gfx/vr/gfxVRPuppet.cpp
+++ b/gfx/vr/gfxVRPuppet.cpp
@@ -284,16 +284,17 @@ VRDisplayPuppet::UpdateConstantBuffers()
 }
 
 bool
 VRDisplayPuppet::SubmitFrame(ID3D11Texture2D* aSource,
                              const IntSize& aSize,
                              const gfx::Rect& aLeftEyeRect,
                              const gfx::Rect& aRightEyeRect)
 {
+  MOZ_ASSERT(mSubmitThread->GetThread() == NS_GetCurrentThread());
   if (!mIsPresenting) {
     return false;
   }
 
   if (!CreateD3DObjects()) {
     return false;
   }
   AutoRestoreRenderState restoreState(this);
@@ -480,16 +481,17 @@ VRDisplayPuppet::SubmitFrame(ID3D11Textu
 #elif defined(XP_MACOSX)
 
 bool
 VRDisplayPuppet::SubmitFrame(MacIOSurface* aMacIOSurface,
                              const IntSize& aSize,
                              const gfx::Rect& aLeftEyeRect,
                              const gfx::Rect& aRightEyeRect)
 {
+  MOZ_ASSERT(mSubmitThread->GetThread() == NS_GetCurrentThread());
   if (!mIsPresenting || !aMacIOSurface) {
     return false;
   }
 
   VRManager* vm = VRManager::Get();
   MOZ_ASSERT(vm);
 
   switch (gfxPrefs::VRPuppetSubmitFrame()) {
@@ -553,18 +555,19 @@ VRDisplayPuppet::SubmitFrame(MacIOSurfac
   return false;
 }
 
 #elif defined(MOZ_ANDROID_GOOGLE_VR)
 
 bool
 VRDisplayPuppet::SubmitFrame(const mozilla::layers::EGLImageDescriptor* aDescriptor,
                            const gfx::Rect& aLeftEyeRect,
-                           const gfx::Rect& aRightEyeRect) {
-
+                           const gfx::Rect& aRightEyeRect)
+{
+  MOZ_ASSERT(mSubmitThread->GetThread() == NS_GetCurrentThread());
   return false;
 }
 
 #endif
 
 void
 VRDisplayPuppet::NotifyVSync()
 {
--- a/gfx/vr/ipc/VRLayerParent.cpp
+++ b/gfx/vr/ipc/VRLayerParent.cpp
@@ -60,36 +60,20 @@ VRLayerParent::Destroy()
 
 mozilla::ipc::IPCResult
 VRLayerParent::RecvSubmitFrame(const layers::SurfaceDescriptor &aTexture,
                                const uint64_t& aFrameId,
                                const gfx::Rect& aLeftEyeRect,
                                const gfx::Rect& aRightEyeRect)
 {
   if (mVRDisplayID) {
-    MessageLoop* loop = layers::CompositorThreadHolder::Loop();
     VRManager* vm = VRManager::Get();
     RefPtr<VRDisplayHost> display = vm->GetDisplay(mVRDisplayID);
     if (display) {
-      // Because VR compositor still shares the same graphics device with Compositor thread.
-      // We have to post sumbit frame tasks to Compositor thread.
-      // TODO: Move SubmitFrame to Bug 1392217.
-      loop->PostTask(NewRunnableMethod<VRDisplayHost*, const layers::SurfaceDescriptor, uint64_t,
-                                       const gfx::Rect&, const gfx::Rect&>(
-                     "gfx::VRLayerParent::SubmitFrame",
-                     this,
-                     &VRLayerParent::SubmitFrame, display, aTexture, aFrameId, aLeftEyeRect, aRightEyeRect));
+      display->SubmitFrame(this, aTexture, aFrameId, aLeftEyeRect, aRightEyeRect);
     }
   }
 
   return IPC_OK();
 }
 
-void
-VRLayerParent::SubmitFrame(VRDisplayHost* aDisplay, const layers::SurfaceDescriptor& aTexture,
-                           uint64_t aFrameId, const gfx::Rect& aLeftEyeRect, const gfx::Rect& aRightEyeRect)
-{
-  aDisplay->SubmitFrame(this, aTexture, aFrameId,
-                        aLeftEyeRect, aRightEyeRect);
-}
-
 } // namespace gfx
 } // namespace mozilla
--- a/gfx/vr/ipc/VRLayerParent.h
+++ b/gfx/vr/ipc/VRLayerParent.h
@@ -35,18 +35,14 @@ protected:
   void Destroy();
 
   bool mIPCOpen;
 
   uint32_t mVRDisplayID;
   gfx::Rect mLeftEyeRect;
   gfx::Rect mRightEyeRect;
   uint32_t mGroup;
-
-private:
-  void SubmitFrame(VRDisplayHost* aDisplay, const layers::SurfaceDescriptor& aTexture,
-                   uint64_t aFrameId, const gfx::Rect& aLeftEyeRect, const gfx::Rect& aRightEyeRect);
 };
 
 } // namespace gfx
 } // namespace mozilla
 
 #endif