tor-browser

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

WebRenderLayerManager.cpp (30087B)


      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 "WebRenderLayerManager.h"
      8 
      9 #include "DisplayItemCache.h"
     10 #include "GeckoProfiler.h"
     11 #include "mozilla/StaticPrefs_apz.h"
     12 #include "mozilla/StaticPrefs_layers.h"
     13 #include "mozilla/dom/BrowserChild.h"
     14 #include "mozilla/gfx/DrawEventRecorder.h"
     15 #include "mozilla/layers/APZTestData.h"
     16 #include "mozilla/layers/CompositorBridgeChild.h"
     17 #include "mozilla/layers/StackingContextHelper.h"
     18 #include "mozilla/layers/TextureClient.h"
     19 #include "mozilla/layers/TransactionIdAllocator.h"
     20 #include "mozilla/layers/WebRenderBridgeChild.h"
     21 #include "mozilla/PerfStats.h"
     22 #include "nsDisplayList.h"
     23 #include "nsLayoutUtils.h"
     24 #include "WebRenderCanvasRenderer.h"
     25 #include "LayerUserData.h"
     26 
     27 #ifdef XP_WIN
     28 #  include "gfxDWriteFonts.h"
     29 #  include "mozilla/WindowsProcessMitigations.h"
     30 #endif
     31 
     32 namespace mozilla {
     33 
     34 namespace gfx {
     35 wr::PipelineId GetTemporaryWebRenderPipelineId(wr::PipelineId aMainPipeline);
     36 }
     37 
     38 using namespace gfx;
     39 
     40 namespace layers {
     41 
     42 WebRenderLayerManager::WebRenderLayerManager(nsIWidget* aWidget)
     43    : mWidget(aWidget),
     44      mLatestTransactionId{0},
     45      mNeedsComposite(false),
     46      mIsFirstPaint(false),
     47      mDestroyed(false),
     48      mTarget(nullptr),
     49      mPaintSequenceNumber(0),
     50      mApzTestData(new APZTestData),
     51      mWebRenderCommandBuilder(this) {
     52  MOZ_COUNT_CTOR(WebRenderLayerManager);
     53  mStateManager.mLayerManager = this;
     54 
     55  if (XRE_IsContentProcess() &&
     56      StaticPrefs::gfx_webrender_enable_item_cache_AtStartup()) {
     57    static const size_t kInitialCacheSize = 1024;
     58    static const size_t kMaximumCacheSize = 10240;
     59 
     60    mDisplayItemCache.SetCapacity(kInitialCacheSize, kMaximumCacheSize);
     61  }
     62 }
     63 
     64 KnowsCompositor* WebRenderLayerManager::AsKnowsCompositor() { return mWrChild; }
     65 
     66 bool WebRenderLayerManager::Initialize(
     67    PCompositorBridgeChild* aCBChild, wr::PipelineId aLayersId,
     68    TextureFactoryIdentifier* aTextureFactoryIdentifier, nsCString& aError) {
     69  MOZ_ASSERT(mWrChild == nullptr);
     70  MOZ_ASSERT(aTextureFactoryIdentifier);
     71 
     72  // When we fail to initialize WebRender, it is useful to know if it has ever
     73  // succeeded, or if this is the first attempt.
     74  static bool hasInitialized = false;
     75 
     76  WindowKind windowKind;
     77  if (mWidget->GetWindowType() != widget::WindowType::Popup) {
     78    windowKind = WindowKind::MAIN;
     79  } else {
     80    windowKind = WindowKind::SECONDARY;
     81  }
     82 
     83  LayoutDeviceIntSize size = mWidget->GetClientSize();
     84  // Check widget size
     85  if (!wr::WindowSizeSanityCheck(size.width, size.height)) {
     86    gfxCriticalNoteOnce << "Widget size is not valid " << size
     87                        << " isParent: " << XRE_IsParentProcess();
     88  }
     89 
     90  PWebRenderBridgeChild* bridge =
     91      aCBChild->SendPWebRenderBridgeConstructor(aLayersId, size, windowKind);
     92  if (!bridge) {
     93    // This should only fail if we attempt to access a layer we don't have
     94    // permission for, or more likely, the GPU process crashed again during
     95    // reinitialization. We can expect to be notified again to reinitialize
     96    // (which may or may not be using WebRender).
     97    gfxCriticalNote << "Failed to create WebRenderBridgeChild.";
     98    aError.Assign(hasInitialized
     99                      ? "FEATURE_FAILURE_WEBRENDER_INITIALIZE_IPDL_POST"_ns
    100                      : "FEATURE_FAILURE_WEBRENDER_INITIALIZE_IPDL_FIRST"_ns);
    101    return false;
    102  }
    103 
    104  mWrChild = static_cast<WebRenderBridgeChild*>(bridge);
    105  mHasFlushedThisChild = false;
    106 
    107  TextureFactoryIdentifier textureFactoryIdentifier;
    108  wr::MaybeIdNamespace idNamespace;
    109  // Sync ipc
    110  if (!WrBridge()->SendEnsureConnected(&textureFactoryIdentifier, &idNamespace,
    111                                       &aError)) {
    112    gfxCriticalNote << "Failed as lost WebRenderBridgeChild.";
    113    aError.Assign(hasInitialized
    114                      ? "FEATURE_FAILURE_WEBRENDER_INITIALIZE_SYNC_POST"_ns
    115                      : "FEATURE_FAILURE_WEBRENDER_INITIALIZE_SYNC_FIRST"_ns);
    116    return false;
    117  }
    118 
    119  if (textureFactoryIdentifier.mParentBackend == LayersBackend::LAYERS_NONE ||
    120      idNamespace.isNothing()) {
    121    gfxCriticalNote << "Failed to connect WebRenderBridgeChild. isParent="
    122                    << XRE_IsParentProcess();
    123    aError.Append(hasInitialized ? "_POST"_ns : "_FIRST"_ns);
    124    return false;
    125  }
    126 
    127  WrBridge()->SetWebRenderLayerManager(this);
    128  WrBridge()->IdentifyTextureHost(textureFactoryIdentifier);
    129  WrBridge()->SetNamespace(idNamespace.ref());
    130  *aTextureFactoryIdentifier = textureFactoryIdentifier;
    131 
    132  mDLBuilder = MakeUnique<wr::DisplayListBuilder>(
    133      WrBridge()->GetPipeline(), WrBridge()->GetWebRenderBackend());
    134 
    135  hasInitialized = true;
    136  return true;
    137 }
    138 
    139 void WebRenderLayerManager::Destroy() { DoDestroy(/* aIsSync */ false); }
    140 
    141 void WebRenderLayerManager::DoDestroy(bool aIsSync) {
    142  MOZ_ASSERT(NS_IsMainThread());
    143 
    144  if (IsDestroyed()) {
    145    return;
    146  }
    147 
    148  mDLBuilder = nullptr;
    149  mUserData.Destroy();
    150  mPartialPrerenderedAnimations.Clear();
    151 
    152  mStateManager.Destroy();
    153 
    154  if (WrBridge()) {
    155    WrBridge()->Destroy(aIsSync);
    156  }
    157 
    158  mWebRenderCommandBuilder.Destroy();
    159 
    160  if (mTransactionIdAllocator) {
    161    // Make sure to notify the refresh driver just in case it's waiting on a
    162    // pending transaction. Do this at the top of the event loop so we don't
    163    // cause a paint to occur during compositor shutdown.
    164    RefPtr<TransactionIdAllocator> allocator = mTransactionIdAllocator;
    165    TransactionId id = mLatestTransactionId;
    166 
    167    RefPtr<Runnable> task = NS_NewRunnableFunction(
    168        "TransactionIdAllocator::NotifyTransactionCompleted",
    169        [allocator, id]() -> void {
    170          allocator->ClearPendingTransactions();
    171          allocator->NotifyTransactionCompleted(id);
    172        });
    173    NS_DispatchToMainThread(task.forget());
    174  }
    175 
    176  // Forget the widget pointer in case we outlive our owning widget.
    177  mWidget = nullptr;
    178  mDestroyed = true;
    179 }
    180 
    181 WebRenderLayerManager::~WebRenderLayerManager() {
    182  Destroy();
    183  MOZ_COUNT_DTOR(WebRenderLayerManager);
    184 }
    185 
    186 CompositorBridgeChild* WebRenderLayerManager::GetCompositorBridgeChild() {
    187  return WrBridge()->GetCompositorBridgeChild();
    188 }
    189 
    190 void WebRenderLayerManager::GetBackendName(nsAString& name) {
    191  if (WrBridge()->UsingSoftwareWebRenderD3D11()) {
    192    name.AssignLiteral("WebRender (Software D3D11)");
    193  } else if (WrBridge()->UsingSoftwareWebRenderOpenGL()) {
    194    name.AssignLiteral("WebRender (Software OpenGL)");
    195  } else if (WrBridge()->UsingSoftwareWebRender()) {
    196    name.AssignLiteral("WebRender (Software)");
    197  } else if (WrBridge()->GetUseLayerCompositor()) {
    198    name.AssignLiteral("WebRender Layer Compositor");
    199  } else {
    200    name.AssignLiteral("WebRender");
    201  }
    202 }
    203 
    204 uint32_t WebRenderLayerManager::StartFrameTimeRecording(int32_t aBufferSize) {
    205  CompositorBridgeChild* renderer = GetCompositorBridgeChild();
    206  if (renderer) {
    207    uint32_t startIndex;
    208    renderer->SendStartFrameTimeRecording(aBufferSize, &startIndex);
    209    return startIndex;
    210  }
    211  return -1;
    212 }
    213 
    214 void WebRenderLayerManager::StopFrameTimeRecording(
    215    uint32_t aStartIndex, nsTArray<float>& aFrameIntervals) {
    216  CompositorBridgeChild* renderer = GetCompositorBridgeChild();
    217  if (renderer) {
    218    renderer->SendStopFrameTimeRecording(aStartIndex, &aFrameIntervals);
    219  }
    220 }
    221 
    222 void WebRenderLayerManager::TakeCompositionPayloads(
    223    nsTArray<CompositionPayload>& aPayloads) {
    224  aPayloads.Clear();
    225 
    226  std::swap(mPayload, aPayloads);
    227 }
    228 
    229 bool WebRenderLayerManager::BeginTransactionWithTarget(gfxContext* aTarget,
    230                                                       const nsCString& aURL) {
    231  mTarget = aTarget;
    232  bool retval = BeginTransaction(aURL);
    233  if (!retval) {
    234    mTarget = nullptr;
    235  }
    236  return retval;
    237 }
    238 
    239 bool WebRenderLayerManager::BeginTransaction(const nsCString& aURL) {
    240  if (!WrBridge()->IPCOpen()) {
    241    gfxCriticalNote << "IPC Channel is already torn down unexpectedly\n";
    242    return false;
    243  }
    244 
    245  mTransactionStart = TimeStamp::Now();
    246  mURL = aURL;
    247 
    248  // Increment the paint sequence number even if test logging isn't
    249  // enabled in this process; it may be enabled in the parent process,
    250  // and the parent process expects unique sequence numbers.
    251  ++mPaintSequenceNumber;
    252  if (StaticPrefs::apz_test_logging_enabled()) {
    253    mApzTestData->StartNewPaint(mPaintSequenceNumber);
    254  }
    255  return true;
    256 }
    257 
    258 bool WebRenderLayerManager::EndEmptyTransaction(EndTransactionFlags aFlags) {
    259  auto clearTarget = MakeScopeExit([&] { mTarget = nullptr; });
    260 
    261  // If we haven't sent a display list (since creation or since the last time we
    262  // sent ClearDisplayList to the parent) then we can't do an empty transaction
    263  // because the parent doesn't have a display list for us and we need to send a
    264  // display list first.
    265  if (!WrBridge()->GetSentDisplayList()) {
    266    return false;
    267  }
    268 
    269  mDisplayItemCache.SkipWaitingForPartialDisplayList();
    270 
    271  // Don't block on hidden windows on Linux as it may block all rendering.
    272  const bool throttle = mWidget->IsMapped();
    273  mLatestTransactionId = mTransactionIdAllocator->GetTransactionId(throttle);
    274 
    275  if (aFlags & EndTransactionFlags::END_NO_COMPOSITE &&
    276      !mWebRenderCommandBuilder.NeedsEmptyTransaction()) {
    277    if (mPendingScrollUpdates.IsEmpty()) {
    278      MOZ_ASSERT(!mTarget);
    279      WrBridge()->SendSetFocusTarget(mFocusTarget);
    280      // Revoke TransactionId to trigger next paint.
    281      mTransactionIdAllocator->RevokeTransactionId(mLatestTransactionId);
    282      mLatestTransactionId = mLatestTransactionId.Prev();
    283      return true;
    284    }
    285  }
    286 
    287  LayoutDeviceIntSize size = mWidget->GetClientSize();
    288  WrBridge()->BeginTransaction();
    289 
    290  mWebRenderCommandBuilder.EmptyTransaction();
    291 
    292  // Get the time of when the refresh driver start its tick (if available),
    293  // otherwise use the time of when LayerManager::BeginTransaction was called.
    294  TimeStamp refreshStart = mTransactionIdAllocator->GetTransactionStart();
    295  if (!refreshStart) {
    296    refreshStart = mTransactionStart;
    297  }
    298 
    299  // Skip the synchronization for buffer since we also skip the painting during
    300  // device-reset status.
    301  if (!gfxPlatform::GetPlatform()->DidRenderingDeviceReset()) {
    302    if (WrBridge()->GetSyncObject() &&
    303        WrBridge()->GetSyncObject()->IsSyncObjectValid()) {
    304      WrBridge()->GetSyncObject()->Synchronize();
    305    }
    306  }
    307 
    308  GetCompositorBridgeChild()->EndCanvasTransaction();
    309 
    310  Maybe<TransactionData> transactionData;
    311  if (mStateManager.mAsyncResourceUpdates || !mPendingScrollUpdates.IsEmpty() ||
    312      WrBridge()->HasWebRenderParentCommands()) {
    313    transactionData.emplace();
    314    transactionData->mIdNamespace = WrBridge()->GetNamespace();
    315    transactionData->mPaintSequenceNumber = mPaintSequenceNumber;
    316    if (mStateManager.mAsyncResourceUpdates) {
    317      mStateManager.mAsyncResourceUpdates->Flush(
    318          transactionData->mResourceUpdates, transactionData->mSmallShmems,
    319          transactionData->mLargeShmems);
    320    }
    321    transactionData->mScrollUpdates = std::move(mPendingScrollUpdates);
    322    for (const auto& scrollId : transactionData->mScrollUpdates.Keys()) {
    323      nsLayoutUtils::NotifyPaintSkipTransaction(/*scroll id=*/scrollId);
    324    }
    325  }
    326 
    327  Maybe<wr::IpcResourceUpdateQueue> nothing;
    328  WrBridge()->EndEmptyTransaction(mFocusTarget, std::move(transactionData),
    329                                  mLatestTransactionId,
    330                                  mTransactionIdAllocator->GetVsyncId(),
    331                                  mTransactionIdAllocator->GetVsyncStart(),
    332                                  refreshStart, mTransactionStart, mURL);
    333  mTransactionStart = TimeStamp();
    334 
    335  MakeSnapshotIfRequired(size);
    336  return true;
    337 }
    338 
    339 void WebRenderLayerManager::EndTransactionWithoutLayer(
    340    nsDisplayList* aDisplayList, nsDisplayListBuilder* aDisplayListBuilder,
    341    WrFiltersHolder&& aFilters, WebRenderBackgroundData* aBackground,
    342    const double aGeckoDLBuildTime, bool aRenderOffscreen) {
    343  AUTO_PROFILER_MARKER("WrDisplayList", GRAPHICS);
    344 
    345  auto clearTarget = MakeScopeExit([&] { mTarget = nullptr; });
    346 
    347  WrBridge()->BeginTransaction();
    348 
    349  LayoutDeviceIntSize size = mWidget->GetClientSize();
    350 
    351  UniquePtr<wr::DisplayListBuilder> offscreenBuilder;
    352  wr::DisplayListBuilder* diplayListBuilder = mDLBuilder.get();
    353  DisplayItemCache* itemCache = &mDisplayItemCache;
    354  if (aRenderOffscreen) {
    355    wr::PipelineId mainId = WrBridge()->GetPipeline();
    356    wr::PipelineId tmpPipeline = gfx::GetTemporaryWebRenderPipelineId(mainId);
    357    offscreenBuilder = MakeUnique<wr::DisplayListBuilder>(
    358        tmpPipeline, WrBridge()->GetWebRenderBackend());
    359    diplayListBuilder = offscreenBuilder.get();
    360    itemCache = nullptr;
    361  }
    362 
    363  diplayListBuilder->Begin(itemCache);
    364 
    365  wr::IpcResourceUpdateQueue resourceUpdates(WrBridge());
    366  wr::usize builderDumpIndex = 0;
    367  bool containsSVGGroup = false;
    368  bool dumpEnabled =
    369      mWebRenderCommandBuilder.ShouldDumpDisplayList(aDisplayListBuilder);
    370  Maybe<AutoDisplayItemCacheSuppressor> cacheSuppressor;
    371  if (dumpEnabled) {
    372    cacheSuppressor.emplace(itemCache);
    373    printf_stderr("-- WebRender display list build --\n");
    374  }
    375 
    376  if (XRE_IsContentProcess() &&
    377      StaticPrefs::gfx_webrender_debug_dl_dump_content_serialized()) {
    378    diplayListBuilder->DumpSerializedDisplayList();
    379  }
    380 
    381  if (aDisplayList) {
    382    MOZ_ASSERT(aDisplayListBuilder && !aBackground);
    383    if (itemCache) {
    384      itemCache->SetDisplayList(aDisplayListBuilder, aDisplayList);
    385    }
    386 
    387    mWebRenderCommandBuilder.BuildWebRenderCommands(
    388        *diplayListBuilder, resourceUpdates, aDisplayList, aDisplayListBuilder,
    389        mScrollData, std::move(aFilters));
    390 
    391    aDisplayListBuilder->NotifyAndClearScrollContainerFrames();
    392 
    393    builderDumpIndex = mWebRenderCommandBuilder.GetBuilderDumpIndex();
    394    containsSVGGroup = mWebRenderCommandBuilder.GetContainsSVGGroup();
    395  } else {
    396    // ViewToPaint does not have frame yet, then render only background clolor.
    397    MOZ_ASSERT(!aDisplayListBuilder && aBackground);
    398    aBackground->AddWebRenderCommands(*diplayListBuilder);
    399    if (dumpEnabled) {
    400      printf_stderr("(no display list; background only)\n");
    401      builderDumpIndex = diplayListBuilder->Dump(
    402          /*indent*/ 1, Some(builderDumpIndex), Nothing());
    403    }
    404  }
    405 
    406  if (AsyncPanZoomEnabled()) {
    407    if (mIsFirstPaint) {
    408      mScrollData.SetIsFirstPaint(true);
    409      mIsFirstPaint = false;
    410    }
    411    mScrollData.SetPaintSequenceNumber(mPaintSequenceNumber);
    412    if (dumpEnabled) {
    413      std::stringstream str;
    414      str << mScrollData;
    415      print_stderr(str);
    416    }
    417  }
    418 
    419  // Since we're sending a full mScrollData that will include the new scroll
    420  // offsets, and we can throw away the pending scroll updates we had kept for
    421  // an empty transaction.
    422  ClearAndNotifyOfFullTransactionPendingScrollInfoUpdate();
    423 
    424  // Don't block on hidden windows on Linux as it may block all rendering.
    425  const bool throttle = mWidget->IsMapped() && !aRenderOffscreen;
    426  mLatestTransactionId = mTransactionIdAllocator->GetTransactionId(throttle);
    427 
    428  // Get the time of when the refresh driver start its tick (if available),
    429  // otherwise use the time of when LayerManager::BeginTransaction was called.
    430  TimeStamp refreshStart = mTransactionIdAllocator->GetTransactionStart();
    431  if (!refreshStart) {
    432    refreshStart = mTransactionStart;
    433  }
    434 
    435  if (mStateManager.mAsyncResourceUpdates) {
    436    if (resourceUpdates.IsEmpty()) {
    437      resourceUpdates.ReplaceResources(
    438          std::move(mStateManager.mAsyncResourceUpdates.ref()));
    439    } else {
    440      WrBridge()->UpdateResources(mStateManager.mAsyncResourceUpdates.ref());
    441    }
    442    mStateManager.mAsyncResourceUpdates.reset();
    443  }
    444 
    445  if (aRenderOffscreen) {
    446    // Unused images are safe to discard since we know that no display list
    447    // references them. We Want to do this because in some contrived cases
    448    // we can end up generating a lot of offscreen transactions that produce
    449    // a lot of unused images without sending a non-offscreen transaction
    450    // to clean them up.
    451    mStateManager.DiscardUnusedImagesInTransaction(resourceUpdates);
    452  } else {
    453    // Don't discard images and fonts in an offscreen transaction. It won't
    454    // replace the display list in the active scene so the images may still
    455    // be used by the previous (which remains current) display list.
    456    mStateManager.DiscardImagesInTransaction(resourceUpdates);
    457    WrBridge()->RemoveExpiredFontKeys(resourceUpdates);
    458  }
    459 
    460  // Skip the synchronization for buffer since we also skip the painting during
    461  // device-reset status.
    462  if (!gfxPlatform::GetPlatform()->DidRenderingDeviceReset()) {
    463    if (WrBridge()->GetSyncObject() &&
    464        WrBridge()->GetSyncObject()->IsSyncObjectValid()) {
    465      WrBridge()->GetSyncObject()->Synchronize();
    466    }
    467  }
    468 
    469  GetCompositorBridgeChild()->EndCanvasTransaction();
    470 
    471  {
    472    AUTO_PROFILER_MARKER("ForwardDPTransaction", GRAPHICS);
    473    DisplayListData dlData;
    474    diplayListBuilder->End(dlData);
    475    resourceUpdates.Flush(dlData.mResourceUpdates, dlData.mSmallShmems,
    476                          dlData.mLargeShmems);
    477    dlData.mRect =
    478        LayoutDeviceRect(LayoutDevicePoint(), LayoutDeviceSize(size));
    479    dlData.mScrollData.emplace(std::move(mScrollData));
    480    dlData.mDLDesc.gecko_display_list_type =
    481        aDisplayListBuilder && aDisplayListBuilder->PartialBuildFailed()
    482            ? wr::GeckoDisplayListType::Full(aGeckoDLBuildTime)
    483            : wr::GeckoDisplayListType::Partial(aGeckoDLBuildTime);
    484 
    485    // convert from nanoseconds to microseconds
    486    auto duration = TimeDuration::FromMicroseconds(
    487        double(dlData.mDLDesc.builder_finish_time -
    488               dlData.mDLDesc.builder_start_time) /
    489        1000.);
    490    PerfStats::RecordMeasurement(PerfStats::Metric::WrDisplayListBuilding,
    491                                 duration);
    492    bool ret = WrBridge()->EndTransaction(
    493        std::move(dlData), mLatestTransactionId, containsSVGGroup,
    494        mTransactionIdAllocator->GetVsyncId(), aRenderOffscreen,
    495        mTransactionIdAllocator->GetVsyncStart(), refreshStart,
    496        mTransactionStart, mURL);
    497    if (!ret && itemCache) {
    498      // Failed to send display list, reset display item cache state.
    499      itemCache->Clear();
    500    }
    501 
    502    WrBridge()->SendSetFocusTarget(mFocusTarget);
    503    mFocusTarget = FocusTarget();
    504  }
    505 
    506  // Discard animations after calling WrBridge()->EndTransaction().
    507  // It updates mWrEpoch in WebRenderBridgeParent. The updated mWrEpoch is
    508  // necessary for deleting animations at the correct time.
    509  mStateManager.DiscardCompositorAnimations();
    510 
    511  mTransactionStart = TimeStamp();
    512 
    513  MakeSnapshotIfRequired(size);
    514  mNeedsComposite = false;
    515 }
    516 
    517 void WebRenderLayerManager::SetFocusTarget(const FocusTarget& aFocusTarget) {
    518  mFocusTarget = aFocusTarget;
    519 }
    520 
    521 bool WebRenderLayerManager::AsyncPanZoomEnabled() const {
    522  return mWidget->AsyncPanZoomEnabled();
    523 }
    524 
    525 IntRect ToOutsideIntRect(const gfxRect& aRect) {
    526  return IntRect::RoundOut(aRect.X(), aRect.Y(), aRect.Width(), aRect.Height());
    527 }
    528 
    529 void WebRenderLayerManager::MakeSnapshotIfRequired(LayoutDeviceIntSize aSize) {
    530  auto clearTarget = MakeScopeExit([&] { mTarget = nullptr; });
    531 
    532  if (!mTarget || !mTarget->GetDrawTarget() || aSize.IsEmpty()) {
    533    return;
    534  }
    535 
    536  // XXX Add other TextureData supports.
    537  // Only BufferTexture is supported now.
    538 
    539  // TODO: fixup for proper surface format.
    540  // The GLES spec only guarantees that RGBA can be used with glReadPixels,
    541  // so on Android we use RGBA.
    542  SurfaceFormat format =
    543 #ifdef MOZ_WIDGET_ANDROID
    544      SurfaceFormat::R8G8B8A8;
    545 #else
    546      SurfaceFormat::B8G8R8A8;
    547 #endif
    548  RefPtr<TextureClient> texture = TextureClient::CreateForRawBufferAccess(
    549      WrBridge(), format, aSize.ToUnknownSize(), BackendType::SKIA,
    550      TextureFlags::SNAPSHOT);
    551  if (!texture) {
    552    return;
    553  }
    554 
    555  // The other side knows our ContentParentId and WebRenderBridgeChild will
    556  // ignore the one provided here in favour of what WebRenderBridgeParent
    557  // already has.
    558  texture->InitIPDLActor(WrBridge(), dom::ContentParentId());
    559  if (!texture->GetIPDLActor()) {
    560    return;
    561  }
    562 
    563  IntRect bounds = ToOutsideIntRect(mTarget->GetClipExtents());
    564  bool needsYFlip = false;
    565  if (!WrBridge()->SendGetSnapshot(WrapNotNull(texture->GetIPDLActor()),
    566                                   &needsYFlip)) {
    567    return;
    568  }
    569 
    570  TextureClientAutoLock autoLock(texture, OpenMode::OPEN_READ_ONLY);
    571  if (!autoLock.Succeeded()) {
    572    return;
    573  }
    574  RefPtr<DrawTarget> drawTarget = texture->BorrowDrawTarget();
    575  if (!drawTarget || !drawTarget->IsValid()) {
    576    return;
    577  }
    578  RefPtr<SourceSurface> snapshot = drawTarget->Snapshot();
    579  /*
    580    static int count = 0;
    581    char filename[100];
    582    snprintf(filename, 100, "output%d.png", count++);
    583    printf_stderr("Writing to :%s\n", filename);
    584    gfxUtils::WriteAsPNG(snapshot, filename);
    585    */
    586 
    587  Rect dst(bounds.X(), bounds.Y(), bounds.Width(), bounds.Height());
    588  Rect src(0, 0, bounds.Width(), bounds.Height());
    589 
    590  Matrix m;
    591  if (needsYFlip) {
    592    m = Matrix::Scaling(1.0, -1.0).PostTranslate(0.0, aSize.height);
    593  }
    594  SurfacePattern pattern(snapshot, ExtendMode::CLAMP, m);
    595  DrawTarget* dt = mTarget->GetDrawTarget();
    596  MOZ_RELEASE_ASSERT(dt);
    597  dt->FillRect(dst, pattern);
    598 
    599  mTarget = nullptr;
    600 }
    601 
    602 void WebRenderLayerManager::DiscardImages() {
    603  wr::IpcResourceUpdateQueue resources(WrBridge());
    604  mStateManager.DiscardImagesInTransaction(resources);
    605  WrBridge()->UpdateResources(resources);
    606 }
    607 
    608 void WebRenderLayerManager::DiscardLocalImages() {
    609  mStateManager.DiscardLocalImages();
    610 }
    611 
    612 void WebRenderLayerManager::DidComposite(
    613    TransactionId aTransactionId, const mozilla::TimeStamp& aCompositeStart,
    614    const mozilla::TimeStamp& aCompositeEnd) {
    615  if (IsDestroyed()) {
    616    return;
    617  }
    618 
    619  MOZ_ASSERT(mWidget);
    620 
    621  // Notifying the observers may tick the refresh driver which can cause
    622  // a lot of different things to happen that may affect the lifetime of
    623  // this layer manager. So let's make sure this object stays alive until
    624  // the end of the method invocation.
    625  RefPtr<WebRenderLayerManager> selfRef = this;
    626 
    627  // |aTransactionId| will be > 0 if the compositor is acknowledging a shadow
    628  // layers transaction.
    629  if (aTransactionId.IsValid()) {
    630    nsIWidgetListener* listener = mWidget->GetWidgetListener();
    631    if (listener) {
    632      listener->DidCompositeWindow(aTransactionId, aCompositeStart,
    633                                   aCompositeEnd);
    634    }
    635    listener = mWidget->GetAttachedWidgetListener();
    636    if (listener) {
    637      listener->DidCompositeWindow(aTransactionId, aCompositeStart,
    638                                   aCompositeEnd);
    639    }
    640    if (mTransactionIdAllocator) {
    641      mTransactionIdAllocator->NotifyTransactionCompleted(aTransactionId);
    642    }
    643  }
    644 }
    645 
    646 void WebRenderLayerManager::ClearCachedResources() {
    647  if (!WrBridge()->IPCOpen()) {
    648    gfxCriticalNote << "IPC Channel is already torn down unexpectedly\n";
    649    return;
    650  }
    651  WrBridge()->BeginClearCachedResources();
    652  // We flush any pending async resource updates before we clear the display
    653  // list items because some resources (e.g. images) might be shared between
    654  // multiple layer managers, not get freed here, and we want to keep their
    655  // states consistent.
    656  mStateManager.FlushAsyncResourceUpdates();
    657  mWebRenderCommandBuilder.ClearCachedResources();
    658  DiscardImages();
    659  mStateManager.ClearCachedResources();
    660  if (CompositorBridgeChild* compositorBridge = GetCompositorBridgeChild()) {
    661    compositorBridge->ClearCachedResources();
    662  }
    663  WrBridge()->EndClearCachedResources();
    664 }
    665 
    666 void WebRenderLayerManager::WrUpdated() {
    667  ClearAsyncAnimations();
    668  mStateManager.mAsyncResourceUpdates.reset();
    669  mWebRenderCommandBuilder.ClearCachedResources();
    670  DiscardLocalImages();
    671  mDisplayItemCache.Clear();
    672 
    673  if (mWidget) {
    674    if (dom::BrowserChild* browserChild = mWidget->GetOwningBrowserChild()) {
    675      browserChild->SchedulePaint();
    676    }
    677  }
    678 }
    679 
    680 void WebRenderLayerManager::UpdateTextureFactoryIdentifier(
    681    const TextureFactoryIdentifier& aNewIdentifier) {
    682  WrBridge()->IdentifyTextureHost(aNewIdentifier);
    683 }
    684 
    685 TextureFactoryIdentifier WebRenderLayerManager::GetTextureFactoryIdentifier() {
    686  return WrBridge()->GetTextureFactoryIdentifier();
    687 }
    688 
    689 void WebRenderLayerManager::SetTransactionIdAllocator(
    690    TransactionIdAllocator* aAllocator) {
    691  // When changing the refresh driver, the previous refresh driver may never
    692  // receive updates of pending transactions it's waiting for. So clear the
    693  // waiting state before assigning another refresh driver.
    694  if (mTransactionIdAllocator && (aAllocator != mTransactionIdAllocator)) {
    695    mTransactionIdAllocator->ClearPendingTransactions();
    696 
    697    // We should also reset the transaction id of the new allocator to previous
    698    // allocator's last transaction id, so that completed transactions for
    699    // previous allocator will be ignored and won't confuse the new allocator.
    700    if (aAllocator) {
    701      aAllocator->ResetInitialTransactionId(
    702          mTransactionIdAllocator->LastTransactionId());
    703    }
    704  }
    705 
    706  mTransactionIdAllocator = aAllocator;
    707 }
    708 
    709 TransactionId WebRenderLayerManager::GetLastTransactionId() {
    710  return mLatestTransactionId;
    711 }
    712 
    713 void WebRenderLayerManager::FlushRendering(wr::RenderReasons aReasons) {
    714  CompositorBridgeChild* cBridge = GetCompositorBridgeChild();
    715  if (!cBridge) {
    716    return;
    717  }
    718  MOZ_ASSERT(mWidget);
    719 
    720  // If widget bounds size is different from the last flush, consider
    721  // this to be a resize. It's important to use GetClientSize here,
    722  // because that has extra plumbing to support initial display cases
    723  // where the widget doesn't yet have real bounds.
    724  LayoutDeviceIntSize widgetSize = mWidget->GetClientSize();
    725  bool resizing = widgetSize != mFlushWidgetSize;
    726  mFlushWidgetSize = widgetSize;
    727 
    728  if (resizing) {
    729    aReasons = aReasons | wr::RenderReasons::RESIZE;
    730  }
    731 
    732  // Check for the conditions where we we force a sync flush. The first
    733  // flush for this child should always be sync. Resizes should be
    734  // sometimes be sync. Everything else can be async.
    735  if (!mHasFlushedThisChild ||
    736      (resizing && (mWidget->SynchronouslyRepaintOnResize() ||
    737                    StaticPrefs::layers_force_synchronous_resize()))) {
    738    cBridge->SendFlushRendering(aReasons);
    739  } else {
    740    cBridge->SendFlushRenderingAsync(aReasons);
    741  }
    742 
    743  mHasFlushedThisChild = true;
    744 }
    745 
    746 void WebRenderLayerManager::WaitOnTransactionProcessed() {
    747  CompositorBridgeChild* bridge = GetCompositorBridgeChild();
    748  if (bridge) {
    749    bridge->SendWaitOnTransactionProcessed();
    750  }
    751 }
    752 
    753 void WebRenderLayerManager::SendInvalidRegion(const nsIntRegion& aRegion) {
    754  // XXX Webrender does not support invalid region yet.
    755 
    756 #ifndef XP_WIN
    757  if (WrBridge()) {
    758    WrBridge()->SendInvalidateRenderedFrame();
    759  }
    760 #endif
    761 }
    762 
    763 void WebRenderLayerManager::ScheduleComposite(wr::RenderReasons aReasons) {
    764  WrBridge()->SendScheduleComposite(aReasons);
    765 }
    766 
    767 already_AddRefed<PersistentBufferProvider>
    768 WebRenderLayerManager::CreatePersistentBufferProvider(
    769    const gfx::IntSize& aSize, gfx::SurfaceFormat aFormat,
    770    bool aWillReadFrequently) {
    771  // Only initialize devices if hardware acceleration may possibly be used.
    772  // Remoting moves hardware usage out-of-process, while will-read-frequently
    773  // avoids hardware acceleration entirely.
    774  if (!aWillReadFrequently && !gfxPlatform::UseRemoteCanvas()) {
    775 #ifdef XP_WIN
    776    // Any kind of hardware acceleration is incompatible with Win32k Lockdown
    777    // We don't initialize devices here so that PersistentBufferProviderShared
    778    // will fall back to using a piece of shared memory as a backing for the
    779    // canvas
    780    if (!IsWin32kLockedDown()) {
    781      gfxPlatform::GetPlatform()->EnsureDevicesInitialized();
    782    }
    783 #else
    784    gfxPlatform::GetPlatform()->EnsureDevicesInitialized();
    785 #endif
    786  }
    787 
    788  RefPtr<PersistentBufferProvider> provider =
    789      PersistentBufferProviderShared::Create(
    790          aSize, aFormat, AsKnowsCompositor(), aWillReadFrequently);
    791  if (provider) {
    792    return provider.forget();
    793  }
    794 
    795  return WindowRenderer::CreatePersistentBufferProvider(aSize, aFormat);
    796 }
    797 
    798 void WebRenderLayerManager::ClearAsyncAnimations() {
    799  mStateManager.ClearAsyncAnimations();
    800 }
    801 
    802 void WebRenderLayerManager::WrReleasedImages(
    803    const nsTArray<wr::ExternalImageKeyPair>& aPairs) {
    804  mStateManager.WrReleasedImages(aPairs);
    805 }
    806 
    807 void WebRenderLayerManager::GetFrameUniformity(FrameUniformityData* aOutData) {
    808  WrBridge()->SendGetFrameUniformity(aOutData);
    809 }
    810 
    811 /*static*/
    812 void WebRenderLayerManager::LayerUserDataDestroy(void* data) {
    813  delete static_cast<LayerUserData*>(data);
    814 }
    815 
    816 UniquePtr<LayerUserData> WebRenderLayerManager::RemoveUserData(void* aKey) {
    817  UniquePtr<LayerUserData> d(static_cast<LayerUserData*>(
    818      mUserData.Remove(static_cast<gfx::UserDataKey*>(aKey))));
    819  return d;
    820 }
    821 
    822 void WebRenderLayerManager::
    823    ClearAndNotifyOfFullTransactionPendingScrollInfoUpdate() {
    824  for (ScrollableLayerGuid::ViewID update : mPendingScrollUpdates.Keys()) {
    825    nsLayoutUtils::NotifyApzTransaction(update);
    826  }
    827  mPendingScrollUpdates.Clear();
    828 }
    829 
    830 bool WebRenderLayerManager::AddPendingScrollUpdateForNextTransaction(
    831    ScrollableLayerGuid::ViewID aScrollId,
    832    const ScrollPositionUpdate& aUpdateInfo) {
    833  mPendingScrollUpdates.LookupOrInsert(aScrollId).AppendElement(aUpdateInfo);
    834  return true;
    835 }
    836 
    837 // See equivalent function in ClientLayerManager
    838 void WebRenderLayerManager::LogTestDataForCurrentPaint(
    839    ScrollableLayerGuid::ViewID aScrollId, const std::string& aKey,
    840    const std::string& aValue) {
    841  MOZ_ASSERT(StaticPrefs::apz_test_logging_enabled(), "don't call me");
    842  mApzTestData->LogTestDataForPaint(mPaintSequenceNumber, aScrollId, aKey,
    843                                    aValue);
    844 }
    845 void WebRenderLayerManager::LogAdditionalTestData(const std::string& aKey,
    846                                                  const std::string& aValue) {
    847  MOZ_ASSERT(StaticPrefs::apz_test_logging_enabled(), "don't call me");
    848  mApzTestData->RecordAdditionalData(aKey, aValue);
    849 }
    850 
    851 }  // namespace layers
    852 }  // namespace mozilla