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 434816 c13f5102b030016333714932043cce744963973d
parent 434815 b8abf66f07492a34279b7b61093a5e125b756269
child 434817 42e5371334d998003e6059035c17a2852f7417b4
push id8114
push userjlorenzo@mozilla.com
push dateThu, 02 Nov 2017 16:33:21 +0000
treeherdermozilla-beta@73e0d89a540f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdaoshengmu, jgilbert
bugs1400457
milestone58.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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;