tor-browser

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

gfxPlatform.cpp (150252B)


      1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
      2 * This Source Code Form is subject to the terms of the Mozilla Public
      3 * License, v. 2.0. If a copy of the MPL was not distributed with this
      4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      5 
      6 #include "mozilla/FontPropertyTypes.h"
      7 #include "mozilla/RDDProcessManager.h"
      8 #include "mozilla/image/ImageMemoryReporter.h"
      9 #include "mozilla/layers/CompositorManagerChild.h"
     10 #include "mozilla/layers/CompositorThread.h"
     11 #include "mozilla/layers/ImageBridgeChild.h"
     12 #include "mozilla/layers/ISurfaceAllocator.h"  // for GfxMemoryImageReporter
     13 #include "mozilla/layers/CompositorBridgeChild.h"
     14 #include "mozilla/layers/RemoteTextureMap.h"
     15 #include "mozilla/layers/VideoBridgeParent.h"
     16 #include "mozilla/webrender/RenderThread.h"
     17 #include "mozilla/webrender/WebRenderAPI.h"
     18 #include "mozilla/webrender/webrender_ffi.h"
     19 #include "mozilla/gfx/BuildConstants.h"
     20 #include "mozilla/gfx/gfxConfigManager.h"
     21 #include "mozilla/gfx/gfxVars.h"
     22 #include "mozilla/gfx/GPUProcessManager.h"
     23 #include "mozilla/gfx/GraphicsMessages.h"
     24 #include "mozilla/gfx/CanvasRenderThread.h"
     25 #include "mozilla/gfx/CanvasShutdownManager.h"
     26 #include "mozilla/ClearOnShutdown.h"
     27 #include "mozilla/EnumTypeTraits.h"
     28 #include "mozilla/StaticPrefs_accessibility.h"
     29 #include "mozilla/StaticPrefs_apz.h"
     30 #include "mozilla/StaticPrefs_bidi.h"
     31 #include "mozilla/StaticPrefs_gfx.h"
     32 #include "mozilla/StaticPrefs_layout.h"
     33 #include "mozilla/StaticPrefs_layers.h"
     34 #include "mozilla/StaticPrefs_media.h"
     35 #include "mozilla/StaticPrefs_privacy.h"
     36 #include "mozilla/StaticPrefs_webgl.h"
     37 #include "mozilla/StaticPrefs_widget.h"
     38 #include "mozilla/glean/GfxMetrics.h"
     39 #include "mozilla/TimeStamp.h"
     40 #include "mozilla/IntegerPrintfMacros.h"
     41 #include "mozilla/Base64.h"
     42 #include "mozilla/VsyncDispatcher.h"
     43 
     44 #include "mozilla/Logging.h"
     45 #include "mozilla/Components.h"
     46 #include "nsAppRunner.h"
     47 #include "nsAppDirectoryServiceDefs.h"
     48 #include "nsCSSProps.h"
     49 #include "nsContentUtils.h"
     50 
     51 #include "gfxCrashReporterUtils.h"
     52 #include "gfxPlatform.h"
     53 #include "gfxPlatformWorker.h"
     54 
     55 #include "gfxBlur.h"
     56 #include "gfxEnv.h"
     57 #include "gfxTextRun.h"
     58 #include "gfxUserFontSet.h"
     59 #include "gfxConfig.h"
     60 #include "GfxDriverInfo.h"
     61 #include "VRProcessManager.h"
     62 #include "VRThread.h"
     63 
     64 #ifdef XP_WIN
     65 #  include <process.h>
     66 #  define getpid _getpid
     67 #else
     68 #  include <unistd.h>
     69 #endif
     70 
     71 #include "nsXULAppAPI.h"
     72 #include "nsIXULAppInfo.h"
     73 #include "nsDirectoryServiceUtils.h"
     74 #include "nsDirectoryServiceDefs.h"
     75 
     76 #if defined(XP_WIN)
     77 #  include "gfxWindowsPlatform.h"
     78 #  include "mozilla/layers/CompositeProcessD3D11FencesHolderMap.h"
     79 #  include "mozilla/widget/WinWindowOcclusionTracker.h"
     80 #elif defined(XP_DARWIN)
     81 #  include "gfxPlatformMac.h"
     82 #  include "gfxQuartzSurface.h"
     83 #elif defined(MOZ_WIDGET_GTK)
     84 #  include "gfxPlatformGtk.h"
     85 #elif defined(ANDROID)
     86 #  include "gfxAndroidPlatform.h"
     87 #endif
     88 #if defined(MOZ_WIDGET_ANDROID)
     89 #  include "mozilla/java/HardwareCodecCapabilityUtilsWrappers.h"
     90 #endif
     91 
     92 #ifdef XP_WIN
     93 #  include "mozilla/WindowsVersion.h"
     94 #  include "WinUtils.h"
     95 #endif
     96 
     97 #include "nsGkAtoms.h"
     98 #include "gfxPlatformFontList.h"
     99 #include "gfxContext.h"
    100 #include "gfxImageSurface.h"
    101 #include "nsUnicodeProperties.h"
    102 #include "harfbuzz/hb.h"
    103 #include "gfxGraphiteShaper.h"
    104 #include "gfx2DGlue.h"
    105 #include "gfxGradientCache.h"
    106 #include "gfxUtils.h"  // for NextPowerOfTwo
    107 #include "gfxFontMissingGlyphs.h"
    108 
    109 #include "nsExceptionHandler.h"
    110 #include "nsServiceManagerUtils.h"
    111 #include "nsTArray.h"
    112 #include "nsIObserverService.h"
    113 #include "mozilla/widget/Screen.h"
    114 #include "mozilla/widget/ScreenManager.h"
    115 #include "MainThreadUtils.h"
    116 
    117 #include "nsWeakReference.h"
    118 
    119 #include "cairo.h"
    120 #include "qcms.h"
    121 
    122 #include "imgITools.h"
    123 
    124 #include "nsCRT.h"
    125 #include "GLContext.h"
    126 #include "GLContextProvider.h"
    127 #include "mozilla/gfx/Logging.h"
    128 
    129 #ifdef __GNUC__
    130 #  pragma GCC diagnostic push
    131 #  pragma GCC diagnostic ignored "-Wshadow"
    132 #endif
    133 #include "skia/include/core/SkGraphics.h"
    134 #ifdef MOZ_ENABLE_FREETYPE
    135 #  include "skia/include/ports/SkTypeface_cairo.h"
    136 #endif
    137 #include "mozilla/gfx/SkMemoryReporter.h"
    138 #ifdef __GNUC__
    139 #  pragma GCC diagnostic pop  // -Wshadow
    140 #endif
    141 static const uint32_t kDefaultGlyphCacheSize = -1;
    142 
    143 #include "mozilla/Preferences.h"
    144 #include "mozilla/Assertions.h"
    145 #include "mozilla/Atomics.h"
    146 #include "mozilla/Attributes.h"
    147 #include "mozilla/Mutex.h"
    148 
    149 #include "nsIGfxInfo.h"
    150 #include "nsIXULRuntime.h"
    151 #include "VsyncSource.h"
    152 #include "SoftwareVsyncSource.h"
    153 #include "nscore.h"  // for NS_FREE_PERMANENT_DATA
    154 #include "mozilla/dom/ContentChild.h"
    155 #include "mozilla/dom/ContentParent.h"
    156 #include "mozilla/dom/TouchEvent.h"
    157 #include "gfxVR.h"
    158 #include "VRManager.h"
    159 #include "VRManagerChild.h"
    160 #include "mozilla/gfx/GPUParent.h"
    161 #include "prsystem.h"
    162 
    163 #include "mozilla/gfx/2D.h"
    164 #include "mozilla/gfx/SourceSurfaceCairo.h"
    165 
    166 using namespace mozilla;
    167 using namespace mozilla::layers;
    168 using namespace mozilla::gl;
    169 using namespace mozilla::gfx;
    170 
    171 static bool gEverInitialized = false;
    172 gfxPlatform* gfxPlatform::gPlatform = nullptr;
    173 
    174 Atomic<bool, ReleaseAcquire> gfxPlatform::gCMSInitialized;
    175 CMSMode gfxPlatform::gCMSMode = CMSMode::Off;
    176 
    177 const ContentDeviceData* gContentDeviceInitData = nullptr;
    178 
    179 /// This override of the LogForwarder, initially used for the critical graphics
    180 /// errors, is sending the log to the crash annotations as well, but only
    181 /// if the capacity set with the method below is >= 2.  We always retain the
    182 /// very first critical message, and the latest capacity-1 messages are
    183 /// rotated through. Note that we don't expect the total number of times
    184 /// this gets called to be large - it is meant for critical errors only.
    185 
    186 class CrashStatsLogForwarder : public mozilla::gfx::LogForwarder {
    187 public:
    188  explicit CrashStatsLogForwarder(CrashReporter::Annotation aKey);
    189  void Log(const std::string& aString) override;
    190  void CrashAction(LogReason aReason) override;
    191  bool UpdateStringsVector(const std::string& aString) override;
    192 
    193  LoggingRecord LoggingRecordCopy() override;
    194 
    195  void SetCircularBufferSize(uint32_t aCapacity);
    196 
    197 private:
    198  // Helper for the Log()
    199  void UpdateCrashReport(const MutexAutoLock& aProofOfLock);
    200  bool UpdateStringsVectorInternal(const std::string& aString,
    201                                   const MutexAutoLock& aProofOfLock);
    202 
    203 private:
    204  LoggingRecord mBuffer;
    205  CrashReporter::Annotation mCrashCriticalKey;
    206  uint32_t mMaxCapacity;
    207  int32_t mIndex;
    208  Mutex mMutex MOZ_UNANNOTATED;
    209 };
    210 
    211 CrashStatsLogForwarder::CrashStatsLogForwarder(CrashReporter::Annotation aKey)
    212    : mCrashCriticalKey(aKey),
    213      mMaxCapacity(0),
    214      mIndex(-1),
    215      mMutex("CrashStatsLogForwarder") {}
    216 
    217 void CrashStatsLogForwarder::SetCircularBufferSize(uint32_t aCapacity) {
    218  MutexAutoLock lock(mMutex);
    219 
    220  mMaxCapacity = aCapacity;
    221  mBuffer.reserve(static_cast<size_t>(aCapacity));
    222 }
    223 
    224 LoggingRecord CrashStatsLogForwarder::LoggingRecordCopy() {
    225  MutexAutoLock lock(mMutex);
    226  return mBuffer;
    227 }
    228 
    229 bool CrashStatsLogForwarder::UpdateStringsVector(const std::string& aString) {
    230  MutexAutoLock lock(mMutex);
    231  return UpdateStringsVectorInternal(aString, lock);
    232 }
    233 
    234 bool CrashStatsLogForwarder::UpdateStringsVectorInternal(
    235    const std::string& aString, const MutexAutoLock& aProofOfLock) {
    236  // We want at least the first one and the last one.  Otherwise, no point.
    237  if (mMaxCapacity < 2) {
    238    return false;
    239  }
    240 
    241  mIndex += 1;
    242  MOZ_ASSERT(mIndex >= 0);
    243 
    244  // index will count 0, 1, 2, ..., max-1, 1, 2, ..., max-1, 1, 2, ...
    245  int32_t index = mIndex ? (mIndex - 1) % (mMaxCapacity - 1) + 1 : 0;
    246  MOZ_ASSERT(index >= 0 && index < (int32_t)mMaxCapacity);
    247  MOZ_ASSERT(index <= mIndex && index <= (int32_t)mBuffer.size());
    248 
    249  // ToSeconds preserves the full precision of the TimeDuration. It is assumed
    250  // that visualizations of this value will format/truncate it to their needs.
    251  double tStamp =
    252      (TimeStamp::NowLoRes() - TimeStamp::ProcessCreation()).ToSeconds();
    253 
    254  // Checking for index >= mBuffer.size(), rather than index == mBuffer.size()
    255  // just out of paranoia, but we know index <= mBuffer.size().
    256  LoggingRecordEntry newEntry(mIndex, aString, tStamp);
    257  if (index >= static_cast<int32_t>(mBuffer.size())) {
    258    mBuffer.push_back(newEntry);
    259  } else {
    260    mBuffer[index] = newEntry;
    261  }
    262  return true;
    263 }
    264 
    265 void CrashStatsLogForwarder::UpdateCrashReport(
    266    const MutexAutoLock& aProofOfLock) {
    267  std::stringstream message;
    268  std::string logAnnotation;
    269 
    270  switch (XRE_GetProcessType()) {
    271    case GeckoProcessType_Default:
    272      logAnnotation = "|[";
    273      break;
    274    case GeckoProcessType_Content:
    275      logAnnotation = "|[C";
    276      break;
    277    case GeckoProcessType_GPU:
    278      logAnnotation = "|[G";
    279      break;
    280    default:
    281      logAnnotation = "|[X";
    282      break;
    283  }
    284 
    285  for (auto& it : mBuffer) {
    286    message << logAnnotation << std::get<0>(it) << "]" << std::get<1>(it)
    287            << " (t=" << std::get<2>(it) << ") ";
    288  }
    289 
    290  nsresult annotated = CrashReporter::RecordAnnotationCString(
    291      mCrashCriticalKey, message.str().c_str());
    292 
    293  if (annotated != NS_OK) {
    294    printf("Crash Annotation %s: %s",
    295           CrashReporter::AnnotationToString(mCrashCriticalKey),
    296           message.str().c_str());
    297  }
    298 }
    299 
    300 class LogForwarderEvent : public Runnable {
    301  virtual ~LogForwarderEvent() = default;
    302 
    303 public:
    304  NS_INLINE_DECL_REFCOUNTING_INHERITED(LogForwarderEvent, Runnable)
    305 
    306  explicit LogForwarderEvent(const nsCString& aMessage)
    307      : mozilla::Runnable("LogForwarderEvent"), mMessage(aMessage) {}
    308 
    309  NS_IMETHOD Run() override {
    310    MOZ_ASSERT(NS_IsMainThread() &&
    311               (XRE_IsContentProcess() || XRE_IsGPUProcess()));
    312 
    313    if (XRE_IsContentProcess()) {
    314      dom::ContentChild* cc = dom::ContentChild::GetSingleton();
    315      (void)cc->SendGraphicsError(mMessage);
    316    } else if (XRE_IsGPUProcess()) {
    317      GPUParent* gp = GPUParent::GetSingleton();
    318      (void)gp->SendGraphicsError(mMessage);
    319    }
    320 
    321    return NS_OK;
    322  }
    323 
    324 protected:
    325  nsCString mMessage;
    326 };
    327 
    328 void CrashStatsLogForwarder::Log(const std::string& aString) {
    329  MutexAutoLock lock(mMutex);
    330  PROFILER_MARKER_TEXT("gfx::CriticalError", GRAPHICS, {},
    331                       nsDependentCString(aString.c_str()));
    332 
    333  if (UpdateStringsVectorInternal(aString, lock)) {
    334    UpdateCrashReport(lock);
    335  }
    336 
    337  // Add it to the parent strings
    338  if (!XRE_IsParentProcess()) {
    339    nsCString stringToSend(aString.c_str());
    340    if (NS_IsMainThread()) {
    341      if (XRE_IsContentProcess()) {
    342        dom::ContentChild* cc = dom::ContentChild::GetSingleton();
    343        (void)cc->SendGraphicsError(stringToSend);
    344      } else if (XRE_IsGPUProcess()) {
    345        GPUParent* gp = GPUParent::GetSingleton();
    346        (void)gp->SendGraphicsError(stringToSend);
    347      }
    348    } else {
    349      nsCOMPtr<nsIRunnable> r1 = new LogForwarderEvent(stringToSend);
    350      NS_DispatchToMainThread(r1);
    351    }
    352  }
    353 }
    354 
    355 class CrashTelemetryEvent : public Runnable {
    356  virtual ~CrashTelemetryEvent() = default;
    357 
    358 public:
    359  NS_INLINE_DECL_REFCOUNTING_INHERITED(CrashTelemetryEvent, Runnable)
    360 
    361  explicit CrashTelemetryEvent(uint32_t aReason)
    362      : mozilla::Runnable("CrashTelemetryEvent"), mReason(aReason) {}
    363 
    364  NS_IMETHOD Run() override {
    365    MOZ_ASSERT(NS_IsMainThread());
    366    glean::gfx::crash.AccumulateSingleSample(mReason);
    367    return NS_OK;
    368  }
    369 
    370 protected:
    371  uint32_t mReason;
    372 };
    373 
    374 void CrashStatsLogForwarder::CrashAction(LogReason aReason) {
    375 #ifndef RELEASE_OR_BETA
    376  // Non-release builds crash by default, but will use telemetry
    377  // if this environment variable is present.
    378  static bool useTelemetry = gfxEnv::MOZ_GFX_CRASH_TELEMETRY();
    379 #else
    380  // Release builds use telemetry by default, but will crash instead
    381  // if this environment variable is present.
    382  static bool useTelemetry = !gfxEnv::MOZ_GFX_CRASH_MOZ_CRASH();
    383 #endif
    384 
    385  if (useTelemetry) {
    386    // The callers need to assure that aReason is in the range
    387    // that the telemetry call below supports.
    388    if (NS_IsMainThread()) {
    389      glean::gfx::crash.AccumulateSingleSample((uint32_t)aReason);
    390    } else {
    391      nsCOMPtr<nsIRunnable> r1 = new CrashTelemetryEvent((uint32_t)aReason);
    392      NS_DispatchToMainThread(r1);
    393    }
    394  } else {
    395    // ignoring aReason, we can get the information we need from the stack
    396    MOZ_CRASH("GFX_CRASH");
    397  }
    398 }
    399 
    400 #define GFX_DOWNLOADABLE_FONTS_ENABLED "gfx.downloadable_fonts.enabled"
    401 
    402 #define GFX_PREF_FALLBACK_USE_CMAPS \
    403  "gfx.font_rendering.fallback.always_use_cmaps"
    404 
    405 #define GFX_PREF_OPENTYPE_SVG "gfx.font_rendering.opentype_svg.enabled"
    406 
    407 #define GFX_PREF_WORD_CACHE_CHARLIMIT "gfx.font_rendering.wordcache.charlimit"
    408 #define GFX_PREF_WORD_CACHE_MAXENTRIES "gfx.font_rendering.wordcache.maxentries"
    409 
    410 #define GFX_PREF_GRAPHITE_SHAPING "gfx.font_rendering.graphite.enabled"
    411 #if defined(XP_DARWIN)
    412 #  define GFX_PREF_CORETEXT_SHAPING "gfx.font_rendering.coretext.enabled"
    413 #endif
    414 
    415 #define FONT_VARIATIONS_PREF "layout.css.font-variations.enabled"
    416 
    417 static const char* kObservedPrefs[] = {"gfx.downloadable_fonts.",
    418                                       "gfx.font_rendering.", nullptr};
    419 
    420 static void FontPrefChanged(const char* aPref, void* aData) {
    421  MOZ_ASSERT(aPref);
    422  NS_ASSERTION(gfxPlatform::GetPlatform(), "the singleton instance has gone");
    423  gfxPlatform::GetPlatform()->FontsPrefsChanged(aPref);
    424 }
    425 
    426 void gfxPlatform::OnMemoryPressure(layers::MemoryPressureReason aWhy) {
    427  Factory::PurgeAllCaches();
    428  gfxGradientCache::PurgeAllCaches();
    429  gfxFontMissingGlyphs::Purge();
    430  PurgeSkiaFontCache();
    431  if (XRE_IsParentProcess()) {
    432    layers::CompositorManagerChild* manager =
    433        CompositorManagerChild::GetInstance();
    434    if (manager) {
    435      manager->SendNotifyMemoryPressure();
    436    }
    437  }
    438 }
    439 
    440 gfxPlatform::gfxPlatform()
    441    : mAzureCanvasBackendCollector(this, &gfxPlatform::GetAzureBackendInfo),
    442      mApzSupportCollector(this, &gfxPlatform::GetApzSupportInfo),
    443      mFrameStatsCollector(this, &gfxPlatform::GetFrameStats),
    444      mCMSInfoCollector(this, &gfxPlatform::GetCMSSupportInfo),
    445      mDisplayInfoCollector(this, &gfxPlatform::GetDisplayInfo),
    446      mOverlayInfoCollector(this, &gfxPlatform::GetOverlayInfo),
    447      mSwapChainInfoCollector(this, &gfxPlatform::GetSwapChainInfo),
    448      mCompositorBackend(layers::LayersBackend::LAYERS_NONE) {
    449  mAllowDownloadableFonts = UNINITIALIZED_VALUE;
    450 
    451  InitBackendPrefs(GetBackendPrefs());
    452  VRManager::ManagerInit();
    453 }
    454 
    455 bool gfxPlatform::Initialized() { return !!gPlatform; }
    456 
    457 /* static */
    458 void gfxPlatform::InitChild(const ContentDeviceData& aData) {
    459  MOZ_ASSERT(XRE_IsContentProcess());
    460  MOZ_ASSERT(!gPlatform,
    461             "InitChild() should be called before first GetPlatform()");
    462  // Make the provided initial ContentDeviceData available to the init
    463  // routines.
    464  gContentDeviceInitData = &aData;
    465  Init();
    466  gContentDeviceInitData = nullptr;
    467 }
    468 
    469 #define WR_DEBUG_PREF "gfx.webrender.debug"
    470 
    471 static void SwapIntervalPrefChangeCallback(const char* aPrefName, void*) {
    472  bool egl = Preferences::GetBool("gfx.swap-interval.egl", false);
    473  bool glx = Preferences::GetBool("gfx.swap-interval.glx", false);
    474  gfxVars::SetSwapIntervalEGL(egl);
    475  gfxVars::SetSwapIntervalGLX(glx);
    476 }
    477 
    478 static void WebRendeProfilerUIPrefChangeCallback(const char* aPrefName, void*) {
    479  nsCString uiString;
    480  if (NS_SUCCEEDED(Preferences::GetCString("gfx.webrender.debug.profiler-ui",
    481                                           uiString))) {
    482    gfxVars::SetWebRenderProfilerUI(uiString);
    483  }
    484 }
    485 
    486 // List of boolean dynamic parameter for WebRender.
    487 //
    488 // The parameters in this list are:
    489 //  - The pref name.
    490 //  - The BoolParameter enum variant (see webrender_api/src/lib.rs)
    491 //  - A default value.
    492 #define WR_BOOL_PARAMETER_LIST(_)                                     \
    493  _("gfx.webrender.batched-texture-uploads",                          \
    494    wr::BoolParameter::BatchedUploads, true)                          \
    495  _("gfx.webrender.draw-calls-for-texture-copy",                      \
    496    wr::BoolParameter::DrawCallsForTextureCopy, true)                 \
    497  _("gfx.webrender.pbo-uploads", wr::BoolParameter::PboUploads, true) \
    498  _("gfx.webrender.multithreading", wr::BoolParameter::Multithreading, true)
    499 
    500 static void WebRenderBoolParameterChangeCallback(const char*, void*) {
    501  uint32_t bits = 0;
    502 
    503 #define WR_BOOL_PARAMETER(name, key, default_val) \
    504  if (Preferences::GetBool(name, default_val)) {  \
    505    bits |= 1 << (uint32_t)key;                   \
    506  }
    507 
    508  WR_BOOL_PARAMETER_LIST(WR_BOOL_PARAMETER)
    509 #undef WR_BOOL_PARAMETER
    510 
    511  gfx::gfxVars::SetWebRenderBoolParameters(bits);
    512 }
    513 
    514 static void RegisterWebRenderBoolParamCallback() {
    515 #define WR_BOOL_PARAMETER(name, _key, _default_val) \
    516  Preferences::RegisterCallback(WebRenderBoolParameterChangeCallback, name);
    517 
    518  WR_BOOL_PARAMETER_LIST(WR_BOOL_PARAMETER)
    519 #undef WR_BOOL_PARAMETER
    520 
    521  WebRenderBoolParameterChangeCallback(nullptr, nullptr);
    522 }
    523 
    524 static void WebRenderDebugPrefChangeCallback(const char* aPrefName, void*) {
    525  wr::DebugFlags flags{0};
    526 #define GFX_WEBRENDER_DEBUG(suffix, bit)                   \
    527  if (Preferences::GetBool(WR_DEBUG_PREF suffix, false)) { \
    528    flags |= (bit);                                        \
    529  }
    530 
    531  GFX_WEBRENDER_DEBUG(".profiler", wr::DebugFlags::PROFILER_DBG)
    532  GFX_WEBRENDER_DEBUG(".render-targets", wr::DebugFlags::RENDER_TARGET_DBG)
    533  GFX_WEBRENDER_DEBUG(".texture-cache", wr::DebugFlags::TEXTURE_CACHE_DBG)
    534  GFX_WEBRENDER_DEBUG(".gpu-time-queries", wr::DebugFlags::GPU_TIME_QUERIES)
    535  GFX_WEBRENDER_DEBUG(".gpu-sample-queries", wr::DebugFlags::GPU_SAMPLE_QUERIES)
    536  GFX_WEBRENDER_DEBUG(".disable-batching", wr::DebugFlags::DISABLE_BATCHING)
    537  GFX_WEBRENDER_DEBUG(".epochs", wr::DebugFlags::EPOCHS)
    538  GFX_WEBRENDER_DEBUG(".smart-profiler", wr::DebugFlags::SMART_PROFILER)
    539  GFX_WEBRENDER_DEBUG(".echo-driver-messages",
    540                      wr::DebugFlags::ECHO_DRIVER_MESSAGES)
    541  GFX_WEBRENDER_DEBUG(".show-overdraw", wr::DebugFlags::SHOW_OVERDRAW)
    542  GFX_WEBRENDER_DEBUG(".texture-cache.clear-evicted",
    543                      wr::DebugFlags::TEXTURE_CACHE_DBG_CLEAR_EVICTED)
    544  GFX_WEBRENDER_DEBUG(".picture-caching", wr::DebugFlags::PICTURE_CACHING_DBG)
    545  GFX_WEBRENDER_DEBUG(".picture-borders", wr::DebugFlags::PICTURE_BORDERS)
    546  GFX_WEBRENDER_DEBUG(".force-picture-invalidation",
    547                      wr::DebugFlags::FORCE_PICTURE_INVALIDATION)
    548  // Bit 18 is for the zoom display, which requires the mouse position and thus
    549  // currently only works in wrench.
    550  GFX_WEBRENDER_DEBUG(".small-screen", wr::DebugFlags::SMALL_SCREEN)
    551  GFX_WEBRENDER_DEBUG(".disable-opaque-pass",
    552                      wr::DebugFlags::DISABLE_OPAQUE_PASS)
    553  GFX_WEBRENDER_DEBUG(".disable-alpha-pass", wr::DebugFlags::DISABLE_ALPHA_PASS)
    554  GFX_WEBRENDER_DEBUG(".disable-clip-masks", wr::DebugFlags::DISABLE_CLIP_MASKS)
    555  GFX_WEBRENDER_DEBUG(".disable-text-prims", wr::DebugFlags::DISABLE_TEXT_PRIMS)
    556  GFX_WEBRENDER_DEBUG(".disable-gradient-prims",
    557                      wr::DebugFlags::DISABLE_GRADIENT_PRIMS)
    558  GFX_WEBRENDER_DEBUG(".obscure-images", wr::DebugFlags::OBSCURE_IMAGES)
    559  GFX_WEBRENDER_DEBUG(".glyph-flashing", wr::DebugFlags::GLYPH_FLASHING)
    560  GFX_WEBRENDER_DEBUG(".capture-profiler", wr::DebugFlags::PROFILER_CAPTURE)
    561  GFX_WEBRENDER_DEBUG(".window-visibility",
    562                      wr::DebugFlags::WINDOW_VISIBILITY_DBG)
    563  GFX_WEBRENDER_DEBUG(".restrict-blob-size", wr::DebugFlags::RESTRICT_BLOB_SIZE)
    564  GFX_WEBRENDER_DEBUG(".surface-promotion-logging",
    565                      wr::DebugFlags::SURFACE_PROMOTION_LOGGING)
    566  GFX_WEBRENDER_DEBUG(".missing-snapshot-panic",
    567                      wr::DebugFlags::MISSING_SNAPSHOT_PANIC)
    568  GFX_WEBRENDER_DEBUG(".missing-snapshot-pink",
    569                      wr::DebugFlags::MISSING_SNAPSHOT_PINK)
    570  GFX_WEBRENDER_DEBUG(".highlight-backdrop-filters",
    571                      wr::DebugFlags::HIGHLIGHT_BACKDROP_FILTERS)
    572  GFX_WEBRENDER_DEBUG(".external-composite-borders",
    573                      wr::DebugFlags::EXTERNAL_COMPOSITE_BORDERS)
    574 #undef GFX_WEBRENDER_DEBUG
    575  gfx::gfxVars::SetWebRenderDebugFlags(flags._0);
    576 
    577  uint32_t threshold = Preferences::GetFloat(
    578      StaticPrefs::GetPrefName_gfx_webrender_debug_slow_cpu_frame_threshold(),
    579      10.0);
    580  gfx::gfxVars::SetWebRenderSlowCpuFrameThreshold(threshold);
    581 }
    582 
    583 static void WebRenderQualityPrefChangeCallback(const char* aPref, void*) {
    584  gfxPlatform::GetPlatform()->UpdateForceSubpixelAAWherePossible();
    585 }
    586 
    587 static void WebRenderBatchingPrefChangeCallback(const char* aPrefName, void*) {
    588  uint32_t count = Preferences::GetUint(
    589      StaticPrefs::GetPrefName_gfx_webrender_batching_lookback(), 10);
    590 
    591  gfx::gfxVars::SetWebRenderBatchingLookback(count);
    592 }
    593 
    594 static void WebRenderBlobTileSizePrefChangeCallback(const char* aPrefName,
    595                                                    void*) {
    596  uint32_t tileSize = Preferences::GetUint(
    597      StaticPrefs::GetPrefName_gfx_webrender_blob_tile_size(), 256);
    598  gfx::gfxVars::SetWebRenderBlobTileSize(tileSize);
    599 }
    600 
    601 static void WebRenderUploadThresholdPrefChangeCallback(const char* aPrefName,
    602                                                       void*) {
    603  int value = Preferences::GetInt(
    604      StaticPrefs::GetPrefName_gfx_webrender_batched_upload_threshold(),
    605      512 * 512);
    606 
    607  gfxVars::SetWebRenderBatchedUploadThreshold(value);
    608 }
    609 
    610 static uint32_t GetSkiaGlyphCacheSize() {
    611  // Only increase font cache size on non-android to save memory.
    612 #if !defined(MOZ_WIDGET_ANDROID)
    613  // 10mb as the default pref cache size on desktop due to talos perf tweaking.
    614  // Chromium uses 20mb and skia default uses 2mb.
    615  // We don't need to change the font cache count since we usually
    616  // cache thrash due to asian character sets in talos.
    617  // Only increase memory on the content process
    618  uint32_t cacheSize =
    619      StaticPrefs::gfx_content_skia_font_cache_size_AtStartup() * 1024 * 1024;
    620  if (mozilla::BrowserTabsRemoteAutostart()) {
    621    return XRE_IsContentProcess() ? cacheSize : kDefaultGlyphCacheSize;
    622  }
    623 
    624  return cacheSize;
    625 #else
    626  return kDefaultGlyphCacheSize;
    627 #endif  // MOZ_WIDGET_ANDROID
    628 }
    629 
    630 class WebRenderMemoryReporter final : public nsIMemoryReporter {
    631 public:
    632  NS_DECL_ISUPPORTS
    633  NS_DECL_NSIMEMORYREPORTER
    634 
    635 private:
    636  ~WebRenderMemoryReporter() = default;
    637 };
    638 
    639 // Memory reporter for WebRender.
    640 //
    641 // The reporting within WebRender is manual and incomplete. We could do a much
    642 // more thorough job by depending on the malloc_size_of crate, but integrating
    643 // that into WebRender is tricky [1].
    644 //
    645 // So the idea is to start with manual reporting for the large allocations
    646 // detected by DMD, and see how much that can cover in practice (which may
    647 // require a few rounds of iteration). If that approach turns out to be
    648 // fundamentally insufficient, we can either duplicate more of the
    649 // malloc_size_of functionality in WebRender, or deal with the complexity of a
    650 // gecko-only crate dependency.
    651 //
    652 // [1] See https://bugzilla.mozilla.org/show_bug.cgi?id=1480293#c1
    653 struct WebRenderMemoryReporterHelper {
    654  WebRenderMemoryReporterHelper(nsIHandleReportCallback* aCallback,
    655                                nsISupports* aData)
    656      : mCallback(aCallback), mData(aData) {}
    657  nsCOMPtr<nsIHandleReportCallback> mCallback;
    658  nsCOMPtr<nsISupports> mData;
    659 
    660  void Report(size_t aBytes, const char* aName) const {
    661    nsPrintfCString path("explicit/gfx/webrender/%s", aName);
    662    nsCString desc("CPU heap memory used by WebRender"_ns);
    663    ReportInternal(aBytes, path, desc, nsIMemoryReporter::KIND_HEAP);
    664  }
    665 
    666  void ReportTexture(size_t aBytes, const char* aName) const {
    667    nsPrintfCString path("gfx/webrender/textures/%s", aName);
    668    nsCString desc("GPU texture memory used by WebRender"_ns);
    669    ReportInternal(aBytes, path, desc, nsIMemoryReporter::KIND_OTHER);
    670  }
    671 
    672  void ReportTotalGPUBytes(size_t aBytes) const {
    673    nsCString path("gfx/webrender/total-gpu-bytes"_ns);
    674    nsCString desc(nsLiteralCString(
    675        "Total GPU bytes used by WebRender (should match textures/ sum)"));
    676    ReportInternal(aBytes, path, desc, nsIMemoryReporter::KIND_OTHER);
    677  }
    678 
    679  void ReportInternal(size_t aBytes, nsACString& aPath, nsACString& aDesc,
    680                      int32_t aKind) const {
    681    // Generally, memory reporters pass the empty string as the process name to
    682    // indicate "current process". However, if we're using a GPU process, the
    683    // measurements will actually take place in that process, and it's easier to
    684    // just note that here rather than trying to invoke the memory reporter in
    685    // the GPU process.
    686    nsAutoCString processName;
    687    if (gfxConfig::IsEnabled(Feature::GPU_PROCESS)) {
    688      GPUParent::GetGPUProcessName(processName);
    689    }
    690 
    691    mCallback->Callback(processName, aPath, aKind,
    692                        nsIMemoryReporter::UNITS_BYTES, aBytes, aDesc, mData);
    693  }
    694 };
    695 
    696 static void FinishAsyncMemoryReport() {
    697  nsCOMPtr<nsIMemoryReporterManager> imgr =
    698      do_GetService("@mozilla.org/memory-reporter-manager;1");
    699  if (imgr) {
    700    imgr->EndReport();
    701  }
    702 }
    703 
    704 // clang-format off
    705 // (For some reason, clang-format gets the second macro right, but totally mangles the first).
    706 #define REPORT_INTERNER(id)                      \
    707  helper.Report(aReport.interning.interners.id, \
    708                "interning/" #id "/interners");
    709 // clang-format on
    710 
    711 #define REPORT_DATA_STORE(id)                     \
    712  helper.Report(aReport.interning.data_stores.id, \
    713                "interning/" #id "/data-stores");
    714 
    715 NS_IMPL_ISUPPORTS(WebRenderMemoryReporter, nsIMemoryReporter)
    716 
    717 NS_IMETHODIMP
    718 WebRenderMemoryReporter::CollectReports(nsIHandleReportCallback* aHandleReport,
    719                                        nsISupports* aData, bool aAnonymize) {
    720  MOZ_ASSERT(XRE_IsParentProcess());
    721  MOZ_ASSERT(NS_IsMainThread());
    722  layers::CompositorManagerChild* manager =
    723      CompositorManagerChild::GetInstance();
    724  if (!manager) {
    725    FinishAsyncMemoryReport();
    726    return NS_OK;
    727  }
    728 
    729  WebRenderMemoryReporterHelper helper(aHandleReport, aData);
    730  manager->SendReportMemory(
    731      [=](wr::MemoryReport aReport) {
    732        // CPU Memory.
    733        helper.Report(aReport.clip_stores, "clip-stores");
    734        helper.Report(aReport.hit_testers, "hit-testers");
    735        helper.Report(aReport.fonts, "resource-cache/fonts");
    736        helper.Report(aReport.weak_fonts, "resource-cache/weak-fonts");
    737        helper.Report(aReport.images, "resource-cache/images");
    738        helper.Report(aReport.rasterized_blobs,
    739                      "resource-cache/rasterized-blobs");
    740        helper.Report(aReport.texture_cache_structures,
    741                      "texture-cache/structures");
    742        helper.Report(aReport.shader_cache, "shader-cache");
    743        helper.Report(aReport.display_list, "display-list");
    744        helper.Report(aReport.swgl, "swgl");
    745        helper.Report(aReport.upload_staging_memory, "upload-stagin-memory");
    746        helper.Report(aReport.frame_allocator, "frame-allocator");
    747        helper.Report(aReport.render_tasks, "frame-allocator/render-tasks");
    748 
    749        WEBRENDER_FOR_EACH_INTERNER(REPORT_INTERNER, );
    750        WEBRENDER_FOR_EACH_INTERNER(REPORT_DATA_STORE, );
    751 
    752        // GPU Memory.
    753        helper.ReportTexture(aReport.vertex_data_textures, "vertex-data");
    754        helper.ReportTexture(aReport.render_target_textures, "render-targets");
    755        helper.ReportTexture(aReport.depth_target_textures, "depth-targets");
    756        helper.ReportTexture(aReport.picture_tile_textures, "picture-tiles");
    757        helper.ReportTexture(aReport.atlas_textures, "texture-cache/atlas");
    758        helper.ReportTexture(aReport.standalone_textures,
    759                             "texture-cache/standalone");
    760        helper.ReportTexture(aReport.texture_upload_pbos,
    761                             "texture-upload-pbos");
    762        helper.ReportTexture(aReport.swap_chain, "swap-chains");
    763        helper.ReportTexture(aReport.render_texture_hosts,
    764                             "render-texture-hosts");
    765        helper.ReportTexture(aReport.upload_staging_textures,
    766                             "upload-staging-textures");
    767 
    768        FinishAsyncMemoryReport();
    769      },
    770      [](mozilla::ipc::ResponseRejectReason&& aReason) {
    771        FinishAsyncMemoryReport();
    772      });
    773 
    774  return NS_OK;
    775 }
    776 
    777 #undef REPORT_INTERNER
    778 #undef REPORT_DATA_STORE
    779 
    780 std::atomic<int8_t> gfxPlatform::sHasVariationFontSupport = -1;
    781 
    782 bool gfxPlatform::HasVariationFontSupport() {
    783  // We record the status here: 0 for not supported, 1 for supported.
    784  if (sHasVariationFontSupport < 0) {
    785    // It doesn't actually matter if we race with another thread setting this,
    786    // as any thread will set it to the same value.
    787 #if defined(XP_WIN)
    788    sHasVariationFontSupport = gfxWindowsPlatform::CheckVariationFontSupport();
    789 #elif defined(XP_DARWIN)
    790    sHasVariationFontSupport = gfxPlatformMac::CheckVariationFontSupport();
    791 #elif defined(MOZ_WIDGET_GTK)
    792    sHasVariationFontSupport = gfxPlatformGtk::CheckVariationFontSupport();
    793 #elif defined(ANDROID)
    794    sHasVariationFontSupport = gfxAndroidPlatform::CheckVariationFontSupport();
    795 #else
    796 #  error "No gfxPlatform implementation available"
    797 #endif
    798  }
    799  return sHasVariationFontSupport > 0;
    800 }
    801 
    802 void gfxPlatform::Init() {
    803  AUTO_PROFILER_MARKER_TEXT("gfxPlatform", GRAPHICS, {},
    804                            "gfxPlatform::Init"_ns);
    805  MOZ_RELEASE_ASSERT(!XRE_IsGPUProcess(), "GFX: Not allowed in GPU process.");
    806  MOZ_RELEASE_ASSERT(!XRE_IsRDDProcess(), "GFX: Not allowed in RDD process.");
    807  MOZ_RELEASE_ASSERT(NS_IsMainThread(), "GFX: Not in main thread.");
    808  MOZ_RELEASE_ASSERT(!gEverInitialized);
    809  if (XRE_IsContentProcess()) {
    810    MOZ_RELEASE_ASSERT(gContentDeviceInitData,
    811                       "Content Process should cal InitChild() before "
    812                       "first GetPlatform()");
    813  }
    814  gEverInitialized = true;
    815 
    816  gfxVars::Initialize();
    817 
    818  gfxConfig::Init();
    819 
    820  if (XRE_IsParentProcess()) {
    821    GPUProcessManager::Initialize();
    822    RDDProcessManager::Initialize();
    823 
    824    nsCOMPtr<nsIFile> file;
    825    nsresult rv = NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(file));
    826    if (NS_FAILED(rv)) {
    827      gfxVars::SetGREDirectory(nsString());
    828    } else {
    829      nsAutoString path;
    830      file->GetPath(path);
    831      gfxVars::SetGREDirectory(nsString(path));
    832    }
    833  }
    834 
    835  if (XRE_IsParentProcess()) {
    836    nsCOMPtr<nsIFile> profDir;
    837    nsresult rv = NS_GetSpecialDirectory(NS_APP_PROFILE_DIR_STARTUP,
    838                                         getter_AddRefs(profDir));
    839    if (NS_FAILED(rv)) {
    840      gfxVars::SetProfDirectory(nsString());
    841    } else {
    842      nsAutoString path;
    843      profDir->GetPath(path);
    844      gfxVars::SetProfDirectory(nsString(path));
    845    }
    846 
    847    nsAutoCString path;
    848    Preferences::GetCString("layers.windowrecording.path", path);
    849    gfxVars::SetLayersWindowRecordingPath(path);
    850 
    851    if (gFxREmbedded) {
    852      gfxVars::SetFxREmbedded(true);
    853    }
    854  }
    855 
    856  // Drop a note in the crash report if we end up forcing an option that could
    857  // destabilize things.  New items should be appended at the end (of an
    858  // existing or in a new section), so that we don't have to know the version to
    859  // interpret these cryptic strings.
    860  {
    861    nsAutoCString forcedPrefs;
    862    // Layers prefs
    863    forcedPrefs.AppendPrintf(
    864        "-L%d%d%d%d",
    865        StaticPrefs::layers_amd_switchable_gfx_enabled_AtStartup(),
    866        StaticPrefs::layers_acceleration_disabled_AtStartup_DoNotUseDirectly(),
    867        StaticPrefs::
    868            layers_acceleration_force_enabled_AtStartup_DoNotUseDirectly(),
    869 #ifdef XP_WIN
    870        StaticPrefs::layers_d3d11_force_warp_AtStartup()
    871 #else
    872        false
    873 #endif
    874    );
    875    // WebGL prefs
    876    forcedPrefs.AppendPrintf(
    877        "-W%d%d%d%d%d%d%d", StaticPrefs::webgl_angle_force_d3d11(),
    878        StaticPrefs::webgl_angle_force_warp(), StaticPrefs::webgl_disabled(),
    879        StaticPrefs::webgl_disable_angle(),
    880 #ifdef XP_WIN
    881        StaticPrefs::webgl_dxgl_enabled(),
    882 #else
    883        false,
    884 #endif
    885        StaticPrefs::webgl_force_enabled(), StaticPrefs::webgl_msaa_force());
    886    // Prefs that don't fit into any of the other sections
    887    forcedPrefs.AppendPrintf("-T%d) ", StaticPrefs::gfx_canvas_accelerated());
    888    ScopedGfxFeatureReporter::AppNote(forcedPrefs);
    889  }
    890 
    891  InitMoz2DLogging();
    892 
    893  /* Initialize the GfxInfo service.
    894   * Note: we can't call functions on GfxInfo that depend
    895   * on gPlatform until after it has been initialized
    896   * below. GfxInfo initialization annotates our
    897   * crash reports so we want to do it before
    898   * we try to load any drivers and do device detection
    899   * incase that code crashes. See bug #591561. */
    900  nsCOMPtr<nsIGfxInfo> gfxInfo;
    901  /* this currently will only succeed on Windows */
    902  gfxInfo = components::GfxInfo::Service();
    903 
    904  if (XRE_IsParentProcess()) {
    905    // Some gfxVars must be initialized prior gPlatform for coherent results.
    906    gfxVars::SetDXInterop2Blocked(IsDXInterop2Blocked());
    907    gfxVars::SetDXNV12Blocked(IsDXNV12Blocked());
    908    gfxVars::SetDXP010Blocked(IsDXP010Blocked());
    909    gfxVars::SetDXP016Blocked(IsDXP016Blocked());
    910  }
    911 
    912 #if defined(XP_WIN)
    913  gPlatform = new gfxWindowsPlatform;
    914 #elif defined(XP_DARWIN)
    915  gPlatform = new gfxPlatformMac;
    916 #elif defined(MOZ_WIDGET_GTK)
    917  gPlatform = new gfxPlatformGtk;
    918 #elif defined(ANDROID)
    919  gPlatform = new gfxAndroidPlatform;
    920 #else
    921 #  error "No gfxPlatform implementation available"
    922 #endif
    923  gPlatform->PopulateScreenInfo();
    924  gPlatform->InitAcceleration();
    925  gPlatform->InitWebRenderConfig();
    926 
    927  gPlatform->InitHardwareVideoConfig();
    928  gPlatform->InitWebGLConfig();
    929  gPlatform->InitWebGPUConfig();
    930  gPlatform->InitWindowOcclusionConfig();
    931  gPlatform->InitBackdropFilterConfig();
    932  gPlatform->InitAcceleratedCanvas2DConfig();
    933 
    934  if (XRE_IsParentProcess()) {
    935    // Monitor for sanity test changes.
    936    Preferences::RegisterCallbackAndCall(
    937        VideoDecodingFailedChangedCallback,
    938        "media.hardware-video-decoding.failed");
    939    Preferences::RegisterCallbackAndCall(HWDRMFailedChangedCallback,
    940                                         "media.eme.hwdrm.failed");
    941  }
    942 
    943 #if defined(XP_WIN)
    944  // When using WebRender, we defer initialization of the D3D11 devices until
    945  // the (rare) cases where they're used. Note that the GPU process where
    946  // WebRender runs doesn't initialize gfxPlatform and performs explicit
    947  // initialization of the bits it needs.
    948  if (XRE_IsParentProcess() && !gfxConfig::IsEnabled(Feature::GPU_PROCESS) &&
    949      StaticPrefs::
    950          gfx_webrender_enabled_no_gpu_process_with_angle_win_AtStartup()) {
    951    gPlatform->EnsureDevicesInitialized();
    952  }
    953 #endif
    954 
    955  if (XRE_IsParentProcess()) {
    956    mozilla::glean::gpu_process::feature_status.Set(
    957        gfxConfig::GetFeature(Feature::GPU_PROCESS)
    958            .GetStatusAndFailureIdString());
    959  }
    960 
    961  if (gfxConfig::IsEnabled(Feature::GPU_PROCESS)) {
    962    GPUProcessManager* gpu = GPUProcessManager::Get();
    963    (void)gpu->LaunchGPUProcess();
    964  }
    965 
    966  if (XRE_IsParentProcess()) {
    967    // Create the global vsync source and dispatcher.
    968    RefPtr<VsyncSource> vsyncSource =
    969        gfxPlatform::ForceSoftwareVsync()
    970            ? gPlatform->GetSoftwareVsyncSource()
    971            : gPlatform->GetGlobalHardwareVsyncSource();
    972    gPlatform->mVsyncDispatcher = new VsyncDispatcher(vsyncSource);
    973 
    974    // Listen for layout.frame_rate pref changes.
    975    Preferences::RegisterCallback(
    976        gfxPlatform::ReInitFrameRate,
    977        nsDependentCString(StaticPrefs::GetPrefName_layout_frame_rate()));
    978    Preferences::RegisterCallback(
    979        gfxPlatform::ReInitFrameRate,
    980        nsDependentCString(
    981            StaticPrefs::GetPrefName_privacy_resistFingerprinting()));
    982  }
    983 
    984  // Create the sRGB to output display profile transforms. They can be accessed
    985  // off the main thread so we want to avoid a race condition.
    986  gPlatform->InitializeCMS();
    987 
    988  SkGraphics::Init();
    989 #ifdef MOZ_ENABLE_FREETYPE
    990  SkInitCairoFT(gPlatform->FontHintingEnabled());
    991 #endif
    992  gfxGradientCache::Init();
    993 
    994  InitLayersIPC();
    995 
    996  // This *create* the platform font list instance, but may not *initialize* it
    997  // yet if the gfx.font-list.lazy-init.enabled pref is set. The first *use*
    998  // of the list will ensure it is initialized.
    999  if (!gPlatform->CreatePlatformFontList()) {
   1000    MOZ_CRASH("Could not initialize gfxPlatformFontList");
   1001  }
   1002 
   1003  gPlatform->mScreenReferenceDrawTarget =
   1004      gPlatform->CreateOffscreenContentDrawTarget(IntSize(1, 1),
   1005                                                  SurfaceFormat::B8G8R8A8);
   1006  if (!gPlatform->mScreenReferenceDrawTarget ||
   1007      !gPlatform->mScreenReferenceDrawTarget->IsValid()) {
   1008    // If TDR is detected, create a draw target with software backend
   1009    // and it should be replaced later when the process gets the device
   1010    // reset notification.
   1011    if (!gPlatform->DidRenderingDeviceReset()) {
   1012      gfxCriticalError() << "Could not initialize mScreenReferenceDrawTarget";
   1013    }
   1014  }
   1015 
   1016  if (NS_FAILED(gfxFontCache::Init())) {
   1017    MOZ_CRASH("Could not initialize gfxFontCache");
   1018  }
   1019 
   1020  Preferences::RegisterPrefixCallbacks(FontPrefChanged, kObservedPrefs);
   1021 
   1022  GLContext::PlatformStartup();
   1023 
   1024  // Listen to memory pressure event so we can purge DrawTarget caches
   1025  gPlatform->mMemoryPressureObserver =
   1026      layers::MemoryPressureObserver::Create(gPlatform);
   1027 
   1028  // Request the imgITools service, implicitly initializing ImageLib.
   1029  nsCOMPtr<imgITools> imgTools = do_GetService("@mozilla.org/image/tools;1");
   1030  if (!imgTools) {
   1031    MOZ_CRASH("Could not initialize ImageLib");
   1032  }
   1033 
   1034  RegisterStrongMemoryReporter(new GfxMemoryImageReporter());
   1035  if (XRE_IsParentProcess()) {
   1036    RegisterStrongAsyncMemoryReporter(new WebRenderMemoryReporter());
   1037  }
   1038 
   1039  RegisterStrongMemoryReporter(new SkMemoryReporter());
   1040 
   1041  uint32_t skiaCacheSize = GetSkiaGlyphCacheSize();
   1042  if (skiaCacheSize != kDefaultGlyphCacheSize) {
   1043    SkGraphics::SetFontCacheLimit(skiaCacheSize);
   1044  }
   1045 
   1046  InitNullMetadata();
   1047  InitOpenGLConfig();
   1048 
   1049  if (XRE_IsParentProcess()) {
   1050    Preferences::Unlock(FONT_VARIATIONS_PREF);
   1051    if (!gfxPlatform::HasVariationFontSupport()) {
   1052      // Ensure variation fonts are disabled and the pref is locked.
   1053      Preferences::SetBool(FONT_VARIATIONS_PREF, false, PrefValueKind::Default);
   1054      Preferences::SetBool(FONT_VARIATIONS_PREF, false);
   1055      Preferences::Lock(FONT_VARIATIONS_PREF);
   1056    }
   1057  }
   1058 
   1059  if (XRE_IsParentProcess()) {
   1060    ReportTelemetry();
   1061  }
   1062 
   1063  nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
   1064  if (obs) {
   1065    obs->NotifyObservers(nullptr, "gfx-features-ready", nullptr);
   1066  }
   1067 }
   1068 
   1069 void gfxPlatform::InitMemoryReportersForGPUProcess() {
   1070  MOZ_RELEASE_ASSERT(XRE_IsGPUProcess());
   1071 
   1072  RegisterStrongMemoryReporter(new GfxMemoryImageReporter());
   1073  RegisterStrongMemoryReporter(new SkMemoryReporter());
   1074 }
   1075 
   1076 void gfxPlatform::ReportTelemetry() {
   1077  MOZ_RELEASE_ASSERT(XRE_IsParentProcess(),
   1078                     "GFX: Only allowed to be called from parent process.");
   1079 
   1080  nsCOMPtr<nsIGfxInfo> gfxInfo = components::GfxInfo::Service();
   1081 
   1082  {
   1083    auto& screenManager = widget::ScreenManager::GetSingleton();
   1084    const uint32_t screenCount = screenManager.CurrentScreenList().Length();
   1085    RefPtr<widget::Screen> primaryScreen = screenManager.GetPrimaryScreen();
   1086    const LayoutDeviceIntRect rect = primaryScreen->GetRect();
   1087 
   1088    mozilla::glean::gfx_display::count.Set(screenCount);
   1089    mozilla::glean::gfx_display::primary_height.Set(rect.Height());
   1090    mozilla::glean::gfx_display::primary_width.Set(rect.Width());
   1091 
   1092    // Check if any screen known by screenManager supports HDR.
   1093    bool supportsHDR = false;
   1094    for (const auto& screen : screenManager.CurrentScreenList()) {
   1095      supportsHDR |= screen->GetIsHDR();
   1096    }
   1097    glean::gfx::supports_hdr.Set(supportsHDR);
   1098  }
   1099 
   1100  nsString adapterDesc;
   1101  gfxInfo->GetAdapterDescription(adapterDesc);
   1102 
   1103 // Android description is constructed in a way that makes it possible to exceed
   1104 // the metric's length limit.
   1105 #if defined(ANDROID)
   1106  if (!adapterDesc.IsEmpty()) {
   1107    adapterDesc.Truncate(99);
   1108  }
   1109 #endif
   1110 
   1111  mozilla::glean::gfx_adapter_primary::description.Set(
   1112      NS_ConvertUTF16toUTF8(adapterDesc));
   1113 
   1114  nsString adapterVendorId;
   1115  gfxInfo->GetAdapterVendorID(adapterVendorId);
   1116  mozilla::glean::gfx_adapter_primary::vendor_id.Set(
   1117      NS_ConvertUTF16toUTF8(adapterVendorId));
   1118 
   1119  nsString adapterDeviceId;
   1120  gfxInfo->GetAdapterDeviceID(adapterDeviceId);
   1121  mozilla::glean::gfx_adapter_primary::device_id.Set(
   1122      NS_ConvertUTF16toUTF8(adapterDeviceId));
   1123 
   1124  nsString adapterSubsystemId;
   1125  gfxInfo->GetAdapterSubsysID(adapterSubsystemId);
   1126  mozilla::glean::gfx_adapter_primary::subsystem_id.Set(
   1127      NS_ConvertUTF16toUTF8(adapterSubsystemId));
   1128 
   1129  uint32_t adapterRam = 0;
   1130  gfxInfo->GetAdapterRAM(&adapterRam);
   1131  mozilla::glean::gfx_adapter_primary::ram.Set(adapterRam);
   1132 
   1133  nsString adapterDriver;
   1134  gfxInfo->GetAdapterDriver(adapterDriver);
   1135  mozilla::glean::gfx_adapter_primary::driver_files.Set(
   1136      NS_ConvertUTF16toUTF8(adapterDriver));
   1137 
   1138  nsString adapterDriverVendor;
   1139  gfxInfo->GetAdapterDriverVendor(adapterDriverVendor);
   1140  mozilla::glean::gfx_adapter_primary::driver_vendor.Set(
   1141      NS_ConvertUTF16toUTF8(adapterDriverVendor));
   1142 
   1143  nsString adapterDriverVersion;
   1144  gfxInfo->GetAdapterDriverVersion(adapterDriverVersion);
   1145  mozilla::glean::gfx_adapter_primary::driver_version.Set(
   1146      NS_ConvertUTF16toUTF8(adapterDriverVersion));
   1147 
   1148  nsString adapterDriverDate;
   1149  gfxInfo->GetAdapterDriverDate(adapterDriverDate);
   1150  mozilla::glean::gfx_adapter_primary::driver_date.Set(
   1151      NS_ConvertUTF16toUTF8(adapterDriverDate));
   1152 
   1153  mozilla::glean::gfx_status::headless.Set(IsHeadless());
   1154 }
   1155 
   1156 static bool IsFeatureSupported(long aFeature, bool aDefault) {
   1157  nsCOMPtr<nsIGfxInfo> gfxInfo = components::GfxInfo::Service();
   1158  nsCString blockId;
   1159  int32_t status;
   1160  if (!NS_SUCCEEDED(gfxInfo->GetFeatureStatus(aFeature, blockId, &status))) {
   1161    return aDefault;
   1162  }
   1163  return status == nsIGfxInfo::FEATURE_STATUS_OK;
   1164 }
   1165 
   1166 /* static*/
   1167 bool gfxPlatform::IsDXInterop2Blocked() {
   1168  return !IsFeatureSupported(nsIGfxInfo::FEATURE_DX_INTEROP2, false);
   1169 }
   1170 
   1171 /* static*/
   1172 bool gfxPlatform::IsDXNV12Blocked() {
   1173  return !IsFeatureSupported(nsIGfxInfo::FEATURE_DX_NV12, false);
   1174 }
   1175 
   1176 /* static*/
   1177 bool gfxPlatform::IsDXP010Blocked() {
   1178  return !IsFeatureSupported(nsIGfxInfo::FEATURE_DX_P010, false);
   1179 }
   1180 
   1181 /* static*/
   1182 bool gfxPlatform::IsDXP016Blocked() {
   1183  return !IsFeatureSupported(nsIGfxInfo::FEATURE_DX_P016, false);
   1184 }
   1185 
   1186 /* static */
   1187 int32_t gfxPlatform::MaxTextureSize() {
   1188  // Make sure we don't completely break rendering because of a typo in the
   1189  // pref or whatnot.
   1190  const int32_t kMinSizePref = 2048;
   1191  return std::max(
   1192      kMinSizePref,
   1193      StaticPrefs::gfx_max_texture_size_AtStartup_DoNotUseDirectly());
   1194 }
   1195 
   1196 /* static */
   1197 int32_t gfxPlatform::MaxAllocSize() {
   1198  // Make sure we don't completely break rendering because of a typo in the
   1199  // pref or whatnot.
   1200  const int32_t kMinAllocPref = 10000000;
   1201  return std::max(kMinAllocPref,
   1202                  StaticPrefs::gfx_max_alloc_size_AtStartup_DoNotUseDirectly());
   1203 }
   1204 
   1205 void gfxPlatform::MaybeInitializeCMS() {
   1206  if (XRE_IsGPUProcess()) {
   1207    // Colors in the GPU process should already be managed, so we don't need to
   1208    // perform color management there.
   1209    gCMSInitialized = true;
   1210    return;
   1211  }
   1212  (void)GetPlatform();
   1213 }
   1214 
   1215 /* static */
   1216 void gfxPlatform::InitMoz2DLogging() {
   1217  auto fwd = new CrashStatsLogForwarder(
   1218      CrashReporter::Annotation::GraphicsCriticalError);
   1219  fwd->SetCircularBufferSize(StaticPrefs::gfx_logging_crash_length_AtStartup());
   1220 
   1221  mozilla::gfx::Config cfg;
   1222  cfg.mLogForwarder = fwd;
   1223  cfg.mMaxTextureSize = gfxPlatform::MaxTextureSize();
   1224  cfg.mMaxAllocSize = gfxPlatform::MaxAllocSize();
   1225 
   1226  gfx::Factory::Init(cfg);
   1227 }
   1228 
   1229 /* static */
   1230 bool gfxPlatform::IsHeadless() {
   1231  static bool initialized = false;
   1232  static bool headless = false;
   1233  if (!initialized) {
   1234    initialized = true;
   1235    headless = PR_GetEnv("MOZ_HEADLESS");
   1236  }
   1237  return headless;
   1238 }
   1239 
   1240 /* static */
   1241 bool gfxPlatform::UseRemoteCanvas() {
   1242  return XRE_IsContentProcess() && gfx::gfxVars::UseAcceleratedCanvas2D();
   1243 }
   1244 
   1245 /* static */
   1246 bool gfxPlatform::IsBackendAccelerated(
   1247    const mozilla::gfx::BackendType aBackendType) {
   1248  return false;
   1249 }
   1250 
   1251 static bool sLayersIPCIsUp = false;
   1252 
   1253 /* static */
   1254 void gfxPlatform::InitNullMetadata() {
   1255  ScrollMetadata::sNullMetadata = new ScrollMetadata();
   1256  ClearOnShutdown(&ScrollMetadata::sNullMetadata);
   1257 }
   1258 
   1259 void gfxPlatform::Shutdown() {
   1260  // In some cases, gPlatform may not be created but Shutdown() called,
   1261  // e.g., during xpcshell tests.
   1262  if (!gPlatform) {
   1263    return;
   1264  }
   1265 
   1266  MOZ_ASSERT(!sLayersIPCIsUp);
   1267 
   1268  // These may be called before the corresponding subsystems have actually
   1269  // started up. That's OK, they can handle it.
   1270  gfxFontCache::Shutdown();
   1271  gfxGradientCache::Shutdown();
   1272  gfxGaussianBlur::ShutdownBlurCache();
   1273  gfxGraphiteShaper::Shutdown();
   1274  gfxPlatformFontList::Shutdown();
   1275  gfxFontMissingGlyphs::Shutdown();
   1276 
   1277  // Free the various non-null transforms and loaded profiles
   1278  gPlatform->ShutdownCMS();
   1279 
   1280  Preferences::UnregisterPrefixCallbacks(FontPrefChanged, kObservedPrefs);
   1281 
   1282  NS_ASSERTION(gPlatform->mMemoryPressureObserver,
   1283               "mMemoryPressureObserver has already gone");
   1284  if (gPlatform->mMemoryPressureObserver) {
   1285    gPlatform->mMemoryPressureObserver->Unregister();
   1286    gPlatform->mMemoryPressureObserver = nullptr;
   1287  }
   1288 
   1289  if (XRE_IsParentProcess()) {
   1290    if (gPlatform->mGlobalHardwareVsyncSource) {
   1291      gPlatform->mGlobalHardwareVsyncSource->Shutdown();
   1292    }
   1293    if (gPlatform->mSoftwareVsyncSource &&
   1294        gPlatform->mSoftwareVsyncSource !=
   1295            gPlatform->mGlobalHardwareVsyncSource) {
   1296      gPlatform->mSoftwareVsyncSource->Shutdown();
   1297    }
   1298  }
   1299 
   1300  gPlatform->mGlobalHardwareVsyncSource = nullptr;
   1301  gPlatform->mSoftwareVsyncSource = nullptr;
   1302  gPlatform->mVsyncDispatcher = nullptr;
   1303 
   1304  // Shut down the default GL context provider.
   1305  GLContextProvider::Shutdown();
   1306 
   1307 #if defined(XP_WIN)
   1308  // The above shutdown calls operate on the available context providers on
   1309  // most platforms.  Windows is a "special snowflake", though, and has three
   1310  // context providers available, so we have to shut all of them down.
   1311  // We should only support the default GL provider on Windows; then, this
   1312  // could go away. Unfortunately, we currently support WGL (the default) for
   1313  // WebGL on Optimus.
   1314  GLContextProviderEGL::Shutdown();
   1315 #endif
   1316 
   1317  if (XRE_IsParentProcess()) {
   1318    GPUProcessManager::Shutdown();
   1319    VRProcessManager::Shutdown();
   1320    RDDProcessManager::Shutdown();
   1321  }
   1322 
   1323  gfx::Factory::ShutDown();
   1324  gfxVars::Shutdown();
   1325  gfxFont::DestroySingletons();
   1326 
   1327  gfxConfig::Shutdown();
   1328 
   1329  gPlatform->WillShutdown();
   1330 
   1331  delete gPlatform;
   1332  gPlatform = nullptr;
   1333 }
   1334 
   1335 /* static */
   1336 void gfxPlatform::InitLayersIPC() {
   1337  if (sLayersIPCIsUp) {
   1338    return;
   1339  }
   1340  sLayersIPCIsUp = true;
   1341 
   1342  if (XRE_IsParentProcess()) {
   1343 #if defined(XP_WIN)
   1344    if (gfxConfig::IsEnabled(gfx::Feature::WINDOW_OCCLUSION)) {
   1345      widget::WinWindowOcclusionTracker::Ensure();
   1346    }
   1347 #endif
   1348    if (!gfxConfig::IsEnabled(Feature::GPU_PROCESS)) {
   1349 #if defined(XP_WIN)
   1350      CompositeProcessD3D11FencesHolderMap::Init();
   1351 #endif
   1352      RemoteTextureMap::Init();
   1353      wr::RenderThread::Start(GPUProcessManager::Get()->AllocateNamespace());
   1354      image::ImageMemoryReporter::InitForWebRender();
   1355    }
   1356 
   1357    layers::CompositorThreadHolder::Start();
   1358 
   1359    if (!gfxConfig::IsEnabled(Feature::GPU_PROCESS)) {
   1360      gfx::CanvasRenderThread::Start();
   1361    }
   1362  }
   1363 }
   1364 
   1365 /* static */
   1366 void gfxPlatform::ShutdownLayersIPC() {
   1367  if (!sLayersIPCIsUp) {
   1368    return;
   1369  }
   1370  sLayersIPCIsUp = false;
   1371 
   1372  if (XRE_IsContentProcess()) {
   1373    gfx::VRManagerChild::ShutDown();
   1374    gfx::CanvasShutdownManager::Shutdown();
   1375    layers::CompositorManagerChild::Shutdown();
   1376    layers::ImageBridgeChild::ShutDown();
   1377  } else if (XRE_IsParentProcess()) {
   1378    VideoBridgeParent::Shutdown();
   1379    RDDProcessManager::RDDProcessShutdown();
   1380    gfx::VRManagerChild::ShutDown();
   1381    gfx::CanvasShutdownManager::Shutdown();
   1382    layers::CompositorManagerChild::Shutdown();
   1383    layers::ImageBridgeChild::ShutDown();
   1384    // This could be running on either the Compositor thread, the Renderer
   1385    // thread, or the dedicated CanvasRender thread, so we need to shutdown
   1386    // before the former two.
   1387    gfx::CanvasRenderThread::Shutdown();
   1388    // This has to happen after shutting down the child protocols.
   1389    layers::CompositorThreadHolder::Shutdown();
   1390    RemoteTextureMap::Shutdown();
   1391    image::ImageMemoryReporter::ShutdownForWebRender();
   1392    // There is a case that RenderThread exists when UseWebRender() is
   1393    // false. This could happen when WebRender was fallbacked to compositor.
   1394    if (wr::RenderThread::Get()) {
   1395      wr::RenderThread::ShutDown();
   1396 
   1397      Preferences::UnregisterCallback(WebRenderDebugPrefChangeCallback,
   1398                                      WR_DEBUG_PREF);
   1399      Preferences::UnregisterCallback(WebRendeProfilerUIPrefChangeCallback,
   1400                                      "gfx.webrender.debug.profiler-ui");
   1401      Preferences::UnregisterCallback(
   1402          WebRenderBlobTileSizePrefChangeCallback,
   1403          nsDependentCString(
   1404              StaticPrefs::GetPrefName_gfx_webrender_blob_tile_size()));
   1405    }
   1406 #if defined(XP_WIN)
   1407    CompositeProcessD3D11FencesHolderMap::Shutdown();
   1408    widget::WinWindowOcclusionTracker::ShutDown();
   1409 #endif
   1410  } else {
   1411    // TODO: There are other kind of processes and we should make sure gfx
   1412    // stuff is either not created there or shut down properly.
   1413  }
   1414 }
   1415 
   1416 void gfxPlatform::WillShutdown() {
   1417  // Destoy these first in case they depend on backend-specific resources.
   1418  // Otherwise, the backend's destructor would be called before the
   1419  // base gfxPlatform destructor.
   1420  mScreenReferenceSurface = nullptr;
   1421  mScreenReferenceDrawTarget = nullptr;
   1422 
   1423  // Always clear out the Skia font cache here, in case it is referencing any
   1424  // SharedFTFaces that would otherwise outlive destruction of the FT_Library
   1425  // that owns them.
   1426  SkGraphics::PurgeFontCache();
   1427 
   1428  // The cairo folks think we should only clean up in debug builds,
   1429  // but we're generally in the habit of trying to shut down as
   1430  // cleanly as possible even in production code, so call this
   1431  // cairo_debug_* function unconditionally.
   1432  //
   1433  // because cairo can assert and thus crash on shutdown, don't do this in
   1434  // release builds
   1435 #ifdef NS_FREE_PERMANENT_DATA
   1436  cairo_debug_reset_static_data();
   1437 #endif
   1438 }
   1439 
   1440 gfxPlatform::~gfxPlatform() = default;
   1441 
   1442 /* static */
   1443 already_AddRefed<DrawTarget> gfxPlatform::CreateDrawTargetForSurface(
   1444    gfxASurface* aSurface, const IntSize& aSize) {
   1445  SurfaceFormat format = aSurface->GetSurfaceFormat();
   1446  RefPtr<DrawTarget> drawTarget = Factory::CreateDrawTargetForCairoSurface(
   1447      aSurface->CairoSurface(), aSize, &format);
   1448  if (!drawTarget) {
   1449    gfxWarning() << "gfxPlatform::CreateDrawTargetForSurface failed in "
   1450                    "CreateDrawTargetForCairoSurface";
   1451    return nullptr;
   1452  }
   1453  return drawTarget.forget();
   1454 }
   1455 
   1456 cairo_user_data_key_t kSourceSurface;
   1457 
   1458 /**
   1459 * Record the backend that was used to construct the SourceSurface.
   1460 * When getting the cached SourceSurface for a gfxASurface/DrawTarget pair,
   1461 * we check to make sure the DrawTarget's backend matches the backend
   1462 * for the cached SourceSurface, and only use it if they match. This
   1463 * can avoid expensive and unnecessary readbacks.
   1464 */
   1465 struct SourceSurfaceUserData {
   1466  RefPtr<SourceSurface> mSrcSurface;
   1467  BackendType mBackendType;
   1468 };
   1469 
   1470 static void SourceBufferDestroy(void* srcSurfUD) {
   1471  delete static_cast<SourceSurfaceUserData*>(srcSurfUD);
   1472 }
   1473 
   1474 UserDataKey kThebesSurface;
   1475 
   1476 struct DependentSourceSurfaceUserData {
   1477  RefPtr<gfxASurface> mSurface;
   1478 };
   1479 
   1480 static void SourceSurfaceDestroyed(void* aData) {
   1481  delete static_cast<DependentSourceSurfaceUserData*>(aData);
   1482 }
   1483 
   1484 void gfxPlatform::ClearSourceSurfaceForSurface(gfxASurface* aSurface) {
   1485  aSurface->SetData(&kSourceSurface, nullptr, nullptr);
   1486 }
   1487 
   1488 /* static */
   1489 already_AddRefed<SourceSurface> gfxPlatform::GetSourceSurfaceForSurface(
   1490    RefPtr<DrawTarget> aTarget, gfxASurface* aSurface, bool aIsPlugin) {
   1491  if (!aSurface->CairoSurface() || aSurface->CairoStatus()) {
   1492    return nullptr;
   1493  }
   1494 
   1495  if (!aTarget) {
   1496    aTarget = gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget();
   1497  }
   1498 
   1499  void* userData = aSurface->GetData(&kSourceSurface);
   1500 
   1501  if (userData) {
   1502    SourceSurfaceUserData* surf = static_cast<SourceSurfaceUserData*>(userData);
   1503 
   1504    if (surf->mSrcSurface->IsValid() &&
   1505        surf->mBackendType == aTarget->GetBackendType()) {
   1506      RefPtr<SourceSurface> srcSurface(surf->mSrcSurface);
   1507      return srcSurface.forget();
   1508    }
   1509    // We can just continue here as when setting new user data the destroy
   1510    // function will be called for the old user data.
   1511  }
   1512 
   1513  SurfaceFormat format = aSurface->GetSurfaceFormat();
   1514 
   1515  if (aTarget->GetBackendType() == BackendType::CAIRO) {
   1516    // If we're going to be used with a CAIRO DrawTarget, then just create a
   1517    // SourceSurfaceCairo since we don't know the underlying type of the CAIRO
   1518    // DrawTarget and can't pick a better surface type. Doing this also avoids
   1519    // readback of aSurface's surface into memory if, for example, aSurface
   1520    // wraps an xlib cairo surface (which can be important to avoid a major
   1521    // slowdown).
   1522    //
   1523    // We return here regardless of whether CreateSourceSurfaceFromNativeSurface
   1524    // succeeds or not since we don't expect to be able to do any better below
   1525    // if it fails.
   1526    //
   1527    // Note that the returned SourceSurfaceCairo holds a strong reference to
   1528    // the cairo_surface_t* that it wraps, which essencially means it holds a
   1529    // strong reference to aSurface since aSurface shares its
   1530    // cairo_surface_t*'s reference count variable. As a result we can't cache
   1531    // srcBuffer on aSurface (see below) since aSurface would then hold a
   1532    // strong reference back to srcBuffer, creating a reference loop and a
   1533    // memory leak. Not caching is fine since wrapping is cheap enough (no
   1534    // copying) so we can just wrap again next time we're called.
   1535    return Factory::CreateSourceSurfaceForCairoSurface(
   1536        aSurface->CairoSurface(), aSurface->GetSize(), format);
   1537  }
   1538 
   1539  RefPtr<SourceSurface> srcBuffer;
   1540 
   1541  // Currently no other DrawTarget types implement
   1542  // CreateSourceSurfaceFromNativeSurface
   1543 
   1544  if (!srcBuffer) {
   1545    // If aSurface wraps data, we can create a SourceSurfaceRawData that wraps
   1546    // the same data, then optimize it for aTarget:
   1547    RefPtr<DataSourceSurface> surf = GetWrappedDataSourceSurface(aSurface);
   1548    if (surf) {
   1549      srcBuffer = aIsPlugin
   1550                      ? aTarget->OptimizeSourceSurfaceForUnknownAlpha(surf)
   1551                      : aTarget->OptimizeSourceSurface(surf);
   1552 
   1553      if (srcBuffer == surf) {
   1554        // GetWrappedDataSourceSurface returns a SourceSurface that holds a
   1555        // strong reference to aSurface since it wraps aSurface's data and
   1556        // needs it to stay alive. As a result we can't cache srcBuffer on
   1557        // aSurface (below) since aSurface would then hold a strong reference
   1558        // back to srcBuffer, creating a reference loop and a memory leak. Not
   1559        // caching is fine since wrapping is cheap enough (no copying) so we
   1560        // can just wrap again next time we're called.
   1561        //
   1562        // Note that the check below doesn't catch this since srcBuffer will be
   1563        // a SourceSurfaceRawData object (even if aSurface is not a
   1564        // gfxImageSurface object), which is why we need this separate check.
   1565        return srcBuffer.forget();
   1566      }
   1567    }
   1568  }
   1569 
   1570  if (!srcBuffer) {
   1571    MOZ_ASSERT(aTarget->GetBackendType() != BackendType::CAIRO,
   1572               "We already tried CreateSourceSurfaceFromNativeSurface with a "
   1573               "DrawTargetCairo above");
   1574    // We've run out of performant options. We now try creating a SourceSurface
   1575    // using a temporary DrawTargetCairo and then optimizing it to aTarget's
   1576    // actual type. The CreateSourceSurfaceFromNativeSurface() call will
   1577    // likely create a DataSourceSurface (possibly involving copying and/or
   1578    // readback), and the OptimizeSourceSurface may well copy again and upload
   1579    // to the GPU. So, while this code path is rarely hit, hitting it may be
   1580    // very slow.
   1581    srcBuffer = Factory::CreateSourceSurfaceForCairoSurface(
   1582        aSurface->CairoSurface(), aSurface->GetSize(), format);
   1583    if (srcBuffer) {
   1584      srcBuffer = aTarget->OptimizeSourceSurface(srcBuffer);
   1585    }
   1586  }
   1587 
   1588  if (!srcBuffer) {
   1589    return nullptr;
   1590  }
   1591 
   1592  if ((srcBuffer->GetType() == SurfaceType::CAIRO &&
   1593       static_cast<SourceSurfaceCairo*>(srcBuffer.get())->GetSurface() ==
   1594           aSurface->CairoSurface()) ||
   1595      (srcBuffer->GetType() == SurfaceType::CAIRO_IMAGE &&
   1596       static_cast<DataSourceSurfaceCairo*>(srcBuffer.get())->GetSurface() ==
   1597           aSurface->CairoSurface())) {
   1598    // See the "Note that the returned SourceSurfaceCairo..." comment above.
   1599    return srcBuffer.forget();
   1600  }
   1601 
   1602  // Add user data to aSurface so we can cache lookups in the future.
   1603  auto* srcSurfUD = new SourceSurfaceUserData;
   1604  srcSurfUD->mBackendType = aTarget->GetBackendType();
   1605  srcSurfUD->mSrcSurface = srcBuffer;
   1606  aSurface->SetData(&kSourceSurface, srcSurfUD, SourceBufferDestroy);
   1607 
   1608  return srcBuffer.forget();
   1609 }
   1610 
   1611 already_AddRefed<DataSourceSurface> gfxPlatform::GetWrappedDataSourceSurface(
   1612    gfxASurface* aSurface) {
   1613  RefPtr<gfxImageSurface> image = aSurface->GetAsImageSurface();
   1614  if (!image) {
   1615    return nullptr;
   1616  }
   1617  RefPtr<DataSourceSurface> result = Factory::CreateWrappingDataSourceSurface(
   1618      image->Data(), image->Stride(), image->GetSize(),
   1619      ImageFormatToSurfaceFormat(image->Format()));
   1620 
   1621  if (!result) {
   1622    return nullptr;
   1623  }
   1624 
   1625  // If we wrapped the underlying data of aSurface, then we need to add user
   1626  // data to make sure aSurface stays alive until we are done with the data.
   1627  auto* srcSurfUD = new DependentSourceSurfaceUserData;
   1628  srcSurfUD->mSurface = aSurface;
   1629  result->AddUserData(&kThebesSurface, srcSurfUD, SourceSurfaceDestroyed);
   1630 
   1631  return result.forget();
   1632 }
   1633 
   1634 void gfxPlatform::PopulateScreenInfo() {
   1635  // We're only going to set some gfxVars here, which is only possible from
   1636  // the parent process.
   1637  if (!XRE_IsParentProcess()) {
   1638    return;
   1639  }
   1640 
   1641  nsCOMPtr<nsIScreenManager> manager =
   1642      do_GetService("@mozilla.org/gfx/screenmanager;1");
   1643  MOZ_ASSERT(manager, "failed to get nsIScreenManager");
   1644 
   1645  nsCOMPtr<nsIScreen> screen;
   1646  manager->GetPrimaryScreen(getter_AddRefs(screen));
   1647  if (!screen) {
   1648    // This can happen in xpcshell, for instance
   1649    return;
   1650  }
   1651 
   1652  int32_t screenDepth;
   1653  screen->GetColorDepth(&screenDepth);
   1654  gfxVars::SetPrimaryScreenDepth(screenDepth);
   1655 }
   1656 
   1657 bool gfxPlatform::SupportsAzureContentForDrawTarget(DrawTarget* aTarget) {
   1658  if (!aTarget || !aTarget->IsValid()) {
   1659    return false;
   1660  }
   1661 
   1662  return SupportsAzureContentForType(aTarget->GetBackendType());
   1663 }
   1664 
   1665 void gfxPlatform::PurgeSkiaFontCache() {
   1666  if (gfxPlatform::GetPlatform()->GetDefaultContentBackend() ==
   1667      BackendType::SKIA) {
   1668    SkGraphics::PurgeFontCache();
   1669  }
   1670 }
   1671 
   1672 already_AddRefed<DrawTarget> gfxPlatform::CreateDrawTargetForBackend(
   1673    BackendType aBackend, const IntSize& aSize, SurfaceFormat aFormat) {
   1674  // There is a bunch of knowledge in the gfxPlatform heirarchy about how to
   1675  // create the best offscreen surface for the current system and situation. We
   1676  // can easily take advantage of this for the Cairo backend, so that's what we
   1677  // do.
   1678  // mozilla::gfx::Factory can get away without having all this knowledge for
   1679  // now, but this might need to change in the future (using
   1680  // CreateOffscreenSurface() and CreateDrawTargetForSurface() for all
   1681  // backends).
   1682  if (aBackend == BackendType::CAIRO) {
   1683    RefPtr<gfxASurface> surf =
   1684        CreateOffscreenSurface(aSize, SurfaceFormatToImageFormat(aFormat));
   1685    if (!surf || surf->CairoStatus()) {
   1686      return nullptr;
   1687    }
   1688    return CreateDrawTargetForSurface(surf, aSize);
   1689  }
   1690  return Factory::CreateDrawTarget(aBackend, aSize, aFormat);
   1691 }
   1692 
   1693 already_AddRefed<DrawTarget> gfxPlatform::CreateOffscreenCanvasDrawTarget(
   1694    const IntSize& aSize, SurfaceFormat aFormat, bool aRequireSoftwareRender) {
   1695  NS_ASSERTION(mPreferredCanvasBackend != BackendType::NONE, "No backend.");
   1696 
   1697  BackendType backend = mFallbackCanvasBackend;
   1698  // If we are using remote canvas we don't want to use acceleration in
   1699  // canvas DrawTargets we are not remoting, so we always use the fallback
   1700  // software one.
   1701  if (!gfxPlatform::UseRemoteCanvas() ||
   1702      !gfxPlatform::IsBackendAccelerated(mPreferredCanvasBackend)) {
   1703    backend = mPreferredCanvasBackend;
   1704  }
   1705 
   1706  if (aRequireSoftwareRender) {
   1707    backend = gfxPlatform::IsBackendAccelerated(mPreferredCanvasBackend)
   1708                  ? mFallbackCanvasBackend
   1709                  : mPreferredCanvasBackend;
   1710  }
   1711 
   1712 #ifdef XP_WIN
   1713  // On Windows, the fallback backend (Cairo) should use its image backend.
   1714  RefPtr<DrawTarget> target =
   1715      Factory::CreateDrawTarget(backend, aSize, aFormat);
   1716 #else
   1717  RefPtr<DrawTarget> target =
   1718      CreateDrawTargetForBackend(backend, aSize, aFormat);
   1719 #endif
   1720 
   1721  if (target || mFallbackCanvasBackend == BackendType::NONE) {
   1722    return target.forget();
   1723  }
   1724 
   1725 #ifdef XP_WIN
   1726  // On Windows, the fallback backend (Cairo) should use its image backend.
   1727  return Factory::CreateDrawTarget(mFallbackCanvasBackend, aSize, aFormat);
   1728 #else
   1729  return CreateDrawTargetForBackend(mFallbackCanvasBackend, aSize, aFormat);
   1730 #endif
   1731 }
   1732 
   1733 already_AddRefed<DrawTarget> gfxPlatform::CreateOffscreenContentDrawTarget(
   1734    const IntSize& aSize, SurfaceFormat aFormat, bool aFallback) {
   1735  BackendType backend = (aFallback) ? mSoftwareBackend : mContentBackend;
   1736  NS_ASSERTION(backend != BackendType::NONE, "No backend.");
   1737  RefPtr<DrawTarget> dt = CreateDrawTargetForBackend(backend, aSize, aFormat);
   1738 
   1739  if (!dt) {
   1740    return nullptr;
   1741  }
   1742 
   1743  // We'd prefer this to take proper care and return a CaptureDT, but for the
   1744  // moment since we can't and this means we're going to be drawing on the main
   1745  // thread force it's initialization. See bug 1526045 and bug 1521368.
   1746  dt->ClearRect(gfx::Rect());
   1747  if (!dt->IsValid()) {
   1748    return nullptr;
   1749  }
   1750  return dt.forget();
   1751 }
   1752 
   1753 already_AddRefed<DrawTarget> gfxPlatform::CreateSimilarSoftwareDrawTarget(
   1754    DrawTarget* aDT, const IntSize& aSize, SurfaceFormat aFormat) {
   1755  RefPtr<DrawTarget> dt;
   1756 
   1757  if (Factory::DoesBackendSupportDataDrawtarget(aDT->GetBackendType())) {
   1758    dt = aDT->CreateSimilarDrawTarget(aSize, aFormat);
   1759  } else {
   1760    BackendType backendType = BackendType::SKIA;
   1761    dt = Factory::CreateDrawTarget(backendType, aSize, aFormat);
   1762  }
   1763 
   1764  return dt.forget();
   1765 }
   1766 
   1767 /* static */
   1768 already_AddRefed<DrawTarget> gfxPlatform::CreateDrawTargetForData(
   1769    unsigned char* aData, const IntSize& aSize, int32_t aStride,
   1770    SurfaceFormat aFormat, bool aUninitialized, bool aIsClear) {
   1771  BackendType backendType = gfxVars::ContentBackend();
   1772  NS_ASSERTION(backendType != BackendType::NONE, "No backend.");
   1773 
   1774  if (!Factory::DoesBackendSupportDataDrawtarget(backendType)) {
   1775    backendType = BackendType::SKIA;
   1776  }
   1777 
   1778  RefPtr<DrawTarget> dt = Factory::CreateDrawTargetForData(
   1779      backendType, aData, aSize, aStride, aFormat, aUninitialized, aIsClear);
   1780 
   1781  return dt.forget();
   1782 }
   1783 
   1784 /* static */
   1785 BackendType gfxPlatform::BackendTypeForName(const nsCString& aName) {
   1786  if (aName.EqualsLiteral("cairo")) return BackendType::CAIRO;
   1787  if (aName.EqualsLiteral("skia")) return BackendType::SKIA;
   1788  return BackendType::NONE;
   1789 }
   1790 
   1791 nsresult gfxPlatform::GetFontList(nsAtom* aLangGroup,
   1792                                  const nsACString& aGenericFamily,
   1793                                  nsTArray<nsString>& aListOfFonts) {
   1794  gfxPlatformFontList::PlatformFontList()->GetFontList(
   1795      aLangGroup, aGenericFamily, aListOfFonts);
   1796  return NS_OK;
   1797 }
   1798 
   1799 nsresult gfxPlatform::UpdateFontList(bool aFullRebuild) {
   1800  gfxPlatformFontList::PlatformFontList()->UpdateFontList(aFullRebuild);
   1801  return NS_OK;
   1802 }
   1803 
   1804 void gfxPlatform::GetStandardFamilyName(const nsCString& aFontName,
   1805                                        nsACString& aFamilyName) {
   1806  gfxPlatformFontList::PlatformFontList()->GetStandardFamilyName(aFontName,
   1807                                                                 aFamilyName);
   1808 }
   1809 
   1810 nsAutoCString gfxPlatform::GetDefaultFontName(
   1811    const nsACString& aLangGroup, const nsACString& aGenericFamily) {
   1812  // To benefit from Return Value Optimization, all paths here must return
   1813  // this one variable:
   1814  nsAutoCString result;
   1815 
   1816  auto* pfl = gfxPlatformFontList::PlatformFontList();
   1817  FamilyAndGeneric fam = pfl->GetDefaultFontFamily(aLangGroup, aGenericFamily);
   1818  if (!pfl->GetLocalizedFamilyName(fam.mFamily, result)) {
   1819    NS_WARNING("missing default font-family name");
   1820  }
   1821 
   1822  return result;
   1823 }
   1824 
   1825 bool gfxPlatform::DownloadableFontsEnabled() {
   1826  if (mAllowDownloadableFonts == UNINITIALIZED_VALUE) {
   1827    mAllowDownloadableFonts =
   1828        Preferences::GetBool(GFX_DOWNLOADABLE_FONTS_ENABLED, false);
   1829  }
   1830 
   1831  return mAllowDownloadableFonts;
   1832 }
   1833 
   1834 bool gfxPlatform::UseCmapsDuringSystemFallback() {
   1835  return StaticPrefs::gfx_font_rendering_fallback_always_use_cmaps();
   1836 }
   1837 
   1838 bool gfxPlatform::OpenTypeSVGEnabled() {
   1839  return StaticPrefs::gfx_font_rendering_opentype_svg_enabled();
   1840 }
   1841 
   1842 uint32_t gfxPlatform::WordCacheCharLimit() {
   1843  return StaticPrefs::gfx_font_rendering_wordcache_charlimit();
   1844 }
   1845 
   1846 uint32_t gfxPlatform::WordCacheMaxEntries() {
   1847  return StaticPrefs::gfx_font_rendering_wordcache_maxentries();
   1848 }
   1849 
   1850 bool gfxPlatform::UseGraphiteShaping() {
   1851  return StaticPrefs::gfx_font_rendering_graphite_enabled();
   1852 }
   1853 
   1854 bool gfxPlatform::IsFontFormatSupported(
   1855    StyleFontFaceSourceFormatKeyword aFormatHint,
   1856    StyleFontFaceSourceTechFlags aTechFlags) {
   1857  // By default, font resources are assumed to be supported; but if the format
   1858  // hint or technology flags explicitly indicate something we don't support,
   1859  // then return false.
   1860  switch (aFormatHint) {
   1861    case StyleFontFaceSourceFormatKeyword::None:
   1862      break;
   1863    case StyleFontFaceSourceFormatKeyword::Collection:
   1864      return false;
   1865    case StyleFontFaceSourceFormatKeyword::Opentype:
   1866    case StyleFontFaceSourceFormatKeyword::Truetype:
   1867      break;
   1868    case StyleFontFaceSourceFormatKeyword::EmbeddedOpentype:
   1869      return false;
   1870    case StyleFontFaceSourceFormatKeyword::Svg:
   1871      return false;
   1872    case StyleFontFaceSourceFormatKeyword::Woff:
   1873      break;
   1874    case StyleFontFaceSourceFormatKeyword::Woff2:
   1875      break;
   1876    case StyleFontFaceSourceFormatKeyword::Unknown:
   1877      return false;
   1878    default:
   1879      MOZ_ASSERT_UNREACHABLE("bad format hint!");
   1880      return false;
   1881  }
   1882  StyleFontFaceSourceTechFlags unsupportedTechnologies =
   1883      StyleFontFaceSourceTechFlags::INCREMENTAL |
   1884      StyleFontFaceSourceTechFlags::COLOR_SBIX;
   1885  if (!StaticPrefs::gfx_downloadable_fonts_keep_color_bitmaps()) {
   1886    unsupportedTechnologies |= StyleFontFaceSourceTechFlags::COLOR_CBDT;
   1887  }
   1888  if (!StaticPrefs::gfx_font_rendering_colr_v1_enabled()) {
   1889    unsupportedTechnologies |= StyleFontFaceSourceTechFlags::COLOR_COLRV1;
   1890  }
   1891  if (!StaticPrefs::layout_css_font_palette_enabled()) {
   1892    unsupportedTechnologies |= StyleFontFaceSourceTechFlags::PALETTES;
   1893  }
   1894  if (!StaticPrefs::layout_css_font_variations_enabled()) {
   1895    unsupportedTechnologies |= StyleFontFaceSourceTechFlags::VARIATIONS;
   1896  }
   1897  if (aTechFlags & unsupportedTechnologies) {
   1898    return false;
   1899  }
   1900  return true;
   1901 }
   1902 
   1903 bool gfxPlatform::IsKnownIconFontFamily(const nsAtom* aFamilyName) const {
   1904  return gfxPlatformFontList::PlatformFontList()->IsKnownIconFontFamily(
   1905      aFamilyName);
   1906 }
   1907 
   1908 gfxFontEntry* gfxPlatform::LookupLocalFont(
   1909    FontVisibilityProvider* aFontVisibilityProvider,
   1910    const nsACString& aFontName, WeightRange aWeightForEntry,
   1911    StretchRange aStretchForEntry, SlantStyleRange aStyleForEntry) {
   1912  return gfxPlatformFontList::PlatformFontList()->LookupLocalFont(
   1913      aFontVisibilityProvider, aFontName, aWeightForEntry, aStretchForEntry,
   1914      aStyleForEntry);
   1915 }
   1916 
   1917 gfxFontEntry* gfxPlatform::MakePlatformFont(const nsACString& aFontName,
   1918                                            WeightRange aWeightForEntry,
   1919                                            StretchRange aStretchForEntry,
   1920                                            SlantStyleRange aStyleForEntry,
   1921                                            const uint8_t* aFontData,
   1922                                            uint32_t aLength) {
   1923  return gfxPlatformFontList::PlatformFontList()->MakePlatformFont(
   1924      aFontName, aWeightForEntry, aStretchForEntry, aStyleForEntry, aFontData,
   1925      aLength);
   1926 }
   1927 
   1928 BackendPrefsData gfxPlatform::GetBackendPrefs() const {
   1929  BackendPrefsData data;
   1930 
   1931  data.mCanvasBitmask = BackendTypeBit(BackendType::SKIA);
   1932  data.mContentBitmask = BackendTypeBit(BackendType::SKIA);
   1933 
   1934 #ifdef MOZ_WIDGET_GTK
   1935  data.mCanvasBitmask |= BackendTypeBit(BackendType::CAIRO);
   1936  data.mContentBitmask |= BackendTypeBit(BackendType::CAIRO);
   1937 #endif
   1938 
   1939  data.mCanvasDefault = BackendType::SKIA;
   1940  data.mContentDefault = BackendType::SKIA;
   1941 
   1942  return data;
   1943 }
   1944 
   1945 void gfxPlatform::InitBackendPrefs(BackendPrefsData&& aPrefsData) {
   1946  mPreferredCanvasBackend = GetCanvasBackendPref(aPrefsData.mCanvasBitmask);
   1947  if (mPreferredCanvasBackend == BackendType::NONE) {
   1948    mPreferredCanvasBackend = aPrefsData.mCanvasDefault;
   1949  }
   1950 
   1951  mFallbackCanvasBackend = GetCanvasBackendPref(
   1952      aPrefsData.mCanvasBitmask & ~BackendTypeBit(mPreferredCanvasBackend));
   1953 
   1954  mContentBackendBitmask = aPrefsData.mContentBitmask;
   1955  mContentBackend = GetContentBackendPref(mContentBackendBitmask);
   1956  if (mContentBackend == BackendType::NONE) {
   1957    mContentBackend = aPrefsData.mContentDefault;
   1958    // mContentBackendBitmask is our canonical reference for supported
   1959    // backends so we need to add the default if we are using it and
   1960    // overriding the prefs.
   1961    mContentBackendBitmask |= BackendTypeBit(aPrefsData.mContentDefault);
   1962  }
   1963 
   1964  uint32_t swBackendBits = BackendTypeBit(BackendType::SKIA);
   1965 #ifdef MOZ_WIDGET_GTK
   1966  swBackendBits |= BackendTypeBit(BackendType::CAIRO);
   1967 #endif
   1968  mSoftwareBackend = GetContentBackendPref(swBackendBits);
   1969  if (mSoftwareBackend == BackendType::NONE) {
   1970    mSoftwareBackend = BackendType::SKIA;
   1971  }
   1972 
   1973  // If we don't have a fallback canvas backend then use the same software
   1974  // fallback as content.
   1975  if (mFallbackCanvasBackend == BackendType::NONE) {
   1976    mFallbackCanvasBackend = mSoftwareBackend;
   1977  }
   1978 
   1979  if (XRE_IsParentProcess()) {
   1980    gfxVars::SetContentBackend(mContentBackend);
   1981    gfxVars::SetSoftwareBackend(mSoftwareBackend);
   1982  }
   1983 }
   1984 
   1985 /* static */
   1986 BackendType gfxPlatform::GetCanvasBackendPref(uint32_t aBackendBitmask) {
   1987  return GetBackendPref("gfx.canvas.azure.backends", aBackendBitmask);
   1988 }
   1989 
   1990 /* static */
   1991 BackendType gfxPlatform::GetContentBackendPref(uint32_t& aBackendBitmask) {
   1992  return GetBackendPref("gfx.content.azure.backends", aBackendBitmask);
   1993 }
   1994 
   1995 /* static */
   1996 BackendType gfxPlatform::GetBackendPref(const char* aBackendPrefName,
   1997                                        uint32_t& aBackendBitmask) {
   1998  nsTArray<nsCString> backendList;
   1999  nsAutoCString prefString;
   2000  if (NS_SUCCEEDED(Preferences::GetCString(aBackendPrefName, prefString))) {
   2001    ParseString(prefString, ',', backendList);
   2002  }
   2003 
   2004  uint32_t allowedBackends = 0;
   2005  BackendType result = BackendType::NONE;
   2006  for (uint32_t i = 0; i < backendList.Length(); ++i) {
   2007    BackendType type = BackendTypeForName(backendList[i]);
   2008    if (BackendTypeBit(type) & aBackendBitmask) {
   2009      allowedBackends |= BackendTypeBit(type);
   2010      if (result == BackendType::NONE) {
   2011        result = type;
   2012      }
   2013    }
   2014  }
   2015 
   2016  aBackendBitmask = allowedBackends;
   2017  return result;
   2018 }
   2019 
   2020 bool gfxPlatform::InSafeMode() {
   2021  static bool sSafeModeInitialized = false;
   2022  static bool sInSafeMode = false;
   2023 
   2024  if (!sSafeModeInitialized) {
   2025    sSafeModeInitialized = true;
   2026    nsCOMPtr<nsIXULRuntime> xr = do_GetService("@mozilla.org/xre/runtime;1");
   2027    if (xr) {
   2028      xr->GetInSafeMode(&sInSafeMode);
   2029    }
   2030  }
   2031  return sInSafeMode;
   2032 }
   2033 
   2034 bool gfxPlatform::OffMainThreadCompositingEnabled() {
   2035  return UsesOffMainThreadCompositing();
   2036 }
   2037 
   2038 void gfxPlatform::SetCMSModeOverride(CMSMode aMode) { gCMSMode = aMode; }
   2039 
   2040 int gfxPlatform::GetRenderingIntent() {
   2041  // StaticPrefList.yaml is using 0 as the default for the rendering
   2042  // intent preference, based on that being the value for
   2043  // QCMS_INTENT_DEFAULT.  Assert here to catch if that ever
   2044  // changes and we can then figure out what to do about it.
   2045  MOZ_ASSERT(QCMS_INTENT_DEFAULT == 0);
   2046 
   2047  /* Try to query the pref system for a rendering intent. */
   2048  int32_t pIntent = StaticPrefs::gfx_color_management_rendering_intent();
   2049  if ((pIntent < QCMS_INTENT_MIN) || (pIntent > QCMS_INTENT_MAX)) {
   2050    /* If the pref is out of range, use embedded profile. */
   2051    pIntent = -1;
   2052  }
   2053  return pIntent;
   2054 }
   2055 
   2056 DeviceColor gfxPlatform::TransformPixel(const sRGBColor& in,
   2057                                        qcms_transform* transform) {
   2058  if (transform) {
   2059    /* we want the bytes in RGB order */
   2060 #ifdef IS_LITTLE_ENDIAN
   2061    /* ABGR puts the bytes in |RGBA| order on little endian */
   2062    uint32_t packed = in.ToABGR();
   2063    qcms_transform_data(transform, (uint8_t*)&packed, (uint8_t*)&packed, 1);
   2064    auto out = DeviceColor::FromABGR(packed);
   2065 #else
   2066    /* ARGB puts the bytes in |ARGB| order on big endian */
   2067    uint32_t packed = in.UnusualToARGB();
   2068    /* add one to move past the alpha byte */
   2069    qcms_transform_data(transform, (uint8_t*)&packed + 1, (uint8_t*)&packed + 1,
   2070                        1);
   2071    auto out = DeviceColor::UnusualFromARGB(packed);
   2072 #endif
   2073    out.a = in.a;
   2074    return out;
   2075  }
   2076  return DeviceColor(in.r, in.g, in.b, in.a);
   2077 }
   2078 
   2079 nsTArray<uint8_t> gfxPlatform::GetPrefCMSOutputProfileData() {
   2080  const auto mirror = StaticPrefs::gfx_color_management_display_profile();
   2081  const auto fname = *mirror;
   2082  if (fname == "") {
   2083    return nsTArray<uint8_t>();
   2084  }
   2085 
   2086  void* mem = nullptr;
   2087  size_t size = 0;
   2088  qcms_data_from_path(fname.get(), &mem, &size);
   2089 
   2090  nsTArray<uint8_t> result;
   2091 
   2092  if (mem) {
   2093    result.AppendElements(static_cast<uint8_t*>(mem), size);
   2094    free(mem);
   2095  }
   2096 
   2097  return result;
   2098 }
   2099 
   2100 Maybe<nsTArray<uint8_t>>& gfxPlatform::GetCMSOutputProfileData() {
   2101  return mCMSOutputProfileData;
   2102 }
   2103 
   2104 CMSMode GfxColorManagementMode() {
   2105  const auto mode = StaticPrefs::gfx_color_management_mode();
   2106  if (mode >= 0 && mode <= UnderlyingValue(CMSMode::_ENUM_MAX)) {
   2107    return CMSMode(mode);
   2108  }
   2109  return CMSMode::Off;
   2110 }
   2111 
   2112 void gfxPlatform::InitializeCMS() {
   2113  gCMSInitialized = true;
   2114  gCMSMode = GfxColorManagementMode();
   2115 
   2116  mCMSsRGBProfile = qcms_profile_sRGB();
   2117 
   2118  /* Determine if we're using the internal override to force sRGB as
   2119     an output profile for reftests. See Bug 452125.
   2120 
   2121     Note that we don't normally (outside of tests) set a default value
   2122     of this preference, which means nsIPrefBranch::GetBoolPref will
   2123     typically throw (and leave its out-param untouched).
   2124   */
   2125  if (StaticPrefs::gfx_color_management_force_srgb() ||
   2126      StaticPrefs::gfx_color_management_native_srgb()) {
   2127    mCMSOutputProfile = mCMSsRGBProfile;
   2128  }
   2129 
   2130  if (!mCMSOutputProfile) {
   2131    nsTArray<uint8_t> outputProfileData = GetPlatformCMSOutputProfileData();
   2132    if (!outputProfileData.IsEmpty()) {
   2133      mCMSOutputProfile = qcms_profile_from_memory_curves_only(
   2134          outputProfileData.Elements(), outputProfileData.Length());
   2135    }
   2136  }
   2137 
   2138  /* Determine if the profile looks bogus. If so, close the profile
   2139   * and use sRGB instead. See bug 460629, */
   2140  if (mCMSOutputProfile && qcms_profile_is_bogus(mCMSOutputProfile)) {
   2141    NS_ASSERTION(mCMSOutputProfile != mCMSsRGBProfile,
   2142                 "Builtin sRGB profile tagged as bogus!!!");
   2143    qcms_profile_release(mCMSOutputProfile);
   2144    mCMSOutputProfile = nullptr;
   2145  }
   2146 
   2147  if (!mCMSOutputProfile) {
   2148    mCMSOutputProfile = mCMSsRGBProfile;
   2149  }
   2150 
   2151  /* Precache the LUT16 Interpolations for the output profile. See
   2152     bug 444661 for details. */
   2153  qcms_profile_precache_output_transform(mCMSOutputProfile);
   2154 
   2155  // Create the RGB transform.
   2156  mCMSRGBTransform =
   2157      qcms_transform_create(mCMSsRGBProfile, QCMS_DATA_RGB_8, mCMSOutputProfile,
   2158                            QCMS_DATA_RGB_8, QCMS_INTENT_PERCEPTUAL);
   2159 
   2160  // And the inverse.
   2161  mCMSInverseRGBTransform =
   2162      qcms_transform_create(mCMSOutputProfile, QCMS_DATA_RGB_8, mCMSsRGBProfile,
   2163                            QCMS_DATA_RGB_8, QCMS_INTENT_PERCEPTUAL);
   2164 
   2165  // The RGBA transform.
   2166  mCMSRGBATransform = qcms_transform_create(mCMSsRGBProfile, QCMS_DATA_RGBA_8,
   2167                                            mCMSOutputProfile, QCMS_DATA_RGBA_8,
   2168                                            QCMS_INTENT_PERCEPTUAL);
   2169 
   2170  // And the BGRA one.
   2171  mCMSBGRATransform = qcms_transform_create(mCMSsRGBProfile, QCMS_DATA_BGRA_8,
   2172                                            mCMSOutputProfile, QCMS_DATA_BGRA_8,
   2173                                            QCMS_INTENT_PERCEPTUAL);
   2174 
   2175  // FIXME: We only enable iccv4 after we create the platform profile, to
   2176  // wallpaper over bug 1697787.
   2177  //
   2178  // This should happen ideally right after setting gCMSMode.
   2179  if (StaticPrefs::gfx_color_management_enablev4()) {
   2180    qcms_enable_iccv4();
   2181  }
   2182 }
   2183 
   2184 qcms_transform* gfxPlatform::GetCMSOSRGBATransform() {
   2185  switch (SurfaceFormat::OS_RGBA) {
   2186    case SurfaceFormat::B8G8R8A8:
   2187      return GetCMSBGRATransform();
   2188    case SurfaceFormat::R8G8B8A8:
   2189      return GetCMSRGBATransform();
   2190    default:
   2191      // We do not support color management with big endian.
   2192      return nullptr;
   2193  }
   2194 }
   2195 
   2196 qcms_data_type gfxPlatform::GetCMSOSRGBAType() {
   2197  switch (SurfaceFormat::OS_RGBA) {
   2198    case SurfaceFormat::B8G8R8A8:
   2199      return QCMS_DATA_BGRA_8;
   2200    case SurfaceFormat::R8G8B8A8:
   2201      return QCMS_DATA_RGBA_8;
   2202    default:
   2203      // We do not support color management with big endian.
   2204      return QCMS_DATA_RGBA_8;
   2205  }
   2206 }
   2207 
   2208 /* Shuts down various transforms and profiles for CMS. */
   2209 void gfxPlatform::ShutdownCMS() {
   2210  if (mCMSRGBTransform) {
   2211    qcms_transform_release(mCMSRGBTransform);
   2212    mCMSRGBTransform = nullptr;
   2213  }
   2214  if (mCMSInverseRGBTransform) {
   2215    qcms_transform_release(mCMSInverseRGBTransform);
   2216    mCMSInverseRGBTransform = nullptr;
   2217  }
   2218  if (mCMSRGBATransform) {
   2219    qcms_transform_release(mCMSRGBATransform);
   2220    mCMSRGBATransform = nullptr;
   2221  }
   2222  if (mCMSBGRATransform) {
   2223    qcms_transform_release(mCMSBGRATransform);
   2224    mCMSBGRATransform = nullptr;
   2225  }
   2226  if (mCMSOutputProfile) {
   2227    // handle the aliased case
   2228    if (mCMSsRGBProfile == mCMSOutputProfile) {
   2229      mCMSsRGBProfile = nullptr;
   2230    }
   2231 
   2232    qcms_profile_release(mCMSOutputProfile);
   2233    mCMSOutputProfile = nullptr;
   2234  }
   2235  if (mCMSsRGBProfile) {
   2236    qcms_profile_release(mCMSsRGBProfile);
   2237    mCMSsRGBProfile = nullptr;
   2238  }
   2239 
   2240  // Reset the state variables
   2241  gCMSMode = CMSMode::Off;
   2242 }
   2243 
   2244 uint32_t gfxPlatform::GetBidiNumeralOption() {
   2245  return StaticPrefs::bidi_numeral();
   2246 }
   2247 
   2248 /* static */
   2249 void gfxPlatform::FlushFontAndWordCaches() {
   2250  gfxFontCache* fontCache = gfxFontCache::GetCache();
   2251  if (fontCache) {
   2252    fontCache->Flush();
   2253  }
   2254 
   2255  gfxPlatform::PurgeSkiaFontCache();
   2256 }
   2257 
   2258 /* static */
   2259 void gfxPlatform::ForceGlobalReflow(GlobalReflowFlags aFlags) {
   2260  MOZ_ASSERT(NS_IsMainThread());
   2261  bool reframe = !!(aFlags & GlobalReflowFlags::NeedsReframe);
   2262  // Send a notification that will be observed by PresShells in this process
   2263  // only.
   2264  if (nsCOMPtr<nsIObserverService> obs = services::GetObserverService()) {
   2265    char16_t needsReframe[] = {char16_t(reframe), 0};
   2266    obs->NotifyObservers(nullptr, "font-info-updated", needsReframe);
   2267  }
   2268  if (XRE_IsParentProcess() &&
   2269      aFlags & GlobalReflowFlags::BroadcastToChildren) {
   2270    // Propagate the change to child processes.
   2271    for (auto* process :
   2272         dom::ContentParent::AllProcesses(dom::ContentParent::eLive)) {
   2273      (void)process->SendForceGlobalReflow(aFlags);
   2274    }
   2275  }
   2276 }
   2277 
   2278 void gfxPlatform::FontsPrefsChanged(const char* aPref) {
   2279  NS_ASSERTION(aPref != nullptr, "null preference");
   2280  if (!strcmp(GFX_DOWNLOADABLE_FONTS_ENABLED, aPref)) {
   2281    mAllowDownloadableFonts = UNINITIALIZED_VALUE;
   2282  } else if (!strcmp(GFX_PREF_WORD_CACHE_CHARLIMIT, aPref) ||
   2283             !strcmp(GFX_PREF_WORD_CACHE_MAXENTRIES, aPref) ||
   2284             !strcmp(GFX_PREF_GRAPHITE_SHAPING, aPref)) {
   2285    FlushFontAndWordCaches();
   2286  } else if (
   2287 #if defined(XP_DARWIN)
   2288      !strcmp(GFX_PREF_CORETEXT_SHAPING, aPref) ||
   2289 #endif
   2290      !strcmp("gfx.font_rendering.ahem_antialias_none", aPref)) {
   2291    FlushFontAndWordCaches();
   2292  } else if (!strcmp(GFX_PREF_OPENTYPE_SVG, aPref)) {
   2293    gfxFontCache::GetCache()->Flush();
   2294    gfxFontCache::GetCache()->NotifyGlyphsChanged();
   2295  }
   2296 }
   2297 
   2298 mozilla::LogModule* gfxPlatform::GetLog(eGfxLog aWhichLog) {
   2299  // logs shared across gfx
   2300  static LazyLogModule sFontlistLog("fontlist");
   2301  static LazyLogModule sFontInitLog("fontinit");
   2302  static LazyLogModule sTextrunLog("textrun");
   2303  static LazyLogModule sTextrunuiLog("textrunui");
   2304  static LazyLogModule sCmapDataLog("cmapdata");
   2305  static LazyLogModule sTextPerfLog("textperf");
   2306 
   2307  switch (aWhichLog) {
   2308    case eGfxLog_fontlist:
   2309      return sFontlistLog;
   2310    case eGfxLog_fontinit:
   2311      return sFontInitLog;
   2312    case eGfxLog_textrun:
   2313      return sTextrunLog;
   2314    case eGfxLog_textrunui:
   2315      return sTextrunuiLog;
   2316    case eGfxLog_cmapdata:
   2317      return sCmapDataLog;
   2318    case eGfxLog_textperf:
   2319      return sTextPerfLog;
   2320  }
   2321 
   2322  MOZ_ASSERT_UNREACHABLE("Unexpected log type");
   2323  return nullptr;
   2324 }
   2325 
   2326 RefPtr<mozilla::gfx::DrawTarget> gfxPlatform::ScreenReferenceDrawTarget() {
   2327  MOZ_ASSERT_IF(XRE_IsContentProcess(), NS_IsMainThread());
   2328  return (mScreenReferenceDrawTarget)
   2329             ? mScreenReferenceDrawTarget
   2330             : gPlatform->CreateOffscreenContentDrawTarget(
   2331                   IntSize(1, 1), SurfaceFormat::B8G8R8A8, true);
   2332 }
   2333 
   2334 /* static */ RefPtr<mozilla::gfx::DrawTarget>
   2335 gfxPlatform::ThreadLocalScreenReferenceDrawTarget() {
   2336  if (NS_IsMainThread() && gPlatform) {
   2337    return gPlatform->ScreenReferenceDrawTarget();
   2338  }
   2339 
   2340  gfxPlatformWorker* platformWorker = gfxPlatformWorker::Get();
   2341  if (platformWorker) {
   2342    return platformWorker->ScreenReferenceDrawTarget();
   2343  }
   2344 
   2345  return Factory::CreateDrawTarget(BackendType::SKIA, IntSize(1, 1),
   2346                                   SurfaceFormat::B8G8R8A8);
   2347 }
   2348 
   2349 mozilla::gfx::SurfaceFormat gfxPlatform::Optimal2DFormatForContent(
   2350    gfxContentType aContent) {
   2351  switch (aContent) {
   2352    case gfxContentType::COLOR:
   2353      switch (GetOffscreenFormat()) {
   2354        case SurfaceFormat::A8R8G8B8_UINT32:
   2355          return mozilla::gfx::SurfaceFormat::B8G8R8A8;
   2356        case SurfaceFormat::X8R8G8B8_UINT32:
   2357          return mozilla::gfx::SurfaceFormat::B8G8R8X8;
   2358        case SurfaceFormat::R5G6B5_UINT16:
   2359          return mozilla::gfx::SurfaceFormat::R5G6B5_UINT16;
   2360        default:
   2361          MOZ_ASSERT_UNREACHABLE(
   2362              "unknown gfxImageFormat for "
   2363              "gfxContentType::COLOR");
   2364          return mozilla::gfx::SurfaceFormat::B8G8R8A8;
   2365      }
   2366    case gfxContentType::ALPHA:
   2367      return mozilla::gfx::SurfaceFormat::A8;
   2368    case gfxContentType::COLOR_ALPHA:
   2369      return mozilla::gfx::SurfaceFormat::B8G8R8A8;
   2370    default:
   2371      MOZ_ASSERT_UNREACHABLE("unknown gfxContentType");
   2372      return mozilla::gfx::SurfaceFormat::B8G8R8A8;
   2373  }
   2374 }
   2375 
   2376 gfxImageFormat gfxPlatform::OptimalFormatForContent(gfxContentType aContent) {
   2377  switch (aContent) {
   2378    case gfxContentType::COLOR:
   2379      return GetOffscreenFormat();
   2380    case gfxContentType::ALPHA:
   2381      return SurfaceFormat::A8;
   2382    case gfxContentType::COLOR_ALPHA:
   2383      return SurfaceFormat::A8R8G8B8_UINT32;
   2384    default:
   2385      MOZ_ASSERT_UNREACHABLE("unknown gfxContentType");
   2386      return SurfaceFormat::A8R8G8B8_UINT32;
   2387  }
   2388 }
   2389 
   2390 /**
   2391 * There are a number of layers acceleration (or layers in general) preferences
   2392 * that should be consistent for the lifetime of the application (bug 840967).
   2393 * As such, we will evaluate them all as soon as one of them is evaluated
   2394 * and remember the values.  Changing these preferences during the run will
   2395 * not have any effect until we restart.
   2396 */
   2397 static mozilla::Atomic<bool> sLayersAccelerationPrefsInitialized(false);
   2398 
   2399 /* static */
   2400 void gfxPlatform::VideoDecodingFailedChangedCallback(const char* aPref, void*) {
   2401  MOZ_ASSERT(XRE_IsParentProcess());
   2402  if (gPlatform) {
   2403    gPlatform->InitHardwareVideoConfig();
   2404  }
   2405 }
   2406 
   2407 /* static */
   2408 void gfxPlatform::HWDRMFailedChangedCallback(const char* aPref, void*) {
   2409  MOZ_ASSERT(XRE_IsParentProcess());
   2410  if (gPlatform) {
   2411    gPlatform->InitPlatformHardwarDRMConfig();
   2412  }
   2413 }
   2414 
   2415 void gfxPlatform::UpdateForceSubpixelAAWherePossible() {
   2416  bool forceSubpixelAAWherePossible =
   2417      StaticPrefs::gfx_webrender_quality_force_subpixel_aa_where_possible();
   2418  gfxVars::SetForceSubpixelAAWherePossible(forceSubpixelAAWherePossible);
   2419 }
   2420 
   2421 void gfxPlatform::InitAcceleration() {
   2422  if (sLayersAccelerationPrefsInitialized) {
   2423    return;
   2424  }
   2425 
   2426  InitCompositorAccelerationPrefs();
   2427 
   2428  // If this is called for the first time on a non-main thread, we're screwed.
   2429  // At the moment there's no explicit guarantee that the main thread calls
   2430  // this before the compositor thread, but let's at least make the assumption
   2431  // explicit.
   2432  MOZ_ASSERT(NS_IsMainThread(), "can only initialize prefs on the main thread");
   2433 
   2434  if (XRE_IsParentProcess()) {
   2435    gfxVars::SetBrowserTabsRemoteAutostart(BrowserTabsRemoteAutostart());
   2436    gfxVars::SetOffscreenFormat(GetOffscreenFormat());
   2437    gfxVars::SetRequiresAcceleratedGLContextForCompositorOGL(
   2438        RequiresAcceleratedGLContextForCompositorOGL());
   2439 #ifdef XP_WIN
   2440    nsCOMPtr<nsIGfxInfo> gfxInfo = components::GfxInfo::Service();
   2441    nsCString discardFailureId;
   2442    int32_t status;
   2443    if (NS_SUCCEEDED(
   2444            gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_D3D11_KEYED_MUTEX,
   2445                                      discardFailureId, &status))) {
   2446      gfxVars::SetAllowD3D11KeyedMutex(status == nsIGfxInfo::FEATURE_STATUS_OK);
   2447    } else {
   2448      // If we couldn't properly evaluate the status, err on the side
   2449      // of caution and give this functionality to the user.
   2450      gfxCriticalNote << "Cannot evaluate keyed mutex feature status";
   2451      gfxVars::SetAllowD3D11KeyedMutex(true);
   2452    }
   2453    if (StaticPrefs::gfx_direct3d11_use_double_buffering()) {
   2454      gfxVars::SetUseDoubleBufferingWithCompositor(true);
   2455    }
   2456 #endif
   2457  }
   2458 
   2459  sLayersAccelerationPrefsInitialized = true;
   2460 
   2461  if (XRE_IsParentProcess()) {
   2462    InitGPUProcessPrefs();
   2463  }
   2464 }
   2465 
   2466 void gfxPlatform::InitGPUProcessPrefs() {
   2467  // We want to hide this from about:support, so only set a default if the
   2468  // pref is known to be true.
   2469  if (!StaticPrefs::layers_gpu_process_enabled_AtStartup() &&
   2470      !StaticPrefs::layers_gpu_process_force_enabled_AtStartup()) {
   2471    return;
   2472  }
   2473 
   2474  FeatureState& gpuProc = gfxConfig::GetFeature(Feature::GPU_PROCESS);
   2475 
   2476  // We require E10S - otherwise, there is very little benefit to the GPU
   2477  // process, since the UI process must still use acceleration for
   2478  // performance.
   2479  if (!BrowserTabsRemoteAutostart()) {
   2480    gpuProc.DisableByDefault(FeatureStatus::Unavailable,
   2481                             "Multi-process mode is not enabled",
   2482                             "FEATURE_FAILURE_NO_E10S"_ns);
   2483  } else {
   2484    gpuProc.SetDefaultFromPref(
   2485        StaticPrefs::GetPrefName_layers_gpu_process_enabled(), true,
   2486        StaticPrefs::GetPrefDefault_layers_gpu_process_enabled());
   2487  }
   2488 
   2489  if (StaticPrefs::layers_gpu_process_force_enabled_AtStartup()) {
   2490    gpuProc.UserForceEnable("User force-enabled via pref");
   2491  }
   2492 
   2493  nsCString message;
   2494  nsCString failureId;
   2495  if (!gfxPlatform::IsGfxInfoStatusOkay(nsIGfxInfo::FEATURE_GPU_PROCESS,
   2496                                        &message, failureId)) {
   2497    gpuProc.Disable(FeatureStatus::Blocklisted, message.get(), failureId);
   2498    return;
   2499  }
   2500 
   2501  if (IsHeadless()) {
   2502    gpuProc.ForceDisable(FeatureStatus::Blocked, "Headless mode is enabled",
   2503                         "FEATURE_FAILURE_HEADLESS_MODE"_ns);
   2504    return;
   2505  }
   2506 
   2507  InitPlatformGPUProcessPrefs();
   2508 }
   2509 
   2510 void gfxPlatform::InitCompositorAccelerationPrefs() {
   2511  const char* acceleratedEnv = PR_GetEnv("MOZ_ACCELERATED");
   2512 
   2513  FeatureState& feature = gfxConfig::GetFeature(Feature::HW_COMPOSITING);
   2514 
   2515  // Base value - does the platform allow acceleration?
   2516  if (feature.SetDefault(AccelerateLayersByDefault(), FeatureStatus::Blocked,
   2517                         "Acceleration blocked by platform")) {
   2518    if (StaticPrefs::
   2519            layers_acceleration_disabled_AtStartup_DoNotUseDirectly()) {
   2520      feature.UserDisable("Disabled by layers.acceleration.disabled=true",
   2521                          "FEATURE_FAILURE_COMP_PREF"_ns);
   2522    } else if (acceleratedEnv && *acceleratedEnv == '0') {
   2523      feature.UserDisable("Disabled by envvar", "FEATURE_FAILURE_COMP_ENV"_ns);
   2524    }
   2525  } else {
   2526    if (acceleratedEnv && *acceleratedEnv == '1') {
   2527      feature.UserEnable("Enabled by envvar");
   2528    }
   2529  }
   2530 
   2531  // This has specific meaning elsewhere, so we always record it.
   2532  if (StaticPrefs::
   2533          layers_acceleration_force_enabled_AtStartup_DoNotUseDirectly()) {
   2534    feature.UserForceEnable("Force-enabled by pref");
   2535  }
   2536 
   2537  // Safe, headless, and record/replay modes override everything.
   2538  if (InSafeMode()) {
   2539    feature.ForceDisable(FeatureStatus::Blocked,
   2540                         "Acceleration blocked by safe-mode",
   2541                         "FEATURE_FAILURE_COMP_SAFEMODE"_ns);
   2542  }
   2543  if (IsHeadless()) {
   2544    feature.ForceDisable(FeatureStatus::Blocked,
   2545                         "Acceleration blocked by headless mode",
   2546                         "FEATURE_FAILURE_COMP_HEADLESSMODE"_ns);
   2547  }
   2548 }
   2549 
   2550 /*static*/
   2551 bool gfxPlatform::WebRenderPrefEnabled() {
   2552  return StaticPrefs::gfx_webrender_all_AtStartup();
   2553 }
   2554 
   2555 /*static*/
   2556 bool gfxPlatform::WebRenderEnvvarEnabled() {
   2557  const char* env = PR_GetEnv("MOZ_WEBRENDER");
   2558  return (env && *env == '1');
   2559 }
   2560 
   2561 /* static */ const char* gfxPlatform::WebRenderResourcePathOverride() {
   2562  const char* resourcePath = PR_GetEnv("WR_RESOURCE_PATH");
   2563  if (!resourcePath || resourcePath[0] == '\0') {
   2564    return nullptr;
   2565  }
   2566  return resourcePath;
   2567 }
   2568 
   2569 void gfxPlatform::InitWebRenderConfig() {
   2570  bool prefEnabled = WebRenderPrefEnabled();
   2571  bool envvarEnabled = WebRenderEnvvarEnabled();
   2572 
   2573  // WR? WR+   => means WR was enabled on qualified hardware
   2574  // WR! WR+   => means WR was enabled via gfx.webrender.{all,enabled} or
   2575  //              envvar, possibly on unqualified hardware
   2576  // In all cases WR- means WR was not enabled, for one of many possible
   2577  // reasons. Prior to bug 1523788 landing the gfx.webrender.{all,enabled}
   2578  // prefs only worked on Nightly so keep that in mind when looking at older
   2579  // crash reports.
   2580  ScopedGfxFeatureReporter reporter("WR", prefEnabled || envvarEnabled);
   2581  if (!XRE_IsParentProcess()) {
   2582    // The parent process runs through all the real decision-making code
   2583    // later in this function. For other processes we still want to report
   2584    // the state of the feature for crash reports.
   2585    reporter.SetSuccessful();
   2586    return;
   2587  }
   2588 
   2589  // Update the gfxConfig feature states.
   2590  gfxConfigManager manager;
   2591  manager.Init();
   2592  manager.ConfigureWebRender();
   2593 
   2594  if (gfxConfig::IsEnabled(Feature::GPU_PROCESS)) {
   2595    gfxVars::SetGPUProcessEnabled(true);
   2596  }
   2597 
   2598  bool hasHardware = gfxConfig::IsEnabled(Feature::WEBRENDER);
   2599 
   2600 #ifdef MOZ_WIDGET_GTK
   2601  // We require a hardware driver to back the GL context unless the user forced
   2602  // on WebRender.
   2603  if (!gfxConfig::IsForcedOnByUser(Feature::WEBRENDER) &&
   2604      StaticPrefs::gfx_webrender_reject_software_driver_AtStartup()) {
   2605    gfxVars::SetWebRenderRequiresHardwareDriver(true);
   2606  }
   2607 #endif
   2608 
   2609 #ifdef XP_WIN
   2610  if (gfxConfig::IsEnabled(Feature::WEBRENDER_ANGLE)) {
   2611    gfxVars::SetUseWebRenderANGLE(true);
   2612  }
   2613 #endif
   2614 
   2615  if (gfxConfig::IsEnabled(Feature::WEBRENDER_SHADER_CACHE)) {
   2616    gfxVars::SetUseWebRenderProgramBinaryDisk(true);
   2617    bool warmUp = true;
   2618 #ifdef MOZ_WIDGET_ANDROID
   2619    // Loading cached program binaries on the Samsung Xclipse driver on Android
   2620    // 14 is slightly faster than compiling shaders from source, so we still
   2621    // want to keep the disk cache enabled. However, it is slow enough that
   2622    // eagerly warming up the cache with shaders which may not be required can
   2623    // negatively impact performance. See bug 2007127.
   2624    if (jni::GetAPIVersion() == 34) {
   2625      const nsCOMPtr<nsIGfxInfo> gfxInfo = components::GfxInfo::Service();
   2626      nsAutoString renderer;
   2627      gfxInfo->GetAdapterDeviceID(renderer);
   2628      if (renderer.Find(u"Samsung Xclipse") != -1) {
   2629        warmUp = false;
   2630      }
   2631    }
   2632 #endif
   2633    gfxVars::SetShouldWarmUpWebRenderProgramBinaries(warmUp);
   2634  }
   2635 
   2636  gfxVars::SetUseWebRenderOptimizedShaders(
   2637      gfxConfig::IsEnabled(Feature::WEBRENDER_OPTIMIZED_SHADERS));
   2638 
   2639  gfxVars::SetUseSoftwareWebRender(!hasHardware);
   2640 
   2641  Preferences::RegisterPrefixCallbackAndCall(SwapIntervalPrefChangeCallback,
   2642                                             "gfx.swap-interval");
   2643 
   2644  reporter.SetSuccessful();
   2645 
   2646  Preferences::RegisterPrefixCallbackAndCall(WebRenderDebugPrefChangeCallback,
   2647                                             WR_DEBUG_PREF);
   2648 
   2649  RegisterWebRenderBoolParamCallback();
   2650 
   2651  Preferences::RegisterPrefixCallbackAndCall(
   2652      WebRendeProfilerUIPrefChangeCallback, "gfx.webrender.debug.profiler-ui");
   2653  Preferences::RegisterCallback(
   2654      WebRenderQualityPrefChangeCallback,
   2655      nsDependentCString(
   2656          StaticPrefs::
   2657              GetPrefName_gfx_webrender_quality_force_subpixel_aa_where_possible()));
   2658 
   2659  Preferences::RegisterCallback(
   2660      WebRenderBatchingPrefChangeCallback,
   2661      nsDependentCString(
   2662          StaticPrefs::GetPrefName_gfx_webrender_batching_lookback()));
   2663 
   2664  Preferences::RegisterCallbackAndCall(
   2665      WebRenderBlobTileSizePrefChangeCallback,
   2666      nsDependentCString(
   2667          StaticPrefs::GetPrefName_gfx_webrender_blob_tile_size()));
   2668 
   2669  Preferences::RegisterCallbackAndCall(
   2670      WebRenderUploadThresholdPrefChangeCallback,
   2671      nsDependentCString(
   2672          StaticPrefs::GetPrefName_gfx_webrender_batched_upload_threshold()));
   2673 
   2674  if (WebRenderResourcePathOverride()) {
   2675    CrashReporter::RecordAnnotationBool(
   2676        CrashReporter::Annotation::IsWebRenderResourcePathOverridden, true);
   2677  }
   2678 
   2679  UpdateForceSubpixelAAWherePossible();
   2680 
   2681 #if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GTK)
   2682  if (StaticPrefs::gfx_webrender_software_opengl_AtStartup()) {
   2683    gfxVars::SetAllowSoftwareWebRenderOGL(true);
   2684  }
   2685 #endif
   2686 
   2687 #ifdef XP_WIN
   2688  if (gfxConfig::IsEnabled(Feature::WEBRENDER_DCOMP_PRESENT)) {
   2689    gfxVars::SetUseWebRenderDCompWin(true);
   2690  }
   2691  if (StaticPrefs::gfx_webrender_software_d3d11_AtStartup()) {
   2692    gfxVars::SetAllowSoftwareWebRenderD3D11(true);
   2693  }
   2694 
   2695  const bool overlaySupported =
   2696      IsWin10AnniversaryUpdateOrLater() &&
   2697      gfxConfig::IsEnabled(Feature::WEBRENDER_COMPOSITOR);
   2698  MOZ_ASSERT_IF(overlaySupported,
   2699                gfxConfig::IsEnabled(Feature::WEBRENDER_DCOMP_PRESENT));
   2700 
   2701  bool useVideoHwOverlay = false;
   2702  if (StaticPrefs::gfx_webrender_dcomp_video_hw_overlay_win_AtStartup()) {
   2703    if (overlaySupported) {
   2704      useVideoHwOverlay = true;
   2705    }
   2706 
   2707    if (useVideoHwOverlay &&
   2708        !StaticPrefs::
   2709            gfx_webrender_dcomp_video_hw_overlay_win_force_enabled_AtStartup()) {
   2710      nsCString failureId;
   2711      int32_t status;
   2712      const nsCOMPtr<nsIGfxInfo> gfxInfo = components::GfxInfo::Service();
   2713      if (NS_FAILED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_VIDEO_OVERLAY,
   2714                                              failureId, &status))) {
   2715        FeatureState& feature =
   2716            gfxConfig::GetFeature(Feature::VIDEO_HARDWARE_OVERLAY);
   2717        feature.DisableByDefault(FeatureStatus::BlockedNoGfxInfo,
   2718                                 "gfxInfo is broken",
   2719                                 "FEATURE_FAILURE_WR_NO_GFX_INFO"_ns);
   2720        useVideoHwOverlay = false;
   2721      } else {
   2722        if (status != nsIGfxInfo::FEATURE_STATUS_OK) {
   2723          FeatureState& feature =
   2724              gfxConfig::GetFeature(Feature::VIDEO_HARDWARE_OVERLAY);
   2725          feature.DisableByDefault(FeatureStatus::Blocked,
   2726                                   "Blocklisted by gfxInfo", failureId);
   2727          useVideoHwOverlay = false;
   2728        }
   2729      }
   2730    }
   2731  } else if (overlaySupported) {
   2732    FeatureState& feature =
   2733        gfxConfig::GetFeature(Feature::VIDEO_HARDWARE_OVERLAY);
   2734    feature.DisableByDefault(FeatureStatus::Blocked, "Disabled by pref",
   2735                             "FEATURE_FAILURE_DISABLED_BY_PREF"_ns);
   2736  }
   2737 
   2738  if (useVideoHwOverlay) {
   2739    FeatureState& feature =
   2740        gfxConfig::GetFeature(Feature::VIDEO_HARDWARE_OVERLAY);
   2741    feature.EnableByDefault();
   2742    gfxVars::SetUseWebRenderDCompVideoHwOverlayWin(true);
   2743  }
   2744 
   2745  bool useVideoSwOverlay = false;
   2746  if (overlaySupported &&
   2747      StaticPrefs::gfx_webrender_dcomp_video_sw_overlay_win_AtStartup()) {
   2748    useVideoSwOverlay = true;
   2749 
   2750    if (useVideoSwOverlay &&
   2751        !StaticPrefs::
   2752            gfx_webrender_dcomp_video_sw_overlay_win_force_enabled_AtStartup()) {
   2753      nsCString failureId;
   2754      int32_t status;
   2755      const nsCOMPtr<nsIGfxInfo> gfxInfo = components::GfxInfo::Service();
   2756      if (NS_FAILED(gfxInfo->GetFeatureStatus(
   2757              nsIGfxInfo::FEATURE_VIDEO_SOFTWARE_OVERLAY, failureId,
   2758              &status))) {
   2759        FeatureState& feature =
   2760            gfxConfig::GetFeature(Feature::VIDEO_SOFTWARE_OVERLAY);
   2761        feature.DisableByDefault(FeatureStatus::BlockedNoGfxInfo,
   2762                                 "gfxInfo is broken",
   2763                                 "FEATURE_FAILURE_WR_NO_GFX_INFO"_ns);
   2764        useVideoSwOverlay = false;
   2765      } else {
   2766        if (status != nsIGfxInfo::FEATURE_STATUS_OK) {
   2767          FeatureState& feature =
   2768              gfxConfig::GetFeature(Feature::VIDEO_SOFTWARE_OVERLAY);
   2769          feature.DisableByDefault(FeatureStatus::Blocked,
   2770                                   "Blocklisted by gfxInfo", failureId);
   2771          useVideoSwOverlay = false;
   2772        }
   2773      }
   2774    }
   2775  } else if (overlaySupported) {
   2776    FeatureState& feature =
   2777        gfxConfig::GetFeature(Feature::VIDEO_SOFTWARE_OVERLAY);
   2778    feature.DisableByDefault(FeatureStatus::Blocked, "Disabled by pref",
   2779                             "FEATURE_FAILURE_DISABLED_BY_PREF"_ns);
   2780  }
   2781 
   2782  if (useVideoSwOverlay) {
   2783    FeatureState& feature =
   2784        gfxConfig::GetFeature(Feature::VIDEO_SOFTWARE_OVERLAY);
   2785    feature.EnableByDefault();
   2786    gfxVars::SetUseWebRenderDCompVideoSwOverlayWin(true);
   2787  }
   2788 
   2789  bool useHwVideoZeroCopy = false;
   2790  if (StaticPrefs::media_wmf_zero_copy_nv12_textures_AtStartup()) {
   2791    if (hasHardware) {
   2792      useHwVideoZeroCopy = true;
   2793    }
   2794 
   2795    if (useHwVideoZeroCopy &&
   2796        !StaticPrefs::
   2797            media_wmf_zero_copy_nv12_textures_force_enabled_AtStartup()) {
   2798      nsCString failureId;
   2799      int32_t status;
   2800      const nsCOMPtr<nsIGfxInfo> gfxInfo = components::GfxInfo::Service();
   2801      if (NS_FAILED(gfxInfo->GetFeatureStatus(
   2802              nsIGfxInfo::FEATURE_HW_DECODED_VIDEO_ZERO_COPY, failureId,
   2803              &status))) {
   2804        FeatureState& feature =
   2805            gfxConfig::GetFeature(Feature::HW_DECODED_VIDEO_ZERO_COPY);
   2806        feature.DisableByDefault(FeatureStatus::BlockedNoGfxInfo,
   2807                                 "gfxInfo is broken",
   2808                                 "FEATURE_FAILURE_WR_NO_GFX_INFO"_ns);
   2809        useHwVideoZeroCopy = false;
   2810      } else {
   2811        if (status != nsIGfxInfo::FEATURE_ALLOW_ALWAYS) {
   2812          FeatureState& feature =
   2813              gfxConfig::GetFeature(Feature::HW_DECODED_VIDEO_ZERO_COPY);
   2814          feature.DisableByDefault(FeatureStatus::Blocked,
   2815                                   "Blocklisted by gfxInfo", failureId);
   2816          useHwVideoZeroCopy = false;
   2817        }
   2818      }
   2819    }
   2820  }
   2821 
   2822  if (useHwVideoZeroCopy) {
   2823    FeatureState& feature =
   2824        gfxConfig::GetFeature(Feature::HW_DECODED_VIDEO_ZERO_COPY);
   2825    feature.EnableByDefault();
   2826    gfxVars::SetHwDecodedVideoZeroCopy(true);
   2827  }
   2828 
   2829  bool reuseDecoderDevice = false;
   2830  if (StaticPrefs::gfx_direct3d11_reuse_decoder_device_AtStartup()) {
   2831    reuseDecoderDevice = true;
   2832 
   2833    if (reuseDecoderDevice &&
   2834        !StaticPrefs::
   2835            gfx_direct3d11_reuse_decoder_device_force_enabled_AtStartup()) {
   2836      nsCString failureId;
   2837      int32_t status;
   2838      const nsCOMPtr<nsIGfxInfo> gfxInfo = components::GfxInfo::Service();
   2839      if (NS_FAILED(gfxInfo->GetFeatureStatus(
   2840              nsIGfxInfo::FEATURE_REUSE_DECODER_DEVICE, failureId, &status))) {
   2841        FeatureState& feature =
   2842            gfxConfig::GetFeature(Feature::REUSE_DECODER_DEVICE);
   2843        feature.DisableByDefault(FeatureStatus::BlockedNoGfxInfo,
   2844                                 "gfxInfo is broken",
   2845                                 "FEATURE_FAILURE_WR_NO_GFX_INFO"_ns);
   2846        reuseDecoderDevice = false;
   2847      } else {
   2848        if (status != nsIGfxInfo::FEATURE_STATUS_OK) {
   2849          FeatureState& feature =
   2850              gfxConfig::GetFeature(Feature::REUSE_DECODER_DEVICE);
   2851          feature.DisableByDefault(FeatureStatus::Blocked,
   2852                                   "Blocklisted by gfxInfo", failureId);
   2853          reuseDecoderDevice = false;
   2854        }
   2855      }
   2856    }
   2857  }
   2858 
   2859  if (reuseDecoderDevice) {
   2860    FeatureState& feature =
   2861        gfxConfig::GetFeature(Feature::REUSE_DECODER_DEVICE);
   2862    feature.EnableByDefault();
   2863    gfxVars::SetReuseDecoderDevice(true);
   2864  }
   2865 
   2866  if (Preferences::GetBool("gfx.webrender.flip-sequential", false)) {
   2867    if (gfxVars::UseWebRenderANGLE()) {
   2868      gfxVars::SetUseWebRenderFlipSequentialWin(true);
   2869    }
   2870  }
   2871  if (Preferences::GetBool("gfx.webrender.triple-buffering.enabled", false)) {
   2872    if (gfxVars::UseWebRenderDCompWin() ||
   2873        gfxVars::UseWebRenderFlipSequentialWin()) {
   2874      gfxVars::SetUseWebRenderTripleBufferingWin(true);
   2875    }
   2876  }
   2877 
   2878  if (StaticPrefs::
   2879          gfx_webrender_layer_compositor_use_dcomp_texture_AtStartup() &&
   2880      IsWin1122H2OrLater() && gfxVars::UseWebRenderDCompWin()) {
   2881    gfxVars::SetWebRenderLayerCompositorDCompTexture(true);
   2882  }
   2883 
   2884  if (StaticPrefs::gfx_webrender_dcomp_texture_overlay_win_AtStartup() &&
   2885      IsWin1122H2OrLater() && gfxVars::UseWebRenderDCompWin()) {
   2886    gfxVars::SetUseWebRenderDCompositionTextureOverlayWin(true);
   2887  }
   2888 #endif
   2889 
   2890  bool allowOverlayVpAutoHDR = false;
   2891  if (StaticPrefs::gfx_webrender_overlay_vp_auto_hdr_AtStartup()) {
   2892    allowOverlayVpAutoHDR = true;
   2893 
   2894    nsCString failureId;
   2895    int32_t status;
   2896    const nsCOMPtr<nsIGfxInfo> gfxInfo = components::GfxInfo::Service();
   2897    if (NS_FAILED(gfxInfo->GetFeatureStatus(
   2898            nsIGfxInfo::FEATURE_OVERLAY_VP_AUTO_HDR, failureId, &status))) {
   2899      allowOverlayVpAutoHDR = false;
   2900    } else {
   2901      if (status != nsIGfxInfo::FEATURE_STATUS_OK) {
   2902        allowOverlayVpAutoHDR = false;
   2903      }
   2904    }
   2905  }
   2906 
   2907  if (allowOverlayVpAutoHDR) {
   2908    gfxVars::SetWebRenderOverlayVpAutoHDR(true);
   2909  }
   2910 
   2911  if (StaticPrefs::gfx_webrender_overlay_hdr_AtStartup()) {
   2912    gfxVars::SetWebRenderOverlayHDR(true);
   2913  }
   2914 
   2915  bool allowOverlayVpSuperResolution = false;
   2916  if (StaticPrefs::gfx_webrender_overlay_vp_super_resolution_AtStartup()) {
   2917    allowOverlayVpSuperResolution = true;
   2918 
   2919    nsCString failureId;
   2920    int32_t status;
   2921    const nsCOMPtr<nsIGfxInfo> gfxInfo = components::GfxInfo::Service();
   2922    if (NS_FAILED(gfxInfo->GetFeatureStatus(
   2923            nsIGfxInfo::FEATURE_OVERLAY_VP_SUPER_RESOLUTION, failureId,
   2924            &status))) {
   2925      allowOverlayVpSuperResolution = false;
   2926    } else {
   2927      if (status != nsIGfxInfo::FEATURE_STATUS_OK) {
   2928        allowOverlayVpSuperResolution = false;
   2929      }
   2930    }
   2931  }
   2932 
   2933  if (allowOverlayVpSuperResolution) {
   2934    gfxVars::SetWebRenderOverlayVpSuperResolution(true);
   2935  }
   2936 
   2937  if (gfxConfig::IsEnabled(Feature::WEBRENDER_COMPOSITOR)) {
   2938    gfxVars::SetUseWebRenderCompositor(true);
   2939  }
   2940 
   2941  glean::gfx::os_compositor.Set(
   2942      gfx::gfxConfig::IsEnabled(gfx::Feature::WEBRENDER_COMPOSITOR));
   2943 
   2944  if (gfxConfig::IsEnabled(Feature::WEBRENDER_PARTIAL)) {
   2945    gfxVars::SetWebRenderMaxPartialPresentRects(
   2946        StaticPrefs::gfx_webrender_max_partial_present_rects_AtStartup());
   2947  }
   2948 
   2949  // Set features that affect WR's RendererOptions
   2950  gfxVars::SetUseGLSwizzle(
   2951      IsFeatureSupported(nsIGfxInfo::FEATURE_GL_SWIZZLE, true));
   2952  gfxVars::SetUseWebRenderScissoredCacheClears(gfx::gfxConfig::IsEnabled(
   2953      gfx::Feature::WEBRENDER_SCISSORED_CACHE_CLEARS));
   2954 
   2955  gfxVars::SetAllowGLNorm16Textures(
   2956      gfx::gfxConfig::IsEnabled(gfx::Feature::GL_NORM16_TEXTURES));
   2957 
   2958  // The RemoveShaderCacheFromDiskIfNecessary() needs to be called after
   2959  // WebRenderConfig initialization.
   2960  gfxUtils::RemoveShaderCacheFromDiskIfNecessary();
   2961 }
   2962 
   2963 void gfxPlatform::InitHardwareVideoConfig() {
   2964  if (!XRE_IsParentProcess()) {
   2965    return;
   2966  }
   2967 
   2968  // Collect the gfxVar updates into a single message.
   2969  gfxVarsCollectUpdates collect;
   2970 
   2971  FeatureState& featureDec =
   2972      gfxConfig::GetFeature(Feature::HARDWARE_VIDEO_DECODING);
   2973  featureDec.Reset();
   2974  featureDec.EnableByDefault();
   2975 
   2976  if (!StaticPrefs::media_hardware_video_decoding_enabled_AtStartup()) {
   2977    featureDec.UserDisable(
   2978        "User disabled via media.hardware-video-decoding.enabled pref",
   2979        "FEATURE_HARDWARE_VIDEO_DECODING_PREF_1_DISABLED"_ns);
   2980  }
   2981 #ifdef XP_WIN
   2982  else if (!StaticPrefs::media_wmf_dxva_d3d11_enabled()) {
   2983    featureDec.UserDisable(
   2984        "User disabled via media.wmf.dxva.d3d11.enabled pref",
   2985        "FEATURE_HARDWARE_VIDEO_DECODING_PREF_2_DISABLED"_ns);
   2986  }
   2987 #endif
   2988  else if (StaticPrefs::
   2989               media_hardware_video_decoding_force_enabled_AtStartup()) {
   2990    featureDec.UserForceEnable("Force enabled by pref");
   2991  }
   2992 
   2993  int32_t status = nsIGfxInfo::FEATURE_STATUS_UNKNOWN;
   2994  nsCOMPtr<nsIGfxInfo> gfxInfo = components::GfxInfo::Service();
   2995  nsCString failureId;
   2996  if (NS_FAILED(gfxInfo->GetFeatureStatus(
   2997          nsIGfxInfo::FEATURE_HARDWARE_VIDEO_DECODING, failureId, &status))) {
   2998    featureDec.Disable(FeatureStatus::BlockedNoGfxInfo, "gfxInfo is broken",
   2999                       "FEATURE_FAILURE_NO_GFX_INFO"_ns);
   3000  } else if (status != nsIGfxInfo::FEATURE_STATUS_OK) {
   3001    featureDec.Disable(FeatureStatus::Blocklisted, "Blocklisted by gfxInfo",
   3002                       failureId);
   3003  }
   3004 
   3005  if (status == nsIGfxInfo::FEATURE_BLOCKED_PLATFORM_TEST) {
   3006    featureDec.ForceDisable(FeatureStatus::Unavailable,
   3007                            "Force disabled by gfxInfo", failureId);
   3008  } else if (Preferences::GetBool("media.hardware-video-decoding.failed",
   3009                                  false)) {
   3010    featureDec.ForceDisable(FeatureStatus::Unavailable,
   3011                            "Force disabled by failed sanity test",
   3012                            "FEATURE_FAILURE_SANITY_TEST_FAILED"_ns);
   3013  }
   3014 
   3015  FeatureState& featureEnc =
   3016      gfxConfig::GetFeature(Feature::HARDWARE_VIDEO_ENCODING);
   3017  featureEnc.Reset();
   3018  featureEnc.EnableByDefault();
   3019 
   3020  if (!StaticPrefs::media_hardware_video_encoding_enabled_AtStartup()) {
   3021    featureDec.UserDisable(
   3022        "User disabled via media.hardware-video-encoding.enabled pref",
   3023        "FEATURE_HARDWARE_VIDEO_ENCODING_PREF_1_DISABLED"_ns);
   3024  }
   3025 #ifdef XP_WIN
   3026  else if (!StaticPrefs::media_wmf_dxva_d3d11_enabled()) {
   3027    featureDec.UserDisable(
   3028        "User disabled via media.wmf.dxva.d3d11.enabled pref",
   3029        "FEATURE_HARDWARE_VIDEO_ENCODING_PREF_2_DISABLED"_ns);
   3030  }
   3031 #endif
   3032  else if (StaticPrefs::
   3033               media_hardware_video_encoding_force_enabled_AtStartup()) {
   3034    featureEnc.UserForceEnable("Force enabled by pref");
   3035  }
   3036 
   3037  status = nsIGfxInfo::FEATURE_STATUS_UNKNOWN;
   3038  if (NS_FAILED(gfxInfo->GetFeatureStatus(
   3039          nsIGfxInfo::FEATURE_HARDWARE_VIDEO_ENCODING, failureId, &status))) {
   3040    featureEnc.Disable(FeatureStatus::BlockedNoGfxInfo, "gfxInfo is broken",
   3041                       "FEATURE_FAILURE_NO_GFX_INFO"_ns);
   3042  } else if (status != nsIGfxInfo::FEATURE_STATUS_OK) {
   3043    featureEnc.Disable(FeatureStatus::Blocklisted, "Blocklisted by gfxInfo",
   3044                       failureId);
   3045  }
   3046 
   3047  if (status == nsIGfxInfo::FEATURE_BLOCKED_PLATFORM_TEST) {
   3048    featureEnc.ForceDisable(FeatureStatus::Unavailable,
   3049                            "Force disabled by gfxInfo", failureId);
   3050  } else if (Preferences::GetBool("media.hardware-video-decoding.failed",
   3051                                  false)) {
   3052    featureEnc.ForceDisable(FeatureStatus::Unavailable,
   3053                            "Force disabled by failed sanity test",
   3054                            "FEATURE_FAILURE_SANITY_TEST_FAILED"_ns);
   3055  }
   3056 
   3057  InitPlatformHardwareVideoConfig();
   3058  InitPlatformHardwarDRMConfig();
   3059 
   3060  nsCString message;
   3061  gfxVars::SetCanUseHardwareVideoDecoding(featureDec.IsEnabled());
   3062  gfxVars::SetCanUseHardwareVideoEncoding(featureEnc.IsEnabled());
   3063 
   3064 #ifdef MOZ_WIDGET_ANDROID
   3065 #  define CODEC_HW_FEATURE_SETUP_PLATFORM(name, type, encoder)             \
   3066    feature##type##name.SetDefault(gfxAndroidPlatform::IsHwCodecSupported( \
   3067                                       media::MediaCodec::name, encoder),  \
   3068                                   FeatureStatus::Unavailable,             \
   3069                                   "Hardware codec not available");
   3070 #else
   3071 #  define CODEC_HW_FEATURE_SETUP_PLATFORM(name, type, encoder) \
   3072    feature##type##name.EnableByDefault();
   3073 #endif
   3074 
   3075 #define CODEC_HW_FEATURE_SETUP(name)                                           \
   3076  FeatureState& featureDec##name =                                             \
   3077      gfxConfig::GetFeature(Feature::name##_HW_DECODE);                        \
   3078  featureDec##name.Reset();                                                    \
   3079  if (featureDec.IsEnabled()) {                                                \
   3080    CODEC_HW_FEATURE_SETUP_PLATFORM(name, Dec, false)                          \
   3081    if (!IsGfxInfoStatusOkay(nsIGfxInfo::FEATURE_##name##_HW_DECODE, &message, \
   3082                             failureId)) {                                     \
   3083      featureDec##name.Disable(FeatureStatus::Blocklisted, message.get(),      \
   3084                               failureId);                                     \
   3085    }                                                                          \
   3086  }                                                                            \
   3087  gfxVars::SetUse##name##HwDecode(featureDec##name.IsEnabled());               \
   3088  FeatureState& featureEnc##name =                                             \
   3089      gfxConfig::GetFeature(Feature::name##_HW_ENCODE);                        \
   3090  featureEnc##name.Reset();                                                    \
   3091  if (featureEnc.IsEnabled()) {                                                \
   3092    CODEC_HW_FEATURE_SETUP_PLATFORM(name, Enc, true)                           \
   3093    if (!IsGfxInfoStatusOkay(nsIGfxInfo::FEATURE_##name##_HW_ENCODE, &message, \
   3094                             failureId)) {                                     \
   3095      featureEnc##name.Disable(FeatureStatus::Blocklisted, message.get(),      \
   3096                               failureId);                                     \
   3097    }                                                                          \
   3098  }                                                                            \
   3099  gfxVars::SetUse##name##HwEncode(featureEnc##name.IsEnabled());
   3100 
   3101  CODEC_HW_FEATURE_SETUP(AV1)
   3102  CODEC_HW_FEATURE_SETUP(VP8)
   3103  CODEC_HW_FEATURE_SETUP(VP9)
   3104 
   3105  // H264/HEVC_HW_DECODE/ENCODE are used on Linux, Android, and Windows.
   3106 #if defined(MOZ_WIDGET_GTK) || defined(MOZ_WIDGET_ANDROID) || defined(XP_WIN)
   3107  CODEC_HW_FEATURE_SETUP(H264)
   3108  CODEC_HW_FEATURE_SETUP(HEVC)
   3109 #endif
   3110 
   3111 #undef CODEC_HW_FEATURE_SETUP_PLATFORM
   3112 #undef CODEC_HW_FEATURE_SETUP
   3113 }
   3114 
   3115 void gfxPlatform::InitWebGLConfig() {
   3116  if (!XRE_IsParentProcess()) return;
   3117 
   3118  const nsCOMPtr<nsIGfxInfo> gfxInfo = components::GfxInfo::Service();
   3119 
   3120  const auto IsFeatureOk = [&](const int32_t feature) {
   3121    nsCString discardFailureId;
   3122    int32_t status;
   3123    MOZ_RELEASE_ASSERT(NS_SUCCEEDED(
   3124        gfxInfo->GetFeatureStatus(feature, discardFailureId, &status)));
   3125    return (status == nsIGfxInfo::FEATURE_STATUS_OK);
   3126  };
   3127 
   3128  gfxVars::SetAllowWebgl2(IsFeatureOk(nsIGfxInfo::FEATURE_WEBGL2));
   3129  gfxVars::SetWebglAllowWindowsNativeGl(
   3130      IsFeatureOk(nsIGfxInfo::FEATURE_WEBGL_OPENGL));
   3131  gfxVars::SetAllowWebglAccelAngle(
   3132      IsFeatureOk(nsIGfxInfo::FEATURE_WEBGL_ANGLE));
   3133  gfxVars::SetWebglUseHardware(
   3134      IsFeatureOk(nsIGfxInfo::FEATURE_WEBGL_USE_HARDWARE));
   3135 
   3136  if (kIsMacOS) {
   3137    // Avoid crash for Intel HD Graphics 3000 on OSX. (Bug 1413269)
   3138    nsString vendorID, deviceID;
   3139    gfxInfo->GetAdapterVendorID(vendorID);
   3140    gfxInfo->GetAdapterDeviceID(deviceID);
   3141    if (vendorID.EqualsLiteral("0x8086") &&
   3142        (deviceID.EqualsLiteral("0x0116") ||
   3143         deviceID.EqualsLiteral("0x0126"))) {
   3144      gfxVars::SetWebglAllowCoreProfile(false);
   3145    }
   3146  }
   3147 
   3148  bool allowWebGLOop =
   3149      IsFeatureOk(nsIGfxInfo::FEATURE_ALLOW_WEBGL_OUT_OF_PROCESS);
   3150  if (!kIsAndroid) {
   3151    gfxVars::SetAllowWebglOop(allowWebGLOop);
   3152  } else {
   3153    // On android, enable out-of-process WebGL only when GPU process exists.
   3154    gfxVars::SetAllowWebglOop(allowWebGLOop &&
   3155                              gfxConfig::IsEnabled(Feature::GPU_PROCESS));
   3156    // Enable gl::SharedSurface of AndroidHardwareBuffer when out-of-process
   3157    // WebGL is enabled.
   3158 #ifdef MOZ_WIDGET_ANDROID
   3159    if (gfxVars::AllowWebglOop() &&
   3160        StaticPrefs::webgl_out_of_process_enable_ahardwarebuffer_AtStartup()) {
   3161      gfxVars::SetUseAHardwareBufferSharedSurfaceWebglOop(true);
   3162    }
   3163 #endif
   3164  }
   3165 
   3166  bool threadsafeGL = IsFeatureOk(nsIGfxInfo::FEATURE_THREADSAFE_GL);
   3167  threadsafeGL |= StaticPrefs::webgl_threadsafe_gl_force_enabled_AtStartup();
   3168  threadsafeGL &= !StaticPrefs::webgl_threadsafe_gl_force_disabled_AtStartup();
   3169  gfxVars::SetSupportsThreadsafeGL(threadsafeGL);
   3170 
   3171  FeatureState& feature =
   3172      gfxConfig::GetFeature(Feature::CANVAS_RENDERER_THREAD);
   3173  if (!threadsafeGL) {
   3174    feature.DisableByDefault(FeatureStatus::Blocked, "Thread unsafe GL",
   3175                             "FEATURE_FAILURE_THREAD_UNSAFE_GL"_ns);
   3176  } else if (!StaticPrefs::webgl_use_canvas_render_thread_AtStartup()) {
   3177    feature.DisableByDefault(FeatureStatus::Blocked, "Disabled by pref",
   3178                             "FEATURE_FAILURE_DISABLED_BY_PREF"_ns);
   3179  } else {
   3180    feature.EnableByDefault();
   3181  }
   3182  gfxVars::SetUseCanvasRenderThread(feature.IsEnabled());
   3183 
   3184  bool webglOopAsyncPresentForceSync =
   3185      (threadsafeGL && !gfxVars::UseCanvasRenderThread()) ||
   3186      StaticPrefs::webgl_out_of_process_async_present_force_sync();
   3187  gfxVars::SetWebglOopAsyncPresentForceSync(webglOopAsyncPresentForceSync);
   3188 
   3189  if (kIsAndroid) {
   3190    // Don't enable robust buffer access on Adreno 620 and 630 devices.
   3191    // It causes the linking of some shaders to fail. See bug 1485441 and
   3192    // bug 1810693.
   3193    nsAutoString renderer;
   3194    gfxInfo->GetAdapterDeviceID(renderer);
   3195    if ((renderer.Find(u"Adreno (TM) 620") != -1) ||
   3196        (renderer.Find(u"Adreno (TM) 630") != -1)) {
   3197      gfxVars::SetAllowEglRbab(false);
   3198    }
   3199  }
   3200 
   3201 #ifdef MOZ_WIDGET_GTK
   3202  if (kIsLinux) {
   3203    FeatureState& feature =
   3204        gfxConfig::GetFeature(Feature::DMABUF_SURFACE_EXPORT);
   3205    feature.EnableByDefault();
   3206    nsCString discardFailureId;
   3207    int32_t status;
   3208    if (NS_FAILED(
   3209            gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DMABUF_SURFACE_EXPORT,
   3210                                      discardFailureId, &status)) ||
   3211        status != nsIGfxInfo::FEATURE_STATUS_OK) {
   3212 #  ifdef NIGHTLY_BUILD
   3213      if (StaticPrefs::widget_dmabuf_export_force_enabled_AtStartup()) {
   3214        feature.UserForceEnable("Force-enabled by pref");
   3215      } else
   3216 #  endif
   3217      {
   3218        feature.Disable(FeatureStatus::Blocked, "Blocklisted by gfxInfo",
   3219                        discardFailureId);
   3220      }
   3221    }
   3222    gfxVars::SetUseDMABufSurfaceExport(feature.IsEnabled());
   3223  }
   3224 
   3225  if (kIsLinux) {
   3226    FeatureState& feature = gfxConfig::GetFeature(Feature::DMABUF_WEBGL);
   3227    feature.EnableByDefault();
   3228    if (!StaticPrefs::widget_dmabuf_webgl_enabled_AtStartup()) {
   3229      feature.UserDisable("Disabled by pref",
   3230                          "FEATURE_FAILURE_DISABLED_BY_PREF"_ns);
   3231    }
   3232    nsCString discardFailureId;
   3233    int32_t status;
   3234    if (NS_FAILED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DMABUF_WEBGL,
   3235                                            discardFailureId, &status)) ||
   3236        status != nsIGfxInfo::FEATURE_STATUS_OK) {
   3237      feature.Disable(FeatureStatus::Blocked, "Blocklisted by gfxInfo",
   3238                      discardFailureId);
   3239    }
   3240    gfxVars::SetUseDMABufWebGL(feature.IsEnabled());
   3241  }
   3242 #endif
   3243 }
   3244 
   3245 void gfxPlatform::InitWebGPUConfig() {
   3246  if (!XRE_IsParentProcess()) {
   3247    return;
   3248  }
   3249 
   3250  FeatureState& featureWebGPU = gfxConfig::GetFeature(Feature::WEBGPU);
   3251  featureWebGPU.EnableByDefault();
   3252 
   3253  if (!gfxConfig::IsEnabled(Feature::GPU_PROCESS) &&
   3254      !StaticPrefs::dom_webgpu_allow_in_parent_AtStartup()) {
   3255    featureWebGPU.Disable(FeatureStatus::UnavailableNoGpuProcess,
   3256                          "Disabled without GPU process",
   3257                          "FEATURE_WEBGPU_NO_GPU_PROCESS"_ns);
   3258  }
   3259 
   3260  nsCString message;
   3261  nsCString failureId;
   3262  if (!IsGfxInfoStatusOkay(nsIGfxInfo::FEATURE_WEBGPU, &message, failureId)) {
   3263    if (StaticPrefs::gfx_webgpu_ignore_blocklist_AtStartup()) {
   3264      featureWebGPU.UserForceEnable(
   3265          "Ignoring blocklist entry because gfx.webgpu.ignore-blocklist is "
   3266          "true.");
   3267    }
   3268    featureWebGPU.Disable(FeatureStatus::Blocklisted, message.get(), failureId);
   3269  }
   3270 
   3271  gfxVars::SetAllowWebGPU(featureWebGPU.IsEnabled());
   3272 
   3273  if (StaticPrefs::dom_webgpu_allow_present_without_readback()
   3274 #if XP_WIN
   3275      && IsWin10CreatorsUpdateOrLater()
   3276 #endif
   3277  ) {
   3278    gfxVars::SetAllowWebGPUPresentWithoutReadback(true);
   3279  }
   3280 
   3281  FeatureState& featureExternalTexture =
   3282      gfxConfig::GetFeature(Feature::WEBGPU_EXTERNAL_TEXTURE);
   3283  featureExternalTexture.SetDefaultFromPref(
   3284      StaticPrefs::GetPrefName_dom_webgpu_external_texture_enabled(), true,
   3285      StaticPrefs::GetPrefDefault_dom_webgpu_external_texture_enabled());
   3286  if (!IsGfxInfoStatusOkay(nsIGfxInfo::FEATURE_WEBGPU_EXTERNAL_TEXTURE,
   3287                           &message, failureId)) {
   3288    featureExternalTexture.Disable(FeatureStatus::Blocklisted, message.get(),
   3289                                   failureId);
   3290  }
   3291 #if !defined(XP_WIN) && !defined(XP_MACOSX)
   3292  featureExternalTexture.ForceDisable(
   3293      FeatureStatus::Blocked,
   3294      "WebGPU external textures are not supported on this Operating System",
   3295      "WEBGPU_EXTERNAL_TEXTURE_UNSUPPORTED_OS"_ns);
   3296 #endif
   3297  gfxVars::SetAllowWebGPUExternalTexture(featureExternalTexture.IsEnabled());
   3298 }
   3299 
   3300 #ifdef XP_WIN
   3301 static void WindowOcclusionPrefChangeCallback(const char* aPref, void*) {
   3302  const char* env = PR_GetEnv("MOZ_WINDOW_OCCLUSION");
   3303  if (env) {
   3304    // env has a higher priority than pref.
   3305    return;
   3306  }
   3307 
   3308  FeatureState& feature = gfxConfig::GetFeature(Feature::WINDOW_OCCLUSION);
   3309  bool enabled =
   3310      StaticPrefs::widget_windows_window_occlusion_tracking_enabled();
   3311 
   3312  printf_stderr("Dynamically enable window occlusion %d\n", enabled);
   3313 
   3314  // Update feature before calling WinUtils::EnableWindowOcclusion()
   3315  if (enabled) {
   3316    feature.UserEnable("User enabled by pref");
   3317  } else {
   3318    feature.UserDisable("User disabled via pref",
   3319                        "FEATURE_FAILURE_PREF_DISABLED"_ns);
   3320  }
   3321  widget::WinUtils::EnableWindowOcclusion(enabled);
   3322 }
   3323 #endif
   3324 
   3325 void gfxPlatform::InitWindowOcclusionConfig() {
   3326  if (!XRE_IsParentProcess()) {
   3327    return;
   3328  }
   3329 #ifdef XP_WIN
   3330  FeatureState& feature = gfxConfig::GetFeature(Feature::WINDOW_OCCLUSION);
   3331  feature.SetDefaultFromPref(
   3332      StaticPrefs::
   3333          GetPrefName_widget_windows_window_occlusion_tracking_enabled(),
   3334      true,
   3335      StaticPrefs::
   3336          GetPrefDefault_widget_windows_window_occlusion_tracking_enabled());
   3337 
   3338  const char* env = PR_GetEnv("MOZ_WINDOW_OCCLUSION");
   3339  if (env) {
   3340    if (*env == '1') {
   3341      feature.UserForceEnable("Force enabled by envvar");
   3342    } else {
   3343      feature.UserDisable("Force disabled by envvar",
   3344                          "FEATURE_FAILURE_OCCL_ENV"_ns);
   3345    }
   3346  }
   3347 
   3348  Preferences::RegisterCallback(
   3349      WindowOcclusionPrefChangeCallback,
   3350      nsDependentCString(
   3351          StaticPrefs::
   3352              GetPrefName_widget_windows_window_occlusion_tracking_enabled()));
   3353 #endif
   3354 }
   3355 
   3356 static void BackdropFilterPrefChangeCallback(const char*, void*) {
   3357  FeatureState& feature = gfxConfig::GetFeature(Feature::BACKDROP_FILTER);
   3358 
   3359  // We need to reset because the user status needs to be set before the
   3360  // environment status, but the environment status comes from the blocklist,
   3361  // and the user status can be updated after the fact.
   3362  feature.Reset();
   3363  feature.EnableByDefault();
   3364 
   3365  if (StaticPrefs::layout_css_backdrop_filter_force_enabled()) {
   3366    feature.UserForceEnable("Force enabled by pref");
   3367  }
   3368 
   3369  nsCString message;
   3370  nsCString failureId;
   3371  if (!gfxPlatform::IsGfxInfoStatusOkay(nsIGfxInfo::FEATURE_BACKDROP_FILTER,
   3372                                        &message, failureId)) {
   3373    feature.Disable(FeatureStatus::Blocklisted, message.get(), failureId);
   3374  }
   3375 
   3376  // This may still be gated by the layout.css.backdrop-filter.enabled pref but
   3377  // the test infrastructure is very sensitive to how changes to that pref
   3378  // propagate, so we don't include them in the gfxVars/gfxFeature.
   3379  gfxVars::SetAllowBackdropFilter(feature.IsEnabled());
   3380 }
   3381 
   3382 void gfxPlatform::InitBackdropFilterConfig() {
   3383  // This would ideally be in the nsCSSProps code
   3384  // but nsCSSProps is initialized before gfxPlatform
   3385  // so it has to be done here.
   3386  gfxVars::AddReceiver(&nsCSSProps::GfxVarReceiver());
   3387 
   3388  if (!XRE_IsParentProcess()) {
   3389    // gfxVars doesn't notify receivers when initialized on content processes
   3390    // we need to explicitly recompute backdrop-filter's enabled state here.
   3391    nsCSSProps::RecomputeEnabledState(
   3392        StaticPrefs::GetPrefName_layout_css_backdrop_filter_enabled());
   3393    return;
   3394  }
   3395 
   3396  BackdropFilterPrefChangeCallback(nullptr, nullptr);
   3397 
   3398  Preferences::RegisterCallback(
   3399      BackdropFilterPrefChangeCallback,
   3400      nsDependentCString(
   3401          StaticPrefs::GetPrefName_layout_css_backdrop_filter_force_enabled()));
   3402 }
   3403 
   3404 static void AcceleratedCanvas2DPrefChangeCallback(const char*, void*) {
   3405  FeatureState& feature = gfxConfig::GetFeature(Feature::ACCELERATED_CANVAS2D);
   3406 
   3407  // Reset to track toggling prefs and ensure force-enable does not happen
   3408  // after blocklist.
   3409  feature.Reset();
   3410 
   3411  // gfx.canvas.accelerated pref controls whether platform enables the feature,
   3412  // but it still allows blocklisting to override it later.
   3413  feature.SetDefaultFromPref(
   3414      StaticPrefs::GetPrefName_gfx_canvas_accelerated(), true,
   3415      StaticPrefs::GetPrefDefault_gfx_canvas_accelerated());
   3416 
   3417  // gfx.canvas.accelerated.force-enabled overrides the blocklist.
   3418  if (StaticPrefs::gfx_canvas_accelerated_force_enabled()) {
   3419    feature.UserForceEnable("Force-enabled by pref");
   3420  }
   3421 
   3422  if (!StaticPrefs::gfx_canvas_accelerated_allow_in_parent_AtStartup() &&
   3423      !gfxConfig::IsEnabled(Feature::GPU_PROCESS)) {
   3424    feature.Disable(FeatureStatus::Blocked, "Disabled by GPU Process disabled",
   3425                    "FEATURE_FAILURE_DISABLED_BY_GPU_PROCESS_DISABLED"_ns);
   3426  } else if (!gfxConfig::IsEnabled(Feature::WEBRENDER)) {
   3427    // There isn't much benefit to accelerating Canvas2D if we can't accelerate
   3428    // WebRender itself.
   3429    feature.Disable(FeatureStatus::Blocked, "Disabled by Software WebRender",
   3430                    "FEATURE_FAILURE_DISABLED_BY_SOFTWARE_WEBRENDER"_ns);
   3431  }
   3432 
   3433  // Check if blocklisted despite the default pref.
   3434  nsCString message;
   3435  nsCString failureId;
   3436  if (!gfxPlatform::IsGfxInfoStatusOkay(
   3437          nsIGfxInfo::FEATURE_ACCELERATED_CANVAS2D, &message, failureId)) {
   3438    feature.Disable(FeatureStatus::Blocklisted, message.get(), failureId);
   3439  }
   3440 
   3441  gfxVars::SetUseAcceleratedCanvas2D(feature.IsEnabled());
   3442 }
   3443 
   3444 void gfxPlatform::InitAcceleratedCanvas2DConfig() {
   3445  if (!XRE_IsParentProcess()) {
   3446    return;
   3447  }
   3448 
   3449  // Decide during pref changes whether or not to enable acceleration. This
   3450  // allows easily toggling acceleration on and off to test performance.
   3451  AcceleratedCanvas2DPrefChangeCallback(nullptr, nullptr);
   3452 
   3453  Preferences::RegisterCallback(
   3454      AcceleratedCanvas2DPrefChangeCallback,
   3455      nsDependentCString(StaticPrefs::GetPrefName_gfx_canvas_accelerated()));
   3456  Preferences::RegisterCallback(
   3457      AcceleratedCanvas2DPrefChangeCallback,
   3458      nsDependentCString(
   3459          StaticPrefs::GetPrefName_gfx_canvas_accelerated_force_enabled()));
   3460 }
   3461 
   3462 bool gfxPlatform::AccelerateLayersByDefault() {
   3463 #if defined(MOZ_GL_PROVIDER) || defined(MOZ_WIDGET_UIKIT)
   3464  return true;
   3465 #else
   3466  return false;
   3467 #endif
   3468 }
   3469 
   3470 /* static */
   3471 bool gfxPlatform::UsesOffMainThreadCompositing() {
   3472  if (XRE_GetProcessType() == GeckoProcessType_GPU) {
   3473    return true;
   3474  }
   3475 
   3476  static bool firstTime = true;
   3477  static bool result = false;
   3478 
   3479  if (firstTime) {
   3480    MOZ_ASSERT(sLayersAccelerationPrefsInitialized);
   3481    result = gfxVars::BrowserTabsRemoteAutostart() ||
   3482             !StaticPrefs::
   3483                 layers_offmainthreadcomposition_force_disabled_AtStartup();
   3484 #if defined(MOZ_WIDGET_GTK)
   3485    // Linux users who chose OpenGL are being included in OMTC
   3486    result |= StaticPrefs::
   3487        layers_acceleration_force_enabled_AtStartup_DoNotUseDirectly();
   3488 
   3489 #endif
   3490    firstTime = false;
   3491  }
   3492 
   3493  return result;
   3494 }
   3495 
   3496 RefPtr<mozilla::VsyncDispatcher> gfxPlatform::GetGlobalVsyncDispatcher() {
   3497  MOZ_ASSERT(mVsyncDispatcher,
   3498             "mVsyncDispatcher should have been initialized by ReInitFrameRate "
   3499             "during gfxPlatform init");
   3500  MOZ_ASSERT(XRE_IsParentProcess());
   3501  return mVsyncDispatcher;
   3502 }
   3503 
   3504 already_AddRefed<mozilla::gfx::VsyncSource>
   3505 gfxPlatform::GetGlobalHardwareVsyncSource() {
   3506  if (!mGlobalHardwareVsyncSource) {
   3507    mGlobalHardwareVsyncSource = CreateGlobalHardwareVsyncSource();
   3508  }
   3509  return do_AddRef(mGlobalHardwareVsyncSource);
   3510 }
   3511 
   3512 /***
   3513 * The preference "layout.frame_rate" has 3 meanings depending on the value:
   3514 *
   3515 * -1 = Auto (default), use hardware vsync or software vsync @ 60 hz if hw
   3516 *      vsync fails.
   3517 *  0 = ASAP mode - used during talos testing.
   3518 *  X = Software vsync at a rate of X times per second.
   3519 */
   3520 already_AddRefed<mozilla::gfx::VsyncSource>
   3521 gfxPlatform::GetSoftwareVsyncSource() {
   3522  if (!mSoftwareVsyncSource) {
   3523    double rateInMS = 1000.0 / (double)gfxPlatform::GetSoftwareVsyncRate();
   3524    mSoftwareVsyncSource = new mozilla::gfx::SoftwareVsyncSource(
   3525        TimeDuration::FromMilliseconds(rateInMS));
   3526  }
   3527  return do_AddRef(mSoftwareVsyncSource);
   3528 }
   3529 
   3530 /* static */
   3531 bool gfxPlatform::IsInLayoutAsapMode() {
   3532  // There are 2 modes of ASAP mode.
   3533  // 1 is that the refresh driver and compositor are in lock step
   3534  // the second is that the compositor goes ASAP and the refresh driver
   3535  // goes at whatever the configurated rate is. This only checks the version
   3536  // talos uses, which is the refresh driver and compositor are in lockstep.
   3537  // Ignore privacy_resistFingerprinting to preserve ASAP mode there.
   3538  return StaticPrefs::layout_frame_rate() == 0;
   3539 }
   3540 
   3541 static int LayoutFrameRateFromPrefs() {
   3542  auto val = StaticPrefs::layout_frame_rate();
   3543  if (nsContentUtils::ShouldResistFingerprinting(
   3544          "The frame rate is a global property.", RFPTarget::FrameRate)) {
   3545    val = 60;
   3546  }
   3547  return val;
   3548 }
   3549 
   3550 /* static */
   3551 bool gfxPlatform::ForceSoftwareVsync() {
   3552  return LayoutFrameRateFromPrefs() > 0;
   3553 }
   3554 
   3555 /* static */
   3556 int gfxPlatform::GetSoftwareVsyncRate() {
   3557  int preferenceRate = LayoutFrameRateFromPrefs();
   3558  if (preferenceRate <= 0) {
   3559    return gfxPlatform::GetDefaultFrameRate();
   3560  }
   3561  return preferenceRate;
   3562 }
   3563 
   3564 /* static */
   3565 int gfxPlatform::GetDefaultFrameRate() { return 60; }
   3566 
   3567 /* static */
   3568 void gfxPlatform::ReInitFrameRate(const char* aPrefIgnored,
   3569                                  void* aDataIgnored) {
   3570  MOZ_RELEASE_ASSERT(XRE_IsParentProcess());
   3571 
   3572  if (gPlatform->mSoftwareVsyncSource) {
   3573    // Update the rate of the existing software vsync source.
   3574    double rateInMS = 1000.0 / (double)gfxPlatform::GetSoftwareVsyncRate();
   3575    gPlatform->mSoftwareVsyncSource->SetVsyncRate(
   3576        TimeDuration::FromMilliseconds(rateInMS));
   3577  }
   3578 
   3579  // Swap out the dispatcher's underlying source.
   3580  RefPtr<VsyncSource> vsyncSource =
   3581      gfxPlatform::ForceSoftwareVsync()
   3582          ? gPlatform->GetSoftwareVsyncSource()
   3583          : gPlatform->GetGlobalHardwareVsyncSource();
   3584  gPlatform->mVsyncDispatcher->SetVsyncSource(vsyncSource);
   3585 }
   3586 
   3587 /* static */
   3588 void gfxPlatform::ResetHardwareVsyncSource() {
   3589  if (gPlatform->mGlobalHardwareVsyncSource) {
   3590    gPlatform->mGlobalHardwareVsyncSource->Shutdown();
   3591    gPlatform->mGlobalHardwareVsyncSource = nullptr;
   3592  }
   3593 }
   3594 
   3595 const char* gfxPlatform::GetAzureCanvasBackend() const {
   3596  BackendType backend{};
   3597 
   3598  if (gfxConfig::IsEnabled(Feature::GPU_PROCESS)) {
   3599    // Assume content process' backend prefs.
   3600    BackendPrefsData data = GetBackendPrefs();
   3601    backend = GetCanvasBackendPref(data.mCanvasBitmask);
   3602    if (backend == BackendType::NONE) {
   3603      backend = data.mCanvasDefault;
   3604    }
   3605  } else {
   3606    backend = mPreferredCanvasBackend;
   3607  }
   3608 
   3609  return GetBackendName(backend);
   3610 }
   3611 
   3612 const char* gfxPlatform::GetAzureContentBackend() const {
   3613  BackendType backend{};
   3614 
   3615  if (gfxConfig::IsEnabled(Feature::GPU_PROCESS)) {
   3616    // Assume content process' backend prefs.
   3617    BackendPrefsData data = GetBackendPrefs();
   3618    backend = GetContentBackendPref(data.mContentBitmask);
   3619    if (backend == BackendType::NONE) {
   3620      backend = data.mContentDefault;
   3621    }
   3622  } else {
   3623    backend = mContentBackend;
   3624  }
   3625 
   3626  return GetBackendName(backend);
   3627 }
   3628 
   3629 void gfxPlatform::GetAzureBackendInfo(mozilla::widget::InfoObject& aObj) {
   3630  if (gfxConfig::IsEnabled(Feature::GPU_PROCESS)) {
   3631    aObj.DefineProperty("AzureCanvasBackend (UI Process)",
   3632                        GetBackendName(mPreferredCanvasBackend));
   3633    aObj.DefineProperty("AzureFallbackCanvasBackend (UI Process)",
   3634                        GetBackendName(mFallbackCanvasBackend));
   3635    aObj.DefineProperty("AzureContentBackend (UI Process)",
   3636                        GetBackendName(mContentBackend));
   3637  } else {
   3638    aObj.DefineProperty("AzureFallbackCanvasBackend",
   3639                        GetBackendName(mFallbackCanvasBackend));
   3640  }
   3641 
   3642  aObj.DefineProperty("AzureCanvasBackend", GetAzureCanvasBackend());
   3643  aObj.DefineProperty("AzureContentBackend", GetAzureContentBackend());
   3644 }
   3645 
   3646 void gfxPlatform::GetApzSupportInfo(mozilla::widget::InfoObject& aObj) {
   3647  if (!gfxPlatform::AsyncPanZoomEnabled()) {
   3648    return;
   3649  }
   3650 
   3651  if (SupportsApzWheelInput()) {
   3652    aObj.DefineProperty("ApzWheelInput", 1);
   3653  }
   3654 
   3655  if (SupportsApzTouchInput()) {
   3656    aObj.DefineProperty("ApzTouchInput", 1);
   3657  }
   3658 
   3659  if (SupportsApzDragInput()) {
   3660    aObj.DefineProperty("ApzDragInput", 1);
   3661  }
   3662 
   3663  if (SupportsApzKeyboardInput() &&
   3664      !StaticPrefs::accessibility_browsewithcaret()) {
   3665    aObj.DefineProperty("ApzKeyboardInput", 1);
   3666  }
   3667 
   3668  if (SupportsApzAutoscrolling()) {
   3669    aObj.DefineProperty("ApzAutoscrollInput", 1);
   3670  }
   3671 
   3672  if (SupportsApzZooming()) {
   3673    aObj.DefineProperty("ApzZoomingInput", 1);
   3674  }
   3675 }
   3676 
   3677 void gfxPlatform::GetFrameStats(mozilla::widget::InfoObject& aObj) {
   3678  uint32_t i = 0;
   3679  for (FrameStats& f : mFrameStats) {
   3680    nsPrintfCString name("Slow Frame #%02u", ++i);
   3681 
   3682    nsPrintfCString value(
   3683        "Frame %" PRIu64
   3684        "(%s) CONTENT_FRAME_TIME %d - Transaction start %f, main-thread time "
   3685        "%f, full paint time %f, Skipped composites %u, Composite start %f, "
   3686        "Resource upload time %f, Render time %f, Composite time %f",
   3687        f.id().mId, f.url().get(), f.contentFrameTime(),
   3688        (f.transactionStart() - f.refreshStart()).ToMilliseconds(),
   3689        (f.fwdTime() - f.transactionStart()).ToMilliseconds(),
   3690        f.sceneBuiltTime()
   3691            ? (f.sceneBuiltTime() - f.transactionStart()).ToMilliseconds()
   3692            : 0.0,
   3693        f.skippedComposites(),
   3694        (f.compositeStart() - f.refreshStart()).ToMilliseconds(),
   3695        f.resourceUploadTime(),
   3696        (f.compositeEnd() - f.renderStart()).ToMilliseconds(),
   3697        (f.compositeEnd() - f.compositeStart()).ToMilliseconds());
   3698    aObj.DefineProperty(name.get(), value.get());
   3699  }
   3700 }
   3701 
   3702 void gfxPlatform::GetCMSSupportInfo(mozilla::widget::InfoObject& aObj) {
   3703  nsTArray<uint8_t> outputProfileData =
   3704      gfxPlatform::GetPlatform()->GetPlatformCMSOutputProfileData();
   3705  if (outputProfileData.IsEmpty()) {
   3706    nsPrintfCString msg("Empty profile data");
   3707    aObj.DefineProperty("CMSOutputProfile", msg.get());
   3708    return;
   3709  }
   3710 
   3711  // Some profiles can be quite large. We don't want to include giant profiles
   3712  // by default in about:support. For now, we only accept less than 8kiB.
   3713  const size_t kMaxProfileSize = 8192;
   3714  if (outputProfileData.Length() >= kMaxProfileSize) {
   3715    nsPrintfCString msg("%zu bytes, too large", outputProfileData.Length());
   3716    aObj.DefineProperty("CMSOutputProfile", msg.get());
   3717    return;
   3718  }
   3719 
   3720  nsString encodedProfile;
   3721  nsresult rv =
   3722      Base64Encode(reinterpret_cast<const char*>(outputProfileData.Elements()),
   3723                   outputProfileData.Length(), encodedProfile);
   3724  if (!NS_SUCCEEDED(rv)) {
   3725    nsPrintfCString msg("base64 encode failed 0x%08x",
   3726                        static_cast<uint32_t>(rv));
   3727    aObj.DefineProperty("CMSOutputProfile", msg.get());
   3728    return;
   3729  }
   3730 
   3731  aObj.DefineProperty("CMSOutputProfile", encodedProfile);
   3732 }
   3733 
   3734 void gfxPlatform::GetDisplayInfo(mozilla::widget::InfoObject& aObj) {
   3735  auto& screens = widget::ScreenManager::GetSingleton().CurrentScreenList();
   3736  aObj.DefineProperty("DisplayCount", screens.Length());
   3737 
   3738  size_t i = 0;
   3739  for (auto& screen : screens) {
   3740    const LayoutDeviceIntRect rect = screen->GetRect();
   3741    nsPrintfCString value("%dx%d@%dHz scales:%f|%f", rect.width, rect.height,
   3742                          screen->GetRefreshRate(),
   3743                          screen->GetContentsScaleFactor(),
   3744                          screen->GetDefaultCSSScaleFactor());
   3745 
   3746    aObj.DefineProperty(nsPrintfCString("Display%zu", i++).get(),
   3747                        NS_ConvertUTF8toUTF16(value));
   3748  }
   3749 
   3750  // Platform display info is only currently used for about:support and getting
   3751  // it might fail in a child process anyway.
   3752  if (XRE_IsParentProcess()) {
   3753    GetPlatformDisplayInfo(aObj);
   3754  }
   3755 }
   3756 
   3757 void gfxPlatform::GetOverlayInfo(mozilla::widget::InfoObject& aObj) {
   3758  if (mOverlayInfo.isNothing()) {
   3759    return;
   3760  }
   3761 
   3762  auto toString = [](mozilla::layers::OverlaySupportType aType) -> const char* {
   3763    switch (aType) {
   3764      case mozilla::layers::OverlaySupportType::None:
   3765        return "None";
   3766      case mozilla::layers::OverlaySupportType::Software:
   3767        return "Software";
   3768      case mozilla::layers::OverlaySupportType::Direct:
   3769        return "Direct";
   3770      case mozilla::layers::OverlaySupportType::Scaling:
   3771        return "Scaling";
   3772      default:
   3773        MOZ_ASSERT_UNREACHABLE("Unexpected to be called");
   3774    }
   3775    MOZ_CRASH("Incomplete switch");
   3776  };
   3777 
   3778  auto toStringBool = [](bool aSupported) -> const char* {
   3779    if (aSupported) {
   3780      return "Supported";
   3781    }
   3782    return "Not Supported";
   3783  };
   3784 
   3785  nsPrintfCString value(
   3786      "NV12=%s YUV2=%s BGRA8=%s RGB10A2=%s RGBA16F=%s VpSR=%s VpAutoHDR=%s "
   3787      "HDR=%s",
   3788      toString(mOverlayInfo.ref().mNv12Overlay),
   3789      toString(mOverlayInfo.ref().mYuy2Overlay),
   3790      toString(mOverlayInfo.ref().mBgra8Overlay),
   3791      toString(mOverlayInfo.ref().mRgb10a2Overlay),
   3792      toString(mOverlayInfo.ref().mRgba16fOverlay),
   3793      toStringBool(mOverlayInfo.ref().mSupportsVpSuperResolution),
   3794      toStringBool(mOverlayInfo.ref().mSupportsVpAutoHDR),
   3795      toStringBool(mOverlayInfo.ref().mSupportsHDR));
   3796 
   3797  aObj.DefineProperty("OverlaySupport", NS_ConvertUTF8toUTF16(value));
   3798 }
   3799 
   3800 void gfxPlatform::GetSwapChainInfo(mozilla::widget::InfoObject& aObj) {
   3801  if (mSwapChainInfo.isNothing()) {
   3802    return;
   3803  }
   3804 
   3805  auto toString = [](bool aTearingSupported) -> const char* {
   3806    if (aTearingSupported) {
   3807      return "Supported";
   3808    }
   3809    return "Not Supported";
   3810  };
   3811 
   3812  nsPrintfCString value("%s", toString(mSwapChainInfo.ref().mTearingSupported));
   3813 
   3814  aObj.DefineProperty("SwapChainTearingSupport", NS_ConvertUTF8toUTF16(value));
   3815 }
   3816 
   3817 class FrameStatsComparator {
   3818 public:
   3819  bool Equals(const FrameStats& aA, const FrameStats& aB) const {
   3820    return aA.contentFrameTime() == aB.contentFrameTime();
   3821  }
   3822  // Reverse the condition here since we want the array sorted largest to
   3823  // smallest.
   3824  bool LessThan(const FrameStats& aA, const FrameStats& aB) const {
   3825    return aA.contentFrameTime() > aB.contentFrameTime();
   3826  }
   3827 };
   3828 
   3829 void gfxPlatform::NotifyFrameStats(nsTArray<FrameStats>&& aFrameStats) {
   3830  if (!StaticPrefs::gfx_logging_slow_frames_enabled_AtStartup()) {
   3831    return;
   3832  }
   3833 
   3834  FrameStatsComparator comp;
   3835  for (FrameStats& f : aFrameStats) {
   3836    mFrameStats.InsertElementSorted(f, comp);
   3837  }
   3838  if (mFrameStats.Length() > 10) {
   3839    mFrameStats.SetLength(10);
   3840  }
   3841 }
   3842 
   3843 /*static*/
   3844 uint32_t gfxPlatform::TargetFrameRate() {
   3845  if (gPlatform && gPlatform->mVsyncDispatcher) {
   3846    return round(1000.0 /
   3847                 gPlatform->mVsyncDispatcher->GetVsyncRate().ToMilliseconds());
   3848  }
   3849  return 0;
   3850 }
   3851 
   3852 /* static */
   3853 bool gfxPlatform::UseDesktopZoomingScrollbars() {
   3854  return StaticPrefs::apz_allow_zooming();
   3855 }
   3856 
   3857 /*static*/
   3858 bool gfxPlatform::AsyncPanZoomEnabled() {
   3859 #if !defined(MOZ_WIDGET_ANDROID) && !defined(MOZ_WIDGET_UIKIT)
   3860  // For XUL applications (everything but Firefox on Android)
   3861  // we only want to use APZ when E10S is enabled. If
   3862  // we ever get input events off the main thread we can consider relaxing
   3863  // this requirement.
   3864  if (!BrowserTabsRemoteAutostart()) {
   3865    return false;
   3866  }
   3867 #endif
   3868 #ifdef MOZ_WIDGET_ANDROID
   3869  return true;
   3870 #else
   3871  // If Fission is enabled, OOP iframes require APZ for hittest.  So, we
   3872  // need to forcibly enable APZ in that case for avoiding users confused.
   3873  if (FissionAutostart()) {
   3874    return true;
   3875  }
   3876  return StaticPrefs::
   3877      layers_async_pan_zoom_enabled_AtStartup_DoNotUseDirectly();
   3878 #endif
   3879 }
   3880 
   3881 /*static*/
   3882 bool gfxPlatform::PerfWarnings() {
   3883  return StaticPrefs::gfx_perf_warnings_enabled();
   3884 }
   3885 
   3886 void gfxPlatform::NotifyCompositorCreated(LayersBackend aBackend) {
   3887  if (mCompositorBackend == aBackend) {
   3888    return;
   3889  }
   3890 
   3891  if (mCompositorBackend != LayersBackend::LAYERS_NONE) {
   3892    gfxCriticalNote << "Compositors might be mixed (" << int(mCompositorBackend)
   3893                    << "," << int(aBackend) << ")";
   3894  }
   3895 
   3896  // Set the backend before we notify so it's available immediately.
   3897  mCompositorBackend = aBackend;
   3898 
   3899  if (XRE_IsParentProcess()) {
   3900    nsDependentCString compositor(GetLayersBackendName(mCompositorBackend));
   3901    mozilla::glean::gfx_status::compositor.Set(compositor);
   3902 
   3903    nsCString geckoVersion;
   3904    nsCOMPtr<nsIXULAppInfo> app = do_GetService("@mozilla.org/xre/app-info;1");
   3905    if (app) {
   3906      app->GetVersion(geckoVersion);
   3907    }
   3908    mozilla::glean::gfx_status::last_compositor_gecko_version.Set(geckoVersion);
   3909 
   3910    mozilla::glean::gfx_feature::webrender.Set(
   3911        gfxConfig::GetFeature(gfx::Feature::WEBRENDER)
   3912            .GetStatusAndFailureIdString());
   3913  }
   3914 
   3915  // Notify that we created a compositor, so telemetry can update.
   3916  NS_DispatchToMainThread(
   3917      NS_NewRunnableFunction("gfxPlatform::NotifyCompositorCreated", [] {
   3918        if (nsCOMPtr<nsIObserverService> obsvc =
   3919                services::GetObserverService()) {
   3920          obsvc->NotifyObservers(nullptr, "compositor:created", nullptr);
   3921        }
   3922      }));
   3923 }
   3924 
   3925 /* static */
   3926 bool gfxPlatform::FallbackFromAcceleration(FeatureStatus aStatus,
   3927                                           const char* aMessage,
   3928                                           const nsACString& aFailureId,
   3929                                           bool aCrashAfterFinalFallback) {
   3930  // We always want to ensure (Hardware) WebRender is disabled.
   3931  if (gfxConfig::IsEnabled(Feature::WEBRENDER)) {
   3932    gfxConfig::GetFeature(Feature::WEBRENDER)
   3933        .ForceDisable(aStatus, aMessage, aFailureId);
   3934  }
   3935 
   3936  // Determine whether or not we are allowed to use Software WebRender in
   3937  // fallback without the GPU process. Either the pref is false, or the feature
   3938  // is enabled and we are currently still using it.
   3939  bool swglFallbackAllowed =
   3940      !StaticPrefs::
   3941          gfx_webrender_fallback_software_requires_gpu_process_AtStartup() ||
   3942      gfxConfig::IsEnabled(Feature::GPU_PROCESS);
   3943 
   3944 #ifdef XP_WIN
   3945  // Before we disable D3D11 and HW_COMPOSITING, we should check if we can
   3946  // fallback from WebRender to Software WebRender + D3D11 compositing.
   3947  if (swglFallbackAllowed && gfxVars::AllowSoftwareWebRenderD3D11() &&
   3948      gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING) &&
   3949      !gfxVars::UseSoftwareWebRender()) {
   3950    // Fallback to Software WebRender + D3D11 compositing.
   3951    gfxCriticalNote << "Fallback WR to SW-WR + D3D11";
   3952    gfxVars::SetUseSoftwareWebRender(true);
   3953    return true;
   3954  }
   3955 
   3956  if (swglFallbackAllowed && gfxVars::AllowSoftwareWebRenderD3D11() &&
   3957      gfxVars::UseSoftwareWebRender()) {
   3958    // Fallback from Software WebRender + D3D11 to Software WebRender.
   3959    gfxCriticalNote << "Fallback SW-WR + D3D11 to SW-WR";
   3960    gfxVars::SetAllowSoftwareWebRenderD3D11(false);
   3961    return true;
   3962  }
   3963 
   3964  // We aren't using Software WebRender + D3D11 compositing, so turn off D3D11.
   3965  if (gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)) {
   3966    gfxConfig::GetFeature(Feature::D3D11_COMPOSITING)
   3967        .ForceDisable(aStatus, aMessage, aFailureId);
   3968  }
   3969 #endif
   3970 
   3971 #if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GTK)
   3972  // Before we disable OpenGL and HW_COMPOSITING, we should check if we can
   3973  // fallback from WebRender to Software WebRender + OpenGL compositing.
   3974  if (swglFallbackAllowed && gfxVars::AllowSoftwareWebRenderOGL() &&
   3975      gfxConfig::IsEnabled(Feature::OPENGL_COMPOSITING) &&
   3976      !gfxVars::UseSoftwareWebRender()) {
   3977    // Fallback to Software WebRender + OpenGL compositing.
   3978    gfxCriticalNote << "Fallback WR to SW-WR + OpenGL";
   3979    gfxVars::SetUseSoftwareWebRender(true);
   3980    return true;
   3981  }
   3982 #endif
   3983  // Android does not want to fallback to SW-WR.
   3984 #ifdef MOZ_WIDGET_GTK
   3985  if (swglFallbackAllowed && gfxVars::AllowSoftwareWebRenderOGL() &&
   3986      gfxVars::UseSoftwareWebRender()) {
   3987    // Fallback from Software WebRender + OpenGL to Software WebRender.
   3988    gfxCriticalNote << "Fallback SW-WR + OpenGL to SW-WR";
   3989    gfxVars::SetAllowSoftwareWebRenderOGL(false);
   3990    return true;
   3991  }
   3992 #endif
   3993 
   3994 #ifndef MOZ_WIDGET_ANDROID
   3995  // Non-Android wants to fallback to Software WebRender or Basic. Android wants
   3996  // to fallback to OpenGL.
   3997  if (gfxConfig::IsEnabled(Feature::HW_COMPOSITING)) {
   3998    gfxConfig::GetFeature(Feature::HW_COMPOSITING)
   3999        .ForceDisable(aStatus, aMessage, aFailureId);
   4000  }
   4001 #endif
   4002 
   4003  if (StaticPrefs::gfx_webrender_fallback_software_AtStartup() &&
   4004      swglFallbackAllowed && !gfxVars::UseSoftwareWebRender()) {
   4005    // Fallback from WebRender to Software WebRender.
   4006    gfxCriticalNote << "Fallback WR to SW-WR";
   4007    DisableAcceleratedCanvasForFallback(
   4008        FeatureStatus::UnavailableNoHwCompositing,
   4009        "Disabled by fallback to Software WebRender",
   4010        "FEATURE_FAILURE_DISABLED_BY_FALLBACK_SOFTWARE_WEBRENDER"_ns);
   4011    gfxVars::SetUseSoftwareWebRender(true);
   4012    return true;
   4013  }
   4014 
   4015  if (!gfxVars::UseSoftwareWebRender()) {
   4016    // Software WebRender may be disabled due to a startup issue with the
   4017    // blocklist, despite it being our only fallback option based on the prefs.
   4018    // If WebRender is unable to be initialized, this means that user would
   4019    // otherwise get stuck with WebRender. As such, force a switch to Software
   4020    // WebRender in this case.
   4021    gfxCriticalNoteOnce << "Fallback WR to SW-WR, forced";
   4022    DisableAcceleratedCanvasForFallback(
   4023        FeatureStatus::UnavailableNoHwCompositing,
   4024        "Disabled by fallback to Software WebRender",
   4025        "FEATURE_FAILURE_DISABLED_BY_FALLBACK_SOFTWARE_WEBRENDER"_ns);
   4026    gfxVars::SetUseSoftwareWebRender(true);
   4027    return true;
   4028  }
   4029 
   4030  if ((gfxVars::UseAcceleratedCanvas2D() &&
   4031       !StaticPrefs::gfx_canvas_accelerated_allow_in_parent_AtStartup()) ||
   4032      (gfxVars::AllowWebGPU() &&
   4033       !StaticPrefs::dom_webgpu_allow_in_parent_AtStartup()) ||
   4034      (kIsAndroid && gfxVars::AllowWebglOop())) {
   4035    // Because content has a lot of control over inputs to remote canvas, we
   4036    // try to disable it as part of our final fallback step before disabling
   4037    // the GPU process. We don't actually support remote canvas in the parent
   4038    // process anyways, so this is not meaningfully worse from just
   4039    // switching directly to the parent process.
   4040    gfxCriticalNoteOnce << "Fallback SW-WR, disable remote canvas";
   4041    DisableAllCanvasForFallback(
   4042        FeatureStatus::UnavailableNoGpuProcess,
   4043        "Disabled by fallback to GPU Process disabled",
   4044        "FEATURE_FAILURE_DISABLED_BY_FALLBACK_GPU_PROCESS_DISABLED"_ns);
   4045    return true;
   4046  }
   4047 
   4048  if (aCrashAfterFinalFallback) {
   4049    MOZ_CRASH("Fallback configurations exhausted");
   4050  }
   4051 
   4052  // Continue using Software WebRender (disabled fallback to Basic).
   4053  gfxCriticalNoteOnce << "Fallback remains SW-WR";
   4054  return false;
   4055 }
   4056 
   4057 /* static */
   4058 void gfxPlatform::DisableAcceleratedCanvasForFallback(
   4059    FeatureStatus aStatus, const char* aMessage, const nsACString& aFailureId) {
   4060  if (gfxVars::UseAcceleratedCanvas2D() &&
   4061      !StaticPrefs::gfx_canvas_accelerated_allow_in_parent_AtStartup()) {
   4062    gfxConfig::Disable(Feature::ACCELERATED_CANVAS2D, aStatus, aMessage,
   4063                       aFailureId);
   4064    gfxVars::SetUseAcceleratedCanvas2D(false);
   4065  }
   4066 }
   4067 
   4068 /* static */
   4069 void gfxPlatform::DisableAllCanvasForFallback(FeatureStatus aStatus,
   4070                                              const char* aMessage,
   4071                                              const nsACString& aFailureId) {
   4072  DisableAcceleratedCanvasForFallback(aStatus, aMessage, aFailureId);
   4073 
   4074  if (gfxVars::AllowWebGPU() &&
   4075      !StaticPrefs::dom_webgpu_allow_in_parent_AtStartup()) {
   4076    gfxConfig::Disable(Feature::WEBGPU, aStatus, aMessage, aFailureId);
   4077    gfxVars::SetAllowWebGPU(false);
   4078  }
   4079 
   4080  if (kIsAndroid) {
   4081    // On android, enable out-of-process WebGL only when GPU process exists.
   4082    gfxVars::SetAllowWebglOop(false);
   4083  }
   4084 }
   4085 
   4086 /* static */
   4087 void gfxPlatform::DisableGPUProcess() {
   4088  DisableAllCanvasForFallback(
   4089      FeatureStatus::UnavailableNoGpuProcess,
   4090      "Disabled by fallback to GPU Process disabled",
   4091      "FEATURE_FAILURE_DISABLED_BY_FALLBACK_GPU_PROCESS_DISABLED"_ns);
   4092 
   4093 #if defined(XP_WIN)
   4094  CompositeProcessD3D11FencesHolderMap::Init();
   4095 #endif
   4096  RemoteTextureMap::Init();
   4097  // We need to initialize the parent process to prepare for WebRender if we
   4098  // did not end up disabling it, despite losing the GPU process.
   4099  wr::RenderThread::Start(GPUProcessManager::Get()->AllocateNamespace());
   4100  gfx::CanvasRenderThread::Start();
   4101  image::ImageMemoryReporter::InitForWebRender();
   4102 }
   4103 
   4104 /* static */ void gfxPlatform::DisableRemoteCanvas() {
   4105  if (gfxVars::UseAcceleratedCanvas2D()) {
   4106    gfxConfig::ForceDisable(Feature::ACCELERATED_CANVAS2D,
   4107                            FeatureStatus::Failed, "Disabled by runtime error",
   4108                            "FEATURE_ACCELERATED_CANVAS2D_RUNTIME_ERROR"_ns);
   4109    gfxVars::SetUseAcceleratedCanvas2D(false);
   4110  }
   4111 }
   4112 
   4113 void gfxPlatform::ImportCachedContentDeviceData() {
   4114  MOZ_ASSERT(XRE_IsContentProcess());
   4115 
   4116  // Import the content device data if we've got some waiting.
   4117  if (!gContentDeviceInitData) {
   4118    return;
   4119  }
   4120 
   4121  ImportContentDeviceData(*gContentDeviceInitData);
   4122  gContentDeviceInitData = nullptr;
   4123 }
   4124 
   4125 void gfxPlatform::ImportContentDeviceData(
   4126    const mozilla::gfx::ContentDeviceData& aData) {
   4127  MOZ_ASSERT(XRE_IsContentProcess());
   4128 
   4129  const DevicePrefs& prefs = aData.prefs();
   4130  gfxConfig::Inherit(Feature::HW_COMPOSITING, prefs.hwCompositing());
   4131 
   4132  // We don't inherit Feature::OPENGL_COMPOSITING here, because platforms
   4133  // will handle that (without imported data from the parent) in
   4134  // InitOpenGLConfig.
   4135  mCMSOutputProfileData = Some(aData.cmsOutputProfileData().Clone());
   4136 }
   4137 
   4138 void gfxPlatform::BuildContentDeviceData(
   4139    mozilla::gfx::ContentDeviceData* aOut) {
   4140  MOZ_ASSERT(XRE_IsParentProcess());
   4141 
   4142  aOut->prefs().hwCompositing() = gfxConfig::GetValue(Feature::HW_COMPOSITING);
   4143  aOut->prefs().oglCompositing() =
   4144      gfxConfig::GetValue(Feature::OPENGL_COMPOSITING);
   4145 }
   4146 
   4147 void gfxPlatform::ImportGPUDeviceData(
   4148    const mozilla::gfx::GPUDeviceData& aData) {
   4149  MOZ_ASSERT(XRE_IsParentProcess());
   4150 
   4151  gfxConfig::ImportChange(Feature::OPENGL_COMPOSITING, aData.oglCompositing());
   4152 }
   4153 
   4154 bool gfxPlatform::SupportsApzTouchInput() const {
   4155  return dom::TouchEvent::PrefEnabled(nullptr);
   4156 }
   4157 
   4158 bool gfxPlatform::SupportsApzDragInput() const {
   4159  return StaticPrefs::apz_drag_enabled();
   4160 }
   4161 
   4162 bool gfxPlatform::SupportsApzKeyboardInput() const {
   4163  return StaticPrefs::apz_keyboard_enabled_AtStartup();
   4164 }
   4165 
   4166 bool gfxPlatform::SupportsApzAutoscrolling() const {
   4167  return StaticPrefs::apz_autoscroll_enabled();
   4168 }
   4169 
   4170 bool gfxPlatform::SupportsApzZooming() const {
   4171  return StaticPrefs::apz_allow_zooming();
   4172 }
   4173 
   4174 void gfxPlatform::InitOpenGLConfig() {
   4175 #ifdef XP_WIN
   4176  // Don't enable by default on Windows, since it could show up in
   4177  // about:support even though it'll never get used. Only attempt if user
   4178  // enables the pref
   4179  if (!Preferences::GetBool("layers.prefer-opengl")) {
   4180    return;
   4181  }
   4182 #endif
   4183 
   4184  FeatureState& openGLFeature =
   4185      gfxConfig::GetFeature(Feature::OPENGL_COMPOSITING);
   4186 
   4187  // Check to see hw comp supported
   4188  if (!gfxConfig::IsEnabled(Feature::HW_COMPOSITING)) {
   4189    openGLFeature.DisableByDefault(FeatureStatus::Unavailable,
   4190                                   "Hardware compositing is disabled",
   4191                                   "FEATURE_FAILURE_OPENGL_NEED_HWCOMP"_ns);
   4192    return;
   4193  }
   4194 
   4195 #ifdef XP_WIN
   4196  openGLFeature.SetDefaultFromPref(
   4197      StaticPrefs::GetPrefName_layers_prefer_opengl(), true,
   4198      StaticPrefs::GetPrefDefault_layers_prefer_opengl());
   4199 #else
   4200  openGLFeature.EnableByDefault();
   4201 #endif
   4202 
   4203  // When layers acceleration is force-enabled, enable it even for blocklisted
   4204  // devices.
   4205  if (StaticPrefs::
   4206          layers_acceleration_force_enabled_AtStartup_DoNotUseDirectly()) {
   4207    openGLFeature.UserForceEnable("Force-enabled by pref");
   4208    return;
   4209  }
   4210 
   4211  nsCString message;
   4212  nsCString failureId;
   4213  if (!IsGfxInfoStatusOkay(nsIGfxInfo::FEATURE_OPENGL_LAYERS, &message,
   4214                           failureId)) {
   4215    openGLFeature.Disable(FeatureStatus::Blocklisted, message.get(), failureId);
   4216  }
   4217 }
   4218 
   4219 bool gfxPlatform::IsGfxInfoStatusOkay(int32_t aFeature, nsCString* aOutMessage,
   4220                                      nsCString& aFailureId) {
   4221  nsCOMPtr<nsIGfxInfo> gfxInfo = components::GfxInfo::Service();
   4222  if (!gfxInfo) {
   4223    return true;
   4224  }
   4225 
   4226  int32_t status;
   4227  if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(aFeature, aFailureId, &status)) &&
   4228      status != nsIGfxInfo::FEATURE_STATUS_OK) {
   4229    aOutMessage->AssignLiteral("#BLOCKLIST_");
   4230    aOutMessage->AppendASCII(aFailureId.get());
   4231    return false;
   4232  }
   4233 
   4234  return true;
   4235 }