Bug 1400457 - Isolate VR Rendering from Compositor r=daoshengmu,jgilbert
authorKearwood "Kip" Gilbert <kgilbert@mozilla.com>
Fri, 21 Jul 2017 17:30:34 -0700
changeset 426693 c13f5102b030016333714932043cce744963973d
parent 426692 b8abf66f07492a34279b7b61093a5e125b756269
child 426694 42e5371334d998003e6059035c17a2852f7417b4
push id97
push userfmarier@mozilla.com
push dateSat, 14 Oct 2017 01:12:59 +0000
reviewersdaoshengmu, jgilbert
bugs1400457
milestone58.0a1
Bug 1400457 - Isolate VR Rendering from Compositor r=daoshengmu,jgilbert - WebVR is no longer dependent on PTexture, TextureParent, TextureHost, and TextureChild. It continues to use TextureClient for pooling and coordinating locks with other Gecko code. - PreserveDrawingBuffer now behaving correctly for 2d display mirroring - Preparation for separating to VR process MozReview-Commit-ID: 2RGOulCInSu
dom/canvas/WebGLContext.cpp
dom/canvas/WebGLContext.h
dom/html/HTMLCanvasElement.cpp
dom/html/HTMLCanvasElement.h
gfx/vr/VRDisplayHost.cpp
gfx/vr/VRDisplayHost.h
gfx/vr/VRManager.cpp
gfx/vr/VRManager.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/ipc/PVRLayer.ipdl
gfx/vr/ipc/VRLayerChild.cpp
gfx/vr/ipc/VRLayerChild.h
gfx/vr/ipc/VRLayerParent.cpp
gfx/vr/ipc/VRLayerParent.h
--- a/dom/canvas/WebGLContext.cpp
+++ b/dom/canvas/WebGLContext.cpp
@@ -2328,90 +2328,37 @@ WebGLContext::GetUnpackSize(bool isFunc3
     totalBytes += usedBytesPerRow;
 
     return totalBytes;
 }
 
 already_AddRefed<layers::SharedSurfaceTextureClient>
 WebGLContext::GetVRFrame()
 {
-    if (!mLayerIsMirror) {
-        /**
-         * Do not allow VR frame submission until a mirroring canvas layer has
-         * been returned by GetCanvasLayer
-         */
-        return nullptr;
-    }
-
-    VRManagerChild* vrmc = VRManagerChild::Get();
-    if (!vrmc) {
-        return nullptr;
-    }
-
-    /**
-     * Swap buffers as though composition has occurred.
-     * We will then share the resulting front buffer to be submitted to the VR
-     * compositor.
-     */
-    BeginComposition();
-    EndComposition();
-
-    gl::GLScreenBuffer* screen = gl->Screen();
-    if (!screen) {
-        return nullptr;
-    }
-
-    RefPtr<SharedSurfaceTextureClient> sharedSurface = screen->Front();
-    if (!sharedSurface) {
-        return nullptr;
-    }
-
-    if (sharedSurface && sharedSurface->GetAllocator() != vrmc) {
-        RefPtr<SharedSurfaceTextureClient> dest =
-        screen->Factory()->NewTexClient(sharedSurface->GetSize(), vrmc);
-        if (!dest) {
-            return nullptr;
-        }
-        gl::SharedSurface* destSurf = dest->Surf();
-        destSurf->ProducerAcquire();
-        SharedSurface::ProdCopy(sharedSurface->Surf(), dest->Surf(),
-                                screen->Factory());
-        destSurf->ProducerRelease();
-
-        return dest.forget();
-    }
+  /**
+   * Swap buffers as though composition has occurred.
+   * We will then share the resulting front buffer to be submitted to the VR
+   * compositor.
+   */
+  BeginComposition();
+  EndComposition();
+
+  gl::GLScreenBuffer* screen = gl->Screen();
+  if (!screen) {
+      return nullptr;
+  }
+
+  RefPtr<SharedSurfaceTextureClient> sharedSurface = screen->Front();
+  if (!sharedSurface) {
+      return nullptr;
+  }
 
   return sharedSurface.forget();
 }
 
-bool
-WebGLContext::StartVRPresentation()
-{
-    VRManagerChild* vrmc = VRManagerChild::Get();
-    if (!vrmc) {
-        return false;
-    }
-    gl::GLScreenBuffer* screen = gl->Screen();
-    if (!screen) {
-        return false;
-    }
-    gl::SurfaceCaps caps = screen->mCaps;
-
-    UniquePtr<gl::SurfaceFactory> factory =
-        gl::GLScreenBuffer::CreateFactory(gl,
-            caps,
-            vrmc,
-            TextureFlags::ORIGIN_BOTTOM_LEFT);
-
-    if (factory) {
-        screen->Morph(Move(factory));
-    }
-    return true;
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 
 static inline size_t
 SizeOfViewElem(const dom::ArrayBufferView& view)
 {
     const auto& elemType = view.Type();
     if (elemType == js::Scalar::MaxTypedArrayViewType) // DataViews.
         return 1;
--- a/dom/canvas/WebGLContext.h
+++ b/dom/canvas/WebGLContext.h
@@ -637,17 +637,16 @@ public:
     bool IsShader(const WebGLShader* shader);
     bool IsVertexArray(const WebGLVertexArray* vao);
     void LineWidth(GLfloat width);
     void LinkProgram(WebGLProgram& prog);
     void PixelStorei(GLenum pname, GLint param);
     void PolygonOffset(GLfloat factor, GLfloat units);
 
     already_AddRefed<layers::SharedSurfaceTextureClient> GetVRFrame();
-    bool StartVRPresentation();
 
     ////
 
     webgl::PackingInfo
     ValidImplementationColorReadPI(const webgl::FormatUsageInfo* usage) const;
 
 protected:
     bool ReadPixels_SharedPrecheck(dom::CallerType aCallerType,
--- a/dom/html/HTMLCanvasElement.cpp
+++ b/dom/html/HTMLCanvasElement.cpp
@@ -373,17 +373,16 @@ HTMLCanvasElementObserver::HandleEvent(n
 
 NS_IMPL_ISUPPORTS(HTMLCanvasElementObserver, nsIObserver)
 
 // ---------------------------------------------------------------------------
 
 HTMLCanvasElement::HTMLCanvasElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
   : nsGenericHTMLElement(aNodeInfo),
     mResetLayer(true) ,
-    mVRPresentationActive(false),
     mWriteOnly(false)
 {}
 
 HTMLCanvasElement::~HTMLCanvasElement()
 {
   if (mContextObserver) {
     mContextObserver->Destroy();
     mContextObserver = nullptr;
@@ -1155,17 +1154,17 @@ HTMLCanvasElement::GetCanvasLayer(nsDisp
 {
   // The address of sOffscreenCanvasLayerUserDataDummy is used as the user
   // data key for retained LayerManagers managed by FrameLayerBuilder.
   // We don't much care about what value in it, so just assign a dummy
   // value for it.
   static uint8_t sOffscreenCanvasLayerUserDataDummy = 0;
 
   if (mCurrentContext) {
-    return mCurrentContext->GetCanvasLayer(aBuilder, aOldLayer, aManager, mVRPresentationActive);
+    return mCurrentContext->GetCanvasLayer(aBuilder, aOldLayer, aManager);
   }
 
   if (mOffscreenCanvas) {
     if (!mResetLayer &&
         aOldLayer && aOldLayer->HasUserData(&sOffscreenCanvasLayerUserDataDummy)) {
       RefPtr<Layer> ret = aOldLayer;
       return ret.forget();
     }
@@ -1498,42 +1497,16 @@ HTMLCanvasElement::InvalidateFromAsyncCa
   HTMLCanvasElement *element = aRenderer->mHTMLCanvasElement;
   if (!element) {
     return;
   }
 
   element->InvalidateCanvasContent(nullptr);
 }
 
-void
-HTMLCanvasElement::StartVRPresentation()
-{
-  if (GetCurrentContextType() != CanvasContextType::WebGL1 &&
-      GetCurrentContextType() != CanvasContextType::WebGL2) {
-    return;
-  }
-
-  WebGLContext* webgl = static_cast<WebGLContext*>(GetContextAtIndex(0));
-  if (!webgl) {
-    return;
-  }
-
-  if (!webgl->StartVRPresentation()) {
-    return;
-  }
-
-  mVRPresentationActive = true;
-}
-
-void
-HTMLCanvasElement::StopVRPresentation()
-{
-  mVRPresentationActive = false;
-}
-
 already_AddRefed<layers::SharedSurfaceTextureClient>
 HTMLCanvasElement::GetVRFrame()
 {
   if (GetCurrentContextType() != CanvasContextType::WebGL1 &&
       GetCurrentContextType() != CanvasContextType::WebGL2) {
     return nullptr;
   }
 
--- a/dom/html/HTMLCanvasElement.h
+++ b/dom/html/HTMLCanvasElement.h
@@ -336,18 +336,16 @@ public:
 
   void OnVisibilityChange();
 
   void OnMemoryPressure();
 
   static void SetAttrFromAsyncCanvasRenderer(AsyncCanvasRenderer *aRenderer);
   static void InvalidateFromAsyncCanvasRenderer(AsyncCanvasRenderer *aRenderer);
 
-  void StartVRPresentation();
-  void StopVRPresentation();
   already_AddRefed<layers::SharedSurfaceTextureClient> GetVRFrame();
 
 protected:
   virtual ~HTMLCanvasElement();
 
   virtual JSObject* WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
   virtual nsIntSize GetWidthHeight() override;
@@ -381,17 +379,16 @@ protected:
   RefPtr<HTMLCanvasElement> mOriginalCanvas;
   RefPtr<PrintCallback> mPrintCallback;
   RefPtr<HTMLCanvasPrintState> mPrintState;
   nsTArray<WeakPtr<FrameCaptureListener>> mRequestedFrameListeners;
   RefPtr<RequestedFrameRefreshObserver> mRequestedFrameRefreshObserver;
   RefPtr<AsyncCanvasRenderer> mAsyncCanvasRenderer;
   RefPtr<OffscreenCanvas> mOffscreenCanvas;
   RefPtr<HTMLCanvasElementObserver> mContextObserver;
-  bool mVRPresentationActive;
 
 public:
   // Record whether this canvas should be write-only or not.
   // We set this when script paints an image from a different origin.
   // We also transitively set it when script paints a canvas which
   // is itself write-only.
   bool                     mWriteOnly;
 
--- a/gfx/vr/VRDisplayHost.cpp
+++ b/gfx/vr/VRDisplayHost.cpp
@@ -250,17 +250,18 @@ VRDisplayHost::NotifyVSync()
   if (bShouldStartFrame) {
     VRManager *vm = VRManager::Get();
     MOZ_ASSERT(vm);
     vm->NotifyVRVsync(mDisplayInfo.mDisplayID);
   }
 }
 
 void
-VRDisplayHost::SubmitFrame(VRLayerParent* aLayer, PTextureParent* aTexture,
+VRDisplayHost::SubmitFrame(VRLayerParent* aLayer,
+                           const layers::SurfaceDescriptor &aTexture,
                            uint64_t aFrameId,
                            const gfx::Rect& aLeftEyeRect,
                            const gfx::Rect& aRightEyeRect)
 {
   AutoProfilerTracing tracing("VR", "SubmitFrameAtVRDisplayHost");
 
   if ((mDisplayInfo.mGroupMask & aLayer->GetGroup()) == 0) {
     // Suppress layers hidden by the group mask
@@ -268,70 +269,86 @@ VRDisplayHost::SubmitFrame(VRLayerParent
   }
 
   // Ensure that we only accept the first SubmitFrame call per RAF cycle.
   if (!mFrameStarted || aFrameId != mDisplayInfo.mFrameId) {
     return;
   }
   mFrameStarted = false;
 
-#if defined(XP_WIN)
-
-  TextureHost* th = TextureHost::AsTextureHost(aTexture);
-
-  // WebVR doesn't use the compositor to compose the frame, so use
-  // AutoLockTextureHostWithoutCompositor here.
-  AutoLockTextureHostWithoutCompositor autoLock(th);
-  if (autoLock.Failed()) {
-    NS_WARNING("Failed to lock the VR layer texture");
-    return;
-  }
+  switch (aTexture.type()) {
 
-  CompositableTextureSourceRef source;
-  if (!th->BindTextureSource(source)) {
-    NS_WARNING("The TextureHost was successfully locked but can't provide a TextureSource");
-    return;
-  }
-  MOZ_ASSERT(source);
-
-  IntSize texSize = source->GetSize();
-
-  TextureSourceD3D11* sourceD3D11 = source->AsSourceD3D11();
-  if (!sourceD3D11) {
-    NS_WARNING("VRDisplayHost::SubmitFrame failed to get a TextureSourceD3D11");
-    return;
-  }
+#if defined(XP_WIN)
+    case SurfaceDescriptor::TSurfaceDescriptorD3D10: {
+      if (!CreateD3DObjects()) {
+        return;
+      }
+      const SurfaceDescriptorD3D10& surf = aTexture.get_SurfaceDescriptorD3D10();
+      RefPtr<ID3D11Texture2D> dxTexture;
+      HRESULT hr = mDevice->OpenSharedResource((HANDLE)surf.handle(),
+        __uuidof(ID3D11Texture2D),
+        (void**)(ID3D11Texture2D**)getter_AddRefs(dxTexture));
+      if (FAILED(hr) || !dxTexture) {
+        NS_WARNING("Failed to open shared texture");
+        return;
+      }
 
-  if (!SubmitFrame(sourceD3D11, texSize, aLeftEyeRect, aRightEyeRect)) {
-    return;
-  }
-
+      // Similar to LockD3DTexture in TextureD3D11.cpp
+      RefPtr<IDXGIKeyedMutex> mutex;
+      dxTexture->QueryInterface((IDXGIKeyedMutex**)getter_AddRefs(mutex));
+      if (mutex) {
+        HRESULT hr = mutex->AcquireSync(0, 1000);
+        if (hr == WAIT_TIMEOUT) {
+          gfxDevCrash(LogReason::D3DLockTimeout) << "D3D lock mutex timeout";
+        }
+        else if (hr == WAIT_ABANDONED) {
+          gfxCriticalNote << "GFX: D3D11 lock mutex abandoned";
+        }
+        if (FAILED(hr)) {
+          NS_WARNING("Failed to lock the texture");
+          return;
+        }
+      }
+      bool success = SubmitFrame(dxTexture, surf.size(),
+                                 aLeftEyeRect, aRightEyeRect);
+      if (mutex) {
+        HRESULT hr = mutex->ReleaseSync(0);
+        if (FAILED(hr)) {
+          NS_WARNING("Failed to unlock the texture");
+        }
+      }
+      if (!success) {
+        return;
+      }
+      break;
+    }
 #elif defined(XP_MACOSX)
-
-  TextureHost* th = TextureHost::AsTextureHost(aTexture);
-
-  MacIOSurface* surf = th->GetMacIOSurface();
-  if (!surf) {
-    NS_WARNING("VRDisplayHost::SubmitFrame failed to get a MacIOSurface");
-    return;
+    case SurfaceDescriptor::TSurfaceDescriptorMacIOSurface: {
+      const auto& desc = aTexture.get_SurfaceDescriptorMacIOSurface();
+      RefPtr<MacIOSurface> surf = MacIOSurface::LookupSurface(desc.surfaceId(),
+                                                              desc.scaleFactor(),
+                                                              !desc.isOpaque());
+      if (!surf) {
+        NS_WARNING("VRDisplayHost::SubmitFrame failed to get a MacIOSurface");
+        return;
+      }
+      IntSize texSize = gfx::IntSize(surf->GetDevicePixelWidth(),
+                                     surf->GetDevicePixelHeight());
+      if (!SubmitFrame(surf, texSize, aLeftEyeRect, aRightEyeRect)) {
+        return;
+      }
+      break;
+    }
+#endif
+    default: {
+      NS_WARNING("Unsupported SurfaceDescriptor type for VR layer texture");
+      return;
+    }
   }
 
-  IntSize texSize = gfx::IntSize(surf->GetDevicePixelWidth(),
-                                 surf->GetDevicePixelHeight());
-
-  if (!SubmitFrame(surf, texSize, aLeftEyeRect, aRightEyeRect)) {
-    return;
-  }
-
-#else
-
-  NS_WARNING("WebVR is not supported on this platform.");
-  return;
-#endif
-
 #if defined(XP_WIN) || defined(XP_MACOSX)
 
   /**
    * Trigger the next VSync immediately after we are successfully
    * submitting frames.  As SubmitFrame is responsible for throttling
    * the render loop, if we don't successfully call it, we shouldn't trigger
    * NotifyVRVsync immediately, as it will run unbounded.
    * If NotifyVRVsync is not called here due to SubmitFrame failing, the
--- a/gfx/vr/VRDisplayHost.h
+++ b/gfx/vr/VRDisplayHost.h
@@ -12,30 +12,24 @@
 #include "nsCOMPtr.h"
 #include "mozilla/RefPtr.h"
 #include "mozilla/gfx/2D.h"
 #include "mozilla/Atomics.h"
 #include "mozilla/EnumeratedArray.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/TypedEnumBits.h"
 #include "mozilla/dom/GamepadPoseState.h"
+#include "mozilla/layers/LayersSurfaces.h"  // for SurfaceDescriptor
+
 #if defined(XP_WIN)
 #include <d3d11_1.h>
-#endif
-
-#if defined(XP_MACOSX)
+#elif defined(XP_MACOSX)
 class MacIOSurface;
 #endif
 namespace mozilla {
-namespace layers {
-class PTextureParent;
-#if defined(XP_WIN)
-class TextureSourceD3D11;
-#endif
-} // namespace layers
 namespace gfx {
 class VRLayerParent;
 
 class VRDisplayHost {
 public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VRDisplayHost)
 
   const VRDisplayInfo& GetDisplayInfo() const { return mDisplayInfo; }
@@ -45,17 +39,17 @@ public:
 
   virtual void ZeroSensor() = 0;
   virtual void StartPresentation() = 0;
   virtual void StopPresentation() = 0;
   virtual void NotifyVSync();
 
   void StartFrame();
   void SubmitFrame(VRLayerParent* aLayer,
-                   mozilla::layers::PTextureParent* aTexture,
+                   const layers::SurfaceDescriptor& aTexture,
                    uint64_t aFrameId,
                    const gfx::Rect& aLeftEyeRect,
                    const gfx::Rect& aRightEyeRect);
 
   bool CheckClearDisplayInfoDirty();
   void SetGroupMask(uint32_t aGroupMask);
   bool GetIsConnected();
 
@@ -76,17 +70,17 @@ protected:
   explicit VRDisplayHost(VRDeviceType aType);
   virtual ~VRDisplayHost();
 
 #if defined(XP_WIN)
   // Subclasses should override this SubmitFrame function.
   // Returns true if the SubmitFrame call will block as necessary
   // to control timing of the next frame and throttle the render loop
   // for the needed framerate.
-  virtual bool SubmitFrame(mozilla::layers::TextureSourceD3D11* aSource,
+  virtual bool SubmitFrame(ID3D11Texture2D* aSource,
                            const IntSize& aSize,
                            const gfx::Rect& aLeftEyeRect,
                            const gfx::Rect& aRightEyeRect) = 0;
 #elif defined(XP_MACOSX)
   virtual bool SubmitFrame(MacIOSurface* aMacIOSurface,
                            const IntSize& aSize,
                            const gfx::Rect& aLeftEyeRect,
                            const gfx::Rect& aRightEyeRect) = 0;
--- a/gfx/vr/VRManager.cpp
+++ b/gfx/vr/VRManager.cpp
@@ -338,30 +338,16 @@ VRManager::GetDisplay(const uint32_t& aD
 {
   RefPtr<gfx::VRDisplayHost> display;
   if (mVRDisplays.Get(aDisplayID, getter_AddRefs(display))) {
     return display;
   }
   return nullptr;
 }
 
-void
-VRManager::SubmitFrame(VRLayerParent* aLayer, layers::PTextureParent* aTexture,
-                       uint64_t aFrameId,
-                       const gfx::Rect& aLeftEyeRect,
-                       const gfx::Rect& aRightEyeRect)
-{
-  TextureHost* th = TextureHost::AsTextureHost(aTexture);
-  mLastFrame = th;
-  RefPtr<VRDisplayHost> display = GetDisplay(aLayer->GetDisplayID());
-  if (display) {
-    display->SubmitFrame(aLayer, aTexture, aFrameId, aLeftEyeRect, aRightEyeRect);
-  }
-}
-
 RefPtr<gfx::VRControllerHost>
 VRManager::GetController(const uint32_t& aControllerID)
 {
   RefPtr<gfx::VRControllerHost> controller;
   if (mVRControllers.Get(aControllerID, getter_AddRefs(controller))) {
     return controller;
   }
   return nullptr;
--- a/gfx/vr/VRManager.h
+++ b/gfx/vr/VRManager.h
@@ -38,36 +38,30 @@ public:
   void NotifyVRVsync(const uint32_t& aDisplayID);
   void RefreshVRDisplays(bool aMustDispatch = false);
   void RefreshVRControllers();
   void ScanForControllers();
   void RemoveControllers();
   template<class T> void NotifyGamepadChange(uint32_t aIndex, const T& aInfo);
   RefPtr<gfx::VRDisplayHost> GetDisplay(const uint32_t& aDisplayID);
   void GetVRDisplayInfo(nsTArray<VRDisplayInfo>& aDisplayInfo);
-
-  void SubmitFrame(VRLayerParent* aLayer, layers::PTextureParent* aTexture,
-                   uint64_t aFrameId,
-                   const gfx::Rect& aLeftEyeRect,
-                   const gfx::Rect& aRightEyeRect);
   RefPtr<gfx::VRControllerHost> GetController(const uint32_t& aControllerID);
   void GetVRControllerInfo(nsTArray<VRControllerInfo>& aControllerInfo);
   void CreateVRTestSystem();
   void VibrateHaptic(uint32_t aControllerIdx, uint32_t aHapticIndex,
                      double aIntensity, double aDuration, uint32_t aPromiseID);
   void StopVibrateHaptic(uint32_t aControllerIdx);
   void NotifyVibrateHapticCompleted(uint32_t aPromiseID);
   void DispatchSubmitFrameResult(uint32_t aDisplayID, const VRSubmitFrameResultInfo& aResult);
 
 protected:
   VRManager();
   ~VRManager();
 
 private:
-  RefPtr<layers::TextureHost> mLastFrame;
 
   void Init();
   void Destroy();
   void Shutdown();
 
   void DispatchVRDisplayInfoUpdate();
 
   typedef nsTHashtable<nsRefPtrHashKey<VRManagerParent>> VRManagerParentSet;
--- a/gfx/vr/gfxVROSVR.cpp
+++ b/gfx/vr/gfxVROSVR.cpp
@@ -316,17 +316,17 @@ VRDisplayOSVR::GetSensorState()
   }
 
   return result;
 }
 
 #if defined(XP_WIN)
 
 bool
-VRDisplayOSVR::SubmitFrame(TextureSourceD3D11* aSource,
+VRDisplayOSVR::SubmitFrame(ID3D11Texture2D* aSource,
   const IntSize& aSize,
   const gfx::Rect& aLeftEyeRect,
   const gfx::Rect& aRightEyeRect)
 {
   // XXX Add code to submit frame
   return false;
 }
 
--- a/gfx/vr/gfxVROSVR.h
+++ b/gfx/vr/gfxVROSVR.h
@@ -31,17 +31,17 @@ public:
   void ZeroSensor() override;
 
 protected:
   VRHMDSensorState GetSensorState() override;
   virtual void StartPresentation() override;
   virtual void StopPresentation() override;
 
 #if defined(XP_WIN)
-  virtual bool SubmitFrame(mozilla::layers::TextureSourceD3D11* aSource,
+  virtual bool SubmitFrame(ID3D11Texture2D* aSource,
                            const IntSize& aSize,
                            const gfx::Rect& aLeftEyeRect,
                            const gfx::Rect& aRightEyeRect) override;
 #elif defined(XP_MACOSX)
   virtual bool SubmitFrame(MacIOSurface* aMacIOSurface,
                            const IntSize& aSize,
                            const gfx::Rect& aLeftEyeRect,
                            const gfx::Rect& aRightEyeRect) override;
--- a/gfx/vr/gfxVROculus.cpp
+++ b/gfx/vr/gfxVROculus.cpp
@@ -1027,20 +1027,20 @@ VRDisplayOculus::UpdateConstantBuffers()
   ID3D11Buffer *buffer = mVSConstantBuffer;
   mContext->VSSetConstantBuffers(0, 1, &buffer);
   buffer = mPSConstantBuffer;
   mContext->PSSetConstantBuffers(0, 1, &buffer);
   return true;
 }
 
 bool
-VRDisplayOculus::SubmitFrame(TextureSourceD3D11* aSource,
-  const IntSize& aSize,
-  const gfx::Rect& aLeftEyeRect,
-  const gfx::Rect& aRightEyeRect)
+VRDisplayOculus::SubmitFrame(ID3D11Texture2D* aSource,
+                             const IntSize& aSize,
+                             const gfx::Rect& aLeftEyeRect,
+                             const gfx::Rect& aRightEyeRect)
 {
   if (!CreateD3DObjects()) {
     return false;
   }
 
   AutoRestoreRenderState restoreState(this);
   if (!restoreState.IsSuccess()) {
     return false;
@@ -1100,22 +1100,25 @@ VRDisplayOculus::SubmitFrame(TextureSour
   mContext->IASetVertexBuffers(0, 1, &vbuffer, &vsize, &voffset);
   mContext->IASetIndexBuffer(nullptr, DXGI_FORMAT_R16_UINT, 0);
   mContext->IASetInputLayout(mInputLayout);
   mContext->RSSetViewports(1, &viewport);
   mContext->RSSetScissorRects(1, &scissor);
   mContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
   mContext->VSSetShader(mQuadVS, nullptr, 0);
   mContext->PSSetShader(mQuadPS, nullptr, 0);
-  ID3D11ShaderResourceView* srView = aSource->GetShaderResourceView();
-  if (!srView) {
-    NS_WARNING("Failed to get SRV for Oculus");
-    return false;
+
+  RefPtr<ID3D11ShaderResourceView> srView;
+  HRESULT hr = mDevice->CreateShaderResourceView(aSource, nullptr, getter_AddRefs(srView));
+  if (FAILED(hr)) {
+    gfxWarning() << "Could not create shader resource view for Oculus: " << hexa(hr);
+    return nullptr;
   }
-  mContext->PSSetShaderResources(0 /* 0 == TexSlot::RGB */, 1, &srView);
+  ID3D11ShaderResourceView* viewPtr = srView.get();
+  mContext->PSSetShaderResources(0 /* 0 == TexSlot::RGB */, 1, &viewPtr);
   // XXX Use Constant from TexSlot in CompositorD3D11.cpp?
 
   ID3D11SamplerState *sampler = mLinearSamplerState;
   mContext->PSSetSamplers(0, 1, &sampler);
 
   if (!UpdateConstantBuffers()) {
     NS_WARNING("Failed to update constant buffers for Oculus");
     return false;
--- a/gfx/vr/gfxVROculus.h
+++ b/gfx/vr/gfxVROculus.h
@@ -84,17 +84,17 @@ class VRDisplayOculus : public VRDisplay
 public:
   virtual void NotifyVSync() override;
   void ZeroSensor() override;
 
 protected:
   virtual VRHMDSensorState GetSensorState() override;
   virtual void StartPresentation() override;
   virtual void StopPresentation() override;
-  virtual bool SubmitFrame(mozilla::layers::TextureSourceD3D11* aSource,
+  virtual bool SubmitFrame(ID3D11Texture2D* aSource,
                            const IntSize& aSize,
                            const gfx::Rect& aLeftEyeRect,
                            const gfx::Rect& aRightEyeRect) override;
   void UpdateStageParameters();
 
 public:
   explicit VRDisplayOculus(VROculusSession* aSession);
   void Destroy();
--- a/gfx/vr/gfxVROpenVR.cpp
+++ b/gfx/vr/gfxVROpenVR.cpp
@@ -359,22 +359,22 @@ VRDisplayOpenVR::SubmitFrame(void* aText
 
   mVRCompositor->PostPresentHandoff();
   return true;
 }
 
 #if defined(XP_WIN)
 
 bool
-VRDisplayOpenVR::SubmitFrame(TextureSourceD3D11* aSource,
+VRDisplayOpenVR::SubmitFrame(ID3D11Texture2D* aSource,
                              const IntSize& aSize,
                              const gfx::Rect& aLeftEyeRect,
                              const gfx::Rect& aRightEyeRect)
 {
-  return SubmitFrame((void *)aSource->GetD3D11Texture(),
+  return SubmitFrame((void *)aSource,
                      ::vr::ETextureType::TextureType_DirectX,
                      aSize, aLeftEyeRect, aRightEyeRect);
 }
 
 #elif defined(XP_MACOSX)
 
 bool
 VRDisplayOpenVR::SubmitFrame(MacIOSurface* aMacIOSurface,
--- a/gfx/vr/gfxVROpenVR.h
+++ b/gfx/vr/gfxVROpenVR.h
@@ -33,17 +33,17 @@ public:
   void ZeroSensor() override;
   bool GetIsHmdPresent();
 
 protected:
   virtual VRHMDSensorState GetSensorState() override;
   virtual void StartPresentation() override;
   virtual void StopPresentation() override;
 #if defined(XP_WIN)
-  virtual bool SubmitFrame(mozilla::layers::TextureSourceD3D11* aSource,
+  virtual bool SubmitFrame(ID3D11Texture2D* aSource,
                            const IntSize& aSize,
                            const gfx::Rect& aLeftEyeRect,
                            const gfx::Rect& aRightEyeRect) override;
 #elif defined(XP_MACOSX)
   virtual bool SubmitFrame(MacIOSurface* aMacIOSurface,
                            const IntSize& aSize,
                            const gfx::Rect& aLeftEyeRect,
                            const gfx::Rect& aRightEyeRect) override;
--- a/gfx/vr/gfxVRPuppet.cpp
+++ b/gfx/vr/gfxVRPuppet.cpp
@@ -269,17 +269,17 @@ VRDisplayPuppet::UpdateConstantBuffers()
   ID3D11Buffer *buffer = mVSConstantBuffer;
   mContext->VSSetConstantBuffers(0, 1, &buffer);
   buffer = mPSConstantBuffer;
   mContext->PSSetConstantBuffers(0, 1, &buffer);
   return true;
 }
 
 bool
-VRDisplayPuppet::SubmitFrame(TextureSourceD3D11* aSource,
+VRDisplayPuppet::SubmitFrame(ID3D11Texture2D* aSource,
                              const IntSize& aSize,
                              const gfx::Rect& aLeftEyeRect,
                              const gfx::Rect& aRightEyeRect)
 {
   if (!mIsPresenting) {
     return false;
   }
 
@@ -298,24 +298,23 @@ VRDisplayPuppet::SubmitFrame(TextureSour
     case 0:
       // The VR frame is not displayed.
       break;
     case 1:
     {
       // The frames are submitted to VR compositor are decoded
       // into a base64Image and dispatched to the DOM side.
       D3D11_TEXTURE2D_DESC desc;
-      ID3D11Texture2D* texture = aSource->GetD3D11Texture();
-      texture->GetDesc(&desc);
+      aSource->GetDesc(&desc);
       MOZ_ASSERT(desc.Format == DXGI_FORMAT_B8G8R8A8_UNORM,
                  "Only support B8G8R8A8_UNORM format.");
       // Map the staging resource
       ID3D11Texture2D* mappedTexture = nullptr;
       D3D11_MAPPED_SUBRESOURCE mapInfo;
-      HRESULT hr = mContext->Map(texture,
+      HRESULT hr = mContext->Map(aSource,
                                  0,  // Subsource
                                  D3D11_MAP_READ,
                                  0,  // MapFlags
                                  &mapInfo);
 
       if (FAILED(hr)) {
         // If we can't map this texture, copy it to a staging resource.
         if (hr == E_INVALIDARG) {
@@ -333,33 +332,33 @@ VRDisplayPuppet::SubmitFrame(TextureSour
 
           ID3D11Texture2D* stagingTexture = nullptr;
           hr = mDevice->CreateTexture2D(&desc2, nullptr, &stagingTexture);
           if (FAILED(hr)) {
             MOZ_ASSERT(false, "Failed to create a staging texture");
             return false;
           }
           // Copy the texture to a staging resource
-          mContext->CopyResource(stagingTexture, texture);
+          mContext->CopyResource(stagingTexture, aSource);
           // Map the staging resource
           hr = mContext->Map(stagingTexture,
                              0,  // Subsource
                              D3D11_MAP_READ,
                              0,  // MapFlags
                              &mapInfo);
           if (FAILED(hr)) {
             MOZ_ASSERT(false, "Failed to map staging texture");
           }
           mappedTexture = stagingTexture;
         } else {
           MOZ_ASSERT(false, "Failed to map staging texture");
           return false;
         }
       } else {
-        mappedTexture = texture;
+        mappedTexture = aSource;
       }
       // Ideally, we should convert the srcData to a PNG image and decode it
       // to a Base64 string here, but the GPU process does not have the privilege to
       // access the image library. So, we have to convert the RAW image data
       // to a base64 string and forward it to let the content process to
       // do the image conversion.
       char* srcData = static_cast<char*>(mapInfo.pData);
       VRSubmitFrameResultInfo result;
@@ -424,22 +423,25 @@ VRDisplayPuppet::SubmitFrame(TextureSour
       mContext->IASetVertexBuffers(0, 1, &vbuffer, &vsize, &voffset);
       mContext->IASetIndexBuffer(nullptr, DXGI_FORMAT_R16_UINT, 0);
       mContext->IASetInputLayout(mInputLayout);
       mContext->RSSetViewports(1, &viewport);
       mContext->RSSetScissorRects(1, &scissor);
       mContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
       mContext->VSSetShader(mQuadVS, nullptr, 0);
       mContext->PSSetShader(mQuadPS, nullptr, 0);
-      ID3D11ShaderResourceView* srView = aSource->GetShaderResourceView();
-      if (!srView) {
-        NS_WARNING("Failed to get SRV for Puppet");
-        return false;
+
+      RefPtr<ID3D11ShaderResourceView> srView;
+      HRESULT hr = mDevice->CreateShaderResourceView(aSource, nullptr, getter_AddRefs(srView));
+      if (FAILED(hr) || !srView) {
+        gfxWarning() << "Could not create shader resource view for Puppet: " << hexa(hr);
+        return nullptr;
       }
-      mContext->PSSetShaderResources(0 /* 0 == TexSlot::RGB */, 1, &srView);
+      ID3D11ShaderResourceView* viewPtr = srView.get();
+      mContext->PSSetShaderResources(0 /* 0 == TexSlot::RGB */, 1, &viewPtr);
       // XXX Use Constant from TexSlot in CompositorD3D11.cpp?
 
       ID3D11SamplerState *sampler = mLinearSamplerState;
       mContext->PSSetSamplers(0, 1, &sampler);
 
       if (!UpdateConstantBuffers()) {
         NS_WARNING("Failed to update constant buffers for Puppet");
         return false;
--- a/gfx/vr/gfxVRPuppet.h
+++ b/gfx/vr/gfxVRPuppet.h
@@ -27,17 +27,17 @@ public:
   void SetSensorState(const VRHMDSensorState& aSensorState);
   void ZeroSensor() override;
 
 protected:
   virtual VRHMDSensorState GetSensorState() override;
   virtual void StartPresentation() override;
   virtual void StopPresentation() override;
 #if defined(XP_WIN)
-  virtual bool SubmitFrame(mozilla::layers::TextureSourceD3D11* aSource,
+  virtual bool SubmitFrame(ID3D11Texture2D* aSource,
                            const IntSize& aSize,
                            const gfx::Rect& aLeftEyeRect,
                            const gfx::Rect& aRightEyeRect) override;
 #elif defined(XP_MACOSX)
   virtual bool SubmitFrame(MacIOSurface* aMacIOSurface,
                            const IntSize& aSize,
                            const gfx::Rect& aLeftEyeRect,
                            const gfx::Rect& aRightEyeRect) override;
--- a/gfx/vr/ipc/PVRLayer.ipdl
+++ b/gfx/vr/ipc/PVRLayer.ipdl
@@ -1,29 +1,29 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * vim: sw=2 ts=8 et :
  */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+include LayersSurfaces;
 include protocol PVRManager;
-include protocol PTexture;
 
 using mozilla::gfx::Rect from "mozilla/gfx/Rect.h";
 
 namespace mozilla {
 namespace gfx {
 
 async protocol PVRLayer
 {
   manager PVRManager;
 
 parent:
-  async SubmitFrame(PTexture aTexture, uint64_t aFrameId,
+  async SubmitFrame(SurfaceDescriptor aTexture, uint64_t aFrameId,
                     Rect aLeftEyeRect, Rect aRightEyeRect);
 
   async Destroy();
 
 child:
   async __delete__();
 };
 
--- a/gfx/vr/ipc/VRLayerChild.cpp
+++ b/gfx/vr/ipc/VRLayerChild.cpp
@@ -6,98 +6,107 @@
 #include "VRLayerChild.h"
 #include "GLScreenBuffer.h"
 #include "mozilla/layers/TextureClientSharedSurface.h"
 #include "SharedSurface.h"                // for SharedSurface
 #include "SharedSurfaceGL.h"              // for SharedSurface
 #include "mozilla/layers/LayersMessages.h" // for TimedTexture
 #include "nsICanvasRenderingContextInternal.h"
 #include "mozilla/dom/HTMLCanvasElement.h"
+#include "mozilla/layers/SyncObject.h" // for SyncObjectClient
 
 namespace mozilla {
 namespace gfx {
 
 VRLayerChild::VRLayerChild()
   : mCanvasElement(nullptr)
-  , mShSurfClient(nullptr)
-  , mFront(nullptr)
   , mIPCOpen(false)
+  , mLastSubmittedFrameId(0)
 {
   MOZ_COUNT_CTOR(VRLayerChild);
 }
 
 VRLayerChild::~VRLayerChild()
 {
-  if (mCanvasElement) {
-    mCanvasElement->StopVRPresentation();
-  }
-
   ClearSurfaces();
 
   MOZ_COUNT_DTOR(VRLayerChild);
 }
 
 void
 VRLayerChild::Initialize(dom::HTMLCanvasElement* aCanvasElement,
                          const gfx::Rect& aLeftEyeRect, const gfx::Rect& aRightEyeRect)
 {
   MOZ_ASSERT(aCanvasElement);
-  aCanvasElement->StartVRPresentation();
   mLeftEyeRect = aLeftEyeRect;
   mRightEyeRect = aRightEyeRect;
   if (mCanvasElement == nullptr) {
     mCanvasElement = aCanvasElement;
     VRManagerChild *vrmc = VRManagerChild::Get();
     vrmc->RunFrameRequestCallbacks();
   } else {
     mCanvasElement = aCanvasElement;
   }
 }
 
 void
 VRLayerChild::SubmitFrame(uint64_t aFrameId)
 {
-  if (!mCanvasElement) {
+  // aFrameId will not increment unless the previuosly submitted
+  // frame was received by the VR thread and submitted to the VR
+  // compositor.  We early-exit here in the event that SubmitFrame
+  // was called twice for the same aFrameId.
+  if (!mCanvasElement || aFrameId == mLastSubmittedFrameId) {
     return;
   }
+  mLastSubmittedFrameId = aFrameId;
+
+  // Keep the SharedSurfaceTextureClient alive long enough for
+  // 1 extra frame, accomodating overlapped asynchronous rendering.
+  mLastFrameTexture = mThisFrameTexture;
+
+  mThisFrameTexture = mCanvasElement->GetVRFrame();
+  if (!mThisFrameTexture) {
+    return;
+  }
+  VRManagerChild* vrmc = VRManagerChild::Get();
+  layers::SyncObjectClient* syncObject = vrmc->GetSyncObject();
+  mThisFrameTexture->SyncWithObject(syncObject);
+  if (!gfxPlatform::GetPlatform()->DidRenderingDeviceReset()) {
+    if (syncObject && syncObject->IsSyncObjectValid()) {
+      syncObject->Synchronize();
+    }
+  }
 
-  mShSurfClient = mCanvasElement->GetVRFrame();
-  if (!mShSurfClient) {
-    return;
-  }
-
-  gl::SharedSurface* surf = mShSurfClient->Surf();
+  gl::SharedSurface* surf = mThisFrameTexture->Surf();
   if (surf->mType == gl::SharedSurfaceType::Basic) {
     gfxCriticalError() << "SharedSurfaceType::Basic not supported for WebVR";
     return;
   }
 
-  mFront = mShSurfClient;
-  mShSurfClient = nullptr;
+  layers::SurfaceDescriptor desc;
+  if (!surf->ToSurfaceDescriptor(&desc)) {
+    gfxCriticalError() << "SharedSurface::ToSurfaceDescriptor failed in VRLayerChild::SubmitFrame";
+    return;
+  }
 
-  mFront->SetAddedToCompositableClient();
-  VRManagerChild* vrmc = VRManagerChild::Get();
-  mFront->SyncWithObject(vrmc->GetSyncObject());
-  MOZ_ALWAYS_TRUE(mFront->InitIPDLActor(vrmc));
-
-  SendSubmitFrame(mFront->GetIPDLActor(), aFrameId,
-                  mLeftEyeRect, mRightEyeRect);
+  SendSubmitFrame(desc, aFrameId, mLeftEyeRect, mRightEyeRect);
 }
 
 bool
 VRLayerChild::IsIPCOpen()
 {
   return mIPCOpen;
 }
 
 void
 VRLayerChild::ClearSurfaces()
 {
-  mFront = nullptr;
-  mShSurfClient = nullptr;
+  mThisFrameTexture = nullptr;
+  mLastFrameTexture = nullptr;
 }
 
 void
 VRLayerChild::ActorDestroy(ActorDestroyReason aWhy)
 {
   mIPCOpen = false;
 }
 
--- a/gfx/vr/ipc/VRLayerChild.h
+++ b/gfx/vr/ipc/VRLayerChild.h
@@ -42,27 +42,30 @@ public:
 
 private:
   VRLayerChild();
   virtual ~VRLayerChild();
   void ClearSurfaces();
   virtual void ActorDestroy(ActorDestroyReason aWhy) override;
 
   RefPtr<dom::HTMLCanvasElement> mCanvasElement;
-  RefPtr<layers::SharedSurfaceTextureClient> mShSurfClient;
-  RefPtr<layers::TextureClient> mFront;
   bool mIPCOpen;
 
   // AddIPDLReference and ReleaseIPDLReference are only to be called by CreateIPDLActor
   // and DestroyIPDLActor, respectively. We intentionally make them private to prevent misuse.
   // The purpose of these methods is to be aware of when the IPC system around this
   // actor goes down: mIPCOpen is then set to false.
   void AddIPDLReference();
   void ReleaseIPDLReference();
 
   gfx::Rect mLeftEyeRect;
   gfx::Rect mRightEyeRect;
+
+  RefPtr<layers::SharedSurfaceTextureClient> mThisFrameTexture;
+  RefPtr<layers::SharedSurfaceTextureClient> mLastFrameTexture;
+
+  uint64_t mLastSubmittedFrameId;
 };
 
 } // namespace gfx
 } // namespace mozilla
 
 #endif
--- a/gfx/vr/ipc/VRLayerParent.cpp
+++ b/gfx/vr/ipc/VRLayerParent.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 
 #include "VRLayerParent.h"
 #include "mozilla/Unused.h"
+#include "VRDisplayHost.h"
 
 namespace mozilla {
 namespace gfx {
 
 VRLayerParent::VRLayerParent(uint32_t aVRDisplayID, const uint32_t aGroup)
   : mIPCOpen(true)
   , mVRDisplayID(aVRDisplayID)
   , mGroup(aGroup)
@@ -50,24 +51,28 @@ VRLayerParent::Destroy()
   }
 
   if (mIPCOpen) {
     Unused << PVRLayerParent::Send__delete__(this);
   }
 }
 
 mozilla::ipc::IPCResult
-VRLayerParent::RecvSubmitFrame(PTextureParent* texture,
+VRLayerParent::RecvSubmitFrame(const layers::SurfaceDescriptor &aTexture,
                                const uint64_t& aFrameId,
                                const gfx::Rect& aLeftEyeRect,
                                const gfx::Rect& aRightEyeRect)
 {
   if (mVRDisplayID) {
     VRManager* vm = VRManager::Get();
-    vm->SubmitFrame(this, texture, aFrameId, aLeftEyeRect, aRightEyeRect);
+    RefPtr<VRDisplayHost> display = vm->GetDisplay(mVRDisplayID);
+    if (display) {
+      display->SubmitFrame(this, aTexture, aFrameId,
+                           aLeftEyeRect, aRightEyeRect);
+    }
   }
 
   return IPC_OK();
 }
 
 
 } // namespace gfx
 } // namespace mozilla
--- a/gfx/vr/ipc/VRLayerParent.h
+++ b/gfx/vr/ipc/VRLayerParent.h
@@ -15,17 +15,17 @@
 namespace mozilla {
 namespace gfx {
 
 class VRLayerParent : public PVRLayerParent {
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VRLayerParent)
 
 public:
   VRLayerParent(uint32_t aVRDisplayID, const uint32_t aGroup);
-  virtual mozilla::ipc::IPCResult RecvSubmitFrame(PTextureParent* texture,
+  virtual mozilla::ipc::IPCResult RecvSubmitFrame(const layers::SurfaceDescriptor &aTexture,
                                                   const uint64_t& aFrameId,
                                                   const gfx::Rect& aLeftEyeRect,
                                                   const gfx::Rect& aRightEyeRect) override;
   virtual mozilla::ipc::IPCResult RecvDestroy() override;
   uint32_t GetDisplayID() const { return mVRDisplayID; }
   uint32_t GetGroup() const { return mGroup; }
 protected:
   virtual void ActorDestroy(ActorDestroyReason aWhy) override;