tor-browser

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

ContentCompositorBridgeParent.cpp (16393B)


      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/ContentCompositorBridgeParent.h"
      8 
      9 #include <stdint.h>  // for uint64_t
     10 
     11 #include "apz/src/APZCTreeManager.h"  // for APZCTreeManager
     12 #include "gfxUtils.h"
     13 #ifdef XP_WIN
     14 #  include "mozilla/gfx/DeviceManagerDx.h"  // for DeviceManagerDx
     15 #  include "mozilla/layers/ImageDataSerializer.h"
     16 #endif
     17 #include "mozilla/layers/AnimationHelper.h"  // for CompositorAnimationStorage
     18 #include "mozilla/layers/APZCTreeManagerParent.h"  // for APZCTreeManagerParent
     19 #include "mozilla/layers/APZUpdater.h"             // for APZUpdater
     20 #include "mozilla/layers/CompositorManagerParent.h"
     21 #include "mozilla/layers/CompositorOptions.h"
     22 #include "mozilla/layers/CompositorThread.h"
     23 #include "mozilla/layers/LayerTreeOwnerTracker.h"
     24 #include "mozilla/layers/RemoteContentController.h"
     25 #include "mozilla/layers/WebRenderBridgeParent.h"
     26 #include "mozilla/layers/AsyncImagePipelineManager.h"
     27 #include "mozilla/mozalloc.h"  // for operator new, etc
     28 #include "nsDebug.h"           // for NS_ASSERTION, etc
     29 #include "nsTArray.h"          // for nsTArray
     30 #include "nsXULAppAPI.h"       // for XRE_GetAsyncIOEventTarget
     31 #include "mozilla/StaticPrefs_dom.h"
     32 #include "mozilla/StaticPtr.h"
     33 #include "mozilla/BaseProfilerMarkerTypes.h"
     34 #include "GeckoProfiler.h"
     35 
     36 namespace mozilla::layers {
     37 
     38 void EraseLayerState(LayersId aId);
     39 
     40 void ContentCompositorBridgeParent::ActorDestroy(ActorDestroyReason aWhy) {
     41  mCanSend = false;
     42 
     43  // We must keep this object alive untill the code handling message
     44  // reception is finished on this thread.
     45  GetCurrentSerialEventTarget()->Dispatch(NewRunnableMethod(
     46      "layers::ContentCompositorBridgeParent::DeferredDestroy", this,
     47      &ContentCompositorBridgeParent::DeferredDestroy));
     48 }
     49 
     50 PAPZCTreeManagerParent*
     51 ContentCompositorBridgeParent::AllocPAPZCTreeManagerParent(
     52    const LayersId& aLayersId) {
     53  // Check to see if this child process has access to this layer tree.
     54  if (!LayerTreeOwnerTracker::Get()->IsMapped(aLayersId, OtherPid())) {
     55    NS_ERROR(
     56        "Unexpected layers id in AllocPAPZCTreeManagerParent; dropping "
     57        "message...");
     58    return nullptr;
     59  }
     60 
     61  StaticMonitorAutoLock lock(CompositorBridgeParent::sIndirectLayerTreesLock);
     62  CompositorBridgeParent::LayerTreeState& state =
     63      CompositorBridgeParent::sIndirectLayerTrees[aLayersId];
     64 
     65  // If the widget has shutdown its compositor, we may not have had a chance yet
     66  // to unmap our layers id, and we could get here without a parent compositor.
     67  // In this case return an empty APZCTM.
     68  if (!state.mParent) {
     69    // Note: we immediately call ClearTree since otherwise the APZCTM will
     70    // retain a reference to itself, through the checkerboard observer.
     71    LayersId dummyId{0};
     72    const bool connectedToWebRender = false;
     73    RefPtr<APZCTreeManager> temp = APZCTreeManager::Create(dummyId);
     74    RefPtr<APZUpdater> tempUpdater = new APZUpdater(temp, connectedToWebRender);
     75    tempUpdater->ClearTree(dummyId);
     76    return new APZCTreeManagerParent(aLayersId, temp, tempUpdater);
     77  }
     78 
     79  // If we do not have APZ enabled, we should gracefully fail.
     80  if (!state.mParent->GetOptions().UseAPZ()) {
     81    return nullptr;
     82  }
     83 
     84  state.mParent->AllocateAPZCTreeManagerParent(lock, aLayersId, state);
     85  return state.mApzcTreeManagerParent;
     86 }
     87 
     88 bool ContentCompositorBridgeParent::DeallocPAPZCTreeManagerParent(
     89    PAPZCTreeManagerParent* aActor) {
     90  APZCTreeManagerParent* parent = static_cast<APZCTreeManagerParent*>(aActor);
     91 
     92  StaticMonitorAutoLock lock(CompositorBridgeParent::sIndirectLayerTreesLock);
     93  auto iter =
     94      CompositorBridgeParent::sIndirectLayerTrees.find(parent->GetLayersId());
     95  if (iter != CompositorBridgeParent::sIndirectLayerTrees.end()) {
     96    CompositorBridgeParent::LayerTreeState& state = iter->second;
     97    MOZ_ASSERT(state.mApzcTreeManagerParent == parent);
     98    state.mApzcTreeManagerParent = nullptr;
     99  }
    100 
    101  delete parent;
    102 
    103  return true;
    104 }
    105 
    106 PAPZParent* ContentCompositorBridgeParent::AllocPAPZParent(
    107    const LayersId& aLayersId) {
    108  // Check to see if this child process has access to this layer tree.
    109  if (!LayerTreeOwnerTracker::Get()->IsMapped(aLayersId, OtherPid())) {
    110    NS_ERROR("Unexpected layers id in AllocPAPZParent; dropping message...");
    111    return nullptr;
    112  }
    113 
    114  RemoteContentController* controller = new RemoteContentController();
    115 
    116  // Increment the controller's refcount before we return it. This will keep the
    117  // controller alive until it is released by IPDL in DeallocPAPZParent.
    118  controller->AddRef();
    119 
    120  StaticMonitorAutoLock lock(CompositorBridgeParent::sIndirectLayerTreesLock);
    121  CompositorBridgeParent::LayerTreeState& state =
    122      CompositorBridgeParent::sIndirectLayerTrees[aLayersId];
    123  MOZ_ASSERT(!state.mController);
    124  state.mController = controller;
    125 
    126  return controller;
    127 }
    128 
    129 bool ContentCompositorBridgeParent::DeallocPAPZParent(PAPZParent* aActor) {
    130  RemoteContentController* controller =
    131      static_cast<RemoteContentController*>(aActor);
    132  controller->Release();
    133  return true;
    134 }
    135 
    136 PWebRenderBridgeParent*
    137 ContentCompositorBridgeParent::AllocPWebRenderBridgeParent(
    138    const wr::PipelineId& aPipelineId, const LayoutDeviceIntSize& aSize,
    139    const WindowKind& aWindowKind) {
    140  LayersId layersId = wr::AsLayersId(aPipelineId);
    141  // Check to see if this child process has access to this layer tree.
    142  if (!LayerTreeOwnerTracker::Get()->IsMapped(layersId, OtherPid())) {
    143    NS_ERROR(
    144        "Unexpected layers id in AllocPWebRenderBridgeParent; dropping "
    145        "message...");
    146    return nullptr;
    147  }
    148 
    149  RefPtr<CompositorBridgeParent> cbp = nullptr;
    150  RefPtr<WebRenderBridgeParent> root = nullptr;
    151 
    152  {  // scope lock
    153    StaticMonitorAutoLock lock(CompositorBridgeParent::sIndirectLayerTreesLock);
    154    MOZ_ASSERT(CompositorBridgeParent::sIndirectLayerTrees.find(layersId) !=
    155               CompositorBridgeParent::sIndirectLayerTrees.end());
    156    MOZ_ASSERT(
    157        CompositorBridgeParent::sIndirectLayerTrees[layersId].mWrBridge ==
    158        nullptr);
    159    cbp = CompositorBridgeParent::sIndirectLayerTrees[layersId].mParent;
    160    if (cbp) {
    161      root = CompositorBridgeParent::sIndirectLayerTrees[cbp->RootLayerTreeId()]
    162                 .mWrBridge;
    163    }
    164  }
    165 
    166  RefPtr<wr::WebRenderAPI> api;
    167  if (root) {
    168    api = root->GetWebRenderAPI();
    169  }
    170 
    171  if (!root || !api) {
    172    // This could happen when this function is called after
    173    // CompositorBridgeParent destruction. This was observed during Tab move
    174    // between different windows.
    175    NS_WARNING(
    176        nsPrintfCString("Created child without a matching parent? root %p",
    177                        root.get())
    178            .get());
    179    nsCString error("NO_PARENT");
    180    WebRenderBridgeParent* parent =
    181        WebRenderBridgeParent::CreateDestroyed(aPipelineId, std::move(error));
    182    parent->AddRef();  // IPDL reference
    183    return parent;
    184  }
    185 
    186  api = api->Clone();
    187  RefPtr<AsyncImagePipelineManager> holder = root->AsyncImageManager();
    188  WebRenderBridgeParent* parent = new WebRenderBridgeParent(
    189      this, aPipelineId, nullptr, root->CompositorScheduler(), std::move(api),
    190      std::move(holder), cbp->GetVsyncInterval());
    191  parent->AddRef();  // IPDL reference
    192 
    193  {  // scope lock
    194    StaticMonitorAutoLock lock(CompositorBridgeParent::sIndirectLayerTreesLock);
    195    CompositorBridgeParent::sIndirectLayerTrees[layersId]
    196        .mContentCompositorBridgeParent = this;
    197    CompositorBridgeParent::sIndirectLayerTrees[layersId].mWrBridge = parent;
    198  }
    199 
    200  return parent;
    201 }
    202 
    203 bool ContentCompositorBridgeParent::DeallocPWebRenderBridgeParent(
    204    PWebRenderBridgeParent* aActor) {
    205  WebRenderBridgeParent* parent = static_cast<WebRenderBridgeParent*>(aActor);
    206  EraseLayerState(wr::AsLayersId(parent->PipelineId()));
    207  parent->Release();  // IPDL reference
    208  return true;
    209 }
    210 
    211 mozilla::ipc::IPCResult ContentCompositorBridgeParent::RecvNotifyChildCreated(
    212    const LayersId& child, CompositorOptions* aOptions) {
    213  StaticMonitorAutoLock lock(CompositorBridgeParent::sIndirectLayerTreesLock);
    214  for (auto it = CompositorBridgeParent::sIndirectLayerTrees.begin();
    215       it != CompositorBridgeParent::sIndirectLayerTrees.end(); it++) {
    216    CompositorBridgeParent::LayerTreeState& lts = it->second;
    217    if (lts.mParent && lts.mContentCompositorBridgeParent == this) {
    218      lts.mParent->NotifyChildCreated(child);
    219      *aOptions = lts.mParent->GetOptions();
    220      return IPC_OK();
    221    }
    222  }
    223  return IPC_FAIL_NO_REASON(this);
    224 }
    225 
    226 mozilla::ipc::IPCResult
    227 ContentCompositorBridgeParent::RecvMapAndNotifyChildCreated(
    228    const LayersId& child, const base::ProcessId& pid,
    229    CompositorOptions* aOptions) {
    230  // This can only be called from the browser process, as the mapping
    231  // ensures proper window ownership of layer trees.
    232  return IPC_FAIL_NO_REASON(this);
    233 }
    234 
    235 mozilla::ipc::IPCResult
    236 ContentCompositorBridgeParent::RecvNotifyMemoryPressure() {
    237  // This can only be called from the browser process.
    238  return IPC_FAIL_NO_REASON(this);
    239 }
    240 
    241 mozilla::ipc::IPCResult ContentCompositorBridgeParent::RecvCheckContentOnlyTDR(
    242    const uint32_t& sequenceNum, bool* isContentOnlyTDR) {
    243  *isContentOnlyTDR = false;
    244 #ifdef XP_WIN
    245  gfx::ContentDeviceData compositor;
    246 
    247  gfx::DeviceManagerDx* dm = gfx::DeviceManagerDx::Get();
    248 
    249  // Check that the D3D11 device sequence numbers match.
    250  gfx::D3D11DeviceStatus status;
    251  dm->ExportDeviceInfo(&status);
    252 
    253  if (sequenceNum == static_cast<uint32_t>(status.sequenceNumber()) &&
    254      !dm->HasDeviceReset()) {
    255    *isContentOnlyTDR = true;
    256  }
    257 
    258 #endif
    259  return IPC_OK();
    260 };
    261 
    262 void ContentCompositorBridgeParent::DidCompositeLocked(
    263    LayersId aId, const VsyncId& aVsyncId, TimeStamp& aCompositeStart,
    264    TimeStamp& aCompositeEnd) {
    265  CompositorBridgeParent::sIndirectLayerTreesLock.AssertCurrentThreadOwns();
    266  if (CompositorBridgeParent::sIndirectLayerTrees[aId].mWrBridge) {
    267    MOZ_ASSERT(false);  // this should never get called for a WR compositor
    268  }
    269 }
    270 
    271 bool ContentCompositorBridgeParent::SetTestSampleTime(const LayersId& aId,
    272                                                      const TimeStamp& aTime) {
    273  MOZ_ASSERT(aId.IsValid());
    274  const CompositorBridgeParent::LayerTreeState* state =
    275      CompositorBridgeParent::GetIndirectShadowTree(aId);
    276  if (!state) {
    277    return false;
    278  }
    279 
    280  MOZ_ASSERT(state->mParent);
    281  return state->mParent->SetTestSampleTime(aId, aTime);
    282 }
    283 
    284 void ContentCompositorBridgeParent::LeaveTestMode(const LayersId& aId) {
    285  MOZ_ASSERT(aId.IsValid());
    286  const CompositorBridgeParent::LayerTreeState* state =
    287      CompositorBridgeParent::GetIndirectShadowTree(aId);
    288  if (!state) {
    289    return;
    290  }
    291 
    292  MOZ_ASSERT(state->mParent);
    293  state->mParent->LeaveTestMode(aId);
    294 }
    295 
    296 void ContentCompositorBridgeParent::SetTestAsyncScrollOffset(
    297    const LayersId& aLayersId, const ScrollableLayerGuid::ViewID& aScrollId,
    298    const CSSPoint& aPoint) {
    299  MOZ_ASSERT(aLayersId.IsValid());
    300  const CompositorBridgeParent::LayerTreeState* state =
    301      CompositorBridgeParent::GetIndirectShadowTree(aLayersId);
    302  if (!state) {
    303    return;
    304  }
    305 
    306  MOZ_ASSERT(state->mParent);
    307  state->mParent->SetTestAsyncScrollOffset(aLayersId, aScrollId, aPoint);
    308 }
    309 
    310 void ContentCompositorBridgeParent::SetTestAsyncZoom(
    311    const LayersId& aLayersId, const ScrollableLayerGuid::ViewID& aScrollId,
    312    const LayerToParentLayerScale& aZoom) {
    313  MOZ_ASSERT(aLayersId.IsValid());
    314  const CompositorBridgeParent::LayerTreeState* state =
    315      CompositorBridgeParent::GetIndirectShadowTree(aLayersId);
    316  if (!state) {
    317    return;
    318  }
    319 
    320  MOZ_ASSERT(state->mParent);
    321  state->mParent->SetTestAsyncZoom(aLayersId, aScrollId, aZoom);
    322 }
    323 
    324 void ContentCompositorBridgeParent::FlushApzRepaints(
    325    const LayersId& aLayersId) {
    326  MOZ_ASSERT(aLayersId.IsValid());
    327  const CompositorBridgeParent::LayerTreeState* state =
    328      CompositorBridgeParent::GetIndirectShadowTree(aLayersId);
    329  if (!state || !state->mParent) {
    330    return;
    331  }
    332 
    333  state->mParent->FlushApzRepaints(aLayersId);
    334 }
    335 
    336 void ContentCompositorBridgeParent::GetAPZTestData(const LayersId& aLayersId,
    337                                                   APZTestData* aOutData) {
    338  MOZ_ASSERT(aLayersId.IsValid());
    339  const CompositorBridgeParent::LayerTreeState* state =
    340      CompositorBridgeParent::GetIndirectShadowTree(aLayersId);
    341  if (!state || !state->mParent) {
    342    return;
    343  }
    344 
    345  state->mParent->GetAPZTestData(aLayersId, aOutData);
    346 }
    347 
    348 void ContentCompositorBridgeParent::GetFrameUniformity(
    349    const LayersId& aLayersId, FrameUniformityData* aOutData) {
    350  MOZ_ASSERT(aLayersId.IsValid());
    351  const CompositorBridgeParent::LayerTreeState* state =
    352      CompositorBridgeParent::GetIndirectShadowTree(aLayersId);
    353  if (!state || !state->mParent) {
    354    return;
    355  }
    356 
    357  state->mParent->GetFrameUniformity(aLayersId, aOutData);
    358 }
    359 
    360 void ContentCompositorBridgeParent::SetConfirmedTargetAPZC(
    361    const LayersId& aLayersId, const uint64_t& aInputBlockId,
    362    nsTArray<ScrollableLayerGuid>&& aTargets) {
    363  MOZ_ASSERT(aLayersId.IsValid());
    364  const CompositorBridgeParent::LayerTreeState* state =
    365      CompositorBridgeParent::GetIndirectShadowTree(aLayersId);
    366  if (!state || !state->mParent) {
    367    return;
    368  }
    369 
    370  state->mParent->SetConfirmedTargetAPZC(aLayersId, aInputBlockId,
    371                                         std::move(aTargets));
    372 }
    373 
    374 void ContentCompositorBridgeParent::EndWheelTransaction(
    375    const LayersId& aLayersId,
    376    PWebRenderBridgeParent::EndWheelTransactionResolver&& aResolve) {
    377  MOZ_ASSERT(aLayersId.IsValid());
    378  const CompositorBridgeParent::LayerTreeState* state =
    379      CompositorBridgeParent::GetIndirectShadowTree(aLayersId);
    380  if (!state || !state->mParent) {
    381    return;
    382  }
    383 
    384  state->mParent->EndWheelTransaction(aLayersId, std::move(aResolve));
    385 }
    386 
    387 void ContentCompositorBridgeParent::DeferredDestroy() { mSelfRef = nullptr; }
    388 
    389 ContentCompositorBridgeParent::~ContentCompositorBridgeParent() {
    390  MOZ_ASSERT(XRE_GetAsyncIOEventTarget());
    391 }
    392 
    393 PTextureParent* ContentCompositorBridgeParent::AllocPTextureParent(
    394    const SurfaceDescriptor& aSharedData, ReadLockDescriptor& aReadLock,
    395    const LayersBackend& aLayersBackend, const TextureFlags& aFlags,
    396    const LayersId& aId, const uint64_t& aSerial,
    397    const wr::MaybeExternalImageId& aExternalImageId) {
    398  CompositorBridgeParent::LayerTreeState* state = nullptr;
    399 
    400  StaticMonitorAutoLock lock(CompositorBridgeParent::sIndirectLayerTreesLock);
    401  auto itr = CompositorBridgeParent::sIndirectLayerTrees.find(aId);
    402  if (CompositorBridgeParent::sIndirectLayerTrees.end() != itr) {
    403    state = &itr->second;
    404  }
    405 
    406  TextureFlags flags = aFlags;
    407 
    408  LayersBackend actualBackend = LayersBackend::LAYERS_NONE;
    409  if (!state) {
    410    // The compositor was recreated, and we're receiving layers updates for a
    411    // a layer manager that will soon be discarded or invalidated. We can't
    412    // return null because this will mess up deserialization later and we'll
    413    // kill the content process. Instead, we signal that the underlying
    414    // TextureHost should not attempt to access the compositor.
    415    flags |= TextureFlags::INVALID_COMPOSITOR;
    416  } else if (actualBackend != LayersBackend::LAYERS_NONE &&
    417             aLayersBackend != actualBackend) {
    418    gfxDevCrash(gfx::LogReason::PAllocTextureBackendMismatch)
    419        << "Texture backend is wrong";
    420  }
    421 
    422  return TextureHost::CreateIPDLActor(
    423      this, aSharedData, std::move(aReadLock), aLayersBackend, aFlags,
    424      mCompositorManager->GetContentId(), aSerial, aExternalImageId);
    425 }
    426 
    427 bool ContentCompositorBridgeParent::DeallocPTextureParent(
    428    PTextureParent* actor) {
    429  return TextureHost::DestroyIPDLActor(actor);
    430 }
    431 
    432 bool ContentCompositorBridgeParent::IsSameProcess() const {
    433  return OtherPid() == base::GetCurrentProcId();
    434 }
    435 
    436 void ContentCompositorBridgeParent::ObserveLayersUpdate(LayersId aLayersId,
    437                                                        bool aActive) {
    438  MOZ_ASSERT(aLayersId.IsValid());
    439 
    440  CompositorBridgeParent::LayerTreeState* state =
    441      CompositorBridgeParent::GetIndirectShadowTree(aLayersId);
    442  if (!state || !state->mParent) {
    443    return;
    444  }
    445 
    446  (void)state->mParent->SendObserveLayersUpdate(aLayersId, aActive);
    447 }
    448 
    449 }  // namespace mozilla::layers