зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1852145
- Part 2. Spawn worker threads in CanvasRenderThread. r=gfx-reviewers,lsalzman
In preparation for moving PCanvas to be instantiated from PCanvasManager, and running its IPDL objects on the virtual thread chosen by CanvasRenderThread, this patch adds the necessary plumbing for utilizing worker threads for PCanvas rendering. A future patch in the series will make use of it. Differential Revision: https://phabricator.services.mozilla.com/D187720
This commit is contained in:
Родитель
f1d22fb2f1
Коммит
0a322737dd
|
@ -7,10 +7,15 @@
|
|||
#include "CanvasRenderThread.h"
|
||||
|
||||
#include "mozilla/BackgroundHangMonitor.h"
|
||||
#include "mozilla/SharedThreadPool.h"
|
||||
#include "mozilla/StaticPrefs_gfx.h"
|
||||
#include "mozilla/TaskQueue.h"
|
||||
#include "mozilla/gfx/CanvasManagerParent.h"
|
||||
#include "mozilla/gfx/gfxVars.h"
|
||||
#include "mozilla/layers/CompositorThread.h"
|
||||
#include "mozilla/webrender/RenderThread.h"
|
||||
#include "nsThread.h"
|
||||
#include "prsystem.h"
|
||||
#include "transport/runnable_utils.h"
|
||||
|
||||
namespace mozilla::gfx {
|
||||
|
@ -22,8 +27,11 @@ static bool sCanvasRenderThreadEverStarted = false;
|
|||
#endif
|
||||
|
||||
CanvasRenderThread::CanvasRenderThread(nsCOMPtr<nsIThread>&& aThread,
|
||||
nsCOMPtr<nsIThreadPool>&& aWorkers,
|
||||
bool aCreatedThread)
|
||||
: mThread(std::move(aThread)), mCreatedThread(aCreatedThread) {}
|
||||
: mThread(std::move(aThread)),
|
||||
mWorkers(std::move(aWorkers)),
|
||||
mCreatedThread(aCreatedThread) {}
|
||||
|
||||
CanvasRenderThread::~CanvasRenderThread() = default;
|
||||
|
||||
|
@ -39,6 +47,31 @@ void CanvasRenderThread::Start() {
|
|||
sCanvasRenderThreadEverStarted = true;
|
||||
#endif
|
||||
|
||||
int32_t threadPref =
|
||||
StaticPrefs::gfx_canvas_remote_worker_threads_AtStartup();
|
||||
uint32_t threadLimit;
|
||||
if (threadPref < 0) {
|
||||
// Given that the canvas workers are receiving instructions from
|
||||
// content processes, it probably doesn't make sense to have more than
|
||||
// half the number of processors doing canvas drawing. We set the
|
||||
// lower limit to 2, so that even on single processor systems, if
|
||||
// there is more than one window with canvas drawing, the OS can
|
||||
// manage the load between them.
|
||||
threadLimit = std::max(2, PR_GetNumberOfProcessors() / 2);
|
||||
} else {
|
||||
threadLimit = uint32_t(threadPref);
|
||||
}
|
||||
|
||||
// We don't spawn any workers if the user set the limit to 0. Instead we will
|
||||
// use the CanvasRenderThread virtual thread.
|
||||
nsCOMPtr<nsIThreadPool> workers;
|
||||
if (threadLimit > 0) {
|
||||
workers = SharedThreadPool::Get("CanvasWorkers"_ns, threadLimit);
|
||||
if (NS_WARN_IF(!workers)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIThread> thread;
|
||||
if (!gfxVars::SupportsThreadsafeGL()) {
|
||||
thread = wr::RenderThread::GetRenderThread();
|
||||
|
@ -49,8 +82,8 @@ void CanvasRenderThread::Start() {
|
|||
}
|
||||
|
||||
if (thread) {
|
||||
sCanvasRenderThread =
|
||||
new CanvasRenderThread(std::move(thread), /* aCreatedThread */ false);
|
||||
sCanvasRenderThread = new CanvasRenderThread(
|
||||
std::move(thread), std::move(workers), /* aCreatedThread */ false);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -95,8 +128,8 @@ void CanvasRenderThread::Start() {
|
|||
return;
|
||||
}
|
||||
|
||||
sCanvasRenderThread =
|
||||
new CanvasRenderThread(std::move(thread), /* aCreatedThread */ true);
|
||||
sCanvasRenderThread = new CanvasRenderThread(
|
||||
std::move(thread), std::move(workers), /* aCreatedThread */ true);
|
||||
}
|
||||
|
||||
// static
|
||||
|
@ -114,6 +147,7 @@ void CanvasRenderThread::Shutdown() {
|
|||
|
||||
// Null out sCanvasRenderThread before we enter synchronous Shutdown,
|
||||
// from here on we are to be considered shut down for our consumers.
|
||||
nsCOMPtr<nsIThreadPool> oldWorkers = sCanvasRenderThread->mWorkers;
|
||||
nsCOMPtr<nsIThread> oldThread;
|
||||
if (sCanvasRenderThread->mCreatedThread) {
|
||||
oldThread = sCanvasRenderThread->GetCanvasRenderThread();
|
||||
|
@ -121,6 +155,10 @@ void CanvasRenderThread::Shutdown() {
|
|||
}
|
||||
sCanvasRenderThread = nullptr;
|
||||
|
||||
if (oldWorkers) {
|
||||
oldWorkers->Shutdown();
|
||||
}
|
||||
|
||||
// We do a synchronous shutdown here while spinning the MT event loop, but
|
||||
// only if we created a dedicated CanvasRender thread.
|
||||
if (oldThread) {
|
||||
|
@ -134,6 +172,25 @@ bool CanvasRenderThread::IsInCanvasRenderThread() {
|
|||
sCanvasRenderThread->mThread == NS_GetCurrentThread();
|
||||
}
|
||||
|
||||
/* static */ bool CanvasRenderThread::IsInCanvasWorkerThread() {
|
||||
// It is possible there are no worker threads, and the worker is the same as
|
||||
// the CanvasRenderThread itself.
|
||||
return sCanvasRenderThread &&
|
||||
((sCanvasRenderThread->mWorkers &&
|
||||
sCanvasRenderThread->mWorkers->IsOnCurrentThread()) ||
|
||||
(!sCanvasRenderThread->mWorkers &&
|
||||
sCanvasRenderThread->mThread == NS_GetCurrentThread()));
|
||||
}
|
||||
|
||||
/* static */ bool CanvasRenderThread::IsInCanvasRenderOrWorkerThread() {
|
||||
// It is possible there are no worker threads, and the worker is the same as
|
||||
// the CanvasRenderThread itself.
|
||||
return sCanvasRenderThread &&
|
||||
(sCanvasRenderThread->mThread == NS_GetCurrentThread() ||
|
||||
(sCanvasRenderThread->mWorkers &&
|
||||
sCanvasRenderThread->mWorkers->IsOnCurrentThread()));
|
||||
}
|
||||
|
||||
// static
|
||||
already_AddRefed<nsIThread> CanvasRenderThread::GetCanvasRenderThread() {
|
||||
nsCOMPtr<nsIThread> thread;
|
||||
|
@ -143,9 +200,31 @@ already_AddRefed<nsIThread> CanvasRenderThread::GetCanvasRenderThread() {
|
|||
return thread.forget();
|
||||
}
|
||||
|
||||
void CanvasRenderThread::PostRunnable(already_AddRefed<nsIRunnable> aRunnable) {
|
||||
nsCOMPtr<nsIRunnable> runnable = aRunnable;
|
||||
mThread->Dispatch(runnable.forget());
|
||||
/* static */ already_AddRefed<TaskQueue> CanvasRenderThread::CreateTaskQueue(
|
||||
bool aPreferWorkers) {
|
||||
if (!sCanvasRenderThread) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!aPreferWorkers || !sCanvasRenderThread->mWorkers) {
|
||||
return TaskQueue::Create(do_AddRef(sCanvasRenderThread->mThread),
|
||||
"CanvasWorker")
|
||||
.forget();
|
||||
}
|
||||
|
||||
return TaskQueue::Create(do_AddRef(sCanvasRenderThread->mWorkers),
|
||||
"CanvasWorker")
|
||||
.forget();
|
||||
}
|
||||
|
||||
/* static */ void CanvasRenderThread::Dispatch(
|
||||
already_AddRefed<nsIRunnable> aRunnable) {
|
||||
if (!sCanvasRenderThread) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(false,
|
||||
"Dispatching after CanvasRenderThread shutdown!");
|
||||
return;
|
||||
}
|
||||
sCanvasRenderThread->mThread->Dispatch(std::move(aRunnable));
|
||||
}
|
||||
|
||||
} // namespace mozilla::gfx
|
||||
|
|
|
@ -7,15 +7,18 @@
|
|||
#ifndef _include_gfx_ipc_CanvasRenderThread_h__
|
||||
#define _include_gfx_ipc_CanvasRenderThread_h__
|
||||
|
||||
#include "mozilla/DataMutex.h"
|
||||
#include "mozilla/layers/SynchronousTask.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "mozilla/AlreadyAddRefed.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "nsThread.h"
|
||||
|
||||
class nsIRunnable;
|
||||
class nsIThread;
|
||||
class nsIThreadPool;
|
||||
|
||||
namespace mozilla::gfx {
|
||||
namespace mozilla {
|
||||
class TaskQueue;
|
||||
|
||||
namespace gfx {
|
||||
|
||||
/**
|
||||
* This class represents the virtual thread for canvas rendering. Depending on
|
||||
|
@ -39,22 +42,34 @@ class CanvasRenderThread final {
|
|||
/// Can be called from any thread.
|
||||
static bool IsInCanvasRenderThread();
|
||||
|
||||
/// Can be called from any thread.
|
||||
static bool IsInCanvasWorkerThread();
|
||||
|
||||
/// Can be called from any thread.
|
||||
static bool IsInCanvasRenderOrWorkerThread();
|
||||
|
||||
/// Can be called from any thread, may return nullptr late in shutdown.
|
||||
static already_AddRefed<nsIThread> GetCanvasRenderThread();
|
||||
|
||||
static already_AddRefed<TaskQueue> CreateTaskQueue(bool aPreferWorkers);
|
||||
|
||||
static void Dispatch(already_AddRefed<nsIRunnable> aRunnable);
|
||||
|
||||
private:
|
||||
CanvasRenderThread(nsCOMPtr<nsIThread>&& aThread, bool aCreatedThread);
|
||||
CanvasRenderThread(nsCOMPtr<nsIThread>&& aThread,
|
||||
nsCOMPtr<nsIThreadPool>&& aWorkers, bool aCreatedThread);
|
||||
~CanvasRenderThread();
|
||||
|
||||
void PostRunnable(already_AddRefed<nsIRunnable> aRunnable);
|
||||
|
||||
nsCOMPtr<nsIThread> const mThread;
|
||||
|
||||
nsCOMPtr<nsIThreadPool> const mWorkers;
|
||||
|
||||
// True if mThread points to CanvasRender thread, false if mThread points to
|
||||
// Compositor/Render thread.
|
||||
bool mCreatedThread;
|
||||
};
|
||||
|
||||
} // namespace mozilla::gfx
|
||||
} // namespace gfx
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // _include_gfx_ipc_CanvasRenderThread_h__
|
||||
|
|
|
@ -5666,6 +5666,19 @@
|
|||
value: false
|
||||
mirror: once
|
||||
|
||||
# How many worker threads spawned for remote canvas
|
||||
# -1 - Calculate based on processor cores
|
||||
# 0 - No worker threads spawned, will do work on CanvasRenderThread
|
||||
# >0 - Create worker thread pool with given size
|
||||
- name: gfx.canvas.remote.worker-threads
|
||||
type: int32_t
|
||||
#if defined(XP_WIN)
|
||||
value: -1
|
||||
#else
|
||||
value: 0
|
||||
#endif
|
||||
mirror: once
|
||||
|
||||
- name: gfx.canvas.willreadfrequently.enabled
|
||||
type: bool
|
||||
#if defined(XP_WIN)
|
||||
|
|
Загрузка…
Ссылка в новой задаче