summaryrefslogtreecommitdiffstats
path: root/gfx/ipc/CanvasManagerParent.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/ipc/CanvasManagerParent.cpp')
-rw-r--r--gfx/ipc/CanvasManagerParent.cpp236
1 files changed, 236 insertions, 0 deletions
diff --git a/gfx/ipc/CanvasManagerParent.cpp b/gfx/ipc/CanvasManagerParent.cpp
new file mode 100644
index 0000000000..50fdb6e104
--- /dev/null
+++ b/gfx/ipc/CanvasManagerParent.cpp
@@ -0,0 +1,236 @@
+/* -*- 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 "gfxPlatform.h"
+#include "mozilla/dom/WebGLParent.h"
+#include "mozilla/gfx/CanvasRenderThread.h"
+#include "mozilla/gfx/gfxVars.h"
+#include "mozilla/gfx/GPUParent.h"
+#include "mozilla/ipc/Endpoint.h"
+#include "mozilla/layers/CanvasTranslator.h"
+#include "mozilla/layers/CompositorThread.h"
+#include "mozilla/layers/ISurfaceAllocator.h"
+#include "mozilla/layers/SharedSurfacesParent.h"
+#include "mozilla/StaticPrefs_gfx.h"
+#include "mozilla/StaticPrefs_webgl.h"
+#include "mozilla/webgpu/WebGPUParent.h"
+#include "nsIThread.h"
+#include "nsThreadUtils.h"
+
+namespace mozilla::gfx {
+
+CanvasManagerParent::ManagerSet CanvasManagerParent::sManagers;
+
+/* static */ void CanvasManagerParent::Init(
+ Endpoint<PCanvasManagerParent>&& aEndpoint,
+ layers::SharedSurfacesHolder* aSharedSurfacesHolder,
+ const dom::ContentParentId& aContentId) {
+ MOZ_ASSERT(layers::CompositorThreadHolder::IsInCompositorThread());
+
+ auto manager =
+ MakeRefPtr<CanvasManagerParent>(aSharedSurfacesHolder, aContentId);
+
+ nsCOMPtr<nsIThread> owningThread =
+ gfx::CanvasRenderThread::GetCanvasRenderThread();
+ MOZ_ASSERT(owningThread);
+
+ owningThread->Dispatch(NewRunnableMethod<Endpoint<PCanvasManagerParent>&&>(
+ "CanvasManagerParent::Bind", manager, &CanvasManagerParent::Bind,
+ std::move(aEndpoint)));
+}
+
+/* static */ void CanvasManagerParent::Shutdown() {
+ MOZ_ASSERT(NS_IsMainThread());
+
+ nsCOMPtr<nsIThread> owningThread =
+ gfx::CanvasRenderThread::GetCanvasRenderThread();
+ MOZ_ASSERT(owningThread);
+
+ NS_DispatchAndSpinEventLoopUntilComplete(
+ "CanvasManagerParent::Shutdown"_ns, owningThread,
+ NS_NewRunnableFunction("CanvasManagerParent::Shutdown", []() -> void {
+ CanvasManagerParent::ShutdownInternal();
+ }));
+}
+
+/* static */ void CanvasManagerParent::ShutdownInternal() {
+ nsTArray<RefPtr<CanvasManagerParent>> 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();
+ }
+}
+
+/* static */ void CanvasManagerParent::DisableRemoteCanvas() {
+ NS_DispatchToMainThread(
+ NS_NewRunnableFunction("CanvasManagerParent::DisableRemoteCanvas", [] {
+ if (XRE_IsGPUProcess()) {
+ GPUParent::GetSingleton()->NotifyDisableRemoteCanvas();
+ } else {
+ gfxPlatform::DisableRemoteCanvas();
+ }
+ }));
+
+ if (CanvasRenderThread::IsInCanvasRenderThread()) {
+ DisableRemoteCanvasInternal();
+ return;
+ }
+
+ CanvasRenderThread::Dispatch(NS_NewRunnableFunction(
+ "CanvasManagerParent::DisableRemoteCanvas",
+ [] { CanvasManagerParent::DisableRemoteCanvasInternal(); }));
+}
+
+/* static */ void CanvasManagerParent::DisableRemoteCanvasInternal() {
+ MOZ_ASSERT(CanvasRenderThread::IsInCanvasRenderThread());
+
+ AutoTArray<RefPtr<layers::CanvasTranslator>, 16> actors;
+ for (const auto& manager : sManagers) {
+ for (const auto& canvas : manager->ManagedPCanvasParent()) {
+ actors.AppendElement(static_cast<layers::CanvasTranslator*>(canvas));
+ }
+ }
+
+ for (const auto& actor : actors) {
+ Unused << NS_WARN_IF(!actor->SendDeactivate());
+ }
+}
+
+CanvasManagerParent::CanvasManagerParent(
+ layers::SharedSurfacesHolder* aSharedSurfacesHolder,
+ const dom::ContentParentId& aContentId)
+ : mSharedSurfacesHolder(aSharedSurfacesHolder), mContentId(aContentId) {}
+
+CanvasManagerParent::~CanvasManagerParent() = default;
+
+void CanvasManagerParent::Bind(Endpoint<PCanvasManagerParent>&& aEndpoint) {
+ if (!aEndpoint.Bind(this)) {
+ NS_WARNING("Failed to bind CanvasManagerParent!");
+ return;
+ }
+
+#ifdef DEBUG
+ for (CanvasManagerParent* i : sManagers) {
+ MOZ_ASSERT_IF(i->mContentId == mContentId,
+ i->OtherPidMaybeInvalid() == OtherPidMaybeInvalid());
+ }
+#endif
+
+ sManagers.Insert(this);
+}
+
+void CanvasManagerParent::ActorDestroy(ActorDestroyReason aWhy) {
+ sManagers.Remove(this);
+}
+
+already_AddRefed<dom::PWebGLParent> CanvasManagerParent::AllocPWebGLParent() {
+ if (NS_WARN_IF(!gfxVars::AllowWebglOop() &&
+ !StaticPrefs::webgl_out_of_process_force())) {
+ MOZ_ASSERT_UNREACHABLE("AllocPWebGLParent without remote WebGL");
+ return nullptr;
+ }
+ return MakeAndAddRef<dom::WebGLParent>(mContentId);
+}
+
+already_AddRefed<webgpu::PWebGPUParent>
+CanvasManagerParent::AllocPWebGPUParent() {
+ if (NS_WARN_IF(!gfxVars::AllowWebGPU())) {
+ MOZ_ASSERT_UNREACHABLE("AllocPWebGPUParent without WebGPU");
+ return nullptr;
+ }
+
+ return MakeAndAddRef<webgpu::WebGPUParent>();
+}
+
+mozilla::ipc::IPCResult CanvasManagerParent::RecvInitialize(
+ const uint32_t& aId) {
+ if (!aId) {
+ return IPC_FAIL(this, "invalid id");
+ }
+ if (mId) {
+ return IPC_FAIL(this, "already initialized");
+ }
+ mId = aId;
+ return IPC_OK();
+}
+
+already_AddRefed<layers::PCanvasParent>
+CanvasManagerParent::AllocPCanvasParent() {
+ if (NS_WARN_IF(!gfx::gfxVars::RemoteCanvasEnabled() &&
+ !gfx::gfxVars::UseAcceleratedCanvas2D())) {
+ MOZ_ASSERT_UNREACHABLE("AllocPCanvasParent without remote canvas");
+ return nullptr;
+ }
+ if (NS_WARN_IF(!mId)) {
+ MOZ_ASSERT_UNREACHABLE("AllocPCanvasParent without ID");
+ return nullptr;
+ }
+ return MakeAndAddRef<layers::CanvasTranslator>(mSharedSurfacesHolder,
+ mContentId, mId);
+}
+
+mozilla::ipc::IPCResult CanvasManagerParent::RecvGetSnapshot(
+ const uint32_t& aManagerId, const int32_t& aProtocolId,
+ const Maybe<RemoteTextureOwnerId>& aOwnerId,
+ webgl::FrontBufferSnapshotIpc* aResult) {
+ if (!aManagerId) {
+ return IPC_FAIL(this, "invalid id");
+ }
+
+ IProtocol* actor = nullptr;
+ for (CanvasManagerParent* i : sManagers) {
+ if (i->mContentId == mContentId && i->mId == aManagerId) {
+ actor = i->Lookup(aProtocolId);
+ break;
+ }
+ }
+
+ if (!actor) {
+ return IPC_FAIL(this, "invalid actor");
+ }
+
+ if (actor->GetSide() != mozilla::ipc::Side::ParentSide) {
+ return IPC_FAIL(this, "unsupported actor");
+ }
+
+ webgl::FrontBufferSnapshotIpc buffer;
+ switch (actor->GetProtocolId()) {
+ case ProtocolId::PWebGLMsgStart: {
+ RefPtr<dom::WebGLParent> webgl = static_cast<dom::WebGLParent*>(actor);
+ mozilla::ipc::IPCResult rv = webgl->GetFrontBufferSnapshot(&buffer, this);
+ if (!rv) {
+ return rv;
+ }
+ } break;
+ case ProtocolId::PWebGPUMsgStart: {
+ RefPtr<webgpu::WebGPUParent> webgpu =
+ static_cast<webgpu::WebGPUParent*>(actor);
+ IntSize size;
+ if (aOwnerId.isNothing()) {
+ return IPC_FAIL(this, "invalid OwnerId");
+ }
+ mozilla::ipc::IPCResult rv =
+ webgpu->GetFrontBufferSnapshot(this, *aOwnerId, buffer.shmem, size);
+ if (!rv) {
+ return rv;
+ }
+ buffer.surfSize.x = static_cast<uint32_t>(size.width);
+ buffer.surfSize.y = static_cast<uint32_t>(size.height);
+ } break;
+ default:
+ return IPC_FAIL(this, "unsupported protocol");
+ }
+
+ *aResult = std::move(buffer);
+ return IPC_OK();
+}
+
+} // namespace mozilla::gfx