diff options
Diffstat (limited to 'gfx/vr/ipc')
-rw-r--r-- | gfx/vr/ipc/PVRLayer.ipdl | 27 | ||||
-rw-r--r-- | gfx/vr/ipc/PVRManager.ipdl | 86 | ||||
-rw-r--r-- | gfx/vr/ipc/VRLayerChild.cpp | 86 | ||||
-rw-r--r-- | gfx/vr/ipc/VRLayerChild.h | 53 | ||||
-rw-r--r-- | gfx/vr/ipc/VRLayerParent.cpp | 59 | ||||
-rw-r--r-- | gfx/vr/ipc/VRLayerParent.h | 43 | ||||
-rw-r--r-- | gfx/vr/ipc/VRManagerChild.cpp | 593 | ||||
-rw-r--r-- | gfx/vr/ipc/VRManagerChild.h | 185 | ||||
-rw-r--r-- | gfx/vr/ipc/VRManagerParent.cpp | 332 | ||||
-rw-r--r-- | gfx/vr/ipc/VRManagerParent.h | 118 | ||||
-rw-r--r-- | gfx/vr/ipc/VRMessageUtils.h | 193 |
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 |