Bug 1482613 - Make WebVR work with multiprocess enabled on Android r=kip,rbarker,kvark
authorImanol Fernandez <imanol@mozilla.com>
Fri, 24 Aug 2018 15:32:12 +0000
changeset 433304 a17e0db21cae
parent 433303 902644464343
child 433305 1dc785e713d9
push id68263
push userrbarker@mozilla.com
push dateFri, 24 Aug 2018 15:32:42 +0000
treeherderautoland@a17e0db21cae [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskip, rbarker, kvark
bugs1482613
milestone63.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 1482613 - Make WebVR work with multiprocess enabled on Android r=kip,rbarker,kvark MozReview-Commit-ID: G9aHbp0G7DK Differential Revision: https://phabricator.services.mozilla.com/D3152
dom/canvas/WebGLContext.cpp
dom/canvas/WebGLContext.h
gfx/gl/GLScreenBuffer.h
gfx/vr/VRDisplayHost.cpp
gfx/vr/VRDisplayHost.h
gfx/vr/VRDisplayPresentation.cpp
gfx/vr/gfxVRExternal.cpp
gfx/vr/gfxVRExternal.h
gfx/vr/ipc/VRLayerChild.cpp
gfx/vr/ipc/VRLayerChild.h
--- a/dom/canvas/WebGLContext.cpp
+++ b/dom/canvas/WebGLContext.cpp
@@ -78,17 +78,17 @@
 #include "nsCocoaFeatures.h"
 #endif
 
 #ifdef XP_WIN
 #include "WGLLibrary.h"
 #endif
 
 #if defined(MOZ_WIDGET_ANDROID)
-    #include "../../gfx/vr/gfxVRExternal.h"
+#include "mozilla/layers/ImageBridgeChild.h"
 #endif
 
 // Generated
 #include "mozilla/dom/WebGLRenderingContextBinding.h"
 
 
 namespace mozilla {
 
@@ -231,16 +231,19 @@ WebGLContext::DestroyResourcesAndContext
     mActiveProgramLinkInfo = nullptr;
     mBoundDrawFramebuffer = nullptr;
     mBoundReadFramebuffer = nullptr;
     mBoundRenderbuffer = nullptr;
     mBoundVertexArray = nullptr;
     mDefaultVertexArray = nullptr;
     mBoundTransformFeedback = nullptr;
     mDefaultTransformFeedback = nullptr;
+#if defined(MOZ_WIDGET_ANDROID)
+    mVRScreen = nullptr;
+#endif
 
     mQuerySlot_SamplesPassed = nullptr;
     mQuerySlot_TFPrimsWritten = nullptr;
     mQuerySlot_TimeElapsed = nullptr;
 
     mIndexedUniformBufferBindings.clear();
 
     if (mAvailabilityRunnable) {
@@ -783,17 +786,17 @@ WebGLContext::SetDimensions(int32_t sign
         {
             return NS_OK;
         }
 
         if (IsContextLost())
             return NS_OK;
 
         // If we've already drawn, we should commit the current buffer.
-        PresentScreenBuffer();
+        PresentScreenBuffer(gl->Screen());
 
         if (IsContextLost()) {
             GenerateWarning("WebGL context was lost due to swap failure.");
             return NS_OK;
         }
 
         // Kill our current default fb(s), for later lazy allocation.
         mRequestedSize = {width, height};
@@ -1458,30 +1461,30 @@ WebGLContext::BlitBackbufferToCurDriverF
     if (mScissorTestEnabled) {
         gl->fEnable(LOCAL_GL_SCISSOR_TEST);
     }
 }
 
 // For an overview of how WebGL compositing works, see:
 // https://wiki.mozilla.org/Platform/GFX/WebGL/Compositing
 bool
-WebGLContext::PresentScreenBuffer()
+WebGLContext::PresentScreenBuffer(GLScreenBuffer* const targetScreen)
 {
     const FuncScope funcScope(*this, "<PresentScreenBuffer>");
     if (IsContextLost())
         return false;
 
     if (!mShouldPresent)
         return false;
 
     if (!ValidateAndInitFB(nullptr))
         return false;
 
-    const auto& screen = gl->Screen();
-    if (screen->Size() != mDefaultFB->mSize &&
+    const auto& screen = targetScreen ? targetScreen : gl->Screen();
+    if ((!screen->IsReadBufferReady() || screen->Size() != mDefaultFB->mSize) &&
         !screen->Resize(mDefaultFB->mSize))
     {
         GenerateWarning("screen->Resize failed. Losing context.");
         ForceLoseContext();
         return false;
     }
 
     gl->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
@@ -1515,20 +1518,20 @@ WebGLContext::PresentScreenBuffer()
     mShouldPresent = false;
     OnEndOfFrame();
 
     return true;
 }
 
 // Prepare the context for capture before compositing
 void
-WebGLContext::BeginComposition()
+WebGLContext::BeginComposition(GLScreenBuffer* const screen)
 {
     // Present our screenbuffer, if needed.
-    PresentScreenBuffer();
+    PresentScreenBuffer(screen);
     mDrawCallsSinceLastFlush = 0;
 }
 
 // Clean up the context after captured for compositing
 void
 WebGLContext::EndComposition()
 {
     // Mark ourselves as no longer invalidated.
@@ -2296,57 +2299,50 @@ WebGLContext::GetUnpackSize(bool isFunc3
     return totalBytes;
 }
 
 
 #if defined(MOZ_WIDGET_ANDROID)
 already_AddRefed<layers::SharedSurfaceTextureClient>
 WebGLContext::GetVRFrame()
 {
-  if (!gl)
-    return nullptr;
-
-  int frameId = gfx::impl::VRDisplayExternal::sPushIndex;
-  static int lastFrameId = -1;
-  /**
-   * Android doesn't like duplicated GetVRFrame within the same gfxVRExternal frame.
-   * Ballout forced composition calls if we are in the same VRExternal push frame index.
-   * Also discard frameId 0 because sometimes compositor is not paused yet due to channel communication delays.
-   */
-  const bool ignoreFrame = lastFrameId == frameId || frameId == 0;
-  lastFrameId = frameId;
-  if (!ignoreFrame) {
-      BeginComposition();
-      EndComposition();
-  }
-
-  if (!gl) {
-    return nullptr;
-  }
-
-  gl::GLScreenBuffer* screen = gl->Screen();
-  if (!screen) {
-    return nullptr;
-  }
-
-  RefPtr<SharedSurfaceTextureClient> sharedSurface = screen->Front();
-  if (!sharedSurface || !sharedSurface->Surf()) {
-    return nullptr;
-  }
-
-  /**
-   * Make sure that the WebGL buffer is committed to the attached SurfaceTexture on Android.
-   */
-  if (!ignoreFrame) {
+    if (!gl)
+        return nullptr;
+    
+    // Create a custom GLScreenBuffer for VR.
+    if (!mVRScreen) {
+        auto caps = gl->Screen()->mCaps;
+        mVRScreen = GLScreenBuffer::Create(gl, gfx::IntSize(1, 1), caps);
+
+        RefPtr<ImageBridgeChild> imageBridge = ImageBridgeChild::GetSingleton();
+        if (imageBridge) {
+            TextureFlags flags = TextureFlags::ORIGIN_BOTTOM_LEFT;
+            UniquePtr<gl::SurfaceFactory> factory = gl::GLScreenBuffer::CreateFactory(gl, caps, imageBridge.get(), flags);
+            mVRScreen->Morph(std::move(factory));
+        }
+    }
+
+    // Swap buffers as though composition has occurred.
+    // We will then share the resulting front buffer to be submitted to the VR compositor.
+    BeginComposition(mVRScreen.get());
+    EndComposition();
+
+    if (IsContextLost())
+        return nullptr;
+
+    RefPtr<SharedSurfaceTextureClient> sharedSurface = mVRScreen->Front();
+    if (!sharedSurface || !sharedSurface->Surf())
+        return nullptr;
+
+    // Make sure that the WebGL buffer is committed to the attached SurfaceTexture on Android.
     sharedSurface->Surf()->ProducerAcquire();
     sharedSurface->Surf()->Commit();
     sharedSurface->Surf()->ProducerRelease();
-  }
-
-  return sharedSurface.forget();
+
+    return sharedSurface.forget();
 }
 #else
 already_AddRefed<layers::SharedSurfaceTextureClient>
 WebGLContext::GetVRFrame()
 {
   /**
    * Swap buffers as though composition has occurred.
    * We will then share the resulting front buffer to be submitted to the VR
--- a/dom/canvas/WebGLContext.h
+++ b/dom/canvas/WebGLContext.h
@@ -90,16 +90,17 @@ struct WebGLContextAttributes;
 } // namespace dom
 
 namespace gfx {
 class SourceSurface;
 class VRLayerChild;
 } // namespace gfx
 
 namespace gl {
+class GLScreenBuffer;
 class MozFramebuffer;
 } // namespace gl
 
 namespace webgl {
 class AvailabilityRunnable;
 struct CachedDrawFetchLimits;
 struct LinkedProgramInfo;
 class ShaderValidator;
@@ -493,20 +494,20 @@ public:
     bool IsContextCleanForFrameCapture() override { return !mCapturedFrameInvalidated; }
 
     gl::GLContext* GL() const { return gl; }
 
     bool IsPremultAlpha() const { return mOptions.premultipliedAlpha; }
 
     bool IsPreservingDrawingBuffer() const { return mOptions.preserveDrawingBuffer; }
 
-    bool PresentScreenBuffer();
+    bool PresentScreenBuffer(gl::GLScreenBuffer* const screen = nullptr);
 
     // Prepare the context for capture before compositing
-    void BeginComposition();
+    void BeginComposition(gl::GLScreenBuffer* const screen = nullptr);
     // Clean up the context after captured for compositing
     void EndComposition();
 
     // a number that increments every time we have an event that causes
     // all context resources to be lost.
     uint32_t Generation() const { return mGeneration.value(); }
 
     // This is similar to GLContext::ClearSafely, but tries to minimize the
@@ -1975,16 +1976,19 @@ protected:
 
     mutable uint8_t mDriverColorMask = 0;
     bool mDriverDepthTest = false;
     bool mDriverStencilTest = false;
 
     bool mNeedsIndexValidation = false;
 
     const bool mAllowFBInvalidation;
+#if defined(MOZ_WIDGET_ANDROID)
+    UniquePtr<gl::GLScreenBuffer> mVRScreen;
+#endif
 
     bool Has64BitTimestamps() const;
 
     // --
 
     const uint8_t mMsaaSamples;
     mutable gfx::IntSize mRequestedSize;
     mutable UniquePtr<gl::MozFramebuffer> mDefaultFB;
--- a/gfx/gl/GLScreenBuffer.h
+++ b/gfx/gl/GLScreenBuffer.h
@@ -217,16 +217,20 @@ public:
     void DeletingFB(GLuint fb);
 
     const gfx::IntSize& Size() const {
         MOZ_ASSERT(mRead);
         MOZ_ASSERT(!mDraw || mDraw->mSize == mRead->Size());
         return mRead->Size();
     }
 
+    bool IsReadBufferReady() const {
+        return mRead.get() != nullptr;
+    }
+
     void BindAsFramebuffer(GLContext* const gl, GLenum target) const;
 
     void RequireBlit();
     void AssureBlitted();
     void AfterDrawCall();
     void BeforeReadCall();
 
     bool CopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x,
--- a/gfx/vr/VRDisplayHost.cpp
+++ b/gfx/vr/VRDisplayHost.cpp
@@ -23,16 +23,19 @@
 #elif defined(XP_MACOSX)
 
 #include "mozilla/gfx/MacIOSurface.h"
 
 #endif
 
 #if defined(MOZ_WIDGET_ANDROID)
 #include "mozilla/layers/CompositorThread.h"
+// Max frame duration on Android before the watchdog submits a new one.
+// Probably we can get rid of this when we enforce that SubmitFrame can only be called in a VRDisplay loop.
+#define ANDROID_MAX_FRAME_DURATION 4000
 #endif // defined(MOZ_WIDGET_ANDROID)
 
 
 using namespace mozilla;
 using namespace mozilla::gfx;
 using namespace mozilla::layers;
 
 VRDisplayHost::AutoRestoreRenderState::AutoRestoreRenderState(VRDisplayHost* aDisplay)
@@ -74,16 +77,21 @@ VRDisplayHost::VRDisplayHost(VRDeviceTyp
   MOZ_COUNT_CTOR(VRDisplayHost);
   mDisplayInfo.mType = aType;
   mDisplayInfo.mDisplayID = VRSystemManager::AllocateDisplayID();
   mDisplayInfo.mPresentingGroups = 0;
   mDisplayInfo.mGroupMask = kVRGroupContent;
   mDisplayInfo.mFrameId = 0;
   mDisplayInfo.mDisplayState.mPresentingGeneration = 0;
   mDisplayInfo.mDisplayState.mDisplayName[0] = '\0';
+
+#if defined(MOZ_WIDGET_ANDROID)
+  mLastSubmittedFrameId = 0;
+  mLastStartedFrame = 0;
+#endif // defined(MOZ_WIDGET_ANDROID)
 }
 
 VRDisplayHost::~VRDisplayHost()
 {
   if (mSubmitThread) {
     mSubmitThread->Shutdown();
     mSubmitThread = nullptr;
   }
@@ -195,20 +203,34 @@ VRDisplayHost::RemoveLayer(VRLayerParent
   vm->RefreshVRDisplays();
 }
 
 void
 VRDisplayHost::StartFrame()
 {
   AUTO_PROFILER_TRACING("VR", "GetSensorState");
 
+#if defined(MOZ_WIDGET_ANDROID)
+  const bool isPresenting = mLastUpdateDisplayInfo.GetPresentingGroups() != 0;
+  double duration = mLastFrameStart.IsNull() ? 0.0 : (TimeStamp::Now() - mLastFrameStart).ToMilliseconds();
+  /**
+   * Do not start more VR frames until the last submitted frame is already processed.
+   */
+  if (isPresenting && mLastStartedFrame > 0 && mDisplayInfo.mDisplayState.mLastSubmittedFrameId < mLastStartedFrame && duration < (double)ANDROID_MAX_FRAME_DURATION) {
+    return;
+  }
+#endif // !defined(MOZ_WIDGET_ANDROID)
+
   mLastFrameStart = TimeStamp::Now();
   ++mDisplayInfo.mFrameId;
   mDisplayInfo.mLastSensorState[mDisplayInfo.mFrameId % kVRMaxLatencyFrames] = GetSensorState();
   mFrameStarted = true;
+#if defined(MOZ_WIDGET_ANDROID)
+  mLastStartedFrame = mDisplayInfo.mFrameId;
+#endif // !defined(MOZ_WIDGET_ANDROID)  
 }
 
 void
 VRDisplayHost::NotifyVSync()
 {
   /**
    * We will trigger a new frame immediately after a successful frame texture
    * submission.  If content fails to call VRDisplay.submitFrame after
@@ -311,16 +333,29 @@ VRDisplayHost::SubmitFrame(VRLayerParent
     return;
   }
 
   // Ensure that we only accept the first SubmitFrame call per RAF cycle.
   if (!mFrameStarted || aFrameId != mDisplayInfo.mFrameId) {
     return;
   }
 
+#if defined(MOZ_WIDGET_ANDROID)
+  /**
+   * Do not queue more submit frames until the last submitted frame is already processed 
+   * and the new WebGL texture is ready.
+   */
+  if (mLastSubmittedFrameId > 0 && mLastSubmittedFrameId != mDisplayInfo.mDisplayState.mLastSubmittedFrameId) {
+    mLastStartedFrame = 0;
+    return;
+  }
+
+  mLastSubmittedFrameId = aFrameId;
+#endif // !defined(MOZ_WIDGET_ANDROID)
+
   mFrameStarted = false;
 
   RefPtr<Runnable> submit =
     NewRunnableMethod<StoreCopyPassByConstLRef<layers::SurfaceDescriptor>, uint64_t,
       StoreCopyPassByConstLRef<gfx::Rect>, StoreCopyPassByConstLRef<gfx::Rect>>(
       "gfx::VRDisplayHost::SubmitFrameInternal", this, &VRDisplayHost::SubmitFrameInternal,
       aTexture, aFrameId, aLeftEyeRect, aRightEyeRect);
 
--- a/gfx/vr/VRDisplayHost.h
+++ b/gfx/vr/VRDisplayHost.h
@@ -96,16 +96,21 @@ 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(MOZ_WIDGET_ANDROID)
+protected:
+  uint64_t mLastSubmittedFrameId;
+  uint64_t mLastStartedFrame;
+#endif // defined(MOZ_WIDGET_ANDROID)
 
 #if defined(XP_WIN)
 protected:
   bool CreateD3DObjects();
   RefPtr<ID3D11Device1> mDevice;
   RefPtr<ID3D11DeviceContext1> mContext;
   ID3D11Device1* GetD3DDevice();
   ID3D11DeviceContext1* GetD3DDeviceContext();
--- a/gfx/vr/VRDisplayPresentation.cpp
+++ b/gfx/vr/VRDisplayPresentation.cpp
@@ -136,12 +136,12 @@ VRDisplayPresentation::~VRDisplayPresent
 {
   DestroyLayers();
   mDisplayClient->PresentationDestroyed();
 }
 
 void VRDisplayPresentation::SubmitFrame()
 {
   for (VRLayerChild *layer : mLayers) {
-    layer->SubmitFrame(mDisplayClient->GetDisplayInfo().GetFrameId());
+    layer->SubmitFrame(mDisplayClient->GetDisplayInfo());
     break; // Currently only one layer supported, submit only the first
   }
 }
--- a/gfx/vr/gfxVRExternal.cpp
+++ b/gfx/vr/gfxVRExternal.cpp
@@ -47,18 +47,16 @@ static const char* kShmemName = "/moz.ge
 #endif
 
 using namespace mozilla;
 using namespace mozilla::gfx;
 using namespace mozilla::gfx::impl;
 using namespace mozilla::layers;
 using namespace mozilla::dom;
 
-int VRDisplayExternal::sPushIndex = 0;
-
 VRDisplayExternal::VRDisplayExternal(const VRDisplayState& aDisplayState)
   : VRDisplayHost(VRDeviceType::External)
   , mBrowserState{}
   , mLastSensorState{}
 {
   MOZ_COUNT_CTOR_INHERITED(VRDisplayExternal, VRDisplayHost);
   mDisplayInfo.mDisplayState = aDisplayState;
 
@@ -103,26 +101,27 @@ VRDisplayExternal::GetSensorState()
 }
 
 void
 VRDisplayExternal::StartPresentation()
 {
   if (mBrowserState.presentationActive) {
     return;
   }
-  sPushIndex = 0;
   mTelemetry.Clear();
   mTelemetry.mPresentationStart = TimeStamp::Now();
 
   // Indicate that we are ready to start immersive mode
   mBrowserState.presentationActive = true;
   mBrowserState.layerState[0].type = VRLayerType::LayerType_Stereo_Immersive;
   PushState();
 
 #if defined(MOZ_WIDGET_ANDROID)
+  mLastSubmittedFrameId = 0;
+  mLastStartedFrame = 0;
   /**
    * Android compositor is paused when presentation starts. That causes VRManager::NotifyVsync() not to be called.
    * We post a VRTask to call VRManager::NotifyVsync() while the compositor is paused on Android.
    * VRManager::NotifyVsync() should be called constinuosly while the compositor is paused because Gecko WebVR Architecture
    * relies on that to act as a "watchdog" in order to avoid render loop stalls and recover from SubmitFrame call timeouts.
    */
   PostVRTask();
 #endif
@@ -157,17 +156,16 @@ VRDisplayExternal::RunVRTask() {
 #endif // defined(MOZ_WIDGET_ANDROID)
 
 void
 VRDisplayExternal::StopPresentation()
 {
   if (!mBrowserState.presentationActive) {
     return;
   }
-  sPushIndex = 0;
 
   // Indicate that we have stopped immersive mode
   mBrowserState.presentationActive = false;
   memset(mBrowserState.layerState, 0, sizeof(VRLayerState) * mozilla::ArrayLength(mBrowserState.layerState));
 
   PushState(true);
 
   // TODO - Implement telemetry:
@@ -271,17 +269,16 @@ VRDisplayExternal::SubmitFrame(const lay
   layer.mLeftEyeRect.width = aLeftEyeRect.width;
   layer.mLeftEyeRect.height = aLeftEyeRect.height;
   layer.mRightEyeRect.x = aRightEyeRect.x;
   layer.mRightEyeRect.y = aRightEyeRect.y;
   layer.mRightEyeRect.width = aRightEyeRect.width;
   layer.mRightEyeRect.height = aRightEyeRect.height;
 
   PushState(true);
-  sPushIndex++;
 
 #if defined(MOZ_WIDGET_ANDROID)
   PullState([&]() {
     return (mDisplayInfo.mDisplayState.mLastSubmittedFrameId >= aFrameId) ||
             mDisplayInfo.mDisplayState.mSuppressFrames ||
             !mDisplayInfo.mDisplayState.mIsConnected;
   });
 
--- a/gfx/vr/gfxVRExternal.h
+++ b/gfx/vr/gfxVRExternal.h
@@ -26,17 +26,16 @@ namespace gfx {
 class VRThread;
 
 namespace impl {
 
 class VRDisplayExternal : public VRDisplayHost
 {
 public:
   void ZeroSensor() override;
-  static int sPushIndex;
 
 protected:
   VRHMDSensorState GetSensorState() override;
   void StartPresentation() override;
   void StopPresentation() override;
   void StartVRNavigation() override;
   void StopVRNavigation(const TimeDuration& aTimeout) override;
 
--- a/gfx/vr/ipc/VRLayerChild.cpp
+++ b/gfx/vr/ipc/VRLayerChild.cpp
@@ -45,32 +45,48 @@ VRLayerChild::Initialize(dom::HTMLCanvas
     VRManagerChild *vrmc = VRManagerChild::Get();
     vrmc->RunFrameRequestCallbacks();
   } else {
     mCanvasElement = aCanvasElement;
   }
 }
 
 void
-VRLayerChild::SubmitFrame(uint64_t aFrameId)
+VRLayerChild::SubmitFrame(const VRDisplayInfo& aDisplayInfo)
 {
+  uint64_t frameId = aDisplayInfo.GetFrameId();
+
   // 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) {
+  if (!mCanvasElement || frameId == mLastSubmittedFrameId) {
     return;
   }
-  mLastSubmittedFrameId = aFrameId;
 
   // Keep the SharedSurfaceTextureClient alive long enough for
   // 1 extra frame, accomodating overlapped asynchronous rendering.
   mLastFrameTexture = mThisFrameTexture;
 
+#if defined(MOZ_WIDGET_ANDROID)
+  /**
+   * Do not blit WebGL to a SurfaceTexture until the last submitted frame is already processed
+   * and the new frame poses are ready. SurfaceTextures need to be released in the VR render thread 
+   * in order to allow to be used again in the WebGLContext GLScreenBuffer producer.
+   * Not doing so causes some freezes, crashes or other undefined behaviour.
+   */
+  if (!mThisFrameTexture || aDisplayInfo.mDisplayState.mLastSubmittedFrameId == mLastSubmittedFrameId) {
+      mThisFrameTexture = mCanvasElement->GetVRFrame();
+  }
+#else
   mThisFrameTexture = mCanvasElement->GetVRFrame();
+#endif // defined(MOZ_WIDGET_ANDROID)
+
+  mLastSubmittedFrameId = frameId;
+
   if (!mThisFrameTexture) {
     return;
   }
   VRManagerChild* vrmc = VRManagerChild::Get();
   layers::SyncObjectClient* syncObject = vrmc->GetSyncObject();
   mThisFrameTexture->SyncWithObject(syncObject);
   if (!gfxPlatform::GetPlatform()->DidRenderingDeviceReset()) {
     if (syncObject && syncObject->IsSyncObjectValid()) {
@@ -85,17 +101,17 @@ VRLayerChild::SubmitFrame(uint64_t aFram
   }
 
   layers::SurfaceDescriptor desc;
   if (!surf->ToSurfaceDescriptor(&desc)) {
     gfxCriticalError() << "SharedSurface::ToSurfaceDescriptor failed in VRLayerChild::SubmitFrame";
     return;
   }
 
-  SendSubmitFrame(desc, aFrameId, mLeftEyeRect, mRightEyeRect);
+  SendSubmitFrame(desc, frameId, mLeftEyeRect, mRightEyeRect);
 }
 
 bool
 VRLayerChild::IsIPCOpen()
 {
   return mIPCOpen;
 }
 
--- a/gfx/vr/ipc/VRLayerChild.h
+++ b/gfx/vr/ipc/VRLayerChild.h
@@ -32,17 +32,17 @@ class VRLayerChild : public PVRLayerChil
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VRLayerChild)
 
 public:
   static PVRLayerChild* CreateIPDLActor();
   static bool DestroyIPDLActor(PVRLayerChild* actor);
 
   void Initialize(dom::HTMLCanvasElement* aCanvasElement,
                   const gfx::Rect& aLeftEyeRect, const gfx::Rect& aRightEyeRect);
-  void SubmitFrame(uint64_t aFrameId);
+  void SubmitFrame(const VRDisplayInfo& aDisplayInfo);
   bool IsIPCOpen();
 
 private:
   VRLayerChild();
   virtual ~VRLayerChild();
   void ClearSurfaces();
   virtual void ActorDestroy(ActorDestroyReason aWhy) override;