tor-browser

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

CompositorManagerParent.cpp (14020B)


      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 "mozilla/layers/CompositorManagerParent.h"
      8 #include "mozilla/gfx/GPUParent.h"
      9 #include "mozilla/gfx/CanvasManagerParent.h"
     10 #include "mozilla/webrender/RenderThread.h"
     11 #include "mozilla/ipc/Endpoint.h"
     12 #include "mozilla/layers/CompositorBridgeParent.h"
     13 #include "mozilla/layers/ContentCompositorBridgeParent.h"
     14 #include "mozilla/layers/CompositorThread.h"
     15 #include "mozilla/layers/RemoteTextureMap.h"
     16 #include "mozilla/layers/SharedSurfacesParent.h"
     17 #include "gfxPlatform.h"
     18 #include "VsyncSource.h"
     19 
     20 namespace mozilla {
     21 namespace layers {
     22 
     23 StaticMonitor CompositorManagerParent::sMonitor;
     24 StaticRefPtr<CompositorManagerParent> CompositorManagerParent::sInstance;
     25 MOZ_RUNINIT CompositorManagerParent::ManagerMap
     26    CompositorManagerParent::sManagers;
     27 
     28 /* static */
     29 already_AddRefed<CompositorManagerParent>
     30 CompositorManagerParent::CreateSameProcess(uint32_t aNamespace) {
     31  MOZ_ASSERT(XRE_IsParentProcess());
     32  MOZ_ASSERT(NS_IsMainThread());
     33  StaticMonitorAutoLock lock(sMonitor);
     34 
     35  // We are creating a manager for the UI process, inside the combined GPU/UI
     36  // process. It is created more-or-less the same but we retain a reference to
     37  // the parent to access state.
     38  if (NS_WARN_IF(sInstance)) {
     39    MOZ_ASSERT_UNREACHABLE("Already initialized");
     40    return nullptr;
     41  }
     42 
     43  // The child is responsible for setting up the IPC channel in the same
     44  // process case because if we open from the child perspective, we can do it
     45  // on the main thread and complete before we return the manager handles.
     46  RefPtr<CompositorManagerParent> parent =
     47      new CompositorManagerParent(dom::ContentParentId(), aNamespace);
     48  parent->SetOtherEndpointProcInfo(ipc::EndpointProcInfo::Current());
     49  return parent.forget();
     50 }
     51 
     52 /* static */
     53 bool CompositorManagerParent::Create(
     54    Endpoint<PCompositorManagerParent>&& aEndpoint,
     55    dom::ContentParentId aChildId, uint32_t aNamespace, bool aIsRoot) {
     56  MOZ_ASSERT(NS_IsMainThread());
     57 
     58  // We are creating a manager for the another process, inside the GPU process
     59  // (or UI process if it subsumbed the GPU process).
     60  MOZ_ASSERT(aEndpoint.OtherPid() != base::GetCurrentProcId());
     61 
     62  if (!CompositorThreadHolder::IsActive()) {
     63    return false;
     64  }
     65 
     66  RefPtr<CompositorManagerParent> bridge =
     67      new CompositorManagerParent(aChildId, aNamespace);
     68 
     69  RefPtr<Runnable> runnable =
     70      NewRunnableMethod<Endpoint<PCompositorManagerParent>&&, bool>(
     71          "CompositorManagerParent::Bind", bridge,
     72          &CompositorManagerParent::Bind, std::move(aEndpoint), aIsRoot);
     73  CompositorThread()->Dispatch(runnable.forget());
     74  return true;
     75 }
     76 
     77 /* static */
     78 already_AddRefed<CompositorBridgeParent>
     79 CompositorManagerParent::CreateSameProcessWidgetCompositorBridge(
     80    CSSToLayoutDeviceScale aScale, const CompositorOptions& aOptions,
     81    bool aUseExternalSurfaceSize, const gfx::IntSize& aSurfaceSize,
     82    uint64_t aInnerWindowId) {
     83  MOZ_ASSERT(XRE_IsParentProcess());
     84  MOZ_ASSERT(NS_IsMainThread());
     85 
     86  // When we are in a combined UI / GPU process, InProcessCompositorSession
     87  // requires both the parent and child PCompositorBridge actors for its own
     88  // construction, which is done on the main thread. Normally
     89  // CompositorBridgeParent is created on the compositor thread via the IPDL
     90  // plumbing (CompositorManagerParent::AllocPCompositorBridgeParent). Thus to
     91  // actually get a reference to the parent, we would need to block on the
     92  // compositor thread until it handles our constructor message. Because only
     93  // one one IPDL constructor is permitted per parent and child protocol, we
     94  // cannot make the normal case async and this case sync. Instead what we do
     95  // is leave the constructor async (a boon to the content process setup) and
     96  // create the parent ahead of time. It will pull the preinitialized parent
     97  // from the queue when it receives the message and give that to IPDL.
     98 
     99  // Note that the static mutex not only is used to protect sInstance, but also
    100  // mPendingCompositorBridges.
    101  StaticMonitorAutoLock lock(sMonitor);
    102  if (NS_WARN_IF(!sInstance)) {
    103    return nullptr;
    104  }
    105 
    106  TimeDuration vsyncRate =
    107      gfxPlatform::GetPlatform()->GetGlobalVsyncDispatcher()->GetVsyncRate();
    108 
    109  RefPtr<CompositorBridgeParent> bridge = new CompositorBridgeParent(
    110      sInstance, aScale, vsyncRate, aOptions, aUseExternalSurfaceSize,
    111      aSurfaceSize, aInnerWindowId);
    112 
    113  sInstance->mPendingCompositorBridges.AppendElement(bridge);
    114  return bridge.forget();
    115 }
    116 
    117 CompositorManagerParent::CompositorManagerParent(
    118    dom::ContentParentId aContentId, uint32_t aNamespace)
    119    : mCompositorThreadHolder(CompositorThreadHolder::GetSingleton()),
    120      mSharedSurfacesHolder(MakeRefPtr<SharedSurfacesHolder>(aNamespace)),
    121      mContentId(aContentId),
    122      mNamespace(aNamespace) {}
    123 
    124 CompositorManagerParent::~CompositorManagerParent() = default;
    125 
    126 void CompositorManagerParent::Bind(
    127    Endpoint<PCompositorManagerParent>&& aEndpoint, bool aIsRoot) {
    128  MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
    129  if (NS_WARN_IF(!aEndpoint.Bind(this))) {
    130    return;
    131  }
    132 
    133  BindComplete(aIsRoot);
    134 }
    135 
    136 void CompositorManagerParent::BindComplete(bool aIsRoot) {
    137  MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread() ||
    138             NS_IsMainThread());
    139 
    140  StaticMonitorAutoLock lock(sMonitor);
    141  if (aIsRoot) {
    142    MOZ_ASSERT(!sInstance);
    143    sInstance = this;
    144  }
    145 
    146  MOZ_RELEASE_ASSERT(sManagers.try_emplace(mNamespace, this).second);
    147 }
    148 
    149 void CompositorManagerParent::ActorDestroy(ActorDestroyReason aReason) {
    150  GetCurrentSerialEventTarget()->Dispatch(
    151      NewRunnableMethod("layers::CompositorManagerParent::DeferredDestroy",
    152                        this, &CompositorManagerParent::DeferredDestroy));
    153 
    154  if (mRemoteTextureTxnScheduler) {
    155    mRemoteTextureTxnScheduler = nullptr;
    156  }
    157 
    158  StaticMonitorAutoLock lock(sMonitor);
    159  if (sInstance == this) {
    160    sInstance = nullptr;
    161  }
    162 
    163  MOZ_RELEASE_ASSERT(sManagers.erase(mNamespace) > 0);
    164  sMonitor.NotifyAll();
    165 }
    166 
    167 void CompositorManagerParent::DeferredDestroy() {
    168  mCompositorThreadHolder = nullptr;
    169 }
    170 
    171 /* static */
    172 void CompositorManagerParent::ShutdownInternal() {
    173  nsTArray<RefPtr<CompositorManagerParent>> actors;
    174 
    175  // We move here because we may attempt to acquire the same lock during the
    176  // destroy to remove the reference in sManagers.
    177  {
    178    StaticMonitorAutoLock lock(sMonitor);
    179    actors.SetCapacity(sManagers.size());
    180    for (auto& i : sManagers) {
    181      actors.AppendElement(i.second);
    182    }
    183  }
    184 
    185  for (auto& actor : actors) {
    186    actor->Close();
    187  }
    188 }
    189 
    190 /* static */
    191 void CompositorManagerParent::Shutdown() {
    192  MOZ_ASSERT(NS_IsMainThread());
    193 
    194  CompositorThread()->Dispatch(NS_NewRunnableFunction(
    195      "layers::CompositorManagerParent::Shutdown",
    196      []() -> void { CompositorManagerParent::ShutdownInternal(); }));
    197 }
    198 
    199 /* static */ void CompositorManagerParent::WaitForSharedSurface(
    200    const wr::ExternalImageId& aId) {
    201  uint32_t extNamespace = static_cast<uint32_t>(wr::AsUint64(aId) >> 32);
    202  uint32_t resourceId = static_cast<uint32_t>(wr::AsUint64(aId));
    203 
    204  StaticMonitorAutoLock lock(sMonitor);
    205 
    206  while (true) {
    207    const auto i = sManagers.find(extNamespace);
    208    if (NS_WARN_IF(i == sManagers.end())) {
    209      break;
    210    }
    211 
    212    // We know that when the resource ID is allocated, we either fail to have
    213    // shared the surface with the compositor process, and so we don't use the
    214    // external image ID, or we have queued an IPDL message over the
    215    // corresponding CompositorManagerParent object to map that surface into
    216    // memory. They are dispatched in order, so we can safely wait until either
    217    // the actor is closed, or the last seen resource ID reaches the target.
    218    if (i->second->mLastSharedSurfaceResourceId >= resourceId) {
    219      break;
    220    }
    221 
    222    lock.Wait();
    223  }
    224 }
    225 
    226 already_AddRefed<PCompositorBridgeParent>
    227 CompositorManagerParent::AllocPCompositorBridgeParent(
    228    const CompositorBridgeOptions& aOpt) {
    229  switch (aOpt.type()) {
    230    case CompositorBridgeOptions::TContentCompositorOptions: {
    231      RefPtr<ContentCompositorBridgeParent> bridge =
    232          new ContentCompositorBridgeParent(this);
    233      return bridge.forget();
    234    }
    235    case CompositorBridgeOptions::TWidgetCompositorOptions: {
    236      // Only the UI process is allowed to create widget compositors in the
    237      // compositor process.
    238      gfx::GPUParent* gpu = gfx::GPUParent::GetSingleton();
    239      if (NS_WARN_IF(!gpu || OtherPid() != gpu->OtherPid())) {
    240        MOZ_ASSERT_UNREACHABLE("Child cannot create widget compositor!");
    241        break;
    242      }
    243 
    244      const WidgetCompositorOptions& opt = aOpt.get_WidgetCompositorOptions();
    245      RefPtr<CompositorBridgeParent> bridge = new CompositorBridgeParent(
    246          this, opt.scale(), opt.vsyncRate(), opt.options(),
    247          opt.useExternalSurfaceSize(), opt.surfaceSize(), opt.innerWindowId());
    248      return bridge.forget();
    249    }
    250    case CompositorBridgeOptions::TSameProcessWidgetCompositorOptions: {
    251      // If the GPU and UI process are combined, we actually already created the
    252      // CompositorBridgeParent, so we need to reuse that to inject it into the
    253      // IPDL framework.
    254      if (NS_WARN_IF(OtherPid() != base::GetCurrentProcId())) {
    255        MOZ_ASSERT_UNREACHABLE("Child cannot create same process compositor!");
    256        break;
    257      }
    258 
    259      // Note that the static mutex not only is used to protect sInstance, but
    260      // also mPendingCompositorBridges.
    261      StaticMonitorAutoLock lock(sMonitor);
    262      if (mPendingCompositorBridges.IsEmpty()) {
    263        break;
    264      }
    265 
    266      RefPtr<CompositorBridgeParent> bridge = mPendingCompositorBridges[0];
    267      mPendingCompositorBridges.RemoveElementAt(0);
    268      return bridge.forget();
    269    }
    270    default:
    271      break;
    272  }
    273 
    274  return nullptr;
    275 }
    276 
    277 /* static */ void CompositorManagerParent::AddSharedSurface(
    278    const wr::ExternalImageId& aId, gfx::SourceSurfaceSharedData* aSurface) {
    279  MOZ_ASSERT(XRE_IsParentProcess());
    280 
    281  StaticMonitorAutoLock lock(sMonitor);
    282  if (NS_WARN_IF(!sInstance)) {
    283    return;
    284  }
    285 
    286  if (NS_WARN_IF(!sInstance->OwnsExternalImageId(aId))) {
    287    MOZ_ASSERT_UNREACHABLE("Wrong namespace?");
    288    return;
    289  }
    290 
    291  SharedSurfacesParent::AddSameProcess(aId, aSurface);
    292 
    293  uint32_t resourceId = static_cast<uint32_t>(wr::AsUint64(aId));
    294  MOZ_RELEASE_ASSERT(sInstance->mLastSharedSurfaceResourceId < resourceId);
    295  sInstance->mLastSharedSurfaceResourceId = resourceId;
    296  sMonitor.NotifyAll();
    297 }
    298 
    299 mozilla::ipc::IPCResult CompositorManagerParent::RecvAddSharedSurface(
    300    const wr::ExternalImageId& aId, SurfaceDescriptorShared&& aDesc) {
    301  if (NS_WARN_IF(!OwnsExternalImageId(aId))) {
    302    MOZ_ASSERT_UNREACHABLE("Wrong namespace?");
    303    return IPC_OK();
    304  }
    305 
    306  SharedSurfacesParent::Add(aId, std::move(aDesc), OtherPid());
    307 
    308  StaticMonitorAutoLock lock(sMonitor);
    309  uint32_t resourceId = static_cast<uint32_t>(wr::AsUint64(aId));
    310  MOZ_RELEASE_ASSERT(mLastSharedSurfaceResourceId < resourceId);
    311  mLastSharedSurfaceResourceId = resourceId;
    312  sMonitor.NotifyAll();
    313  return IPC_OK();
    314 }
    315 
    316 mozilla::ipc::IPCResult CompositorManagerParent::RecvRemoveSharedSurface(
    317    const wr::ExternalImageId& aId) {
    318  if (NS_WARN_IF(!OwnsExternalImageId(aId))) {
    319    MOZ_ASSERT_UNREACHABLE("Wrong namespace?");
    320    return IPC_OK();
    321  }
    322 
    323  SharedSurfacesParent::Remove(aId);
    324  return IPC_OK();
    325 }
    326 
    327 mozilla::ipc::IPCResult CompositorManagerParent::RecvReportSharedSurfacesMemory(
    328    ReportSharedSurfacesMemoryResolver&& aResolver) {
    329  SharedSurfacesMemoryReport report;
    330  SharedSurfacesParent::AccumulateMemoryReport(mNamespace, report);
    331  aResolver(std::move(report));
    332  return IPC_OK();
    333 }
    334 
    335 mozilla::ipc::IPCResult CompositorManagerParent::RecvNotifyMemoryPressure() {
    336  nsTArray<PCompositorBridgeParent*> compositorBridges;
    337  ManagedPCompositorBridgeParent(compositorBridges);
    338  for (auto bridge : compositorBridges) {
    339    static_cast<CompositorBridgeParentBase*>(bridge)->NotifyMemoryPressure();
    340  }
    341  return IPC_OK();
    342 }
    343 
    344 mozilla::ipc::IPCResult CompositorManagerParent::RecvReportMemory(
    345    ReportMemoryResolver&& aResolver) {
    346  MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
    347  MemoryReport aggregate;
    348  PodZero(&aggregate);
    349 
    350  // Accumulate RenderBackend usage.
    351  nsTArray<PCompositorBridgeParent*> compositorBridges;
    352  ManagedPCompositorBridgeParent(compositorBridges);
    353  for (auto bridge : compositorBridges) {
    354    static_cast<CompositorBridgeParentBase*>(bridge)->AccumulateMemoryReport(
    355        &aggregate);
    356  }
    357 
    358  // Accumulate Renderer usage asynchronously, and resolve.
    359  //
    360  // Note that the IPDL machinery requires aResolver to be called on this
    361  // thread, so we can't just pass it over to the renderer thread. We use
    362  // an intermediate MozPromise instead.
    363  wr::RenderThread::AccumulateMemoryReport(aggregate)->Then(
    364      CompositorThread(), __func__,
    365      [resolver = std::move(aResolver)](MemoryReport aReport) {
    366        resolver(aReport);
    367      },
    368      [](bool) {
    369        MOZ_ASSERT_UNREACHABLE("MemoryReport promises are never rejected");
    370      });
    371 
    372  return IPC_OK();
    373 }
    374 
    375 mozilla::ipc::IPCResult CompositorManagerParent::RecvInitCanvasManager(
    376    Endpoint<PCanvasManagerParent>&& aEndpoint) {
    377  gfx::CanvasManagerParent::Init(std::move(aEndpoint), mSharedSurfacesHolder,
    378                                 mContentId);
    379  mRemoteTextureTxnScheduler = RemoteTextureTxnScheduler::Create(this);
    380  return IPC_OK();
    381 }
    382 
    383 /* static */
    384 void CompositorManagerParent::NotifyWebRenderError(wr::WebRenderError aError) {
    385  MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
    386 
    387  StaticMonitorAutoLock lock(sMonitor);
    388  if (NS_WARN_IF(!sInstance)) {
    389    return;
    390  }
    391  (void)sInstance->SendNotifyWebRenderError(aError);
    392 }
    393 
    394 }  // namespace layers
    395 }  // namespace mozilla