tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ImageBridgeChild.cpp (30174B)


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