author | David Anderson <danderson@mozilla.com> |
Tue, 20 Sep 2016 01:18:50 -0700 | |
changeset 314465 | 9a6f5fac405ffd3ab59163bf4c5ec866a1bb142b |
parent 314464 | 5ac08fb77360da01e694dd3fb5fef07a64173298 |
child 314466 | 101e8160640228dcc0e59429d27a2f3a3a6a957d |
push id | 81899 |
push user | danderson@mozilla.com |
push date | Tue, 20 Sep 2016 08:20:45 +0000 |
treeherder | mozilla-inbound@101e81606402 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | mattwoodrow, billm |
bugs | 1300936 |
milestone | 52.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/dom/ipc/ContentChild.cpp +++ b/dom/ipc/ContentChild.cpp @@ -1181,16 +1181,33 @@ ContentChild::RecvInitRendering(Endpoint return false; } if (!gfx::VRManagerChild::InitForContent(Move(aVRBridge))) { return false; } return true; } +bool +ContentChild::RecvReinitRendering(Endpoint<PCompositorBridgeChild>&& aCompositor, + Endpoint<PImageBridgeChild>&& aImageBridge, + Endpoint<PVRManagerChild>&& aVRBridge) +{ + if (!CompositorBridgeChild::ReinitForContent(Move(aCompositor))) { + return false; + } + if (!ImageBridgeChild::ReinitForContent(Move(aImageBridge))) { + return false; + } + if (!gfx::VRManagerChild::ReinitForContent(Move(aVRBridge))) { + return false; + } + return true; +} + PSharedBufferManagerChild* ContentChild::AllocPSharedBufferManagerChild(mozilla::ipc::Transport* aTransport, base::ProcessId aOtherProcess) { return SharedBufferManagerChild::StartUpInChildProcess(aTransport, aOtherProcess); } PBackgroundChild*
--- a/dom/ipc/ContentChild.h +++ b/dom/ipc/ContentChild.h @@ -162,16 +162,22 @@ public: base::ProcessId otherProcess) override; bool RecvInitRendering( Endpoint<PCompositorBridgeChild>&& aCompositor, Endpoint<PImageBridgeChild>&& aImageBridge, Endpoint<PVRManagerChild>&& aVRBridge) override; + bool + RecvReinitRendering( + Endpoint<PCompositorBridgeChild>&& aCompositor, + Endpoint<PImageBridgeChild>&& aImageBridge, + Endpoint<PVRManagerChild>&& aVRBridge) override; + PSharedBufferManagerChild* AllocPSharedBufferManagerChild(mozilla::ipc::Transport* aTransport, base::ProcessId aOtherProcess) override; PProcessHangMonitorChild* AllocPProcessHangMonitorChild(Transport* aTransport, ProcessId aOtherProcess) override;
--- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -1819,16 +1819,21 @@ ContentParent::ActorDestroy(ActorDestroy sObserverTopics[i]); } } // remove the global remote preferences observers Preferences::RemoveObserver(this, ""); gfxVars::RemoveReceiver(this); + if (GPUProcessManager* gpu = GPUProcessManager::Get()) { + // Note: the manager could have shutdown already. + gpu->RemoveListener(this); + } + RecvRemoveGeolocationListener(); mConsoleService = nullptr; #ifdef MOZ_ENABLE_PROFILER_SPS if (mGatherer && !mProfile.IsEmpty()) { mGatherer->OOPExitProfile(mProfile); } @@ -2234,16 +2239,18 @@ ContentParent::InitInternal(ProcessPrior &imageBridge, &vrBridge); MOZ_ASSERT(opened); Unused << SendInitRendering( Move(compositor), Move(imageBridge), Move(vrBridge)); + + gpm->AddListener(this); } #ifdef MOZ_WIDGET_GONK DebugOnly<bool> opened = PSharedBufferManager::Open(this); MOZ_ASSERT(opened); #endif } if (gAppData) { @@ -2373,16 +2380,38 @@ ContentParent::RecvGetGfxVars(Infallible // Now that content has initialized gfxVars, we can start listening for // updates. gfxVars::AddReceiver(this); return true; } void +ContentParent::OnCompositorUnexpectedShutdown() +{ + GPUProcessManager* gpm = GPUProcessManager::Get(); + + Endpoint<PCompositorBridgeChild> compositor; + Endpoint<PImageBridgeChild> imageBridge; + Endpoint<PVRManagerChild> vrBridge; + + DebugOnly<bool> opened = gpm->CreateContentBridges( + OtherPid(), + &compositor, + &imageBridge, + &vrBridge); + MOZ_ASSERT(opened); + + Unused << SendReinitRendering( + Move(compositor), + Move(imageBridge), + Move(vrBridge)); +} + +void ContentParent::OnVarChanged(const GfxVarUpdate& aVar) { if (!mIPCOpen) { return; } Unused << SendVarUpdate(aVar); }
--- a/dom/ipc/ContentParent.h +++ b/dom/ipc/ContentParent.h @@ -5,16 +5,17 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef mozilla_dom_ContentParent_h #define mozilla_dom_ContentParent_h #include "mozilla/dom/PContentParent.h" #include "mozilla/dom/nsIContentParent.h" #include "mozilla/gfx/gfxVarReceiver.h" +#include "mozilla/gfx/GPUProcessListener.h" #include "mozilla/ipc/GeckoChildProcessHost.h" #include "mozilla/Attributes.h" #include "mozilla/FileUtils.h" #include "mozilla/HalTypes.h" #include "mozilla/LinkedList.h" #include "mozilla/StaticPtr.h" #include "mozilla/UniquePtr.h" @@ -87,16 +88,17 @@ class GetFilesHelper; class ContentParent final : public PContentParent , public nsIContentParent , public nsIObserver , public nsIDOMGeoPositionCallback , public nsIDOMGeoPositionErrorCallback , public gfx::gfxVarReceiver , public mozilla::LinkedListElement<ContentParent> + , public gfx::GPUProcessListener { typedef mozilla::ipc::GeckoChildProcessHost GeckoChildProcessHost; typedef mozilla::ipc::OptionalURIParams OptionalURIParams; typedef mozilla::ipc::PFileDescriptorSetParent PFileDescriptorSetParent; typedef mozilla::ipc::TestShellParent TestShellParent; typedef mozilla::ipc::URIParams URIParams; typedef mozilla::ipc::PrincipalInfo PrincipalInfo; typedef mozilla::dom::ClonedMessageData ClonedMessageData; @@ -569,16 +571,17 @@ public: protected: void OnChannelConnected(int32_t pid) override; virtual void ActorDestroy(ActorDestroyReason why) override; bool ShouldContinueFromReplyTimeout() override; void OnVarChanged(const GfxVarUpdate& aVar) override; + void OnCompositorUnexpectedShutdown() override; private: static nsDataHashtable<nsStringHashKey, ContentParent*> *sAppContentParents; static nsTArray<ContentParent*>* sNonAppContentParents; static nsTArray<ContentParent*>* sPrivateContent; static StaticAutoPtr<LinkedList<ContentParent> > sContentParents; static void JoinProcessesIOThread(const nsTArray<ContentParent*>* aProcesses,
--- a/dom/ipc/PContent.ipdl +++ b/dom/ipc/PContent.ipdl @@ -464,16 +464,24 @@ both: child: // Give the content process its endpoints to the compositor. async InitRendering( Endpoint<PCompositorBridgeChild> compositor, Endpoint<PImageBridgeChild> imageBridge, Endpoint<PVRManagerChild> vr); + // Re-create the rendering stack using the given endpoints. This is sent + // after the compositor process has crashed. The new endpoints may be to a + // newly launched GPU process, or the compositor thread of the UI process. + async ReinitRendering( + Endpoint<PCompositorBridgeChild> compositor, + Endpoint<PImageBridgeChild> bridge, + Endpoint<PVRManagerChild> vr); + /** * Enable system-level sandboxing features, if available. Can * usually only be performed zero or one times. The child may * abnormally exit if this fails; the details are OS-specific. */ async SetProcessSandbox(MaybeFileDesc aBroker); async PMemoryReportRequest(uint32_t generation, bool anonymize,
new file mode 100644 --- /dev/null +++ b/gfx/ipc/GPUProcessListener.h @@ -0,0 +1,27 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=99: */ +/* 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 _include_mozilla_gfx_ipc_GPUProcessListener_h_ +#define _include_mozilla_gfx_ipc_GPUProcessListener_h_ + +namespace mozilla { +namespace gfx { + +class GPUProcessListener +{ + public: + virtual ~GPUProcessListener() + {} + + // Called when the compositor has died and the rendering stack must be + // recreated. + virtual void OnCompositorUnexpectedShutdown() + {} +}; + +} // namespace gfx +} // namespace mozilla + +#endif // _include_mozilla_gfx_ipc_GPUProcessListener_h_
--- a/gfx/ipc/GPUProcessManager.cpp +++ b/gfx/ipc/GPUProcessManager.cpp @@ -1,15 +1,16 @@ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=99: */ /* 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 "GPUProcessManager.h" #include "GPUProcessHost.h" +#include "GPUProcessListener.h" #include "mozilla/StaticPtr.h" #include "mozilla/dom/ContentParent.h" #include "mozilla/layers/APZCTreeManager.h" #include "mozilla/layers/APZCTreeManagerChild.h" #include "mozilla/layers/CompositorBridgeParent.h" #include "mozilla/layers/ImageBridgeChild.h" #include "mozilla/layers/ImageBridgeParent.h" #include "mozilla/layers/InProcessCompositorSession.h" @@ -239,27 +240,100 @@ GPUProcessManager::OnProcessLaunchComple void GPUProcessManager::OnProcessUnexpectedShutdown(GPUProcessHost* aHost) { MOZ_ASSERT(mProcess && mProcess == aHost); DestroyProcess(); + // The shutdown and restart sequence for the GPU process is as follows: + // + // (1) The GPU process dies. IPDL will enqueue an ActorDestroy message on + // each channel owning a bridge to the GPU process, on the thread + // owning that channel. + // + // (2) The first channel to process its ActorDestroy message will post a + // message to the main thread to call NotifyRemoteActorDestroyed on + // the GPUProcessManager, which calls OnProcessUnexpectedShutdown if + // it has not handled shutdown for this process yet. + // + // (3) We then notify each widget that its session with the compositor is + // now invalid. The widget is responsible for destroying its layer + // manager and CompositorBridgeChild. Note that at this stage, not + // all actors may have received ActorDestroy yet. CompositorBridgeChild + // may attempt to send messages, and if this happens, it will probably + // report a MsgDropped error. This is okay. + // + // (4) At this point, the UI process has a clean slate: no layers should + // exist for the old compositor. We may make a decision on whether or + // not to re-launch the GPU process. Currently, we do not relaunch it, + // and any new compositors will be created in-process and will default + // to software. + // + // (5) Next we notify each ContentParent of the lost connection. It will + // request new endpoints from the GPUProcessManager and forward them + // to its ContentChild. The parent-side of these endpoints may come + // from the compositor thread of the UI process, or the compositor + // thread of the GPU process. However, no actual compositors should + // exist yet. + // + // (6) Each ContentChild will receive new endpoints. It will destroy its + // Compositor/ImageBridgeChild singletons and recreate them, as well + // as invalidate all retained layers. + // + // (7) In addition, each ContentChild will ask each of its TabChildren + // to re-request association with the compositor for the window + // owning the tab. The sequence of calls looks like: + // (a) [CONTENT] ContentChild::RecvReinitRendering + // (b) [CONTENT] TabChild::ReinitRendering + // (c) [CONTENT] TabChild::SendEnsureLayersConnected + // (d) [UI] TabParent::RecvEnsureLayersConnected + // (e) [UI] RenderFrameParent::EnsureLayersConnected + // (f) [UI] CompositorBridgeChild::SendNotifyChildRecreated + // + // Note that at step (e), RenderFrameParent will call GetLayerManager + // on the nsIWidget owning the tab. This step ensures that a compositor + // exists for the window. If we decided to launch a new GPU Process, + // at this point we block until the process has launched and we're + // able to create a new window compositor. Otherwise, if compositing + // is now in-process, this will simply create a new + // CompositorBridgeParent in the UI process. If there are multiple tabs + // in the same window, additional tabs will simply return the already- + // established compositor. + // + // Finally, this step serves one other crucial function: tabs must be + // associated with a window compositor or else they can't forward + // layer transactions. So this step both ensures that a compositor + // exists, and that the tab can forward layers. + // + // (8) Last, if the window had no remote tabs, step (7) will not have + // applied, and the window will not have a new compositor just yet. + // The next refresh tick and paint will ensure that one exists, again + // via nsIWidget::GetLayerManager. + // Build a list of sessions to notify, since notification might delete // entries from the list. nsTArray<RefPtr<RemoteCompositorSession>> sessions; for (auto& session : mRemoteSessions) { sessions.AppendElement(session); } - // Notify. + // Notify each widget that we have lost the GPU process. This will ensure + // that each widget destroys its layer manager and CompositorBridgeChild. for (const auto& session : sessions) { session->NotifySessionLost(); } + + // Notify content. This will ensure that each content process re-establishes + // a connection to the compositor thread (whether it's in-process or in a + // newly launched GPU process). + for (const auto& listener : mListeners) { + listener->OnCompositorUnexpectedShutdown(); + } } void GPUProcessManager::NotifyRemoteActorDestroyed(const uint64_t& aProcessToken) { if (!NS_IsMainThread()) { RefPtr<Runnable> task = mTaskFactory.NewRunnableMethod( &GPUProcessManager::NotifyRemoteActorDestroyed, aProcessToken); @@ -608,10 +682,22 @@ GPUProcessManager::RegisterSession(Remot } void GPUProcessManager::UnregisterSession(RemoteCompositorSession* aSession) { mRemoteSessions.RemoveElement(aSession); } +void +GPUProcessManager::AddListener(GPUProcessListener* aListener) +{ + mListeners.AppendElement(aListener); +} + +void +GPUProcessManager::RemoveListener(GPUProcessListener* aListener) +{ + mListeners.RemoveElement(aListener); +} + } // namespace gfx } // namespace mozilla
--- a/gfx/ipc/GPUProcessManager.h +++ b/gfx/ipc/GPUProcessManager.h @@ -39,16 +39,17 @@ class ContentParent; class TabParent; } // namespace dom namespace ipc { class GeckoChildProcessHost; } // namespace ipc namespace gfx { class GPUChild; +class GPUProcessListener; class PVRManagerChild; class VsyncBridgeChild; class VsyncIOThreadHolder; // The GPUProcessManager is a singleton responsible for creating GPU-bound // objects that may live in another process. Currently, it provides access // to the compositor via CompositorBridgeParent. class GPUProcessManager final : public GPUProcessHost::Listener @@ -116,16 +117,19 @@ public: void OnProcessLaunchComplete(GPUProcessHost* aHost) override; void OnProcessUnexpectedShutdown(GPUProcessHost* aHost) override; // Notify the GPUProcessManager that a top-level PGPU protocol has been // terminated. This may be called from any thread. void NotifyRemoteActorDestroyed(const uint64_t& aProcessToken); + void AddListener(GPUProcessListener* aListener); + void RemoveListener(GPUProcessListener* aListener); + // Returns access to the PGPU protocol if a GPU process is present. GPUChild* GetGPUChild() { return mGPUChild; } private: // Called from our xpcom-shutdown observer. void OnXPCOMShutdown(); @@ -184,16 +188,17 @@ private: private: RefPtr<Observer> mObserver; ipc::TaskFactory<GPUProcessManager> mTaskFactory; RefPtr<VsyncIOThreadHolder> mVsyncIOThread; uint64_t mNextLayerTreeId; nsTArray<RefPtr<RemoteCompositorSession>> mRemoteSessions; + nsTArray<GPUProcessListener*> mListeners; // Fields that are associated with the current GPU process. GPUProcessHost* mProcess; MOZ_INIT_OUTSIDE_CTOR uint64_t mProcessToken; GPUChild* mGPUChild; RefPtr<VsyncBridgeChild> mVsyncBridge; };
--- a/gfx/ipc/moz.build +++ b/gfx/ipc/moz.build @@ -9,16 +9,17 @@ EXPORTS.mozilla += [ 'GfxMessageUtils.h' ] EXPORTS.mozilla.gfx += [ 'GPUChild.h', 'GPUParent.h', 'GPUProcessHost.h', 'GPUProcessImpl.h', + 'GPUProcessListener.h', 'GPUProcessManager.h', 'SharedDIB.h', 'VsyncBridgeChild.h', 'VsyncBridgeParent.h', 'VsyncIOThreadHolder.h', ] EXPORTS.mozilla.layers += [
--- a/gfx/layers/ipc/CompositorBridgeChild.cpp +++ b/gfx/layers/ipc/CompositorBridgeChild.cpp @@ -191,16 +191,32 @@ CompositorBridgeChild::InitForContent(En child->mCanSend = true; // We release this ref in DeferredDestroyCompositor. sCompositorBridge = child; return true; } +/* static */ bool +CompositorBridgeChild::ReinitForContent(Endpoint<PCompositorBridgeChild>&& aEndpoint) +{ + MOZ_ASSERT(NS_IsMainThread()); + + if (RefPtr<CompositorBridgeChild> old = sCompositorBridge.forget()) { + // Note that at this point, ActorDestroy may not have been called yet, + // meaning mCanSend is still true. In this case we will try to send a + // synchronous WillClose message to the parent, and will certainly get + // a false result and a MsgDropped processing error. This is okay. + old->Destroy(); + } + + return InitForContent(Move(aEndpoint)); +} + CompositorBridgeParent* CompositorBridgeChild::InitSameProcess(widget::CompositorWidget* aWidget, const uint64_t& aLayerTreeId, CSSToLayoutDeviceScale aScale, bool aUseAPZ, bool aUseExternalSurface, const gfx::IntSize& aSurfaceSize) {
--- a/gfx/layers/ipc/CompositorBridgeChild.h +++ b/gfx/layers/ipc/CompositorBridgeChild.h @@ -59,16 +59,17 @@ public: * in progressive paint calculations. */ bool LookupCompositorFrameMetrics(const FrameMetrics::ViewID aId, FrameMetrics&); /** * Initialize the singleton compositor bridge for a content process. */ static bool InitForContent(Endpoint<PCompositorBridgeChild>&& aEndpoint); + static bool ReinitForContent(Endpoint<PCompositorBridgeChild>&& aEndpoint); static RefPtr<CompositorBridgeChild> CreateRemote( const uint64_t& aProcessToken, ClientLayerManager* aLayerManager, Endpoint<PCompositorBridgeChild>&& aEndpoint); /** * Initialize the CompositorBridgeChild, create CompositorBridgeParent, and
--- a/gfx/layers/ipc/ImageBridgeChild.cpp +++ b/gfx/layers/ipc/ImageBridgeChild.cpp @@ -447,17 +447,19 @@ ImageBridgeChild::ShutdownStep1(Synchron ManagedPTextureChild(textures); for (int i = textures.Length() - 1; i >= 0; --i) { RefPtr<TextureClient> client = TextureClient::AsTextureClient(textures[i]); if (client) { client->Destroy(); } } - SendWillClose(); + if (mCanSend) { + SendWillClose(); + } MarkShutDown(); // From now on, no message can be sent through the image bridge from the // client side except the final Stop message. } // dispatched function void @@ -853,19 +855,21 @@ ImageBridgeChild::SendImageBridgeThreadI bool ImageBridgeChild::InitForContent(Endpoint<PImageBridgeChild>&& aEndpoint) { MOZ_ASSERT(NS_IsMainThread()); gfxPlatform::GetPlatform(); - sImageBridgeChildThread = new ImageBridgeThread(); - if (!sImageBridgeChildThread->Start()) { - return false; + if (!sImageBridgeChildThread) { + sImageBridgeChildThread = new ImageBridgeThread(); + if (!sImageBridgeChildThread->Start()) { + return false; + } } RefPtr<ImageBridgeChild> child = new ImageBridgeChild(); RefPtr<Runnable> runnable = NewRunnableMethod<Endpoint<PImageBridgeChild>&&>( child, &ImageBridgeChild::Bind, Move(aEndpoint)); @@ -875,16 +879,30 @@ ImageBridgeChild::InitForContent(Endpoin { StaticMutexAutoLock lock(sImageBridgeSingletonLock); sImageBridgeChildSingleton = child; } return true; } +bool +ImageBridgeChild::ReinitForContent(Endpoint<PImageBridgeChild>&& aEndpoint) +{ + MOZ_ASSERT(NS_IsMainThread()); + + // Note that at this point, ActorDestroy may not have been called yet, + // meaning mCanSend is still true. In this case we will try to send a + // synchronous WillClose message to the parent, and will certainly get a + // false result and a MsgDropped processing error. This is okay. + ShutdownSingleton(); + + return InitForContent(Move(aEndpoint)); +} + void ImageBridgeChild::Bind(Endpoint<PImageBridgeChild>&& aEndpoint) { if (!aEndpoint.Bind(this)) { return; } // This reference is dropped in DeallocPImageBridgeChild. @@ -903,29 +921,38 @@ ImageBridgeChild::BindSameProcess(RefPtr // This reference is dropped in DeallocPImageBridgeChild. this->AddRef(); mCanSend = true; SendImageBridgeThreadId(); } -void ImageBridgeChild::ShutDown() +/* static */ void +ImageBridgeChild::ShutDown() +{ + MOZ_ASSERT(NS_IsMainThread()); + + ShutdownSingleton(); + + delete sImageBridgeChildThread; + sImageBridgeChildThread = nullptr; +} + +/* static */ void +ImageBridgeChild::ShutdownSingleton() { MOZ_ASSERT(NS_IsMainThread()); if (RefPtr<ImageBridgeChild> child = GetSingleton()) { child->WillShutdown(); StaticMutexAutoLock lock(sImageBridgeSingletonLock); sImageBridgeChildSingleton = nullptr; } - - delete sImageBridgeChildThread; - sImageBridgeChildThread = nullptr; } void ImageBridgeChild::WillShutdown() { { SynchronousTask task("ImageBridge ShutdownStep1 lock");
--- a/gfx/layers/ipc/ImageBridgeChild.h +++ b/gfx/layers/ipc/ImageBridgeChild.h @@ -123,16 +123,17 @@ public: * * We may want to use a specifi thread in the future. In this case, use * CreateWithThread instead. */ static void InitSameProcess(); static void InitWithGPUProcess(Endpoint<PImageBridgeChild>&& aEndpoint); static bool InitForContent(Endpoint<PImageBridgeChild>&& aEndpoint); + static bool ReinitForContent(Endpoint<PImageBridgeChild>&& aEndpoint); /** * Destroys the image bridge by calling DestroyBridge, and destroys the * ImageBridge's thread. * * If you don't want to destroy the thread, call DestroyBridge directly * instead. */ @@ -384,16 +385,18 @@ protected: void ShutdownStep2(SynchronousTask* aTask); void MarkShutDown(); void ActorDestroy(ActorDestroyReason aWhy) override; void DeallocPImageBridgeChild() override; bool CanSend() const; + static void ShutdownSingleton(); + private: class ShutdownObserver final : public nsIObserver { public: NS_DECL_ISUPPORTS NS_DECL_NSIOBSERVER explicit ShutdownObserver(ImageBridgeChild* aImageBridge);
--- a/gfx/vr/ipc/VRManagerChild.cpp +++ b/gfx/vr/ipc/VRManagerChild.cpp @@ -91,16 +91,26 @@ VRManagerChild::InitForContent(Endpoint< 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();
--- a/gfx/vr/ipc/VRManagerChild.h +++ b/gfx/vr/ipc/VRManagerChild.h @@ -43,16 +43,17 @@ public: int GetInputFrameID(); bool GetVRDisplays(nsTArray<RefPtr<VRDisplayClient> >& aDisplays); bool RefreshVRDisplaysWithCallback(dom::Navigator* aNavigator); 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;