tor-browser

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

RenderThread.h (19911B)


      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 #ifndef MOZILLA_LAYERS_RENDERTHREAD_H
      8 #define MOZILLA_LAYERS_RENDERTHREAD_H
      9 
     10 #include "base/basictypes.h"       // for DISALLOW_EVIL_CONSTRUCTORS
     11 #include "base/platform_thread.h"  // for PlatformThreadId
     12 #include "base/thread.h"           // for Thread
     13 #include "base/message_loop.h"
     14 #include "GLTypes.h"  // for GLenum
     15 #include "nsISupportsImpl.h"
     16 #include "mozilla/gfx/Point.h"
     17 #include "mozilla/Hal.h"
     18 #include "mozilla/MozPromise.h"
     19 #include "mozilla/DataMutex.h"
     20 #include "mozilla/Maybe.h"
     21 #include "mozilla/webrender/webrender_ffi.h"
     22 #include "mozilla/UniquePtr.h"
     23 #include "mozilla/webrender/WebRenderTypes.h"
     24 #include "mozilla/layers/CompositionRecorder.h"
     25 #include "mozilla/layers/SynchronousTask.h"
     26 #include "mozilla/UniquePtr.h"
     27 #include "mozilla/VsyncDispatcher.h"
     28 
     29 #include <list>
     30 #include <queue>
     31 #include <unordered_map>
     32 
     33 namespace mozilla {
     34 namespace gl {
     35 class GLContext;
     36 }  // namespace gl
     37 namespace layers {
     38 class CompositorBridgeParent;
     39 class Fence;
     40 class ShaderProgramOGLsHolder;
     41 class SurfacePool;
     42 }  // namespace layers
     43 namespace wr {
     44 
     45 typedef MozPromise<MemoryReport, bool, true> MemoryReportPromise;
     46 
     47 class RendererOGL;
     48 class RenderTextureHost;
     49 class RenderTextureHostUsageInfo;
     50 class RenderThread;
     51 
     52 /// A rayon thread pool that is shared by all WebRender instances within a
     53 /// process.
     54 class WebRenderThreadPool {
     55 public:
     56  explicit WebRenderThreadPool(bool low_priority);
     57 
     58  ~WebRenderThreadPool();
     59 
     60  wr::WrThreadPool* Raw() {
     61    // If this pointer is null we are likely at some late shutdown stage,
     62    // when threads are no longer safe to interact with.
     63    MOZ_RELEASE_ASSERT(mThreadPool);
     64    return mThreadPool;
     65  }
     66 
     67  /// Prematurely destroys this handle to the thread pool.
     68  /// After calling this the object is useless.
     69  void Release();
     70 
     71 protected:
     72  wr::WrThreadPool* mThreadPool;
     73 };
     74 
     75 /// An optional dedicated thread for glyph rasterization shared by all WebRender
     76 /// instances within a process.
     77 class MaybeWebRenderGlyphRasterThread {
     78 public:
     79  explicit MaybeWebRenderGlyphRasterThread(bool aEnabled);
     80 
     81  ~MaybeWebRenderGlyphRasterThread();
     82 
     83  bool IsEnabled() const { return mThread != nullptr; }
     84 
     85  const wr::WrGlyphRasterThread* Raw() { return mThread; }
     86 
     87 protected:
     88  wr::WrGlyphRasterThread* mThread;
     89 };
     90 
     91 class WebRenderProgramCache final {
     92 public:
     93  explicit WebRenderProgramCache(wr::WrThreadPool* aThreadPool);
     94 
     95  ~WebRenderProgramCache();
     96 
     97  wr::WrProgramCache* Raw() { return mProgramCache; }
     98 
     99 protected:
    100  wr::WrProgramCache* mProgramCache;
    101 };
    102 
    103 class WebRenderShaders final {
    104 public:
    105  WebRenderShaders(gl::GLContext* gl, WebRenderProgramCache* programCache);
    106  ~WebRenderShaders();
    107 
    108  // Returns true if ResumeWarmup() should be called again
    109  bool ResumeWarmup();
    110 
    111  wr::WrShaders* RawShaders() { return mShaders; }
    112 
    113 protected:
    114  RefPtr<gl::GLContext> mGL;
    115  wr::WrShaders* mShaders;
    116 };
    117 
    118 class WebRenderPipelineInfo final {
    119  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WebRenderPipelineInfo);
    120 
    121  const wr::WrPipelineInfo& Raw() const { return mPipelineInfo; }
    122  wr::WrPipelineInfo& Raw() { return mPipelineInfo; }
    123 
    124 protected:
    125  ~WebRenderPipelineInfo() = default;
    126  wr::WrPipelineInfo mPipelineInfo;
    127 };
    128 
    129 /// Base class for an event that can be scheduled to run on the render thread.
    130 ///
    131 /// The event can be passed through the same channels as regular WebRender
    132 /// messages to preserve ordering.
    133 class RendererEvent {
    134 public:
    135  RendererEvent() : mCreationTimeStamp(TimeStamp::Now()) {}
    136  virtual ~RendererEvent() = default;
    137  virtual void Run(RenderThread& aRenderThread, wr::WindowId aWindow) = 0;
    138  virtual const char* Name() = 0;
    139 
    140  const TimeStamp mCreationTimeStamp;
    141 };
    142 
    143 /// The render thread is where WebRender issues all of its GPU work, and as much
    144 /// as possible this thread should only serve this purpose.
    145 ///
    146 /// The render thread owns the different RendererOGLs (one per window) and
    147 /// implements the RenderNotifier api exposed by the WebRender bindings.
    148 ///
    149 /// Callers are not allowed to post tasks to the render thread's event loop
    150 /// directly and must instead use the RendererEvent mechanism which avoids races
    151 /// between the events and WebRender's own messages.
    152 ///
    153 /// The GL context(s) should be created and used on this thread only.
    154 /// XXX - I've tried to organize code so that we can potentially avoid making
    155 /// this a singleton since this bad habit has a tendency to bite us later, but
    156 /// I haven't gotten all the way there either, in order to focus on the more
    157 /// important pieces first. So we are a bit in-between (this is totally a
    158 /// singleton but in some places we pretend it's not). Hopefully we can evolve
    159 /// this in a way that keeps the door open to removing the singleton bits.
    160 class RenderThread final {
    161  NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_DELETE_ON_MAIN_THREAD(RenderThread)
    162 
    163 public:
    164  /// Can be called from any thread.
    165  static RenderThread* Get();
    166 
    167  /// Can only be called from the main thread.
    168  static void Start(uint32_t aNamespace);
    169 
    170  /// Can only be called from the main thread.
    171  static void ShutDown();
    172 
    173  /// Can be called from any thread.
    174  static bool IsInRenderThread();
    175 
    176  /// Can be called from any thread.
    177  static already_AddRefed<nsIThread> GetRenderThread();
    178 
    179  // Can be called from any thread. Dispatches an event to the Renderer thread
    180  // to iterate over all Renderers, accumulates memory statistics, and resolves
    181  // the return promise.
    182  static RefPtr<MemoryReportPromise> AccumulateMemoryReport(
    183      MemoryReport aInitial);
    184 
    185  /// Can only be called from the main thread.
    186  static void PostHandleDeviceReset(gfx::DeviceResetDetectPlace aPlace,
    187                                    gfx::DeviceResetReason aReason);
    188 
    189  /// Can only be called from the render thread.
    190  void AddRenderer(wr::WindowId aWindowId, UniquePtr<RendererOGL> aRenderer);
    191 
    192  /// Can only be called from the render thread.
    193  void RemoveRenderer(wr::WindowId aWindowId);
    194 
    195  /// Can only be called from the render thread.
    196  RendererOGL* GetRenderer(wr::WindowId aWindowId);
    197 
    198  /// Automatically forwarded to the render thread.
    199  void SetClearColor(wr::WindowId aWindowId, wr::ColorF aColor);
    200 
    201  /// Automatically forwarded to the render thread.
    202  void SetProfilerUI(wr::WindowId aWindowId, const nsACString& aUI);
    203 
    204  /// Automatically forwarded to the render thread.
    205  void PipelineSizeChanged(wr::WindowId aWindowId, uint64_t aPipelineId,
    206                           float aWidth, float aHeight);
    207 
    208  /// Post RendererEvent to the render thread.
    209  void PostEvent(wr::WindowId aWindowId, UniquePtr<RendererEvent> aEvent);
    210 
    211  /// Can only be called from the render thread.
    212  void SetFramePublishId(wr::WindowId aWindowId, FramePublishId aPublishId);
    213 
    214  /// Can only be called from the render thread.
    215  void UpdateAndRender(wr::WindowId aWindowId, const VsyncId& aStartId,
    216                       const TimeStamp& aStartTime,
    217                       const wr::FrameReadyParams& aParams,
    218                       const Maybe<gfx::IntSize>& aReadbackSize,
    219                       const Maybe<wr::ImageFormat>& aReadbackFormat,
    220                       const Maybe<Range<uint8_t>>& aReadbackBuffer,
    221                       RendererStats* aStats, bool* aNeedsYFlip = nullptr);
    222 
    223  void Pause(wr::WindowId aWindowId);
    224  bool Resume(wr::WindowId aWindowId);
    225  void NotifyIdle();
    226 
    227  /// Can be called from any thread.
    228  void RegisterExternalImage(const wr::ExternalImageId& aExternalImageId,
    229                             already_AddRefed<RenderTextureHost> aTexture);
    230 
    231  /// Can be called from any thread.
    232  void UnregisterExternalImage(const wr::ExternalImageId& aExternalImageId);
    233 
    234  /// Can be called from any thread.
    235  void DestroyExternalImagesSyncWait(
    236      const std::vector<wr::ExternalImageId>&& aIds);
    237 
    238  /// Can be called from any thread.
    239  void PrepareForUse(const wr::ExternalImageId& aExternalImageId);
    240 
    241  /// Can be called from any thread.
    242  void NotifyNotUsed(const wr::ExternalImageId& aExternalImageId);
    243 
    244  /// Can be called from any thread.
    245  void NotifyForUse(const wr::ExternalImageId& aExternalImageId);
    246 
    247  void HandleRenderTextureOps();
    248 
    249  /// Can be called from any thread.
    250  RefPtr<RenderTextureHostUsageInfo> GetOrMergeUsageInfo(
    251      const wr::ExternalImageId& aExternalImageId,
    252      RefPtr<RenderTextureHostUsageInfo> aUsageInfo);
    253 
    254  /// Can only be called from the render thread.
    255  void UnregisterExternalImageDuringShutdown(
    256      const wr::ExternalImageId& aExternalImageId);
    257 
    258  /// Can only be called from the render thread.
    259  RenderTextureHost* GetRenderTexture(
    260      const wr::ExternalImageId& aExternalImageId);
    261 
    262  /// Can only be called from the render thread.
    263  std::tuple<RenderTextureHost*, RefPtr<RenderTextureHostUsageInfo>>
    264  GetRenderTextureAndUsageInfo(const wr::ExternalImageId& aExternalImageId);
    265 
    266  /// Can be called from any thread.
    267  bool IsDestroyed(wr::WindowId aWindowId);
    268  /// Can be called from any thread.
    269  void SetDestroyed(wr::WindowId aWindowId);
    270  /// Can be called from any thread.
    271  bool TooManyPendingFrames(wr::WindowId aWindowId);
    272  /// Can be called from any thread.
    273  ///
    274  /// Should always be paired with a call to `WebRenderAPI::GenerateFrame` that
    275  /// has `tracked` set to true.
    276  void IncPendingFrameCount(wr::WindowId aWindowId, const VsyncId& aStartId,
    277                            const TimeStamp& aStartTime);
    278  /// Can be called from any thread.
    279  void DecPendingFrameBuildCount(wr::WindowId aWindowId);
    280  void DecPendingFrameCount(wr::WindowId aWindowId);
    281 
    282  // RenderNotifier implementation
    283  void WrNotifierEvent_WakeUp(WrWindowId aWindowId, bool aCompositeNeeded);
    284  void WrNotifierEvent_NewFrameReady(WrWindowId aWindowId,
    285                                     wr::FramePublishId aPublishId,
    286                                     const wr::FrameReadyParams* aParams);
    287  void WrNotifierEvent_ExternalEvent(WrWindowId aWindowId, size_t aRawEvent);
    288 
    289  /// Can be called from any thread.
    290  WebRenderThreadPool& ThreadPool() { return mThreadPool; }
    291 
    292  /// Thread pool for low priority scene building
    293  /// Can be called from any thread.
    294  WebRenderThreadPool& ThreadPoolLP() { return mThreadPoolLP; }
    295 
    296  /// A pool of large memory chunks used by the per-frame allocators.
    297  WrChunkPool* MemoryChunkPool() { return mChunkPool; }
    298 
    299  /// Optional global glyph raster thread.
    300  /// Can be called from any thread.
    301  MaybeWebRenderGlyphRasterThread& GlyphRasterThread() {
    302    return mGlyphRasterThread;
    303  }
    304 
    305  /// Returns the cache used to serialize shader programs to disk, if enabled.
    306  ///
    307  /// Can only be called from the render thread.
    308  WebRenderProgramCache* GetProgramCache() {
    309    MOZ_ASSERT(IsInRenderThread());
    310    return mProgramCache.get();
    311  }
    312 
    313  /// Can only be called from the render thread.
    314  WebRenderShaders* GetShaders() {
    315    MOZ_ASSERT(IsInRenderThread());
    316    return mShaders.get();
    317  }
    318 
    319  /// Can only be called from the render thread.
    320  gl::GLContext* SingletonGL(nsACString& aError);
    321  gl::GLContext* SingletonGL();
    322  gl::GLContext* SingletonGLForCompositorOGL();
    323  void ClearSingletonGL();
    324  RefPtr<layers::SurfacePool> SharedSurfacePool();
    325  void ClearSharedSurfacePool();
    326 
    327  RefPtr<layers::ShaderProgramOGLsHolder> GetProgramsForCompositorOGL();
    328 
    329  /// Can only be called from the render thread.
    330  void HandleDeviceReset(gfx::DeviceResetDetectPlace aPlace,
    331                         gfx::DeviceResetReason aReason);
    332  /// Can only be called from the render thread.
    333  bool IsHandlingDeviceReset();
    334  /// Can be called from any thread.
    335  void SimulateDeviceReset();
    336 
    337  /// Can only be called from the render thread.
    338  void NotifyWebRenderError(WebRenderError aError);
    339 
    340  /// Can only be called from the render thread.
    341  void HandleWebRenderError(WebRenderError aError);
    342  /// Can only be called from the render thread.
    343  bool IsHandlingWebRenderError();
    344 
    345  /// Can only be called from the render thread.
    346  bool SyncObjectNeeded();
    347 
    348  size_t RendererCount() const;
    349  size_t ActiveRendererCount() const { return sActiveRendererCount; };
    350  void UpdateActiveRendererCount();
    351 
    352  void BeginRecordingForWindow(wr::WindowId aWindowId,
    353                               const TimeStamp& aRecordingStart,
    354                               wr::PipelineId aRootPipelineId);
    355 
    356  Maybe<layers::FrameRecording> EndRecordingForWindow(wr::WindowId aWindowId);
    357 
    358  static void MaybeEnableGLDebugMessage(gl::GLContext* aGLContext);
    359 
    360  void SetBatteryInfo(const hal::BatteryInformation& aBatteryInfo);
    361  bool GetPowerIsCharging();
    362 
    363  void BeginShaderWarmupIfNeeded();
    364 
    365 private:
    366  static size_t sRendererCount;
    367  static size_t sActiveRendererCount;
    368 
    369  enum class RenderTextureOp {
    370    PrepareForUse,
    371    NotifyForUse,
    372    NotifyNotUsed,
    373  };
    374  class WrNotifierEvent {
    375   public:
    376    enum class Tag {
    377      WakeUp,
    378      NewFrameReady,
    379      ExternalEvent,
    380    };
    381    const Tag mTag;
    382 
    383   private:
    384    WrNotifierEvent(const Tag aTag, wr::FramePublishId aPublishId,
    385                    wr::FrameReadyParams aParams)
    386        : mTag(aTag), mPublishId(aPublishId), mParams(aParams) {
    387      MOZ_ASSERT(mTag == Tag::NewFrameReady);
    388    }
    389    WrNotifierEvent(const Tag aTag, wr::FrameReadyParams aParams)
    390        : mTag(aTag), mParams(aParams) {
    391      MOZ_ASSERT(mTag == Tag::WakeUp);
    392    }
    393    WrNotifierEvent(const Tag aTag, UniquePtr<RendererEvent>&& aRendererEvent)
    394        : mTag(aTag), mRendererEvent(std::move(aRendererEvent)) {
    395      MOZ_ASSERT(mTag == Tag::ExternalEvent);
    396    }
    397 
    398    const wr::FramePublishId mPublishId = wr::FramePublishId::INVALID;
    399    const wr::FrameReadyParams mParams = {
    400        .present = false,
    401        .render = false,
    402        .scrolled = false,
    403        .tracked = false,
    404    };
    405    UniquePtr<RendererEvent> mRendererEvent;
    406 
    407   public:
    408    static WrNotifierEvent WakeUp(const bool aCompositeNeeded) {
    409      wr::FrameReadyParams params = {
    410          .present = aCompositeNeeded,
    411          .render = aCompositeNeeded,
    412          .scrolled = false,
    413          .tracked = false,
    414      };
    415      return WrNotifierEvent(Tag::WakeUp, params);
    416    }
    417 
    418    static WrNotifierEvent NewFrameReady(FramePublishId aPublishId,
    419                                         const wr::FrameReadyParams* aParams) {
    420      return WrNotifierEvent(Tag::NewFrameReady, aPublishId, *aParams);
    421    }
    422 
    423    static WrNotifierEvent ExternalEvent(
    424        UniquePtr<RendererEvent>&& aRendererEvent) {
    425      return WrNotifierEvent(Tag::ExternalEvent, std::move(aRendererEvent));
    426    }
    427 
    428    const wr::FrameReadyParams& FrameReadyParams() const {
    429      MOZ_ASSERT(mTag == Tag::NewFrameReady || mTag == Tag::WakeUp,
    430                 "Unexpected NotiferEvent tag");
    431      return mParams;
    432    }
    433    FramePublishId PublishId() {
    434      if (mTag == Tag::NewFrameReady) {
    435        return mPublishId;
    436      }
    437      MOZ_ASSERT_UNREACHABLE("Unexpected NotiferEvent tag");
    438      return FramePublishId::INVALID;
    439    }
    440    UniquePtr<RendererEvent> ExternalEvent() {
    441      if (mTag == Tag::ExternalEvent) {
    442        MOZ_ASSERT(mRendererEvent);
    443        return std::move(mRendererEvent);
    444      }
    445      MOZ_ASSERT_UNREACHABLE("Unexpected NotiferEvent tag");
    446      return nullptr;
    447    }
    448  };
    449 
    450  explicit RenderThread(RefPtr<nsIThread> aThread);
    451 
    452  void HandleFrameOneDocInner(wr::WindowId aWindowId,
    453                              const wr::FrameReadyParams& aParams,
    454                              Maybe<FramePublishId> aPublishId);
    455 
    456  void DeferredRenderTextureHostDestroy();
    457  void ShutDownTask();
    458  void InitDeviceTask();
    459  void PostResumeShaderWarmupRunnable();
    460  void ResumeShaderWarmup();
    461  void HandleFrameOneDoc(wr::WindowId aWindowId, const wr::FrameReadyParams&,
    462                         Maybe<FramePublishId> aPublishId);
    463  void RunEvent(wr::WindowId aWindowId, UniquePtr<RendererEvent> aEvent,
    464                bool aViaWebRender);
    465  void PostRunnable(already_AddRefed<nsIRunnable> aRunnable);
    466 
    467  void DoAccumulateMemoryReport(MemoryReport,
    468                                const RefPtr<MemoryReportPromise::Private>&);
    469 
    470  void AddRenderTextureOp(RenderTextureOp aOp,
    471                          const wr::ExternalImageId& aExternalImageId);
    472 
    473  void CreateSingletonGL(nsACString& aError);
    474 
    475  void DestroyExternalImages(const std::vector<wr::ExternalImageId>&& aIds);
    476 
    477  struct WindowInfo;
    478 
    479  void PostWrNotifierEvents(WrWindowId aWindowId);
    480  void PostWrNotifierEvents(WrWindowId aWindowId, WindowInfo* aInfo);
    481  void HandleWrNotifierEvents(WrWindowId aWindowId);
    482  void WrNotifierEvent_HandleWakeUp(wr::WindowId aWindowId,
    483                                    const wr::FrameReadyParams& aParams);
    484  void WrNotifierEvent_HandleNewFrameReady(wr::WindowId aWindowId,
    485                                           wr::FramePublishId aPublishId,
    486                                           const wr::FrameReadyParams& aParams);
    487  void WrNotifierEvent_HandleExternalEvent(
    488      wr::WindowId aWindowId, UniquePtr<RendererEvent> aRendererEvent);
    489 
    490  ~RenderThread();
    491 
    492  RefPtr<nsIThread> const mThread;
    493 
    494  WebRenderThreadPool mThreadPool;
    495  WebRenderThreadPool mThreadPoolLP;
    496  WrChunkPool* mChunkPool;
    497  MaybeWebRenderGlyphRasterThread mGlyphRasterThread;
    498 
    499  UniquePtr<WebRenderProgramCache> mProgramCache;
    500  UniquePtr<WebRenderShaders> mShaders;
    501  RefPtr<layers::ShaderProgramOGLsHolder> mProgramsForCompositorOGL;
    502 
    503  // An optional shared GLContext to be used for all
    504  // windows.
    505  RefPtr<gl::GLContext> mSingletonGL;
    506  bool mSingletonGLIsForHardwareWebRender;
    507 
    508  RefPtr<layers::SurfacePool> mSurfacePool;
    509 
    510  std::map<wr::WindowId, UniquePtr<RendererOGL>> mRenderers;
    511 
    512  DataMutex<Maybe<hal::BatteryInformation>> mBatteryInfo;
    513 
    514  struct PendingFrameInfo {
    515    TimeStamp mStartTime;
    516    VsyncId mStartId;
    517  };
    518 
    519  struct WindowInfo {
    520    int64_t PendingCount() { return mPendingFrames.size(); }
    521    std::queue<PendingFrameInfo> mPendingFrames;
    522    uint8_t mPendingFrameBuild = 0;
    523    bool mIsDestroyed = false;
    524    RefPtr<nsIRunnable> mWrNotifierEventsRunnable;
    525    std::queue<WrNotifierEvent> mPendingWrNotifierEvents;
    526  };
    527 
    528  DataMutex<std::unordered_map<uint64_t, UniquePtr<WindowInfo>>> mWindowInfos;
    529 
    530  std::unordered_map<uint64_t, UniquePtr<std::queue<WrNotifierEvent>>>
    531      mWrNotifierEventsQueues;
    532 
    533  struct ExternalImageIdHashFn {
    534    std::size_t operator()(const wr::ExternalImageId& aId) const {
    535      return HashGeneric(wr::AsUint64(aId));
    536    }
    537  };
    538 
    539  Mutex mRenderTextureMapLock;
    540  std::unordered_map<wr::ExternalImageId, RefPtr<RenderTextureHost>,
    541                     ExternalImageIdHashFn>
    542      mRenderTextures MOZ_GUARDED_BY(mRenderTextureMapLock);
    543  std::unordered_map<wr::ExternalImageId, RefPtr<RenderTextureHost>,
    544                     ExternalImageIdHashFn>
    545      mSyncObjectNeededRenderTextures MOZ_GUARDED_BY(mRenderTextureMapLock);
    546  std::list<std::pair<RenderTextureOp, RefPtr<RenderTextureHost>>>
    547      mRenderTextureOps MOZ_GUARDED_BY(mRenderTextureMapLock);
    548 
    549  // Used to remove all RenderTextureHost that are going to be removed by
    550  // a deferred callback and remove them right away without waiting for the
    551  // callback. On device reset we have to remove all GL related resources right
    552  // away.
    553  std::list<RefPtr<RenderTextureHost>> mRenderTexturesDeferred
    554      MOZ_GUARDED_BY(mRenderTextureMapLock);
    555 
    556  RefPtr<nsIRunnable> mRenderTextureOpsRunnable
    557      MOZ_GUARDED_BY(mRenderTextureMapLock);
    558 
    559 #ifdef DEBUG
    560  // used for tests only to ensure render textures don't increase
    561  int32_t mRenderTexturesLastTime MOZ_GUARDED_BY(mRenderTextureMapLock) = -1;
    562 #endif
    563 
    564  // Set from MainThread, read from either MainThread or RenderThread
    565  bool mHasShutdown;
    566 
    567  // Only accessed from the RenderThread
    568  bool mHandlingDeviceReset;
    569  bool mHandlingWebRenderError;
    570 };
    571 
    572 }  // namespace wr
    573 }  // namespace mozilla
    574 
    575 #endif