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