tor-browser

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

WebRenderBridgeParent.cpp (102905B)


      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/WebRenderBridgeParent.h"
      8 
      9 #include "mozmemory.h"
     10 #include "CompositableHost.h"
     11 #include "gfxEnv.h"
     12 #include "gfxPlatform.h"
     13 #include "gfxOTSUtils.h"
     14 #include "GeckoProfiler.h"
     15 #include "GLContext.h"
     16 #include "GLContextProvider.h"
     17 #include "GLLibraryLoader.h"
     18 #include "nsExceptionHandler.h"
     19 #include "mozilla/Range.h"
     20 #include "mozilla/EnumeratedRange.h"
     21 #include "mozilla/StaticPrefs_gfx.h"
     22 #include "mozilla/StaticPrefs_webgl.h"
     23 #include "mozilla/UniquePtr.h"
     24 #include "mozilla/gfx/gfxVars.h"
     25 #include "mozilla/gfx/GPUParent.h"
     26 #include "mozilla/glean/GfxMetrics.h"
     27 #include "mozilla/layers/AnimationHelper.h"
     28 #include "mozilla/layers/APZSampler.h"
     29 #include "mozilla/layers/APZUpdater.h"
     30 #include "mozilla/layers/Compositor.h"
     31 #include "mozilla/layers/CompositorBridgeParent.h"
     32 #include "mozilla/layers/CompositorAnimationStorage.h"
     33 #include "mozilla/layers/CompositorThread.h"
     34 #include "mozilla/layers/CompositorVsyncScheduler.h"
     35 #include "mozilla/layers/ImageBridgeParent.h"
     36 #include "mozilla/layers/ImageDataSerializer.h"
     37 #include "mozilla/layers/IpcResourceUpdateQueue.h"
     38 #include "mozilla/layers/OMTASampler.h"
     39 #include "mozilla/layers/RemoteTextureMap.h"
     40 #include "mozilla/layers/SharedSurfacesParent.h"
     41 #include "mozilla/layers/TextureHost.h"
     42 #include "mozilla/layers/AsyncImagePipelineManager.h"
     43 #include "mozilla/layers/UiCompositorControllerParent.h"
     44 #include "mozilla/layers/WebRenderImageHost.h"
     45 #include "mozilla/layers/WebRenderTextureHost.h"
     46 #include "mozilla/ProfilerMarkerTypes.h"
     47 #include "mozilla/TimeStamp.h"
     48 #include "mozilla/webrender/RenderTextureHostSWGL.h"
     49 #include "mozilla/webrender/RenderThread.h"
     50 #include "mozilla/widget/CompositorWidget.h"
     51 
     52 #ifdef XP_WIN
     53 #  include "mozilla/gfx/DeviceManagerDx.h"
     54 #  include "mozilla/widget/WinCompositorWidget.h"
     55 #endif
     56 #if defined(MOZ_WIDGET_GTK)
     57 #  include "mozilla/widget/GtkCompositorWidget.h"
     58 #endif
     59 
     60 bool is_in_main_thread() { return NS_IsMainThread(); }
     61 
     62 bool is_in_compositor_thread() {
     63  return mozilla::layers::CompositorThreadHolder::IsInCompositorThread();
     64 }
     65 
     66 bool is_in_render_thread() {
     67  return mozilla::wr::RenderThread::IsInRenderThread();
     68 }
     69 
     70 bool gecko_profiler_thread_is_being_profiled() {
     71  return profiler_thread_is_being_profiled(ThreadProfilingFeatures::Any);
     72 }
     73 
     74 bool is_glcontext_gles(void* const glcontext_ptr) {
     75  MOZ_RELEASE_ASSERT(glcontext_ptr);
     76  return reinterpret_cast<mozilla::gl::GLContext*>(glcontext_ptr)->IsGLES();
     77 }
     78 
     79 bool is_glcontext_angle(void* glcontext_ptr) {
     80  MOZ_ASSERT(glcontext_ptr);
     81 
     82  mozilla::gl::GLContext* glcontext =
     83      reinterpret_cast<mozilla::gl::GLContext*>(glcontext_ptr);
     84  if (!glcontext) {
     85    return false;
     86  }
     87  return glcontext->IsANGLE();
     88 }
     89 
     90 const char* gfx_wr_resource_path_override() {
     91  return gfxPlatform::WebRenderResourcePathOverride();
     92 }
     93 
     94 bool gfx_wr_use_optimized_shaders() {
     95  return mozilla::gfx::gfxVars::UseWebRenderOptimizedShaders();
     96 }
     97 
     98 void gfx_critical_note(const char* msg) { gfxCriticalNote << msg; }
     99 
    100 void gfx_critical_error(const char* msg) { gfxCriticalError() << msg; }
    101 
    102 void gecko_printf_stderr_output(const char* msg) { printf_stderr("%s\n", msg); }
    103 
    104 void* get_proc_address_from_glcontext(void* glcontext_ptr,
    105                                      const char* procname) {
    106  mozilla::gl::GLContext* glcontext =
    107      reinterpret_cast<mozilla::gl::GLContext*>(glcontext_ptr);
    108  MOZ_ASSERT(glcontext);
    109  if (!glcontext) {
    110    return nullptr;
    111  }
    112  const auto& loader = glcontext->GetSymbolLoader();
    113  MOZ_ASSERT(loader);
    114 
    115  const auto ret = loader->GetProcAddress(procname);
    116  return reinterpret_cast<void*>(ret);
    117 }
    118 
    119 static CrashReporter::Annotation FromWrCrashAnnotation(
    120    mozilla::wr::CrashAnnotation aAnnotation) {
    121  switch (aAnnotation) {
    122    case mozilla::wr::CrashAnnotation::CompileShader:
    123      return CrashReporter::Annotation::GraphicsCompileShader;
    124    case mozilla::wr::CrashAnnotation::DrawShader:
    125      return CrashReporter::Annotation::GraphicsDrawShader;
    126    case mozilla::wr::CrashAnnotation::FontFile:
    127      return CrashReporter::Annotation::GraphicsFontFile;
    128    default:
    129      MOZ_ASSERT_UNREACHABLE("Unhandled annotation!");
    130      return CrashReporter::Annotation::Count;
    131  }
    132 }
    133 
    134 extern "C" {
    135 
    136 void gfx_wr_set_crash_annotation(mozilla::wr::CrashAnnotation aAnnotation,
    137                                 const char* aValue) {
    138  MOZ_ASSERT(aValue);
    139 
    140  auto annotation = FromWrCrashAnnotation(aAnnotation);
    141  if (annotation == CrashReporter::Annotation::Count) {
    142    return;
    143  }
    144 
    145  CrashReporter::RecordAnnotationCString(annotation, aValue);
    146 }
    147 
    148 void gfx_wr_clear_crash_annotation(mozilla::wr::CrashAnnotation aAnnotation) {
    149  auto annotation = FromWrCrashAnnotation(aAnnotation);
    150  if (annotation == CrashReporter::Annotation::Count) {
    151    return;
    152  }
    153 
    154  CrashReporter::UnrecordAnnotation(annotation);
    155 }
    156 }
    157 
    158 namespace mozilla::gfx {
    159 wr::PipelineId GetTemporaryWebRenderPipelineId(wr::PipelineId aMainPipeline);
    160 }
    161 
    162 namespace mozilla::layers {
    163 
    164 using namespace mozilla::gfx;
    165 
    166 #ifdef MOZ_MEMORY
    167 static bool sAllocAsjustmentTaskCancelled = false;
    168 static bool sIncreasedDirtyPageThreshold = false;
    169 
    170 static void ResetDirtyPageModifier();
    171 
    172 static void ScheduleResetMaxDirtyPageModifier() {
    173  NS_DelayedDispatchToCurrentThread(
    174      NewRunnableFunction("ResetDirtyPageModifier", &ResetDirtyPageModifier),
    175      100  // In ms.
    176  );
    177 }
    178 
    179 static void NeedIncreasedMaxDirtyPageModifier() {
    180  if (sIncreasedDirtyPageThreshold) {
    181    sAllocAsjustmentTaskCancelled = true;
    182    return;
    183  }
    184 
    185  moz_set_max_dirty_page_modifier(3);
    186  sIncreasedDirtyPageThreshold = true;
    187 
    188  ScheduleResetMaxDirtyPageModifier();
    189 }
    190 
    191 static void ResetDirtyPageModifier() {
    192  if (!sIncreasedDirtyPageThreshold) {
    193    return;
    194  }
    195 
    196  if (sAllocAsjustmentTaskCancelled) {
    197    sAllocAsjustmentTaskCancelled = false;
    198    ScheduleResetMaxDirtyPageModifier();
    199    return;
    200  }
    201 
    202  moz_set_max_dirty_page_modifier(0);
    203 
    204  wr::RenderThread* renderThread = wr::RenderThread::Get();
    205  if (renderThread) {
    206    renderThread->NotifyIdle();
    207  }
    208 
    209  jemalloc_free_excess_dirty_pages();
    210 
    211  sIncreasedDirtyPageThreshold = false;
    212 }
    213 #else
    214 // Don't bother doing anything of the memory allocator doesn't support this.
    215 static void NeedIncreasedMaxDirtyPageModifier() {}
    216 #endif
    217 
    218 LazyLogModule gWebRenderBridgeParentLog("WebRenderBridgeParent");
    219 #define LOG(...) \
    220  MOZ_LOG(gWebRenderBridgeParentLog, LogLevel::Debug, (__VA_ARGS__))
    221 
    222 class ScheduleObserveLayersUpdate : public wr::NotificationHandler {
    223 public:
    224  ScheduleObserveLayersUpdate(RefPtr<CompositorBridgeParentBase> aBridge,
    225                              LayersId aLayersId, bool aIsActive)
    226      : mBridge(std::move(aBridge)),
    227        mLayersId(aLayersId),
    228        mIsActive(aIsActive) {}
    229 
    230  void Notify(wr::Checkpoint) override {
    231    CompositorThread()->Dispatch(NewRunnableMethod<LayersId, int>(
    232        "ObserveLayersUpdate", mBridge,
    233        &CompositorBridgeParentBase::ObserveLayersUpdate, mLayersId,
    234        mIsActive));
    235  }
    236 
    237 protected:
    238  RefPtr<CompositorBridgeParentBase> mBridge;
    239  LayersId mLayersId;
    240  bool mIsActive;
    241 };
    242 
    243 class SceneBuiltNotification : public wr::NotificationHandler {
    244 public:
    245  SceneBuiltNotification(WebRenderBridgeParent* aParent, wr::Epoch aEpoch,
    246                         TimeStamp aTxnStartTime)
    247      : mParent(aParent), mEpoch(aEpoch), mTxnStartTime(aTxnStartTime) {}
    248 
    249  void Notify(wr::Checkpoint) override {
    250    auto startTime = this->mTxnStartTime;
    251    RefPtr<WebRenderBridgeParent> parent = mParent;
    252    wr::Epoch epoch = mEpoch;
    253    CompositorThread()->Dispatch(NS_NewRunnableFunction(
    254        "SceneBuiltNotificationRunnable", [parent, epoch, startTime]() {
    255          auto endTime = TimeStamp::Now();
    256          if (profiler_thread_is_being_profiled_for_markers()) {
    257            PROFILER_MARKER("CONTENT_FULL_PAINT_TIME", GRAPHICS,
    258                            MarkerTiming::Interval(startTime, endTime),
    259                            ContentBuildMarker);
    260          }
    261          mozilla::glean::gfx_content::full_paint_time.AccumulateRawDuration(
    262              endTime - startTime);
    263          parent->NotifySceneBuiltForEpoch(epoch, endTime);
    264        }));
    265  }
    266 
    267 protected:
    268  RefPtr<WebRenderBridgeParent> mParent;
    269  wr::Epoch mEpoch;
    270  TimeStamp mTxnStartTime;
    271 };
    272 
    273 class WebRenderBridgeParent::ScheduleSharedSurfaceRelease final
    274    : public wr::NotificationHandler {
    275 public:
    276  explicit ScheduleSharedSurfaceRelease(WebRenderBridgeParent* aWrBridge)
    277      : mWrBridge(aWrBridge), mSurfaces(20) {}
    278 
    279  ~ScheduleSharedSurfaceRelease() override {
    280    if (!mSurfaces.IsEmpty()) {
    281      MOZ_ASSERT_UNREACHABLE("Unreleased surfaces!");
    282      gfxCriticalNote << "ScheduleSharedSurfaceRelease destroyed non-empty";
    283      NotifyInternal(/* aFromCheckpoint */ false);
    284    }
    285  }
    286 
    287  void Add(const wr::ImageKey& aKey, const wr::ExternalImageId& aId) {
    288    mSurfaces.AppendElement(wr::ExternalImageKeyPair{aKey, aId});
    289  }
    290 
    291  void Notify(wr::Checkpoint) override {
    292    NotifyInternal(/* aFromCheckpoint */ true);
    293  }
    294 
    295 private:
    296  void NotifyInternal(bool aFromCheckpoint) {
    297    CompositorThread()->Dispatch(
    298        NewRunnableMethod<nsTArray<wr::ExternalImageKeyPair>, bool>(
    299            "ObserveSharedSurfaceRelease", mWrBridge,
    300            &WebRenderBridgeParent::ObserveSharedSurfaceRelease,
    301            std::move(mSurfaces), aFromCheckpoint));
    302  }
    303 
    304  RefPtr<WebRenderBridgeParent> mWrBridge;
    305  nsTArray<wr::ExternalImageKeyPair> mSurfaces;
    306 };
    307 
    308 class MOZ_STACK_CLASS AutoWebRenderBridgeParentAsyncMessageSender final {
    309 public:
    310  explicit AutoWebRenderBridgeParentAsyncMessageSender(
    311      WebRenderBridgeParent* aWebRenderBridgeParent,
    312      nsTArray<OpDestroy>* aDestroyActors = nullptr)
    313      : mWebRenderBridgeParent(aWebRenderBridgeParent),
    314        mActorsToDestroy(aDestroyActors) {
    315    mWebRenderBridgeParent->SetAboutToSendAsyncMessages();
    316  }
    317 
    318  ~AutoWebRenderBridgeParentAsyncMessageSender() {
    319    mWebRenderBridgeParent->SendPendingAsyncMessages();
    320    if (mActorsToDestroy) {
    321      // Destroy the actors after sending the async messages because the latter
    322      // may contain references to some actors.
    323      for (const auto& op : *mActorsToDestroy) {
    324        mWebRenderBridgeParent->DestroyActor(op);
    325      }
    326    }
    327  }
    328 
    329 private:
    330  WebRenderBridgeParent* mWebRenderBridgeParent;
    331  nsTArray<OpDestroy>* mActorsToDestroy;
    332 };
    333 
    334 WebRenderBridgeParent::WebRenderBridgeParent(
    335    CompositorBridgeParentBase* aCompositorBridge,
    336    const wr::PipelineId& aPipelineId, widget::CompositorWidget* aWidget,
    337    CompositorVsyncScheduler* aScheduler, RefPtr<wr::WebRenderAPI>&& aApi,
    338    RefPtr<AsyncImagePipelineManager>&& aImageMgr, TimeDuration aVsyncRate)
    339    : mCompositorBridge(aCompositorBridge),
    340      mPipelineId(aPipelineId),
    341      mWidget(aWidget),
    342      mApi(aApi),
    343      mAsyncImageManager(aImageMgr),
    344      mCompositorScheduler(aScheduler),
    345      mVsyncRate(aVsyncRate),
    346      mWrEpoch{0},
    347      mIdNamespace(aApi->GetNamespace()),
    348 #if defined(MOZ_WIDGET_ANDROID)
    349      mScreenPixelsTarget(nullptr),
    350 #endif
    351      mBlobTileSize(256),
    352      mSkippedCompositeReasons(wr::RenderReasons::NONE),
    353      mDestroyed(false),
    354      mIsFirstPaint(true),
    355      mPendingScrollPayloads("WebRenderBridgeParent::mPendingScrollPayloads") {
    356  MOZ_ASSERT(mAsyncImageManager);
    357  LOG("WebRenderBridgeParent::WebRenderBridgeParent() PipelineId %" PRIx64
    358      " Id %" PRIx64 " root %d",
    359      wr::AsUint64(mPipelineId), wr::AsUint64(mApi->GetId()),
    360      IsRootWebRenderBridgeParent());
    361 
    362  mAsyncImageManager->AddPipeline(mPipelineId, this);
    363  if (IsRootWebRenderBridgeParent()) {
    364    MOZ_ASSERT(!mCompositorScheduler);
    365    mCompositorScheduler = new CompositorVsyncScheduler(this, mWidget);
    366    UpdateDebugFlags();
    367    UpdateQualitySettings();
    368    UpdateProfilerUI();
    369    UpdateParameters();
    370    // Start with the cached bool parameter bits inverted so that we update them
    371    // all.
    372    mBoolParameterBits = ~gfxVars::WebRenderBoolParameters();
    373    UpdateBoolParameters();
    374  }
    375  mRemoteTextureTxnScheduler =
    376      RemoteTextureTxnScheduler::Create(aCompositorBridge);
    377 }
    378 
    379 WebRenderBridgeParent::WebRenderBridgeParent(const wr::PipelineId& aPipelineId,
    380                                             nsCString&& aError)
    381    : mCompositorBridge(nullptr),
    382      mPipelineId(aPipelineId),
    383      mWrEpoch{0},
    384      mIdNamespace{0},
    385      mInitError(aError),
    386      mDestroyed(true),
    387      mIsFirstPaint(false),
    388      mPendingScrollPayloads("WebRenderBridgeParent::mPendingScrollPayloads") {
    389  LOG("WebRenderBridgeParent::WebRenderBridgeParent() PipelineId %" PRIx64 "",
    390      wr::AsUint64(mPipelineId));
    391 }
    392 
    393 WebRenderBridgeParent::~WebRenderBridgeParent() {
    394  LOG("WebRenderBridgeParent::WebRenderBridgeParent() PipelineId %" PRIx64 "",
    395      wr::AsUint64(mPipelineId));
    396 }
    397 
    398 /* static */
    399 WebRenderBridgeParent* WebRenderBridgeParent::CreateDestroyed(
    400    const wr::PipelineId& aPipelineId, nsCString&& aError) {
    401  return new WebRenderBridgeParent(aPipelineId, std::move(aError));
    402 }
    403 
    404 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvEnsureConnected(
    405    TextureFactoryIdentifier* aTextureFactoryIdentifier,
    406    MaybeIdNamespace* aMaybeIdNamespace, nsCString* aError) {
    407  if (mDestroyed) {
    408    *aTextureFactoryIdentifier =
    409        TextureFactoryIdentifier(LayersBackend::LAYERS_NONE);
    410    *aMaybeIdNamespace = Nothing();
    411    if (mInitError.IsEmpty()) {
    412      // Got destroyed after we initialized but before the handshake finished?
    413      aError->AssignLiteral("FEATURE_FAILURE_WEBRENDER_INITIALIZE_RACE");
    414    } else {
    415      *aError = std::move(mInitError);
    416    }
    417    return IPC_OK();
    418  }
    419 
    420  MOZ_ASSERT(mIdNamespace.mHandle != 0);
    421  *aTextureFactoryIdentifier = GetTextureFactoryIdentifier();
    422  *aMaybeIdNamespace = Some(mIdNamespace);
    423 
    424  return IPC_OK();
    425 }
    426 
    427 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvShutdown() {
    428  return HandleShutdown();
    429 }
    430 
    431 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvShutdownSync() {
    432  return HandleShutdown();
    433 }
    434 
    435 mozilla::ipc::IPCResult WebRenderBridgeParent::HandleShutdown() {
    436  Destroy();
    437  IProtocol* mgr = Manager();
    438  if (!Send__delete__(this)) {
    439    return IPC_FAIL_NO_REASON(mgr);
    440  }
    441  return IPC_OK();
    442 }
    443 
    444 void WebRenderBridgeParent::Destroy() {
    445  if (mDestroyed) {
    446    return;
    447  }
    448  LOG("WebRenderBridgeParent::Destroy() PipelineId %" PRIx64 " Id %" PRIx64
    449      " root %d",
    450      wr::AsUint64(mPipelineId), wr::AsUint64(mApi->GetId()),
    451      IsRootWebRenderBridgeParent());
    452 
    453  mDestroyed = true;
    454  if (mRemoteTextureTxnScheduler) {
    455    mRemoteTextureTxnScheduler = nullptr;
    456  }
    457  if (mWebRenderBridgeRef) {
    458    // Break mutual reference
    459    mWebRenderBridgeRef->Clear();
    460    mWebRenderBridgeRef = nullptr;
    461  }
    462  for (const auto& entry : mCompositables) {
    463    entry.second->OnReleased();
    464  }
    465  mCompositables.clear();
    466  ClearResources();
    467 }
    468 
    469 struct WROTSAlloc {
    470  wr::Vec<uint8_t> mVec;
    471 
    472  void* Grow(void* aPtr, size_t aLength) {
    473    if (aLength > mVec.Capacity()) {
    474      mVec.Reserve(aLength - mVec.Capacity());
    475    }
    476    return mVec.inner.data;
    477  }
    478  wr::Vec<uint8_t> ShrinkToFit(void* aPtr, size_t aLength) {
    479    wr::Vec<uint8_t> result(std::move(mVec));
    480    result.inner.length = aLength;
    481    return result;
    482  }
    483  void Free(void* aPtr) {}
    484 };
    485 
    486 static bool ReadRawFont(const OpAddRawFont& aOp, wr::ShmSegmentsReader& aReader,
    487                        wr::TransactionBuilder& aUpdates) {
    488  wr::Vec<uint8_t> sourceBytes;
    489  Maybe<Range<uint8_t>> ptr =
    490      aReader.GetReadPointerOrCopy(aOp.bytes(), sourceBytes);
    491  if (ptr.isNothing()) {
    492    gfxCriticalNote << "No read pointer from reader for sanitizing font "
    493                    << aOp.key().mHandle;
    494    return false;
    495  }
    496  Range<uint8_t>& source = ptr.ref();
    497  // Attempt to sanitize the font before passing it along for updating.
    498  // Ensure that we're not strict here about font types, since any font that
    499  // failed generating a descriptor might end up here as raw font data.
    500  size_t lengthHint = gfxOTSContext::GuessSanitizedFontSize(
    501      source.begin().get(), source.length(), false);
    502  if (!lengthHint) {
    503    gfxCriticalNote << "Could not determine font type for sanitizing font "
    504                    << aOp.key().mHandle;
    505    return false;
    506  }
    507  gfxOTSExpandingMemoryStream<WROTSAlloc> output(lengthHint);
    508  gfxOTSContext otsContext;
    509  if (!otsContext.Process(&output, source.begin().get(), source.length())) {
    510    gfxCriticalNote << "Failed sanitizing font " << aOp.key().mHandle;
    511    return false;
    512  }
    513  wr::Vec<uint8_t> bytes = output.forget();
    514 
    515  aUpdates.AddRawFont(aOp.key(), bytes, aOp.fontIndex());
    516  return true;
    517 }
    518 
    519 bool WebRenderBridgeParent::UpdateResources(
    520    const nsTArray<OpUpdateResource>& aResourceUpdates,
    521    const nsTArray<RefCountedShmem>& aSmallShmems,
    522    const nsTArray<ipc::Shmem>& aLargeShmems,
    523    wr::TransactionBuilder& aUpdates) {
    524  wr::ShmSegmentsReader reader(aSmallShmems, aLargeShmems);
    525  UniquePtr<ScheduleSharedSurfaceRelease> scheduleRelease;
    526 
    527  while (GPUParent::MaybeFlushMemory()) {
    528    // If the GPU process has memory pressure, preemptively unmap some of our
    529    // shared memory images. If we are in the parent process, the expiration
    530    // tracker itself will listen for the memory pressure event.
    531    if (!SharedSurfacesParent::AgeAndExpireOneGeneration()) {
    532      break;
    533    }
    534  }
    535 
    536  bool success = true;
    537  for (const auto& cmd : aResourceUpdates) {
    538    switch (cmd.type()) {
    539      case OpUpdateResource::TOpAddImage: {
    540        const auto& op = cmd.get_OpAddImage();
    541        if (!MatchesNamespace(op.key())) {
    542          MOZ_ASSERT_UNREACHABLE("Stale image key (add)!");
    543          break;
    544        }
    545 
    546        wr::Vec<uint8_t> bytes;
    547        if (reader.Read(op.bytes(), bytes)) {
    548          aUpdates.AddImage(op.key(), op.descriptor(), bytes);
    549        } else {
    550          gfxCriticalNote << "TOpAddImage failed";
    551          success = false;
    552        }
    553        break;
    554      }
    555      case OpUpdateResource::TOpUpdateImage: {
    556        const auto& op = cmd.get_OpUpdateImage();
    557        if (!MatchesNamespace(op.key())) {
    558          MOZ_ASSERT_UNREACHABLE("Stale image key (update)!");
    559          break;
    560        }
    561 
    562        wr::Vec<uint8_t> bytes;
    563        if (reader.Read(op.bytes(), bytes)) {
    564          aUpdates.UpdateImageBuffer(op.key(), op.descriptor(), bytes);
    565        } else {
    566          gfxCriticalNote << "TOpUpdateImage failed";
    567          success = false;
    568        }
    569        break;
    570      }
    571      case OpUpdateResource::TOpAddBlobImage: {
    572        const auto& op = cmd.get_OpAddBlobImage();
    573        if (!MatchesNamespace(op.key())) {
    574          MOZ_ASSERT_UNREACHABLE("Stale blob image key (add)!");
    575          break;
    576        }
    577 
    578        wr::Vec<uint8_t> bytes;
    579        if (reader.Read(op.bytes(), bytes)) {
    580          aUpdates.AddBlobImage(op.key(), op.descriptor(), mBlobTileSize, bytes,
    581                                wr::ToDeviceIntRect(op.visibleRect()));
    582        } else {
    583          gfxCriticalNote << "TOpAddBlobImage failed";
    584          success = false;
    585        }
    586 
    587        break;
    588      }
    589      case OpUpdateResource::TOpUpdateBlobImage: {
    590        const auto& op = cmd.get_OpUpdateBlobImage();
    591        if (!MatchesNamespace(op.key())) {
    592          MOZ_ASSERT_UNREACHABLE("Stale blob image key (update)!");
    593          break;
    594        }
    595 
    596        wr::Vec<uint8_t> bytes;
    597        if (reader.Read(op.bytes(), bytes)) {
    598          aUpdates.UpdateBlobImage(op.key(), op.descriptor(), bytes,
    599                                   wr::ToDeviceIntRect(op.visibleRect()),
    600                                   wr::ToLayoutIntRect(op.dirtyRect()));
    601        } else {
    602          gfxCriticalNote << "TOpUpdateBlobImage failed";
    603          success = false;
    604        }
    605        break;
    606      }
    607      case OpUpdateResource::TOpSetBlobImageVisibleArea: {
    608        const auto& op = cmd.get_OpSetBlobImageVisibleArea();
    609        if (!MatchesNamespace(op.key())) {
    610          MOZ_ASSERT_UNREACHABLE("Stale blob image key (visible)!");
    611          break;
    612        }
    613        aUpdates.SetBlobImageVisibleArea(op.key(),
    614                                         wr::ToDeviceIntRect(op.area()));
    615        break;
    616      }
    617      case OpUpdateResource::TOpAddSnapshotImage: {
    618        const auto& op = cmd.get_OpAddSnapshotImage();
    619        if (!MatchesNamespace(wr::AsImageKey(op.key()))) {
    620          MOZ_ASSERT_UNREACHABLE("Stale snapshot image key (add)!");
    621          break;
    622        }
    623        aUpdates.AddSnapshotImage(op.key());
    624        break;
    625      }
    626      case OpUpdateResource::TOpDeleteSnapshotImage: {
    627        const auto& op = cmd.get_OpDeleteSnapshotImage();
    628        if (NS_WARN_IF(!MatchesNamespace(wr::AsImageKey(op.key())))) {
    629          // TODO(bug 1972525): Fix tab detach with an active view transition
    630          // and uncomment this assertion.
    631          //
    632          // MOZ_ASSERT_UNREACHABLE("Stale snapshot image key (remove)!");
    633          break;
    634        }
    635        aUpdates.DeleteSnapshotImage(op.key());
    636        break;
    637      }
    638      case OpUpdateResource::TOpAddSharedExternalImage: {
    639        const auto& op = cmd.get_OpAddSharedExternalImage();
    640        // gfxCriticalNote is called on error
    641        if (!AddSharedExternalImage(op.externalImageId(), op.key(), aUpdates)) {
    642          success = false;
    643        }
    644        break;
    645      }
    646      case OpUpdateResource::TOpPushExternalImageForTexture: {
    647        const auto& op = cmd.get_OpPushExternalImageForTexture();
    648        CompositableTextureHostRef texture;
    649        texture = TextureHost::AsTextureHost(op.texture().AsParent());
    650        // gfxCriticalNote is called on error
    651        if (!PushExternalImageForTexture(op.externalImageId(), op.key(),
    652                                         texture, op.isUpdate(), aUpdates)) {
    653          success = false;
    654        }
    655        break;
    656      }
    657      case OpUpdateResource::TOpUpdateSharedExternalImage: {
    658        const auto& op = cmd.get_OpUpdateSharedExternalImage();
    659        // gfxCriticalNote is called on error
    660        if (!UpdateSharedExternalImage(op.externalImageId(), op.key(),
    661                                       op.dirtyRect(), aUpdates,
    662                                       scheduleRelease)) {
    663          success = false;
    664        }
    665        break;
    666      }
    667      case OpUpdateResource::TOpAddRawFont: {
    668        if (!ReadRawFont(cmd.get_OpAddRawFont(), reader, aUpdates)) {
    669          success = false;
    670        }
    671        break;
    672      }
    673      case OpUpdateResource::TOpAddFontDescriptor: {
    674        const auto& op = cmd.get_OpAddFontDescriptor();
    675        if (!MatchesNamespace(op.key())) {
    676          MOZ_ASSERT_UNREACHABLE("Stale font key (add descriptor)!");
    677          break;
    678        }
    679 
    680        wr::Vec<uint8_t> bytes;
    681        if (reader.Read(op.bytes(), bytes)) {
    682          aUpdates.AddFontDescriptor(op.key(), bytes, op.fontIndex());
    683        } else {
    684          gfxCriticalNote << "TOpAddFontDescriptor failed";
    685          success = false;
    686        }
    687        break;
    688      }
    689      case OpUpdateResource::TOpAddFontInstance: {
    690        const auto& op = cmd.get_OpAddFontInstance();
    691        if (!MatchesNamespace(op.instanceKey()) ||
    692            !MatchesNamespace(op.fontKey())) {
    693          MOZ_ASSERT_UNREACHABLE("Stale font key (add instance)!");
    694          break;
    695        }
    696 
    697        wr::Vec<uint8_t> variations;
    698        if (reader.Read(op.variations(), variations)) {
    699          aUpdates.AddFontInstance(op.instanceKey(), op.fontKey(),
    700                                   op.glyphSize(), op.options().ptrOr(nullptr),
    701                                   op.platformOptions().ptrOr(nullptr),
    702                                   variations);
    703        } else {
    704          gfxCriticalNote << "TOpAddFontInstance failed";
    705          success = false;
    706        }
    707        break;
    708      }
    709      case OpUpdateResource::TOpDeleteImage: {
    710        const auto& op = cmd.get_OpDeleteImage();
    711        if (!MatchesNamespace(op.key())) {
    712          // TODO(aosmond): We should also assert here, but the callers are less
    713          // careful about checking when cleaning up their old keys. We should
    714          // perform an audit on image key usage.
    715          break;
    716        }
    717 
    718        DeleteImage(op.key(), aUpdates);
    719        break;
    720      }
    721      case OpUpdateResource::TOpDeleteBlobImage: {
    722        const auto& op = cmd.get_OpDeleteBlobImage();
    723        if (!MatchesNamespace(op.key())) {
    724          MOZ_ASSERT_UNREACHABLE("Stale blob image key (delete)!");
    725          break;
    726        }
    727 
    728        aUpdates.DeleteBlobImage(op.key());
    729        break;
    730      }
    731      case OpUpdateResource::TOpDeleteFont: {
    732        const auto& op = cmd.get_OpDeleteFont();
    733        if (!MatchesNamespace(op.key())) {
    734          MOZ_ASSERT_UNREACHABLE("Stale font key (delete)!");
    735          break;
    736        }
    737 
    738        aUpdates.DeleteFont(op.key());
    739        break;
    740      }
    741      case OpUpdateResource::TOpDeleteFontInstance: {
    742        const auto& op = cmd.get_OpDeleteFontInstance();
    743        if (!MatchesNamespace(op.key())) {
    744          MOZ_ASSERT_UNREACHABLE("Stale font instance key (delete)!");
    745          break;
    746        }
    747 
    748        aUpdates.DeleteFontInstance(op.key());
    749        break;
    750      }
    751      case OpUpdateResource::T__None:
    752        break;
    753    }
    754  }
    755 
    756  if (scheduleRelease) {
    757    // When software WR is enabled, shared surfaces are read during rendering
    758    // rather than copied to the texture cache.
    759    wr::Checkpoint when = mApi->GetBackendType() == WebRenderBackend::SOFTWARE
    760                              ? wr::Checkpoint::FrameRendered
    761                              : wr::Checkpoint::FrameTexturesUpdated;
    762    aUpdates.Notify(when, std::move(scheduleRelease));
    763  }
    764 
    765  MOZ_ASSERT(success);
    766  return success;
    767 }
    768 
    769 bool WebRenderBridgeParent::AddSharedExternalImage(
    770    wr::ExternalImageId aExtId, wr::ImageKey aKey,
    771    wr::TransactionBuilder& aResources) {
    772  if (!MatchesNamespace(aKey)) {
    773    MOZ_ASSERT_UNREACHABLE("Stale shared external image key (add)!");
    774    return true;
    775  }
    776 
    777  auto key = wr::AsUint64(aKey);
    778  auto it = mSharedSurfaceIds.find(key);
    779  if (it != mSharedSurfaceIds.end()) {
    780    gfxCriticalNote << "Readding known shared surface: " << key;
    781    return false;
    782  }
    783 
    784  RefPtr<DataSourceSurface> dSurf = SharedSurfacesParent::Acquire(aExtId);
    785  if (!dSurf) {
    786    gfxCriticalNote
    787        << "DataSourceSurface of SharedSurfaces does not exist for extId:"
    788        << wr::AsUint64(aExtId);
    789    return false;
    790  }
    791 
    792  mSharedSurfaceIds.insert(std::make_pair(key, aExtId));
    793 
    794  // Prefer raw buffers, unless our backend requires native textures.
    795  IntSize surfaceSize = dSurf->GetSize();
    796  TextureHost::NativeTexturePolicy policy =
    797      TextureHost::BackendNativeTexturePolicy(mApi->GetBackendType(),
    798                                              surfaceSize);
    799  auto imageType =
    800      policy == TextureHost::NativeTexturePolicy::REQUIRE
    801          ? wr::ExternalImageType::TextureHandle(wr::ImageBufferKind::Texture2D)
    802          : wr::ExternalImageType::Buffer();
    803  wr::ImageDescriptor descriptor(surfaceSize, dSurf->Stride(),
    804                                 dSurf->GetFormat());
    805  aResources.AddExternalImage(aKey, descriptor, aExtId, imageType, 0);
    806  return true;
    807 }
    808 
    809 bool WebRenderBridgeParent::PushExternalImageForTexture(
    810    wr::ExternalImageId aExtId, wr::ImageKey aKey, TextureHost* aTexture,
    811    bool aIsUpdate, wr::TransactionBuilder& aResources) {
    812  if (!MatchesNamespace(aKey)) {
    813    MOZ_ASSERT_UNREACHABLE("Stale texture external image key!");
    814    return true;
    815  }
    816 
    817  if (!aTexture) {
    818    gfxCriticalNote << "TextureHost does not exist for extId:"
    819                    << wr::AsUint64(aExtId);
    820    return false;
    821  }
    822 
    823  auto op = aIsUpdate ? TextureHost::UPDATE_IMAGE : TextureHost::ADD_IMAGE;
    824  WebRenderTextureHost* wrTexture = aTexture->AsWebRenderTextureHost();
    825  if (wrTexture) {
    826    Range<wr::ImageKey> keys(&aKey, 1);
    827    wrTexture->PushResourceUpdates(aResources, op, keys,
    828                                   wrTexture->GetExternalImageKey());
    829    auto it = mTextureHosts.find(wr::AsUint64(aKey));
    830    MOZ_ASSERT((it == mTextureHosts.end() && !aIsUpdate) ||
    831               (it != mTextureHosts.end() && aIsUpdate));
    832    if (it != mTextureHosts.end()) {
    833      // Release Texture if it exists.
    834      ReleaseTextureOfImage(aKey);
    835    }
    836    mTextureHosts.emplace(wr::AsUint64(aKey),
    837                          CompositableTextureHostRef(aTexture));
    838    return true;
    839  }
    840 
    841  RefPtr<DataSourceSurface> dSurf = aTexture->GetAsSurface();
    842  if (!dSurf) {
    843    gfxCriticalNote
    844        << "TextureHost does not return DataSourceSurface for extId:"
    845        << wr::AsUint64(aExtId);
    846    return false;
    847  }
    848 
    849  DataSourceSurface::MappedSurface map;
    850  if (!dSurf->Map(gfx::DataSourceSurface::MapType::READ, &map)) {
    851    gfxCriticalNote << "DataSourceSurface failed to map for Image for extId:"
    852                    << wr::AsUint64(aExtId);
    853    return false;
    854  }
    855 
    856  IntSize size = dSurf->GetSize();
    857  wr::ImageDescriptor descriptor(size, map.mStride, dSurf->GetFormat());
    858  wr::Vec<uint8_t> data;
    859  data.PushBytes(Range<uint8_t>(map.mData, size.height * map.mStride));
    860 
    861  if (op == TextureHost::UPDATE_IMAGE) {
    862    aResources.UpdateImageBuffer(aKey, descriptor, data);
    863  } else {
    864    aResources.AddImage(aKey, descriptor, data);
    865  }
    866 
    867  dSurf->Unmap();
    868 
    869  return true;
    870 }
    871 
    872 bool WebRenderBridgeParent::UpdateSharedExternalImage(
    873    wr::ExternalImageId aExtId, wr::ImageKey aKey,
    874    const ImageIntRect& aDirtyRect, wr::TransactionBuilder& aResources,
    875    UniquePtr<ScheduleSharedSurfaceRelease>& aScheduleRelease) {
    876  if (!MatchesNamespace(aKey)) {
    877    MOZ_ASSERT_UNREACHABLE("Stale shared external image key (update)!");
    878    return true;
    879  }
    880 
    881  auto key = wr::AsUint64(aKey);
    882  auto it = mSharedSurfaceIds.find(key);
    883  if (it == mSharedSurfaceIds.end()) {
    884    gfxCriticalNote << "Updating unknown shared surface: " << key;
    885    return false;
    886  }
    887 
    888  RefPtr<DataSourceSurface> dSurf;
    889  if (it->second == aExtId) {
    890    dSurf = SharedSurfacesParent::Get(aExtId);
    891  } else {
    892    dSurf = SharedSurfacesParent::Acquire(aExtId);
    893  }
    894 
    895  if (!dSurf) {
    896    gfxCriticalNote << "Shared surface does not exist for extId:"
    897                    << wr::AsUint64(aExtId);
    898    return false;
    899  }
    900 
    901  if (!(it->second == aExtId)) {
    902    // We already have a mapping for this image key, so ensure we release the
    903    // previous external image ID. This can happen when an image is animated,
    904    // and it is changing the external image that the animation points to.
    905    if (!aScheduleRelease) {
    906      aScheduleRelease = MakeUnique<ScheduleSharedSurfaceRelease>(this);
    907    }
    908    aScheduleRelease->Add(aKey, it->second);
    909    it->second = aExtId;
    910  }
    911 
    912  // Prefer raw buffers, unless our backend requires native textures.
    913  IntSize surfaceSize = dSurf->GetSize();
    914  TextureHost::NativeTexturePolicy policy =
    915      TextureHost::BackendNativeTexturePolicy(mApi->GetBackendType(),
    916                                              surfaceSize);
    917  auto imageType =
    918      policy == TextureHost::NativeTexturePolicy::REQUIRE
    919          ? wr::ExternalImageType::TextureHandle(wr::ImageBufferKind::Texture2D)
    920          : wr::ExternalImageType::Buffer();
    921  wr::ImageDescriptor descriptor(surfaceSize, dSurf->Stride(),
    922                                 dSurf->GetFormat());
    923  aResources.UpdateExternalImageWithDirtyRect(
    924      aKey, descriptor, aExtId, imageType, wr::ToDeviceIntRect(aDirtyRect), 0,
    925      /* aNormalizedUvs */ false);
    926 
    927  return true;
    928 }
    929 
    930 void WebRenderBridgeParent::ObserveSharedSurfaceRelease(
    931    const nsTArray<wr::ExternalImageKeyPair>& aPairs,
    932    const bool& aFromCheckpoint) {
    933  if (!mDestroyed) {
    934    (void)SendWrReleasedImages(aPairs);
    935  }
    936 
    937  if (!aFromCheckpoint && mAsyncImageManager) {
    938    // We failed to receive a checkpoint notification, so we are releasing these
    939    // surfaces blind. Let's wait until the next epoch to complete releasing.
    940    for (const auto& pair : aPairs) {
    941      mAsyncImageManager->HoldExternalImage(mPipelineId, mWrEpoch, pair.id);
    942    }
    943    return;
    944  }
    945 
    946  // We hit the checkpoint, so we know we can safely release the surfaces now.
    947  for (const auto& pair : aPairs) {
    948    SharedSurfacesParent::Release(pair.id);
    949  }
    950 }
    951 
    952 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvUpdateResources(
    953    const wr::IdNamespace& aIdNamespace,
    954    nsTArray<OpUpdateResource>&& aResourceUpdates,
    955    nsTArray<RefCountedShmem>&& aSmallShmems,
    956    nsTArray<ipc::Shmem>&& aLargeShmems) {
    957  const bool isValidMessage = aIdNamespace == mIdNamespace;
    958 
    959  if (mDestroyed || !isValidMessage) {
    960    wr::IpcResourceUpdateQueue::ReleaseShmems(this, aSmallShmems);
    961    wr::IpcResourceUpdateQueue::ReleaseShmems(this, aLargeShmems);
    962    return IPC_OK();
    963  }
    964 
    965  LOG("WebRenderBridgeParent::RecvUpdateResources() PipelineId %" PRIx64
    966      " Id %" PRIx64 " root %d",
    967      wr::AsUint64(mPipelineId), wr::AsUint64(mApi->GetId()),
    968      IsRootWebRenderBridgeParent());
    969 
    970  wr::TransactionBuilder txn(mApi);
    971  txn.SetLowPriority(!IsRootWebRenderBridgeParent());
    972 
    973  (void)GetNextWrEpoch();
    974 
    975  bool success =
    976      UpdateResources(aResourceUpdates, aSmallShmems, aLargeShmems, txn);
    977  wr::IpcResourceUpdateQueue::ReleaseShmems(this, aSmallShmems);
    978  wr::IpcResourceUpdateQueue::ReleaseShmems(this, aLargeShmems);
    979 
    980  // Even when txn.IsResourceUpdatesEmpty() is true, there could be resource
    981  // updates. It is handled by WebRenderTextureHostWrapper. In this case
    982  // txn.IsRenderedFrameInvalidated() becomes true.
    983  if (!txn.IsResourceUpdatesEmpty() || txn.IsRenderedFrameInvalidated()) {
    984    // There are resource updates, then we update Epoch of transaction.
    985    txn.UpdateEpoch(mPipelineId, mWrEpoch);
    986    mAsyncImageManager->SetWillGenerateFrame();
    987    ScheduleGenerateFrame(wr::RenderReasons::RESOURCE_UPDATE);
    988  } else {
    989    // If TransactionBuilder does not have resource updates nor display list,
    990    // ScheduleGenerateFrame is not triggered via SceneBuilder and there is no
    991    // need to update WrEpoch.
    992    // Then we want to rollback WrEpoch. See Bug 1490117.
    993    RollbackWrEpoch();
    994  }
    995 
    996  mApi->SendTransaction(txn);
    997 
    998  if (!success) {
    999    return IPC_FAIL(this, "Invalid WebRender resource data shmem or address.");
   1000  }
   1001 
   1002  return IPC_OK();
   1003 }
   1004 
   1005 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvDeleteCompositorAnimations(
   1006    nsTArray<uint64_t>&& aIds) {
   1007  if (mDestroyed) {
   1008    return IPC_OK();
   1009  }
   1010 
   1011  LOG("WebRenderBridgeParent::RecvDeleteCompositorAnimations() PipelineId "
   1012      "%" PRIx64 " Id %" PRIx64 " root %d",
   1013      wr::AsUint64(mPipelineId), wr::AsUint64(mApi->GetId()),
   1014      IsRootWebRenderBridgeParent());
   1015 
   1016  // Once mWrEpoch has been rendered, we can delete these compositor animations
   1017  mCompositorAnimationsToDelete.push(
   1018      CompositorAnimationIdsForEpoch(mWrEpoch, std::move(aIds)));
   1019  return IPC_OK();
   1020 }
   1021 
   1022 void WebRenderBridgeParent::RemoveEpochDataPriorTo(
   1023    const wr::Epoch& aRenderedEpoch) {
   1024  if (RefPtr<OMTASampler> sampler = GetOMTASampler()) {
   1025    sampler->RemoveEpochDataPriorTo(mCompositorAnimationsToDelete,
   1026                                    mActiveAnimations, aRenderedEpoch);
   1027  }
   1028 }
   1029 
   1030 bool WebRenderBridgeParent::IsRootWebRenderBridgeParent() const {
   1031  return !!mWidget;
   1032 }
   1033 
   1034 void WebRenderBridgeParent::BeginRecording(const TimeStamp& aRecordingStart) {
   1035  mApi->BeginRecording(aRecordingStart, mPipelineId);
   1036 }
   1037 
   1038 RefPtr<wr::WebRenderAPI::EndRecordingPromise>
   1039 WebRenderBridgeParent::EndRecording() {
   1040  return mApi->EndRecording();
   1041 }
   1042 
   1043 void WebRenderBridgeParent::AddPendingScrollPayload(
   1044    CompositionPayload& aPayload, const VsyncId& aCompositeStartId) {
   1045  auto pendingScrollPayloads = mPendingScrollPayloads.Lock();
   1046  nsTArray<CompositionPayload>* payloads =
   1047      pendingScrollPayloads->GetOrInsertNew(aCompositeStartId.mId);
   1048 
   1049  payloads->AppendElement(aPayload);
   1050 }
   1051 
   1052 nsTArray<CompositionPayload> WebRenderBridgeParent::TakePendingScrollPayload(
   1053    const VsyncId& aCompositeStartId) {
   1054  auto pendingScrollPayloads = mPendingScrollPayloads.Lock();
   1055  nsTArray<CompositionPayload> payload;
   1056  if (nsTArray<CompositionPayload>* storedPayload =
   1057          pendingScrollPayloads->Get(aCompositeStartId.mId)) {
   1058    payload.AppendElements(std::move(*storedPayload));
   1059    pendingScrollPayloads->Remove(aCompositeStartId.mId);
   1060  }
   1061  return payload;
   1062 }
   1063 
   1064 CompositorBridgeParent* WebRenderBridgeParent::GetRootCompositorBridgeParent()
   1065    const {
   1066  if (!mCompositorBridge) {
   1067    return nullptr;
   1068  }
   1069 
   1070  if (IsRootWebRenderBridgeParent()) {
   1071    // This WebRenderBridgeParent is attached to the root
   1072    // CompositorBridgeParent.
   1073    return static_cast<CompositorBridgeParent*>(mCompositorBridge);
   1074  }
   1075 
   1076  // Otherwise, this WebRenderBridgeParent is attached to a
   1077  // ContentCompositorBridgeParent so we have an extra level of
   1078  // indirection to unravel.
   1079  CompositorBridgeParent::LayerTreeState* lts =
   1080      CompositorBridgeParent::GetIndirectShadowTree(GetLayersId());
   1081  if (!lts) {
   1082    return nullptr;
   1083  }
   1084  return lts->mParent;
   1085 }
   1086 
   1087 RefPtr<WebRenderBridgeParent>
   1088 WebRenderBridgeParent::GetRootWebRenderBridgeParent() const {
   1089  CompositorBridgeParent* cbp = GetRootCompositorBridgeParent();
   1090  if (!cbp) {
   1091    return nullptr;
   1092  }
   1093 
   1094  return cbp->GetWebRenderBridgeParent();
   1095 }
   1096 
   1097 void WebRenderBridgeParent::UpdateAPZFocusState(const FocusTarget& aFocus) {
   1098  CompositorBridgeParent* cbp = GetRootCompositorBridgeParent();
   1099  if (!cbp) {
   1100    return;
   1101  }
   1102  LayersId rootLayersId = cbp->RootLayerTreeId();
   1103  if (RefPtr<APZUpdater> apz = cbp->GetAPZUpdater()) {
   1104    apz->UpdateFocusState(rootLayersId, GetLayersId(), aFocus);
   1105  }
   1106 }
   1107 
   1108 void WebRenderBridgeParent::UpdateAPZScrollData(const wr::Epoch& aEpoch,
   1109                                                WebRenderScrollData&& aData) {
   1110  CompositorBridgeParent* cbp = GetRootCompositorBridgeParent();
   1111  if (!cbp) {
   1112    return;
   1113  }
   1114  LayersId rootLayersId = cbp->RootLayerTreeId();
   1115  if (RefPtr<APZUpdater> apz = cbp->GetAPZUpdater()) {
   1116    apz->UpdateScrollDataAndTreeState(rootLayersId, GetLayersId(), aEpoch,
   1117                                      std::move(aData));
   1118  }
   1119 }
   1120 
   1121 void WebRenderBridgeParent::UpdateAPZScrollOffsets(
   1122    ScrollUpdatesMap&& aUpdates, uint32_t aPaintSequenceNumber) {
   1123  CompositorBridgeParent* cbp = GetRootCompositorBridgeParent();
   1124  if (!cbp) {
   1125    return;
   1126  }
   1127  LayersId rootLayersId = cbp->RootLayerTreeId();
   1128  if (RefPtr<APZUpdater> apz = cbp->GetAPZUpdater()) {
   1129    apz->UpdateScrollOffsets(rootLayersId, GetLayersId(), std::move(aUpdates),
   1130                             aPaintSequenceNumber);
   1131  }
   1132 }
   1133 
   1134 void WebRenderBridgeParent::SetAPZSampleTime() {
   1135  CompositorBridgeParent* cbp = GetRootCompositorBridgeParent();
   1136  if (!cbp) {
   1137    return;
   1138  }
   1139  if (RefPtr<APZSampler> apz = cbp->GetAPZSampler()) {
   1140    SampleTime animationTime;
   1141    if (Maybe<TimeStamp> testTime = cbp->GetTestingTimeStamp()) {
   1142      animationTime = SampleTime::FromTest(*testTime);
   1143    } else {
   1144      animationTime = mCompositorScheduler->GetLastComposeTime();
   1145    }
   1146    TimeDuration frameInterval = cbp->GetVsyncInterval();
   1147    // As with the non-webrender codepath in AsyncCompositionManager, we want to
   1148    // use the timestamp for the next vsync when advancing animations.
   1149    if (frameInterval != TimeDuration::Forever()) {
   1150      animationTime = animationTime + frameInterval;
   1151    }
   1152    apz->SetSampleTime(animationTime);
   1153  }
   1154 }
   1155 
   1156 bool WebRenderBridgeParent::SetDisplayList(
   1157    const LayoutDeviceRect& aRect, ipc::ByteBuf&& aDLItems,
   1158    ipc::ByteBuf&& aDLCache, ipc::ByteBuf&& aSpatialTreeDL,
   1159    const wr::BuiltDisplayListDescriptor& aDLDesc,
   1160    const nsTArray<OpUpdateResource>& aResourceUpdates,
   1161    const nsTArray<RefCountedShmem>& aSmallShmems,
   1162    const nsTArray<ipc::Shmem>& aLargeShmems, const TimeStamp& aTxnStartTime,
   1163    wr::TransactionBuilder& aTxn, wr::Epoch aWrEpoch, const VsyncId& aVsyncId,
   1164    bool aRenderOffscreen) {
   1165  bool success =
   1166      UpdateResources(aResourceUpdates, aSmallShmems, aLargeShmems, aTxn);
   1167 
   1168  wr::Vec<uint8_t> dlItems(std::move(aDLItems));
   1169  wr::Vec<uint8_t> dlCache(std::move(aDLCache));
   1170  wr::Vec<uint8_t> dlSpatialTreeData(std::move(aSpatialTreeDL));
   1171 
   1172  if (IsRootWebRenderBridgeParent()) {
   1173    LayoutDeviceIntSize widgetSize = mWidget->GetClientSize();
   1174    LayoutDeviceIntRect rect =
   1175        LayoutDeviceIntRect(LayoutDeviceIntPoint(), widgetSize);
   1176    aTxn.SetDocumentView(rect);
   1177  }
   1178 
   1179  wr::PipelineId pipelineId = mPipelineId;
   1180  if (aRenderOffscreen) {
   1181    pipelineId = gfx::GetTemporaryWebRenderPipelineId(pipelineId);
   1182  }
   1183 
   1184  aTxn.SetDisplayList(aWrEpoch, pipelineId, aDLDesc, dlItems, dlCache,
   1185                      dlSpatialTreeData);
   1186 
   1187  if (aRenderOffscreen) {
   1188    aTxn.RenderOffscreen(pipelineId);
   1189    aTxn.RemovePipeline(pipelineId);
   1190  } else {
   1191    MaybeNotifyOfLayers(aTxn, true);
   1192  }
   1193 
   1194  if (!IsRootWebRenderBridgeParent() && !aRenderOffscreen) {
   1195    aTxn.Notify(wr::Checkpoint::SceneBuilt, MakeUnique<SceneBuiltNotification>(
   1196                                                this, aWrEpoch, aTxnStartTime));
   1197  }
   1198 
   1199  NeedIncreasedMaxDirtyPageModifier();
   1200 
   1201  mApi->SendTransaction(aTxn);
   1202 
   1203  // We will schedule generating a frame after the scene
   1204  // build is done, so we don't need to do it here.
   1205  return success;
   1206 }
   1207 
   1208 bool WebRenderBridgeParent::ProcessDisplayListData(
   1209    DisplayListData& aDisplayList, wr::Epoch aWrEpoch,
   1210    const TimeStamp& aTxnStartTime, bool aValidTransaction,
   1211    bool aRenderOffscreen, const VsyncId& aVsyncId) {
   1212  wr::TransactionBuilder txn(mApi, /* aUseSceneBuilderThread */ true,
   1213                             mRemoteTextureTxnScheduler, mFwdTransactionId);
   1214  Maybe<wr::AutoTransactionSender> sender;
   1215 
   1216  if (aDisplayList.mScrollData && !aDisplayList.mScrollData->Validate()) {
   1217    // If the scroll data is invalid, the entire transaction needs to be dropped
   1218    // because the scroll data and the display list cross-reference each other.
   1219    MOZ_ASSERT(
   1220        false,
   1221        "Content sent malformed scroll data (or validation check has a bug)");
   1222    aValidTransaction = false;
   1223  }
   1224 
   1225  if (!aValidTransaction) {
   1226    return true;
   1227  }
   1228 
   1229  MOZ_ASSERT(aDisplayList.mIdNamespace == mIdNamespace);
   1230 
   1231  // Note that this needs to happen before the display list transaction is
   1232  // sent to WebRender, so that the UpdateHitTestingTree call is guaranteed to
   1233  // be in the updater queue at the time that the scene swap completes.
   1234  if (aDisplayList.mScrollData) {
   1235    UpdateAPZScrollData(aWrEpoch, std::move(aDisplayList.mScrollData.ref()));
   1236  }
   1237 
   1238  txn.SetLowPriority(!IsRootWebRenderBridgeParent());
   1239  sender.emplace(mApi, &txn);
   1240  bool success = true;
   1241 
   1242  success =
   1243      ProcessWebRenderParentCommands(aDisplayList.mCommands, txn) && success;
   1244 
   1245  if (aDisplayList.mDLItems && aDisplayList.mDLCache &&
   1246      aDisplayList.mDLSpatialTree) {
   1247    success = SetDisplayList(
   1248                  aDisplayList.mRect, std::move(aDisplayList.mDLItems.ref()),
   1249                  std::move(aDisplayList.mDLCache.ref()),
   1250                  std::move(aDisplayList.mDLSpatialTree.ref()),
   1251                  aDisplayList.mDLDesc, aDisplayList.mResourceUpdates,
   1252                  aDisplayList.mSmallShmems, aDisplayList.mLargeShmems,
   1253                  aTxnStartTime, txn, aWrEpoch, aVsyncId, aRenderOffscreen) &&
   1254              success;
   1255  }
   1256 
   1257  return success;
   1258 }
   1259 
   1260 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvSetDisplayList(
   1261    DisplayListData&& aDisplayList, nsTArray<OpDestroy>&& aToDestroy,
   1262    const uint64_t& aFwdTransactionId, const TransactionId& aTransactionId,
   1263    const bool& aContainsSVGGroup, const VsyncId& aVsyncId,
   1264    const TimeStamp& aVsyncStartTime, const TimeStamp& aRefreshStartTime,
   1265    const TimeStamp& aTxnStartTime, const nsACString& aTxnURL,
   1266    const TimeStamp& aFwdTime, nsTArray<CompositionPayload>&& aPayloads,
   1267    const bool& aRenderOffscreen) {
   1268  if (mDestroyed) {
   1269    for (const auto& op : aToDestroy) {
   1270      DestroyActor(op);
   1271    }
   1272    wr::IpcResourceUpdateQueue::ReleaseShmems(this, aDisplayList.mSmallShmems);
   1273    wr::IpcResourceUpdateQueue::ReleaseShmems(this, aDisplayList.mLargeShmems);
   1274    return IPC_OK();
   1275  }
   1276 
   1277  LOG("WebRenderBridgeParent::RecvSetDisplayList() PipelineId %" PRIx64
   1278      " Id %" PRIx64 " root %d",
   1279      wr::AsUint64(mPipelineId), wr::AsUint64(mApi->GetId()),
   1280      IsRootWebRenderBridgeParent());
   1281 
   1282  if (!IsRootWebRenderBridgeParent()) {
   1283    CrashReporter::RecordAnnotationNSCString(CrashReporter::Annotation::URL,
   1284                                             aTxnURL);
   1285  }
   1286 
   1287  CompositorBridgeParent* cbp = GetRootCompositorBridgeParent();
   1288  uint64_t innerWindowId = cbp ? cbp->GetInnerWindowId() : 0;
   1289  AUTO_PROFILER_MARKER_INNERWINDOWID("SetDisplayList", GRAPHICS, innerWindowId);
   1290  UpdateFwdTransactionId(aFwdTransactionId);
   1291 
   1292  // This ensures that destroy operations are always processed. It is not safe
   1293  // to early-return from RecvDPEnd without doing so.
   1294  AutoWebRenderBridgeParentAsyncMessageSender autoAsyncMessageSender(
   1295      this, &aToDestroy);
   1296 
   1297  wr::Epoch wrEpoch = GetNextWrEpoch();
   1298 
   1299  mReceivedDisplayList = true;
   1300 
   1301  if (aDisplayList.mScrollData && aDisplayList.mScrollData->IsFirstPaint()) {
   1302    mIsFirstPaint = true;
   1303  }
   1304 
   1305  bool validTransaction = aDisplayList.mIdNamespace == mIdNamespace;
   1306  bool success =
   1307      ProcessDisplayListData(aDisplayList, wrEpoch, aTxnStartTime,
   1308                             validTransaction, aRenderOffscreen, aVsyncId);
   1309 
   1310  if (!IsRootWebRenderBridgeParent()) {
   1311    aPayloads.AppendElement(
   1312        CompositionPayload{CompositionPayloadType::eContentPaint, aFwdTime});
   1313  }
   1314 
   1315  HoldPendingTransactionId(wrEpoch, aTransactionId, aContainsSVGGroup, aVsyncId,
   1316                           aVsyncStartTime, aRefreshStartTime, aTxnStartTime,
   1317                           aTxnURL, aFwdTime, mIsFirstPaint,
   1318                           std::move(aPayloads));
   1319  mIsFirstPaint = false;
   1320 
   1321  if (!validTransaction) {
   1322    // Pretend we composited since someone is wating for this event,
   1323    // though DisplayList was not pushed to webrender.
   1324    if (CompositorBridgeParent* cbp = GetRootCompositorBridgeParent()) {
   1325      TimeStamp now = TimeStamp::Now();
   1326      cbp->NotifyPipelineRendered(mPipelineId, wrEpoch, VsyncId(), now, now,
   1327                                  now);
   1328    }
   1329  }
   1330 
   1331  wr::IpcResourceUpdateQueue::ReleaseShmems(this, aDisplayList.mSmallShmems);
   1332  wr::IpcResourceUpdateQueue::ReleaseShmems(this, aDisplayList.mLargeShmems);
   1333 
   1334  if (!success) {
   1335    return IPC_FAIL(this, "Failed to process DisplayListData.");
   1336  }
   1337 
   1338  return IPC_OK();
   1339 }
   1340 
   1341 bool WebRenderBridgeParent::ProcessEmptyTransactionUpdates(
   1342    TransactionData& aData, bool* aScheduleComposite) {
   1343  *aScheduleComposite = false;
   1344  wr::TransactionBuilder txn(mApi, /* aUseSceneBuilderThread */ true,
   1345                             mRemoteTextureTxnScheduler, mFwdTransactionId);
   1346  txn.SetLowPriority(!IsRootWebRenderBridgeParent());
   1347 
   1348  if (!aData.mScrollUpdates.IsEmpty()) {
   1349    UpdateAPZScrollOffsets(std::move(aData.mScrollUpdates),
   1350                           aData.mPaintSequenceNumber);
   1351  }
   1352 
   1353  // Update WrEpoch for UpdateResources() and ProcessWebRenderParentCommands().
   1354  // WrEpoch is used to manage ExternalImages lifetimes in
   1355  // AsyncImagePipelineManager.
   1356  (void)GetNextWrEpoch();
   1357 
   1358  const bool validTransaction = aData.mIdNamespace == mIdNamespace;
   1359  bool success = true;
   1360 
   1361  if (validTransaction) {
   1362    success = UpdateResources(aData.mResourceUpdates, aData.mSmallShmems,
   1363                              aData.mLargeShmems, txn);
   1364    if (!aData.mCommands.IsEmpty()) {
   1365      success = ProcessWebRenderParentCommands(aData.mCommands, txn) && success;
   1366    }
   1367  }
   1368 
   1369  MaybeNotifyOfLayers(txn, true);
   1370 
   1371  // Even when txn.IsResourceUpdatesEmpty() is true, there could be resource
   1372  // updates. It is handled by WebRenderTextureHostWrapper. In this case
   1373  // txn.IsRenderedFrameInvalidated() becomes true.
   1374  if (!txn.IsResourceUpdatesEmpty() || txn.IsRenderedFrameInvalidated()) {
   1375    // There are resource updates, then we update Epoch of transaction.
   1376    txn.UpdateEpoch(mPipelineId, mWrEpoch);
   1377    *aScheduleComposite = true;
   1378    NeedIncreasedMaxDirtyPageModifier();
   1379  } else {
   1380    // If TransactionBuilder does not have resource updates nor display list,
   1381    // ScheduleGenerateFrame is not triggered via SceneBuilder and there is no
   1382    // need to update WrEpoch.
   1383    // Then we want to rollback WrEpoch. See Bug 1490117.
   1384    RollbackWrEpoch();
   1385  }
   1386 
   1387  if (!txn.IsEmpty()) {
   1388    mApi->SendTransaction(txn);
   1389  }
   1390 
   1391  if (*aScheduleComposite) {
   1392    mAsyncImageManager->SetWillGenerateFrame();
   1393  }
   1394 
   1395  return success;
   1396 }
   1397 
   1398 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvEmptyTransaction(
   1399    const FocusTarget& aFocusTarget, Maybe<TransactionData>&& aTransactionData,
   1400    nsTArray<OpDestroy>&& aToDestroy, const uint64_t& aFwdTransactionId,
   1401    const TransactionId& aTransactionId, const VsyncId& aVsyncId,
   1402    const TimeStamp& aVsyncStartTime, const TimeStamp& aRefreshStartTime,
   1403    const TimeStamp& aTxnStartTime, const nsACString& aTxnURL,
   1404    const TimeStamp& aFwdTime, nsTArray<CompositionPayload>&& aPayloads) {
   1405  if (mDestroyed) {
   1406    for (const auto& op : aToDestroy) {
   1407      DestroyActor(op);
   1408    }
   1409    if (aTransactionData) {
   1410      wr::IpcResourceUpdateQueue::ReleaseShmems(this,
   1411                                                aTransactionData->mSmallShmems);
   1412      wr::IpcResourceUpdateQueue::ReleaseShmems(this,
   1413                                                aTransactionData->mLargeShmems);
   1414    }
   1415    return IPC_OK();
   1416  }
   1417 
   1418  LOG("WebRenderBridgeParent::RecvEmptyTransaction() PipelineId %" PRIx64
   1419      " Id %" PRIx64 " root %d",
   1420      wr::AsUint64(mPipelineId), wr::AsUint64(mApi->GetId()),
   1421      IsRootWebRenderBridgeParent());
   1422 
   1423  if (!IsRootWebRenderBridgeParent()) {
   1424    CrashReporter::RecordAnnotationNSCString(CrashReporter::Annotation::URL,
   1425                                             aTxnURL);
   1426  }
   1427 
   1428  AUTO_PROFILER_MARKER("EmptyTransaction", GRAPHICS);
   1429  UpdateFwdTransactionId(aFwdTransactionId);
   1430 
   1431  // This ensures that destroy operations are always processed. It is not safe
   1432  // to early-return without doing so.
   1433  AutoWebRenderBridgeParentAsyncMessageSender autoAsyncMessageSender(
   1434      this, &aToDestroy);
   1435 
   1436  UpdateAPZFocusState(aFocusTarget);
   1437 
   1438  bool scheduleAnyComposite = false;
   1439  wr::RenderReasons renderReasons = wr::RenderReasons::NONE;
   1440 
   1441  bool success = true;
   1442  if (aTransactionData) {
   1443    bool scheduleComposite = false;
   1444    success =
   1445        ProcessEmptyTransactionUpdates(*aTransactionData, &scheduleComposite);
   1446    scheduleAnyComposite = scheduleAnyComposite || scheduleComposite;
   1447    renderReasons |= wr::RenderReasons::RESOURCE_UPDATE;
   1448  }
   1449 
   1450  // If we are going to kick off a new composite as a result of this
   1451  // transaction, or if there are already composite-triggering pending
   1452  // transactions inflight, then set sendDidComposite to false because we will
   1453  // send the DidComposite message after the composite occurs.
   1454  // If there are no pending transactions and we're not going to do a
   1455  // composite, then we leave sendDidComposite as true so we just send
   1456  // the DidComposite notification now.
   1457  bool sendDidComposite =
   1458      !scheduleAnyComposite && mPendingTransactionIds.empty();
   1459 
   1460  // Only register a value for CONTENT_FRAME_TIME telemetry if we actually drew
   1461  // something. It is for consistency with disabling WebRender.
   1462  HoldPendingTransactionId(mWrEpoch, aTransactionId, false, aVsyncId,
   1463                           aVsyncStartTime, aRefreshStartTime, aTxnStartTime,
   1464                           aTxnURL, aFwdTime,
   1465                           /* aIsFirstPaint */ false, std::move(aPayloads),
   1466                           /* aUseForTelemetry */ scheduleAnyComposite);
   1467 
   1468  if (scheduleAnyComposite) {
   1469    ScheduleGenerateFrame(renderReasons);
   1470  } else if (sendDidComposite) {
   1471    // The only thing in the pending transaction id queue should be the entry
   1472    // we just added, and now we're going to pretend we rendered it
   1473    MOZ_ASSERT(mPendingTransactionIds.size() == 1);
   1474    if (CompositorBridgeParent* cbp = GetRootCompositorBridgeParent()) {
   1475      TimeStamp now = TimeStamp::Now();
   1476      cbp->NotifyPipelineRendered(mPipelineId, mWrEpoch, VsyncId(), now, now,
   1477                                  now);
   1478    }
   1479  }
   1480 
   1481  if (aTransactionData) {
   1482    wr::IpcResourceUpdateQueue::ReleaseShmems(this,
   1483                                              aTransactionData->mSmallShmems);
   1484    wr::IpcResourceUpdateQueue::ReleaseShmems(this,
   1485                                              aTransactionData->mLargeShmems);
   1486  }
   1487 
   1488  if (!success) {
   1489    return IPC_FAIL(this, "Failed to process empty transaction update.");
   1490  }
   1491 
   1492  return IPC_OK();
   1493 }
   1494 
   1495 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvSetFocusTarget(
   1496    const FocusTarget& aFocusTarget) {
   1497  UpdateAPZFocusState(aFocusTarget);
   1498  return IPC_OK();
   1499 }
   1500 
   1501 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvParentCommands(
   1502    const wr::IdNamespace& aIdNamespace,
   1503    nsTArray<WebRenderParentCommand>&& aCommands) {
   1504  if (mDestroyed) {
   1505    return IPC_OK();
   1506  }
   1507 
   1508  const bool isValidMessage = aIdNamespace == mIdNamespace;
   1509  if (!isValidMessage) {
   1510    return IPC_OK();
   1511  }
   1512 
   1513  LOG("WebRenderBridgeParent::RecvParentCommands() PipelineId %" PRIx64
   1514      " Id %" PRIx64 " root %d",
   1515      wr::AsUint64(mPipelineId), wr::AsUint64(mApi->GetId()),
   1516      IsRootWebRenderBridgeParent());
   1517 
   1518  wr::TransactionBuilder txn(mApi);
   1519  txn.SetLowPriority(!IsRootWebRenderBridgeParent());
   1520  bool success = ProcessWebRenderParentCommands(aCommands, txn);
   1521  NeedIncreasedMaxDirtyPageModifier();
   1522  mApi->SendTransaction(txn);
   1523 
   1524  if (!success) {
   1525    return IPC_FAIL(this, "Invalid parent command found");
   1526  }
   1527 
   1528  return IPC_OK();
   1529 }
   1530 
   1531 bool WebRenderBridgeParent::ProcessWebRenderParentCommands(
   1532    const nsTArray<WebRenderParentCommand>& aCommands,
   1533    wr::TransactionBuilder& aTxn) {
   1534  // Transaction for async image pipeline that uses ImageBridge always need to
   1535  // be non low priority.
   1536  wr::TransactionBuilder txnForImageBridge(mApi->GetRootAPI());
   1537  wr::AutoTransactionSender sender(mApi->GetRootAPI(), &txnForImageBridge);
   1538 
   1539  bool success = true;
   1540  for (nsTArray<WebRenderParentCommand>::index_type i = 0;
   1541       i < aCommands.Length(); ++i) {
   1542    const WebRenderParentCommand& cmd = aCommands[i];
   1543    switch (cmd.type()) {
   1544      case WebRenderParentCommand::TOpAddPipelineIdForCompositable: {
   1545        const OpAddPipelineIdForCompositable& op =
   1546            cmd.get_OpAddPipelineIdForCompositable();
   1547        AddPipelineIdForCompositable(op.pipelineId(), op.handle(), op.owner(),
   1548                                     aTxn, txnForImageBridge);
   1549        break;
   1550      }
   1551      case WebRenderParentCommand::TOpRemovePipelineIdForCompositable: {
   1552        const OpRemovePipelineIdForCompositable& op =
   1553            cmd.get_OpRemovePipelineIdForCompositable();
   1554        auto* pendingOps = mApi->GetPendingAsyncImagePipelineOps(aTxn);
   1555 
   1556        RemovePipelineIdForCompositable(op.pipelineId(), pendingOps, aTxn);
   1557        break;
   1558      }
   1559      case WebRenderParentCommand::TOpReleaseTextureOfImage: {
   1560        const OpReleaseTextureOfImage& op = cmd.get_OpReleaseTextureOfImage();
   1561        ReleaseTextureOfImage(op.key());
   1562        break;
   1563      }
   1564      case WebRenderParentCommand::TOpUpdateAsyncImagePipeline: {
   1565        const OpUpdateAsyncImagePipeline& op =
   1566            cmd.get_OpUpdateAsyncImagePipeline();
   1567 
   1568        auto* pendingOps = mApi->GetPendingAsyncImagePipelineOps(aTxn);
   1569        auto* pendingRemotetextures = mApi->GetPendingRemoteTextureInfoList();
   1570 
   1571        mAsyncImageManager->UpdateAsyncImagePipeline(
   1572            op.pipelineId(), op.scBounds(), op.rotation(), op.filter(),
   1573            op.mixBlendMode());
   1574        MOZ_ASSERT_IF(IsRootWebRenderBridgeParent(), !pendingRemotetextures);
   1575        mAsyncImageManager->ApplyAsyncImageForPipeline(
   1576            op.pipelineId(), aTxn, txnForImageBridge, pendingOps,
   1577            pendingRemotetextures);
   1578        break;
   1579      }
   1580      case WebRenderParentCommand::TOpUpdatedAsyncImagePipeline: {
   1581        const OpUpdatedAsyncImagePipeline& op =
   1582            cmd.get_OpUpdatedAsyncImagePipeline();
   1583        aTxn.InvalidateRenderedFrame(wr::RenderReasons::ASYNC_IMAGE);
   1584 
   1585        auto* pendingOps = mApi->GetPendingAsyncImagePipelineOps(aTxn);
   1586        auto* pendingRemotetextures = mApi->GetPendingRemoteTextureInfoList();
   1587 
   1588        MOZ_ASSERT_IF(IsRootWebRenderBridgeParent(), !pendingRemotetextures);
   1589        mAsyncImageManager->ApplyAsyncImageForPipeline(
   1590            op.pipelineId(), aTxn, txnForImageBridge, pendingOps,
   1591            pendingRemotetextures);
   1592        break;
   1593      }
   1594      case WebRenderParentCommand::TCompositableOperation: {
   1595        if (!ReceiveCompositableUpdate(cmd.get_CompositableOperation())) {
   1596          NS_ERROR("ReceiveCompositableUpdate failed");
   1597        }
   1598        break;
   1599      }
   1600      case WebRenderParentCommand::TOpAddCompositorAnimations: {
   1601        const OpAddCompositorAnimations& op =
   1602            cmd.get_OpAddCompositorAnimations();
   1603        CompositorAnimations data(std::move(op.data()));
   1604        // AnimationHelper::GetNextCompositorAnimationsId() encodes the child
   1605        // process PID in the upper 32 bits of the id, verify that this is as
   1606        // expected.
   1607        if ((data.id() >> 32) != (uint64_t)OtherPid()) {
   1608          gfxCriticalNote << "TOpAddCompositorAnimations bad id";
   1609          success = false;
   1610          continue;
   1611        }
   1612        if (data.animations().Length()) {
   1613          if (RefPtr<OMTASampler> sampler = GetOMTASampler()) {
   1614            sampler->SetAnimations(data.id(), GetLayersId(), data.animations());
   1615            const auto activeAnim = mActiveAnimations.find(data.id());
   1616            if (activeAnim == mActiveAnimations.end()) {
   1617              mActiveAnimations.emplace(data.id(), mWrEpoch);
   1618            } else {
   1619              // Update wr::Epoch if the animation already exists.
   1620              activeAnim->second = mWrEpoch;
   1621            }
   1622          }
   1623        }
   1624        break;
   1625      }
   1626      default: {
   1627        // other commands are handle on the child
   1628        break;
   1629      }
   1630    }
   1631  }
   1632 
   1633  MOZ_ASSERT(success);
   1634  return success;
   1635 }
   1636 
   1637 void WebRenderBridgeParent::FlushSceneBuilds() {
   1638  MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
   1639 
   1640  // Since we are sending transactions through the scene builder thread, we need
   1641  // to block until all the inflight transactions have been processed. This
   1642  // flush message blocks until all previously sent scenes have been built
   1643  // and received by the render backend thread.
   1644  mApi->FlushSceneBuilder();
   1645  // The post-swap hook for async-scene-building calls the
   1646  // ScheduleRenderOnCompositorThread function from the scene builder thread,
   1647  // which then triggers a call to ScheduleGenerateFrame() on the compositor
   1648  // thread. But since *this* function is running on the compositor thread,
   1649  // that scheduling will not happen until this call stack unwinds (or we
   1650  // could spin a nested event loop, but that's more messy). Instead, we
   1651  // simulate it ourselves by calling ScheduleGenerateFrame() directly.
   1652  // Note also that the post-swap hook will run and do another
   1653  // ScheduleGenerateFrame() after we unwind here, so we will end up with an
   1654  // extra render/composite that is probably avoidable, but in practice we
   1655  // shouldn't be calling this function all that much in production so this
   1656  // is probably fine. If it becomes an issue we can add more state tracking
   1657  // machinery to optimize it away.
   1658  ScheduleGenerateFrame(wr::RenderReasons::FLUSH);
   1659 }
   1660 
   1661 void WebRenderBridgeParent::FlushFrameGeneration(wr::RenderReasons aReasons) {
   1662  MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
   1663  MOZ_ASSERT(IsRootWebRenderBridgeParent());  // This function is only useful on
   1664                                              // the root WRBP
   1665 
   1666  // This forces a new GenerateFrame transaction to be sent to the render
   1667  // backend thread, if one is pending. This doesn't block on any other threads.
   1668  if (mCompositorScheduler->NeedsComposite()) {
   1669    mCompositorScheduler->CancelCurrentCompositeTask();
   1670    // Update timestamp of scheduler for APZ and animation.
   1671    mCompositorScheduler->UpdateLastComposeTime();
   1672    MaybeGenerateFrame(VsyncId(), /* aForceGenerateFrame */ true,
   1673                       aReasons | wr::RenderReasons::FLUSH);
   1674  }
   1675 }
   1676 
   1677 void WebRenderBridgeParent::FlushFramePresentation() {
   1678  MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
   1679 
   1680  // This sends a message to the render backend thread to send a message
   1681  // to the renderer thread, and waits for that message to be processed. So
   1682  // this effectively blocks on the render backend and renderer threads,
   1683  // following the same codepath that WebRender takes to render and composite
   1684  // a frame.
   1685  mApi->WaitUntilPresentationFlushed();
   1686 }
   1687 
   1688 void WebRenderBridgeParent::DisableNativeCompositor() {
   1689  // Make sure that SceneBuilder thread does not have a task.
   1690  mApi->FlushSceneBuilder();
   1691  // Disable WebRender's native compositor usage
   1692  mApi->EnableNativeCompositor(false);
   1693  // Ensure we generate and render a frame immediately.
   1694  ScheduleForcedGenerateFrame(wr::RenderReasons::CONFIG_CHANGE);
   1695 
   1696  mDisablingNativeCompositor = true;
   1697 }
   1698 
   1699 void WebRenderBridgeParent::UpdateQualitySettings() {
   1700  if (!IsRootWebRenderBridgeParent()) {
   1701    MOZ_ASSERT_UNREACHABLE("unexpected to be called");
   1702    return;
   1703  }
   1704  wr::TransactionBuilder txn(mApi);
   1705  txn.UpdateQualitySettings(gfxVars::ForceSubpixelAAWherePossible());
   1706  mApi->SendTransaction(txn);
   1707 }
   1708 
   1709 void WebRenderBridgeParent::UpdateDebugFlags() {
   1710  if (!IsRootWebRenderBridgeParent()) {
   1711    MOZ_ASSERT_UNREACHABLE("unexpected to be called");
   1712    return;
   1713  }
   1714 
   1715  mApi->UpdateDebugFlags(gfxVars::WebRenderDebugFlags());
   1716 }
   1717 
   1718 void WebRenderBridgeParent::UpdateProfilerUI() {
   1719  if (!IsRootWebRenderBridgeParent()) {
   1720    MOZ_ASSERT_UNREACHABLE("unexpected to be called");
   1721    return;
   1722  }
   1723 
   1724  nsCString uiString = gfxVars::GetWebRenderProfilerUIOrDefault();
   1725  mApi->SetProfilerUI(uiString);
   1726 }
   1727 
   1728 void WebRenderBridgeParent::UpdateParameters() {
   1729  if (!IsRootWebRenderBridgeParent()) {
   1730    MOZ_ASSERT_UNREACHABLE("unexpected to be called");
   1731    return;
   1732  }
   1733 
   1734  uint32_t count = gfxVars::WebRenderBatchingLookback();
   1735  mApi->SetBatchingLookback(count);
   1736  mApi->SetInt(wr::IntParameter::BatchedUploadThreshold,
   1737               gfxVars::WebRenderBatchedUploadThreshold());
   1738  uint32_t slow_cpu_frame = gfxVars::WebRenderSlowCpuFrameThreshold();
   1739  mApi->SetFloat(wr::FloatParameter::SlowCpuFrameThreshold, slow_cpu_frame);
   1740 
   1741  mBlobTileSize = gfxVars::WebRenderBlobTileSize();
   1742 }
   1743 
   1744 void WebRenderBridgeParent::UpdateBoolParameters() {
   1745  if (!IsRootWebRenderBridgeParent()) {
   1746    MOZ_ASSERT_UNREACHABLE("unexpected to be called");
   1747    return;
   1748  }
   1749 
   1750  uint32_t bits = gfxVars::WebRenderBoolParameters();
   1751  uint32_t changedBits = mBoolParameterBits ^ bits;
   1752 
   1753  for (auto paramName : MakeEnumeratedRange(wr::BoolParameter::Sentinel)) {
   1754    uint32_t i = (uint32_t)paramName;
   1755    if (changedBits & (1 << i)) {
   1756      bool value = (bits & (1 << i)) != 0;
   1757      mApi->SetBool(paramName, value);
   1758    }
   1759  }
   1760  mBoolParameterBits = bits;
   1761 }
   1762 
   1763 #if defined(MOZ_WIDGET_ANDROID)
   1764 void WebRenderBridgeParent::RequestScreenPixels(
   1765    UiCompositorControllerParent* aController) {
   1766  mScreenPixelsTarget = aController;
   1767 }
   1768 
   1769 void WebRenderBridgeParent::MaybeCaptureScreenPixels() {
   1770  if (!mScreenPixelsTarget) {
   1771    return;
   1772  }
   1773 
   1774  if (mDestroyed) {
   1775    return;
   1776  }
   1777 
   1778  if (auto* cbp = GetRootCompositorBridgeParent()) {
   1779    cbp->FlushPendingWrTransactionEventsWithWait();
   1780  }
   1781 
   1782  // This function should only get called in the root WRBP.
   1783  MOZ_ASSERT(IsRootWebRenderBridgeParent());
   1784 #  ifdef DEBUG
   1785  CompositorBridgeParent* cbp = GetRootCompositorBridgeParent();
   1786  MOZ_ASSERT(cbp && !cbp->IsPaused());
   1787 #  endif
   1788 
   1789  SurfaceFormat format = SurfaceFormat::R8G8B8A8;  // On android we use RGBA8
   1790  auto client_size = mWidget->GetClientSize();
   1791  size_t buffer_size =
   1792      client_size.width * client_size.height * BytesPerPixel(format);
   1793 
   1794  ipc::Shmem mem;
   1795  if (!mScreenPixelsTarget->AllocPixelBuffer(buffer_size, &mem)) {
   1796    // Failed to alloc shmem, Just bail out.
   1797    return;
   1798  }
   1799 
   1800  IntSize size(client_size.width, client_size.height);
   1801 
   1802  bool needsYFlip = false;
   1803  mApi->Readback(TimeStamp::Now(), size, format,
   1804                 Range<uint8_t>(mem.get<uint8_t>(), buffer_size), &needsYFlip);
   1805 
   1806  (void)mScreenPixelsTarget->SendScreenPixels(
   1807      std::move(mem), ScreenIntSize(client_size.width, client_size.height),
   1808      needsYFlip);
   1809 
   1810  mScreenPixelsTarget = nullptr;
   1811 }
   1812 #endif
   1813 
   1814 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvGetSnapshot(
   1815    NotNull<PTextureParent*> aTexture, bool* aNeedsYFlip) {
   1816  *aNeedsYFlip = false;
   1817  CompositorBridgeParent* cbp = GetRootCompositorBridgeParent();
   1818  if (mDestroyed || !cbp || cbp->IsPaused()) {
   1819    return IPC_OK();
   1820  }
   1821 
   1822  if (auto* cbp = GetRootCompositorBridgeParent()) {
   1823    cbp->FlushPendingWrTransactionEventsWithWait();
   1824  }
   1825 
   1826  LOG("WebRenderBridgeParent::RecvGetSnapshot() PipelineId %" PRIx64
   1827      " Id %" PRIx64 " root %d",
   1828      wr::AsUint64(mPipelineId), wr::AsUint64(mApi->GetId()),
   1829      IsRootWebRenderBridgeParent());
   1830 
   1831  // This function should only get called in the root WRBP. If this function
   1832  // gets called in a non-root WRBP, we will set mForceRendering in this WRBP
   1833  // but it will have no effect because CompositeToTarget (which reads the
   1834  // flag) only gets invoked in the root WRBP. So we assert that this is the
   1835  // root WRBP (i.e. has a non-null mWidget) to catch violations of this rule.
   1836  MOZ_ASSERT(IsRootWebRenderBridgeParent());
   1837 
   1838  RefPtr<TextureHost> texture = TextureHost::AsTextureHost(aTexture);
   1839  if (!texture) {
   1840    // We kill the content process rather than have it continue with an invalid
   1841    // snapshot, that may be too harsh and we could decide to return some sort
   1842    // of error to the child process and let it deal with it...
   1843    return IPC_FAIL_NO_REASON(this);
   1844  }
   1845 
   1846  // XXX Add other TextureHost supports.
   1847  // Only BufferTextureHost is supported now.
   1848  BufferTextureHost* bufferTexture = texture->AsBufferTextureHost();
   1849  if (!bufferTexture) {
   1850    // We kill the content process rather than have it continue with an invalid
   1851    // snapshot, that may be too harsh and we could decide to return some sort
   1852    // of error to the child process and let it deal with it...
   1853    return IPC_FAIL_NO_REASON(this);
   1854  }
   1855 
   1856  TimeStamp start = TimeStamp::Now();
   1857  MOZ_ASSERT(bufferTexture->GetBufferDescriptor().type() ==
   1858             BufferDescriptor::TRGBDescriptor);
   1859  DebugOnly<uint32_t> stride = ImageDataSerializer::GetRGBStride(
   1860      bufferTexture->GetBufferDescriptor().get_RGBDescriptor());
   1861  uint8_t* buffer = bufferTexture->GetBuffer();
   1862  IntSize size = bufferTexture->GetSize();
   1863 
   1864  MOZ_ASSERT(buffer);
   1865  // For now the only formats we get here are RGBA and BGRA, and code below is
   1866  // assuming a bpp of 4. If we allow other formats, the code needs adjusting
   1867  // accordingly.
   1868  MOZ_ASSERT(BytesPerPixel(bufferTexture->GetFormat()) == 4);
   1869  uint32_t buffer_size = size.width * size.height * 4;
   1870 
   1871  // Assert the stride of the buffer is what webrender expects
   1872  MOZ_ASSERT((uint32_t)(size.width * 4) == stride);
   1873 
   1874  FlushSceneBuilds();
   1875  FlushFrameGeneration(wr::RenderReasons::SNAPSHOT);
   1876  mApi->Readback(start, size, bufferTexture->GetFormat(),
   1877                 Range<uint8_t>(buffer, buffer_size), aNeedsYFlip);
   1878 
   1879  return IPC_OK();
   1880 }
   1881 
   1882 void WebRenderBridgeParent::AddPipelineIdForCompositable(
   1883    const wr::PipelineId& aPipelineId, const CompositableHandle& aHandle,
   1884    const CompositableHandleOwner& aOwner, wr::TransactionBuilder& aTxn,
   1885    wr::TransactionBuilder& aTxnForImageBridge) {
   1886  if (mDestroyed) {
   1887    return;
   1888  }
   1889 
   1890  MOZ_ASSERT(mAsyncCompositables.find(wr::AsUint64(aPipelineId)) ==
   1891             mAsyncCompositables.end());
   1892 
   1893  RefPtr<CompositableHost> host;
   1894  switch (aOwner) {
   1895    case CompositableHandleOwner::WebRenderBridge:
   1896      host = FindCompositable(aHandle);
   1897      break;
   1898    case CompositableHandleOwner::ImageBridge: {
   1899      RefPtr<ImageBridgeParent> imageBridge =
   1900          ImageBridgeParent::GetInstance(OtherPid());
   1901      if (!imageBridge) {
   1902        return;
   1903      }
   1904      host = imageBridge->FindCompositable(aHandle);
   1905      break;
   1906    }
   1907  }
   1908 
   1909  if (!host) {
   1910    return;
   1911  }
   1912 
   1913  WebRenderImageHost* wrHost = host->AsWebRenderImageHost();
   1914  MOZ_ASSERT(wrHost);
   1915  if (!wrHost) {
   1916    gfxCriticalNote
   1917        << "Incompatible CompositableHost at WebRenderBridgeParent.";
   1918  }
   1919 
   1920  if (!wrHost) {
   1921    return;
   1922  }
   1923 
   1924  wrHost->SetWrBridge(aPipelineId, this);
   1925  mAsyncCompositables.emplace(wr::AsUint64(aPipelineId), wrHost);
   1926  mAsyncImageManager->AddAsyncImagePipeline(aPipelineId, wrHost);
   1927 
   1928  // If this is being called from WebRenderBridgeParent::RecvSetDisplayList,
   1929  // then aTxn might contain a display list that references pipelines that
   1930  // we just added to the async image manager.
   1931  // If we send the display list alone then WR will not yet have the content for
   1932  // the pipelines and so it will emit errors; the SetEmptyDisplayList call
   1933  // below ensure that we provide its content to WR as part of the same
   1934  // transaction.
   1935  mAsyncImageManager->SetEmptyDisplayList(aPipelineId, aTxn,
   1936                                          aTxnForImageBridge);
   1937 }
   1938 
   1939 void WebRenderBridgeParent::RemovePipelineIdForCompositable(
   1940    const wr::PipelineId& aPipelineId, AsyncImagePipelineOps* aPendingOps,
   1941    wr::TransactionBuilder& aTxn) {
   1942  if (mDestroyed) {
   1943    return;
   1944  }
   1945 
   1946  auto it = mAsyncCompositables.find(wr::AsUint64(aPipelineId));
   1947  if (it == mAsyncCompositables.end()) {
   1948    return;
   1949  }
   1950  RefPtr<WebRenderImageHost>& wrHost = it->second;
   1951 
   1952  wrHost->ClearWrBridge(aPipelineId, this);
   1953  mAsyncImageManager->RemoveAsyncImagePipeline(aPipelineId, aPendingOps, aTxn);
   1954  aTxn.RemovePipeline(aPipelineId);
   1955  mAsyncCompositables.erase(wr::AsUint64(aPipelineId));
   1956 }
   1957 
   1958 void WebRenderBridgeParent::DeleteImage(const ImageKey& aKey,
   1959                                        wr::TransactionBuilder& aUpdates) {
   1960  if (mDestroyed) {
   1961    return;
   1962  }
   1963 
   1964  auto it = mSharedSurfaceIds.find(wr::AsUint64(aKey));
   1965  if (it != mSharedSurfaceIds.end()) {
   1966    mAsyncImageManager->HoldExternalImage(mPipelineId, mWrEpoch, it->second);
   1967    mSharedSurfaceIds.erase(it);
   1968  }
   1969 
   1970  aUpdates.DeleteImage(aKey);
   1971 }
   1972 
   1973 void WebRenderBridgeParent::ReleaseTextureOfImage(const wr::ImageKey& aKey) {
   1974  if (mDestroyed) {
   1975    return;
   1976  }
   1977 
   1978  uint64_t id = wr::AsUint64(aKey);
   1979  CompositableTextureHostRef texture;
   1980  WebRenderTextureHost* wrTexture = nullptr;
   1981 
   1982  auto it = mTextureHosts.find(id);
   1983  if (it != mTextureHosts.end()) {
   1984    wrTexture = (*it).second->AsWebRenderTextureHost();
   1985  }
   1986  if (wrTexture) {
   1987    mAsyncImageManager->HoldExternalImage(mPipelineId, mWrEpoch, wrTexture);
   1988  }
   1989  mTextureHosts.erase(id);
   1990 }
   1991 
   1992 void WebRenderBridgeParent::MaybeNotifyOfLayers(
   1993    wr::TransactionBuilder& aBuilder, bool aWillHaveLayers) {
   1994  if (mLastNotifiedHasLayers == aWillHaveLayers) {
   1995    return;
   1996  }
   1997 
   1998  aBuilder.Notify(wr::Checkpoint::SceneBuilt,
   1999                  MakeUnique<ScheduleObserveLayersUpdate>(
   2000                      mCompositorBridge, GetLayersId(), aWillHaveLayers));
   2001  mLastNotifiedHasLayers = aWillHaveLayers;
   2002 }
   2003 
   2004 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvClearCachedResources() {
   2005  if (mDestroyed) {
   2006    return IPC_OK();
   2007  }
   2008 
   2009  LOG("WebRenderBridgeParent::RecvClearCachedResources() PipelineId %" PRIx64
   2010      " Id %" PRIx64 " root %d",
   2011      wr::AsUint64(mPipelineId), wr::AsUint64(mApi->GetId()),
   2012      IsRootWebRenderBridgeParent());
   2013 
   2014  if (!IsRootWebRenderBridgeParent()) {
   2015    mApi->FlushPendingWrTransactionEventsWithoutWait();
   2016  }
   2017 
   2018  // Clear resources
   2019  wr::TransactionBuilder txn(mApi);
   2020  txn.SetLowPriority(true);
   2021  txn.ClearDisplayList(GetNextWrEpoch(), mPipelineId);
   2022  MaybeNotifyOfLayers(txn, false);
   2023  mApi->SendTransaction(txn);
   2024 
   2025  // Schedule generate frame to clean up Pipeline
   2026  ScheduleGenerateFrame(wr::RenderReasons::CLEAR_RESOURCES);
   2027 
   2028  ClearAnimationResources();
   2029 
   2030  return IPC_OK();
   2031 }
   2032 
   2033 wr::Epoch WebRenderBridgeParent::UpdateWebRender(
   2034    CompositorVsyncScheduler* aScheduler, RefPtr<wr::WebRenderAPI>&& aApi,
   2035    AsyncImagePipelineManager* aImageMgr,
   2036    const TextureFactoryIdentifier& aTextureFactoryIdentifier) {
   2037  MOZ_ASSERT(!IsRootWebRenderBridgeParent());
   2038  MOZ_ASSERT(aScheduler);
   2039  MOZ_ASSERT(aApi);
   2040  MOZ_ASSERT(aImageMgr);
   2041 
   2042  if (mDestroyed) {
   2043    return mWrEpoch;
   2044  }
   2045 
   2046  // Update id name space to identify obsoleted keys.
   2047  // Since usage of invalid keys could cause crash in webrender.
   2048  mIdNamespace = aApi->GetNamespace();
   2049  // XXX Remove it when webrender supports sharing/moving Keys between different
   2050  // webrender instances.
   2051  // XXX It requests client to update/reallocate webrender related resources,
   2052  // but parent side does not wait end of the update.
   2053  // The code could become simpler if we could serialise old keys deallocation
   2054  // and new keys allocation. But we do not do it, it is because client side
   2055  // deallocate old layers/webrender keys after new layers/webrender keys
   2056  // allocation. Without client side's layout refactoring, we could not finish
   2057  // all old layers/webrender keys removals before new layer/webrender keys
   2058  // allocation. In future, we could address the problem.
   2059  (void)SendWrUpdated(mIdNamespace, aTextureFactoryIdentifier);
   2060  CompositorBridgeParentBase* cBridge = mCompositorBridge;
   2061  // XXX Stop to clear resources if webreder supports resources sharing between
   2062  // different webrender instances.
   2063  ClearResources();
   2064  mCompositorBridge = cBridge;
   2065  mCompositorScheduler = aScheduler;
   2066  mApi = aApi;
   2067  mAsyncImageManager = aImageMgr;
   2068 
   2069  // Register pipeline to updated AsyncImageManager.
   2070  mAsyncImageManager->AddPipeline(mPipelineId, this);
   2071 
   2072  LOG("WebRenderBridgeParent::UpdateWebRender() PipelineId %" PRIx64
   2073      " Id %" PRIx64 " root %d",
   2074      wr::AsUint64(mPipelineId), wr::AsUint64(mApi->GetId()),
   2075      IsRootWebRenderBridgeParent());
   2076 
   2077  return GetNextWrEpoch();  // Update webrender epoch
   2078 }
   2079 
   2080 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvInvalidateRenderedFrame() {
   2081  // This function should only get called in the root WRBP
   2082  MOZ_ASSERT(IsRootWebRenderBridgeParent());
   2083  LOG("WebRenderBridgeParent::RecvInvalidateRenderedFrame() PipelineId %" PRIx64
   2084      " Id %" PRIx64 " root %d",
   2085      wr::AsUint64(mPipelineId), wr::AsUint64(mApi->GetId()),
   2086      IsRootWebRenderBridgeParent());
   2087 
   2088  InvalidateRenderedFrame(wr::RenderReasons::WIDGET);
   2089  return IPC_OK();
   2090 }
   2091 
   2092 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvScheduleComposite(
   2093    const wr::RenderReasons& aReasons) {
   2094  LOG("WebRenderBridgeParent::RecvScheduleComposite() PipelineId %" PRIx64
   2095      " Id %" PRIx64 " root %d",
   2096      wr::AsUint64(mPipelineId), wr::AsUint64(mApi->GetId()),
   2097      IsRootWebRenderBridgeParent());
   2098 
   2099  // Caller of LayerManager::ScheduleComposite() expects that it trigger
   2100  // composite. Then we do not want to skip generate frame.
   2101  ScheduleForcedGenerateFrame(aReasons);
   2102  return IPC_OK();
   2103 }
   2104 
   2105 void WebRenderBridgeParent::InvalidateRenderedFrame(
   2106    wr::RenderReasons aReasons) {
   2107  if (mDestroyed) {
   2108    return;
   2109  }
   2110 
   2111  wr::TransactionBuilder fastTxn(mApi, /* aUseSceneBuilderThread */ false);
   2112  fastTxn.InvalidateRenderedFrame(aReasons);
   2113  mApi->SendTransaction(fastTxn);
   2114 }
   2115 
   2116 void WebRenderBridgeParent::ScheduleForcedGenerateFrame(
   2117    wr::RenderReasons aReasons) {
   2118  if (mDestroyed) {
   2119    return;
   2120  }
   2121 
   2122  InvalidateRenderedFrame(aReasons);
   2123  ScheduleGenerateFrame(aReasons);
   2124 }
   2125 
   2126 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvCapture() {
   2127  if (!mDestroyed) {
   2128    mApi->Capture();
   2129  }
   2130  return IPC_OK();
   2131 }
   2132 
   2133 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvStartCaptureSequence(
   2134    const nsACString& aPath, const uint32_t& aFlags) {
   2135  if (!mDestroyed) {
   2136    mApi->StartCaptureSequence(aPath, aFlags);
   2137  }
   2138  return IPC_OK();
   2139 }
   2140 
   2141 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvStopCaptureSequence() {
   2142  if (!mDestroyed) {
   2143    mApi->StopCaptureSequence();
   2144  }
   2145  return IPC_OK();
   2146 }
   2147 
   2148 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvSyncWithCompositor() {
   2149  LOG("WebRenderBridgeParent::RecvSyncWithCompositor() PipelineId %" PRIx64
   2150      " Id %" PRIx64 " root %d",
   2151      wr::AsUint64(mPipelineId), wr::AsUint64(mApi->GetId()),
   2152      IsRootWebRenderBridgeParent());
   2153 
   2154  if (mDestroyed) {
   2155    return IPC_OK();
   2156  }
   2157 
   2158  FlushSceneBuilds();
   2159  if (RefPtr<WebRenderBridgeParent> root = GetRootWebRenderBridgeParent()) {
   2160    root->FlushFrameGeneration(wr::RenderReasons::CONTENT_SYNC);
   2161  }
   2162  FlushFramePresentation();
   2163  // Finally, we force the AsyncImagePipelineManager to handle all the
   2164  // pipeline updates produced in the last step, so that it frees any
   2165  // unneeded textures. Then we can return from this sync IPC call knowing
   2166  // that we've done everything we can to flush stuff on the compositor.
   2167  mAsyncImageManager->ProcessPipelineUpdates();
   2168 
   2169  return IPC_OK();
   2170 }
   2171 
   2172 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvSetConfirmedTargetAPZC(
   2173    const uint64_t& aBlockId, nsTArray<ScrollableLayerGuid>&& aTargets) {
   2174  for (size_t i = 0; i < aTargets.Length(); i++) {
   2175    // Guard against bad data from hijacked child processes
   2176    if (aTargets[i].mLayersId != GetLayersId()) {
   2177      NS_ERROR(
   2178          "Unexpected layers id in RecvSetConfirmedTargetAPZC; dropping "
   2179          "message...");
   2180      return IPC_FAIL(this, "Bad layers id");
   2181    }
   2182  }
   2183 
   2184  if (mDestroyed) {
   2185    return IPC_OK();
   2186  }
   2187  mCompositorBridge->SetConfirmedTargetAPZC(GetLayersId(), aBlockId,
   2188                                            std::move(aTargets));
   2189  return IPC_OK();
   2190 }
   2191 
   2192 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvSetTestSampleTime(
   2193    const TimeStamp& aTime) {
   2194  if (mDestroyed) {
   2195    return IPC_FAIL_NO_REASON(this);
   2196  }
   2197 
   2198  if (!mCompositorBridge->SetTestSampleTime(GetLayersId(), aTime)) {
   2199    return IPC_FAIL_NO_REASON(this);
   2200  }
   2201  if (RefPtr<OMTASampler> sampler = GetOMTASampler()) {
   2202    sampler->EnterTestMode();
   2203  }
   2204 
   2205  return IPC_OK();
   2206 }
   2207 
   2208 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvLeaveTestMode() {
   2209  if (mDestroyed) {
   2210    return IPC_FAIL_NO_REASON(this);
   2211  }
   2212 
   2213  mCompositorBridge->LeaveTestMode(GetLayersId());
   2214  if (RefPtr<OMTASampler> sampler = GetOMTASampler()) {
   2215    sampler->LeaveTestMode();
   2216  }
   2217 
   2218  return IPC_OK();
   2219 }
   2220 
   2221 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvGetAnimationValue(
   2222    const uint64_t& aCompositorAnimationsId, OMTAValue* aValue) {
   2223  if (mDestroyed) {
   2224    return IPC_FAIL_NO_REASON(this);
   2225  }
   2226 
   2227  if (RefPtr<OMTASampler> sampler = GetOMTASampler()) {
   2228    Maybe<TimeStamp> testingTimeStamp;
   2229    if (CompositorBridgeParent* cbp = GetRootCompositorBridgeParent()) {
   2230      testingTimeStamp = cbp->GetTestingTimeStamp();
   2231    }
   2232 
   2233    sampler->SampleForTesting(testingTimeStamp);
   2234    *aValue = sampler->GetOMTAValue(aCompositorAnimationsId);
   2235  }
   2236 
   2237  return IPC_OK();
   2238 }
   2239 
   2240 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvSetAsyncScrollOffset(
   2241    const ScrollableLayerGuid::ViewID& aScrollId, const float& aX,
   2242    const float& aY) {
   2243  if (mDestroyed) {
   2244    return IPC_OK();
   2245  }
   2246  mCompositorBridge->SetTestAsyncScrollOffset(GetLayersId(), aScrollId,
   2247                                              CSSPoint(aX, aY));
   2248  return IPC_OK();
   2249 }
   2250 
   2251 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvSetAsyncZoom(
   2252    const ScrollableLayerGuid::ViewID& aScrollId, const float& aZoom) {
   2253  if (mDestroyed) {
   2254    return IPC_OK();
   2255  }
   2256  mCompositorBridge->SetTestAsyncZoom(GetLayersId(), aScrollId,
   2257                                      LayerToParentLayerScale(aZoom));
   2258  return IPC_OK();
   2259 }
   2260 
   2261 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvFlushApzRepaints() {
   2262  if (mDestroyed) {
   2263    return IPC_OK();
   2264  }
   2265  mCompositorBridge->FlushApzRepaints(GetLayersId());
   2266  return IPC_OK();
   2267 }
   2268 
   2269 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvGetAPZTestData(
   2270    APZTestData* aOutData) {
   2271  if (mDestroyed) {
   2272    return IPC_FAIL_NO_REASON(this);
   2273  }
   2274 
   2275  mCompositorBridge->GetAPZTestData(GetLayersId(), aOutData);
   2276  return IPC_OK();
   2277 }
   2278 
   2279 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvGetFrameUniformity(
   2280    FrameUniformityData* aOutData) {
   2281  if (mDestroyed) {
   2282    return IPC_FAIL_NO_REASON(this);
   2283  }
   2284 
   2285  mCompositorBridge->GetFrameUniformity(GetLayersId(), aOutData);
   2286  return IPC_OK();
   2287 }
   2288 
   2289 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvEndWheelTransaction(
   2290    EndWheelTransactionResolver&& aResolve) {
   2291  if (mDestroyed) {
   2292    return IPC_OK();
   2293  }
   2294  mCompositorBridge->EndWheelTransaction(GetLayersId(), std::move(aResolve));
   2295  return IPC_OK();
   2296 }
   2297 
   2298 void WebRenderBridgeParent::ActorDestroy(ActorDestroyReason aWhy) { Destroy(); }
   2299 
   2300 void WebRenderBridgeParent::ResetPreviousSampleTime() {
   2301  if (RefPtr<OMTASampler> sampler = GetOMTASampler()) {
   2302    sampler->ResetPreviousSampleTime();
   2303  }
   2304 }
   2305 
   2306 RefPtr<OMTASampler> WebRenderBridgeParent::GetOMTASampler() const {
   2307  CompositorBridgeParent* cbp = GetRootCompositorBridgeParent();
   2308  if (!cbp) {
   2309    return nullptr;
   2310  }
   2311  return cbp->GetOMTASampler();
   2312 }
   2313 
   2314 void WebRenderBridgeParent::SetOMTASampleTime() {
   2315  MOZ_ASSERT(IsRootWebRenderBridgeParent());
   2316  if (RefPtr<OMTASampler> sampler = GetOMTASampler()) {
   2317    sampler->SetSampleTime(mCompositorScheduler->GetLastComposeTime().Time());
   2318  }
   2319 }
   2320 
   2321 void WebRenderBridgeParent::RetrySkippedComposite() {
   2322  if (!mSkippedComposite) {
   2323    return;
   2324  }
   2325 
   2326  mSkippedComposite = false;
   2327  if (mCompositorScheduler) {
   2328    mCompositorScheduler->ScheduleComposition(mSkippedCompositeReasons |
   2329                                              RenderReasons::SKIPPED_COMPOSITE);
   2330  }
   2331  mSkippedCompositeReasons = wr::RenderReasons::NONE;
   2332 }
   2333 
   2334 void WebRenderBridgeParent::CompositeToTarget(VsyncId aId,
   2335                                              wr::RenderReasons aReasons,
   2336                                              gfx::DrawTarget* aTarget,
   2337                                              const gfx::IntRect* aRect) {
   2338  // This function should only get called in the root WRBP
   2339  MOZ_ASSERT(IsRootWebRenderBridgeParent());
   2340 
   2341  // The two arguments are part of the CompositorVsyncSchedulerOwner API but in
   2342  // this implementation they should never be non-null.
   2343  MOZ_ASSERT(aTarget == nullptr);
   2344  MOZ_ASSERT(aRect == nullptr);
   2345 
   2346  LOG("WebRenderBridgeParent::CompositeToTarget() PipelineId %" PRIx64
   2347      " Id %" PRIx64 " root %d",
   2348      wr::AsUint64(mPipelineId), wr::AsUint64(mApi->GetId()),
   2349      IsRootWebRenderBridgeParent());
   2350 
   2351  CompositorBridgeParent* cbp = GetRootCompositorBridgeParent();
   2352  uint64_t innerWindowId = cbp ? cbp->GetInnerWindowId() : 0;
   2353  AUTO_PROFILER_MARKER_INNERWINDOWID("CompositeToTarget", GRAPHICS,
   2354                                     innerWindowId);
   2355 
   2356  bool paused = true;
   2357  if (cbp) {
   2358    paused = cbp->IsPaused();
   2359  }
   2360 
   2361  if (paused || !mReceivedDisplayList) {
   2362    ResetPreviousSampleTime();
   2363    mCompositionOpportunityId = mCompositionOpportunityId.Next();
   2364    PROFILER_MARKER_TEXT("Discarded composite", GRAPHICS,
   2365                         MarkerInnerWindowId(innerWindowId),
   2366                         paused ? "Paused"_ns : "No display list"_ns);
   2367    return;
   2368  }
   2369 
   2370  mSkippedComposite =
   2371      wr::RenderThread::Get()->TooManyPendingFrames(mApi->GetId());
   2372 
   2373  if (mSkippedComposite) {
   2374    // Render thread is busy, try next time.
   2375    mSkippedComposite = true;
   2376    mSkippedCompositeReasons = mSkippedCompositeReasons | aReasons;
   2377    ResetPreviousSampleTime();
   2378 
   2379    // Record that we skipped presenting a frame for
   2380    // all pending transactions that have finished scene building.
   2381    for (auto& id : mPendingTransactionIds) {
   2382      if (id.mSceneBuiltTime) {
   2383        id.mSkippedComposites++;
   2384      }
   2385    }
   2386 
   2387    PROFILER_MARKER_TEXT("SkippedComposite", GRAPHICS,
   2388                         MarkerInnerWindowId(innerWindowId),
   2389                         "Too many pending frames");
   2390 
   2391    glean::gfx::skipped_composites.Add(1);
   2392 
   2393    return;
   2394  }
   2395 
   2396  mCompositionOpportunityId = mCompositionOpportunityId.Next();
   2397  MaybeGenerateFrame(aId, /* aForceGenerateFrame */ false, aReasons);
   2398 }
   2399 
   2400 TimeDuration WebRenderBridgeParent::GetVsyncInterval() const {
   2401  // This function should only get called in the root WRBP
   2402  MOZ_ASSERT(IsRootWebRenderBridgeParent());
   2403  if (CompositorBridgeParent* cbp = GetRootCompositorBridgeParent()) {
   2404    return cbp->GetVsyncInterval();
   2405  }
   2406  return TimeDuration();
   2407 }
   2408 
   2409 void WebRenderBridgeParent::MaybeGenerateFrame(VsyncId aId,
   2410                                               bool aForceGenerateFrame,
   2411                                               wr::RenderReasons aReasons) {
   2412  // This function should only get called in the root WRBP
   2413  MOZ_ASSERT(IsRootWebRenderBridgeParent());
   2414  LOG("WebRenderBridgeParent::MaybeGenerateFrame() PipelineId %" PRIx64
   2415      " Id %" PRIx64 " root %d",
   2416      wr::AsUint64(mPipelineId), wr::AsUint64(mApi->GetId()),
   2417      IsRootWebRenderBridgeParent());
   2418 
   2419  if (CompositorBridgeParent* cbp = GetRootCompositorBridgeParent()) {
   2420    // Skip WR render during paused state.
   2421    if (cbp->IsPaused()) {
   2422      TimeStamp now = TimeStamp::Now();
   2423      PROFILER_MARKER_TEXT(
   2424          "SkippedComposite", GRAPHICS,
   2425          MarkerOptions(MarkerInnerWindowId(cbp->GetInnerWindowId()),
   2426                        MarkerTiming::InstantAt(now)),
   2427          "CompositorBridgeParent is paused");
   2428      cbp->NotifyPipelineRendered(mPipelineId, mWrEpoch, VsyncId(), now, now,
   2429                                  now);
   2430      return;
   2431    }
   2432  }
   2433 
   2434  TimeStamp start = TimeStamp::Now();
   2435 
   2436  // Ensure GenerateFrame is handled on the render backend thread rather
   2437  // than going through the scene builder thread. That way we continue
   2438  // generating frames with the old scene even during slow scene builds.
   2439  wr::TransactionBuilder fastTxn(mApi, false /* useSceneBuilderThread */);
   2440  // Handle transaction that is related to DisplayList.
   2441  wr::TransactionBuilder sceneBuilderTxn(mApi);
   2442  wr::AutoTransactionSender sender(mApi, &sceneBuilderTxn);
   2443 
   2444  mAsyncImageManager->SetCompositionInfo(start, mCompositionOpportunityId);
   2445  mAsyncImageManager->ApplyAsyncImagesOfImageBridge(sceneBuilderTxn, fastTxn);
   2446  mAsyncImageManager->SetCompositionInfo(TimeStamp(),
   2447                                         CompositionOpportunityId{});
   2448 
   2449  if (!mAsyncImageManager->GetCompositeUntilTime().IsNull()) {
   2450    // Trigger another CompositeToTarget() call because there might be another
   2451    // frame that we want to generate after this one.
   2452    // It will check if we actually want to generate the frame or not.
   2453    mCompositorScheduler->ScheduleComposition(
   2454        wr::RenderReasons::ASYNC_IMAGE_COMPOSITE_UNTIL);
   2455  }
   2456 
   2457  bool generateFrame = !fastTxn.IsEmpty() || aForceGenerateFrame;
   2458 
   2459  if (mAsyncImageManager->GetAndResetWillGenerateFrame()) {
   2460    aReasons |= wr::RenderReasons::ASYNC_IMAGE;
   2461    generateFrame = true;
   2462  }
   2463 
   2464  if (!generateFrame) {
   2465    // Could skip generating frame now.
   2466    PROFILER_MARKER_TEXT("SkippedComposite", GRAPHICS,
   2467                         MarkerTiming::InstantAt(start),
   2468                         "No reason to generate frame");
   2469    ResetPreviousSampleTime();
   2470    return;
   2471  }
   2472 
   2473  if (RefPtr<OMTASampler> sampler = GetOMTASampler()) {
   2474    if (sampler->HasAnimations()) {
   2475      ScheduleGenerateFrame(wr::RenderReasons::ANIMATED_PROPERTY);
   2476    }
   2477  }
   2478 
   2479  SetOMTASampleTime();
   2480  SetAPZSampleTime();
   2481 
   2482 #if defined(ENABLE_FRAME_LATENCY_LOG)
   2483  auto startTime = TimeStamp::Now();
   2484  mApi->SetFrameStartTime(startTime);
   2485 #endif
   2486 
   2487  const bool present = true;
   2488  const bool tracked = true;
   2489  fastTxn.GenerateFrame(aId, present, tracked, aReasons);
   2490  wr::RenderThread::Get()->IncPendingFrameCount(mApi->GetId(), aId, start);
   2491 
   2492  NeedIncreasedMaxDirtyPageModifier();
   2493 
   2494  mApi->SendTransaction(fastTxn);
   2495 
   2496 #if defined(MOZ_WIDGET_ANDROID)
   2497  MaybeCaptureScreenPixels();
   2498 #endif
   2499 
   2500  mMostRecentComposite = TimeStamp::Now();
   2501 
   2502  // During disabling native compositor, webrender needs to render twice.
   2503  // Otherwise, browser flashes black.
   2504  // XXX better fix?
   2505  if (mDisablingNativeCompositor) {
   2506    mDisablingNativeCompositor = false;
   2507 
   2508    // Ensure we generate and render a frame immediately.
   2509    ScheduleForcedGenerateFrame(aReasons);
   2510  }
   2511 }
   2512 
   2513 void WebRenderBridgeParent::HoldPendingTransactionId(
   2514    const wr::Epoch& aWrEpoch, TransactionId aTransactionId,
   2515    bool aContainsSVGGroup, const VsyncId& aVsyncId,
   2516    const TimeStamp& aVsyncStartTime, const TimeStamp& aRefreshStartTime,
   2517    const TimeStamp& aTxnStartTime, const nsACString& aTxnURL,
   2518    const TimeStamp& aFwdTime, const bool aIsFirstPaint,
   2519    nsTArray<CompositionPayload>&& aPayloads, const bool aUseForTelemetry) {
   2520  MOZ_ASSERT(aTransactionId > LastPendingTransactionId());
   2521  mPendingTransactionIds.push_back(PendingTransactionId(
   2522      aWrEpoch, aTransactionId, aContainsSVGGroup, aVsyncId, aVsyncStartTime,
   2523      aRefreshStartTime, aTxnStartTime, aTxnURL, aFwdTime, aIsFirstPaint,
   2524      aUseForTelemetry, std::move(aPayloads)));
   2525 }
   2526 
   2527 TransactionId WebRenderBridgeParent::LastPendingTransactionId() {
   2528  TransactionId id{0};
   2529  if (!mPendingTransactionIds.empty()) {
   2530    id = mPendingTransactionIds.back().mId;
   2531  }
   2532  return id;
   2533 }
   2534 
   2535 void WebRenderBridgeParent::NotifySceneBuiltForEpoch(
   2536    const wr::Epoch& aEpoch, const TimeStamp& aEndTime) {
   2537  for (auto& id : mPendingTransactionIds) {
   2538    if (id.mEpoch.mHandle == aEpoch.mHandle) {
   2539      id.mSceneBuiltTime = aEndTime;
   2540      break;
   2541    }
   2542  }
   2543 }
   2544 
   2545 void WebRenderBridgeParent::ScheduleFrameAfterSceneBuild(
   2546    RefPtr<const wr::WebRenderPipelineInfo> aInfo) {
   2547  MOZ_ASSERT(IsRootWebRenderBridgeParent());
   2548  if (!mCompositorScheduler) {
   2549    return;
   2550  }
   2551 
   2552  mAsyncImageManager->SetWillGenerateFrame();
   2553 
   2554  // If the scheduler has a composite more recent than our last composite (which
   2555  // we missed), and we're within the threshold ms of the last vsync, then
   2556  // kick of a late composite.
   2557  TimeStamp lastVsync = mCompositorScheduler->GetLastVsyncTime();
   2558  VsyncId lastVsyncId = mCompositorScheduler->GetLastVsyncId();
   2559  if (lastVsyncId == VsyncId() || !mMostRecentComposite ||
   2560      mMostRecentComposite >= lastVsync ||
   2561      ((TimeStamp::Now() - lastVsync).ToMilliseconds() >
   2562       StaticPrefs::gfx_webrender_late_scenebuild_threshold())) {
   2563    mCompositorScheduler->ScheduleComposition(wr::RenderReasons::SCENE);
   2564    return;
   2565  }
   2566 
   2567  // Look through all the pipelines contained within the built scene
   2568  // and check which vsync they initiated from.
   2569  const auto& info = aInfo->Raw();
   2570  for (const auto& epoch : info.epochs) {
   2571    WebRenderBridgeParent* wrBridge = this;
   2572    if (!(epoch.pipeline_id == PipelineId())) {
   2573      wrBridge = mAsyncImageManager->GetWrBridge(epoch.pipeline_id);
   2574    }
   2575 
   2576    if (wrBridge) {
   2577      VsyncId startId = wrBridge->GetVsyncIdForEpoch(epoch.epoch);
   2578      // If any of the pipelines started building on the current vsync (i.e
   2579      // we did all of display list building and scene building within the
   2580      // threshold), then don't do an early composite.
   2581      if (startId == lastVsyncId) {
   2582        mCompositorScheduler->ScheduleComposition(wr::RenderReasons::SCENE);
   2583        return;
   2584      }
   2585    }
   2586  }
   2587 
   2588  CompositeToTarget(mCompositorScheduler->GetLastVsyncId(),
   2589                    wr::RenderReasons::SCENE, nullptr, nullptr);
   2590 }
   2591 
   2592 static void RecordPaintPhaseTelemetry(wr::RendererStats* aStats) {
   2593  if (!aStats || !aStats->full_paint) {
   2594    return;
   2595  }
   2596 
   2597  const double geckoDL = aStats->gecko_display_list_time;
   2598  const double wrDL = aStats->wr_display_list_time;
   2599  const double sceneBuild = aStats->scene_build_time;
   2600  const double frameBuild = aStats->frame_build_time;
   2601  const double totalMs = geckoDL + wrDL + sceneBuild + frameBuild;
   2602 
   2603  // If the total time was >= 16ms, then it's likely we missed a frame due to
   2604  // painting. We bucket these metrics separately.
   2605  const bool isLargePaint = totalMs >= 16.0;
   2606 
   2607  // Split the results based on display list build type, partial or full.
   2608  const bool isFullDisplayList = aStats->full_display_list;
   2609 
   2610  auto AsPercentage = [&](const double aTimeMs) -> double {
   2611    MOZ_ASSERT(aTimeMs <= totalMs);
   2612    return (aTimeMs / totalMs) * 100.0;
   2613  };
   2614 
   2615  auto RecordKey = [&](const nsCString& aKey, const double aTimeMs) -> void {
   2616    const auto val = static_cast<uint32_t>(AsPercentage(aTimeMs));
   2617    if (isFullDisplayList) {
   2618      if (isLargePaint) {
   2619        glean::gfx_content::large_paint_phase_weight_full.Get(aKey)
   2620            .AccumulateSingleSample(val);
   2621      } else {
   2622        glean::gfx_content::small_paint_phase_weight_full.Get(aKey)
   2623            .AccumulateSingleSample(val);
   2624      }
   2625    } else {
   2626      if (isLargePaint) {
   2627        glean::gfx_content::large_paint_phase_weight_partial.Get(aKey)
   2628            .AccumulateSingleSample(val);
   2629      } else {
   2630        glean::gfx_content::small_paint_phase_weight_partial.Get(aKey)
   2631            .AccumulateSingleSample(val);
   2632      }
   2633    }
   2634  };
   2635 
   2636  RecordKey("dl"_ns, geckoDL);
   2637  RecordKey("wrdl"_ns, wrDL);
   2638  RecordKey("sb"_ns, sceneBuild);
   2639  RecordKey("fb"_ns, frameBuild);
   2640 }
   2641 
   2642 void WebRenderBridgeParent::FlushTransactionIdsForEpoch(
   2643    const wr::Epoch& aEpoch, const VsyncId& aCompositeStartId,
   2644    const TimeStamp& aCompositeStartTime, const TimeStamp& aRenderStartTime,
   2645    const TimeStamp& aEndTime, UiCompositorControllerParent* aUiController,
   2646    wr::RendererStats* aStats, nsTArray<FrameStats>& aOutputStats,
   2647    nsTArray<TransactionId>& aOutputTransactions) {
   2648  while (!mPendingTransactionIds.empty()) {
   2649    const auto& transactionId = mPendingTransactionIds.front();
   2650 
   2651    if (aEpoch.mHandle < transactionId.mEpoch.mHandle) {
   2652      break;
   2653    }
   2654 
   2655    if (!IsRootWebRenderBridgeParent() && !mVsyncRate.IsZero() &&
   2656        transactionId.mUseForTelemetry) {
   2657      auto fullPaintTime =
   2658          transactionId.mSceneBuiltTime
   2659              ? transactionId.mSceneBuiltTime - transactionId.mTxnStartTime
   2660              : TimeDuration::FromMilliseconds(0);
   2661 
   2662      int32_t contentFrameTime = RecordContentFrameTime(
   2663          transactionId.mVsyncId, transactionId.mVsyncStartTime,
   2664          transactionId.mTxnStartTime, aCompositeStartId, aEndTime,
   2665          fullPaintTime, mVsyncRate, transactionId.mContainsSVGGroup, true,
   2666          aStats);
   2667 
   2668      RecordPaintPhaseTelemetry(aStats);
   2669 
   2670      if (StaticPrefs::gfx_logging_slow_frames_enabled_AtStartup() &&
   2671          contentFrameTime > 200) {
   2672        aOutputStats.AppendElement(FrameStats(
   2673            transactionId.mId, aCompositeStartTime, aRenderStartTime, aEndTime,
   2674            contentFrameTime,
   2675            aStats ? (double(aStats->resource_upload_time) / 1000000.0) : 0.0,
   2676            transactionId.mTxnStartTime, transactionId.mRefreshStartTime,
   2677            transactionId.mFwdTime, transactionId.mSceneBuiltTime,
   2678            transactionId.mSkippedComposites, transactionId.mTxnURL));
   2679      }
   2680    }
   2681 
   2682 #if defined(ENABLE_FRAME_LATENCY_LOG)
   2683    if (transactionId.mRefreshStartTime) {
   2684      int32_t latencyMs =
   2685          lround((aEndTime - transactionId.mRefreshStartTime).ToMilliseconds());
   2686      printf_stderr(
   2687          "From transaction start to end of generate frame latencyMs %d this "
   2688          "%p\n",
   2689          latencyMs, this);
   2690    }
   2691    if (transactionId.mFwdTime) {
   2692      int32_t latencyMs =
   2693          lround((aEndTime - transactionId.mFwdTime).ToMilliseconds());
   2694      printf_stderr(
   2695          "From forwarding transaction to end of generate frame latencyMs %d "
   2696          "this %p\n",
   2697          latencyMs, this);
   2698    }
   2699 #endif
   2700 
   2701    if (aUiController && transactionId.mIsFirstPaint) {
   2702      aUiController->NotifyFirstPaint();
   2703    }
   2704 
   2705    RecordCompositionPayloadsPresented(aEndTime, transactionId.mPayloads);
   2706 
   2707    aOutputTransactions.AppendElement(transactionId.mId);
   2708    mPendingTransactionIds.pop_front();
   2709  }
   2710 }
   2711 
   2712 LayersId WebRenderBridgeParent::GetLayersId() const {
   2713  return wr::AsLayersId(mPipelineId);
   2714 }
   2715 
   2716 void WebRenderBridgeParent::ScheduleGenerateFrame(wr::RenderReasons aReasons) {
   2717  if (mCompositorScheduler) {
   2718    mAsyncImageManager->SetWillGenerateFrame();
   2719    mCompositorScheduler->ScheduleComposition(aReasons);
   2720  }
   2721 }
   2722 
   2723 void WebRenderBridgeParent::FlushRendering(wr::RenderReasons aReasons,
   2724                                           bool aBlocking) {
   2725  if (mDestroyed) {
   2726    return;
   2727  }
   2728 
   2729  if (aBlocking) {
   2730    FlushSceneBuilds();
   2731    FlushFrameGeneration(aReasons);
   2732    FlushFramePresentation();
   2733  } else {
   2734    ScheduleGenerateFrame(aReasons);
   2735  }
   2736 }
   2737 
   2738 ipc::IPCResult WebRenderBridgeParent::RecvSetDefaultClearColor(
   2739    const uint32_t& aColor) {
   2740  SetClearColor(gfx::DeviceColor::FromABGR(aColor));
   2741  return IPC_OK();
   2742 }
   2743 
   2744 void WebRenderBridgeParent::SetClearColor(const gfx::DeviceColor& aColor) {
   2745  MOZ_ASSERT(IsRootWebRenderBridgeParent());
   2746 
   2747  if (!IsRootWebRenderBridgeParent() || mDestroyed) {
   2748    return;
   2749  }
   2750 
   2751  mApi->SetClearColor(aColor);
   2752 }
   2753 
   2754 void WebRenderBridgeParent::Pause() {
   2755  MOZ_ASSERT(IsRootWebRenderBridgeParent());
   2756  LOG("WebRenderBridgeParent::Pause() PipelineId %" PRIx64 " Id %" PRIx64
   2757      " root %d",
   2758      wr::AsUint64(mPipelineId), wr::AsUint64(mApi->GetId()),
   2759      IsRootWebRenderBridgeParent());
   2760 
   2761  if (!IsRootWebRenderBridgeParent() || mDestroyed) {
   2762    return;
   2763  }
   2764 
   2765  mApi->Pause();
   2766 }
   2767 
   2768 bool WebRenderBridgeParent::Resume() {
   2769  MOZ_ASSERT(IsRootWebRenderBridgeParent());
   2770  LOG("WebRenderBridgeParent::Resume() PipelineId %" PRIx64 " Id %" PRIx64
   2771      " root %d",
   2772      wr::AsUint64(mPipelineId), wr::AsUint64(mApi->GetId()),
   2773      IsRootWebRenderBridgeParent());
   2774 
   2775  if (!IsRootWebRenderBridgeParent() || mDestroyed) {
   2776    return false;
   2777  }
   2778 
   2779  if (!mApi->Resume()) {
   2780    return false;
   2781  }
   2782 
   2783  // Ensure we generate and render a frame immediately.
   2784  ScheduleForcedGenerateFrame(wr::RenderReasons::WIDGET);
   2785  return true;
   2786 }
   2787 
   2788 void WebRenderBridgeParent::ClearResources() {
   2789  if (!mApi) {
   2790    return;
   2791  }
   2792 
   2793  if (!IsRootWebRenderBridgeParent()) {
   2794    mApi->FlushPendingWrTransactionEventsWithoutWait();
   2795  }
   2796 
   2797  LOG("WebRenderBridgeParent::ClearResources() PipelineId %" PRIx64
   2798      " Id %" PRIx64 " root %d",
   2799      wr::AsUint64(mPipelineId), wr::AsUint64(mApi->GetId()),
   2800      IsRootWebRenderBridgeParent());
   2801 
   2802  wr::Epoch wrEpoch = GetNextWrEpoch();
   2803  mReceivedDisplayList = false;
   2804  // Schedule generate frame to clean up Pipeline
   2805  ScheduleGenerateFrame(wr::RenderReasons::CLEAR_RESOURCES);
   2806 
   2807  // WrFontKeys and WrImageKeys are deleted during WebRenderAPI destruction.
   2808  for (const auto& entry : mTextureHosts) {
   2809    WebRenderTextureHost* wrTexture = entry.second->AsWebRenderTextureHost();
   2810    MOZ_ASSERT(wrTexture);
   2811    if (wrTexture) {
   2812      mAsyncImageManager->HoldExternalImage(mPipelineId, wrEpoch, wrTexture);
   2813    }
   2814  }
   2815  mTextureHosts.clear();
   2816 
   2817  for (const auto& entry : mSharedSurfaceIds) {
   2818    mAsyncImageManager->HoldExternalImage(mPipelineId, mWrEpoch, entry.second);
   2819  }
   2820  mSharedSurfaceIds.clear();
   2821 
   2822  mAsyncImageManager->RemovePipeline(mPipelineId, wrEpoch);
   2823 
   2824  wr::TransactionBuilder txn(mApi);
   2825  txn.SetLowPriority(true);
   2826  txn.ClearDisplayList(wrEpoch, mPipelineId);
   2827 
   2828  for (const auto& entry : mAsyncCompositables) {
   2829    wr::PipelineId pipelineId = wr::AsPipelineId(entry.first);
   2830    RefPtr<WebRenderImageHost> host = entry.second;
   2831    host->ClearWrBridge(pipelineId, this);
   2832    mAsyncImageManager->RemoveAsyncImagePipeline(
   2833        pipelineId, /* aPendingOps */ nullptr, txn);
   2834    txn.RemovePipeline(pipelineId);
   2835  }
   2836  mAsyncCompositables.clear();
   2837  txn.RemovePipeline(mPipelineId);
   2838  mApi->SendTransaction(txn);
   2839 
   2840  ClearAnimationResources();
   2841 
   2842  if (IsRootWebRenderBridgeParent()) {
   2843    mCompositorScheduler->Destroy();
   2844    mApi->DestroyRenderer();
   2845  }
   2846 
   2847  mCompositorScheduler = nullptr;
   2848  mAsyncImageManager = nullptr;
   2849  mApi = nullptr;
   2850  mCompositorBridge = nullptr;
   2851 }
   2852 
   2853 void WebRenderBridgeParent::ClearAnimationResources() {
   2854  if (RefPtr<OMTASampler> sampler = GetOMTASampler()) {
   2855    sampler->ClearActiveAnimations(mActiveAnimations);
   2856  }
   2857  mActiveAnimations.clear();
   2858  std::queue<CompositorAnimationIdsForEpoch>().swap(
   2859      mCompositorAnimationsToDelete);  // clear queue
   2860 }
   2861 
   2862 void WebRenderBridgeParent::SendAsyncMessage(
   2863    const nsTArray<AsyncParentMessageData>& aMessage) {
   2864  MOZ_ASSERT_UNREACHABLE("unexpected to be called");
   2865 }
   2866 
   2867 void WebRenderBridgeParent::SendPendingAsyncMessages() {
   2868  MOZ_ASSERT(mCompositorBridge);
   2869  mCompositorBridge->SendPendingAsyncMessages();
   2870 }
   2871 
   2872 void WebRenderBridgeParent::SetAboutToSendAsyncMessages() {
   2873  MOZ_ASSERT(mCompositorBridge);
   2874  mCompositorBridge->SetAboutToSendAsyncMessages();
   2875 }
   2876 
   2877 void WebRenderBridgeParent::NotifyNotUsed(PTextureParent* aTexture,
   2878                                          uint64_t aTransactionId) {
   2879  MOZ_ASSERT_UNREACHABLE("unexpected to be called");
   2880 }
   2881 
   2882 base::ProcessId WebRenderBridgeParent::GetChildProcessId() {
   2883  return OtherPid();
   2884 }
   2885 
   2886 dom::ContentParentId WebRenderBridgeParent::GetContentId() {
   2887  MOZ_ASSERT(mCompositorBridge);
   2888  return mCompositorBridge->GetContentId();
   2889 }
   2890 
   2891 bool WebRenderBridgeParent::IsSameProcess() const {
   2892  return OtherPid() == base::GetCurrentProcId();
   2893 }
   2894 
   2895 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvNewCompositable(
   2896    const CompositableHandle& aHandle, const TextureInfo& aInfo) {
   2897  if (mDestroyed) {
   2898    return IPC_OK();
   2899  }
   2900  if (!AddCompositable(aHandle, aInfo)) {
   2901    return IPC_FAIL_NO_REASON(this);
   2902  }
   2903  return IPC_OK();
   2904 }
   2905 
   2906 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvReleaseCompositable(
   2907    const CompositableHandle& aHandle) {
   2908  if (mDestroyed) {
   2909    return IPC_OK();
   2910  }
   2911  ReleaseCompositable(aHandle);
   2912  return IPC_OK();
   2913 }
   2914 
   2915 TextureFactoryIdentifier WebRenderBridgeParent::GetTextureFactoryIdentifier() {
   2916  MOZ_ASSERT(mApi);
   2917 
   2918 #ifdef XP_WIN
   2919  const bool supportsD3D11NV12 = gfx::DeviceManagerDx::Get()->CanUseNV12();
   2920 #else
   2921  const bool supportsD3D11NV12 = false;
   2922 #endif
   2923 
   2924  TextureFactoryIdentifier ident(
   2925      mApi->GetBackendType(), mApi->GetCompositorType(), XRE_GetProcessType(),
   2926      mApi->GetMaxTextureSize(), mApi->GetUseANGLE(), mApi->GetUseDComp(),
   2927      mApi->GetUseLayerCompositor(), mAsyncImageManager->UseCompositorWnd(),
   2928      false, false, false, supportsD3D11NV12, mApi->GetSyncHandle());
   2929  return ident;
   2930 }
   2931 
   2932 wr::Epoch WebRenderBridgeParent::GetNextWrEpoch() {
   2933  MOZ_RELEASE_ASSERT(mWrEpoch.mHandle != UINT32_MAX);
   2934  mWrEpoch.mHandle++;
   2935  return mWrEpoch;
   2936 }
   2937 
   2938 void WebRenderBridgeParent::RollbackWrEpoch() {
   2939  MOZ_RELEASE_ASSERT(mWrEpoch.mHandle != 0);
   2940  mWrEpoch.mHandle--;
   2941 }
   2942 
   2943 void WebRenderBridgeParent::ExtractImageCompositeNotifications(
   2944    nsTArray<ImageCompositeNotificationInfo>* aNotifications) {
   2945  MOZ_ASSERT(IsRootWebRenderBridgeParent());
   2946  if (mDestroyed) {
   2947    return;
   2948  }
   2949  mAsyncImageManager->FlushImageNotifications(aNotifications);
   2950 }
   2951 
   2952 void WebRenderBridgeParent::FlushPendingWrTransactionEventsWithWait() {
   2953  if (mDestroyed || IsRootWebRenderBridgeParent()) {
   2954    return;
   2955  }
   2956  mApi->FlushPendingWrTransactionEventsWithWait();
   2957 }
   2958 
   2959 RefPtr<WebRenderBridgeParentRef>
   2960 WebRenderBridgeParent::GetWebRenderBridgeParentRef() {
   2961  if (mDestroyed) {
   2962    return nullptr;
   2963  }
   2964 
   2965  if (!mWebRenderBridgeRef) {
   2966    mWebRenderBridgeRef = new WebRenderBridgeParentRef(this);
   2967  }
   2968  return mWebRenderBridgeRef;
   2969 }
   2970 
   2971 WebRenderBridgeParentRef::WebRenderBridgeParentRef(
   2972    WebRenderBridgeParent* aWebRenderBridge)
   2973    : mWebRenderBridge(aWebRenderBridge) {
   2974  MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
   2975  MOZ_ASSERT(mWebRenderBridge);
   2976 }
   2977 
   2978 RefPtr<WebRenderBridgeParent> WebRenderBridgeParentRef::WrBridge() {
   2979  return mWebRenderBridge;
   2980 }
   2981 
   2982 void WebRenderBridgeParentRef::Clear() {
   2983  MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
   2984  mWebRenderBridge = nullptr;
   2985 }
   2986 
   2987 WebRenderBridgeParentRef::~WebRenderBridgeParentRef() {
   2988  MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
   2989  MOZ_ASSERT(!mWebRenderBridge);
   2990 }
   2991 
   2992 }  // namespace mozilla::layers