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