summaryrefslogtreecommitdiffstats
path: root/gfx/vr/ipc
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/vr/ipc')
-rw-r--r--gfx/vr/ipc/PVRLayer.ipdl27
-rw-r--r--gfx/vr/ipc/PVRManager.ipdl86
-rw-r--r--gfx/vr/ipc/VRLayerChild.cpp86
-rw-r--r--gfx/vr/ipc/VRLayerChild.h53
-rw-r--r--gfx/vr/ipc/VRLayerParent.cpp59
-rw-r--r--gfx/vr/ipc/VRLayerParent.h43
-rw-r--r--gfx/vr/ipc/VRManagerChild.cpp593
-rw-r--r--gfx/vr/ipc/VRManagerChild.h185
-rw-r--r--gfx/vr/ipc/VRManagerParent.cpp332
-rw-r--r--gfx/vr/ipc/VRManagerParent.h118
-rw-r--r--gfx/vr/ipc/VRMessageUtils.h193
11 files changed, 1775 insertions, 0 deletions
diff --git a/gfx/vr/ipc/PVRLayer.ipdl b/gfx/vr/ipc/PVRLayer.ipdl
new file mode 100644
index 000000000..593fccdd4
--- /dev/null
+++ b/gfx/vr/ipc/PVRLayer.ipdl
@@ -0,0 +1,27 @@
+/* -*- 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 protocol PVRManager;
+include protocol PTexture;
+
+namespace mozilla {
+namespace gfx {
+
+async protocol PVRLayer
+{
+ manager PVRManager;
+
+parent:
+ async SubmitFrame(PTexture aTexture);
+ async Destroy();
+
+child:
+ async __delete__();
+};
+
+} // gfx
+} // mozilla
diff --git a/gfx/vr/ipc/PVRManager.ipdl b/gfx/vr/ipc/PVRManager.ipdl
new file mode 100644
index 000000000..65f114fba
--- /dev/null
+++ b/gfx/vr/ipc/PVRManager.ipdl
@@ -0,0 +1,86 @@
+/* -*- 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 PLayer;
+include protocol PTexture;
+include protocol PVRLayer;
+include LayersMessages;
+include GamepadEventTypes;
+
+include "VRMessageUtils.h";
+
+using struct mozilla::gfx::VRFieldOfView from "gfxVR.h";
+using struct mozilla::gfx::VRDisplayInfo from "gfxVR.h";
+using struct mozilla::gfx::VRSensorUpdate from "gfxVR.h";
+using struct mozilla::gfx::VRHMDSensorState from "gfxVR.h";
+using struct mozilla::gfx::VRControllerInfo from "gfxVR.h";
+using mozilla::layers::LayersBackend from "mozilla/layers/LayersTypes.h";
+using mozilla::layers::TextureFlags from "mozilla/layers/CompositorTypes.h";
+
+
+namespace mozilla {
+namespace gfx {
+
+/**
+ * The PVRManager protocol is used to enable communication of VR display
+ * enumeration and sensor state between the compositor thread and
+ * content threads/processes.
+ */
+sync protocol PVRManager
+{
+ manages PTexture;
+ manages PVRLayer;
+
+parent:
+ async PTexture(SurfaceDescriptor aSharedData, LayersBackend aBackend,
+ TextureFlags aTextureFlags, uint64_t aSerial);
+
+ async PVRLayer(uint32_t aDisplayID, float aLeftEyeX, float aLeftEyeY, float aLeftEyeWidth, float aLeftEyeHeight, float aRightEyeX, float aRightEyeY, float aRightEyeWidth, float aRightEyeHeight);
+
+ // (Re)Enumerate VR Displays. An updated list of VR displays will be returned
+ // asynchronously to children via UpdateDisplayInfo.
+ async RefreshDisplays();
+
+ // GetDisplays synchronously returns the VR displays that have already been
+ // enumerated by RefreshDisplays() but does not enumerate new ones.
+ sync GetDisplays() returns(VRDisplayInfo[] aDisplayInfo);
+
+ // Reset the sensor of the display identified by aDisplayID so that the current
+ // sensor state is the "Zero" position.
+ async ResetSensor(uint32_t aDisplayID);
+
+ sync GetSensorState(uint32_t aDisplayID) returns(VRHMDSensorState aState);
+ sync GetImmediateSensorState(uint32_t aDisplayID) returns(VRHMDSensorState aState);
+ sync SetHaveEventListener(bool aHaveEventListener);
+
+ async ControllerListenerAdded();
+ async ControllerListenerRemoved();
+ // GetControllers synchronously returns the VR controllers that have already been
+ // enumerated by RefreshVRControllers() but does not enumerate new ones.
+ sync GetControllers() returns(VRControllerInfo[] aControllerInfo);
+
+child:
+
+ async ParentAsyncMessages(AsyncParentMessageData[] aMessages);
+
+ // Notify children of updated VR display enumeration and details. This will
+ // be sent to all children when the parent receives RefreshDisplays, even
+ // if no changes have been detected. This ensures that Promises exposed
+ // through DOM calls are always resolved.
+ async UpdateDisplayInfo(VRDisplayInfo[] aDisplayUpdates);
+
+ async NotifyVSync();
+ async NotifyVRVSync(uint32_t aDisplayID);
+ async GamepadUpdate(GamepadChangeEvent aGamepadEvent);
+
+ async __delete__();
+
+};
+
+} // gfx
+} // mozilla
diff --git a/gfx/vr/ipc/VRLayerChild.cpp b/gfx/vr/ipc/VRLayerChild.cpp
new file mode 100644
index 000000000..cffe9c1f1
--- /dev/null
+++ b/gfx/vr/ipc/VRLayerChild.cpp
@@ -0,0 +1,86 @@
+/* -*- 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 "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"
+
+namespace mozilla {
+namespace gfx {
+
+VRLayerChild::VRLayerChild(uint32_t aVRDisplayID, VRManagerChild* aVRManagerChild)
+ : mVRDisplayID(aVRDisplayID)
+ , mCanvasElement(nullptr)
+ , mShSurfClient(nullptr)
+ , mFront(nullptr)
+{
+ MOZ_COUNT_CTOR(VRLayerChild);
+}
+
+VRLayerChild::~VRLayerChild()
+{
+ if (mCanvasElement) {
+ mCanvasElement->StopVRPresentation();
+ }
+
+ ClearSurfaces();
+
+ MOZ_COUNT_DTOR(VRLayerChild);
+}
+
+void
+VRLayerChild::Initialize(dom::HTMLCanvasElement* aCanvasElement)
+{
+ MOZ_ASSERT(aCanvasElement);
+ mCanvasElement = aCanvasElement;
+ mCanvasElement->StartVRPresentation();
+
+ VRManagerChild *vrmc = VRManagerChild::Get();
+ vrmc->RunFrameRequestCallbacks();
+}
+
+void
+VRLayerChild::SubmitFrame()
+{
+ if (!mCanvasElement) {
+ return;
+ }
+
+ mShSurfClient = mCanvasElement->GetVRFrame();
+ if (!mShSurfClient) {
+ return;
+ }
+
+ gl::SharedSurface* surf = mShSurfClient->Surf();
+ if (surf->mType == gl::SharedSurfaceType::Basic) {
+ gfxCriticalError() << "SharedSurfaceType::Basic not supported for WebVR";
+ return;
+ }
+
+ mFront = mShSurfClient;
+ mShSurfClient = nullptr;
+
+ mFront->SetAddedToCompositableClient();
+ VRManagerChild* vrmc = VRManagerChild::Get();
+ mFront->SyncWithObject(vrmc->GetSyncObject());
+ MOZ_ALWAYS_TRUE(mFront->InitIPDLActor(vrmc));
+
+ SendSubmitFrame(mFront->GetIPDLActor());
+}
+
+void
+VRLayerChild::ClearSurfaces()
+{
+ mFront = nullptr;
+ mShSurfClient = nullptr;
+}
+
+} // namespace gfx
+} // namespace mozilla
diff --git a/gfx/vr/ipc/VRLayerChild.h b/gfx/vr/ipc/VRLayerChild.h
new file mode 100644
index 000000000..df42dddac
--- /dev/null
+++ b/gfx/vr/ipc/VRLayerChild.h
@@ -0,0 +1,53 @@
+/* -*- 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/. */
+
+#ifndef GFX_VR_LAYERCHILD_H
+#define GFX_VR_LAYERCHILD_H
+
+#include "VRManagerChild.h"
+
+#include "mozilla/RefPtr.h"
+#include "mozilla/gfx/PVRLayerChild.h"
+#include "GLContext.h"
+#include "gfxVR.h"
+
+class nsICanvasRenderingContextInternal;
+
+namespace mozilla {
+class WebGLContext;
+namespace dom {
+class HTMLCanvasElement;
+}
+namespace layers {
+class SharedSurfaceTextureClient;
+}
+namespace gl {
+class SurfaceFactory;
+}
+namespace gfx {
+
+class VRLayerChild : public PVRLayerChild {
+ NS_INLINE_DECL_REFCOUNTING(VRLayerChild)
+
+public:
+ VRLayerChild(uint32_t aVRDisplayID, VRManagerChild* aVRManagerChild);
+ void Initialize(dom::HTMLCanvasElement* aCanvasElement);
+ void SubmitFrame();
+
+protected:
+ virtual ~VRLayerChild();
+ void ClearSurfaces();
+
+ uint32_t mVRDisplayID;
+
+ RefPtr<dom::HTMLCanvasElement> mCanvasElement;
+ RefPtr<layers::SharedSurfaceTextureClient> mShSurfClient;
+ RefPtr<layers::TextureClient> mFront;
+};
+
+} // namespace gfx
+} // namespace mozilla
+
+#endif
diff --git a/gfx/vr/ipc/VRLayerParent.cpp b/gfx/vr/ipc/VRLayerParent.cpp
new file mode 100644
index 000000000..6c6980817
--- /dev/null
+++ b/gfx/vr/ipc/VRLayerParent.cpp
@@ -0,0 +1,59 @@
+/* -*- 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"
+
+namespace mozilla {
+namespace gfx {
+
+VRLayerParent::VRLayerParent(uint32_t aVRDisplayID, const Rect& aLeftEyeRect, const Rect& aRightEyeRect)
+ : mIPCOpen(true)
+ , mVRDisplayID(aVRDisplayID)
+ , mLeftEyeRect(aLeftEyeRect)
+ , mRightEyeRect(aRightEyeRect)
+{
+ MOZ_COUNT_CTOR(VRLayerParent);
+}
+
+VRLayerParent::~VRLayerParent()
+{
+ MOZ_COUNT_DTOR(VRLayerParent);
+}
+
+bool
+VRLayerParent::RecvDestroy()
+{
+ Destroy();
+ return true;
+}
+
+void
+VRLayerParent::ActorDestroy(ActorDestroyReason aWhy)
+{
+ mIPCOpen = false;
+}
+
+void
+VRLayerParent::Destroy()
+{
+ if (mIPCOpen) {
+ Unused << PVRLayerParent::Send__delete__(this);
+ }
+}
+
+bool
+VRLayerParent::RecvSubmitFrame(PTextureParent* texture)
+{
+ VRManager* vm = VRManager::Get();
+ vm->SubmitFrame(this, texture, mLeftEyeRect, mRightEyeRect);
+
+ return true;
+}
+
+
+} // namespace gfx
+} // namespace mozilla
diff --git a/gfx/vr/ipc/VRLayerParent.h b/gfx/vr/ipc/VRLayerParent.h
new file mode 100644
index 000000000..bd69c9546
--- /dev/null
+++ b/gfx/vr/ipc/VRLayerParent.h
@@ -0,0 +1,43 @@
+/* -*- 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/. */
+
+#ifndef GFX_VR_LAYERPARENT_H
+#define GFX_VR_LAYERPARENT_H
+
+#include "VRManager.h"
+
+#include "mozilla/RefPtr.h"
+#include "mozilla/gfx/PVRLayerParent.h"
+#include "gfxVR.h"
+
+namespace mozilla {
+namespace gfx {
+
+class VRLayerParent : public PVRLayerParent {
+ NS_INLINE_DECL_REFCOUNTING(VRLayerParent)
+
+public:
+ VRLayerParent(uint32_t aVRDisplayID, const Rect& aLeftEyeRect, const Rect& aRightEyeRect);
+ virtual bool RecvSubmitFrame(PTextureParent* texture) override;
+ virtual bool RecvDestroy() override;
+ uint32_t GetDisplayID() const { return mVRDisplayID; }
+protected:
+ virtual void ActorDestroy(ActorDestroyReason aWhy) override;
+
+ virtual ~VRLayerParent();
+ void Destroy();
+
+ bool mIPCOpen;
+
+ uint32_t mVRDisplayID;
+ gfx::IntSize mSize;
+ gfx::Rect mLeftEyeRect;
+ gfx::Rect mRightEyeRect;
+};
+
+} // namespace gfx
+} // namespace mozilla
+
+#endif
diff --git a/gfx/vr/ipc/VRManagerChild.cpp b/gfx/vr/ipc/VRManagerChild.cpp
new file mode 100644
index 000000000..70ced86c3
--- /dev/null
+++ b/gfx/vr/ipc/VRManagerChild.cpp
@@ -0,0 +1,593 @@
+/* -*- 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 "VRManagerChild.h"
+#include "VRManagerParent.h"
+#include "VRDisplayClient.h"
+#include "nsGlobalWindow.h"
+#include "mozilla/StaticPtr.h"
+#include "mozilla/layers/CompositorThread.h" // for CompositorThread
+#include "mozilla/dom/Navigator.h"
+#include "mozilla/dom/VREventObserver.h"
+#include "mozilla/dom/WindowBinding.h" // for FrameRequestCallback
+#include "mozilla/dom/ContentChild.h"
+#include "mozilla/layers/TextureClient.h"
+#include "nsContentUtils.h"
+
+#ifdef MOZ_GAMEPAD
+#include "mozilla/dom/GamepadManager.h"
+#endif
+
+using layers::TextureClient;
+
+namespace {
+const nsTArray<RefPtr<dom::VREventObserver>>::index_type kNoIndex =
+ nsTArray<RefPtr<dom::VREventObserver> >::NoIndex;
+} // namespace
+
+namespace mozilla {
+namespace gfx {
+
+static StaticRefPtr<VRManagerChild> sVRManagerChildSingleton;
+static StaticRefPtr<VRManagerParent> sVRManagerParentSingleton;
+
+void ReleaseVRManagerParentSingleton() {
+ sVRManagerParentSingleton = nullptr;
+}
+
+VRManagerChild::VRManagerChild()
+ : TextureForwarder()
+ , mDisplaysInitialized(false)
+ , mInputFrameID(-1)
+ , mMessageLoop(MessageLoop::current())
+ , mFrameRequestCallbackCounter(0)
+ , mBackend(layers::LayersBackend::LAYERS_NONE)
+{
+ MOZ_COUNT_CTOR(VRManagerChild);
+ MOZ_ASSERT(NS_IsMainThread());
+
+ mStartTimeStamp = TimeStamp::Now();
+}
+
+VRManagerChild::~VRManagerChild()
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ MOZ_COUNT_DTOR(VRManagerChild);
+}
+
+/*static*/ void
+VRManagerChild::IdentifyTextureHost(const TextureFactoryIdentifier& aIdentifier)
+{
+ if (sVRManagerChildSingleton) {
+ sVRManagerChildSingleton->mBackend = aIdentifier.mParentBackend;
+ sVRManagerChildSingleton->mSyncObject = SyncObject::CreateSyncObject(aIdentifier.mSyncHandle);
+ }
+}
+
+layers::LayersBackend
+VRManagerChild::GetBackendType() const
+{
+ return mBackend;
+}
+
+/*static*/ VRManagerChild*
+VRManagerChild::Get()
+{
+ MOZ_ASSERT(sVRManagerChildSingleton);
+ return sVRManagerChildSingleton;
+}
+
+/* static */ bool
+VRManagerChild::IsCreated()
+{
+ return !!sVRManagerChildSingleton;
+}
+
+/* static */ bool
+VRManagerChild::InitForContent(Endpoint<PVRManagerChild>&& aEndpoint)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ MOZ_ASSERT(!sVRManagerChildSingleton);
+
+ RefPtr<VRManagerChild> child(new VRManagerChild());
+ if (!aEndpoint.Bind(child)) {
+ NS_RUNTIMEABORT("Couldn't Open() Compositor channel.");
+ return false;
+ }
+ sVRManagerChildSingleton = child;
+ return true;
+}
+
+/* static */ bool
+VRManagerChild::ReinitForContent(Endpoint<PVRManagerChild>&& aEndpoint)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+
+ ShutDown();
+
+ return InitForContent(Move(aEndpoint));
+}
+
+/*static*/ void
+VRManagerChild::InitSameProcess()
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ MOZ_ASSERT(!sVRManagerChildSingleton);
+
+ sVRManagerChildSingleton = new VRManagerChild();
+ sVRManagerParentSingleton = VRManagerParent::CreateSameProcess();
+ sVRManagerChildSingleton->Open(sVRManagerParentSingleton->GetIPCChannel(),
+ mozilla::layers::CompositorThreadHolder::Loop(),
+ mozilla::ipc::ChildSide);
+}
+
+/* static */ void
+VRManagerChild::InitWithGPUProcess(Endpoint<PVRManagerChild>&& aEndpoint)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ MOZ_ASSERT(!sVRManagerChildSingleton);
+
+ sVRManagerChildSingleton = new VRManagerChild();
+ if (!aEndpoint.Bind(sVRManagerChildSingleton)) {
+ NS_RUNTIMEABORT("Couldn't Open() Compositor channel.");
+ return;
+ }
+}
+
+/*static*/ void
+VRManagerChild::ShutDown()
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ if (sVRManagerChildSingleton) {
+ sVRManagerChildSingleton->Destroy();
+ sVRManagerChildSingleton = nullptr;
+ }
+}
+
+/*static*/ void
+VRManagerChild::DeferredDestroy(RefPtr<VRManagerChild> aVRManagerChild)
+{
+ aVRManagerChild->Close();
+}
+
+void
+VRManagerChild::Destroy()
+{
+ mTexturesWaitingRecycled.Clear();
+
+ // Keep ourselves alive until everything has been shut down
+ RefPtr<VRManagerChild> selfRef = this;
+
+ // The DeferredDestroyVRManager task takes ownership of
+ // the VRManagerChild and will release it when it runs.
+ MessageLoop::current()->PostTask(
+ NewRunnableFunction(DeferredDestroy, selfRef));
+}
+
+layers::PTextureChild*
+VRManagerChild::AllocPTextureChild(const SurfaceDescriptor&,
+ const LayersBackend&,
+ const TextureFlags&,
+ const uint64_t&)
+{
+ return TextureClient::CreateIPDLActor();
+}
+
+bool
+VRManagerChild::DeallocPTextureChild(PTextureChild* actor)
+{
+ return TextureClient::DestroyIPDLActor(actor);
+}
+
+PVRLayerChild*
+VRManagerChild::AllocPVRLayerChild(const uint32_t& aDisplayID,
+ const float& aLeftEyeX,
+ const float& aLeftEyeY,
+ const float& aLeftEyeWidth,
+ const float& aLeftEyeHeight,
+ const float& aRightEyeX,
+ const float& aRightEyeY,
+ const float& aRightEyeWidth,
+ const float& aRightEyeHeight)
+{
+ RefPtr<VRLayerChild> layer = new VRLayerChild(aDisplayID, this);
+ return layer.forget().take();
+}
+
+bool
+VRManagerChild::DeallocPVRLayerChild(PVRLayerChild* actor)
+{
+ delete actor;
+ return true;
+}
+
+void
+VRManagerChild::UpdateDisplayInfo(nsTArray<VRDisplayInfo>& aDisplayUpdates)
+{
+ bool bDisplayConnected = false;
+ bool bDisplayDisconnected = false;
+
+ // Check if any displays have been disconnected
+ for (auto& display : mDisplays) {
+ bool found = false;
+ for (auto& displayUpdate : aDisplayUpdates) {
+ if (display->GetDisplayInfo().GetDisplayID() == displayUpdate.GetDisplayID()) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ display->NotifyDisconnected();
+ bDisplayDisconnected = true;
+ }
+ }
+
+ // mDisplays could be a hashed container for more scalability, but not worth
+ // it now as we expect < 10 entries.
+ nsTArray<RefPtr<VRDisplayClient>> displays;
+ for (VRDisplayInfo& displayUpdate : aDisplayUpdates) {
+ bool isNewDisplay = true;
+ for (auto& display : mDisplays) {
+ const VRDisplayInfo& prevInfo = display->GetDisplayInfo();
+ if (prevInfo.GetDisplayID() == displayUpdate.GetDisplayID()) {
+ if (displayUpdate.GetIsConnected() && !prevInfo.GetIsConnected()) {
+ bDisplayConnected = true;
+ }
+ if (!displayUpdate.GetIsConnected() && prevInfo.GetIsConnected()) {
+ bDisplayDisconnected = true;
+ }
+ display->UpdateDisplayInfo(displayUpdate);
+ displays.AppendElement(display);
+ isNewDisplay = false;
+ break;
+ }
+ }
+ if (isNewDisplay) {
+ displays.AppendElement(new VRDisplayClient(displayUpdate));
+ bDisplayConnected = true;
+ }
+ }
+
+ mDisplays = displays;
+
+ if (bDisplayConnected) {
+ FireDOMVRDisplayConnectEvent();
+ }
+ if (bDisplayDisconnected) {
+ FireDOMVRDisplayDisconnectEvent();
+ }
+
+ mDisplaysInitialized = true;
+}
+
+bool
+VRManagerChild::RecvUpdateDisplayInfo(nsTArray<VRDisplayInfo>&& aDisplayUpdates)
+{
+ UpdateDisplayInfo(aDisplayUpdates);
+ for (auto& windowId : mNavigatorCallbacks) {
+ /** We must call NotifyVRDisplaysUpdated for every
+ * window's Navigator in mNavigatorCallbacks to ensure that
+ * the promise returned by Navigator.GetVRDevices
+ * can resolve. This must happen even if no changes
+ * to VRDisplays have been detected here.
+ */
+ nsGlobalWindow* window = nsGlobalWindow::GetInnerWindowWithId(windowId);
+ if (!window) {
+ continue;
+ }
+ ErrorResult result;
+ dom::Navigator* nav = window->GetNavigator(result);
+ if (NS_WARN_IF(result.Failed())) {
+ continue;
+ }
+ nav->NotifyVRDisplaysUpdated();
+ }
+ mNavigatorCallbacks.Clear();
+ return true;
+}
+
+bool
+VRManagerChild::GetVRDisplays(nsTArray<RefPtr<VRDisplayClient>>& aDisplays)
+{
+ if (!mDisplaysInitialized) {
+ /**
+ * If we haven't received any asynchronous callback after requesting
+ * display enumeration with RefreshDisplays, get the existing displays
+ * that have already been enumerated by other VRManagerChild instances.
+ */
+ nsTArray<VRDisplayInfo> displays;
+ Unused << SendGetDisplays(&displays);
+ UpdateDisplayInfo(displays);
+ }
+ aDisplays = mDisplays;
+ return true;
+}
+
+bool
+VRManagerChild::RefreshVRDisplaysWithCallback(uint64_t aWindowId)
+{
+ bool success = SendRefreshDisplays();
+ if (success) {
+ mNavigatorCallbacks.AppendElement(aWindowId);
+ }
+ return success;
+}
+
+int
+VRManagerChild::GetInputFrameID()
+{
+ return mInputFrameID;
+}
+
+bool
+VRManagerChild::RecvParentAsyncMessages(InfallibleTArray<AsyncParentMessageData>&& aMessages)
+{
+ for (InfallibleTArray<AsyncParentMessageData>::index_type i = 0; i < aMessages.Length(); ++i) {
+ const AsyncParentMessageData& message = aMessages[i];
+
+ switch (message.type()) {
+ case AsyncParentMessageData::TOpNotifyNotUsed: {
+ const OpNotifyNotUsed& op = message.get_OpNotifyNotUsed();
+ NotifyNotUsed(op.TextureId(), op.fwdTransactionId());
+ break;
+ }
+ default:
+ NS_ERROR("unknown AsyncParentMessageData type");
+ return false;
+ }
+ }
+ return true;
+}
+
+PTextureChild*
+VRManagerChild::CreateTexture(const SurfaceDescriptor& aSharedData,
+ LayersBackend aLayersBackend,
+ TextureFlags aFlags,
+ uint64_t aSerial)
+{
+ return SendPTextureConstructor(aSharedData, aLayersBackend, aFlags, aSerial);
+}
+
+void
+VRManagerChild::CancelWaitForRecycle(uint64_t aTextureId)
+{
+ RefPtr<TextureClient> client = mTexturesWaitingRecycled.Get(aTextureId);
+ if (!client) {
+ return;
+ }
+ mTexturesWaitingRecycled.Remove(aTextureId);
+}
+
+void
+VRManagerChild::NotifyNotUsed(uint64_t aTextureId, uint64_t aFwdTransactionId)
+{
+ RefPtr<TextureClient> client = mTexturesWaitingRecycled.Get(aTextureId);
+ if (!client) {
+ return;
+ }
+ mTexturesWaitingRecycled.Remove(aTextureId);
+}
+
+bool
+VRManagerChild::AllocShmem(size_t aSize,
+ ipc::SharedMemory::SharedMemoryType aType,
+ ipc::Shmem* aShmem)
+{
+ return PVRManagerChild::AllocShmem(aSize, aType, aShmem);
+}
+
+bool
+VRManagerChild::AllocUnsafeShmem(size_t aSize,
+ ipc::SharedMemory::SharedMemoryType aType,
+ ipc::Shmem* aShmem)
+{
+ return PVRManagerChild::AllocUnsafeShmem(aSize, aType, aShmem);
+}
+
+bool
+VRManagerChild::DeallocShmem(ipc::Shmem& aShmem)
+{
+ return PVRManagerChild::DeallocShmem(aShmem);
+}
+
+PVRLayerChild*
+VRManagerChild::CreateVRLayer(uint32_t aDisplayID, const Rect& aLeftEyeRect, const Rect& aRightEyeRect)
+{
+ return SendPVRLayerConstructor(aDisplayID,
+ aLeftEyeRect.x, aLeftEyeRect.y, aLeftEyeRect.width, aLeftEyeRect.height,
+ aRightEyeRect.x, aRightEyeRect.y, aRightEyeRect.width, aRightEyeRect.height);
+}
+
+
+// XXX TODO - VRManagerChild::FrameRequest is the same as nsIDocument::FrameRequest, should we consolodate these?
+struct VRManagerChild::FrameRequest
+{
+ FrameRequest(mozilla::dom::FrameRequestCallback& aCallback,
+ int32_t aHandle) :
+ mCallback(&aCallback),
+ mHandle(aHandle)
+ {}
+
+ // Conversion operator so that we can append these to a
+ // FrameRequestCallbackList
+ operator const RefPtr<mozilla::dom::FrameRequestCallback>& () const {
+ return mCallback;
+ }
+
+ // Comparator operators to allow RemoveElementSorted with an
+ // integer argument on arrays of FrameRequest
+ bool operator==(int32_t aHandle) const {
+ return mHandle == aHandle;
+ }
+ bool operator<(int32_t aHandle) const {
+ return mHandle < aHandle;
+ }
+
+ RefPtr<mozilla::dom::FrameRequestCallback> mCallback;
+ int32_t mHandle;
+};
+
+nsresult
+VRManagerChild::ScheduleFrameRequestCallback(mozilla::dom::FrameRequestCallback& aCallback,
+ int32_t *aHandle)
+{
+ if (mFrameRequestCallbackCounter == INT32_MAX) {
+ // Can't increment without overflowing; bail out
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+ int32_t newHandle = ++mFrameRequestCallbackCounter;
+
+ DebugOnly<FrameRequest*> request =
+ mFrameRequestCallbacks.AppendElement(FrameRequest(aCallback, newHandle));
+ NS_ASSERTION(request, "This is supposed to be infallible!");
+
+ *aHandle = newHandle;
+ return NS_OK;
+}
+
+void
+VRManagerChild::CancelFrameRequestCallback(int32_t aHandle)
+{
+ // mFrameRequestCallbacks is stored sorted by handle
+ mFrameRequestCallbacks.RemoveElementSorted(aHandle);
+}
+
+bool
+VRManagerChild::RecvNotifyVSync()
+{
+ for (auto& display : mDisplays) {
+ display->NotifyVsync();
+ }
+
+ return true;
+}
+
+bool
+VRManagerChild::RecvNotifyVRVSync(const uint32_t& aDisplayID)
+{
+ for (auto& display : mDisplays) {
+ if (display->GetDisplayInfo().GetDisplayID() == aDisplayID) {
+ display->NotifyVRVsync();
+ }
+ }
+
+ return true;
+}
+
+bool
+VRManagerChild::RecvGamepadUpdate(const GamepadChangeEvent& aGamepadEvent)
+{
+#ifdef MOZ_GAMEPAD
+ // VRManagerChild could be at other processes, but GamepadManager
+ // only exists at the content process or the same process
+ // in non-e10s mode.
+ MOZ_ASSERT(XRE_IsContentProcess() || IsSameProcess());
+
+ RefPtr<GamepadManager> gamepadManager(GamepadManager::GetService());
+ if (gamepadManager) {
+ gamepadManager->Update(aGamepadEvent);
+ }
+#endif
+
+ return true;
+}
+
+void
+VRManagerChild::RunFrameRequestCallbacks()
+{
+ TimeStamp nowTime = TimeStamp::Now();
+ mozilla::TimeDuration duration = nowTime - mStartTimeStamp;
+ DOMHighResTimeStamp timeStamp = duration.ToMilliseconds();
+
+
+ nsTArray<FrameRequest> callbacks;
+ callbacks.AppendElements(mFrameRequestCallbacks);
+ mFrameRequestCallbacks.Clear();
+ for (auto& callback : callbacks) {
+ callback.mCallback->Call(timeStamp);
+ }
+}
+
+void
+VRManagerChild::FireDOMVRDisplayConnectEvent()
+{
+ nsContentUtils::AddScriptRunner(NewRunnableMethod(this,
+ &VRManagerChild::FireDOMVRDisplayConnectEventInternal));
+}
+
+void
+VRManagerChild::FireDOMVRDisplayDisconnectEvent()
+{
+ nsContentUtils::AddScriptRunner(NewRunnableMethod(this,
+ &VRManagerChild::FireDOMVRDisplayDisconnectEventInternal));
+}
+
+void
+VRManagerChild::FireDOMVRDisplayPresentChangeEvent()
+{
+ nsContentUtils::AddScriptRunner(NewRunnableMethod(this,
+ &VRManagerChild::FireDOMVRDisplayPresentChangeEventInternal));
+}
+
+void
+VRManagerChild::FireDOMVRDisplayConnectEventInternal()
+{
+ for (auto& listener : mListeners) {
+ listener->NotifyVRDisplayConnect();
+ }
+}
+
+void
+VRManagerChild::FireDOMVRDisplayDisconnectEventInternal()
+{
+ for (auto& listener : mListeners) {
+ listener->NotifyVRDisplayDisconnect();
+ }
+}
+
+void
+VRManagerChild::FireDOMVRDisplayPresentChangeEventInternal()
+{
+ for (auto& listener : mListeners) {
+ listener->NotifyVRDisplayPresentChange();
+ }
+}
+
+void
+VRManagerChild::AddListener(dom::VREventObserver* aObserver)
+{
+ MOZ_ASSERT(aObserver);
+
+ if (mListeners.IndexOf(aObserver) != kNoIndex) {
+ return; // already exists
+ }
+
+ mListeners.AppendElement(aObserver);
+ if (mListeners.Length() == 1) {
+ Unused << SendSetHaveEventListener(true);
+ }
+}
+
+void
+VRManagerChild::RemoveListener(dom::VREventObserver* aObserver)
+{
+ MOZ_ASSERT(aObserver);
+
+ mListeners.RemoveElement(aObserver);
+ if (mListeners.IsEmpty()) {
+ Unused << SendSetHaveEventListener(false);
+ }
+}
+
+void
+VRManagerChild::HandleFatalError(const char* aName, const char* aMsg) const
+{
+ dom::ContentChild::FatalErrorIfNotUsingGPUProcess(aName, aMsg, OtherPid());
+}
+
+} // namespace gfx
+} // namespace mozilla
diff --git a/gfx/vr/ipc/VRManagerChild.h b/gfx/vr/ipc/VRManagerChild.h
new file mode 100644
index 000000000..c898cd2f8
--- /dev/null
+++ b/gfx/vr/ipc/VRManagerChild.h
@@ -0,0 +1,185 @@
+/* -*- 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/. */
+
+#ifndef MOZILLA_GFX_VR_VRMANAGERCHILD_H
+#define MOZILLA_GFX_VR_VRMANAGERCHILD_H
+
+#include "mozilla/gfx/PVRManagerChild.h"
+#include "mozilla/ipc/SharedMemory.h" // for SharedMemory, etc
+#include "ThreadSafeRefcountingWithMainThreadDestruction.h"
+#include "mozilla/layers/ISurfaceAllocator.h" // for ISurfaceAllocator
+#include "mozilla/layers/LayersTypes.h" // for LayersBackend
+#include "mozilla/layers/TextureForwarder.h"
+
+namespace mozilla {
+namespace dom {
+class GamepadManager;
+class Navigator;
+class VRDisplay;
+class VREventObserver;
+} // namespace dom
+namespace layers {
+class PCompositableChild;
+class TextureClient;
+}
+namespace gfx {
+class VRLayerChild;
+class VRDisplayClient;
+
+class VRManagerChild : public PVRManagerChild
+ , public layers::TextureForwarder
+ , public layers::KnowsCompositor
+{
+public:
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VRManagerChild, override);
+
+ TextureForwarder* GetTextureForwarder() override { return this; }
+ LayersIPCActor* GetLayersIPCActor() override { return this; }
+
+ static VRManagerChild* Get();
+
+ // Indicate that an observer wants to receive VR events.
+ void AddListener(dom::VREventObserver* aObserver);
+ // Indicate that an observer should no longer receive VR events.
+ void RemoveListener(dom::VREventObserver* aObserver);
+
+ int GetInputFrameID();
+ bool GetVRDisplays(nsTArray<RefPtr<VRDisplayClient> >& aDisplays);
+ bool RefreshVRDisplaysWithCallback(uint64_t aWindowId);
+
+ static void InitSameProcess();
+ static void InitWithGPUProcess(Endpoint<PVRManagerChild>&& aEndpoint);
+ static bool InitForContent(Endpoint<PVRManagerChild>&& aEndpoint);
+ static bool ReinitForContent(Endpoint<PVRManagerChild>&& aEndpoint);
+ static void ShutDown();
+
+ static bool IsCreated();
+
+ virtual PTextureChild* CreateTexture(const SurfaceDescriptor& aSharedData,
+ layers::LayersBackend aLayersBackend,
+ TextureFlags aFlags,
+ uint64_t aSerial) override;
+ virtual void CancelWaitForRecycle(uint64_t aTextureId) override;
+
+ PVRLayerChild* CreateVRLayer(uint32_t aDisplayID, const Rect& aLeftEyeRect, const Rect& aRightEyeRect);
+
+ static void IdentifyTextureHost(const layers::TextureFactoryIdentifier& aIdentifier);
+ layers::LayersBackend GetBackendType() const;
+ layers::SyncObject* GetSyncObject() { return mSyncObject; }
+
+ virtual MessageLoop* GetMessageLoop() const override { return mMessageLoop; }
+ virtual base::ProcessId GetParentPid() const override { return OtherPid(); }
+
+ nsresult ScheduleFrameRequestCallback(mozilla::dom::FrameRequestCallback& aCallback,
+ int32_t *aHandle);
+ void CancelFrameRequestCallback(int32_t aHandle);
+ void RunFrameRequestCallbacks();
+
+ void UpdateDisplayInfo(nsTArray<VRDisplayInfo>& aDisplayUpdates);
+ void FireDOMVRDisplayConnectEvent();
+ void FireDOMVRDisplayDisconnectEvent();
+ void FireDOMVRDisplayPresentChangeEvent();
+
+ virtual void HandleFatalError(const char* aName, const char* aMsg) const override;
+
+protected:
+ explicit VRManagerChild();
+ ~VRManagerChild();
+ void Destroy();
+ static void DeferredDestroy(RefPtr<VRManagerChild> aVRManagerChild);
+
+ virtual PTextureChild* AllocPTextureChild(const SurfaceDescriptor& aSharedData,
+ const layers::LayersBackend& aLayersBackend,
+ const TextureFlags& aFlags,
+ const uint64_t& aSerial) override;
+ virtual bool DeallocPTextureChild(PTextureChild* actor) override;
+
+ virtual PVRLayerChild* AllocPVRLayerChild(const uint32_t& aDisplayID,
+ const float& aLeftEyeX,
+ const float& aLeftEyeY,
+ const float& aLeftEyeWidth,
+ const float& aLeftEyeHeight,
+ const float& aRightEyeX,
+ const float& aRightEyeY,
+ const float& aRightEyeWidth,
+ const float& aRightEyeHeight) override;
+ virtual bool DeallocPVRLayerChild(PVRLayerChild* actor) override;
+
+ virtual bool RecvUpdateDisplayInfo(nsTArray<VRDisplayInfo>&& aDisplayUpdates) override;
+
+ virtual bool RecvParentAsyncMessages(InfallibleTArray<AsyncParentMessageData>&& aMessages) override;
+
+ virtual bool RecvNotifyVSync() override;
+ virtual bool RecvNotifyVRVSync(const uint32_t& aDisplayID) override;
+ virtual bool RecvGamepadUpdate(const GamepadChangeEvent& aGamepadEvent) override;
+
+ // ShmemAllocator
+
+ virtual bool AllocShmem(size_t aSize,
+ ipc::SharedMemory::SharedMemoryType aType,
+ ipc::Shmem* aShmem) override;
+
+ virtual bool AllocUnsafeShmem(size_t aSize,
+ ipc::SharedMemory::SharedMemoryType aType,
+ ipc::Shmem* aShmem) override;
+
+ virtual bool DeallocShmem(ipc::Shmem& aShmem) override;
+
+ virtual bool IsSameProcess() const override
+ {
+ return OtherPid() == base::GetCurrentProcId();
+ }
+
+ friend class layers::CompositorBridgeChild;
+
+private:
+
+ void FireDOMVRDisplayConnectEventInternal();
+ void FireDOMVRDisplayDisconnectEventInternal();
+ void FireDOMVRDisplayPresentChangeEventInternal();
+ /**
+ * Notify id of Texture When host side end its use. Transaction id is used to
+ * make sure if there is no newer usage.
+ */
+ void NotifyNotUsed(uint64_t aTextureId, uint64_t aFwdTransactionId);
+
+ nsTArray<RefPtr<VRDisplayClient> > mDisplays;
+ bool mDisplaysInitialized;
+ nsTArray<uint64_t> mNavigatorCallbacks;
+
+ int32_t mInputFrameID;
+
+ MessageLoop* mMessageLoop;
+
+ struct FrameRequest;
+
+ nsTArray<FrameRequest> mFrameRequestCallbacks;
+ /**
+ * The current frame request callback handle
+ */
+ int32_t mFrameRequestCallbackCounter;
+ mozilla::TimeStamp mStartTimeStamp;
+
+ // Array of Weak pointers, instance is owned by nsGlobalWindow::mVREventObserver.
+ nsTArray<dom::VREventObserver*> mListeners;
+
+ /**
+ * Hold TextureClients refs until end of their usages on host side.
+ * It defer calling of TextureClient recycle callback.
+ */
+ nsDataHashtable<nsUint64HashKey, RefPtr<layers::TextureClient> > mTexturesWaitingRecycled;
+
+ layers::LayersBackend mBackend;
+ RefPtr<layers::SyncObject> mSyncObject;
+
+ DISALLOW_COPY_AND_ASSIGN(VRManagerChild);
+};
+
+} // namespace mozilla
+} // namespace gfx
+
+#endif // MOZILLA_GFX_VR_VRMANAGERCHILD_H
diff --git a/gfx/vr/ipc/VRManagerParent.cpp b/gfx/vr/ipc/VRManagerParent.cpp
new file mode 100644
index 000000000..725d7dd1d
--- /dev/null
+++ b/gfx/vr/ipc/VRManagerParent.cpp
@@ -0,0 +1,332 @@
+/* -*- 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 "VRManagerParent.h"
+#include "ipc/VRLayerParent.h"
+#include "mozilla/gfx/PVRManagerParent.h"
+#include "mozilla/ipc/ProtocolTypes.h"
+#include "mozilla/ipc/ProtocolUtils.h" // for IToplevelProtocol
+#include "mozilla/TimeStamp.h" // for TimeStamp
+#include "mozilla/layers/CompositorThread.h"
+#include "mozilla/Unused.h"
+#include "VRManager.h"
+
+namespace mozilla {
+using namespace layers;
+namespace gfx {
+
+VRManagerParent::VRManagerParent(ProcessId aChildProcessId, bool aIsContentChild)
+ : HostIPCAllocator()
+ , mHaveEventListener(false)
+ , mIsContentChild(aIsContentChild)
+{
+ MOZ_COUNT_CTOR(VRManagerParent);
+ MOZ_ASSERT(NS_IsMainThread());
+
+ SetOtherProcessId(aChildProcessId);
+}
+
+VRManagerParent::~VRManagerParent()
+{
+ MOZ_ASSERT(!mVRManagerHolder);
+
+ MOZ_COUNT_DTOR(VRManagerParent);
+}
+
+PTextureParent*
+VRManagerParent::AllocPTextureParent(const SurfaceDescriptor& aSharedData,
+ const LayersBackend& aLayersBackend,
+ const TextureFlags& aFlags,
+ const uint64_t& aSerial)
+{
+ return layers::TextureHost::CreateIPDLActor(this, aSharedData, aLayersBackend, aFlags, aSerial);
+}
+
+bool
+VRManagerParent::DeallocPTextureParent(PTextureParent* actor)
+{
+ return layers::TextureHost::DestroyIPDLActor(actor);
+}
+
+PVRLayerParent*
+VRManagerParent::AllocPVRLayerParent(const uint32_t& aDisplayID,
+ const float& aLeftEyeX,
+ const float& aLeftEyeY,
+ const float& aLeftEyeWidth,
+ const float& aLeftEyeHeight,
+ const float& aRightEyeX,
+ const float& aRightEyeY,
+ const float& aRightEyeWidth,
+ const float& aRightEyeHeight)
+{
+ RefPtr<VRLayerParent> layer;
+ layer = new VRLayerParent(aDisplayID,
+ Rect(aLeftEyeX, aLeftEyeY, aLeftEyeWidth, aLeftEyeHeight),
+ Rect(aRightEyeX, aRightEyeY, aRightEyeWidth, aRightEyeHeight));
+ VRManager* vm = VRManager::Get();
+ RefPtr<gfx::VRDisplayHost> display = vm->GetDisplay(aDisplayID);
+ if (display) {
+ display->AddLayer(layer);
+ }
+ return layer.forget().take();
+}
+
+bool
+VRManagerParent::DeallocPVRLayerParent(PVRLayerParent* actor)
+{
+ gfx::VRLayerParent* layer = static_cast<gfx::VRLayerParent*>(actor);
+
+ VRManager* vm = VRManager::Get();
+ RefPtr<gfx::VRDisplayHost> display = vm->GetDisplay(layer->GetDisplayID());
+ if (display) {
+ display->RemoveLayer(layer);
+ }
+
+ delete actor;
+ return true;
+}
+
+bool
+VRManagerParent::AllocShmem(size_t aSize,
+ ipc::SharedMemory::SharedMemoryType aType,
+ ipc::Shmem* aShmem)
+{
+ return PVRManagerParent::AllocShmem(aSize, aType, aShmem);
+}
+
+bool
+VRManagerParent::AllocUnsafeShmem(size_t aSize,
+ ipc::SharedMemory::SharedMemoryType aType,
+ ipc::Shmem* aShmem)
+{
+ return PVRManagerParent::AllocUnsafeShmem(aSize, aType, aShmem);
+}
+
+void
+VRManagerParent::DeallocShmem(ipc::Shmem& aShmem)
+{
+ PVRManagerParent::DeallocShmem(aShmem);
+}
+
+bool
+VRManagerParent::IsSameProcess() const
+{
+ return OtherPid() == base::GetCurrentProcId();
+}
+
+void
+VRManagerParent::NotifyNotUsed(PTextureParent* aTexture, uint64_t aTransactionId)
+{
+ MOZ_ASSERT_UNREACHABLE("unexpected to be called");
+}
+
+void
+VRManagerParent::SendAsyncMessage(const InfallibleTArray<AsyncParentMessageData>& aMessage)
+{
+ MOZ_ASSERT_UNREACHABLE("unexpected to be called");
+}
+
+base::ProcessId
+VRManagerParent::GetChildProcessId()
+{
+ return OtherPid();
+}
+
+void
+VRManagerParent::RegisterWithManager()
+{
+ VRManager* vm = VRManager::Get();
+ vm->AddVRManagerParent(this);
+ mVRManagerHolder = vm;
+}
+
+void
+VRManagerParent::UnregisterFromManager()
+{
+ VRManager* vm = VRManager::Get();
+ vm->RemoveVRManagerParent(this);
+ mVRManagerHolder = nullptr;
+}
+
+/* static */ bool
+VRManagerParent::CreateForContent(Endpoint<PVRManagerParent>&& aEndpoint)
+{
+ MessageLoop* loop = layers::CompositorThreadHolder::Loop();
+
+ RefPtr<VRManagerParent> vmp = new VRManagerParent(aEndpoint.OtherPid(), true);
+ loop->PostTask(NewRunnableMethod<Endpoint<PVRManagerParent>&&>(
+ vmp, &VRManagerParent::Bind, Move(aEndpoint)));
+
+ return true;
+}
+
+void
+VRManagerParent::Bind(Endpoint<PVRManagerParent>&& aEndpoint)
+{
+ if (!aEndpoint.Bind(this)) {
+ return;
+ }
+ mSelfRef = this;
+
+ RegisterWithManager();
+}
+
+/*static*/ void
+VRManagerParent::RegisterVRManagerInCompositorThread(VRManagerParent* aVRManager)
+{
+ aVRManager->RegisterWithManager();
+}
+
+/*static*/ VRManagerParent*
+VRManagerParent::CreateSameProcess()
+{
+ MessageLoop* loop = mozilla::layers::CompositorThreadHolder::Loop();
+ RefPtr<VRManagerParent> vmp = new VRManagerParent(base::GetCurrentProcId(), false);
+ vmp->mCompositorThreadHolder = layers::CompositorThreadHolder::GetSingleton();
+ vmp->mSelfRef = vmp;
+ loop->PostTask(NewRunnableFunction(RegisterVRManagerInCompositorThread, vmp.get()));
+ return vmp.get();
+}
+
+bool
+VRManagerParent::CreateForGPUProcess(Endpoint<PVRManagerParent>&& aEndpoint)
+{
+ MessageLoop* loop = mozilla::layers::CompositorThreadHolder::Loop();
+
+ RefPtr<VRManagerParent> vmp = new VRManagerParent(aEndpoint.OtherPid(), false);
+ vmp->mCompositorThreadHolder = layers::CompositorThreadHolder::GetSingleton();
+ loop->PostTask(NewRunnableMethod<Endpoint<PVRManagerParent>&&>(
+ vmp, &VRManagerParent::Bind, Move(aEndpoint)));
+ return true;
+}
+
+void
+VRManagerParent::DeferredDestroy()
+{
+ mCompositorThreadHolder = nullptr;
+ mSelfRef = nullptr;
+}
+
+void
+VRManagerParent::ActorDestroy(ActorDestroyReason why)
+{
+ UnregisterFromManager();
+ MessageLoop::current()->PostTask(NewRunnableMethod(this, &VRManagerParent::DeferredDestroy));
+}
+
+void
+VRManagerParent::OnChannelConnected(int32_t aPid)
+{
+ mCompositorThreadHolder = layers::CompositorThreadHolder::GetSingleton();
+}
+
+bool
+VRManagerParent::RecvRefreshDisplays()
+{
+ // This is called to refresh the VR Displays for Navigator.GetVRDevices().
+ // We must pass "true" to VRManager::RefreshVRDisplays()
+ // to ensure that the promise returned by Navigator.GetVRDevices
+ // can resolve even if there are no changes to the VR Displays.
+ VRManager* vm = VRManager::Get();
+ vm->RefreshVRDisplays(true);
+
+ return true;
+}
+
+bool
+VRManagerParent::RecvGetDisplays(nsTArray<VRDisplayInfo> *aDisplays)
+{
+ VRManager* vm = VRManager::Get();
+ vm->GetVRDisplayInfo(*aDisplays);
+ return true;
+}
+
+bool
+VRManagerParent::RecvResetSensor(const uint32_t& aDisplayID)
+{
+ VRManager* vm = VRManager::Get();
+ RefPtr<gfx::VRDisplayHost> display = vm->GetDisplay(aDisplayID);
+ if (display != nullptr) {
+ display->ZeroSensor();
+ }
+
+ return true;
+}
+
+bool
+VRManagerParent::RecvGetSensorState(const uint32_t& aDisplayID, VRHMDSensorState* aState)
+{
+ VRManager* vm = VRManager::Get();
+ RefPtr<gfx::VRDisplayHost> display = vm->GetDisplay(aDisplayID);
+ if (display != nullptr) {
+ *aState = display->GetSensorState();
+ }
+ return true;
+}
+
+bool
+VRManagerParent::RecvGetImmediateSensorState(const uint32_t& aDisplayID, VRHMDSensorState* aState)
+{
+ VRManager* vm = VRManager::Get();
+ RefPtr<gfx::VRDisplayHost> display = vm->GetDisplay(aDisplayID);
+ if (display != nullptr) {
+ *aState = display->GetImmediateSensorState();
+ }
+ return true;
+}
+
+bool
+VRManagerParent::HaveEventListener()
+{
+ return mHaveEventListener;
+}
+
+bool
+VRManagerParent::RecvSetHaveEventListener(const bool& aHaveEventListener)
+{
+ mHaveEventListener = aHaveEventListener;
+ return true;
+}
+
+bool
+VRManagerParent::RecvControllerListenerAdded()
+{
+ VRManager* vm = VRManager::Get();
+ // Ask the connected gamepads to be added to GamepadManager
+ vm->ScanForDevices();
+
+ return true;
+}
+
+bool
+VRManagerParent::RecvControllerListenerRemoved()
+{
+ return true;
+}
+
+bool
+VRManagerParent::RecvGetControllers(nsTArray<VRControllerInfo> *aControllers)
+{
+ VRManager* vm = VRManager::Get();
+ vm->GetVRControllerInfo(*aControllers);
+ return true;
+}
+
+bool
+VRManagerParent::SendGamepadUpdate(const GamepadChangeEvent& aGamepadEvent)
+{
+ // GamepadManager only exists at the content process
+ // or the same process in non-e10s mode.
+ if (mIsContentChild || IsSameProcess()) {
+ return PVRManagerParent::SendGamepadUpdate(aGamepadEvent);
+ } else {
+ return true;
+ }
+}
+
+} // namespace gfx
+} // namespace mozilla
diff --git a/gfx/vr/ipc/VRManagerParent.h b/gfx/vr/ipc/VRManagerParent.h
new file mode 100644
index 000000000..d4611c187
--- /dev/null
+++ b/gfx/vr/ipc/VRManagerParent.h
@@ -0,0 +1,118 @@
+/* -*- 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/. */
+
+#ifndef MOZILLA_GFX_VR_VRMANAGERPARENT_H
+#define MOZILLA_GFX_VR_VRMANAGERPARENT_H
+
+#include "mozilla/layers/CompositableTransactionParent.h"
+#include "mozilla/layers/CompositorThread.h" // for CompositorThreadHolder
+#include "mozilla/gfx/PVRManagerParent.h" // for PVRManagerParent
+#include "mozilla/gfx/PVRLayerParent.h" // for PVRLayerParent
+#include "mozilla/ipc/ProtocolUtils.h" // for IToplevelProtocol
+#include "mozilla/TimeStamp.h" // for TimeStamp
+#include "gfxVR.h" // for VRFieldOfView
+
+namespace mozilla {
+using namespace layers;
+namespace gfx {
+
+class VRManager;
+
+class VRManagerParent final : public PVRManagerParent
+ , public HostIPCAllocator
+ , public ShmemAllocator
+{
+public:
+ explicit VRManagerParent(ProcessId aChildProcessId, bool aIsContentChild);
+
+ static VRManagerParent* CreateSameProcess();
+ static bool CreateForGPUProcess(Endpoint<PVRManagerParent>&& aEndpoint);
+ static bool CreateForContent(Endpoint<PVRManagerParent>&& aEndpoint);
+
+ virtual base::ProcessId GetChildProcessId() override;
+
+ // ShmemAllocator
+
+ virtual ShmemAllocator* AsShmemAllocator() override { return this; }
+
+ virtual bool AllocShmem(size_t aSize,
+ ipc::SharedMemory::SharedMemoryType aType,
+ ipc::Shmem* aShmem) override;
+
+ virtual bool AllocUnsafeShmem(size_t aSize,
+ ipc::SharedMemory::SharedMemoryType aType,
+ ipc::Shmem* aShmem) override;
+
+ virtual void DeallocShmem(ipc::Shmem& aShmem) override;
+
+ virtual bool IsSameProcess() const override;
+ bool HaveEventListener();
+
+ virtual void NotifyNotUsed(PTextureParent* aTexture, uint64_t aTransactionId) override;
+ virtual void SendAsyncMessage(const InfallibleTArray<AsyncParentMessageData>& aMessage) override;
+ bool SendGamepadUpdate(const GamepadChangeEvent& aGamepadEvent);
+
+protected:
+ ~VRManagerParent();
+
+ virtual PTextureParent* AllocPTextureParent(const SurfaceDescriptor& aSharedData,
+ const LayersBackend& aLayersBackend,
+ const TextureFlags& aFlags,
+ const uint64_t& aSerial) override;
+ virtual bool DeallocPTextureParent(PTextureParent* actor) override;
+
+ virtual PVRLayerParent* AllocPVRLayerParent(const uint32_t& aDisplayID,
+ const float& aLeftEyeX,
+ const float& aLeftEyeY,
+ const float& aLeftEyeWidth,
+ const float& aLeftEyeHeight,
+ const float& aRightEyeX,
+ const float& aRightEyeY,
+ const float& aRightEyeWidth,
+ const float& aRightEyeHeight) override;
+ virtual bool DeallocPVRLayerParent(PVRLayerParent* actor) override;
+
+ virtual void ActorDestroy(ActorDestroyReason why) override;
+ void OnChannelConnected(int32_t pid) override;
+
+ virtual bool RecvRefreshDisplays() override;
+ virtual bool RecvGetDisplays(nsTArray<VRDisplayInfo> *aDisplays) override;
+ virtual bool RecvResetSensor(const uint32_t& aDisplayID) override;
+ virtual bool RecvGetSensorState(const uint32_t& aDisplayID, VRHMDSensorState* aState) override;
+ virtual bool RecvGetImmediateSensorState(const uint32_t& aDisplayID, VRHMDSensorState* aState) override;
+ virtual bool RecvSetHaveEventListener(const bool& aHaveEventListener) override;
+ virtual bool RecvControllerListenerAdded() override;
+ virtual bool RecvControllerListenerRemoved() override;
+ virtual bool RecvGetControllers(nsTArray<VRControllerInfo> *aControllers) override;
+
+private:
+ void RegisterWithManager();
+ void UnregisterFromManager();
+
+ void Bind(Endpoint<PVRManagerParent>&& aEndpoint);
+
+ static void RegisterVRManagerInCompositorThread(VRManagerParent* aVRManager);
+
+ void DeferredDestroy();
+
+ // This keeps us alive until ActorDestroy(), at which point we do a
+ // deferred destruction of ourselves.
+ RefPtr<VRManagerParent> mSelfRef;
+
+ // Keep the compositor thread alive, until we have destroyed ourselves.
+ RefPtr<layers::CompositorThreadHolder> mCompositorThreadHolder;
+
+ // Keep the VRManager alive, until we have destroyed ourselves.
+ RefPtr<VRManager> mVRManagerHolder;
+ bool mHaveEventListener;
+ bool mIsContentChild;
+};
+
+} // namespace mozilla
+} // namespace gfx
+
+#endif // MOZILLA_GFX_VR_VRMANAGERPARENT_H
diff --git a/gfx/vr/ipc/VRMessageUtils.h b/gfx/vr/ipc/VRMessageUtils.h
new file mode 100644
index 000000000..c066047db
--- /dev/null
+++ b/gfx/vr/ipc/VRMessageUtils.h
@@ -0,0 +1,193 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=8 et tw=80 : */
+/* 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/. */
+
+#ifndef mozilla_gfx_vr_VRMessageUtils_h
+#define mozilla_gfx_vr_VRMessageUtils_h
+
+#include "ipc/IPCMessageUtils.h"
+#include "mozilla/GfxMessageUtils.h"
+#include "VRManager.h"
+
+#include "gfxVR.h"
+
+namespace IPC {
+
+template<>
+struct ParamTraits<mozilla::gfx::VRDeviceType> :
+ public ContiguousEnumSerializer<mozilla::gfx::VRDeviceType,
+ mozilla::gfx::VRDeviceType(0),
+ mozilla::gfx::VRDeviceType(mozilla::gfx::VRDeviceType::NumVRDeviceTypes)> {};
+
+template<>
+struct ParamTraits<mozilla::gfx::VRDisplayCapabilityFlags> :
+ public BitFlagsEnumSerializer<mozilla::gfx::VRDisplayCapabilityFlags,
+ mozilla::gfx::VRDisplayCapabilityFlags::Cap_All> {};
+
+template <>
+struct ParamTraits<mozilla::gfx::VRDisplayInfo>
+{
+ typedef mozilla::gfx::VRDisplayInfo paramType;
+
+ static void Write(Message* aMsg, const paramType& aParam)
+ {
+ WriteParam(aMsg, aParam.mType);
+ WriteParam(aMsg, aParam.mDisplayID);
+ WriteParam(aMsg, aParam.mDisplayName);
+ WriteParam(aMsg, aParam.mCapabilityFlags);
+ WriteParam(aMsg, aParam.mEyeResolution);
+ WriteParam(aMsg, aParam.mIsConnected);
+ WriteParam(aMsg, aParam.mIsPresenting);
+ WriteParam(aMsg, aParam.mStageSize);
+ WriteParam(aMsg, aParam.mSittingToStandingTransform);
+ for (int i = 0; i < mozilla::gfx::VRDisplayInfo::NumEyes; i++) {
+ WriteParam(aMsg, aParam.mEyeFOV[i]);
+ WriteParam(aMsg, aParam.mEyeTranslation[i]);
+ }
+ }
+
+ static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
+ {
+ if (!ReadParam(aMsg, aIter, &(aResult->mType)) ||
+ !ReadParam(aMsg, aIter, &(aResult->mDisplayID)) ||
+ !ReadParam(aMsg, aIter, &(aResult->mDisplayName)) ||
+ !ReadParam(aMsg, aIter, &(aResult->mCapabilityFlags)) ||
+ !ReadParam(aMsg, aIter, &(aResult->mEyeResolution)) ||
+ !ReadParam(aMsg, aIter, &(aResult->mIsConnected)) ||
+ !ReadParam(aMsg, aIter, &(aResult->mIsPresenting)) ||
+ !ReadParam(aMsg, aIter, &(aResult->mStageSize)) ||
+ !ReadParam(aMsg, aIter, &(aResult->mSittingToStandingTransform))) {
+ return false;
+ }
+ for (int i = 0; i < mozilla::gfx::VRDisplayInfo::NumEyes; i++) {
+ if (!ReadParam(aMsg, aIter, &(aResult->mEyeFOV[i])) ||
+ !ReadParam(aMsg, aIter, &(aResult->mEyeTranslation[i]))) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+};
+
+template <>
+struct ParamTraits<mozilla::gfx::VRHMDSensorState>
+{
+ typedef mozilla::gfx::VRHMDSensorState paramType;
+
+ static void Write(Message* aMsg, const paramType& aParam)
+ {
+ WriteParam(aMsg, aParam.timestamp);
+ WriteParam(aMsg, aParam.inputFrameID);
+ WriteParam(aMsg, aParam.flags);
+ WriteParam(aMsg, aParam.orientation[0]);
+ WriteParam(aMsg, aParam.orientation[1]);
+ WriteParam(aMsg, aParam.orientation[2]);
+ WriteParam(aMsg, aParam.orientation[3]);
+ WriteParam(aMsg, aParam.position[0]);
+ WriteParam(aMsg, aParam.position[1]);
+ WriteParam(aMsg, aParam.position[2]);
+ WriteParam(aMsg, aParam.angularVelocity[0]);
+ WriteParam(aMsg, aParam.angularVelocity[1]);
+ WriteParam(aMsg, aParam.angularVelocity[2]);
+ WriteParam(aMsg, aParam.angularAcceleration[0]);
+ WriteParam(aMsg, aParam.angularAcceleration[1]);
+ WriteParam(aMsg, aParam.angularAcceleration[2]);
+ WriteParam(aMsg, aParam.linearVelocity[0]);
+ WriteParam(aMsg, aParam.linearVelocity[1]);
+ WriteParam(aMsg, aParam.linearVelocity[2]);
+ WriteParam(aMsg, aParam.linearAcceleration[0]);
+ WriteParam(aMsg, aParam.linearAcceleration[1]);
+ WriteParam(aMsg, aParam.linearAcceleration[2]);
+ }
+
+ static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
+ {
+ if (!ReadParam(aMsg, aIter, &(aResult->timestamp)) ||
+ !ReadParam(aMsg, aIter, &(aResult->inputFrameID)) ||
+ !ReadParam(aMsg, aIter, &(aResult->flags)) ||
+ !ReadParam(aMsg, aIter, &(aResult->orientation[0])) ||
+ !ReadParam(aMsg, aIter, &(aResult->orientation[1])) ||
+ !ReadParam(aMsg, aIter, &(aResult->orientation[2])) ||
+ !ReadParam(aMsg, aIter, &(aResult->orientation[3])) ||
+ !ReadParam(aMsg, aIter, &(aResult->position[0])) ||
+ !ReadParam(aMsg, aIter, &(aResult->position[1])) ||
+ !ReadParam(aMsg, aIter, &(aResult->position[2])) ||
+ !ReadParam(aMsg, aIter, &(aResult->angularVelocity[0])) ||
+ !ReadParam(aMsg, aIter, &(aResult->angularVelocity[1])) ||
+ !ReadParam(aMsg, aIter, &(aResult->angularVelocity[2])) ||
+ !ReadParam(aMsg, aIter, &(aResult->angularAcceleration[0])) ||
+ !ReadParam(aMsg, aIter, &(aResult->angularAcceleration[1])) ||
+ !ReadParam(aMsg, aIter, &(aResult->angularAcceleration[2])) ||
+ !ReadParam(aMsg, aIter, &(aResult->linearVelocity[0])) ||
+ !ReadParam(aMsg, aIter, &(aResult->linearVelocity[1])) ||
+ !ReadParam(aMsg, aIter, &(aResult->linearVelocity[2])) ||
+ !ReadParam(aMsg, aIter, &(aResult->linearAcceleration[0])) ||
+ !ReadParam(aMsg, aIter, &(aResult->linearAcceleration[1])) ||
+ !ReadParam(aMsg, aIter, &(aResult->linearAcceleration[2]))) {
+ return false;
+ }
+ return true;
+ }
+};
+
+template <>
+struct ParamTraits<mozilla::gfx::VRFieldOfView>
+{
+ typedef mozilla::gfx::VRFieldOfView paramType;
+
+ static void Write(Message* aMsg, const paramType& aParam)
+ {
+ WriteParam(aMsg, aParam.upDegrees);
+ WriteParam(aMsg, aParam.rightDegrees);
+ WriteParam(aMsg, aParam.downDegrees);
+ WriteParam(aMsg, aParam.leftDegrees);
+ }
+
+ static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
+ {
+ if (!ReadParam(aMsg, aIter, &(aResult->upDegrees)) ||
+ !ReadParam(aMsg, aIter, &(aResult->rightDegrees)) ||
+ !ReadParam(aMsg, aIter, &(aResult->downDegrees)) ||
+ !ReadParam(aMsg, aIter, &(aResult->leftDegrees))) {
+ return false;
+ }
+
+ return true;
+ }
+};
+
+template <>
+struct ParamTraits<mozilla::gfx::VRControllerInfo>
+{
+ typedef mozilla::gfx::VRControllerInfo paramType;
+
+ static void Write(Message* aMsg, const paramType& aParam)
+ {
+ WriteParam(aMsg, aParam.mType);
+ WriteParam(aMsg, aParam.mControllerID);
+ WriteParam(aMsg, aParam.mControllerName);
+ WriteParam(aMsg, aParam.mMappingType);
+ WriteParam(aMsg, aParam.mNumButtons);
+ WriteParam(aMsg, aParam.mNumAxes);
+ }
+
+ static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
+ {
+ if (!ReadParam(aMsg, aIter, &(aResult->mType)) ||
+ !ReadParam(aMsg, aIter, &(aResult->mControllerID)) ||
+ !ReadParam(aMsg, aIter, &(aResult->mControllerName)) ||
+ !ReadParam(aMsg, aIter, &(aResult->mMappingType)) ||
+ !ReadParam(aMsg, aIter, &(aResult->mNumButtons)) ||
+ !ReadParam(aMsg, aIter, &(aResult->mNumAxes))) {
+ return false;
+ }
+
+ return true;
+ }
+};
+} // namespace IPC
+
+#endif // mozilla_gfx_vr_VRMessageUtils_h