Bug 1852145 - Part 1. Refactor CanvasRenderThread to represent a virtual thread. r=gfx-reviewers,lsalzman

Prior to this patch, CanvasRenderThread represents the concrete thread
we would spawn if gfxVars::UseCanvasRenderThread() returned true.
CanvasManagerParent was responsible for checking our state and deciding
between using the Compositor, Renderer and CanvasRender threads.

This patch makes the CanvasRenderThread class represent a virtual
thread. It will spawn a CanvasRender thread if necessary. Other classes
may use the abstraction to run on the correct thread without having to
duplicate the selection logic.

Differential Revision: https://phabricator.services.mozilla.com/D187719
This commit is contained in:
Andrew Osmond 2023-09-25 16:18:35 +00:00
Родитель 620833163a
Коммит f1d22fb2f1
7 изменённых файлов: 90 добавлений и 81 удалений

Просмотреть файл

@ -13,7 +13,6 @@
#include "mozilla/ipc/Endpoint.h" #include "mozilla/ipc/Endpoint.h"
#include "mozilla/layers/CompositorThread.h" #include "mozilla/layers/CompositorThread.h"
#include "mozilla/webgpu/WebGPUParent.h" #include "mozilla/webgpu/WebGPUParent.h"
#include "mozilla/webrender/RenderThread.h"
#include "nsIThread.h" #include "nsIThread.h"
#include "nsThreadUtils.h" #include "nsThreadUtils.h"
@ -27,41 +26,21 @@ CanvasManagerParent::ManagerSet CanvasManagerParent::sManagers;
auto manager = MakeRefPtr<CanvasManagerParent>(); auto manager = MakeRefPtr<CanvasManagerParent>();
if (!gfxVars::SupportsThreadsafeGL()) { nsCOMPtr<nsIThread> owningThread =
nsCOMPtr<nsIThread> owningThread; gfx::CanvasRenderThread::GetCanvasRenderThread();
owningThread = wr::RenderThread::GetRenderThread(); MOZ_ASSERT(owningThread);
MOZ_ASSERT(owningThread);
owningThread->Dispatch(NewRunnableMethod<Endpoint<PCanvasManagerParent>&&>( owningThread->Dispatch(NewRunnableMethod<Endpoint<PCanvasManagerParent>&&>(
"CanvasManagerParent::Bind", manager, &CanvasManagerParent::Bind, "CanvasManagerParent::Bind", manager, &CanvasManagerParent::Bind,
std::move(aEndpoint))); std::move(aEndpoint)));
} else if (gfxVars::UseCanvasRenderThread()) {
nsCOMPtr<nsIThread> owningThread;
owningThread = gfx::CanvasRenderThread::GetCanvasRenderThread();
MOZ_ASSERT(owningThread);
owningThread->Dispatch(NewRunnableMethod<Endpoint<PCanvasManagerParent>&&>(
"CanvasManagerParent::Bind", manager, &CanvasManagerParent::Bind,
std::move(aEndpoint)));
} else {
manager->Bind(std::move(aEndpoint));
}
} }
/* static */ void CanvasManagerParent::Shutdown() { /* static */ void CanvasManagerParent::Shutdown() {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
nsCOMPtr<nsISerialEventTarget> owningThread; nsCOMPtr<nsIThread> owningThread =
if (!gfxVars::SupportsThreadsafeGL()) { gfx::CanvasRenderThread::GetCanvasRenderThread();
owningThread = wr::RenderThread::GetRenderThread(); MOZ_ASSERT(owningThread);
} else if (gfxVars::UseCanvasRenderThread()) {
owningThread = gfx::CanvasRenderThread::GetCanvasRenderThread();
} else {
owningThread = layers::CompositorThread();
}
if (!owningThread) {
return;
}
NS_DispatchAndSpinEventLoopUntilComplete( NS_DispatchAndSpinEventLoopUntilComplete(
"CanvasManagerParent::Shutdown"_ns, owningThread, "CanvasManagerParent::Shutdown"_ns, owningThread,

Просмотреть файл

@ -7,6 +7,10 @@
#include "CanvasRenderThread.h" #include "CanvasRenderThread.h"
#include "mozilla/BackgroundHangMonitor.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" #include "transport/runnable_utils.h"
namespace mozilla::gfx { namespace mozilla::gfx {
@ -17,13 +21,11 @@ static mozilla::BackgroundHangMonitor* sBackgroundHangMonitor;
static bool sCanvasRenderThreadEverStarted = false; static bool sCanvasRenderThreadEverStarted = false;
#endif #endif
CanvasRenderThread::CanvasRenderThread(RefPtr<nsIThread> aThread) CanvasRenderThread::CanvasRenderThread(nsCOMPtr<nsIThread>&& aThread,
: mThread(std::move(aThread)) {} bool aCreatedThread)
: mThread(std::move(aThread)), mCreatedThread(aCreatedThread) {}
CanvasRenderThread::~CanvasRenderThread() {} CanvasRenderThread::~CanvasRenderThread() = default;
// static
CanvasRenderThread* CanvasRenderThread::Get() { return sCanvasRenderThread; }
// static // static
void CanvasRenderThread::Start() { void CanvasRenderThread::Start() {
@ -37,6 +39,21 @@ void CanvasRenderThread::Start() {
sCanvasRenderThreadEverStarted = true; sCanvasRenderThreadEverStarted = true;
#endif #endif
nsCOMPtr<nsIThread> 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. // This is 4M, which is higher than the default 256K.
// Increased with bug 1753349 to accommodate the `chromium/5359` branch of // Increased with bug 1753349 to accommodate the `chromium/5359` branch of
// ANGLE, which has large peak stack usage for some pathological shader // ANGLE, which has large peak stack usage for some pathological shader
@ -51,7 +68,6 @@ void CanvasRenderThread::Start() {
const uint32_t stackSize = const uint32_t stackSize =
nsIThreadManager::DEFAULT_STACK_SIZE ? 4096 << 10 : 0; nsIThreadManager::DEFAULT_STACK_SIZE ? 4096 << 10 : 0;
RefPtr<nsIThread> thread;
nsresult rv = NS_NewNamedThread( nsresult rv = NS_NewNamedThread(
"CanvasRenderer", getter_AddRefs(thread), "CanvasRenderer", getter_AddRefs(thread),
NS_NewRunnableFunction( NS_NewRunnableFunction(
@ -75,26 +91,41 @@ void CanvasRenderThread::Start() {
}), }),
{.stackSize = stackSize}); {.stackSize = stackSize});
if (NS_FAILED(rv)) { if (NS_WARN_IF(NS_FAILED(rv))) {
return; return;
} }
sCanvasRenderThread = new CanvasRenderThread(thread); sCanvasRenderThread =
new CanvasRenderThread(std::move(thread), /* aCreatedThread */ true);
} }
// static // static
void CanvasRenderThread::ShutDown() { void CanvasRenderThread::Shutdown() {
MOZ_ASSERT(NS_IsMainThread()); 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, // Null out sCanvasRenderThread before we enter synchronous Shutdown,
// from here on we are to be considered shut down for our consumers. // from here on we are to be considered shut down for our consumers.
nsCOMPtr<nsIThread> oldThread = sCanvasRenderThread->GetCanvasRenderThread(); nsCOMPtr<nsIThread> oldThread;
if (sCanvasRenderThread->mCreatedThread) {
oldThread = sCanvasRenderThread->GetCanvasRenderThread();
MOZ_ASSERT(oldThread);
}
sCanvasRenderThread = nullptr; sCanvasRenderThread = nullptr;
// We do a synchronous shutdown here while spinning the MT event loop. // We do a synchronous shutdown here while spinning the MT event loop, but
MOZ_ASSERT(oldThread); // only if we created a dedicated CanvasRender thread.
oldThread->Shutdown(); if (oldThread) {
oldThread->Shutdown();
}
} }
// static // static

Просмотреть файл

@ -13,22 +13,28 @@
#include "nsISupportsImpl.h" #include "nsISupportsImpl.h"
#include "nsThread.h" #include "nsThread.h"
class nsIRunnable;
namespace mozilla::gfx { 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 { class CanvasRenderThread final {
NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_DELETE_ON_MAIN_THREAD( NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_DELETE_ON_MAIN_THREAD(
CanvasRenderThread) CanvasRenderThread)
public: 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 /// 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(); static void Start();
/// Can only be called from the main thread. /// Can only be called from the main thread. Must be called before the
static void ShutDown(); /// Compositor and Render threads are shutdown.
static void Shutdown();
/// Can be called from any thread. /// Can be called from any thread.
static bool IsInCanvasRenderThread(); static bool IsInCanvasRenderThread();
@ -37,12 +43,16 @@ class CanvasRenderThread final {
static already_AddRefed<nsIThread> GetCanvasRenderThread(); static already_AddRefed<nsIThread> GetCanvasRenderThread();
private: private:
explicit CanvasRenderThread(RefPtr<nsIThread> aThread); CanvasRenderThread(nsCOMPtr<nsIThread>&& aThread, bool aCreatedThread);
~CanvasRenderThread(); ~CanvasRenderThread();
void PostRunnable(already_AddRefed<nsIRunnable> aRunnable); void PostRunnable(already_AddRefed<nsIRunnable> aRunnable);
RefPtr<nsIThread> const mThread; nsCOMPtr<nsIThread> const mThread;
// True if mThread points to CanvasRender thread, false if mThread points to
// Compositor/Render thread.
bool mCreatedThread;
}; };
} // namespace mozilla::gfx } // namespace mozilla::gfx

Просмотреть файл

@ -14,7 +14,6 @@
#include "GPUProcessManager.h" #include "GPUProcessManager.h"
#include "gfxGradientCache.h" #include "gfxGradientCache.h"
#include "GfxInfoBase.h" #include "GfxInfoBase.h"
#include "CanvasManagerParent.h"
#include "VRGPUChild.h" #include "VRGPUChild.h"
#include "VRManager.h" #include "VRManager.h"
#include "VRManagerParent.h" #include "VRManagerParent.h"
@ -378,10 +377,8 @@ mozilla::ipc::IPCResult GPUParent::RecvInit(
#endif #endif
// Make sure to do this *after* we update gfxVars above. // Make sure to do this *after* we update gfxVars above.
if (gfxVars::UseCanvasRenderThread()) {
gfx::CanvasRenderThread::Start();
}
wr::RenderThread::Start(aWrNamespace); wr::RenderThread::Start(aWrNamespace);
gfx::CanvasRenderThread::Start();
image::ImageMemoryReporter::InitForWebRender(); image::ImageMemoryReporter::InitForWebRender();
VRManager::ManagerInit(); VRManager::ManagerInit();
@ -700,9 +697,10 @@ void GPUParent::ActorDestroy(ActorDestroyReason aWhy) {
self->mVsyncBridge = nullptr; self->mVsyncBridge = nullptr;
} }
VideoBridgeParent::Shutdown(); VideoBridgeParent::Shutdown();
// This could be running on either the Compositor or the Renderer // This could be running on either the Compositor thread, the Renderer
// thread. // thread, or the dedicated CanvasRender thread, so we need to shutdown
CanvasManagerParent::Shutdown(); // before the former two.
CanvasRenderThread::Shutdown();
CompositorThreadHolder::Shutdown(); CompositorThreadHolder::Shutdown();
RemoteTextureMap::Shutdown(); RemoteTextureMap::Shutdown();
// There is a case that RenderThread exists when gfxVars::UseWebRender() // There is a case that RenderThread exists when gfxVars::UseWebRender()
@ -711,9 +709,6 @@ void GPUParent::ActorDestroy(ActorDestroyReason aWhy) {
if (wr::RenderThread::Get()) { if (wr::RenderThread::Get()) {
wr::RenderThread::ShutDown(); wr::RenderThread::ShutDown();
} }
if (gfx::CanvasRenderThread::Get()) {
gfx::CanvasRenderThread::ShutDown();
}
#ifdef XP_WIN #ifdef XP_WIN
if (widget::WinCompositorWindowThread::Get()) { if (widget::WinCompositorWindowThread::Get()) {
widget::WinCompositorWindowThread::ShutDown(); widget::WinCompositorWindowThread::ShutDown();

Просмотреть файл

@ -28,7 +28,7 @@ static Atomic<bool> sFinishedCompositorShutDown(false);
static mozilla::BackgroundHangMonitor* sBackgroundHangMonitor; static mozilla::BackgroundHangMonitor* sBackgroundHangMonitor;
static ProfilerThreadId sProfilerThreadId; static ProfilerThreadId sProfilerThreadId;
nsISerialEventTarget* CompositorThread() { nsIThread* CompositorThread() {
return sCompositorThreadHolder return sCompositorThreadHolder
? sCompositorThreadHolder->GetCompositorThread() ? sCompositorThreadHolder->GetCompositorThread()
: nullptr; : nullptr;

Просмотреть файл

@ -13,7 +13,6 @@ namespace mozilla::baseprofiler {
class BaseProfilerThreadId; class BaseProfilerThreadId;
} }
using ProfilerThreadId = mozilla::baseprofiler::BaseProfilerThreadId; using ProfilerThreadId = mozilla::baseprofiler::BaseProfilerThreadId;
class nsISerialEventTarget;
class nsIThread; class nsIThread;
namespace mozilla { namespace mozilla {
@ -26,9 +25,7 @@ class CompositorThreadHolder final {
public: public:
CompositorThreadHolder(); CompositorThreadHolder();
nsISerialEventTarget* GetCompositorThread() const { nsIThread* GetCompositorThread() const { return mCompositorThread; }
return mCompositorThread;
}
static CompositorThreadHolder* GetSingleton(); static CompositorThreadHolder* GetSingleton();
@ -61,7 +58,7 @@ class CompositorThreadHolder final {
friend class CompositorBridgeParent; friend class CompositorBridgeParent;
}; };
nsISerialEventTarget* CompositorThread(); nsIThread* CompositorThread();
} // namespace layers } // namespace layers
} // namespace mozilla } // namespace mozilla

Просмотреть файл

@ -22,7 +22,6 @@
#include "mozilla/gfx/GPUProcessManager.h" #include "mozilla/gfx/GPUProcessManager.h"
#include "mozilla/gfx/GraphicsMessages.h" #include "mozilla/gfx/GraphicsMessages.h"
#include "mozilla/gfx/CanvasManagerChild.h" #include "mozilla/gfx/CanvasManagerChild.h"
#include "mozilla/gfx/CanvasManagerParent.h"
#include "mozilla/gfx/CanvasRenderThread.h" #include "mozilla/gfx/CanvasRenderThread.h"
#include "mozilla/ClearOnShutdown.h" #include "mozilla/ClearOnShutdown.h"
#include "mozilla/DebugOnly.h" #include "mozilla/DebugOnly.h"
@ -1309,14 +1308,15 @@ void gfxPlatform::InitLayersIPC() {
#endif #endif
if (!gfxConfig::IsEnabled(Feature::GPU_PROCESS)) { if (!gfxConfig::IsEnabled(Feature::GPU_PROCESS)) {
RemoteTextureMap::Init(); RemoteTextureMap::Init();
if (gfxVars::UseCanvasRenderThread()) {
gfx::CanvasRenderThread::Start();
}
wr::RenderThread::Start(GPUProcessManager::Get()->AllocateNamespace()); wr::RenderThread::Start(GPUProcessManager::Get()->AllocateNamespace());
image::ImageMemoryReporter::InitForWebRender(); image::ImageMemoryReporter::InitForWebRender();
} }
layers::CompositorThreadHolder::Start(); layers::CompositorThreadHolder::Start();
if (!gfxConfig::IsEnabled(Feature::GPU_PROCESS)) {
gfx::CanvasRenderThread::Start();
}
} }
} }
@ -1343,8 +1343,10 @@ void gfxPlatform::ShutdownLayersIPC() {
gfx::CanvasManagerChild::Shutdown(); gfx::CanvasManagerChild::Shutdown();
layers::CompositorManagerChild::Shutdown(); layers::CompositorManagerChild::Shutdown();
layers::ImageBridgeChild::ShutDown(); layers::ImageBridgeChild::ShutDown();
// This could be running on either the Compositor or the Renderer thread. // This could be running on either the Compositor thread, the Renderer
gfx::CanvasManagerParent::Shutdown(); // 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. // This has to happen after shutting down the child protocols.
layers::CompositorThreadHolder::Shutdown(); layers::CompositorThreadHolder::Shutdown();
RemoteTextureMap::Shutdown(); RemoteTextureMap::Shutdown();
@ -1363,9 +1365,6 @@ void gfxPlatform::ShutdownLayersIPC() {
nsDependentCString( nsDependentCString(
StaticPrefs::GetPrefName_gfx_webrender_blob_tile_size())); StaticPrefs::GetPrefName_gfx_webrender_blob_tile_size()));
} }
if (gfx::CanvasRenderThread::Get()) {
gfx::CanvasRenderThread::ShutDown();
}
#if defined(XP_WIN) #if defined(XP_WIN)
widget::WinWindowOcclusionTracker::ShutDown(); widget::WinWindowOcclusionTracker::ShutDown();
#endif #endif
@ -3851,12 +3850,10 @@ void gfxPlatform::DisableGPUProcess() {
} }
RemoteTextureMap::Init(); RemoteTextureMap::Init();
if (gfxVars::UseCanvasRenderThread()) {
gfx::CanvasRenderThread::Start();
}
// We need to initialize the parent process to prepare for WebRender if we // We need to initialize the parent process to prepare for WebRender if we
// did not end up disabling it, despite losing the GPU process. // did not end up disabling it, despite losing the GPU process.
wr::RenderThread::Start(GPUProcessManager::Get()->AllocateNamespace()); wr::RenderThread::Start(GPUProcessManager::Get()->AllocateNamespace());
gfx::CanvasRenderThread::Start();
image::ImageMemoryReporter::InitForWebRender(); image::ImageMemoryReporter::InitForWebRender();
} }