tor-browser

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

CanvasRenderThread.cpp (6593B)


      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 "CanvasRenderThread.h"
      8 
      9 #include "mozilla/BackgroundHangMonitor.h"
     10 #include "mozilla/SharedThreadPool.h"
     11 #include "mozilla/StaticPrefs_gfx.h"
     12 #include "mozilla/gfx/CanvasManagerParent.h"
     13 #include "mozilla/gfx/gfxVars.h"
     14 #include "mozilla/layers/CanvasTranslator.h"
     15 #include "mozilla/layers/CompositorThread.h"
     16 #include "mozilla/webrender/RenderThread.h"
     17 #include "nsThread.h"
     18 #include "prsystem.h"
     19 #include "transport/runnable_utils.h"
     20 
     21 bool NS_IsInCanvasThreadOrWorker() {
     22  return mozilla::gfx::CanvasRenderThread::IsInCanvasRenderOrWorkerThread();
     23 }
     24 
     25 namespace mozilla::gfx {
     26 
     27 static StaticRefPtr<CanvasRenderThread> sCanvasRenderThread;
     28 static mozilla::BackgroundHangMonitor* sBackgroundHangMonitor;
     29 #ifdef DEBUG
     30 static bool sCanvasRenderThreadEverStarted = false;
     31 #endif
     32 
     33 CanvasRenderThread::CanvasRenderThread(nsCOMPtr<nsIThread>&& aThread,
     34                                       bool aCreatedThread)
     35    : mMutex("CanvasRenderThread::mMutex"),
     36      mThread(std::move(aThread)),
     37      mCreatedThread(aCreatedThread) {}
     38 
     39 CanvasRenderThread::~CanvasRenderThread() = default;
     40 
     41 // static
     42 void CanvasRenderThread::Start() {
     43  MOZ_ASSERT(NS_IsMainThread());
     44  MOZ_ASSERT(!sCanvasRenderThread);
     45 
     46 #ifdef DEBUG
     47  // Check to ensure nobody will try to ever start us more than once during
     48  // the process' lifetime (in particular after Stop).
     49  MOZ_ASSERT(!sCanvasRenderThreadEverStarted);
     50  sCanvasRenderThreadEverStarted = true;
     51 #endif
     52 
     53  nsCOMPtr<nsIThread> thread;
     54  if (!gfxVars::SupportsThreadsafeGL()) {
     55    thread = wr::RenderThread::GetRenderThread();
     56    MOZ_ASSERT(thread);
     57  } else if (!gfxVars::UseCanvasRenderThread()) {
     58    thread = layers::CompositorThread();
     59    MOZ_ASSERT(thread);
     60  }
     61 
     62  if (thread) {
     63    sCanvasRenderThread =
     64        new CanvasRenderThread(std::move(thread), /* aCreatedThread */ false);
     65    return;
     66  }
     67 
     68  // This is 4M, which is higher than the default 256K.
     69  // Increased with bug 1753349 to accommodate the `chromium/5359` branch of
     70  // ANGLE, which has large peak stack usage for some pathological shader
     71  // compilations.
     72  //
     73  // Previously increased to 512K to accommodate Mesa in bug 1753340.
     74  //
     75  // Previously increased to 320K to avoid a stack overflow in the
     76  // Intel Vulkan driver initialization in bug 1716120.
     77  //
     78  // Note: we only override it if it's limited already.
     79  const uint32_t stackSize =
     80      nsIThreadManager::DEFAULT_STACK_SIZE ? 4096 << 10 : 0;
     81 
     82  nsresult rv = NS_NewNamedThread(
     83      "CanvasRenderer", getter_AddRefs(thread),
     84      NS_NewRunnableFunction(
     85          "CanvasRender::BackgroundHangSetup",
     86          []() {
     87            sBackgroundHangMonitor = new mozilla::BackgroundHangMonitor(
     88                "CanvasRendererBHM",
     89                /* Timeout values are powers-of-two to enable us get better
     90                   data. 128ms is chosen for transient hangs because 8Hz should
     91                   be the minimally acceptable goal for Compositor
     92                   responsiveness (normal goal is 60Hz). */
     93                128,
     94                /* 2048ms is chosen for permanent hangs because it's longer than
     95                 * most Compositor hangs seen in the wild, but is short enough
     96                 * to not miss getting native hang stacks. */
     97                2048);
     98            nsCOMPtr<nsIThread> thread = NS_GetCurrentThread();
     99            nsThread* nsthread = static_cast<nsThread*>(thread.get());
    100            nsthread->SetUseHangMonitor(true);
    101            nsthread->SetPriority(nsISupportsPriority::PRIORITY_HIGH);
    102          }),
    103      {.stackSize = stackSize});
    104 
    105  if (NS_WARN_IF(NS_FAILED(rv))) {
    106    return;
    107  }
    108 
    109  sCanvasRenderThread =
    110      new CanvasRenderThread(std::move(thread), /* aCreatedThread */ true);
    111 }
    112 
    113 // static
    114 void CanvasRenderThread::Shutdown() {
    115  MOZ_ASSERT(NS_IsMainThread());
    116 
    117  // It is possible we never initialized this thread in the parent process,
    118  // because we used the GPU process instead.
    119  if (!sCanvasRenderThread) {
    120    MOZ_ASSERT(XRE_IsParentProcess());
    121    return;
    122  }
    123 
    124  // This closes all of the IPDL actors with possibly active task queues.
    125  CanvasManagerParent::Shutdown();
    126 
    127  // Queue any remaining global cleanup for CanvasTranslator
    128  layers::CanvasTranslator::Shutdown();
    129 
    130  bool createdThread = sCanvasRenderThread->mCreatedThread;
    131  nsCOMPtr<nsIThread> oldThread = sCanvasRenderThread->GetCanvasRenderThread();
    132 
    133  // Ensure that we flush the CanvasRenderThread event queue before clearing our
    134  // singleton.
    135  NS_DispatchAndSpinEventLoopUntilComplete(
    136      "CanvasRenderThread::Shutdown"_ns, oldThread,
    137      NS_NewRunnableFunction("CanvasRenderThread::Shutdown", []() -> void {}));
    138 
    139  // Null out sCanvasRenderThread before we enter synchronous Shutdown,
    140  // from here on we are to be considered shut down for our consumers.
    141  sCanvasRenderThread = nullptr;
    142 
    143  // We do a synchronous shutdown here while spinning the MT event loop, but
    144  // only if we created a dedicated CanvasRender thread.
    145  if (createdThread) {
    146    oldThread->Shutdown();
    147  }
    148 }
    149 
    150 // static
    151 bool CanvasRenderThread::IsInCanvasRenderThread() {
    152  return sCanvasRenderThread &&
    153         sCanvasRenderThread->mThread == NS_GetCurrentThread();
    154 }
    155 
    156 /* static */ bool CanvasRenderThread::IsInCanvasWorkerThread() {
    157  // It is possible there are no worker threads, and the worker is the same as
    158  // the CanvasRenderThread itself.
    159  return sCanvasRenderThread &&
    160         sCanvasRenderThread->mThread == NS_GetCurrentThread();
    161 }
    162 
    163 /* static */ bool CanvasRenderThread::IsInCanvasRenderOrWorkerThread() {
    164  // It is possible there are no worker threads, and the worker is the same as
    165  // the CanvasRenderThread itself.
    166  return sCanvasRenderThread &&
    167         sCanvasRenderThread->mThread == NS_GetCurrentThread();
    168 }
    169 
    170 // static
    171 already_AddRefed<nsIThread> CanvasRenderThread::GetCanvasRenderThread() {
    172  nsCOMPtr<nsIThread> thread;
    173  if (sCanvasRenderThread) {
    174    thread = sCanvasRenderThread->mThread;
    175  }
    176  return thread.forget();
    177 }
    178 
    179 /* static */ void CanvasRenderThread::Dispatch(
    180    already_AddRefed<nsIRunnable> aRunnable) {
    181  if (!sCanvasRenderThread) {
    182    MOZ_DIAGNOSTIC_CRASH("Dispatching after CanvasRenderThread shutdown!");
    183    return;
    184  }
    185  sCanvasRenderThread->mThread->Dispatch(std::move(aRunnable));
    186 }
    187 
    188 }  // namespace mozilla::gfx