summaryrefslogtreecommitdiffstats
path: root/gfx/layers/ipc/CanvasThread.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/layers/ipc/CanvasThread.cpp')
-rw-r--r--gfx/layers/ipc/CanvasThread.cpp138
1 files changed, 138 insertions, 0 deletions
diff --git a/gfx/layers/ipc/CanvasThread.cpp b/gfx/layers/ipc/CanvasThread.cpp
new file mode 100644
index 0000000000..3d0a387c04
--- /dev/null
+++ b/gfx/layers/ipc/CanvasThread.cpp
@@ -0,0 +1,138 @@
+/* -*- 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 "CanvasThread.h"
+
+#include "mozilla/SharedThreadPool.h"
+#include "nsThreadUtils.h"
+#include "prsystem.h"
+
+bool NS_IsInCanvasThreadOrWorker() {
+ return mozilla::layers::CanvasThreadHolder::IsInCanvasThreadOrWorker();
+}
+
+namespace mozilla {
+namespace layers {
+
+StaticDataMutex<StaticRefPtr<CanvasThreadHolder>>
+ CanvasThreadHolder::sCanvasThreadHolder("sCanvasThreadHolder");
+
+CanvasThreadHolder::CanvasThreadHolder(
+ already_AddRefed<nsISerialEventTarget> aCanvasThread,
+ already_AddRefed<nsIThreadPool> aCanvasWorkers)
+ : mCanvasThread(aCanvasThread),
+ mCanvasWorkers(aCanvasWorkers),
+ mCompositorThreadKeepAlive(CompositorThreadHolder::GetSingleton()) {
+ MOZ_ASSERT(NS_IsInCompositorThread());
+ MOZ_ASSERT(mCanvasThread);
+ MOZ_ASSERT(mCanvasWorkers);
+}
+
+CanvasThreadHolder::~CanvasThreadHolder() {
+ // Note we can't just use NS_IsInCompositorThread() here because
+ // sCompositorThreadHolder might have already gone.
+ MOZ_ASSERT(
+ mCompositorThreadKeepAlive->GetCompositorThread()->IsOnCurrentThread());
+}
+
+/* static */
+already_AddRefed<CanvasThreadHolder> CanvasThreadHolder::EnsureCanvasThread() {
+ MOZ_ASSERT(NS_IsInCompositorThread());
+
+ auto lockedCanvasThreadHolder = sCanvasThreadHolder.Lock();
+ if (!lockedCanvasThreadHolder.ref()) {
+ nsCOMPtr<nsISerialEventTarget> canvasThread;
+ nsresult rv =
+ NS_CreateBackgroundTaskQueue("Canvas", getter_AddRefs(canvasThread));
+ NS_ENSURE_SUCCESS(rv, nullptr);
+
+ // 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.
+ uint32_t threadLimit = std::max(2, PR_GetNumberOfProcessors() / 2);
+ nsCOMPtr<nsIThreadPool> canvasWorkers =
+ SharedThreadPool::Get("CanvasWorkers"_ns, threadLimit);
+ if (!canvasWorkers) {
+ return nullptr;
+ }
+
+ lockedCanvasThreadHolder.ref() =
+ new CanvasThreadHolder(canvasThread.forget(), canvasWorkers.forget());
+ }
+
+ return do_AddRef(lockedCanvasThreadHolder.ref());
+}
+
+/* static */
+void CanvasThreadHolder::ReleaseOnCompositorThread(
+ already_AddRefed<CanvasThreadHolder> aCanvasThreadHolder) {
+ RefPtr<CanvasThreadHolder> canvasThreadHolder = aCanvasThreadHolder;
+ auto lockedCanvasThreadHolder = sCanvasThreadHolder.Lock();
+ lockedCanvasThreadHolder.ref()
+ ->mCompositorThreadKeepAlive->GetCompositorThread()
+ ->Dispatch(NS_NewRunnableFunction(
+ "CanvasThreadHolder::StaticRelease",
+ [canvasThreadHolder = std::move(canvasThreadHolder)]() mutable {
+ RefPtr<CanvasThreadHolder> threadHolder =
+ canvasThreadHolder.forget();
+ threadHolder = nullptr;
+
+ auto lockedCanvasThreadHolder = sCanvasThreadHolder.Lock();
+ if (lockedCanvasThreadHolder.ref()->mRefCnt == 1) {
+ lockedCanvasThreadHolder.ref() = nullptr;
+ }
+ }));
+}
+
+/* static */
+bool CanvasThreadHolder::IsInCanvasThread() {
+ auto lockedCanvasThreadHolder = sCanvasThreadHolder.Lock();
+ return lockedCanvasThreadHolder.ref() &&
+ lockedCanvasThreadHolder.ref()->mCanvasThread->IsOnCurrentThread();
+}
+
+/* static */
+bool CanvasThreadHolder::IsInCanvasWorker() {
+ auto lockedCanvasThreadHolder = sCanvasThreadHolder.Lock();
+ return lockedCanvasThreadHolder.ref() &&
+ lockedCanvasThreadHolder.ref()->mCanvasWorkers->IsOnCurrentThread();
+}
+
+/* static */
+bool CanvasThreadHolder::IsInCanvasThreadOrWorker() {
+ auto lockedCanvasThreadHolder = sCanvasThreadHolder.Lock();
+ return lockedCanvasThreadHolder.ref() &&
+ (lockedCanvasThreadHolder.ref()->mCanvasWorkers->IsOnCurrentThread() ||
+ lockedCanvasThreadHolder.ref()->mCanvasThread->IsOnCurrentThread());
+}
+
+/* static */
+void CanvasThreadHolder::MaybeDispatchToCanvasThread(
+ already_AddRefed<nsIRunnable> aRunnable) {
+ auto lockedCanvasThreadHolder = sCanvasThreadHolder.Lock();
+ if (!lockedCanvasThreadHolder.ref()) {
+ // There is no canvas thread just release the runnable.
+ nsCOMPtr<nsIRunnable> runnable = aRunnable;
+ return;
+ }
+
+ lockedCanvasThreadHolder.ref()->mCanvasThread->Dispatch(std::move(aRunnable));
+}
+
+void CanvasThreadHolder::DispatchToCanvasThread(
+ already_AddRefed<nsIRunnable> aRunnable) {
+ mCanvasThread->Dispatch(std::move(aRunnable));
+}
+
+already_AddRefed<TaskQueue> CanvasThreadHolder::CreateWorkerTaskQueue() {
+ return TaskQueue::Create(do_AddRef(mCanvasWorkers), "CanvasWorker").forget();
+}
+
+} // namespace layers
+} // namespace mozilla