tor-browser

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

RenderThread.cpp (56033B)


      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 "base/task.h"
      8 #include "GeckoProfiler.h"
      9 #include "gfxPlatform.h"
     10 #include "GLContext.h"
     11 #include "RenderThread.h"
     12 #include "nsThread.h"
     13 #include "nsThreadUtils.h"
     14 #include "transport/runnable_utils.h"
     15 #include "mozilla/BackgroundHangMonitor.h"
     16 #include "mozilla/layers/AsyncImagePipelineManager.h"
     17 #include "mozilla/gfx/gfxVars.h"
     18 #include "mozilla/gfx/GPUParent.h"
     19 #include "mozilla/gfx/GPUProcessManager.h"
     20 #include "mozilla/glean/GfxMetrics.h"
     21 #include "mozilla/layers/CompositorThread.h"
     22 #include "mozilla/layers/CompositorBridgeParent.h"
     23 #include "mozilla/layers/CompositorManagerParent.h"
     24 #include "mozilla/layers/Fence.h"
     25 #include "mozilla/layers/WebRenderBridgeParent.h"
     26 #include "mozilla/layers/SharedSurfacesParent.h"
     27 #include "mozilla/layers/SurfacePool.h"
     28 #include "mozilla/layers/SynchronousTask.h"
     29 #include "mozilla/PerfStats.h"
     30 #include "mozilla/StaticPtr.h"
     31 #include "mozilla/webrender/RendererOGL.h"
     32 #include "mozilla/webrender/RenderTextureHost.h"
     33 #include "mozilla/widget/CompositorWidget.h"
     34 #include "OGLShaderProgram.h"
     35 
     36 #ifdef XP_WIN
     37 #  include "GLContextEGL.h"
     38 #  include "GLLibraryEGL.h"
     39 #  include "mozilla/widget/WinCompositorWindowThread.h"
     40 #  include "mozilla/gfx/DeviceManagerDx.h"
     41 #  include "mozilla/webrender/DCLayerTree.h"
     42 // #  include "nsWindowsHelpers.h"
     43 // #  include <d3d11.h>
     44 #endif
     45 
     46 #ifdef MOZ_WIDGET_ANDROID
     47 #  include "GLLibraryEGL.h"
     48 #  include "mozilla/webrender/RenderAndroidSurfaceTextureHost.h"
     49 #endif
     50 
     51 #ifdef MOZ_WIDGET_GTK
     52 #  include "mozilla/WidgetUtilsGtk.h"
     53 #  include "GLLibraryEGL.h"
     54 #endif
     55 
     56 using namespace mozilla;
     57 
     58 static already_AddRefed<gl::GLContext> CreateGLContext(nsACString& aError);
     59 
     60 MOZ_DEFINE_MALLOC_SIZE_OF(WebRenderRendererMallocSizeOf)
     61 
     62 namespace mozilla::wr {
     63 
     64 LazyLogModule gRenderThreadLog("RenderThread");
     65 // Should be called only on RenderThread, since LazyLogModule is not thread safe
     66 #define LOG(...) MOZ_LOG(gRenderThreadLog, LogLevel::Debug, (__VA_ARGS__))
     67 
     68 static StaticRefPtr<RenderThread> sRenderThread;
     69 static mozilla::BackgroundHangMonitor* sBackgroundHangMonitor;
     70 #ifdef DEBUG
     71 static bool sRenderThreadEverStarted = false;
     72 #endif
     73 size_t RenderThread::sRendererCount = 0;
     74 size_t RenderThread::sActiveRendererCount = 0;
     75 
     76 #if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GTK)
     77 static bool USE_DEDICATED_GLYPH_RASTER_THREAD = true;
     78 #else
     79 static bool USE_DEDICATED_GLYPH_RASTER_THREAD = false;
     80 #endif
     81 
     82 RenderThread::RenderThread(RefPtr<nsIThread> aThread)
     83    : mThread(std::move(aThread)),
     84      mThreadPool(false),
     85      mThreadPoolLP(true),
     86      mChunkPool(wr_chunk_pool_new()),
     87      mGlyphRasterThread(USE_DEDICATED_GLYPH_RASTER_THREAD),
     88      mSingletonGLIsForHardwareWebRender(true),
     89      mBatteryInfo("RenderThread.mBatteryInfo"),
     90      mWindowInfos("RenderThread.mWindowInfos"),
     91      mRenderTextureMapLock("RenderThread.mRenderTextureMapLock"),
     92      mHasShutdown(false),
     93      mHandlingDeviceReset(false),
     94      mHandlingWebRenderError(false) {}
     95 
     96 RenderThread::~RenderThread() {
     97  MOZ_ASSERT(mRenderTexturesDeferred.empty());
     98  wr_chunk_pool_delete(mChunkPool);
     99 }
    100 
    101 // static
    102 RenderThread* RenderThread::Get() { return sRenderThread; }
    103 
    104 // static
    105 void RenderThread::Start(uint32_t aNamespace) {
    106  MOZ_ASSERT(NS_IsMainThread());
    107  MOZ_ASSERT(!sRenderThread);
    108 
    109 #ifdef DEBUG
    110  // Check to ensure nobody will try to ever start us more than once during
    111  // the process' lifetime (in particular after ShutDown).
    112  MOZ_ASSERT(!sRenderThreadEverStarted);
    113  sRenderThreadEverStarted = true;
    114 #endif
    115 
    116  // When the CanvasRenderer thread is disabled, WebGL may be handled on this
    117  // thread, requiring a bigger stack size. See: CanvasManagerParent::Init
    118  //
    119  // This is 4M, which is higher than the default 256K.
    120  // Increased with bug 1753349 to accommodate the `chromium/5359` branch of
    121  // ANGLE, which has large peak stack usage for some pathological shader
    122  // compilations.
    123  //
    124  // Previously increased to 512K to accommodate Mesa in bug 1753340.
    125  //
    126  // Previously increased to 320K to avoid a stack overflow in the
    127  // Intel Vulkan driver initialization in bug 1716120.
    128  //
    129  // Note: we only override it if it's limited already.
    130  uint32_t stackSize = nsIThreadManager::DEFAULT_STACK_SIZE;
    131  if (stackSize && !gfx::gfxVars::SupportsThreadsafeGL()) {
    132    stackSize = std::max(stackSize, 4096U << 10);
    133  }
    134 #if !defined(__OPTIMIZE__)
    135  // swgl's draw_quad_spans will allocate ~1.5MB in no-opt builds
    136  // and the default thread stack size on macOS is 512KB
    137  stackSize = std::max(stackSize, 4 * 1024 * 1024U);
    138 #endif
    139 
    140  RefPtr<nsIThread> thread;
    141  nsresult rv = NS_NewNamedThread(
    142      "Renderer", getter_AddRefs(thread),
    143      NS_NewRunnableFunction(
    144          "Renderer::BackgroundHanSetup",
    145          []() {
    146            sBackgroundHangMonitor = new mozilla::BackgroundHangMonitor(
    147                "Render",
    148                /* Timeout values are powers-of-two to enable us get better
    149                   data. 128ms is chosen for transient hangs because 8Hz should
    150                   be the minimally acceptable goal for Render
    151                   responsiveness (normal goal is 60Hz). */
    152                128,
    153                /* 2048ms is chosen for permanent hangs because it's longer than
    154                 * most Render hangs seen in the wild, but is short enough
    155                 * to not miss getting native hang stacks. */
    156                2048);
    157            nsCOMPtr<nsIThread> thread = NS_GetCurrentThread();
    158            nsThread* nsthread = static_cast<nsThread*>(thread.get());
    159            nsthread->SetUseHangMonitor(true);
    160            nsthread->SetPriority(nsISupportsPriority::PRIORITY_HIGH);
    161          }),
    162      {.stackSize = stackSize});
    163 
    164  if (NS_FAILED(rv)) {
    165    gfxCriticalNote << "Failed to create Renderer thread: "
    166                    << gfx::hexa((uint32_t)rv);
    167    return;
    168  }
    169 
    170  sRenderThread = new RenderThread(thread);
    171  CrashReporter::RegisterAnnotationUSize(
    172      CrashReporter::Annotation::GraphicsNumRenderers, &sRendererCount);
    173  CrashReporter::RegisterAnnotationUSize(
    174      CrashReporter::Annotation::GraphicsNumActiveRenderers,
    175      &sActiveRendererCount);
    176 #ifdef XP_WIN
    177  widget::WinCompositorWindowThread::Start();
    178 #endif
    179  layers::SharedSurfacesParent::Initialize();
    180 
    181  RefPtr<Runnable> runnable = WrapRunnable(
    182      RefPtr<RenderThread>(sRenderThread.get()), &RenderThread::InitDeviceTask);
    183  sRenderThread->PostRunnable(runnable.forget());
    184 }
    185 
    186 // static
    187 void RenderThread::ShutDown() {
    188  MOZ_ASSERT(NS_IsMainThread());
    189  MOZ_ASSERT(sRenderThread);
    190 
    191  {
    192    MutexAutoLock lock(sRenderThread->mRenderTextureMapLock);
    193    sRenderThread->mHasShutdown = true;
    194  }
    195 
    196  RefPtr<Runnable> runnable = WrapRunnable(
    197      RefPtr<RenderThread>(sRenderThread.get()), &RenderThread::ShutDownTask);
    198  sRenderThread->PostRunnable(runnable.forget());
    199 
    200  // This will empty the thread queue and thus run the above runnable while
    201  // spinning the MT event loop.
    202  nsCOMPtr<nsIThread> oldThread = sRenderThread->GetRenderThread();
    203  oldThread->Shutdown();
    204 
    205  layers::SharedSurfacesParent::Shutdown();
    206 
    207 #ifdef XP_WIN
    208  if (widget::WinCompositorWindowThread::Get()) {
    209    widget::WinCompositorWindowThread::ShutDown();
    210  }
    211 #endif
    212 
    213  // We null this out only after we finished shutdown to give everbody the
    214  // chance to check for sRenderThread->mHasShutdown. Hopefully everybody
    215  // checks this before using us!
    216  sRenderThread = nullptr;
    217 }
    218 
    219 extern void ClearAllBlobImageResources();
    220 
    221 void RenderThread::ShutDownTask() {
    222  MOZ_ASSERT(IsInRenderThread());
    223  LOG("RenderThread::ShutDownTask()");
    224 
    225  {
    226    // Clear RenderTextureHosts
    227    MutexAutoLock lock(mRenderTextureMapLock);
    228    mRenderTexturesDeferred.clear();
    229    mRenderTextures.clear();
    230    mSyncObjectNeededRenderTextures.clear();
    231    mRenderTextureOps.clear();
    232  }
    233 
    234  // Let go of our handle to the (internally ref-counted) thread pool.
    235  mThreadPool.Release();
    236  mThreadPoolLP.Release();
    237 
    238  // Releasing on the render thread will allow us to avoid dispatching to remove
    239  // remaining textures from the texture map.
    240  layers::SharedSurfacesParent::ShutdownRenderThread();
    241 
    242 #ifdef XP_WIN
    243  DCLayerTree::Shutdown();
    244 #endif
    245 
    246  ClearAllBlobImageResources();
    247  ClearSingletonGL();
    248  ClearSharedSurfacePool();
    249 }
    250 
    251 // static
    252 bool RenderThread::IsInRenderThread() {
    253  return sRenderThread && sRenderThread->mThread == NS_GetCurrentThread();
    254 }
    255 
    256 // static
    257 already_AddRefed<nsIThread> RenderThread::GetRenderThread() {
    258  nsCOMPtr<nsIThread> thread;
    259  if (sRenderThread) {
    260    thread = sRenderThread->mThread;
    261  }
    262  return thread.forget();
    263 }
    264 
    265 void RenderThread::DoAccumulateMemoryReport(
    266    MemoryReport aReport,
    267    const RefPtr<MemoryReportPromise::Private>& aPromise) {
    268  MOZ_ASSERT(IsInRenderThread());
    269 
    270  for (auto& r : mRenderers) {
    271    r.second->AccumulateMemoryReport(&aReport);
    272  }
    273 
    274  // Note memory used by the shader cache, which is shared across all WR
    275  // instances.
    276  MOZ_ASSERT(aReport.shader_cache == 0);
    277  if (mProgramCache) {
    278    aReport.shader_cache = wr_program_cache_report_memory(
    279        mProgramCache->Raw(), &WebRenderRendererMallocSizeOf);
    280  }
    281 
    282  size_t renderTextureMemory = 0;
    283  {
    284    MutexAutoLock lock(mRenderTextureMapLock);
    285    for (const auto& entry : mRenderTextures) {
    286      renderTextureMemory += entry.second->Bytes();
    287    }
    288  }
    289  aReport.render_texture_hosts = renderTextureMemory;
    290 
    291  aPromise->Resolve(aReport, __func__);
    292 }
    293 
    294 // static
    295 RefPtr<MemoryReportPromise> RenderThread::AccumulateMemoryReport(
    296    MemoryReport aInitial) {
    297  RefPtr<MemoryReportPromise::Private> p =
    298      new MemoryReportPromise::Private(__func__);
    299  MOZ_ASSERT(!IsInRenderThread());
    300  if (!Get()) {
    301    // This happens when the GPU process fails to start and we fall back to the
    302    // basic compositor in the parent process. We could assert against this if
    303    // we made the webrender detection code in gfxPlatform.cpp smarter. See bug
    304    // 1494430 comment 12.
    305    NS_WARNING("No render thread, returning empty memory report");
    306    p->Resolve(aInitial, __func__);
    307    return p;
    308  }
    309 
    310  Get()->PostRunnable(
    311      NewRunnableMethod<MemoryReport, RefPtr<MemoryReportPromise::Private>>(
    312          "wr::RenderThread::DoAccumulateMemoryReport", Get(),
    313          &RenderThread::DoAccumulateMemoryReport, aInitial, p));
    314 
    315  return p;
    316 }
    317 
    318 void RenderThread::SetBatteryInfo(const hal::BatteryInformation& aBatteryInfo) {
    319  MOZ_ASSERT(XRE_IsGPUProcess());
    320 
    321  auto batteryInfo = mBatteryInfo.Lock();
    322  batteryInfo.ref() = Some(aBatteryInfo);
    323 }
    324 
    325 bool RenderThread::GetPowerIsCharging() {
    326  MOZ_ASSERT(XRE_IsGPUProcess());
    327 
    328  auto batteryInfo = mBatteryInfo.Lock();
    329  if (batteryInfo.ref().isSome()) {
    330    return batteryInfo.ref().ref().charging();
    331  }
    332 
    333  gfxCriticalNoteOnce << "BatteryInfo is not set";
    334  MOZ_ASSERT_UNREACHABLE("unexpected to be called");
    335  return false;
    336 }
    337 
    338 void RenderThread::AddRenderer(wr::WindowId aWindowId,
    339                               UniquePtr<RendererOGL> aRenderer) {
    340  MOZ_ASSERT(IsInRenderThread());
    341  LOG("RenderThread::AddRenderer() aWindowId %" PRIx64 "", AsUint64(aWindowId));
    342 
    343  if (mHasShutdown) {
    344    return;
    345  }
    346 
    347  mRenderers[aWindowId] = std::move(aRenderer);
    348  sRendererCount = mRenderers.size();
    349 
    350  auto windows = mWindowInfos.Lock();
    351  windows->emplace(AsUint64(aWindowId), new WindowInfo());
    352  mWrNotifierEventsQueues.emplace(AsUint64(aWindowId),
    353                                  new std::queue<WrNotifierEvent>);
    354 }
    355 
    356 void RenderThread::RemoveRenderer(wr::WindowId aWindowId) {
    357  MOZ_ASSERT(IsInRenderThread());
    358  LOG("RenderThread::RemoveRenderer() aWindowId %" PRIx64 "",
    359      AsUint64(aWindowId));
    360 
    361  if (mHasShutdown) {
    362    return;
    363  }
    364 
    365  mRenderers.erase(aWindowId);
    366  sRendererCount = mRenderers.size();
    367 
    368  if (mRenderers.empty()) {
    369    if (mHandlingDeviceReset) {
    370      ClearSingletonGL();
    371    }
    372    mHandlingDeviceReset = false;
    373    mHandlingWebRenderError = false;
    374  }
    375 
    376  auto windows = mWindowInfos.Lock();
    377  auto it = windows->find(AsUint64(aWindowId));
    378  MOZ_ASSERT(it != windows->end());
    379  windows->erase(it);
    380 
    381  // Defer std::deque<WrNotifierEvent> remove, RemoveRenderer() is called in
    382  // HandleWrNotifierEvents().
    383  RefPtr<Runnable> runnable =
    384      NS_NewRunnableFunction("RenderThread::RemoveRenderer", [aWindowId]() {
    385        auto* self = RenderThread::Get();
    386        auto it = self->mWrNotifierEventsQueues.find(AsUint64(aWindowId));
    387        if (it == self->mWrNotifierEventsQueues.end()) {
    388          return;
    389        }
    390        self->mWrNotifierEventsQueues.erase(it);
    391      });
    392  RenderThread::Get()->PostRunnable(runnable.forget());
    393 }
    394 
    395 RendererOGL* RenderThread::GetRenderer(wr::WindowId aWindowId) {
    396  MOZ_ASSERT(IsInRenderThread());
    397 
    398  auto it = mRenderers.find(aWindowId);
    399  MOZ_ASSERT(it != mRenderers.end());
    400 
    401  if (it == mRenderers.end()) {
    402    return nullptr;
    403  }
    404 
    405  return it->second.get();
    406 }
    407 
    408 size_t RenderThread::RendererCount() const {
    409  MOZ_ASSERT(IsInRenderThread());
    410  return mRenderers.size();
    411 }
    412 
    413 void RenderThread::UpdateActiveRendererCount() {
    414  MOZ_ASSERT(IsInRenderThread());
    415  size_t num_active = 0;
    416  for (const auto& it : mRenderers) {
    417    if (!it.second->IsPaused()) {
    418      num_active++;
    419    }
    420  }
    421  sActiveRendererCount = num_active;
    422 }
    423 
    424 void RenderThread::WrNotifierEvent_WakeUp(WrWindowId aWindowId,
    425                                          bool aCompositeNeeded) {
    426  auto windows = mWindowInfos.Lock();
    427  auto it = windows->find(AsUint64(aWindowId));
    428  if (it == windows->end()) {
    429    MOZ_ASSERT(false);
    430    return;
    431  }
    432 
    433  WindowInfo* info = it->second.get();
    434 
    435  info->mPendingWrNotifierEvents.emplace(
    436      WrNotifierEvent::WakeUp(aCompositeNeeded));
    437  PostWrNotifierEvents(aWindowId, info);
    438 }
    439 
    440 void RenderThread::WrNotifierEvent_NewFrameReady(
    441    WrWindowId aWindowId, wr::FramePublishId aPublishId,
    442    const wr::FrameReadyParams* aParams) {
    443  auto windows = mWindowInfos.Lock();
    444  auto it = windows->find(AsUint64(aWindowId));
    445  if (it == windows->end()) {
    446    MOZ_ASSERT(false);
    447    return;
    448  }
    449  WindowInfo* info = it->second.get();
    450 
    451  info->mPendingWrNotifierEvents.emplace(
    452      WrNotifierEvent::NewFrameReady(aPublishId, aParams));
    453  PostWrNotifierEvents(aWindowId, info);
    454 }
    455 
    456 void RenderThread::WrNotifierEvent_ExternalEvent(WrWindowId aWindowId,
    457                                                 size_t aRawEvent) {
    458  UniquePtr<RendererEvent> evt(reinterpret_cast<RendererEvent*>(aRawEvent));
    459  {
    460    auto windows = mWindowInfos.Lock();
    461    auto it = windows->find(AsUint64(aWindowId));
    462    if (it == windows->end()) {
    463      MOZ_ASSERT(false);
    464      return;
    465    }
    466    WindowInfo* info = it->second.get();
    467 
    468    info->mPendingWrNotifierEvents.emplace(
    469        WrNotifierEvent::ExternalEvent(std::move(evt)));
    470    PostWrNotifierEvents(aWindowId, info);
    471  }
    472 }
    473 
    474 void RenderThread::PostWrNotifierEvents(WrWindowId aWindowId) {
    475  {
    476    auto windows = mWindowInfos.Lock();
    477    auto it = windows->find(AsUint64(aWindowId));
    478    if (it == windows->end()) {
    479      MOZ_ASSERT(false);
    480      return;
    481    }
    482    WindowInfo* info = it->second.get();
    483    PostWrNotifierEvents(aWindowId, info);
    484  }
    485 }
    486 
    487 void RenderThread::PostWrNotifierEvents(WrWindowId aWindowId,
    488                                        WindowInfo* aInfo) {
    489  // Runnable has already been triggered.
    490  if (aInfo->mWrNotifierEventsRunnable) {
    491    return;
    492  }
    493 
    494  // Runnable has not been triggered yet.
    495  RefPtr<nsIRunnable> runnable = NewRunnableMethod<WrWindowId>(
    496      "RenderThread::HandleWrNotifierEvents", this,
    497      &RenderThread::HandleWrNotifierEvents, aWindowId);
    498  aInfo->mWrNotifierEventsRunnable = runnable;
    499  PostRunnable(runnable.forget());
    500 }
    501 
    502 void RenderThread::HandleWrNotifierEvents(WrWindowId aWindowId) {
    503  MOZ_ASSERT(IsInRenderThread());
    504 
    505  auto eventsIt = mWrNotifierEventsQueues.find(AsUint64(aWindowId));
    506  if (eventsIt == mWrNotifierEventsQueues.end()) {
    507    return;
    508  }
    509  auto* events = eventsIt->second.get();
    510 
    511  {
    512    auto windows = mWindowInfos.Lock();
    513    auto infoIt = windows->find(AsUint64(aWindowId));
    514    if (infoIt == windows->end()) {
    515      MOZ_ASSERT(false);
    516      return;
    517    }
    518    WindowInfo* info = infoIt->second.get();
    519    info->mWrNotifierEventsRunnable = nullptr;
    520 
    521    if (events->empty() && !info->mPendingWrNotifierEvents.empty()) {
    522      events->swap(info->mPendingWrNotifierEvents);
    523    }
    524  }
    525 
    526  bool handleNext = true;
    527 
    528  while (!events->empty() && handleNext) {
    529    auto& front = events->front();
    530    switch (front.mTag) {
    531      case WrNotifierEvent::Tag::WakeUp:
    532        WrNotifierEvent_HandleWakeUp(aWindowId, front.FrameReadyParams());
    533        handleNext = false;
    534        break;
    535      case WrNotifierEvent::Tag::NewFrameReady:
    536        WrNotifierEvent_HandleNewFrameReady(aWindowId, front.PublishId(),
    537                                            front.FrameReadyParams());
    538        handleNext = false;
    539        break;
    540      case WrNotifierEvent::Tag::ExternalEvent:
    541        WrNotifierEvent_HandleExternalEvent(aWindowId, front.ExternalEvent());
    542        break;
    543    }
    544    events->pop();
    545  }
    546 
    547  {
    548    auto windows = mWindowInfos.Lock();
    549    auto it = windows->find(AsUint64(aWindowId));
    550    if (it == windows->end()) {
    551      return;
    552    }
    553    WindowInfo* info = it->second.get();
    554 
    555    if (!events->empty() || !info->mPendingWrNotifierEvents.empty()) {
    556      PostWrNotifierEvents(aWindowId, info);
    557    }
    558  }
    559 }
    560 
    561 void RenderThread::WrNotifierEvent_HandleWakeUp(
    562    wr::WindowId aWindowId, const wr::FrameReadyParams& aParams) {
    563  MOZ_ASSERT(IsInRenderThread());
    564  MOZ_ASSERT(!aParams.tracked);
    565  HandleFrameOneDoc(aWindowId, aParams, Nothing());
    566 }
    567 
    568 void RenderThread::WrNotifierEvent_HandleNewFrameReady(
    569    wr::WindowId aWindowId, wr::FramePublishId aPublishId,
    570    const wr::FrameReadyParams& aParams) {
    571  MOZ_ASSERT(IsInRenderThread());
    572 
    573  HandleFrameOneDoc(aWindowId, aParams, Some(aPublishId));
    574 }
    575 
    576 void RenderThread::WrNotifierEvent_HandleExternalEvent(
    577    wr::WindowId aWindowId, UniquePtr<RendererEvent> aRendererEvent) {
    578  MOZ_ASSERT(IsInRenderThread());
    579 
    580  RunEvent(aWindowId, std::move(aRendererEvent), /* aViaWebRender */ true);
    581 }
    582 
    583 void RenderThread::BeginRecordingForWindow(wr::WindowId aWindowId,
    584                                           const TimeStamp& aRecordingStart,
    585                                           wr::PipelineId aRootPipelineId) {
    586  MOZ_ASSERT(IsInRenderThread());
    587  RendererOGL* renderer = GetRenderer(aWindowId);
    588  MOZ_ASSERT(renderer);
    589 
    590  renderer->BeginRecording(aRecordingStart, aRootPipelineId);
    591 }
    592 
    593 Maybe<layers::FrameRecording> RenderThread::EndRecordingForWindow(
    594    wr::WindowId aWindowId) {
    595  MOZ_ASSERT(IsInRenderThread());
    596 
    597  RendererOGL* renderer = GetRenderer(aWindowId);
    598  MOZ_ASSERT(renderer);
    599  return renderer->EndRecording();
    600 }
    601 
    602 void RenderThread::HandleFrameOneDoc(wr::WindowId aWindowId,
    603                                     const wr::FrameReadyParams& aParams,
    604                                     Maybe<FramePublishId> aPublishId) {
    605  MOZ_ASSERT(IsInRenderThread());
    606 
    607  if (mHasShutdown) {
    608    return;
    609  }
    610 
    611  HandleFrameOneDocInner(aWindowId, aParams, aPublishId);
    612 
    613  if (aParams.tracked) {
    614    DecPendingFrameCount(aWindowId);
    615  }
    616 }
    617 
    618 void RenderThread::HandleFrameOneDocInner(wr::WindowId aWindowId,
    619                                          const wr::FrameReadyParams& aParams,
    620                                          Maybe<FramePublishId> aPublishId) {
    621  if (IsDestroyed(aWindowId)) {
    622    return;
    623  }
    624 
    625  if (mHandlingDeviceReset) {
    626    return;
    627  }
    628 
    629  PendingFrameInfo frame;
    630  if (aParams.tracked) {
    631    // scope lock
    632    auto windows = mWindowInfos.Lock();
    633    auto it = windows->find(AsUint64(aWindowId));
    634    if (it == windows->end()) {
    635      MOZ_ASSERT(false);
    636      return;
    637    }
    638 
    639    WindowInfo* info = it->second.get();
    640    PendingFrameInfo& frameInfo = info->mPendingFrames.front();
    641 
    642    frame = frameInfo;
    643  } else {
    644    // Just give the frame info default values.
    645    frame = {TimeStamp::Now(), VsyncId()};
    646  }
    647 
    648  // Sadly this doesn't include the lock, since we don't have the frame there
    649  // yet.
    650  glean::wr::time_to_render_start.AccumulateRawDuration(TimeStamp::Now() -
    651                                                        frame.mStartTime);
    652 
    653  // It is for ensuring that PrepareForUse() is called before
    654  // RenderTextureHost::Lock().
    655  HandleRenderTextureOps();
    656 
    657  if (aPublishId.isSome()) {
    658    SetFramePublishId(aWindowId, aPublishId.ref());
    659  }
    660 
    661  RendererStats stats = {0};
    662 
    663  UpdateAndRender(aWindowId, frame.mStartId, frame.mStartTime, aParams,
    664                  /* aReadbackSize */ Nothing(),
    665                  /* aReadbackFormat */ Nothing(),
    666                  /* aReadbackBuffer */ Nothing(), &stats);
    667 
    668  // The start time is from WebRenderBridgeParent::CompositeToTarget. From that
    669  // point until now (when the frame is finally pushed to the screen) is
    670  // equivalent to the COMPOSITE_TIME metric in the non-WR codepath.
    671  TimeDuration compositeDuration = TimeStamp::Now() - frame.mStartTime;
    672  mozilla::glean::gfx::composite_time.AccumulateRawDuration(compositeDuration);
    673  PerfStats::RecordMeasurement(PerfStats::Metric::Compositing,
    674                               compositeDuration);
    675  if (stats.frame_build_time > 0.0) {
    676    TimeDuration fbTime =
    677        TimeDuration::FromMilliseconds(stats.frame_build_time);
    678    mozilla::glean::wr::framebuild_time.AccumulateRawDuration(fbTime);
    679    PerfStats::RecordMeasurement(PerfStats::Metric::FrameBuilding, fbTime);
    680  }
    681 }
    682 
    683 void RenderThread::SetClearColor(wr::WindowId aWindowId, wr::ColorF aColor) {
    684  if (mHasShutdown) {
    685    return;
    686  }
    687 
    688  if (!IsInRenderThread()) {
    689    PostRunnable(NewRunnableMethod<wr::WindowId, wr::ColorF>(
    690        "wr::RenderThread::SetClearColor", this, &RenderThread::SetClearColor,
    691        aWindowId, aColor));
    692    return;
    693  }
    694 
    695  if (IsDestroyed(aWindowId)) {
    696    return;
    697  }
    698 
    699  auto it = mRenderers.find(aWindowId);
    700  MOZ_ASSERT(it != mRenderers.end());
    701  if (it != mRenderers.end()) {
    702    wr_renderer_set_clear_color(it->second->GetRenderer(), aColor);
    703  }
    704 }
    705 
    706 void RenderThread::SetProfilerUI(wr::WindowId aWindowId,
    707                                 const nsACString& aUI) {
    708  if (mHasShutdown) {
    709    return;
    710  }
    711 
    712  if (!IsInRenderThread()) {
    713    PostRunnable(NewRunnableMethod<wr::WindowId, nsCString>(
    714        "wr::RenderThread::SetProfilerUI", this, &RenderThread::SetProfilerUI,
    715        aWindowId, nsCString(aUI)));
    716    return;
    717  }
    718 
    719  auto it = mRenderers.find(aWindowId);
    720  if (it != mRenderers.end()) {
    721    it->second->SetProfilerUI(aUI);
    722  }
    723 }
    724 
    725 void RenderThread::PostEvent(wr::WindowId aWindowId,
    726                             UniquePtr<RendererEvent> aEvent) {
    727  PostRunnable(
    728      NewRunnableMethod<wr::WindowId, UniquePtr<RendererEvent>&&, bool>(
    729          "wr::RenderThread::PostEvent", this, &RenderThread::RunEvent,
    730          aWindowId, std::move(aEvent), /* aViaWebRender */ false));
    731 }
    732 
    733 void RenderThread::RunEvent(wr::WindowId aWindowId,
    734                            UniquePtr<RendererEvent> aEvent,
    735                            bool aViaWebRender) {
    736  MOZ_ASSERT(IsInRenderThread());
    737 
    738 #ifndef DEBUG
    739  const auto maxDurationMs = 2 * 1000;
    740  const auto start = TimeStamp::Now();
    741  const auto delayMs = static_cast<uint32_t>(
    742      (start - aEvent->mCreationTimeStamp).ToMilliseconds());
    743  // Check for the delay only if RendererEvent is delivered without using
    744  // WebRender. Its delivery via WebRender can be very slow.
    745  if (aViaWebRender && (delayMs > maxDurationMs)) {
    746    gfxCriticalNote << "Calling " << aEvent->Name()
    747                    << "::Run: is delayed: " << delayMs;
    748  }
    749 #endif
    750 
    751  aEvent->Run(*this, aWindowId);
    752  aEvent = nullptr;
    753 
    754 #ifndef DEBUG
    755  const auto end = TimeStamp::Now();
    756  const auto durationMs = static_cast<uint32_t>((end - start).ToMilliseconds());
    757  if (durationMs > maxDurationMs) {
    758    gfxCriticalNote << "NewRenderer::Run is slow: " << durationMs;
    759  }
    760 #endif
    761 }
    762 
    763 static void NotifyDidRender(layers::CompositorBridgeParent* aBridge,
    764                            const RefPtr<const WebRenderPipelineInfo>& aInfo,
    765                            VsyncId aCompositeStartId,
    766                            TimeStamp aCompositeStart, TimeStamp aRenderStart,
    767                            TimeStamp aEnd, bool aRender,
    768                            RendererStats aStats) {
    769  if (aRender && aBridge->GetWrBridge()) {
    770    // We call this here to mimic the behavior in LayerManagerComposite, as to
    771    // not change what Talos measures. That is, we do not record an empty frame
    772    // as a frame.
    773    aBridge->GetWrBridge()->RecordFrame();
    774  }
    775 
    776  aBridge->NotifyDidRender(aCompositeStartId, aCompositeStart, aRenderStart,
    777                           aEnd, &aStats);
    778 
    779  for (const auto& epoch : aInfo->Raw().epochs) {
    780    aBridge->NotifyPipelineRendered(epoch.pipeline_id, epoch.epoch,
    781                                    aCompositeStartId, aCompositeStart,
    782                                    aRenderStart, aEnd, &aStats);
    783  }
    784 
    785  if (aBridge->GetWrBridge()) {
    786    aBridge->GetWrBridge()->RetrySkippedComposite();
    787  }
    788 }
    789 
    790 static void NotifyDidStartRender(layers::CompositorBridgeParent* aBridge) {
    791  if (aBridge->GetWrBridge()) {
    792    aBridge->GetWrBridge()->RetrySkippedComposite();
    793  }
    794 }
    795 
    796 void RenderThread::SetFramePublishId(wr::WindowId aWindowId,
    797                                     FramePublishId aPublishId) {
    798  MOZ_ASSERT(IsInRenderThread());
    799 
    800  auto it = mRenderers.find(aWindowId);
    801  MOZ_ASSERT(it != mRenderers.end());
    802  if (it == mRenderers.end()) {
    803    return;
    804  }
    805  auto& renderer = it->second;
    806 
    807  renderer->SetFramePublishId(aPublishId);
    808 }
    809 
    810 void RenderThread::UpdateAndRender(
    811    wr::WindowId aWindowId, const VsyncId& aStartId,
    812    const TimeStamp& aStartTime, const wr::FrameReadyParams& aParams,
    813    const Maybe<gfx::IntSize>& aReadbackSize,
    814    const Maybe<wr::ImageFormat>& aReadbackFormat,
    815    const Maybe<Range<uint8_t>>& aReadbackBuffer, RendererStats* aStats,
    816    bool* aNeedsYFlip) {
    817  AUTO_PROFILER_LABEL("RenderThread::UpdateAndRender", GRAPHICS);
    818  MOZ_ASSERT(IsInRenderThread());
    819  MOZ_ASSERT(aParams.render || aReadbackBuffer.isNothing());
    820 
    821  auto it = mRenderers.find(aWindowId);
    822  MOZ_ASSERT(it != mRenderers.end());
    823  if (it == mRenderers.end()) {
    824    return;
    825  }
    826 
    827  TimeStamp start = TimeStamp::Now();
    828 
    829  auto& renderer = it->second;
    830 
    831  std::string markerName = "Composite #" + std::to_string(AsUint64(aWindowId));
    832  AutoProfilerTracing tracingCompositeMarker(
    833      markerName.c_str(), geckoprofiler::category::GRAPHICS,
    834      Some(renderer->GetCompositorBridge()->GetInnerWindowId()));
    835 
    836  bool render = aParams.render;
    837  if (renderer->IsPaused()) {
    838    render = false;
    839  }
    840  LOG("RenderThread::UpdateAndRender() aWindowId %" PRIx64 " aRender %d",
    841      AsUint64(aWindowId), render);
    842 
    843  layers::CompositorThread()->Dispatch(
    844      NewRunnableFunction("NotifyDidStartRenderRunnable", &NotifyDidStartRender,
    845                          renderer->GetCompositorBridge()));
    846 
    847  wr::RenderedFrameId latestFrameId;
    848  if (render) {
    849    latestFrameId = renderer->UpdateAndRender(aReadbackSize, aReadbackFormat,
    850                                              aReadbackBuffer, aNeedsYFlip,
    851                                              aParams, aStats);
    852  } else {
    853    renderer->Update();
    854  }
    855  // Check graphics reset status even when rendering is skipped.
    856  renderer->CheckGraphicsResetStatus(
    857      gfx::DeviceResetDetectPlace::WR_POST_UPDATE,
    858      /* aForce */ false);
    859 
    860  TimeStamp end = TimeStamp::Now();
    861  RefPtr<const WebRenderPipelineInfo> info = renderer->GetLastPipelineInfo();
    862 
    863  layers::CompositorThread()->Dispatch(
    864      NewRunnableFunction("NotifyDidRenderRunnable", &NotifyDidRender,
    865                          renderer->GetCompositorBridge(), info, aStartId,
    866                          aStartTime, start, end, render, *aStats));
    867 
    868  RefPtr<layers::Fence> fence;
    869 
    870  if (latestFrameId.IsValid()) {
    871    fence = renderer->GetAndResetReleaseFence();
    872 
    873    // Wait for GPU after posting NotifyDidRender, since the wait is not
    874    // necessary for the NotifyDidRender.
    875    // The wait is necessary for Textures recycling of AsyncImagePipelineManager
    876    // and for avoiding GPU queue is filled with too much tasks.
    877    // WaitForGPU's implementation is different for each platform.
    878    auto timerId = glean::wr::gpu_wait_time.Start();
    879    renderer->WaitForGPU();
    880    glean::wr::gpu_wait_time.StopAndAccumulate(std::move(timerId));
    881  } else {
    882    // Update frame id for NotifyPipelinesUpdated() when rendering does not
    883    // happen, either because rendering was not requested or the frame was
    884    // canceled. Rendering can sometimes be canceled if UpdateAndRender is
    885    // called when the window is not yet ready (not mapped or 0 size).
    886    latestFrameId = renderer->UpdateFrameId();
    887  }
    888 
    889  RenderedFrameId lastCompletedFrameId = renderer->GetLastCompletedFrameId();
    890 
    891  RefPtr<layers::AsyncImagePipelineManager> pipelineMgr =
    892      renderer->GetCompositorBridge()->GetAsyncImagePipelineManager();
    893  // pipelineMgr should always be non-null here because it is only nulled out
    894  // after the WebRenderAPI instance for the CompositorBridgeParent is
    895  // destroyed, and that destruction blocks until the renderer thread has
    896  // removed the relevant renderer. And after that happens we should never reach
    897  // this code at all; it would bail out at the mRenderers.find check above.
    898  MOZ_ASSERT(pipelineMgr);
    899  pipelineMgr->NotifyPipelinesUpdated(info, latestFrameId, lastCompletedFrameId,
    900                                      std::move(fence));
    901 }
    902 
    903 void RenderThread::Pause(wr::WindowId aWindowId) {
    904  MOZ_ASSERT(IsInRenderThread());
    905  LOG("RenderThread::Pause() aWindowId %" PRIx64 "", AsUint64(aWindowId));
    906 
    907  auto it = mRenderers.find(aWindowId);
    908  MOZ_ASSERT(it != mRenderers.end());
    909  if (it == mRenderers.end()) {
    910    gfxCriticalNote << "RenderThread cannot find renderer for window "
    911                    << gfx::hexa(aWindowId) << " to pause.";
    912    return;
    913  }
    914  auto& renderer = it->second;
    915  renderer->Pause();
    916 
    917  UpdateActiveRendererCount();
    918 }
    919 
    920 bool RenderThread::Resume(wr::WindowId aWindowId) {
    921  MOZ_ASSERT(IsInRenderThread());
    922  LOG("enderThread::Resume() aWindowId %" PRIx64 "", AsUint64(aWindowId));
    923 
    924  auto it = mRenderers.find(aWindowId);
    925  MOZ_ASSERT(it != mRenderers.end());
    926  if (it == mRenderers.end()) {
    927    gfxCriticalNote << "RenderThread cannot find renderer for window "
    928                    << gfx::hexa(aWindowId) << " to resume.";
    929    return false;
    930  }
    931  auto& renderer = it->second;
    932  bool resumed = renderer->Resume();
    933 
    934  UpdateActiveRendererCount();
    935 
    936  return resumed;
    937 }
    938 
    939 void RenderThread::NotifyIdle() {
    940  if (!IsInRenderThread()) {
    941    PostRunnable(NewRunnableMethod("RenderThread::NotifyIdle", this,
    942                                   &RenderThread::NotifyIdle));
    943 
    944    return;
    945  }
    946 
    947  wr_chunk_pool_purge(mChunkPool);
    948 }
    949 
    950 bool RenderThread::TooManyPendingFrames(wr::WindowId aWindowId) {
    951  const int64_t maxFrameCount = 1;
    952 
    953  // Too many pending frames if pending frames exit more than maxFrameCount
    954  // or if RenderBackend is still processing a frame.
    955 
    956  auto windows = mWindowInfos.Lock();
    957  auto it = windows->find(AsUint64(aWindowId));
    958  if (it == windows->end()) {
    959    MOZ_ASSERT(false);
    960    return true;
    961  }
    962  WindowInfo* info = it->second.get();
    963 
    964  if (info->PendingCount() > maxFrameCount) {
    965    return true;
    966  }
    967  // If there is no ongoing frame build, we accept a new frame.
    968  return info->mPendingFrameBuild > 0;
    969 }
    970 
    971 bool RenderThread::IsDestroyed(wr::WindowId aWindowId) {
    972  auto windows = mWindowInfos.Lock();
    973  auto it = windows->find(AsUint64(aWindowId));
    974  if (it == windows->end()) {
    975    return true;
    976  }
    977 
    978  return it->second->mIsDestroyed;
    979 }
    980 
    981 void RenderThread::SetDestroyed(wr::WindowId aWindowId) {
    982  auto windows = mWindowInfos.Lock();
    983  auto it = windows->find(AsUint64(aWindowId));
    984  if (it == windows->end()) {
    985    MOZ_ASSERT(false);
    986    return;
    987  }
    988  it->second->mIsDestroyed = true;
    989 }
    990 
    991 void RenderThread::IncPendingFrameCount(wr::WindowId aWindowId,
    992                                        const VsyncId& aStartId,
    993                                        const TimeStamp& aStartTime) {
    994  auto windows = mWindowInfos.Lock();
    995  auto it = windows->find(AsUint64(aWindowId));
    996  if (it == windows->end()) {
    997    MOZ_ASSERT(false);
    998    return;
    999  }
   1000  it->second->mPendingFrameBuild++;
   1001  it->second->mPendingFrames.push(PendingFrameInfo{aStartTime, aStartId});
   1002 }
   1003 
   1004 void RenderThread::DecPendingFrameBuildCount(wr::WindowId aWindowId) {
   1005  auto windows = mWindowInfos.Lock();
   1006  auto it = windows->find(AsUint64(aWindowId));
   1007  if (it == windows->end()) {
   1008    MOZ_ASSERT(false);
   1009    return;
   1010  }
   1011  WindowInfo* info = it->second.get();
   1012  MOZ_RELEASE_ASSERT(info->mPendingFrameBuild >= 1);
   1013  info->mPendingFrameBuild--;
   1014 }
   1015 
   1016 void RenderThread::DecPendingFrameCount(wr::WindowId aWindowId) {
   1017  auto windows = mWindowInfos.Lock();
   1018  auto it = windows->find(AsUint64(aWindowId));
   1019  if (it == windows->end()) {
   1020    MOZ_ASSERT(false);
   1021    return;
   1022  }
   1023  WindowInfo* info = it->second.get();
   1024  info->mPendingFrames.pop();
   1025 }
   1026 
   1027 void RenderThread::RegisterExternalImage(
   1028    const wr::ExternalImageId& aExternalImageId,
   1029    already_AddRefed<RenderTextureHost> aTexture) {
   1030  MutexAutoLock lock(mRenderTextureMapLock);
   1031 
   1032  if (mHasShutdown) {
   1033    return;
   1034  }
   1035  MOZ_ASSERT(mRenderTextures.find(aExternalImageId) == mRenderTextures.end());
   1036  RefPtr<RenderTextureHost> texture = aTexture;
   1037  if (texture->SyncObjectNeeded()) {
   1038    mSyncObjectNeededRenderTextures.emplace(aExternalImageId, texture);
   1039  }
   1040  mRenderTextures.emplace(aExternalImageId, texture);
   1041 
   1042 #ifdef DEBUG
   1043  int32_t maxAllowedIncrease =
   1044      StaticPrefs::gfx_testing_assert_render_textures_increase();
   1045 
   1046  if (maxAllowedIncrease <= 0) {
   1047    mRenderTexturesLastTime = -1;
   1048  } else {
   1049    if (mRenderTexturesLastTime < 0) {
   1050      mRenderTexturesLastTime = static_cast<int32_t>(mRenderTextures.size());
   1051    }
   1052    MOZ_ASSERT((static_cast<int32_t>(mRenderTextures.size()) -
   1053                mRenderTexturesLastTime) < maxAllowedIncrease);
   1054  }
   1055 #endif
   1056 }
   1057 
   1058 void RenderThread::UnregisterExternalImage(
   1059    const wr::ExternalImageId& aExternalImageId) {
   1060  MutexAutoLock lock(mRenderTextureMapLock);
   1061  if (mHasShutdown) {
   1062    return;
   1063  }
   1064  auto it = mRenderTextures.find(aExternalImageId);
   1065  if (it == mRenderTextures.end()) {
   1066    return;
   1067  }
   1068 
   1069  auto& texture = it->second;
   1070  if (texture->SyncObjectNeeded()) {
   1071    MOZ_RELEASE_ASSERT(
   1072        mSyncObjectNeededRenderTextures.erase(aExternalImageId) == 1);
   1073  }
   1074 
   1075  if (!IsInRenderThread()) {
   1076    // The RenderTextureHost should be released in render thread. So, post the
   1077    // deletion task here.
   1078    // The shmem and raw buffer are owned by compositor ipc channel. It's
   1079    // possible that RenderTextureHost is still exist after the shmem/raw buffer
   1080    // deletion. Then the buffer in RenderTextureHost becomes invalid. It's fine
   1081    // for this situation. Gecko will only release the buffer if WR doesn't need
   1082    // it. So, no one will access the invalid buffer in RenderTextureHost.
   1083    RefPtr<RenderTextureHost> texture = it->second;
   1084    mRenderTextures.erase(it);
   1085    mRenderTexturesDeferred.emplace_back(std::move(texture));
   1086    PostRunnable(NewRunnableMethod(
   1087        "RenderThread::DeferredRenderTextureHostDestroy", this,
   1088        &RenderThread::DeferredRenderTextureHostDestroy));
   1089  } else {
   1090    mRenderTextures.erase(it);
   1091  }
   1092 }
   1093 
   1094 void RenderThread::DestroyExternalImagesSyncWait(
   1095    const std::vector<wr::ExternalImageId>&& aIds) {
   1096  if (!IsInRenderThread()) {
   1097    layers::SynchronousTask task("Destroy external images");
   1098 
   1099    RefPtr<Runnable> runnable = NS_NewRunnableFunction(
   1100        "RenderThread::DestroyExternalImagesSyncWait::Runnable",
   1101        [&task, ids = std::move(aIds)]() {
   1102          layers::AutoCompleteTask complete(&task);
   1103          RenderThread::Get()->DestroyExternalImages(std::move(ids));
   1104        });
   1105 
   1106    PostRunnable(runnable.forget());
   1107    task.Wait();
   1108    return;
   1109  }
   1110  DestroyExternalImages(std::move(aIds));
   1111 }
   1112 
   1113 void RenderThread::DestroyExternalImages(
   1114    const std::vector<wr::ExternalImageId>&& aIds) {
   1115  MOZ_ASSERT(IsInRenderThread());
   1116 
   1117  std::vector<RefPtr<RenderTextureHost>> hosts;
   1118  {
   1119    MutexAutoLock lock(mRenderTextureMapLock);
   1120    if (mHasShutdown) {
   1121      return;
   1122    }
   1123 
   1124    for (auto& id : aIds) {
   1125      auto it = mRenderTextures.find(id);
   1126      if (it == mRenderTextures.end()) {
   1127        continue;
   1128      }
   1129      hosts.emplace_back(it->second);
   1130    }
   1131  }
   1132 
   1133  for (auto& host : hosts) {
   1134    host->Destroy();
   1135  }
   1136 }
   1137 
   1138 void RenderThread::PrepareForUse(const wr::ExternalImageId& aExternalImageId) {
   1139  AddRenderTextureOp(RenderTextureOp::PrepareForUse, aExternalImageId);
   1140 }
   1141 
   1142 void RenderThread::NotifyNotUsed(const wr::ExternalImageId& aExternalImageId) {
   1143  AddRenderTextureOp(RenderTextureOp::NotifyNotUsed, aExternalImageId);
   1144 }
   1145 
   1146 void RenderThread::NotifyForUse(const wr::ExternalImageId& aExternalImageId) {
   1147  AddRenderTextureOp(RenderTextureOp::NotifyForUse, aExternalImageId);
   1148 }
   1149 
   1150 void RenderThread::AddRenderTextureOp(
   1151    RenderTextureOp aOp, const wr::ExternalImageId& aExternalImageId) {
   1152  MOZ_ASSERT(!IsInRenderThread());
   1153 
   1154  MutexAutoLock lock(mRenderTextureMapLock);
   1155 
   1156  auto it = mRenderTextures.find(aExternalImageId);
   1157  MOZ_ASSERT(it != mRenderTextures.end());
   1158  if (it == mRenderTextures.end()) {
   1159    return;
   1160  }
   1161 
   1162  RefPtr<RenderTextureHost> texture = it->second;
   1163  mRenderTextureOps.emplace_back(aOp, std::move(texture));
   1164 
   1165  if (mRenderTextureOpsRunnable) {
   1166    // Runnable was already triggered
   1167    return;
   1168  }
   1169 
   1170  RefPtr<nsIRunnable> runnable =
   1171      NewRunnableMethod("RenderThread::HandleRenderTextureOps", this,
   1172                        &RenderThread::HandleRenderTextureOps);
   1173  mRenderTextureOpsRunnable = runnable;
   1174  PostRunnable(runnable.forget());
   1175 }
   1176 
   1177 void RenderThread::HandleRenderTextureOps() {
   1178  MOZ_ASSERT(IsInRenderThread());
   1179 
   1180  std::list<std::pair<RenderTextureOp, RefPtr<RenderTextureHost>>>
   1181      renderTextureOps;
   1182  {
   1183    MutexAutoLock lock(mRenderTextureMapLock);
   1184    mRenderTextureOps.swap(renderTextureOps);
   1185    mRenderTextureOpsRunnable = nullptr;
   1186  }
   1187 
   1188  for (auto& it : renderTextureOps) {
   1189    switch (it.first) {
   1190      case RenderTextureOp::PrepareForUse:
   1191        it.second->PrepareForUse();
   1192        break;
   1193      case RenderTextureOp::NotifyForUse:
   1194        it.second->NotifyForUse();
   1195        break;
   1196      case RenderTextureOp::NotifyNotUsed:
   1197        it.second->NotifyNotUsed();
   1198        break;
   1199    }
   1200  }
   1201 }
   1202 
   1203 RefPtr<RenderTextureHostUsageInfo> RenderThread::GetOrMergeUsageInfo(
   1204    const wr::ExternalImageId& aExternalImageId,
   1205    RefPtr<RenderTextureHostUsageInfo> aUsageInfo) {
   1206  MutexAutoLock lock(mRenderTextureMapLock);
   1207  if (mHasShutdown) {
   1208    return nullptr;
   1209  }
   1210  auto it = mRenderTextures.find(aExternalImageId);
   1211  if (it == mRenderTextures.end()) {
   1212    return nullptr;
   1213  }
   1214 
   1215  auto& texture = it->second;
   1216  return texture->GetOrMergeUsageInfo(lock, aUsageInfo);
   1217 }
   1218 
   1219 void RenderThread::UnregisterExternalImageDuringShutdown(
   1220    const wr::ExternalImageId& aExternalImageId) {
   1221  MOZ_ASSERT(IsInRenderThread());
   1222  MutexAutoLock lock(mRenderTextureMapLock);
   1223  MOZ_ASSERT(mHasShutdown);
   1224  mRenderTextures.erase(aExternalImageId);
   1225 }
   1226 
   1227 bool RenderThread::SyncObjectNeeded() {
   1228  MOZ_ASSERT(IsInRenderThread());
   1229  MutexAutoLock lock(mRenderTextureMapLock);
   1230  return !mSyncObjectNeededRenderTextures.empty();
   1231 }
   1232 
   1233 void RenderThread::DeferredRenderTextureHostDestroy() {
   1234  MutexAutoLock lock(mRenderTextureMapLock);
   1235  mRenderTexturesDeferred.clear();
   1236 }
   1237 
   1238 RenderTextureHost* RenderThread::GetRenderTexture(
   1239    const wr::ExternalImageId& aExternalImageId) {
   1240  MutexAutoLock lock(mRenderTextureMapLock);
   1241  auto it = mRenderTextures.find(aExternalImageId);
   1242  MOZ_ASSERT(it != mRenderTextures.end());
   1243  if (it == mRenderTextures.end()) {
   1244    return nullptr;
   1245  }
   1246  return it->second;
   1247 }
   1248 
   1249 std::tuple<RenderTextureHost*, RefPtr<RenderTextureHostUsageInfo>>
   1250 RenderThread::GetRenderTextureAndUsageInfo(
   1251    const wr::ExternalImageId& aExternalImageId) {
   1252  MutexAutoLock lock(mRenderTextureMapLock);
   1253  auto it = mRenderTextures.find(aExternalImageId);
   1254  MOZ_ASSERT(it != mRenderTextures.end());
   1255  if (it == mRenderTextures.end()) {
   1256    return {};
   1257  }
   1258  return {it->second, it->second->GetTextureHostUsageInfo(lock)};
   1259 }
   1260 
   1261 void RenderThread::InitDeviceTask() {
   1262  MOZ_ASSERT(IsInRenderThread());
   1263  MOZ_ASSERT(!mSingletonGL);
   1264  LOG("RenderThread::InitDeviceTask()");
   1265 
   1266  const auto start = TimeStamp::Now();
   1267 
   1268  if (gfx::gfxVars::UseSoftwareWebRender()) {
   1269    // Ensure we don't instantiate any shared GL context when SW-WR is used.
   1270    return;
   1271  }
   1272 
   1273  nsAutoCString err;
   1274  CreateSingletonGL(err);
   1275  if (gfx::gfxVars::UseWebRenderProgramBinaryDisk()) {
   1276    mProgramCache = MakeUnique<WebRenderProgramCache>(ThreadPool().Raw());
   1277  }
   1278  // Query the shared GL context to force the
   1279  // lazy initialization to happen now.
   1280  SingletonGL();
   1281 
   1282  const auto maxDurationMs = 3 * 1000;
   1283  const auto end = TimeStamp::Now();
   1284  const auto durationMs = static_cast<uint32_t>((end - start).ToMilliseconds());
   1285  if (durationMs > maxDurationMs) {
   1286    gfxCriticalNoteOnce << "RenderThread::InitDeviceTask is slow: "
   1287                        << durationMs;
   1288  }
   1289 }
   1290 
   1291 void RenderThread::BeginShaderWarmupIfNeeded() {
   1292  if (mShaders && gfx::gfxVars::ShouldWarmUpWebRenderProgramBinaries()) {
   1293    PostResumeShaderWarmupRunnable();
   1294  }
   1295 }
   1296 
   1297 void RenderThread::PostResumeShaderWarmupRunnable() {
   1298  RefPtr<Runnable> runnable =
   1299      NewRunnableMethod("RenderThread::ResumeShaderWarmup", this,
   1300                        &RenderThread::ResumeShaderWarmup);
   1301  PostRunnable(runnable.forget());
   1302 }
   1303 
   1304 void RenderThread::ResumeShaderWarmup() {
   1305  if (mShaders) {
   1306    bool needAnotherWarmupStep = mShaders->ResumeWarmup();
   1307    if (needAnotherWarmupStep) {
   1308      PostResumeShaderWarmupRunnable();
   1309    }
   1310  }
   1311 }
   1312 
   1313 void RenderThread::PostRunnable(already_AddRefed<nsIRunnable> aRunnable) {
   1314  nsCOMPtr<nsIRunnable> runnable = aRunnable;
   1315  mThread->Dispatch(runnable.forget());
   1316 }
   1317 
   1318 /* static */ void RenderThread::PostHandleDeviceReset(
   1319    gfx::DeviceResetDetectPlace aPlace, gfx::DeviceResetReason aReason) {
   1320  MOZ_ASSERT(!IsInRenderThread());
   1321  auto* renderThread = Get();
   1322  if (!renderThread) {
   1323    gfx::GPUProcessManager::NotifyDeviceReset(aReason, aPlace);
   1324    return;
   1325  }
   1326 
   1327  renderThread->PostRunnable(
   1328      NewRunnableMethod<gfx::DeviceResetDetectPlace, gfx::DeviceResetReason>(
   1329          "wr::RenderThread::HandleDeviceReset", renderThread,
   1330          &RenderThread::HandleDeviceReset, aPlace, aReason));
   1331 }
   1332 
   1333 void RenderThread::HandleDeviceReset(gfx::DeviceResetDetectPlace aPlace,
   1334                                     gfx::DeviceResetReason aReason) {
   1335  MOZ_ASSERT(IsInRenderThread());
   1336 
   1337  if (mHandlingDeviceReset) {
   1338    return;
   1339  }
   1340 
   1341  mHandlingDeviceReset = true;
   1342 
   1343  {
   1344    MutexAutoLock lock(mRenderTextureMapLock);
   1345    mRenderTexturesDeferred.clear();
   1346    for (const auto& entry : mRenderTextures) {
   1347      entry.second->ClearCachedResources();
   1348    }
   1349  }
   1350 
   1351  gfx::GPUProcessManager::NotifyDeviceReset(aReason, aPlace);
   1352 }
   1353 
   1354 bool RenderThread::IsHandlingDeviceReset() {
   1355  MOZ_ASSERT(IsInRenderThread());
   1356  return mHandlingDeviceReset;
   1357 }
   1358 
   1359 void RenderThread::SimulateDeviceReset() {
   1360  if (!IsInRenderThread()) {
   1361    PostRunnable(NewRunnableMethod("RenderThread::SimulateDeviceReset", this,
   1362                                   &RenderThread::SimulateDeviceReset));
   1363  } else {
   1364    // When this function is called GPUProcessManager::SimulateDeviceReset()
   1365    // already triggers destroying all CompositorSessions before re-creating
   1366    // them.
   1367    HandleDeviceReset(gfx::DeviceResetDetectPlace::WR_SIMULATE,
   1368                      gfx::DeviceResetReason::FORCED_RESET);
   1369  }
   1370 }
   1371 
   1372 static void DoNotifyWebRenderError(WebRenderError aError) {
   1373  layers::CompositorManagerParent::NotifyWebRenderError(aError);
   1374 }
   1375 
   1376 void RenderThread::NotifyWebRenderError(WebRenderError aError) {
   1377  MOZ_ASSERT(IsInRenderThread());
   1378 
   1379  layers::CompositorThread()->Dispatch(NewRunnableFunction(
   1380      "DoNotifyWebRenderErrorRunnable", &DoNotifyWebRenderError, aError));
   1381 }
   1382 
   1383 void RenderThread::HandleWebRenderError(WebRenderError aError) {
   1384  MOZ_ASSERT(IsInRenderThread());
   1385  if (mHandlingWebRenderError) {
   1386    return;
   1387  }
   1388 
   1389  NotifyWebRenderError(aError);
   1390 
   1391  {
   1392    MutexAutoLock lock(mRenderTextureMapLock);
   1393    mRenderTexturesDeferred.clear();
   1394    for (const auto& entry : mRenderTextures) {
   1395      entry.second->ClearCachedResources();
   1396    }
   1397  }
   1398  mHandlingWebRenderError = true;
   1399  // WebRender is going to be disabled by
   1400  // GPUProcessManager::NotifyWebRenderError()
   1401 }
   1402 
   1403 bool RenderThread::IsHandlingWebRenderError() {
   1404  MOZ_ASSERT(IsInRenderThread());
   1405  return mHandlingWebRenderError;
   1406 }
   1407 
   1408 gl::GLContext* RenderThread::SingletonGL() {
   1409  nsAutoCString err;
   1410  auto* gl = SingletonGL(err);
   1411  if (!err.IsEmpty()) {
   1412    gfxCriticalNote << err.get();
   1413  }
   1414  return gl;
   1415 }
   1416 
   1417 void RenderThread::CreateSingletonGL(nsACString& aError) {
   1418  MOZ_ASSERT(IsInRenderThread());
   1419  LOG("RenderThread::CreateSingletonGL()");
   1420 
   1421  mSingletonGL = CreateGLContext(aError);
   1422  mSingletonGLIsForHardwareWebRender = !gfx::gfxVars::UseSoftwareWebRender();
   1423 }
   1424 
   1425 gl::GLContext* RenderThread::SingletonGL(nsACString& aError) {
   1426  MOZ_ASSERT(IsInRenderThread());
   1427  if (!mSingletonGL) {
   1428    CreateSingletonGL(aError);
   1429    mShaders = nullptr;
   1430  }
   1431  if (mSingletonGL && mSingletonGLIsForHardwareWebRender && !mShaders) {
   1432    mShaders = MakeUnique<WebRenderShaders>(mSingletonGL, mProgramCache.get());
   1433  }
   1434 
   1435  return mSingletonGL.get();
   1436 }
   1437 
   1438 gl::GLContext* RenderThread::SingletonGLForCompositorOGL() {
   1439  MOZ_RELEASE_ASSERT(gfx::gfxVars::UseSoftwareWebRender());
   1440 
   1441  if (mSingletonGLIsForHardwareWebRender) {
   1442    // Clear singleton GL, since GLContext is for hardware WebRender.
   1443    ClearSingletonGL();
   1444  }
   1445  return SingletonGL();
   1446 }
   1447 
   1448 void RenderThread::ClearSingletonGL() {
   1449  MOZ_ASSERT(IsInRenderThread());
   1450  LOG("RenderThread::ClearSingletonGL()");
   1451 
   1452  if (mSurfacePool) {
   1453    mSurfacePool->DestroyGLResourcesForContext(mSingletonGL);
   1454  }
   1455  if (mProgramsForCompositorOGL) {
   1456    mProgramsForCompositorOGL->Clear();
   1457    mProgramsForCompositorOGL = nullptr;
   1458  }
   1459  mShaders = nullptr;
   1460  mSingletonGL = nullptr;
   1461 }
   1462 
   1463 RefPtr<layers::ShaderProgramOGLsHolder>
   1464 RenderThread::GetProgramsForCompositorOGL() {
   1465  if (!mSingletonGL) {
   1466    return nullptr;
   1467  }
   1468 
   1469  if (!mProgramsForCompositorOGL) {
   1470    mProgramsForCompositorOGL =
   1471        MakeAndAddRef<layers::ShaderProgramOGLsHolder>(mSingletonGL);
   1472  }
   1473  return mProgramsForCompositorOGL;
   1474 }
   1475 
   1476 RefPtr<layers::SurfacePool> RenderThread::SharedSurfacePool() {
   1477 #if defined(XP_DARWIN) || defined(MOZ_WAYLAND)
   1478  if (!mSurfacePool) {
   1479    size_t poolSizeLimit =
   1480        StaticPrefs::gfx_webrender_compositor_surface_pool_size_AtStartup();
   1481    mSurfacePool = layers::SurfacePool::Create(poolSizeLimit);
   1482  }
   1483 #endif
   1484  return mSurfacePool;
   1485 }
   1486 
   1487 void RenderThread::ClearSharedSurfacePool() { mSurfacePool = nullptr; }
   1488 
   1489 static void GLAPIENTRY DebugMessageCallback(GLenum aSource, GLenum aType,
   1490                                            GLuint aId, GLenum aSeverity,
   1491                                            GLsizei aLength,
   1492                                            const GLchar* aMessage,
   1493                                            const GLvoid* aUserParam) {
   1494  constexpr const char* kContextLost = "Context has been lost.";
   1495 
   1496  if (StaticPrefs::gfx_webrender_gl_debug_message_critical_note_AtStartup() &&
   1497      aSeverity == LOCAL_GL_DEBUG_SEVERITY_HIGH) {
   1498    auto message = std::string(aMessage, aLength);
   1499    // When content lost happned, error messages are flooded by its message.
   1500    if (message != kContextLost) {
   1501      gfxCriticalNote << message;
   1502    } else {
   1503      gfxCriticalNoteOnce << message;
   1504    }
   1505  }
   1506 
   1507  if (StaticPrefs::gfx_webrender_gl_debug_message_print_AtStartup()) {
   1508    gl::GLContext* gl = (gl::GLContext*)aUserParam;
   1509    gl->DebugCallback(aSource, aType, aId, aSeverity, aLength, aMessage);
   1510  }
   1511 }
   1512 
   1513 // static
   1514 void RenderThread::MaybeEnableGLDebugMessage(gl::GLContext* aGLContext) {
   1515  if (!aGLContext) {
   1516    return;
   1517  }
   1518 
   1519  bool enableDebugMessage =
   1520      StaticPrefs::gfx_webrender_gl_debug_message_critical_note_AtStartup() ||
   1521      StaticPrefs::gfx_webrender_gl_debug_message_print_AtStartup();
   1522 
   1523  if (enableDebugMessage &&
   1524      aGLContext->IsExtensionSupported(gl::GLContext::KHR_debug)) {
   1525    aGLContext->fEnable(LOCAL_GL_DEBUG_OUTPUT);
   1526    aGLContext->fDisable(LOCAL_GL_DEBUG_OUTPUT_SYNCHRONOUS);
   1527    aGLContext->fDebugMessageCallback(&DebugMessageCallback, (void*)aGLContext);
   1528    aGLContext->fDebugMessageControl(LOCAL_GL_DONT_CARE, LOCAL_GL_DONT_CARE,
   1529                                     LOCAL_GL_DONT_CARE, 0, nullptr, true);
   1530  }
   1531 }
   1532 
   1533 WebRenderShaders::WebRenderShaders(gl::GLContext* gl,
   1534                                   WebRenderProgramCache* programCache) {
   1535  mGL = gl;
   1536  mShaders =
   1537      wr_shaders_new(gl, programCache ? programCache->Raw() : nullptr,
   1538                     StaticPrefs::gfx_webrender_precache_shaders_AtStartup());
   1539 }
   1540 
   1541 WebRenderShaders::~WebRenderShaders() {
   1542  mGL->MakeCurrent();
   1543  wr_shaders_delete(mShaders);
   1544 }
   1545 
   1546 bool WebRenderShaders::ResumeWarmup() {
   1547  mGL->MakeCurrent();
   1548  return wr_shaders_resume_warmup(mShaders);
   1549 }
   1550 
   1551 WebRenderThreadPool::WebRenderThreadPool(bool low_priority) {
   1552  mThreadPool = wr_thread_pool_new(low_priority);
   1553 }
   1554 
   1555 WebRenderThreadPool::~WebRenderThreadPool() { Release(); }
   1556 
   1557 void WebRenderThreadPool::Release() {
   1558  if (mThreadPool) {
   1559    wr_thread_pool_delete(mThreadPool);
   1560    mThreadPool = nullptr;
   1561  }
   1562 }
   1563 
   1564 MaybeWebRenderGlyphRasterThread::MaybeWebRenderGlyphRasterThread(bool aEnable) {
   1565  if (aEnable) {
   1566    mThread = wr_glyph_raster_thread_new();
   1567  } else {
   1568    mThread = nullptr;
   1569  }
   1570 }
   1571 
   1572 MaybeWebRenderGlyphRasterThread::~MaybeWebRenderGlyphRasterThread() {
   1573  if (mThread) {
   1574    wr_glyph_raster_thread_delete(mThread);
   1575  }
   1576 }
   1577 
   1578 WebRenderProgramCache::WebRenderProgramCache(wr::WrThreadPool* aThreadPool) {
   1579  MOZ_ASSERT(aThreadPool);
   1580 
   1581  nsAutoString path;
   1582  if (gfx::gfxVars::UseWebRenderProgramBinaryDisk()) {
   1583    path.Append(gfx::gfxVars::ProfDirectory());
   1584  }
   1585  mProgramCache = wr_program_cache_new(&path, aThreadPool);
   1586  if (gfx::gfxVars::UseWebRenderProgramBinaryDisk()) {
   1587    wr_try_load_startup_shaders_from_disk(mProgramCache);
   1588  }
   1589 }
   1590 
   1591 WebRenderProgramCache::~WebRenderProgramCache() {
   1592  wr_program_cache_delete(mProgramCache);
   1593 }
   1594 
   1595 }  // namespace mozilla::wr
   1596 
   1597 #ifdef XP_WIN
   1598 static already_AddRefed<gl::GLContext> CreateGLContextANGLE(
   1599    nsACString& aError) {
   1600  const RefPtr<ID3D11Device> d3d11Device =
   1601      gfx::DeviceManagerDx::Get()->GetCompositorDevice();
   1602  if (!d3d11Device) {
   1603    aError.Assign("RcANGLE(no compositor device for EGLDisplay)"_ns);
   1604    return nullptr;
   1605  }
   1606 
   1607  nsCString failureId;
   1608  const auto lib = gl::GLLibraryEGL::Get(&failureId);
   1609  if (!lib) {
   1610    aError.Assign(
   1611        nsPrintfCString("RcANGLE(load EGL lib failed: %s)", failureId.get()));
   1612    return nullptr;
   1613  }
   1614 
   1615  const auto egl = lib->CreateDisplay(d3d11Device.get());
   1616  if (!egl) {
   1617    aError.Assign(nsPrintfCString("RcANGLE(create EGLDisplay failed: %s)",
   1618                                  failureId.get()));
   1619    return nullptr;
   1620  }
   1621 
   1622  gl::CreateContextFlags flags = gl::CreateContextFlags::PREFER_ES3;
   1623 
   1624  if (StaticPrefs::gfx_webrender_prefer_robustness_AtStartup()) {
   1625    flags |= gl::CreateContextFlags::PREFER_ROBUSTNESS;
   1626  }
   1627 
   1628  if (egl->IsExtensionSupported(
   1629          gl::EGLExtension::MOZ_create_context_provoking_vertex_dont_care)) {
   1630    flags |= gl::CreateContextFlags::PROVOKING_VERTEX_DONT_CARE;
   1631  }
   1632 
   1633  // Create GLContext with dummy EGLSurface, the EGLSurface is not used.
   1634  // Instread we override it with EGLSurface of SwapChain's back buffer.
   1635 
   1636  auto gl = gl::GLContextEGL::CreateWithoutSurface(egl, {flags}, &failureId);
   1637  if (!gl || !gl->IsANGLE()) {
   1638    aError.Assign(nsPrintfCString("RcANGLE(create GL context failed: %p, %s)",
   1639                                  gl.get(), failureId.get()));
   1640    return nullptr;
   1641  }
   1642 
   1643  if (!gl->MakeCurrent()) {
   1644    aError.Assign(
   1645        nsPrintfCString("RcANGLE(make current GL context failed: %p, %x)",
   1646                        gl.get(), gl->mEgl->mLib->fGetError()));
   1647    return nullptr;
   1648  }
   1649 
   1650  return gl.forget();
   1651 }
   1652 #endif
   1653 
   1654 #if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GTK)
   1655 static already_AddRefed<gl::GLContext> CreateGLContextEGL() {
   1656  // Create GLContext with dummy EGLSurface.
   1657  bool forHardwareWebRender = true;
   1658  // SW-WR uses CompositorOGL in native compositor.
   1659  if (gfx::gfxVars::UseSoftwareWebRender()) {
   1660    forHardwareWebRender = false;
   1661  }
   1662  RefPtr<gl::GLContext> gl =
   1663      gl::GLContextProviderEGL::CreateForCompositorWidget(
   1664          nullptr, forHardwareWebRender, /* aForceAccelerated */ true);
   1665  if (!gl || !gl->MakeCurrent()) {
   1666    gfxCriticalNote << "Failed GL context creation for hardware WebRender: "
   1667                    << forHardwareWebRender;
   1668    return nullptr;
   1669  }
   1670  return gl.forget();
   1671 }
   1672 #endif
   1673 
   1674 #ifdef XP_DARWIN
   1675 static already_AddRefed<gl::GLContext> CreateGLContextCGL() {
   1676  nsCString failureUnused;
   1677  return gl::GLContextProvider::CreateHeadless(
   1678      {gl::CreateContextFlags::ALLOW_OFFLINE_RENDERER |
   1679       gl::CreateContextFlags::FORBID_SOFTWARE},
   1680      &failureUnused);
   1681 }
   1682 #endif
   1683 
   1684 static already_AddRefed<gl::GLContext> CreateGLContext(nsACString& aError) {
   1685  RefPtr<gl::GLContext> gl;
   1686 
   1687 #ifdef XP_WIN
   1688  if (gfx::gfxVars::UseWebRenderANGLE()) {
   1689    gl = CreateGLContextANGLE(aError);
   1690  }
   1691 #elif defined(MOZ_WIDGET_ANDROID)
   1692  gl = CreateGLContextEGL();
   1693 #elif defined(MOZ_WIDGET_GTK)
   1694  if (gfx::gfxVars::UseEGL()) {
   1695    gl = CreateGLContextEGL();
   1696  }
   1697 #elif XP_DARWIN
   1698  gl = CreateGLContextCGL();
   1699 #endif
   1700 
   1701  wr::RenderThread::MaybeEnableGLDebugMessage(gl);
   1702 
   1703  return gl.forget();
   1704 }
   1705 
   1706 extern "C" {
   1707 
   1708 void wr_notifier_wake_up(mozilla::wr::WrWindowId aWindowId,
   1709                         bool aCompositeNeeded) {
   1710  // wake_up is used for things like propagating debug options or memory
   1711  // pressure events, so we are not tracking pending frame counts.
   1712  mozilla::wr::RenderThread::Get()->WrNotifierEvent_WakeUp(aWindowId,
   1713                                                           aCompositeNeeded);
   1714 }
   1715 
   1716 void wr_notifier_new_frame_ready(wr::WrWindowId aWindowId,
   1717                                 wr::FramePublishId aPublishId,
   1718                                 const wr::FrameReadyParams* aParams) {
   1719  auto* renderThread = mozilla::wr::RenderThread::Get();
   1720  if (aParams->tracked) {
   1721    renderThread->DecPendingFrameBuildCount(aWindowId);
   1722  }
   1723 
   1724  renderThread->WrNotifierEvent_NewFrameReady(aWindowId, aPublishId, aParams);
   1725 }
   1726 
   1727 void wr_notifier_external_event(mozilla::wr::WrWindowId aWindowId,
   1728                                size_t aRawEvent) {
   1729  mozilla::wr::RenderThread::Get()->WrNotifierEvent_ExternalEvent(
   1730      mozilla::wr::WindowId(aWindowId), aRawEvent);
   1731 }
   1732 
   1733 static void NotifyScheduleRender(mozilla::wr::WrWindowId aWindowId,
   1734                                 wr::RenderReasons aReasons) {
   1735  RefPtr<mozilla::layers::CompositorBridgeParent> cbp = mozilla::layers::
   1736      CompositorBridgeParent::GetCompositorBridgeParentFromWindowId(aWindowId);
   1737  if (cbp) {
   1738    cbp->ScheduleComposition(aReasons);
   1739  }
   1740 }
   1741 
   1742 void wr_schedule_render(mozilla::wr::WrWindowId aWindowId,
   1743                        wr::RenderReasons aReasons) {
   1744  layers::CompositorThread()->Dispatch(NewRunnableFunction(
   1745      "NotifyScheduleRender", &NotifyScheduleRender, aWindowId, aReasons));
   1746 }
   1747 
   1748 static void ScheduleFrameAfterSceneBuild(
   1749    mozilla::wr::WrWindowId aWindowId,
   1750    const RefPtr<const wr::WebRenderPipelineInfo>& aInfo) {
   1751  RefPtr<mozilla::layers::CompositorBridgeParent> cbp = mozilla::layers::
   1752      CompositorBridgeParent::GetCompositorBridgeParentFromWindowId(aWindowId);
   1753  if (cbp) {
   1754    cbp->ScheduleFrameAfterSceneBuild(aInfo);
   1755  }
   1756 }
   1757 
   1758 void wr_schedule_frame_after_scene_build(
   1759    mozilla::wr::WrWindowId aWindowId,
   1760    mozilla::wr::WrPipelineInfo* aPipelineInfo) {
   1761  RefPtr<wr::WebRenderPipelineInfo> info = new wr::WebRenderPipelineInfo();
   1762  info->Raw() = std::move(*aPipelineInfo);
   1763  layers::CompositorThread()->Dispatch(
   1764      NewRunnableFunction("ScheduleFrameAfterSceneBuild",
   1765                          &ScheduleFrameAfterSceneBuild, aWindowId, info));
   1766 }
   1767 
   1768 }  // extern C