Bug 1856663 - Add more chunks for Android mochitest-plain. r=jmaher,taskgraph-reviewe...
[gecko.git] / gfx / ipc / CanvasManagerChild.cpp
blobd65503814b811cf1505ca27b3c09c098f7064c3d
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "CanvasManagerChild.h"
8 #include "mozilla/dom/WorkerPrivate.h"
9 #include "mozilla/dom/WorkerRef.h"
10 #include "mozilla/gfx/2D.h"
11 #include "mozilla/gfx/Swizzle.h"
12 #include "mozilla/ipc/Endpoint.h"
13 #include "mozilla/layers/CanvasChild.h"
14 #include "mozilla/layers/CompositorManagerChild.h"
15 #include "mozilla/webgpu/WebGPUChild.h"
17 using namespace mozilla::dom;
18 using namespace mozilla::layers;
20 namespace mozilla::gfx {
22 // The IPDL actor holds a strong reference to CanvasManagerChild which we use
23 // to keep it alive. The owning thread will tell us to close when it is
24 // shutdown, either via CanvasManagerChild::Shutdown for the main thread, or
25 // via a shutdown callback from IPCWorkerRef for worker threads.
26 MOZ_THREAD_LOCAL(CanvasManagerChild*) CanvasManagerChild::sLocalManager;
28 Atomic<uint32_t> CanvasManagerChild::sNextId(1);
30 CanvasManagerChild::CanvasManagerChild(uint32_t aId) : mId(aId) {}
31 CanvasManagerChild::~CanvasManagerChild() = default;
33 void CanvasManagerChild::ActorDestroy(ActorDestroyReason aReason) {
34 if (sLocalManager.get() == this) {
35 sLocalManager.set(nullptr);
39 void CanvasManagerChild::Destroy() {
40 if (mCanvasChild) {
41 mCanvasChild->Destroy();
42 mCanvasChild = nullptr;
45 // The caller has a strong reference. ActorDestroy will clear sLocalManager.
46 Close();
47 mWorkerRef = nullptr;
50 /* static */ void CanvasManagerChild::Shutdown() {
51 MOZ_ASSERT(NS_IsMainThread());
53 // The worker threads should destroy their own CanvasManagerChild instances
54 // during their shutdown sequence. We just need to take care of the main
55 // thread. We need to init here because we may have never created a
56 // CanvasManagerChild for the main thread in the first place.
57 if (sLocalManager.init()) {
58 RefPtr<CanvasManagerChild> manager = sLocalManager.get();
59 if (manager) {
60 manager->Destroy();
65 /* static */ bool CanvasManagerChild::CreateParent(
66 ipc::Endpoint<PCanvasManagerParent>&& aEndpoint) {
67 MOZ_ASSERT(NS_IsMainThread());
69 CompositorManagerChild* manager = CompositorManagerChild::GetInstance();
70 if (!manager || !manager->CanSend()) {
71 return false;
74 return manager->SendInitCanvasManager(std::move(aEndpoint));
77 /* static */ CanvasManagerChild* CanvasManagerChild::Get() {
78 if (NS_WARN_IF(!sLocalManager.init())) {
79 return nullptr;
82 CanvasManagerChild* managerWeak = sLocalManager.get();
83 if (managerWeak) {
84 return managerWeak;
87 // We are only used on the main thread, or on worker threads.
88 WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
89 MOZ_ASSERT_IF(!worker, NS_IsMainThread());
91 ipc::Endpoint<PCanvasManagerParent> parentEndpoint;
92 ipc::Endpoint<PCanvasManagerChild> childEndpoint;
94 auto compositorPid = CompositorManagerChild::GetOtherPid();
95 if (NS_WARN_IF(!compositorPid)) {
96 return nullptr;
99 nsresult rv = PCanvasManager::CreateEndpoints(
100 compositorPid, base::GetCurrentProcId(), &parentEndpoint, &childEndpoint);
101 if (NS_WARN_IF(NS_FAILED(rv))) {
102 return nullptr;
105 auto manager = MakeRefPtr<CanvasManagerChild>(sNextId++);
107 if (worker) {
108 // The IPCWorkerRef will let us know when the worker is shutting down. This
109 // will let us clear our threadlocal reference and close the actor. We rely
110 // upon an explicit shutdown for the main thread.
111 manager->mWorkerRef = IPCWorkerRef::Create(
112 worker, "CanvasManager", [manager]() { manager->Destroy(); });
113 if (NS_WARN_IF(!manager->mWorkerRef)) {
114 return nullptr;
118 if (NS_WARN_IF(!childEndpoint.Bind(manager))) {
119 return nullptr;
122 // We can't talk to the compositor process directly from worker threads, but
123 // the main thread can via CompositorManagerChild.
124 if (worker) {
125 worker->DispatchToMainThread(NS_NewRunnableFunction(
126 "CanvasManagerChild::CreateParent",
127 [parentEndpoint = std::move(parentEndpoint)]() {
128 CreateParent(
129 std::move(const_cast<ipc::Endpoint<PCanvasManagerParent>&&>(
130 parentEndpoint)));
131 }));
132 } else if (NS_WARN_IF(!CreateParent(std::move(parentEndpoint)))) {
133 return nullptr;
136 manager->SendInitialize(manager->Id());
137 sLocalManager.set(manager);
138 return manager;
141 void CanvasManagerChild::EndCanvasTransaction() {
142 if (!mCanvasChild) {
143 return;
146 mCanvasChild->EndTransaction();
147 if (mCanvasChild->ShouldBeCleanedUp()) {
148 mCanvasChild->Destroy();
149 mCanvasChild = nullptr;
153 void CanvasManagerChild::DeactivateCanvas() {
154 mActive = false;
155 if (mCanvasChild) {
156 mCanvasChild->Destroy();
157 mCanvasChild = nullptr;
161 RefPtr<layers::CanvasChild> CanvasManagerChild::GetCanvasChild() {
162 if (!mActive) {
163 MOZ_ASSERT(!mCanvasChild);
164 return nullptr;
167 if (!mCanvasChild) {
168 mCanvasChild = MakeAndAddRef<layers::CanvasChild>();
169 if (!SendPCanvasConstructor(mCanvasChild)) {
170 mCanvasChild = nullptr;
174 return mCanvasChild;
177 RefPtr<webgpu::WebGPUChild> CanvasManagerChild::GetWebGPUChild() {
178 if (!mWebGPUChild) {
179 mWebGPUChild = MakeAndAddRef<webgpu::WebGPUChild>();
180 if (!SendPWebGPUConstructor(mWebGPUChild)) {
181 mWebGPUChild = nullptr;
185 return mWebGPUChild;
188 already_AddRefed<DataSourceSurface> CanvasManagerChild::GetSnapshot(
189 uint32_t aManagerId, int32_t aProtocolId,
190 const Maybe<RemoteTextureOwnerId>& aOwnerId, SurfaceFormat aFormat,
191 bool aPremultiply, bool aYFlip) {
192 if (!CanSend()) {
193 return nullptr;
196 webgl::FrontBufferSnapshotIpc res;
197 if (!SendGetSnapshot(aManagerId, aProtocolId, aOwnerId, &res)) {
198 return nullptr;
201 if (!res.shmem || !res.shmem->IsReadable()) {
202 return nullptr;
205 auto guard = MakeScopeExit([&] { DeallocShmem(res.shmem.ref()); });
207 if (!res.surfSize.x || !res.surfSize.y || res.surfSize.x > INT32_MAX ||
208 res.surfSize.y > INT32_MAX) {
209 return nullptr;
212 IntSize size(res.surfSize.x, res.surfSize.y);
213 CheckedInt32 stride = CheckedInt32(size.width) * sizeof(uint32_t);
214 if (!stride.isValid()) {
215 return nullptr;
218 CheckedInt32 length = stride * size.height;
219 if (!length.isValid() ||
220 size_t(length.value()) != res.shmem->Size<uint8_t>()) {
221 return nullptr;
224 SurfaceFormat format =
225 IsOpaque(aFormat) ? SurfaceFormat::B8G8R8X8 : SurfaceFormat::B8G8R8A8;
226 RefPtr<DataSourceSurface> surface =
227 Factory::CreateDataSourceSurfaceWithStride(size, format, stride.value(),
228 /* aZero */ false);
229 if (!surface) {
230 return nullptr;
233 gfx::DataSourceSurface::ScopedMap map(surface,
234 gfx::DataSourceSurface::READ_WRITE);
235 if (!map.IsMapped()) {
236 return nullptr;
239 // The buffer we may readback from the canvas could be R8G8B8A8, not
240 // premultiplied, and/or has its rows iverted. For the general case, we want
241 // surfaces represented as premultiplied B8G8R8A8, with its rows ordered top
242 // to bottom. Given this path is used for screenshots/SurfaceFromElement,
243 // that's the representation we need.
244 if (aYFlip) {
245 if (aPremultiply) {
246 if (!PremultiplyYFlipData(res.shmem->get<uint8_t>(), stride.value(),
247 aFormat, map.GetData(), map.GetStride(), format,
248 size)) {
249 return nullptr;
251 } else {
252 if (!SwizzleYFlipData(res.shmem->get<uint8_t>(), stride.value(), aFormat,
253 map.GetData(), map.GetStride(), format, size)) {
254 return nullptr;
257 } else if (aPremultiply) {
258 if (!PremultiplyData(res.shmem->get<uint8_t>(), stride.value(), aFormat,
259 map.GetData(), map.GetStride(), format, size)) {
260 return nullptr;
262 } else {
263 if (!SwizzleData(res.shmem->get<uint8_t>(), stride.value(), aFormat,
264 map.GetData(), map.GetStride(), format, size)) {
265 return nullptr;
268 return surface.forget();
271 } // namespace mozilla::gfx