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/. */
6
7 #include "ImageBridgeChild.h"
8
9 #include <vector> // for vector
10
11 #include "ImageBridgeParent.h" // for ImageBridgeParent
12 #include "ImageContainer.h" // for ImageContainer
13 #include "Layers.h" // for Layer, etc
14 #include "SynchronousTask.h"
15 #include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
16 #include "mozilla/Monitor.h" // for Monitor, MonitorAutoLock
17 #include "mozilla/ReentrantMonitor.h" // for ReentrantMonitor, etc
18 #include "mozilla/StaticMutex.h"
19 #include "mozilla/StaticPtr.h" // for StaticRefPtr
20 #include "mozilla/dom/ContentChild.h"
21 #include "mozilla/gfx/Point.h" // for IntSize
22 #include "mozilla/gfx/gfxVars.h"
23 #include "mozilla/ipc/Endpoint.h"
24 #include "mozilla/ipc/MessageChannel.h" // for MessageChannel, etc
25 #include "mozilla/layers/CompositableClient.h" // for CompositableChild, etc
26 #include "mozilla/layers/CompositorThread.h"
27 #include "mozilla/layers/ISurfaceAllocator.h" // for ISurfaceAllocator
28 #include "mozilla/layers/ImageClient.h" // for ImageClient
29 #include "mozilla/layers/LayersMessages.h" // for CompositableOperation
30 #include "mozilla/layers/TextureClient.h" // for TextureClient
31 #include "mozilla/layers/TextureClient.h"
32 #include "mozilla/media/MediaSystemResourceManager.h" // for MediaSystemResourceManager
33 #include "mozilla/media/MediaSystemResourceManagerChild.h" // for MediaSystemResourceManagerChild
34 #include "mozilla/mozalloc.h" // for operator new, etc
35 #include "transport/runnable_utils.h"
36 #include "nsContentUtils.h"
37 #include "nsISupportsImpl.h" // for ImageContainer::AddRef, etc
38 #include "nsTArray.h" // for AutoTArray, nsTArray, etc
39 #include "nsTArrayForwardDeclare.h" // for AutoTArray
40 #include "nsThreadUtils.h" // for NS_IsMainThread
41
42 #if defined(XP_WIN)
43 # include "mozilla/gfx/DeviceManagerDx.h"
44 #endif
45
46 #ifdef MOZ_WIDGET_ANDROID
47 # include "mozilla/layers/AndroidHardwareBuffer.h"
48 #endif
49
50 namespace mozilla {
51 namespace ipc {
52 class Shmem;
53 } // namespace ipc
54
55 namespace layers {
56
57 using namespace mozilla::ipc;
58 using namespace mozilla::gfx;
59 using namespace mozilla::media;
60
61 typedef std::vector<CompositableOperation> OpVector;
62 typedef nsTArray<OpDestroy> OpDestroyVector;
63
64 struct CompositableTransaction {
CompositableTransactionmozilla::layers::CompositableTransaction65 CompositableTransaction() : mFinished(true) {}
~CompositableTransactionmozilla::layers::CompositableTransaction66 ~CompositableTransaction() { End(); }
Finishedmozilla::layers::CompositableTransaction67 bool Finished() const { return mFinished; }
Beginmozilla::layers::CompositableTransaction68 void Begin() {
69 MOZ_ASSERT(mFinished);
70 mFinished = false;
71 }
Endmozilla::layers::CompositableTransaction72 void End() {
73 mFinished = true;
74 mOperations.clear();
75 mDestroyedActors.Clear();
76 }
IsEmptymozilla::layers::CompositableTransaction77 bool IsEmpty() const {
78 return mOperations.empty() && mDestroyedActors.IsEmpty();
79 }
AddNoSwapEditmozilla::layers::CompositableTransaction80 void AddNoSwapEdit(const CompositableOperation& op) {
81 MOZ_ASSERT(!Finished(), "forgot BeginTransaction?");
82 mOperations.push_back(op);
83 }
84
85 OpVector mOperations;
86 OpDestroyVector mDestroyedActors;
87
88 bool mFinished;
89 };
90
91 struct AutoEndTransaction final {
AutoEndTransactionmozilla::layers::AutoEndTransaction92 explicit AutoEndTransaction(CompositableTransaction* aTxn) : mTxn(aTxn) {}
~AutoEndTransactionmozilla::layers::AutoEndTransaction93 ~AutoEndTransaction() { mTxn->End(); }
94 CompositableTransaction* mTxn;
95 };
96
UseTextures(CompositableClient * aCompositable,const nsTArray<TimedTextureClient> & aTextures)97 void ImageBridgeChild::UseTextures(
98 CompositableClient* aCompositable,
99 const nsTArray<TimedTextureClient>& aTextures) {
100 MOZ_ASSERT(aCompositable);
101 MOZ_ASSERT(aCompositable->GetIPCHandle());
102 MOZ_ASSERT(aCompositable->IsConnected());
103
104 AutoTArray<TimedTexture, 4> textures;
105
106 for (auto& t : aTextures) {
107 MOZ_ASSERT(t.mTextureClient);
108 MOZ_ASSERT(t.mTextureClient->GetIPDLActor());
109
110 if (!t.mTextureClient->IsSharedWithCompositor()) {
111 return;
112 }
113
114 bool readLocked = t.mTextureClient->OnForwardedToHost();
115
116 auto fenceFd = t.mTextureClient->GetInternalData()->GetAcquireFence();
117 if (fenceFd.IsValid()) {
118 mTxn->AddNoSwapEdit(CompositableOperation(
119 aCompositable->GetIPCHandle(),
120 OpDeliverAcquireFence(nullptr, t.mTextureClient->GetIPDLActor(),
121 fenceFd)));
122 }
123
124 textures.AppendElement(
125 TimedTexture(nullptr, t.mTextureClient->GetIPDLActor(), t.mTimeStamp,
126 t.mPictureRect, t.mFrameID, t.mProducerID, readLocked));
127
128 // Wait end of usage on host side if TextureFlags::RECYCLE is set
129 HoldUntilCompositableRefReleasedIfNecessary(t.mTextureClient);
130 }
131 mTxn->AddNoSwapEdit(CompositableOperation(aCompositable->GetIPCHandle(),
132 OpUseTexture(textures)));
133 }
134
HoldUntilCompositableRefReleasedIfNecessary(TextureClient * aClient)135 void ImageBridgeChild::HoldUntilCompositableRefReleasedIfNecessary(
136 TextureClient* aClient) {
137 if (!aClient) {
138 return;
139 }
140
141 #ifdef MOZ_WIDGET_ANDROID
142 auto bufferId = aClient->GetInternalData()->GetBufferId();
143 if (bufferId.isSome()) {
144 MOZ_ASSERT(aClient->GetFlags() & TextureFlags::WAIT_HOST_USAGE_END);
145 AndroidHardwareBufferManager::Get()->HoldUntilNotifyNotUsed(
146 bufferId.ref(), GetFwdTransactionId(), /* aUsesImageBridge */ true);
147 }
148 #endif
149
150 // Wait ReleaseCompositableRef only when TextureFlags::RECYCLE or
151 // TextureFlags::WAIT_HOST_USAGE_END is set on ImageBridge.
152 bool waitNotifyNotUsed =
153 aClient->GetFlags() & TextureFlags::RECYCLE ||
154 aClient->GetFlags() & TextureFlags::WAIT_HOST_USAGE_END;
155 if (!waitNotifyNotUsed) {
156 return;
157 }
158
159 aClient->SetLastFwdTransactionId(GetFwdTransactionId());
160 mTexturesWaitingNotifyNotUsed.emplace(aClient->GetSerial(), aClient);
161 }
162
NotifyNotUsed(uint64_t aTextureId,uint64_t aFwdTransactionId)163 void ImageBridgeChild::NotifyNotUsed(uint64_t aTextureId,
164 uint64_t aFwdTransactionId) {
165 auto it = mTexturesWaitingNotifyNotUsed.find(aTextureId);
166 if (it != mTexturesWaitingNotifyNotUsed.end()) {
167 if (aFwdTransactionId < it->second->GetLastFwdTransactionId()) {
168 // Released on host side, but client already requested newer use texture.
169 return;
170 }
171 mTexturesWaitingNotifyNotUsed.erase(it);
172 }
173 }
174
CancelWaitForNotifyNotUsed(uint64_t aTextureId)175 void ImageBridgeChild::CancelWaitForNotifyNotUsed(uint64_t aTextureId) {
176 MOZ_ASSERT(InImageBridgeChildThread());
177 mTexturesWaitingNotifyNotUsed.erase(aTextureId);
178 }
179
180 // Singleton
181 static StaticMutex sImageBridgeSingletonLock;
182 static StaticRefPtr<ImageBridgeChild> sImageBridgeChildSingleton;
183 static StaticRefPtr<nsIThread> sImageBridgeChildThread;
184
185 // dispatched function
ShutdownStep1(SynchronousTask * aTask)186 void ImageBridgeChild::ShutdownStep1(SynchronousTask* aTask) {
187 AutoCompleteTask complete(aTask);
188
189 MOZ_ASSERT(InImageBridgeChildThread(),
190 "Should be in ImageBridgeChild thread.");
191
192 MediaSystemResourceManager::Shutdown();
193
194 // Force all managed protocols to shut themselves down cleanly
195 nsTArray<PTextureChild*> textures;
196 ManagedPTextureChild(textures);
197 for (int i = textures.Length() - 1; i >= 0; --i) {
198 RefPtr<TextureClient> client = TextureClient::AsTextureClient(textures[i]);
199 if (client) {
200 client->Destroy();
201 }
202 }
203
204 if (mCanSend) {
205 SendWillClose();
206 }
207 MarkShutDown();
208
209 // From now on, no message can be sent through the image bridge from the
210 // client side except the final Stop message.
211 }
212
213 // dispatched function
ShutdownStep2(SynchronousTask * aTask)214 void ImageBridgeChild::ShutdownStep2(SynchronousTask* aTask) {
215 AutoCompleteTask complete(aTask);
216
217 MOZ_ASSERT(InImageBridgeChildThread(),
218 "Should be in ImageBridgeChild thread.");
219 if (!mDestroyed) {
220 Close();
221 }
222 }
223
ActorDestroy(ActorDestroyReason aWhy)224 void ImageBridgeChild::ActorDestroy(ActorDestroyReason aWhy) {
225 mCanSend = false;
226 mDestroyed = true;
227 {
228 MutexAutoLock lock(mContainerMapLock);
229 mImageContainerListeners.clear();
230 }
231 }
232
ActorDealloc()233 void ImageBridgeChild::ActorDealloc() { this->Release(); }
234
CreateImageClientSync(SynchronousTask * aTask,RefPtr<ImageClient> * result,CompositableType aType,ImageContainer * aImageContainer)235 void ImageBridgeChild::CreateImageClientSync(SynchronousTask* aTask,
236 RefPtr<ImageClient>* result,
237 CompositableType aType,
238 ImageContainer* aImageContainer) {
239 AutoCompleteTask complete(aTask);
240 *result = CreateImageClientNow(aType, aImageContainer);
241 }
242
ImageBridgeChild(uint32_t aNamespace)243 ImageBridgeChild::ImageBridgeChild(uint32_t aNamespace)
244 : mNamespace(aNamespace),
245 mCanSend(false),
246 mDestroyed(false),
247 mFwdTransactionId(0),
248 mContainerMapLock("ImageBridgeChild.mContainerMapLock") {
249 MOZ_ASSERT(mNamespace);
250 MOZ_ASSERT(NS_IsMainThread());
251
252 mTxn = new CompositableTransaction();
253 }
254
~ImageBridgeChild()255 ImageBridgeChild::~ImageBridgeChild() { delete mTxn; }
256
MarkShutDown()257 void ImageBridgeChild::MarkShutDown() {
258 mTexturesWaitingNotifyNotUsed.clear();
259
260 mCanSend = false;
261 }
262
Connect(CompositableClient * aCompositable,ImageContainer * aImageContainer)263 void ImageBridgeChild::Connect(CompositableClient* aCompositable,
264 ImageContainer* aImageContainer) {
265 MOZ_ASSERT(aCompositable);
266 MOZ_ASSERT(InImageBridgeChildThread());
267 MOZ_ASSERT(CanSend());
268
269 // Note: this is static, rather than per-IBC, so IDs are not re-used across
270 // ImageBridgeChild instances. This is relevant for the GPU process, where
271 // we don't want old IDs to potentially leak into a recreated ImageBridge.
272 static uint64_t sNextID = 1;
273 uint64_t id = sNextID++;
274
275 // ImageClient of ImageContainer provides aImageContainer.
276 // But offscreen canvas does not provide it.
277 if (aImageContainer) {
278 MutexAutoLock lock(mContainerMapLock);
279 MOZ_ASSERT(mImageContainerListeners.find(id) ==
280 mImageContainerListeners.end());
281 mImageContainerListeners.emplace(
282 id, aImageContainer->GetImageContainerListener());
283 }
284
285 CompositableHandle handle(id);
286 aCompositable->InitIPDL(handle);
287 SendNewCompositable(handle, aCompositable->GetTextureInfo());
288 }
289
ForgetImageContainer(const CompositableHandle & aHandle)290 void ImageBridgeChild::ForgetImageContainer(const CompositableHandle& aHandle) {
291 MutexAutoLock lock(mContainerMapLock);
292 mImageContainerListeners.erase(aHandle.Value());
293 }
294
295 /* static */
GetSingleton()296 RefPtr<ImageBridgeChild> ImageBridgeChild::GetSingleton() {
297 StaticMutexAutoLock lock(sImageBridgeSingletonLock);
298 return sImageBridgeChildSingleton;
299 }
300
UpdateImageClient(RefPtr<ImageContainer> aContainer)301 void ImageBridgeChild::UpdateImageClient(RefPtr<ImageContainer> aContainer) {
302 if (!aContainer) {
303 return;
304 }
305
306 if (!InImageBridgeChildThread()) {
307 RefPtr<Runnable> runnable =
308 WrapRunnable(RefPtr<ImageBridgeChild>(this),
309 &ImageBridgeChild::UpdateImageClient, aContainer);
310 GetThread()->Dispatch(runnable.forget());
311 return;
312 }
313
314 if (!CanSend()) {
315 return;
316 }
317
318 RefPtr<ImageClient> client = aContainer->GetImageClient();
319 if (NS_WARN_IF(!client)) {
320 return;
321 }
322
323 // If the client has become disconnected before this event was dispatched,
324 // early return now.
325 if (!client->IsConnected()) {
326 return;
327 }
328
329 BeginTransaction();
330 client->UpdateImage(aContainer, Layer::CONTENT_OPAQUE);
331 EndTransaction();
332 }
333
FlushAllImagesSync(SynchronousTask * aTask,ImageClient * aClient,ImageContainer * aContainer)334 void ImageBridgeChild::FlushAllImagesSync(SynchronousTask* aTask,
335 ImageClient* aClient,
336 ImageContainer* aContainer) {
337 AutoCompleteTask complete(aTask);
338
339 if (!CanSend()) {
340 return;
341 }
342
343 MOZ_ASSERT(aClient);
344 BeginTransaction();
345 if (aContainer) {
346 aContainer->ClearImagesFromImageBridge();
347 }
348 aClient->FlushAllImages();
349 EndTransaction();
350 }
351
FlushAllImages(ImageClient * aClient,ImageContainer * aContainer)352 void ImageBridgeChild::FlushAllImages(ImageClient* aClient,
353 ImageContainer* aContainer) {
354 MOZ_ASSERT(aClient);
355 MOZ_ASSERT(!InImageBridgeChildThread());
356
357 if (InImageBridgeChildThread()) {
358 NS_ERROR(
359 "ImageBridgeChild::FlushAllImages() is called on ImageBridge thread.");
360 return;
361 }
362
363 SynchronousTask task("FlushAllImages Lock");
364
365 // RefPtrs on arguments are not needed since this dispatches synchronously.
366 RefPtr<Runnable> runnable = WrapRunnable(
367 RefPtr<ImageBridgeChild>(this), &ImageBridgeChild::FlushAllImagesSync,
368 &task, aClient, aContainer);
369 GetThread()->Dispatch(runnable.forget());
370
371 task.Wait();
372 }
373
BeginTransaction()374 void ImageBridgeChild::BeginTransaction() {
375 MOZ_ASSERT(CanSend());
376 MOZ_ASSERT(mTxn->Finished(), "uncommitted txn?");
377 UpdateFwdTransactionId();
378 mTxn->Begin();
379 }
380
EndTransaction()381 void ImageBridgeChild::EndTransaction() {
382 MOZ_ASSERT(CanSend());
383 MOZ_ASSERT(!mTxn->Finished(), "forgot BeginTransaction?");
384
385 AutoEndTransaction _(mTxn);
386
387 if (mTxn->IsEmpty()) {
388 return;
389 }
390
391 AutoTArray<CompositableOperation, 10> cset;
392 cset.SetCapacity(mTxn->mOperations.size());
393 if (!mTxn->mOperations.empty()) {
394 cset.AppendElements(&mTxn->mOperations.front(), mTxn->mOperations.size());
395 }
396
397 if (!SendUpdate(cset, mTxn->mDestroyedActors, GetFwdTransactionId())) {
398 NS_WARNING("could not send async texture transaction");
399 return;
400 }
401 }
402
InitForContent(Endpoint<PImageBridgeChild> && aEndpoint,uint32_t aNamespace)403 bool ImageBridgeChild::InitForContent(Endpoint<PImageBridgeChild>&& aEndpoint,
404 uint32_t aNamespace) {
405 MOZ_ASSERT(NS_IsMainThread());
406
407 gfxPlatform::GetPlatform();
408
409 if (!sImageBridgeChildThread) {
410 nsCOMPtr<nsIThread> thread;
411 nsresult rv = NS_NewNamedThread("ImageBridgeChld", getter_AddRefs(thread));
412 MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv),
413 "Failed to start ImageBridgeChild thread!");
414 sImageBridgeChildThread = thread.forget();
415 }
416
417 RefPtr<ImageBridgeChild> child = new ImageBridgeChild(aNamespace);
418
419 child->GetThread()->Dispatch(NS_NewRunnableFunction(
420 "layers::ImageBridgeChild::Bind",
421 [child, endpoint = std::move(aEndpoint)]() mutable {
422 child->Bind(std::move(endpoint));
423 }));
424
425 // Assign this after so other threads can't post messages before we connect to
426 // IPDL.
427 {
428 StaticMutexAutoLock lock(sImageBridgeSingletonLock);
429 sImageBridgeChildSingleton = child;
430 }
431
432 return true;
433 }
434
ReinitForContent(Endpoint<PImageBridgeChild> && aEndpoint,uint32_t aNamespace)435 bool ImageBridgeChild::ReinitForContent(Endpoint<PImageBridgeChild>&& aEndpoint,
436 uint32_t aNamespace) {
437 MOZ_ASSERT(NS_IsMainThread());
438
439 // Note that at this point, ActorDestroy may not have been called yet,
440 // meaning mCanSend is still true. In this case we will try to send a
441 // synchronous WillClose message to the parent, and will certainly get a
442 // false result and a MsgDropped processing error. This is okay.
443 ShutdownSingleton();
444
445 return InitForContent(std::move(aEndpoint), aNamespace);
446 }
447
Bind(Endpoint<PImageBridgeChild> && aEndpoint)448 void ImageBridgeChild::Bind(Endpoint<PImageBridgeChild>&& aEndpoint) {
449 if (!aEndpoint.Bind(this)) {
450 return;
451 }
452
453 // This reference is dropped in DeallocPImageBridgeChild.
454 this->AddRef();
455
456 mCanSend = true;
457 }
458
BindSameProcess(RefPtr<ImageBridgeParent> aParent)459 void ImageBridgeChild::BindSameProcess(RefPtr<ImageBridgeParent> aParent) {
460 Open(aParent, aParent->GetThread(), mozilla::ipc::ChildSide);
461
462 // This reference is dropped in DeallocPImageBridgeChild.
463 this->AddRef();
464
465 mCanSend = true;
466 }
467
468 /* static */
ShutDown()469 void ImageBridgeChild::ShutDown() {
470 MOZ_ASSERT(NS_IsMainThread());
471
472 ShutdownSingleton();
473
474 if (sImageBridgeChildThread) {
475 sImageBridgeChildThread->Shutdown();
476 sImageBridgeChildThread = nullptr;
477 }
478 }
479
480 /* static */
ShutdownSingleton()481 void ImageBridgeChild::ShutdownSingleton() {
482 MOZ_ASSERT(NS_IsMainThread());
483
484 if (RefPtr<ImageBridgeChild> child = GetSingleton()) {
485 child->WillShutdown();
486
487 StaticMutexAutoLock lock(sImageBridgeSingletonLock);
488 sImageBridgeChildSingleton = nullptr;
489 }
490 }
491
WillShutdown()492 void ImageBridgeChild::WillShutdown() {
493 {
494 SynchronousTask task("ImageBridge ShutdownStep1 lock");
495
496 RefPtr<Runnable> runnable =
497 WrapRunnable(RefPtr<ImageBridgeChild>(this),
498 &ImageBridgeChild::ShutdownStep1, &task);
499 GetThread()->Dispatch(runnable.forget());
500
501 task.Wait();
502 }
503
504 {
505 SynchronousTask task("ImageBridge ShutdownStep2 lock");
506
507 RefPtr<Runnable> runnable =
508 WrapRunnable(RefPtr<ImageBridgeChild>(this),
509 &ImageBridgeChild::ShutdownStep2, &task);
510 GetThread()->Dispatch(runnable.forget());
511
512 task.Wait();
513 }
514 }
515
InitSameProcess(uint32_t aNamespace)516 void ImageBridgeChild::InitSameProcess(uint32_t aNamespace) {
517 NS_ASSERTION(NS_IsMainThread(), "Should be on the main Thread!");
518
519 MOZ_ASSERT(!sImageBridgeChildSingleton);
520 MOZ_ASSERT(!sImageBridgeChildThread);
521
522 nsCOMPtr<nsIThread> thread;
523 nsresult rv = NS_NewNamedThread("ImageBridgeChld", getter_AddRefs(thread));
524 MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv),
525 "Failed to start ImageBridgeChild thread!");
526 sImageBridgeChildThread = thread.forget();
527
528 RefPtr<ImageBridgeChild> child = new ImageBridgeChild(aNamespace);
529 RefPtr<ImageBridgeParent> parent = ImageBridgeParent::CreateSameProcess();
530
531 RefPtr<Runnable> runnable =
532 WrapRunnable(child, &ImageBridgeChild::BindSameProcess, parent);
533 child->GetThread()->Dispatch(runnable.forget());
534
535 // Assign this after so other threads can't post messages before we connect to
536 // IPDL.
537 {
538 StaticMutexAutoLock lock(sImageBridgeSingletonLock);
539 sImageBridgeChildSingleton = child;
540 }
541 }
542
543 /* static */
InitWithGPUProcess(Endpoint<PImageBridgeChild> && aEndpoint,uint32_t aNamespace)544 void ImageBridgeChild::InitWithGPUProcess(
545 Endpoint<PImageBridgeChild>&& aEndpoint, uint32_t aNamespace) {
546 MOZ_ASSERT(NS_IsMainThread());
547 MOZ_ASSERT(!sImageBridgeChildSingleton);
548 MOZ_ASSERT(!sImageBridgeChildThread);
549
550 nsCOMPtr<nsIThread> thread;
551 nsresult rv = NS_NewNamedThread("ImageBridgeChld", getter_AddRefs(thread));
552 MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv),
553 "Failed to start ImageBridgeChild thread!");
554 sImageBridgeChildThread = thread.forget();
555
556 RefPtr<ImageBridgeChild> child = new ImageBridgeChild(aNamespace);
557
558 child->GetThread()->Dispatch(NS_NewRunnableFunction(
559 "layers::ImageBridgeChild::Bind",
560 [child, endpoint = std::move(aEndpoint)]() mutable {
561 child->Bind(std::move(endpoint));
562 }));
563
564 // Assign this after so other threads can't post messages before we connect to
565 // IPDL.
566 {
567 StaticMutexAutoLock lock(sImageBridgeSingletonLock);
568 sImageBridgeChildSingleton = child;
569 }
570 }
571
InImageBridgeChildThread()572 bool InImageBridgeChildThread() {
573 return sImageBridgeChildThread &&
574 sImageBridgeChildThread->IsOnCurrentThread();
575 }
576
GetThread() const577 nsISerialEventTarget* ImageBridgeChild::GetThread() const {
578 return sImageBridgeChildThread;
579 }
580
581 /* static */
IdentifyCompositorTextureHost(const TextureFactoryIdentifier & aIdentifier)582 void ImageBridgeChild::IdentifyCompositorTextureHost(
583 const TextureFactoryIdentifier& aIdentifier) {
584 if (RefPtr<ImageBridgeChild> child = GetSingleton()) {
585 child->UpdateTextureFactoryIdentifier(aIdentifier);
586 }
587 }
588
UpdateTextureFactoryIdentifier(const TextureFactoryIdentifier & aIdentifier)589 void ImageBridgeChild::UpdateTextureFactoryIdentifier(
590 const TextureFactoryIdentifier& aIdentifier) {
591 IdentifyTextureHost(aIdentifier);
592 }
593
CreateImageClient(CompositableType aType,ImageContainer * aImageContainer)594 RefPtr<ImageClient> ImageBridgeChild::CreateImageClient(
595 CompositableType aType, ImageContainer* aImageContainer) {
596 if (InImageBridgeChildThread()) {
597 return CreateImageClientNow(aType, aImageContainer);
598 }
599
600 SynchronousTask task("CreateImageClient Lock");
601
602 RefPtr<ImageClient> result = nullptr;
603
604 RefPtr<Runnable> runnable = WrapRunnable(
605 RefPtr<ImageBridgeChild>(this), &ImageBridgeChild::CreateImageClientSync,
606 &task, &result, aType, aImageContainer);
607 GetThread()->Dispatch(runnable.forget());
608
609 task.Wait();
610
611 return result;
612 }
613
CreateImageClientNow(CompositableType aType,ImageContainer * aImageContainer)614 RefPtr<ImageClient> ImageBridgeChild::CreateImageClientNow(
615 CompositableType aType, ImageContainer* aImageContainer) {
616 MOZ_ASSERT(InImageBridgeChildThread());
617 if (!CanSend()) {
618 return nullptr;
619 }
620
621 RefPtr<ImageClient> client =
622 ImageClient::CreateImageClient(aType, this, TextureFlags::NO_FLAGS);
623 MOZ_ASSERT(client, "failed to create ImageClient");
624 if (client) {
625 client->Connect(aImageContainer);
626 }
627 return client;
628 }
629
AllocUnsafeShmem(size_t aSize,ipc::SharedMemory::SharedMemoryType aType,ipc::Shmem * aShmem)630 bool ImageBridgeChild::AllocUnsafeShmem(
631 size_t aSize, ipc::SharedMemory::SharedMemoryType aType,
632 ipc::Shmem* aShmem) {
633 if (!InImageBridgeChildThread()) {
634 return DispatchAllocShmemInternal(aSize, aType, aShmem,
635 true); // true: unsafe
636 }
637
638 if (!CanSend()) {
639 return false;
640 }
641 return PImageBridgeChild::AllocUnsafeShmem(aSize, aType, aShmem);
642 }
643
AllocShmem(size_t aSize,ipc::SharedMemory::SharedMemoryType aType,ipc::Shmem * aShmem)644 bool ImageBridgeChild::AllocShmem(size_t aSize,
645 ipc::SharedMemory::SharedMemoryType aType,
646 ipc::Shmem* aShmem) {
647 if (!InImageBridgeChildThread()) {
648 return DispatchAllocShmemInternal(aSize, aType, aShmem,
649 false); // false: unsafe
650 }
651
652 if (!CanSend()) {
653 return false;
654 }
655 return PImageBridgeChild::AllocShmem(aSize, aType, aShmem);
656 }
657
ProxyAllocShmemNow(SynchronousTask * aTask,size_t aSize,SharedMemory::SharedMemoryType aType,ipc::Shmem * aShmem,bool aUnsafe,bool * aSuccess)658 void ImageBridgeChild::ProxyAllocShmemNow(SynchronousTask* aTask, size_t aSize,
659 SharedMemory::SharedMemoryType aType,
660 ipc::Shmem* aShmem, bool aUnsafe,
661 bool* aSuccess) {
662 AutoCompleteTask complete(aTask);
663
664 if (!CanSend()) {
665 return;
666 }
667
668 bool ok = false;
669 if (aUnsafe) {
670 ok = AllocUnsafeShmem(aSize, aType, aShmem);
671 } else {
672 ok = AllocShmem(aSize, aType, aShmem);
673 }
674 *aSuccess = ok;
675 }
676
DispatchAllocShmemInternal(size_t aSize,SharedMemory::SharedMemoryType aType,ipc::Shmem * aShmem,bool aUnsafe)677 bool ImageBridgeChild::DispatchAllocShmemInternal(
678 size_t aSize, SharedMemory::SharedMemoryType aType, ipc::Shmem* aShmem,
679 bool aUnsafe) {
680 SynchronousTask task("AllocatorProxy alloc");
681
682 bool success = false;
683 RefPtr<Runnable> runnable = WrapRunnable(
684 RefPtr<ImageBridgeChild>(this), &ImageBridgeChild::ProxyAllocShmemNow,
685 &task, aSize, aType, aShmem, aUnsafe, &success);
686 GetThread()->Dispatch(runnable.forget());
687
688 task.Wait();
689
690 return success;
691 }
692
ProxyDeallocShmemNow(SynchronousTask * aTask,ipc::Shmem * aShmem,bool * aResult)693 void ImageBridgeChild::ProxyDeallocShmemNow(SynchronousTask* aTask,
694 ipc::Shmem* aShmem, bool* aResult) {
695 AutoCompleteTask complete(aTask);
696
697 if (!CanSend()) {
698 return;
699 }
700 *aResult = DeallocShmem(*aShmem);
701 }
702
DeallocShmem(ipc::Shmem & aShmem)703 bool ImageBridgeChild::DeallocShmem(ipc::Shmem& aShmem) {
704 if (InImageBridgeChildThread()) {
705 if (!CanSend()) {
706 return false;
707 }
708 return PImageBridgeChild::DeallocShmem(aShmem);
709 }
710
711 // If we can't post a task, then we definitely cannot send, so there's
712 // no reason to queue up this send.
713 if (!CanPostTask()) {
714 return false;
715 }
716
717 SynchronousTask task("AllocatorProxy Dealloc");
718 bool result = false;
719
720 RefPtr<Runnable> runnable = WrapRunnable(
721 RefPtr<ImageBridgeChild>(this), &ImageBridgeChild::ProxyDeallocShmemNow,
722 &task, &aShmem, &result);
723 GetThread()->Dispatch(runnable.forget());
724
725 task.Wait();
726 return result;
727 }
728
AllocPTextureChild(const SurfaceDescriptor &,ReadLockDescriptor &,const LayersBackend &,const TextureFlags &,const uint64_t & aSerial,const wr::MaybeExternalImageId & aExternalImageId)729 PTextureChild* ImageBridgeChild::AllocPTextureChild(
730 const SurfaceDescriptor&, ReadLockDescriptor&, const LayersBackend&,
731 const TextureFlags&, const uint64_t& aSerial,
732 const wr::MaybeExternalImageId& aExternalImageId) {
733 MOZ_ASSERT(CanSend());
734 return TextureClient::CreateIPDLActor();
735 }
736
DeallocPTextureChild(PTextureChild * actor)737 bool ImageBridgeChild::DeallocPTextureChild(PTextureChild* actor) {
738 return TextureClient::DestroyIPDLActor(actor);
739 }
740
741 PMediaSystemResourceManagerChild*
AllocPMediaSystemResourceManagerChild()742 ImageBridgeChild::AllocPMediaSystemResourceManagerChild() {
743 MOZ_ASSERT(CanSend());
744 return new mozilla::media::MediaSystemResourceManagerChild();
745 }
746
DeallocPMediaSystemResourceManagerChild(PMediaSystemResourceManagerChild * aActor)747 bool ImageBridgeChild::DeallocPMediaSystemResourceManagerChild(
748 PMediaSystemResourceManagerChild* aActor) {
749 MOZ_ASSERT(aActor);
750 delete static_cast<mozilla::media::MediaSystemResourceManagerChild*>(aActor);
751 return true;
752 }
753
RecvParentAsyncMessages(nsTArray<AsyncParentMessageData> && aMessages)754 mozilla::ipc::IPCResult ImageBridgeChild::RecvParentAsyncMessages(
755 nsTArray<AsyncParentMessageData>&& aMessages) {
756 for (AsyncParentMessageArray::index_type i = 0; i < aMessages.Length(); ++i) {
757 const AsyncParentMessageData& message = aMessages[i];
758
759 switch (message.type()) {
760 case AsyncParentMessageData::TOpNotifyNotUsed: {
761 const OpNotifyNotUsed& op = message.get_OpNotifyNotUsed();
762 NotifyNotUsed(op.TextureId(), op.fwdTransactionId());
763 break;
764 }
765 case AsyncParentMessageData::TOpDeliverReleaseFence: {
766 #ifdef MOZ_WIDGET_ANDROID
767 const OpDeliverReleaseFence& op = message.get_OpDeliverReleaseFence();
768 ipc::FileDescriptor fenceFd;
769 if (op.fenceFd().isSome()) {
770 fenceFd = *op.fenceFd();
771 }
772 AndroidHardwareBufferManager::Get()->NotifyNotUsed(
773 std::move(fenceFd), op.bufferId(), op.fwdTransactionId(),
774 op.usesImageBridge());
775 #else
776 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
777 #endif
778 break;
779 }
780 default:
781 NS_ERROR("unknown AsyncParentMessageData type");
782 return IPC_FAIL_NO_REASON(this);
783 }
784 }
785 return IPC_OK();
786 }
787
FindListener(const CompositableHandle & aHandle)788 RefPtr<ImageContainerListener> ImageBridgeChild::FindListener(
789 const CompositableHandle& aHandle) {
790 RefPtr<ImageContainerListener> listener;
791 MutexAutoLock lock(mContainerMapLock);
792 auto it = mImageContainerListeners.find(aHandle.Value());
793 if (it != mImageContainerListeners.end()) {
794 listener = it->second;
795 }
796 return listener;
797 }
798
RecvDidComposite(nsTArray<ImageCompositeNotification> && aNotifications)799 mozilla::ipc::IPCResult ImageBridgeChild::RecvDidComposite(
800 nsTArray<ImageCompositeNotification>&& aNotifications) {
801 for (auto& n : aNotifications) {
802 RefPtr<ImageContainerListener> listener = FindListener(n.compositable());
803 if (listener) {
804 listener->NotifyComposite(n);
805 }
806 }
807 return IPC_OK();
808 }
809
RecvReportFramesDropped(const CompositableHandle & aHandle,const uint32_t & aFrames)810 mozilla::ipc::IPCResult ImageBridgeChild::RecvReportFramesDropped(
811 const CompositableHandle& aHandle, const uint32_t& aFrames) {
812 RefPtr<ImageContainerListener> listener = FindListener(aHandle);
813 if (listener) {
814 listener->NotifyDropped(aFrames);
815 }
816
817 return IPC_OK();
818 }
819
CreateTexture(const SurfaceDescriptor & aSharedData,ReadLockDescriptor && aReadLock,LayersBackend aLayersBackend,TextureFlags aFlags,uint64_t aSerial,wr::MaybeExternalImageId & aExternalImageId)820 PTextureChild* ImageBridgeChild::CreateTexture(
821 const SurfaceDescriptor& aSharedData, ReadLockDescriptor&& aReadLock,
822 LayersBackend aLayersBackend, TextureFlags aFlags, uint64_t aSerial,
823 wr::MaybeExternalImageId& aExternalImageId) {
824 MOZ_ASSERT(CanSend());
825 return SendPTextureConstructor(aSharedData, std::move(aReadLock),
826 aLayersBackend, aFlags, aSerial,
827 aExternalImageId);
828 }
829
IBCAddOpDestroy(CompositableTransaction * aTxn,const OpDestroy & op)830 static bool IBCAddOpDestroy(CompositableTransaction* aTxn,
831 const OpDestroy& op) {
832 if (aTxn->Finished()) {
833 return false;
834 }
835
836 aTxn->mDestroyedActors.AppendElement(op);
837 return true;
838 }
839
DestroyInTransaction(PTextureChild * aTexture)840 bool ImageBridgeChild::DestroyInTransaction(PTextureChild* aTexture) {
841 return IBCAddOpDestroy(mTxn, OpDestroy(aTexture));
842 }
843
DestroyInTransaction(const CompositableHandle & aHandle)844 bool ImageBridgeChild::DestroyInTransaction(const CompositableHandle& aHandle) {
845 return IBCAddOpDestroy(mTxn, OpDestroy(aHandle));
846 }
847
RemoveTextureFromCompositable(CompositableClient * aCompositable,TextureClient * aTexture)848 void ImageBridgeChild::RemoveTextureFromCompositable(
849 CompositableClient* aCompositable, TextureClient* aTexture) {
850 MOZ_ASSERT(CanSend());
851 MOZ_ASSERT(aTexture);
852 MOZ_ASSERT(aTexture->IsSharedWithCompositor());
853 MOZ_ASSERT(aCompositable->IsConnected());
854 if (!aTexture || !aTexture->IsSharedWithCompositor() ||
855 !aCompositable->IsConnected()) {
856 return;
857 }
858
859 mTxn->AddNoSwapEdit(CompositableOperation(
860 aCompositable->GetIPCHandle(),
861 OpRemoveTexture(nullptr, aTexture->GetIPDLActor())));
862 }
863
IsSameProcess() const864 bool ImageBridgeChild::IsSameProcess() const {
865 return OtherPid() == base::GetCurrentProcId();
866 }
867
CanPostTask() const868 bool ImageBridgeChild::CanPostTask() const {
869 // During shutdown, the cycle collector may free objects that are holding a
870 // reference to ImageBridgeChild. Since this happens on the main thread,
871 // ImageBridgeChild will attempt to post a task to the ImageBridge thread.
872 // However the thread manager has already been shut down, so the task cannot
873 // post.
874 //
875 // It's okay if this races. We only care about the shutdown case where
876 // everything's happening on the main thread. Even if it races outside of
877 // shutdown, it's still harmless to post the task, since the task must
878 // check CanSend().
879 return !mDestroyed;
880 }
881
ReleaseCompositable(const CompositableHandle & aHandle)882 void ImageBridgeChild::ReleaseCompositable(const CompositableHandle& aHandle) {
883 if (!InImageBridgeChildThread()) {
884 // If we can't post a task, then we definitely cannot send, so there's
885 // no reason to queue up this send.
886 if (!CanPostTask()) {
887 return;
888 }
889
890 RefPtr<Runnable> runnable =
891 WrapRunnable(RefPtr<ImageBridgeChild>(this),
892 &ImageBridgeChild::ReleaseCompositable, aHandle);
893 GetThread()->Dispatch(runnable.forget());
894 return;
895 }
896
897 if (!CanSend()) {
898 return;
899 }
900
901 if (!DestroyInTransaction(aHandle)) {
902 SendReleaseCompositable(aHandle);
903 }
904
905 {
906 MutexAutoLock lock(mContainerMapLock);
907 mImageContainerListeners.erase(aHandle.Value());
908 }
909 }
910
CanSend() const911 bool ImageBridgeChild::CanSend() const {
912 MOZ_ASSERT(InImageBridgeChildThread());
913 return mCanSend;
914 }
915
HandleFatalError(const char * aMsg) const916 void ImageBridgeChild::HandleFatalError(const char* aMsg) const {
917 dom::ContentChild::FatalErrorIfNotUsingGPUProcess(aMsg, OtherPid());
918 }
919
GetNextExternalImageId()920 wr::MaybeExternalImageId ImageBridgeChild::GetNextExternalImageId() {
921 static uint32_t sNextID = 1;
922 ++sNextID;
923 MOZ_RELEASE_ASSERT(sNextID != UINT32_MAX);
924
925 uint64_t imageId = mNamespace;
926 imageId = imageId << 32 | sNextID;
927 return Some(wr::ToExternalImageId(imageId));
928 }
929
930 } // namespace layers
931 } // namespace mozilla
932