diff --git a/gfx/ipc/CanvasManagerParent.cpp b/gfx/ipc/CanvasManagerParent.cpp index 7d6519011b12..bdb441c3ddbe 100644 --- a/gfx/ipc/CanvasManagerParent.cpp +++ b/gfx/ipc/CanvasManagerParent.cpp @@ -13,7 +13,6 @@ #include "mozilla/ipc/Endpoint.h" #include "mozilla/layers/CompositorThread.h" #include "mozilla/webgpu/WebGPUParent.h" -#include "mozilla/webrender/RenderThread.h" #include "nsIThread.h" #include "nsThreadUtils.h" @@ -27,41 +26,21 @@ CanvasManagerParent::ManagerSet CanvasManagerParent::sManagers; auto manager = MakeRefPtr(); - if (!gfxVars::SupportsThreadsafeGL()) { - nsCOMPtr owningThread; - owningThread = wr::RenderThread::GetRenderThread(); - MOZ_ASSERT(owningThread); + nsCOMPtr owningThread = + gfx::CanvasRenderThread::GetCanvasRenderThread(); + MOZ_ASSERT(owningThread); - owningThread->Dispatch(NewRunnableMethod&&>( - "CanvasManagerParent::Bind", manager, &CanvasManagerParent::Bind, - std::move(aEndpoint))); - } else if (gfxVars::UseCanvasRenderThread()) { - nsCOMPtr owningThread; - owningThread = gfx::CanvasRenderThread::GetCanvasRenderThread(); - MOZ_ASSERT(owningThread); - - owningThread->Dispatch(NewRunnableMethod&&>( - "CanvasManagerParent::Bind", manager, &CanvasManagerParent::Bind, - std::move(aEndpoint))); - } else { - manager->Bind(std::move(aEndpoint)); - } + owningThread->Dispatch(NewRunnableMethod&&>( + "CanvasManagerParent::Bind", manager, &CanvasManagerParent::Bind, + std::move(aEndpoint))); } /* static */ void CanvasManagerParent::Shutdown() { MOZ_ASSERT(NS_IsMainThread()); - nsCOMPtr owningThread; - if (!gfxVars::SupportsThreadsafeGL()) { - owningThread = wr::RenderThread::GetRenderThread(); - } else if (gfxVars::UseCanvasRenderThread()) { - owningThread = gfx::CanvasRenderThread::GetCanvasRenderThread(); - } else { - owningThread = layers::CompositorThread(); - } - if (!owningThread) { - return; - } + nsCOMPtr owningThread = + gfx::CanvasRenderThread::GetCanvasRenderThread(); + MOZ_ASSERT(owningThread); NS_DispatchAndSpinEventLoopUntilComplete( "CanvasManagerParent::Shutdown"_ns, owningThread, diff --git a/gfx/ipc/CanvasRenderThread.cpp b/gfx/ipc/CanvasRenderThread.cpp index 5af627d8eb6b..4e6285d7a48a 100644 --- a/gfx/ipc/CanvasRenderThread.cpp +++ b/gfx/ipc/CanvasRenderThread.cpp @@ -7,6 +7,10 @@ #include "CanvasRenderThread.h" #include "mozilla/BackgroundHangMonitor.h" +#include "mozilla/gfx/CanvasManagerParent.h" +#include "mozilla/gfx/gfxVars.h" +#include "mozilla/layers/CompositorThread.h" +#include "mozilla/webrender/RenderThread.h" #include "transport/runnable_utils.h" namespace mozilla::gfx { @@ -17,13 +21,11 @@ static mozilla::BackgroundHangMonitor* sBackgroundHangMonitor; static bool sCanvasRenderThreadEverStarted = false; #endif -CanvasRenderThread::CanvasRenderThread(RefPtr aThread) - : mThread(std::move(aThread)) {} +CanvasRenderThread::CanvasRenderThread(nsCOMPtr&& aThread, + bool aCreatedThread) + : mThread(std::move(aThread)), mCreatedThread(aCreatedThread) {} -CanvasRenderThread::~CanvasRenderThread() {} - -// static -CanvasRenderThread* CanvasRenderThread::Get() { return sCanvasRenderThread; } +CanvasRenderThread::~CanvasRenderThread() = default; // static void CanvasRenderThread::Start() { @@ -37,6 +39,21 @@ void CanvasRenderThread::Start() { sCanvasRenderThreadEverStarted = true; #endif + nsCOMPtr thread; + if (!gfxVars::SupportsThreadsafeGL()) { + thread = wr::RenderThread::GetRenderThread(); + MOZ_ASSERT(thread); + } else if (!gfxVars::UseCanvasRenderThread()) { + thread = layers::CompositorThread(); + MOZ_ASSERT(thread); + } + + if (thread) { + sCanvasRenderThread = + new CanvasRenderThread(std::move(thread), /* aCreatedThread */ false); + return; + } + // This is 4M, which is higher than the default 256K. // Increased with bug 1753349 to accommodate the `chromium/5359` branch of // ANGLE, which has large peak stack usage for some pathological shader @@ -51,7 +68,6 @@ void CanvasRenderThread::Start() { const uint32_t stackSize = nsIThreadManager::DEFAULT_STACK_SIZE ? 4096 << 10 : 0; - RefPtr thread; nsresult rv = NS_NewNamedThread( "CanvasRenderer", getter_AddRefs(thread), NS_NewRunnableFunction( @@ -75,26 +91,41 @@ void CanvasRenderThread::Start() { }), {.stackSize = stackSize}); - if (NS_FAILED(rv)) { + if (NS_WARN_IF(NS_FAILED(rv))) { return; } - sCanvasRenderThread = new CanvasRenderThread(thread); + sCanvasRenderThread = + new CanvasRenderThread(std::move(thread), /* aCreatedThread */ true); } // static -void CanvasRenderThread::ShutDown() { +void CanvasRenderThread::Shutdown() { MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(sCanvasRenderThread); + + // It is possible we never initialized this thread in the parent process, + // because we used the GPU process instead. + if (!sCanvasRenderThread) { + MOZ_ASSERT(XRE_IsParentProcess()); + return; + } + + CanvasManagerParent::Shutdown(); // Null out sCanvasRenderThread before we enter synchronous Shutdown, // from here on we are to be considered shut down for our consumers. - nsCOMPtr oldThread = sCanvasRenderThread->GetCanvasRenderThread(); + nsCOMPtr oldThread; + if (sCanvasRenderThread->mCreatedThread) { + oldThread = sCanvasRenderThread->GetCanvasRenderThread(); + MOZ_ASSERT(oldThread); + } sCanvasRenderThread = nullptr; - // We do a synchronous shutdown here while spinning the MT event loop. - MOZ_ASSERT(oldThread); - oldThread->Shutdown(); + // We do a synchronous shutdown here while spinning the MT event loop, but + // only if we created a dedicated CanvasRender thread. + if (oldThread) { + oldThread->Shutdown(); + } } // static diff --git a/gfx/ipc/CanvasRenderThread.h b/gfx/ipc/CanvasRenderThread.h index 08dd6c6d5442..303f489e5334 100644 --- a/gfx/ipc/CanvasRenderThread.h +++ b/gfx/ipc/CanvasRenderThread.h @@ -13,22 +13,28 @@ #include "nsISupportsImpl.h" #include "nsThread.h" +class nsIRunnable; + namespace mozilla::gfx { +/** + * This class represents the virtual thread for canvas rendering. Depending on + * platform requirements and user configuration, canvas rendering may happen on + * the Compositor thread, Render thread or the CanvasRender thread. + */ class CanvasRenderThread final { NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_DELETE_ON_MAIN_THREAD( CanvasRenderThread) public: - /// Can be called from any thread, may return nullptr late in shutdown. - static CanvasRenderThread* Get(); - /// Can only be called from the main thread, expected to be called at most - /// once during a process' lifetime. + /// once during a process' lifetime. Must be called after the Compositor and + /// Render threads are initialized. static void Start(); - /// Can only be called from the main thread. - static void ShutDown(); + /// Can only be called from the main thread. Must be called before the + /// Compositor and Render threads are shutdown. + static void Shutdown(); /// Can be called from any thread. static bool IsInCanvasRenderThread(); @@ -37,12 +43,16 @@ class CanvasRenderThread final { static already_AddRefed GetCanvasRenderThread(); private: - explicit CanvasRenderThread(RefPtr aThread); + CanvasRenderThread(nsCOMPtr&& aThread, bool aCreatedThread); ~CanvasRenderThread(); void PostRunnable(already_AddRefed aRunnable); - RefPtr const mThread; + nsCOMPtr const mThread; + + // True if mThread points to CanvasRender thread, false if mThread points to + // Compositor/Render thread. + bool mCreatedThread; }; } // namespace mozilla::gfx diff --git a/gfx/ipc/GPUParent.cpp b/gfx/ipc/GPUParent.cpp index c9304e48df95..f13e5d91e03e 100644 --- a/gfx/ipc/GPUParent.cpp +++ b/gfx/ipc/GPUParent.cpp @@ -14,7 +14,6 @@ #include "GPUProcessManager.h" #include "gfxGradientCache.h" #include "GfxInfoBase.h" -#include "CanvasManagerParent.h" #include "VRGPUChild.h" #include "VRManager.h" #include "VRManagerParent.h" @@ -378,10 +377,8 @@ mozilla::ipc::IPCResult GPUParent::RecvInit( #endif // Make sure to do this *after* we update gfxVars above. - if (gfxVars::UseCanvasRenderThread()) { - gfx::CanvasRenderThread::Start(); - } wr::RenderThread::Start(aWrNamespace); + gfx::CanvasRenderThread::Start(); image::ImageMemoryReporter::InitForWebRender(); VRManager::ManagerInit(); @@ -700,9 +697,10 @@ void GPUParent::ActorDestroy(ActorDestroyReason aWhy) { self->mVsyncBridge = nullptr; } VideoBridgeParent::Shutdown(); - // This could be running on either the Compositor or the Renderer - // thread. - CanvasManagerParent::Shutdown(); + // This could be running on either the Compositor thread, the Renderer + // thread, or the dedicated CanvasRender thread, so we need to shutdown + // before the former two. + CanvasRenderThread::Shutdown(); CompositorThreadHolder::Shutdown(); RemoteTextureMap::Shutdown(); // There is a case that RenderThread exists when gfxVars::UseWebRender() @@ -711,9 +709,6 @@ void GPUParent::ActorDestroy(ActorDestroyReason aWhy) { if (wr::RenderThread::Get()) { wr::RenderThread::ShutDown(); } - if (gfx::CanvasRenderThread::Get()) { - gfx::CanvasRenderThread::ShutDown(); - } #ifdef XP_WIN if (widget::WinCompositorWindowThread::Get()) { widget::WinCompositorWindowThread::ShutDown(); diff --git a/gfx/layers/ipc/CompositorThread.cpp b/gfx/layers/ipc/CompositorThread.cpp index c66de80cfb49..3453f72e34f3 100644 --- a/gfx/layers/ipc/CompositorThread.cpp +++ b/gfx/layers/ipc/CompositorThread.cpp @@ -28,7 +28,7 @@ static Atomic sFinishedCompositorShutDown(false); static mozilla::BackgroundHangMonitor* sBackgroundHangMonitor; static ProfilerThreadId sProfilerThreadId; -nsISerialEventTarget* CompositorThread() { +nsIThread* CompositorThread() { return sCompositorThreadHolder ? sCompositorThreadHolder->GetCompositorThread() : nullptr; diff --git a/gfx/layers/ipc/CompositorThread.h b/gfx/layers/ipc/CompositorThread.h index 3a07e21620df..fea479906035 100644 --- a/gfx/layers/ipc/CompositorThread.h +++ b/gfx/layers/ipc/CompositorThread.h @@ -13,7 +13,6 @@ namespace mozilla::baseprofiler { class BaseProfilerThreadId; } using ProfilerThreadId = mozilla::baseprofiler::BaseProfilerThreadId; -class nsISerialEventTarget; class nsIThread; namespace mozilla { @@ -26,9 +25,7 @@ class CompositorThreadHolder final { public: CompositorThreadHolder(); - nsISerialEventTarget* GetCompositorThread() const { - return mCompositorThread; - } + nsIThread* GetCompositorThread() const { return mCompositorThread; } static CompositorThreadHolder* GetSingleton(); @@ -61,7 +58,7 @@ class CompositorThreadHolder final { friend class CompositorBridgeParent; }; -nsISerialEventTarget* CompositorThread(); +nsIThread* CompositorThread(); } // namespace layers } // namespace mozilla diff --git a/gfx/thebes/gfxPlatform.cpp b/gfx/thebes/gfxPlatform.cpp index 04c1732fe32d..1b19f6ebb54d 100644 --- a/gfx/thebes/gfxPlatform.cpp +++ b/gfx/thebes/gfxPlatform.cpp @@ -22,7 +22,6 @@ #include "mozilla/gfx/GPUProcessManager.h" #include "mozilla/gfx/GraphicsMessages.h" #include "mozilla/gfx/CanvasManagerChild.h" -#include "mozilla/gfx/CanvasManagerParent.h" #include "mozilla/gfx/CanvasRenderThread.h" #include "mozilla/ClearOnShutdown.h" #include "mozilla/DebugOnly.h" @@ -1309,14 +1308,15 @@ void gfxPlatform::InitLayersIPC() { #endif if (!gfxConfig::IsEnabled(Feature::GPU_PROCESS)) { RemoteTextureMap::Init(); - if (gfxVars::UseCanvasRenderThread()) { - gfx::CanvasRenderThread::Start(); - } wr::RenderThread::Start(GPUProcessManager::Get()->AllocateNamespace()); image::ImageMemoryReporter::InitForWebRender(); } layers::CompositorThreadHolder::Start(); + + if (!gfxConfig::IsEnabled(Feature::GPU_PROCESS)) { + gfx::CanvasRenderThread::Start(); + } } } @@ -1343,8 +1343,10 @@ void gfxPlatform::ShutdownLayersIPC() { gfx::CanvasManagerChild::Shutdown(); layers::CompositorManagerChild::Shutdown(); layers::ImageBridgeChild::ShutDown(); - // This could be running on either the Compositor or the Renderer thread. - gfx::CanvasManagerParent::Shutdown(); + // This could be running on either the Compositor thread, the Renderer + // thread, or the dedicated CanvasRender thread, so we need to shutdown + // before the former two. + gfx::CanvasRenderThread::Shutdown(); // This has to happen after shutting down the child protocols. layers::CompositorThreadHolder::Shutdown(); RemoteTextureMap::Shutdown(); @@ -1363,9 +1365,6 @@ void gfxPlatform::ShutdownLayersIPC() { nsDependentCString( StaticPrefs::GetPrefName_gfx_webrender_blob_tile_size())); } - if (gfx::CanvasRenderThread::Get()) { - gfx::CanvasRenderThread::ShutDown(); - } #if defined(XP_WIN) widget::WinWindowOcclusionTracker::ShutDown(); #endif @@ -3851,12 +3850,10 @@ void gfxPlatform::DisableGPUProcess() { } RemoteTextureMap::Init(); - if (gfxVars::UseCanvasRenderThread()) { - gfx::CanvasRenderThread::Start(); - } // We need to initialize the parent process to prepare for WebRender if we // did not end up disabling it, despite losing the GPU process. wr::RenderThread::Start(GPUProcessManager::Get()->AllocateNamespace()); + gfx::CanvasRenderThread::Start(); image::ImageMemoryReporter::InitForWebRender(); }