From cdc239b74f597fa69e223cfacd7c78e6e38dcbc6 Mon Sep 17 00:00:00 2001 From: Andrew Osmond Date: Thu, 4 Nov 2021 16:29:44 +0000 Subject: [PATCH] Bug 1734649 - Part 2. Create PCanvasManager to manage WebGL instances. r=jrmuizel This patch adds the necessary IPDL plumbing to allow us to create WebGL instances off the main thread in the content process, and to execute them on the Renderer thread in the compositor process. Differential Revision: https://phabricator.services.mozilla.com/D127839 --- dom/canvas/PWebGL.ipdl | 3 +- gfx/ipc/CanvasManagerChild.cpp | 129 +++++++++++++++++++++ gfx/ipc/CanvasManagerChild.h | 44 +++++++ gfx/ipc/CanvasManagerParent.cpp | 78 +++++++++++++ gfx/ipc/CanvasManagerParent.h | 39 +++++++ gfx/ipc/GPUParent.cpp | 2 + gfx/ipc/PCanvasManager.ipdl | 29 +++++ gfx/ipc/moz.build | 6 + gfx/layers/ipc/CompositorManagerChild.cpp | 5 + gfx/layers/ipc/CompositorManagerChild.h | 9 +- gfx/layers/ipc/CompositorManagerParent.cpp | 7 ++ gfx/layers/ipc/CompositorManagerParent.h | 3 + gfx/layers/ipc/PCompositorManager.ipdl | 3 + gfx/thebes/gfxPlatform.cpp | 5 + gfx/webrender_bindings/RenderThread.cpp | 9 ++ gfx/webrender_bindings/RenderThread.h | 3 + 16 files changed, 371 insertions(+), 3 deletions(-) create mode 100644 gfx/ipc/CanvasManagerChild.cpp create mode 100644 gfx/ipc/CanvasManagerChild.h create mode 100644 gfx/ipc/CanvasManagerParent.cpp create mode 100644 gfx/ipc/CanvasManagerParent.h create mode 100644 gfx/ipc/PCanvasManager.ipdl diff --git a/dom/canvas/PWebGL.ipdl b/dom/canvas/PWebGL.ipdl index 8fdb7e408a7d..73147b0e2171 100644 --- a/dom/canvas/PWebGL.ipdl +++ b/dom/canvas/PWebGL.ipdl @@ -6,6 +6,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ include protocol PCompositorBridge; +include protocol PCanvasManager; using mozilla::layers::CompositableHandle from "mozilla/layers/LayersTypes.h"; using mozilla::layers::SurfaceDescriptor from "mozilla/layers/LayersTypes.h"; @@ -35,7 +36,7 @@ namespace dom { */ [RefCounted] sync protocol PWebGL { - manager PCompositorBridge; + manager PCompositorBridge or PCanvasManager; parent: sync Initialize(InitContextDesc desc) diff --git a/gfx/ipc/CanvasManagerChild.cpp b/gfx/ipc/CanvasManagerChild.cpp new file mode 100644 index 000000000000..433dea36eb2c --- /dev/null +++ b/gfx/ipc/CanvasManagerChild.cpp @@ -0,0 +1,129 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 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/. */ + +#include "CanvasManagerChild.h" +#include "mozilla/dom/WorkerPrivate.h" +#include "mozilla/dom/WorkerRef.h" +#include "mozilla/ipc/Endpoint.h" +#include "mozilla/layers/CompositorManagerChild.h" + +using namespace mozilla::dom; +using namespace mozilla::layers; + +namespace mozilla::gfx { + +// The IPDL actor holds a strong reference to CanvasManagerChild which we use +// to keep it alive. The owning thread will tell us to close when it is +// shutdown, either via CanvasManagerChild::Shutdown for the main thread, or +// via a shutdown callback from IPCWorkerRef for worker threads. +MOZ_THREAD_LOCAL(CanvasManagerChild*) CanvasManagerChild::sLocalManager; + +CanvasManagerChild::CanvasManagerChild() = default; +CanvasManagerChild::~CanvasManagerChild() = default; + +void CanvasManagerChild::ActorDestroy(ActorDestroyReason aReason) { + if (sLocalManager.get() == this) { + sLocalManager.set(nullptr); + } +} + +void CanvasManagerChild::Destroy() { + // The caller has a strong reference. ActorDestroy will clear sLocalManager. + Close(); + mWorkerRef = nullptr; +} + +/* static */ void CanvasManagerChild::Shutdown() { + MOZ_ASSERT(NS_IsMainThread()); + + // The worker threads should destroy their own CanvasManagerChild instances + // during their shutdown sequence. We just need to take care of the main + // thread. We need to init here because we may have never created a + // CanvasManagerChild for the main thread in the first place. + if (sLocalManager.init()) { + RefPtr manager = sLocalManager.get(); + if (manager) { + manager->Destroy(); + } + } +} + +/* static */ bool CanvasManagerChild::CreateParent( + ipc::Endpoint&& aEndpoint) { + MOZ_ASSERT(NS_IsMainThread()); + + CompositorManagerChild* manager = CompositorManagerChild::GetInstance(); + if (!manager || !manager->CanSend()) { + return false; + } + + return manager->SendInitCanvasManager(std::move(aEndpoint)); +} + +/* static */ CanvasManagerChild* CanvasManagerChild::Get() { + if (NS_WARN_IF(!sLocalManager.init())) { + return nullptr; + } + + CanvasManagerChild* managerWeak = sLocalManager.get(); + if (managerWeak) { + return managerWeak; + } + + // We are only used on the main thread, or on worker threads. + WorkerPrivate* worker = GetCurrentThreadWorkerPrivate(); + MOZ_ASSERT_IF(!worker, NS_IsMainThread()); + + ipc::Endpoint parentEndpoint; + ipc::Endpoint childEndpoint; + + auto compositorPid = CompositorManagerChild::GetOtherPid(); + if (NS_WARN_IF(!compositorPid)) { + return nullptr; + } + + nsresult rv = PCanvasManager::CreateEndpoints( + compositorPid, base::GetCurrentProcId(), &parentEndpoint, &childEndpoint); + if (NS_WARN_IF(NS_FAILED(rv))) { + return nullptr; + } + + auto manager = MakeRefPtr(); + + if (worker) { + // The IPCWorkerRef will let us know when the worker is shutting down. This + // will let us clear our threadlocal reference and close the actor. We rely + // upon an explicit shutdown for the main thread. + manager->mWorkerRef = IPCWorkerRef::Create( + worker, "CanvasManager", [manager]() { manager->Destroy(); }); + if (NS_WARN_IF(!manager->mWorkerRef)) { + return nullptr; + } + } + + if (NS_WARN_IF(!childEndpoint.Bind(manager))) { + return nullptr; + } + + // We can't talk to the compositor process directly from worker threads, but + // the main thread can via CompositorManagerChild. + if (worker) { + worker->DispatchToMainThread(NS_NewRunnableFunction( + "CanvasManagerChild::CreateParent", + [parentEndpoint = std::move(parentEndpoint)]() { + CreateParent( + std::move(const_cast&&>( + parentEndpoint))); + })); + } else if (NS_WARN_IF(!CreateParent(std::move(parentEndpoint)))) { + return nullptr; + } + + sLocalManager.set(manager); + return manager; +} + +} // namespace mozilla::gfx diff --git a/gfx/ipc/CanvasManagerChild.h b/gfx/ipc/CanvasManagerChild.h new file mode 100644 index 000000000000..d91e4b24ac96 --- /dev/null +++ b/gfx/ipc/CanvasManagerChild.h @@ -0,0 +1,44 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 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 _include_gfx_ipc_CanvasManagerChild_h__ +#define _include_gfx_ipc_CanvasManagerChild_h__ + +#include "mozilla/gfx/PCanvasManagerChild.h" +#include "mozilla/ThreadLocal.h" + +namespace mozilla { +namespace dom { +class IPCWorkerRef; +class WorkerPrivate; +} // namespace dom + +namespace gfx { + +class CanvasManagerChild final : public PCanvasManagerChild { + public: + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CanvasManagerChild, override); + + CanvasManagerChild(); + void ActorDestroy(ActorDestroyReason aReason) override; + + static CanvasManagerChild* Get(); + static void Shutdown(); + static bool CreateParent( + mozilla::ipc::Endpoint&& aEndpoint); + + private: + ~CanvasManagerChild(); + void Destroy(); + + RefPtr mWorkerRef; + + static MOZ_THREAD_LOCAL(CanvasManagerChild*) sLocalManager; +}; + +} // namespace gfx +} // namespace mozilla + +#endif // _include_gfx_ipc_CanvasManagerChild_h__ diff --git a/gfx/ipc/CanvasManagerParent.cpp b/gfx/ipc/CanvasManagerParent.cpp new file mode 100644 index 000000000000..08917e2059f6 --- /dev/null +++ b/gfx/ipc/CanvasManagerParent.cpp @@ -0,0 +1,78 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 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/. */ + +#include "CanvasManagerParent.h" +#include "mozilla/dom/WebGLParent.h" +#include "mozilla/ipc/Endpoint.h" +#include "mozilla/layers/CompositorThread.h" +#include "mozilla/webrender/RenderThread.h" +#include "nsIThread.h" + +namespace mozilla::gfx { + +CanvasManagerParent::ManagerSet CanvasManagerParent::sManagers; + +/* static */ void CanvasManagerParent::Init( + Endpoint&& aEndpoint) { + MOZ_ASSERT(layers::CompositorThreadHolder::IsInCompositorThread()); + + nsCOMPtr owningThread = wr::RenderThread::GetRenderThread(); + MOZ_ASSERT(owningThread); + + auto manager = MakeRefPtr(); + owningThread->Dispatch(NewRunnableMethod&&>( + "CanvasManagerParent::Bind", manager, &CanvasManagerParent::Bind, + std::move(aEndpoint))); +} + +/* static */ void CanvasManagerParent::Shutdown() { + MOZ_ASSERT(NS_IsMainThread()); + + nsCOMPtr owningThread = wr::RenderThread::GetRenderThread(); + if (!owningThread) { + return; + } + + owningThread->Dispatch( + NS_NewRunnableFunction( + "CanvasManagerParent::Shutdown", + []() -> void { CanvasManagerParent::ShutdownInternal(); }), + NS_DISPATCH_SYNC); +} + +/* static */ void CanvasManagerParent::ShutdownInternal() { + nsTArray> actors(sManagers.Count()); + // Do a copy since Close will remove the entry from the set. + for (const auto& actor : sManagers) { + actors.AppendElement(actor); + } + + for (auto const& actor : actors) { + actor->Close(); + } +} + +CanvasManagerParent::CanvasManagerParent() = default; +CanvasManagerParent::~CanvasManagerParent() = default; + +void CanvasManagerParent::Bind(Endpoint&& aEndpoint) { + if (!aEndpoint.Bind(this)) { + NS_WARNING("Failed to bind CanvasManagerParent!"); + return; + } + + sManagers.Insert(this); +} + +void CanvasManagerParent::ActorDestroy(ActorDestroyReason aWhy) { + sManagers.Remove(this); +} + +already_AddRefed CanvasManagerParent::AllocPWebGLParent() { + return MakeAndAddRef(); +} + +} // namespace mozilla::gfx diff --git a/gfx/ipc/CanvasManagerParent.h b/gfx/ipc/CanvasManagerParent.h new file mode 100644 index 000000000000..cce8fc3177fb --- /dev/null +++ b/gfx/ipc/CanvasManagerParent.h @@ -0,0 +1,39 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 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 _include_gfx_ipc_CanvasManagerParent_h__ +#define _include_gfx_ipc_CanvasManagerParent_h__ + +#include "mozilla/gfx/PCanvasManagerParent.h" +#include "nsHashtablesFwd.h" + +namespace mozilla::gfx { + +class CanvasManagerParent final : public PCanvasManagerParent { + public: + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CanvasManagerParent, override); + + static void Init(Endpoint&& aEndpoint); + + static void Shutdown(); + + CanvasManagerParent(); + + void Bind(Endpoint&& aEndpoint); + void ActorDestroy(ActorDestroyReason aWhy) override; + already_AddRefed AllocPWebGLParent(); + + private: + static void ShutdownInternal(); + + ~CanvasManagerParent(); + + using ManagerSet = nsTHashSet; + static ManagerSet sManagers; +}; + +} // namespace mozilla::gfx + +#endif // _include_gfx_ipc_CanvasManagerParent_h__ diff --git a/gfx/ipc/GPUParent.cpp b/gfx/ipc/GPUParent.cpp index 33cf41a3e1c1..5cd2aeb20943 100644 --- a/gfx/ipc/GPUParent.cpp +++ b/gfx/ipc/GPUParent.cpp @@ -14,6 +14,7 @@ #include "GPUProcessManager.h" #include "gfxGradientCache.h" #include "GfxInfoBase.h" +#include "CanvasManagerParent.h" #include "VRGPUChild.h" #include "VRManager.h" #include "VRManagerParent.h" @@ -629,6 +630,7 @@ void GPUParent::ActorDestroy(ActorDestroyReason aWhy) { } RemoteDecoderManagerParent::ShutdownVideoBridge(); CompositorThreadHolder::Shutdown(); + CanvasManagerParent::Shutdown(); // There is a case that RenderThread exists when gfxVars::UseWebRender() // is false. This could happen when WebRender was fallbacked to // compositor. diff --git a/gfx/ipc/PCanvasManager.ipdl b/gfx/ipc/PCanvasManager.ipdl new file mode 100644 index 000000000000..37a8c04e35b0 --- /dev/null +++ b/gfx/ipc/PCanvasManager.ipdl @@ -0,0 +1,29 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: sw=2 ts=8 et : + */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +include protocol PWebGL; + +namespace mozilla { +namespace gfx { + +/** + * The PCanvasManager protocol is the top-level protocol between the main and + * worker threads in the content process, and the renderer thread in the + * compositor process. This protocol should be used to create accelerated + * canvas instances. + */ +[RefCounted] sync protocol PCanvasManager +{ + manages PWebGL; + +parent: + // Actor that represents one WebGL context. + async PWebGL(); +}; + +} // gfx +} // mozilla diff --git a/gfx/ipc/moz.build b/gfx/ipc/moz.build index 315df2245eab..3714505b118a 100644 --- a/gfx/ipc/moz.build +++ b/gfx/ipc/moz.build @@ -10,6 +10,8 @@ with Files("**"): EXPORTS.mozilla += ["D3DMessageUtils.h", "GfxMessageUtils.h"] EXPORTS.mozilla.gfx += [ + "CanvasManagerChild.h", + "CanvasManagerParent.h", "CrossProcessPaint.h", "GPUChild.h", "GPUParent.h", @@ -34,6 +36,8 @@ EXPORTS.mozilla.widget += [ ] UNIFIED_SOURCES += [ + "CanvasManagerChild.cpp", + "CanvasManagerParent.cpp", "CompositorSession.cpp", "CompositorWidgetVsyncObserver.cpp", "CrossProcessPaint.cpp", @@ -55,6 +59,7 @@ SOURCES += [ IPDL_SOURCES = [ "GraphicsMessages.ipdlh", + "PCanvasManager.ipdl", "PVsyncBridge.ipdl", ] @@ -65,6 +70,7 @@ PREPROCESSED_IPDL_SOURCES += [ LOCAL_INCLUDES += [ "/dom/ipc", "/gfx/cairo/cairo/src", + "/ipc/glue", "/toolkit/crashreporter", "/xpcom/threads", ] diff --git a/gfx/layers/ipc/CompositorManagerChild.cpp b/gfx/layers/ipc/CompositorManagerChild.cpp index 98703bc8ee5a..7956e3cc443c 100644 --- a/gfx/layers/ipc/CompositorManagerChild.cpp +++ b/gfx/layers/ipc/CompositorManagerChild.cpp @@ -23,6 +23,7 @@ namespace layers { using gfx::GPUProcessManager; StaticRefPtr CompositorManagerChild::sInstance; +Atomic CompositorManagerChild::sOtherPid(0); /* static */ bool CompositorManagerChild::IsInitialized(uint64_t aProcessToken) { @@ -51,6 +52,7 @@ void CompositorManagerChild::InitSameProcess(uint32_t aNamespace, parent->BindComplete(/* aIsRoot */ true); sInstance = std::move(child); + sOtherPid = sInstance->OtherPid(); } /* static */ @@ -64,6 +66,7 @@ bool CompositorManagerChild::Init(Endpoint&& aEndpoint, sInstance = new CompositorManagerChild(std::move(aEndpoint), aProcessToken, aNamespace); + sOtherPid = sInstance->OtherPid(); return sInstance->CanSend(); } @@ -78,6 +81,7 @@ void CompositorManagerChild::Shutdown() { sInstance->Close(); sInstance = nullptr; + sOtherPid = 0; } /* static */ @@ -89,6 +93,7 @@ void CompositorManagerChild::OnGPUProcessLost(uint64_t aProcessToken) { // yet to be. As such, we want to pre-emptively set mCanSend to false. if (sInstance && sInstance->mProcessToken == aProcessToken) { sInstance->mCanSend = false; + sOtherPid = 0; } } diff --git a/gfx/layers/ipc/CompositorManagerChild.h b/gfx/layers/ipc/CompositorManagerChild.h index 3e1a6d65e0c1..20c64013c167 100644 --- a/gfx/layers/ipc/CompositorManagerChild.h +++ b/gfx/layers/ipc/CompositorManagerChild.h @@ -7,8 +7,9 @@ #ifndef MOZILLA_GFX_COMPOSITORMANAGERCHILD_H #define MOZILLA_GFX_COMPOSITORMANAGERCHILD_H -#include // for size_t -#include // for uint32_t, uint64_t +#include // for size_t +#include // for uint32_t, uint64_t +#include "mozilla/Atomics.h" #include "mozilla/Attributes.h" // for override #include "mozilla/RefPtr.h" // for already_AddRefed #include "mozilla/StaticPtr.h" // for StaticRefPtr @@ -49,6 +50,9 @@ class CompositorManagerChild : public PCompositorManagerChild { return sInstance; } + // Threadsafe way to get the compositor process ID. + static base::ProcessId GetOtherPid() { return sOtherPid; } + bool CanSend() const { MOZ_ASSERT(NS_IsMainThread()); return mCanSend; @@ -85,6 +89,7 @@ class CompositorManagerChild : public PCompositorManagerChild { private: static StaticRefPtr sInstance; + static Atomic sOtherPid; CompositorManagerChild(CompositorManagerParent* aParent, uint64_t aProcessToken, uint32_t aNamespace); diff --git a/gfx/layers/ipc/CompositorManagerParent.cpp b/gfx/layers/ipc/CompositorManagerParent.cpp index 8b6ee3408095..2d621da52a1b 100644 --- a/gfx/layers/ipc/CompositorManagerParent.cpp +++ b/gfx/layers/ipc/CompositorManagerParent.cpp @@ -6,6 +6,7 @@ #include "mozilla/layers/CompositorManagerParent.h" #include "mozilla/gfx/GPUParent.h" +#include "mozilla/gfx/CanvasManagerParent.h" #include "mozilla/webrender/RenderThread.h" #include "mozilla/ipc/Endpoint.h" #include "mozilla/layers/CompositorBridgeParent.h" @@ -320,6 +321,12 @@ mozilla::ipc::IPCResult CompositorManagerParent::RecvReportMemory( return IPC_OK(); } +mozilla::ipc::IPCResult CompositorManagerParent::RecvInitCanvasManager( + Endpoint&& aEndpoint) { + gfx::CanvasManagerParent::Init(std::move(aEndpoint)); + return IPC_OK(); +} + /* static */ void CompositorManagerParent::NotifyWebRenderError(wr::WebRenderError aError) { MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); diff --git a/gfx/layers/ipc/CompositorManagerParent.h b/gfx/layers/ipc/CompositorManagerParent.h index f16a85aca499..2933f4025085 100644 --- a/gfx/layers/ipc/CompositorManagerParent.h +++ b/gfx/layers/ipc/CompositorManagerParent.h @@ -51,6 +51,9 @@ class CompositorManagerParent final : public PCompositorManagerParent { mozilla::ipc::IPCResult RecvReportMemory(ReportMemoryResolver&&); + mozilla::ipc::IPCResult RecvInitCanvasManager( + Endpoint&&); + void BindComplete(bool aIsRoot); void ActorDestroy(ActorDestroyReason aReason) override; diff --git a/gfx/layers/ipc/PCompositorManager.ipdl b/gfx/layers/ipc/PCompositorManager.ipdl index 3b8ad2ca45fd..551d6e2d9180 100644 --- a/gfx/layers/ipc/PCompositorManager.ipdl +++ b/gfx/layers/ipc/PCompositorManager.ipdl @@ -5,6 +5,7 @@ * 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 PCanvasManager; include protocol PCompositorBridge; include LayersSurfaces; include "mozilla/GfxMessageUtils.h"; @@ -84,6 +85,8 @@ parent: async ReportMemory() returns (MemoryReport aReport); + async InitCanvasManager(Endpoint endpoint); + child: async NotifyWebRenderError(WebRenderError error); }; diff --git a/gfx/thebes/gfxPlatform.cpp b/gfx/thebes/gfxPlatform.cpp index b99e1721aeb7..fdcde9148136 100644 --- a/gfx/thebes/gfxPlatform.cpp +++ b/gfx/thebes/gfxPlatform.cpp @@ -19,6 +19,8 @@ #include "mozilla/gfx/gfxVars.h" #include "mozilla/gfx/GPUProcessManager.h" #include "mozilla/gfx/GraphicsMessages.h" +#include "mozilla/gfx/CanvasManagerChild.h" +#include "mozilla/gfx/CanvasManagerParent.h" #include "mozilla/ClearOnShutdown.h" #include "mozilla/StaticPrefs_accessibility.h" #include "mozilla/StaticPrefs_apz.h" @@ -1305,6 +1307,7 @@ void gfxPlatform::ShutdownLayersIPC() { if (XRE_IsContentProcess()) { gfx::VRManagerChild::ShutDown(); + gfx::CanvasManagerChild::Shutdown(); // cf bug 1215265. if (StaticPrefs::layers_child_process_shutdown()) { layers::CompositorManagerChild::Shutdown(); @@ -1313,11 +1316,13 @@ void gfxPlatform::ShutdownLayersIPC() { } else if (XRE_IsParentProcess()) { gfx::VRManagerChild::ShutDown(); + gfx::CanvasManagerChild::Shutdown(); layers::CompositorManagerChild::Shutdown(); layers::ImageBridgeChild::ShutDown(); // This has to happen after shutting down the child protocols. layers::CompositorThreadHolder::Shutdown(); image::ImageMemoryReporter::ShutdownForWebRender(); + gfx::CanvasManagerParent::Shutdown(); // There is a case that RenderThread exists when UseWebRender() is // false. This could happen when WebRender was fallbacked to compositor. if (wr::RenderThread::Get()) { diff --git a/gfx/webrender_bindings/RenderThread.cpp b/gfx/webrender_bindings/RenderThread.cpp index 2289e8e7222d..72c30b729da6 100644 --- a/gfx/webrender_bindings/RenderThread.cpp +++ b/gfx/webrender_bindings/RenderThread.cpp @@ -173,6 +173,15 @@ bool RenderThread::IsInRenderThread() { return sRenderThread && sRenderThread->mThread == NS_GetCurrentThread(); } +// static +already_AddRefed RenderThread::GetRenderThread() { + nsCOMPtr thread; + if (sRenderThread) { + thread = sRenderThread->mThread; + } + return thread.forget(); +} + void RenderThread::DoAccumulateMemoryReport( MemoryReport aReport, const RefPtr& aPromise) { diff --git a/gfx/webrender_bindings/RenderThread.h b/gfx/webrender_bindings/RenderThread.h index 127c89d84682..d56462a2be3a 100644 --- a/gfx/webrender_bindings/RenderThread.h +++ b/gfx/webrender_bindings/RenderThread.h @@ -146,6 +146,9 @@ class RenderThread final { /// Can be called from any thread. static bool IsInRenderThread(); + /// Can be called from any thread. + static already_AddRefed GetRenderThread(); + // Can be called from any thread. Dispatches an event to the Renderer thread // to iterate over all Renderers, accumulates memory statistics, and resolves // the return promise.