tor-browser

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

ImageBridgeParent.cpp (14908B)


      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 "ImageBridgeParent.h"
      8 #include <stdint.h>            // for uint64_t, uint32_t
      9 #include "CompositableHost.h"  // for CompositableParent, Create
     10 #include "base/process.h"      // for ProcessId
     11 #include "base/task.h"         // for CancelableTask, DeleteTask, etc
     12 #include "mozilla/ClearOnShutdown.h"
     13 #include "mozilla/gfx/Point.h"  // for IntSize
     14 #include "mozilla/Hal.h"        // for hal::SetCurrentThreadPriority()
     15 #include "mozilla/HalTypes.h"   // for hal::THREAD_PRIORITY_COMPOSITOR
     16 #include "mozilla/ipc/Endpoint.h"
     17 #include "mozilla/ipc/MessageChannel.h"  // for MessageChannel, etc
     18 #include "mozilla/media/MediaSystemResourceManagerParent.h"  // for MediaSystemResourceManagerParent
     19 #include "mozilla/layers/BufferTexture.h"
     20 #include "mozilla/layers/CompositableTransactionParent.h"
     21 #include "mozilla/layers/LayersMessages.h"  // for EditReply
     22 #include "mozilla/layers/PImageBridgeParent.h"
     23 #include "mozilla/layers/TextureHostOGL.h"  // for TextureHostOGL
     24 #include "mozilla/layers/Compositor.h"
     25 #include "mozilla/layers/RemoteTextureMap.h"
     26 #include "mozilla/Monitor.h"
     27 #include "mozilla/mozalloc.h"  // for operator new, etc
     28 #include "mozilla/ProfilerLabels.h"
     29 #include "mozilla/ProfilerMarkers.h"
     30 #include "nsDebug.h"                 // for NS_ASSERTION, etc
     31 #include "nsISupportsImpl.h"         // for ImageBridgeParent::Release, etc
     32 #include "nsTArray.h"                // for nsTArray, nsTArray_Impl
     33 #include "nsTArrayForwardDeclare.h"  // for nsTArray
     34 #include "nsXULAppAPI.h"             // for XRE_GetAsyncIOEventTarget
     35 #include "mozilla/layers/TextureHost.h"
     36 #include "nsThreadUtils.h"
     37 
     38 #if defined(XP_WIN)
     39 #  include "mozilla/layers/TextureD3D11.h"
     40 #endif
     41 
     42 namespace mozilla {
     43 namespace layers {
     44 
     45 using namespace mozilla::ipc;
     46 using namespace mozilla::gfx;
     47 using namespace mozilla::media;
     48 
     49 MOZ_RUNINIT ImageBridgeParent::ImageBridgeMap ImageBridgeParent::sImageBridges;
     50 
     51 StaticAutoPtr<mozilla::Monitor> sImageBridgesLock;
     52 
     53 static StaticRefPtr<ImageBridgeParent> sImageBridgeParentSingleton;
     54 
     55 /* static */
     56 void ImageBridgeParent::Setup() {
     57  MOZ_ASSERT(NS_IsMainThread());
     58  if (!sImageBridgesLock) {
     59    sImageBridgesLock = new Monitor("ImageBridges");
     60    mozilla::ClearOnShutdown(&sImageBridgesLock);
     61  }
     62 }
     63 
     64 ImageBridgeParent::ImageBridgeParent(nsISerialEventTarget* aThread,
     65                                     EndpointProcInfo aChildProcessInfo,
     66                                     dom::ContentParentId aContentId)
     67    : mThread(aThread),
     68      mContentId(aContentId),
     69      mClosed(false),
     70      mCompositorThreadHolder(CompositorThreadHolder::GetSingleton()) {
     71  MOZ_ASSERT(NS_IsMainThread());
     72  SetOtherEndpointProcInfo(aChildProcessInfo);
     73  mRemoteTextureTxnScheduler = RemoteTextureTxnScheduler::Create(this);
     74 }
     75 
     76 ImageBridgeParent::~ImageBridgeParent() = default;
     77 
     78 /* static */
     79 ImageBridgeParent* ImageBridgeParent::CreateSameProcess() {
     80  EndpointProcInfo procInfo = EndpointProcInfo::Current();
     81  RefPtr<ImageBridgeParent> parent = new ImageBridgeParent(
     82      CompositorThread(), procInfo, dom::ContentParentId());
     83 
     84  {
     85    MonitorAutoLock lock(*sImageBridgesLock);
     86    MOZ_RELEASE_ASSERT(sImageBridges.count(procInfo.mPid) == 0);
     87    sImageBridges[procInfo.mPid] = parent;
     88  }
     89 
     90  sImageBridgeParentSingleton = parent;
     91  return parent;
     92 }
     93 
     94 /* static */
     95 bool ImageBridgeParent::CreateForGPUProcess(
     96    Endpoint<PImageBridgeParent>&& aEndpoint) {
     97  MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_GPU);
     98 
     99  nsCOMPtr<nsISerialEventTarget> compositorThread = CompositorThread();
    100  if (!compositorThread) {
    101    return false;
    102  }
    103 
    104  RefPtr<ImageBridgeParent> parent =
    105      new ImageBridgeParent(compositorThread, aEndpoint.OtherEndpointProcInfo(),
    106                            dom::ContentParentId());
    107 
    108  compositorThread->Dispatch(NewRunnableMethod<Endpoint<PImageBridgeParent>&&>(
    109      "layers::ImageBridgeParent::Bind", parent, &ImageBridgeParent::Bind,
    110      std::move(aEndpoint)));
    111 
    112  sImageBridgeParentSingleton = parent;
    113  return true;
    114 }
    115 
    116 /* static */
    117 void ImageBridgeParent::ShutdownInternal() {
    118  // We make a copy because we don't want to hold the lock while closing and we
    119  // don't want the object to get freed underneath us.
    120  nsTArray<RefPtr<ImageBridgeParent>> actors;
    121  {
    122    MonitorAutoLock lock(*sImageBridgesLock);
    123    for (const auto& iter : sImageBridges) {
    124      actors.AppendElement(iter.second);
    125    }
    126  }
    127 
    128  for (auto const& actor : actors) {
    129    MOZ_RELEASE_ASSERT(!actor->mClosed);
    130    actor->Close();
    131  }
    132 
    133  sImageBridgeParentSingleton = nullptr;
    134 }
    135 
    136 /* static */
    137 void ImageBridgeParent::Shutdown() {
    138  CompositorThread()->Dispatch(NS_NewRunnableFunction(
    139      "ImageBridgeParent::Shutdown",
    140      []() -> void { ImageBridgeParent::ShutdownInternal(); }));
    141 }
    142 
    143 void ImageBridgeParent::ActorDestroy(ActorDestroyReason aWhy) {
    144  // Can't alloc/dealloc shmems from now on.
    145  mClosed = true;
    146 
    147  if (mRemoteTextureTxnScheduler) {
    148    mRemoteTextureTxnScheduler = nullptr;
    149  }
    150  for (const auto& entry : mCompositables) {
    151    entry.second->OnReleased();
    152  }
    153  mCompositables.clear();
    154  {
    155    MonitorAutoLock lock(*sImageBridgesLock);
    156    sImageBridges.erase(OtherPid());
    157  }
    158  GetThread()->Dispatch(
    159      NewRunnableMethod("layers::ImageBridgeParent::DeferredDestroy", this,
    160                        &ImageBridgeParent::DeferredDestroy));
    161 
    162  // It is very important that this method gets called at shutdown (be it a
    163  // clean or an abnormal shutdown), because DeferredDestroy is what clears
    164  // mCompositorThreadHolder. If mCompositorThreadHolder is not null and
    165  // ActorDestroy is not called, the ImageBridgeParent is leaked which causes
    166  // the CompositorThreadHolder to be leaked and CompsoitorParent's shutdown
    167  // ends up spinning the event loop forever, waiting for the compositor thread
    168  // to terminate.
    169 }
    170 
    171 class MOZ_STACK_CLASS AutoImageBridgeParentAsyncMessageSender final {
    172 public:
    173  explicit AutoImageBridgeParentAsyncMessageSender(
    174      ImageBridgeParent* aImageBridge,
    175      nsTArray<OpDestroy>* aToDestroy = nullptr)
    176      : mImageBridge(aImageBridge), mToDestroy(aToDestroy) {
    177    mImageBridge->SetAboutToSendAsyncMessages();
    178  }
    179 
    180  ~AutoImageBridgeParentAsyncMessageSender() {
    181    mImageBridge->SendPendingAsyncMessages();
    182    if (mToDestroy) {
    183      for (const auto& op : *mToDestroy) {
    184        mImageBridge->DestroyActor(op);
    185      }
    186    }
    187  }
    188 
    189 private:
    190  ImageBridgeParent* mImageBridge;
    191  nsTArray<OpDestroy>* mToDestroy;
    192 };
    193 
    194 mozilla::ipc::IPCResult ImageBridgeParent::RecvUpdate(
    195    EditArray&& aEdits, OpDestroyArray&& aToDestroy,
    196    const uint64_t& aFwdTransactionId) {
    197  AUTO_PROFILER_MARKER("ImageBridgeTransaction", GRAPHICS);
    198  AUTO_PROFILER_LABEL("ImageBridgeParent::RecvUpdate", GRAPHICS);
    199 
    200  // This ensures that destroy operations are always processed. It is not safe
    201  // to early-return from RecvUpdate without doing so.
    202  AutoImageBridgeParentAsyncMessageSender autoAsyncMessageSender(this,
    203                                                                 &aToDestroy);
    204  UpdateFwdTransactionId(aFwdTransactionId);
    205 
    206  auto result = IPC_OK();
    207 
    208  for (const auto& edit : aEdits) {
    209    RefPtr<CompositableHost> compositable =
    210        FindCompositable(edit.compositable());
    211    if (!compositable ||
    212        !ReceiveCompositableUpdate(edit.detail(), WrapNotNull(compositable),
    213                                   edit.compositable())) {
    214      result = IPC_FAIL_NO_REASON(this);
    215      break;
    216    }
    217    uint32_t dropped = compositable->GetDroppedFrames();
    218    if (dropped) {
    219      (void)SendReportFramesDropped(edit.compositable(), dropped);
    220    }
    221  }
    222 
    223  if (mRemoteTextureTxnScheduler) {
    224    mRemoteTextureTxnScheduler->NotifyTxn(aFwdTransactionId);
    225  }
    226 
    227  return result;
    228 }
    229 
    230 /* static */
    231 bool ImageBridgeParent::CreateForContent(
    232    Endpoint<PImageBridgeParent>&& aEndpoint, dom::ContentParentId aContentId) {
    233  nsCOMPtr<nsISerialEventTarget> compositorThread = CompositorThread();
    234  if (!compositorThread) {
    235    return false;
    236  }
    237 
    238  RefPtr<ImageBridgeParent> bridge = new ImageBridgeParent(
    239      compositorThread, aEndpoint.OtherEndpointProcInfo(), aContentId);
    240  compositorThread->Dispatch(NewRunnableMethod<Endpoint<PImageBridgeParent>&&>(
    241      "layers::ImageBridgeParent::Bind", bridge, &ImageBridgeParent::Bind,
    242      std::move(aEndpoint)));
    243 
    244  return true;
    245 }
    246 
    247 void ImageBridgeParent::Bind(Endpoint<PImageBridgeParent>&& aEndpoint) {
    248  if (!aEndpoint.Bind(this)) return;
    249 
    250  // If the child process ID was reused by the OS before the ImageBridgeParent
    251  // object was destroyed, we need to clean it up first.
    252  RefPtr<ImageBridgeParent> oldActor;
    253  {
    254    MonitorAutoLock lock(*sImageBridgesLock);
    255    ImageBridgeMap::const_iterator i = sImageBridges.find(OtherPid());
    256    if (i != sImageBridges.end()) {
    257      oldActor = i->second;
    258    }
    259  }
    260 
    261  // We can't hold the lock during Close because it erases itself from the map.
    262  if (oldActor) {
    263    MOZ_RELEASE_ASSERT(!oldActor->mClosed);
    264    oldActor->Close();
    265  }
    266 
    267  {
    268    MonitorAutoLock lock(*sImageBridgesLock);
    269    sImageBridges[OtherPid()] = this;
    270  }
    271 }
    272 
    273 mozilla::ipc::IPCResult ImageBridgeParent::RecvWillClose() {
    274  // If there is any texture still alive we have to force it to deallocate the
    275  // device data (GL textures, etc.) now because shortly after SenStop() returns
    276  // on the child side the widget will be destroyed along with it's associated
    277  // GL context.
    278  nsTArray<PTextureParent*> textures;
    279  ManagedPTextureParent(textures);
    280  for (unsigned int i = 0; i < textures.Length(); ++i) {
    281    RefPtr<TextureHost> tex = TextureHost::AsTextureHost(textures[i]);
    282    tex->DeallocateDeviceData();
    283  }
    284  return IPC_OK();
    285 }
    286 
    287 mozilla::ipc::IPCResult ImageBridgeParent::RecvNewCompositable(
    288    const CompositableHandle& aHandle, const TextureInfo& aInfo) {
    289  RefPtr<CompositableHost> host = AddCompositable(aHandle, aInfo);
    290  if (!host) {
    291    return IPC_FAIL_NO_REASON(this);
    292  }
    293 
    294  host->SetAsyncRef(AsyncCompositableRef(OtherPid(), aHandle));
    295  return IPC_OK();
    296 }
    297 
    298 mozilla::ipc::IPCResult ImageBridgeParent::RecvReleaseCompositable(
    299    const CompositableHandle& aHandle) {
    300  ReleaseCompositable(aHandle);
    301  return IPC_OK();
    302 }
    303 
    304 PTextureParent* ImageBridgeParent::AllocPTextureParent(
    305    const SurfaceDescriptor& aSharedData, ReadLockDescriptor& aReadLock,
    306    const LayersBackend& aLayersBackend, const TextureFlags& aFlags,
    307    const uint64_t& aSerial, const wr::MaybeExternalImageId& aExternalImageId) {
    308  return TextureHost::CreateIPDLActor(this, aSharedData, std::move(aReadLock),
    309                                      aLayersBackend, aFlags, mContentId,
    310                                      aSerial, aExternalImageId);
    311 }
    312 
    313 bool ImageBridgeParent::DeallocPTextureParent(PTextureParent* actor) {
    314  return TextureHost::DestroyIPDLActor(actor);
    315 }
    316 
    317 PMediaSystemResourceManagerParent*
    318 ImageBridgeParent::AllocPMediaSystemResourceManagerParent() {
    319  return new mozilla::media::MediaSystemResourceManagerParent();
    320 }
    321 
    322 bool ImageBridgeParent::DeallocPMediaSystemResourceManagerParent(
    323    PMediaSystemResourceManagerParent* aActor) {
    324  MOZ_ASSERT(aActor);
    325  delete static_cast<mozilla::media::MediaSystemResourceManagerParent*>(aActor);
    326  return true;
    327 }
    328 
    329 void ImageBridgeParent::SendAsyncMessage(
    330    const nsTArray<AsyncParentMessageData>& aMessage) {
    331  (void)SendParentAsyncMessages(aMessage);
    332 }
    333 
    334 class ProcessIdComparator {
    335 public:
    336  bool Equals(const ImageCompositeNotificationInfo& aA,
    337              const ImageCompositeNotificationInfo& aB) const {
    338    return aA.mImageBridgeProcessId == aB.mImageBridgeProcessId;
    339  }
    340  bool LessThan(const ImageCompositeNotificationInfo& aA,
    341                const ImageCompositeNotificationInfo& aB) const {
    342    return aA.mImageBridgeProcessId < aB.mImageBridgeProcessId;
    343  }
    344 };
    345 
    346 /* static */
    347 bool ImageBridgeParent::NotifyImageComposites(
    348    nsTArray<ImageCompositeNotificationInfo>& aNotifications) {
    349  // Group the notifications by destination process ID and then send the
    350  // notifications in one message per group.
    351  aNotifications.Sort(ProcessIdComparator());
    352  uint32_t i = 0;
    353  bool ok = true;
    354  while (i < aNotifications.Length()) {
    355    AutoTArray<ImageCompositeNotification, 1> notifications;
    356    notifications.AppendElement(aNotifications[i].mNotification);
    357    uint32_t end = i + 1;
    358    MOZ_ASSERT(aNotifications[i].mNotification.compositable());
    359    ProcessId pid = aNotifications[i].mImageBridgeProcessId;
    360    while (end < aNotifications.Length() &&
    361           aNotifications[end].mImageBridgeProcessId == pid) {
    362      notifications.AppendElement(aNotifications[end].mNotification);
    363      ++end;
    364    }
    365    RefPtr<ImageBridgeParent> bridge = GetInstance(pid);
    366    if (!bridge || bridge->mClosed) {
    367      i = end;
    368      continue;
    369    }
    370    bridge->SendPendingAsyncMessages();
    371    if (!bridge->SendDidComposite(notifications)) {
    372      ok = false;
    373    }
    374    i = end;
    375  }
    376  return ok;
    377 }
    378 
    379 void ImageBridgeParent::DeferredDestroy() { mCompositorThreadHolder = nullptr; }
    380 
    381 already_AddRefed<ImageBridgeParent> ImageBridgeParent::GetInstance(
    382    ProcessId aId) {
    383  MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
    384  MonitorAutoLock lock(*sImageBridgesLock);
    385  ImageBridgeMap::const_iterator i = sImageBridges.find(aId);
    386  if (i == sImageBridges.end()) {
    387    NS_WARNING("Cannot find image bridge for process!");
    388    return nullptr;
    389  }
    390  RefPtr<ImageBridgeParent> bridge = i->second;
    391  return bridge.forget();
    392 }
    393 
    394 bool ImageBridgeParent::AllocShmem(size_t aSize, ipc::Shmem* aShmem) {
    395  if (mClosed) {
    396    return false;
    397  }
    398  return PImageBridgeParent::AllocShmem(aSize, aShmem);
    399 }
    400 
    401 bool ImageBridgeParent::AllocUnsafeShmem(size_t aSize, ipc::Shmem* aShmem) {
    402  if (mClosed) {
    403    return false;
    404  }
    405  return PImageBridgeParent::AllocUnsafeShmem(aSize, aShmem);
    406 }
    407 
    408 bool ImageBridgeParent::DeallocShmem(ipc::Shmem& aShmem) {
    409  if (mClosed) {
    410    return false;
    411  }
    412  return PImageBridgeParent::DeallocShmem(aShmem);
    413 }
    414 
    415 bool ImageBridgeParent::IsSameProcess() const {
    416  return OtherPid() == base::GetCurrentProcId();
    417 }
    418 
    419 void ImageBridgeParent::NotifyNotUsed(PTextureParent* aTexture,
    420                                      uint64_t aTransactionId) {
    421  RefPtr<TextureHost> texture = TextureHost::AsTextureHost(aTexture);
    422  if (!texture) {
    423    return;
    424  }
    425 
    426  if (!(texture->GetFlags() & TextureFlags::RECYCLE) &&
    427      !(texture->GetFlags() & TextureFlags::WAIT_HOST_USAGE_END)) {
    428    return;
    429  }
    430 
    431  uint64_t textureId = TextureHost::GetTextureSerial(aTexture);
    432  mPendingAsyncMessage.push_back(OpNotifyNotUsed(textureId, aTransactionId));
    433 
    434  if (!IsAboutToSendAsyncMessages()) {
    435    SendPendingAsyncMessages();
    436  }
    437 }
    438 
    439 }  // namespace layers
    440 }  // namespace mozilla